mirror of
https://github.com/mihonapp/mihon.git
synced 2025-11-18 23:17:28 +01:00
Improve MAL support (UI is very simple yet).
This commit is contained in:
@@ -1,21 +0,0 @@
|
||||
package eu.kanade.mangafeed.data.chaptersync;
|
||||
|
||||
import com.squareup.okhttp.Response;
|
||||
|
||||
import eu.kanade.mangafeed.data.database.models.ChapterSync;
|
||||
import rx.Observable;
|
||||
|
||||
public abstract class BaseChapterSync {
|
||||
|
||||
// Name of the chapter sync service to display
|
||||
public abstract String getName();
|
||||
|
||||
// Id of the sync service (must be declared and obtained from ChapterSyncManager to avoid conflicts)
|
||||
public abstract int getId();
|
||||
|
||||
public abstract Observable<Boolean> login(String username, String password);
|
||||
|
||||
public abstract boolean isLogged();
|
||||
|
||||
public abstract Observable<Response> update(ChapterSync chapter);
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
package eu.kanade.mangafeed.data.chaptersync;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.squareup.okhttp.Credentials;
|
||||
import com.squareup.okhttp.FormEncodingBuilder;
|
||||
import com.squareup.okhttp.Headers;
|
||||
import com.squareup.okhttp.Response;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import eu.kanade.mangafeed.App;
|
||||
import eu.kanade.mangafeed.data.database.models.ChapterSync;
|
||||
import eu.kanade.mangafeed.data.network.NetworkHelper;
|
||||
import eu.kanade.mangafeed.data.preference.PreferencesHelper;
|
||||
import rx.Observable;
|
||||
|
||||
public class MyAnimeList extends BaseChapterSync {
|
||||
|
||||
@Inject PreferencesHelper preferences;
|
||||
@Inject NetworkHelper networkService;
|
||||
|
||||
private Headers headers;
|
||||
|
||||
public static final String BASE_URL = "http://myanimelist.net";
|
||||
|
||||
private static final String ENTRY = "entry";
|
||||
private static final String CHAPTER = "chapter";
|
||||
|
||||
public MyAnimeList(Context context) {
|
||||
App.get(context).getComponent().inject(this);
|
||||
|
||||
String username = preferences.getChapterSyncUsername(this);
|
||||
String password = preferences.getChapterSyncPassword(this);
|
||||
|
||||
if (!username.isEmpty() && !password.isEmpty()) {
|
||||
createHeaders(username, password);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "MyAnimeList";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return ChapterSyncManager.MYANIMELIST;
|
||||
}
|
||||
|
||||
public String getLoginUrl() {
|
||||
return Uri.parse(BASE_URL).buildUpon()
|
||||
.appendEncodedPath("api/account/verify_credentials.xml")
|
||||
.toString();
|
||||
}
|
||||
|
||||
public Observable<Boolean> login(String username, String password) {
|
||||
createHeaders(username, password);
|
||||
return networkService.getResponse(getLoginUrl(), headers, null)
|
||||
.map(response -> response.code() == 200);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLogged() {
|
||||
return !preferences.getChapterSyncUsername(this).isEmpty()
|
||||
&& !preferences.getChapterSyncPassword(this).isEmpty();
|
||||
}
|
||||
|
||||
public String getSearchUrl(String query) {
|
||||
return Uri.parse(BASE_URL).buildUpon()
|
||||
.appendEncodedPath("api/manga/search.xml")
|
||||
.appendQueryParameter("q", query)
|
||||
.toString();
|
||||
}
|
||||
|
||||
public Observable<List<ChapterSync>> search(String query) {
|
||||
return networkService.getStringResponse(getSearchUrl(query), headers, null)
|
||||
.map(Jsoup::parse)
|
||||
.flatMap(doc -> Observable.from(doc.select("entry")))
|
||||
.map(entry -> {
|
||||
ChapterSync chapter = ChapterSync.create(this);
|
||||
chapter.title = entry.select("title").first().text();
|
||||
chapter.remote_id = Integer.parseInt(entry.select("id").first().text());
|
||||
return chapter;
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
public String getListUrl(String username) {
|
||||
return Uri.parse(BASE_URL).buildUpon()
|
||||
.appendPath("malappinfo.php")
|
||||
.appendQueryParameter("u", username)
|
||||
.appendQueryParameter("status", "all")
|
||||
.appendQueryParameter("type", "manga")
|
||||
.toString();
|
||||
}
|
||||
|
||||
public Observable<List<ChapterSync>> getList(String username) {
|
||||
return networkService.getStringResponse(getListUrl(username), headers, null)
|
||||
.map(Jsoup::parse)
|
||||
.flatMap(doc -> Observable.from(doc.select("manga")))
|
||||
.map(entry -> {
|
||||
ChapterSync chapter = ChapterSync.create(this);
|
||||
chapter.title = entry.select("series_title").first().text();
|
||||
chapter.remote_id = Integer.parseInt(
|
||||
entry.select("series_mangadb_id").first().text());
|
||||
chapter.last_chapter_read = Integer.parseInt(
|
||||
entry.select("my_read_chapters").first().text());
|
||||
return chapter;
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
public String getUpdateUrl(ChapterSync chapter) {
|
||||
return Uri.parse(BASE_URL).buildUpon()
|
||||
.appendEncodedPath("api/mangalist/update")
|
||||
.appendPath(chapter.remote_id + ".xml")
|
||||
.toString();
|
||||
}
|
||||
|
||||
public Observable<Response> update(ChapterSync chapter) {
|
||||
XmlSerializer xml = Xml.newSerializer();
|
||||
StringWriter writer = new StringWriter();
|
||||
try {
|
||||
xml.setOutput(writer);
|
||||
xml.startDocument("UTF-8", false);
|
||||
xml.startTag("", ENTRY);
|
||||
xml.startTag("", CHAPTER);
|
||||
xml.text(chapter.last_chapter_read + "");
|
||||
xml.endTag("", CHAPTER);
|
||||
xml.endTag("", ENTRY);
|
||||
xml.endDocument();
|
||||
} catch (IOException e) {
|
||||
return Observable.error(e);
|
||||
}
|
||||
|
||||
FormEncodingBuilder form = new FormEncodingBuilder();
|
||||
form.add("data", writer.toString());
|
||||
|
||||
return networkService.postData(getUpdateUrl(chapter), form.build(), headers);
|
||||
}
|
||||
|
||||
public void createHeaders(String username, String password) {
|
||||
Headers.Builder builder = new Headers.Builder();
|
||||
builder.add("Authorization", Credentials.basic(username, password));
|
||||
// builder.add("User-Agent", "");
|
||||
setHeaders(builder.build());
|
||||
}
|
||||
|
||||
public void setHeaders(Headers headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,21 +16,21 @@ import com.pushtorefresh.storio.sqlite.queries.RawQuery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import eu.kanade.mangafeed.data.chaptersync.BaseChapterSync;
|
||||
import eu.kanade.mangafeed.data.database.models.MangaSync;
|
||||
import eu.kanade.mangafeed.data.mangasync.base.BaseMangaSync;
|
||||
import eu.kanade.mangafeed.data.database.models.Chapter;
|
||||
import eu.kanade.mangafeed.data.database.models.ChapterStorIOSQLiteDeleteResolver;
|
||||
import eu.kanade.mangafeed.data.database.models.ChapterStorIOSQLiteGetResolver;
|
||||
import eu.kanade.mangafeed.data.database.models.ChapterStorIOSQLitePutResolver;
|
||||
import eu.kanade.mangafeed.data.database.models.ChapterSync;
|
||||
import eu.kanade.mangafeed.data.database.models.ChapterSyncStorIOSQLiteDeleteResolver;
|
||||
import eu.kanade.mangafeed.data.database.models.ChapterSyncStorIOSQLiteGetResolver;
|
||||
import eu.kanade.mangafeed.data.database.models.ChapterSyncStorIOSQLitePutResolver;
|
||||
import eu.kanade.mangafeed.data.database.models.Manga;
|
||||
import eu.kanade.mangafeed.data.database.models.MangaStorIOSQLiteDeleteResolver;
|
||||
import eu.kanade.mangafeed.data.database.models.MangaStorIOSQLiteGetResolver;
|
||||
import eu.kanade.mangafeed.data.database.models.MangaStorIOSQLitePutResolver;
|
||||
import eu.kanade.mangafeed.data.database.models.MangaSyncStorIOSQLiteDeleteResolver;
|
||||
import eu.kanade.mangafeed.data.database.models.MangaSyncStorIOSQLiteGetResolver;
|
||||
import eu.kanade.mangafeed.data.database.models.MangaSyncStorIOSQLitePutResolver;
|
||||
import eu.kanade.mangafeed.data.database.resolvers.MangaWithUnreadGetResolver;
|
||||
import eu.kanade.mangafeed.data.database.tables.ChapterSyncTable;
|
||||
import eu.kanade.mangafeed.data.database.tables.MangaSyncTable;
|
||||
import eu.kanade.mangafeed.data.database.tables.ChapterTable;
|
||||
import eu.kanade.mangafeed.data.database.tables.MangaTable;
|
||||
import eu.kanade.mangafeed.util.ChapterRecognition;
|
||||
@@ -55,10 +55,10 @@ public class DatabaseHelper {
|
||||
.getResolver(new ChapterStorIOSQLiteGetResolver())
|
||||
.deleteResolver(new ChapterStorIOSQLiteDeleteResolver())
|
||||
.build())
|
||||
.addTypeMapping(ChapterSync.class, SQLiteTypeMapping.<ChapterSync>builder()
|
||||
.putResolver(new ChapterSyncStorIOSQLitePutResolver())
|
||||
.getResolver(new ChapterSyncStorIOSQLiteGetResolver())
|
||||
.deleteResolver(new ChapterSyncStorIOSQLiteDeleteResolver())
|
||||
.addTypeMapping(MangaSync.class, SQLiteTypeMapping.<MangaSync>builder()
|
||||
.putResolver(new MangaSyncStorIOSQLitePutResolver())
|
||||
.getResolver(new MangaSyncStorIOSQLiteGetResolver())
|
||||
.deleteResolver(new MangaSyncStorIOSQLiteDeleteResolver())
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
@@ -88,7 +88,7 @@ public class DatabaseHelper {
|
||||
.prepare();
|
||||
}
|
||||
|
||||
public PreparedGetListOfObjects<Manga> getMangasWithUnread() {
|
||||
public PreparedGetListOfObjects<Manga> getFavoriteMangasWithUnread() {
|
||||
return db.get()
|
||||
.listOfObjects(Manga.class)
|
||||
.withQuery(RawQuery.builder()
|
||||
@@ -301,30 +301,30 @@ public class DatabaseHelper {
|
||||
.prepare();
|
||||
}
|
||||
|
||||
// Chapter sync related queries
|
||||
// Manga sync related queries
|
||||
|
||||
public PreparedGetListOfObjects<ChapterSync> getChapterSync(Manga manga, BaseChapterSync sync) {
|
||||
public PreparedGetListOfObjects<MangaSync> getMangaSync(Manga manga, BaseMangaSync sync) {
|
||||
|
||||
return db.get()
|
||||
.listOfObjects(ChapterSync.class)
|
||||
.listOfObjects(MangaSync.class)
|
||||
.withQuery(Query.builder()
|
||||
.table(ChapterSyncTable.TABLE)
|
||||
.where(ChapterSyncTable.COLUMN_MANGA_ID + "=? AND " +
|
||||
ChapterSyncTable.COLUMN_SYNC_ID + "=?")
|
||||
.table(MangaSyncTable.TABLE)
|
||||
.where(MangaSyncTable.COLUMN_MANGA_ID + "=? AND " +
|
||||
MangaSyncTable.COLUMN_SYNC_ID + "=?")
|
||||
.whereArgs(manga.id, sync.getId())
|
||||
.build())
|
||||
.prepare();
|
||||
}
|
||||
|
||||
public PreparedPutObject<ChapterSync> insertChapterSync(ChapterSync chapter) {
|
||||
public PreparedPutObject<MangaSync> insertMangaSync(MangaSync manga) {
|
||||
return db.put()
|
||||
.object(chapter)
|
||||
.object(manga)
|
||||
.prepare();
|
||||
}
|
||||
|
||||
public PreparedDeleteObject<ChapterSync> deleteChapterSync(ChapterSync chapter) {
|
||||
public PreparedDeleteObject<MangaSync> deleteMangaSync(MangaSync manga) {
|
||||
return db.delete()
|
||||
.object(chapter)
|
||||
.object(manga)
|
||||
.prepare();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import eu.kanade.mangafeed.data.database.tables.ChapterSyncTable;
|
||||
import eu.kanade.mangafeed.data.database.tables.MangaSyncTable;
|
||||
import eu.kanade.mangafeed.data.database.tables.ChapterTable;
|
||||
import eu.kanade.mangafeed.data.database.tables.MangaTable;
|
||||
|
||||
public class DbOpenHelper extends SQLiteOpenHelper {
|
||||
|
||||
public static final String DATABASE_NAME = "mangafeed.db";
|
||||
public static final int DATABASE_VERSION = 2;
|
||||
public static final int DATABASE_VERSION = 3;
|
||||
|
||||
public DbOpenHelper(@NonNull Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
@@ -22,13 +22,13 @@ public class DbOpenHelper extends SQLiteOpenHelper {
|
||||
public void onCreate(@NonNull SQLiteDatabase db) {
|
||||
db.execSQL(MangaTable.getCreateTableQuery());
|
||||
db.execSQL(ChapterTable.getCreateTableQuery());
|
||||
db.execSQL(ChapterSyncTable.getCreateTableQuery());
|
||||
db.execSQL(MangaSyncTable.getCreateTableQuery());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(@NonNull SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
if (oldVersion == 1)
|
||||
db.execSQL(ChapterSyncTable.getCreateTableQuery());
|
||||
if (oldVersion < 3)
|
||||
db.execSQL(MangaSyncTable.getCreateTableQuery());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
package eu.kanade.mangafeed.data.database.models;
|
||||
|
||||
import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteColumn;
|
||||
import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteType;
|
||||
|
||||
import eu.kanade.mangafeed.data.chaptersync.BaseChapterSync;
|
||||
import eu.kanade.mangafeed.data.database.tables.ChapterSyncTable;
|
||||
|
||||
@StorIOSQLiteType(table = ChapterSyncTable.TABLE)
|
||||
public class ChapterSync {
|
||||
|
||||
@StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_ID, key = true)
|
||||
public long id;
|
||||
|
||||
@StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_MANGA_ID)
|
||||
public long manga_id;
|
||||
|
||||
@StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_SYNC_ID)
|
||||
public int sync_id;
|
||||
|
||||
@StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_REMOTE_ID)
|
||||
public int remote_id;
|
||||
|
||||
@StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_TITLE)
|
||||
public String title;
|
||||
|
||||
@StorIOSQLiteColumn(name = ChapterSyncTable.COLUMN_LAST_CHAPTER_READ)
|
||||
public int last_chapter_read;
|
||||
|
||||
public static ChapterSync create(BaseChapterSync sync) {
|
||||
ChapterSync chapter = new ChapterSync();
|
||||
chapter.sync_id = sync.getId();
|
||||
return chapter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package eu.kanade.mangafeed.data.database.models;
|
||||
|
||||
import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteColumn;
|
||||
import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteType;
|
||||
|
||||
import eu.kanade.mangafeed.data.mangasync.base.BaseMangaSync;
|
||||
import eu.kanade.mangafeed.data.database.tables.MangaSyncTable;
|
||||
|
||||
@StorIOSQLiteType(table = MangaSyncTable.TABLE)
|
||||
public class MangaSync {
|
||||
|
||||
@StorIOSQLiteColumn(name = MangaSyncTable.COLUMN_ID, key = true)
|
||||
public Long id;
|
||||
|
||||
@StorIOSQLiteColumn(name = MangaSyncTable.COLUMN_MANGA_ID)
|
||||
public long manga_id;
|
||||
|
||||
@StorIOSQLiteColumn(name = MangaSyncTable.COLUMN_SYNC_ID)
|
||||
public int sync_id;
|
||||
|
||||
@StorIOSQLiteColumn(name = MangaSyncTable.COLUMN_REMOTE_ID)
|
||||
public int remote_id;
|
||||
|
||||
@StorIOSQLiteColumn(name = MangaSyncTable.COLUMN_TITLE)
|
||||
public String title;
|
||||
|
||||
@StorIOSQLiteColumn(name = MangaSyncTable.COLUMN_LAST_CHAPTER_READ)
|
||||
public int last_chapter_read;
|
||||
|
||||
@StorIOSQLiteColumn(name = MangaSyncTable.COLUMN_SCORE)
|
||||
public float score;
|
||||
|
||||
@StorIOSQLiteColumn(name = MangaSyncTable.COLUMN_STATUS)
|
||||
public int status;
|
||||
|
||||
public static MangaSync create(BaseMangaSync service) {
|
||||
MangaSync mangasync = new MangaSync();
|
||||
mangasync.sync_id = service.getId();
|
||||
return mangasync;
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@ package eu.kanade.mangafeed.data.database.tables;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
public class ChapterSyncTable {
|
||||
public class MangaSyncTable {
|
||||
|
||||
public static final String TABLE = "chapter_sync";
|
||||
public static final String TABLE = "manga_sync";
|
||||
|
||||
public static final String COLUMN_ID = "_id";
|
||||
|
||||
@@ -18,6 +18,10 @@ public class ChapterSyncTable {
|
||||
|
||||
public static final String COLUMN_LAST_CHAPTER_READ = "last_chapter_read";
|
||||
|
||||
public static final String COLUMN_STATUS = "status";
|
||||
|
||||
public static final String COLUMN_SCORE = "score";
|
||||
|
||||
@NonNull
|
||||
public static String getCreateTableQuery() {
|
||||
return "CREATE TABLE " + TABLE + "("
|
||||
@@ -27,6 +31,8 @@ public class ChapterSyncTable {
|
||||
+ COLUMN_REMOTE_ID + " INTEGER NOT NULL, "
|
||||
+ COLUMN_TITLE + " TEXT NOT NULL, "
|
||||
+ COLUMN_LAST_CHAPTER_READ + " INTEGER NOT NULL, "
|
||||
+ COLUMN_STATUS + " INTEGER NOT NULL, "
|
||||
+ COLUMN_SCORE + " FLOAT NOT NULL, "
|
||||
+ "FOREIGN KEY(" + COLUMN_MANGA_ID + ") REFERENCES " + MangaTable.TABLE + "(" + MangaTable.COLUMN_ID + ") "
|
||||
+ "ON DELETE CASCADE"
|
||||
+ ");";
|
||||
@@ -1,18 +1,21 @@
|
||||
package eu.kanade.mangafeed.data.chaptersync;
|
||||
package eu.kanade.mangafeed.data.mangasync;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ChapterSyncManager {
|
||||
import eu.kanade.mangafeed.data.mangasync.base.BaseMangaSync;
|
||||
import eu.kanade.mangafeed.data.mangasync.services.MyAnimeList;
|
||||
|
||||
private List<BaseChapterSync> services;
|
||||
public class MangaSyncManager {
|
||||
|
||||
private List<BaseMangaSync> services;
|
||||
private MyAnimeList myAnimeList;
|
||||
|
||||
public static final int MYANIMELIST = 1;
|
||||
|
||||
public ChapterSyncManager(Context context) {
|
||||
public MangaSyncManager(Context context) {
|
||||
services = new ArrayList<>();
|
||||
myAnimeList = new MyAnimeList(context);
|
||||
services.add(myAnimeList);
|
||||
@@ -22,11 +25,11 @@ public class ChapterSyncManager {
|
||||
return myAnimeList;
|
||||
}
|
||||
|
||||
public List<BaseChapterSync> getChapterSyncServices() {
|
||||
public List<BaseMangaSync> getSyncServices() {
|
||||
return services;
|
||||
}
|
||||
|
||||
public BaseChapterSync getSyncService(int id) {
|
||||
public BaseMangaSync getSyncService(int id) {
|
||||
switch (id) {
|
||||
case MYANIMELIST:
|
||||
return myAnimeList;
|
||||
@@ -0,0 +1,28 @@
|
||||
package eu.kanade.mangafeed.data.mangasync.base;
|
||||
|
||||
import com.squareup.okhttp.Response;
|
||||
|
||||
import eu.kanade.mangafeed.data.database.models.MangaSync;
|
||||
import rx.Observable;
|
||||
|
||||
public abstract class BaseMangaSync {
|
||||
|
||||
// Name of the manga sync service to display
|
||||
public abstract String getName();
|
||||
|
||||
// Id of the sync service (must be declared and obtained from MangaSyncManager to avoid conflicts)
|
||||
public abstract int getId();
|
||||
|
||||
public abstract Observable<Boolean> login(String username, String password);
|
||||
|
||||
public abstract boolean isLogged();
|
||||
|
||||
public abstract Observable<Response> update(MangaSync manga);
|
||||
|
||||
public abstract Observable<Response> add(MangaSync manga);
|
||||
|
||||
public abstract Observable<Response> bind(MangaSync manga);
|
||||
|
||||
public abstract String getStatus(int status);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
package eu.kanade.mangafeed.data.mangasync.services;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.squareup.okhttp.Credentials;
|
||||
import com.squareup.okhttp.FormEncodingBuilder;
|
||||
import com.squareup.okhttp.Headers;
|
||||
import com.squareup.okhttp.RequestBody;
|
||||
import com.squareup.okhttp.Response;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import eu.kanade.mangafeed.App;
|
||||
import eu.kanade.mangafeed.data.database.models.MangaSync;
|
||||
import eu.kanade.mangafeed.data.mangasync.MangaSyncManager;
|
||||
import eu.kanade.mangafeed.data.mangasync.base.BaseMangaSync;
|
||||
import eu.kanade.mangafeed.data.network.NetworkHelper;
|
||||
import eu.kanade.mangafeed.data.preference.PreferencesHelper;
|
||||
import rx.Observable;
|
||||
|
||||
public class MyAnimeList extends BaseMangaSync {
|
||||
|
||||
@Inject PreferencesHelper preferences;
|
||||
@Inject NetworkHelper networkService;
|
||||
|
||||
private Headers headers;
|
||||
private String username;
|
||||
|
||||
public static final String BASE_URL = "http://myanimelist.net";
|
||||
|
||||
private static final String ENTRY_TAG = "entry";
|
||||
private static final String CHAPTER_TAG = "chapter";
|
||||
private static final String SCORE_TAG = "score";
|
||||
private static final String STATUS_TAG = "status";
|
||||
|
||||
public static final int NOT_IN_LIST = 0;
|
||||
public static final int READING = 1;
|
||||
public static final int COMPLETED = 2;
|
||||
public static final int ON_HOLD = 3;
|
||||
public static final int DROPPED = 4;
|
||||
public static final int PLAN_TO_READ = 6;
|
||||
|
||||
public static final int DEFAULT_STATUS = READING;
|
||||
public static final int DEFAULT_SCORE = 0;
|
||||
|
||||
public MyAnimeList(Context context) {
|
||||
App.get(context).getComponent().inject(this);
|
||||
|
||||
String username = preferences.getMangaSyncUsername(this);
|
||||
String password = preferences.getMangaSyncPassword(this);
|
||||
|
||||
if (!username.isEmpty() && !password.isEmpty()) {
|
||||
createHeaders(username, password);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "MyAnimeList";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return MangaSyncManager.MYANIMELIST;
|
||||
}
|
||||
|
||||
public String getLoginUrl() {
|
||||
return Uri.parse(BASE_URL).buildUpon()
|
||||
.appendEncodedPath("api/account/verify_credentials.xml")
|
||||
.toString();
|
||||
}
|
||||
|
||||
public Observable<Boolean> login(String username, String password) {
|
||||
createHeaders(username, password);
|
||||
return networkService.getResponse(getLoginUrl(), headers, null)
|
||||
.map(response -> response.code() == 200);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLogged() {
|
||||
return !preferences.getMangaSyncUsername(this).isEmpty()
|
||||
&& !preferences.getMangaSyncPassword(this).isEmpty();
|
||||
}
|
||||
|
||||
public String getSearchUrl(String query) {
|
||||
return Uri.parse(BASE_URL).buildUpon()
|
||||
.appendEncodedPath("api/manga/search.xml")
|
||||
.appendQueryParameter("q", query)
|
||||
.toString();
|
||||
}
|
||||
|
||||
public Observable<List<MangaSync>> search(String query) {
|
||||
return networkService.getStringResponse(getSearchUrl(query), headers, null)
|
||||
.map(Jsoup::parse)
|
||||
.flatMap(doc -> Observable.from(doc.select("entry")))
|
||||
.map(entry -> {
|
||||
MangaSync manga = MangaSync.create(this);
|
||||
manga.title = entry.select("title").first().text();
|
||||
manga.remote_id = Integer.parseInt(entry.select("id").first().text());
|
||||
return manga;
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
public String getListUrl(String username) {
|
||||
return Uri.parse(BASE_URL).buildUpon()
|
||||
.appendPath("malappinfo.php")
|
||||
.appendQueryParameter("u", username)
|
||||
.appendQueryParameter("status", "all")
|
||||
.appendQueryParameter("type", "manga")
|
||||
.toString();
|
||||
}
|
||||
|
||||
public Observable<List<MangaSync>> getList(String username) {
|
||||
// TODO cache this list for a few minutes
|
||||
return networkService.getStringResponse(getListUrl(username), headers, null)
|
||||
.map(Jsoup::parse)
|
||||
.flatMap(doc -> Observable.from(doc.select("manga")))
|
||||
.map(entry -> {
|
||||
MangaSync manga = MangaSync.create(this);
|
||||
manga.title = entry.select("series_title").first().text();
|
||||
manga.remote_id = Integer.parseInt(
|
||||
entry.select("series_mangadb_id").first().text());
|
||||
manga.last_chapter_read = Integer.parseInt(
|
||||
entry.select("my_read_chapters").first().text());
|
||||
manga.status = Integer.parseInt(
|
||||
entry.select("my_status").first().text());
|
||||
// MAL doesn't support score with decimals
|
||||
manga.score = Integer.parseInt(
|
||||
entry.select("my_score").first().text());
|
||||
return manga;
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
public String getUpdateUrl(MangaSync manga) {
|
||||
return Uri.parse(BASE_URL).buildUpon()
|
||||
.appendEncodedPath("api/mangalist/update")
|
||||
.appendPath(manga.remote_id + ".xml")
|
||||
.toString();
|
||||
}
|
||||
|
||||
public Observable<Response> update(MangaSync manga) {
|
||||
try {
|
||||
RequestBody payload = getMangaPostPayload(manga);
|
||||
return networkService.postData(getUpdateUrl(manga), payload, headers);
|
||||
} catch (IOException e) {
|
||||
return Observable.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getAddUrl(MangaSync manga) {
|
||||
return Uri.parse(BASE_URL).buildUpon()
|
||||
.appendEncodedPath("api/mangalist/add")
|
||||
.appendPath(manga.remote_id + ".xml")
|
||||
.toString();
|
||||
}
|
||||
|
||||
public Observable<Response> add(MangaSync manga) {
|
||||
try {
|
||||
RequestBody payload = getMangaPostPayload(manga);
|
||||
return networkService.postData(getAddUrl(manga), payload, headers);
|
||||
} catch (IOException e) {
|
||||
return Observable.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private RequestBody getMangaPostPayload(MangaSync manga) throws IOException {
|
||||
XmlSerializer xml = Xml.newSerializer();
|
||||
StringWriter writer = new StringWriter();
|
||||
xml.setOutput(writer);
|
||||
xml.startDocument("UTF-8", false);
|
||||
xml.startTag("", ENTRY_TAG);
|
||||
|
||||
// Last chapter read
|
||||
if (manga.last_chapter_read != 0) {
|
||||
xml.startTag("", CHAPTER_TAG);
|
||||
xml.text(manga.last_chapter_read + "");
|
||||
xml.endTag("", CHAPTER_TAG);
|
||||
}
|
||||
// Manga status in the list
|
||||
xml.startTag("", STATUS_TAG);
|
||||
xml.text(manga.status + "");
|
||||
xml.endTag("", STATUS_TAG);
|
||||
// Manga score
|
||||
xml.startTag("", SCORE_TAG);
|
||||
xml.text(manga.score + "");
|
||||
xml.endTag("", SCORE_TAG);
|
||||
|
||||
xml.endTag("", ENTRY_TAG);
|
||||
xml.endDocument();
|
||||
|
||||
FormEncodingBuilder form = new FormEncodingBuilder();
|
||||
form.add("data", writer.toString());
|
||||
return form.build();
|
||||
}
|
||||
|
||||
public Observable<Response> bind(MangaSync manga) {
|
||||
return getList(username)
|
||||
.flatMap(list -> {
|
||||
manga.sync_id = getId();
|
||||
for (MangaSync remoteManga : list) {
|
||||
if (remoteManga.remote_id == manga.remote_id) {
|
||||
// Manga is already in the list
|
||||
manga.score = remoteManga.score;
|
||||
manga.status = remoteManga.status;
|
||||
manga.last_chapter_read = remoteManga.last_chapter_read;
|
||||
return update(manga);
|
||||
}
|
||||
}
|
||||
// Set default fields if it's not found in the list
|
||||
manga.score = DEFAULT_SCORE;
|
||||
manga.status = DEFAULT_STATUS;
|
||||
return add(manga);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatus(int status) {
|
||||
switch (status) {
|
||||
case READING:
|
||||
return "Reading";
|
||||
case COMPLETED:
|
||||
return "Completed";
|
||||
case ON_HOLD:
|
||||
return "On hold";
|
||||
case DROPPED:
|
||||
return "Dropped";
|
||||
case PLAN_TO_READ:
|
||||
return "Plan to read";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public void createHeaders(String username, String password) {
|
||||
this.username = username;
|
||||
Headers.Builder builder = new Headers.Builder();
|
||||
builder.add("Authorization", Credentials.basic(username, password));
|
||||
builder.add("User-Agent", "api-indiv-9F93C52A963974CF674325391990191C");
|
||||
setHeaders(builder.build());
|
||||
}
|
||||
|
||||
public void setHeaders(Headers headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import com.f2prateek.rx.preferences.RxSharedPreferences;
|
||||
import java.io.File;
|
||||
|
||||
import eu.kanade.mangafeed.R;
|
||||
import eu.kanade.mangafeed.data.chaptersync.BaseChapterSync;
|
||||
import eu.kanade.mangafeed.data.mangasync.base.BaseMangaSync;
|
||||
import eu.kanade.mangafeed.data.source.base.Source;
|
||||
import rx.Observable;
|
||||
|
||||
@@ -23,8 +23,8 @@ public class PreferencesHelper {
|
||||
|
||||
private static final String SOURCE_ACCOUNT_USERNAME = "pref_source_username_";
|
||||
private static final String SOURCE_ACCOUNT_PASSWORD = "pref_source_password_";
|
||||
private static final String CHAPTERSYNC_ACCOUNT_USERNAME = "pref_chaptersync_username_";
|
||||
private static final String CHAPTERSYNC_ACCOUNT_PASSWORD = "pref_chaptersync_password_";
|
||||
private static final String MANGASYNC_ACCOUNT_USERNAME = "pref_mangasync_username_";
|
||||
private static final String MANGASYNC_ACCOUNT_PASSWORD = "pref_mangasync_password_";
|
||||
|
||||
private File defaultDownloadsDir;
|
||||
|
||||
@@ -102,18 +102,18 @@ public class PreferencesHelper {
|
||||
.apply();
|
||||
}
|
||||
|
||||
public String getChapterSyncUsername(BaseChapterSync sync) {
|
||||
return prefs.getString(CHAPTERSYNC_ACCOUNT_USERNAME + sync.getId(), "");
|
||||
public String getMangaSyncUsername(BaseMangaSync sync) {
|
||||
return prefs.getString(MANGASYNC_ACCOUNT_USERNAME + sync.getId(), "");
|
||||
}
|
||||
|
||||
public String getChapterSyncPassword(BaseChapterSync sync) {
|
||||
return prefs.getString(CHAPTERSYNC_ACCOUNT_PASSWORD + sync.getId(), "");
|
||||
public String getMangaSyncPassword(BaseMangaSync sync) {
|
||||
return prefs.getString(MANGASYNC_ACCOUNT_PASSWORD + sync.getId(), "");
|
||||
}
|
||||
|
||||
public void setChapterSyncCredentials(BaseChapterSync sync, String username, String password) {
|
||||
public void setMangaSyncCredentials(BaseMangaSync sync, String username, String password) {
|
||||
prefs.edit()
|
||||
.putString(CHAPTERSYNC_ACCOUNT_USERNAME + sync.getId(), username)
|
||||
.putString(CHAPTERSYNC_ACCOUNT_PASSWORD + sync.getId(), password)
|
||||
.putString(MANGASYNC_ACCOUNT_USERNAME + sync.getId(), username)
|
||||
.putString(MANGASYNC_ACCOUNT_PASSWORD + sync.getId(), password)
|
||||
.apply();
|
||||
}
|
||||
|
||||
@@ -127,12 +127,11 @@ public class PreferencesHelper {
|
||||
}
|
||||
|
||||
public int getDownloadThreads() {
|
||||
return Integer.parseInt(prefs.getString(getKey(R.string.pref_download_threads_key), "1"));
|
||||
return prefs.getInt(getKey(R.string.pref_download_slots_key), 1);
|
||||
}
|
||||
|
||||
public Observable<Integer> getDownloadTheadsObservable() {
|
||||
return rxPrefs.getString(getKey(R.string.pref_download_threads_key), "1")
|
||||
.asObservable().map(Integer::parseInt);
|
||||
return rxPrefs.getInteger(getKey(R.string.pref_download_slots_key), 1).asObservable();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.kanade.mangafeed.data.chaptersync;
|
||||
package eu.kanade.mangafeed.data.sync;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
@@ -10,24 +10,24 @@ import javax.inject.Inject;
|
||||
import de.greenrobot.event.EventBus;
|
||||
import eu.kanade.mangafeed.App;
|
||||
import eu.kanade.mangafeed.data.database.DatabaseHelper;
|
||||
import eu.kanade.mangafeed.data.database.models.ChapterSync;
|
||||
import eu.kanade.mangafeed.data.network.NetworkHelper;
|
||||
import eu.kanade.mangafeed.event.UpdateChapterSyncEvent;
|
||||
import eu.kanade.mangafeed.data.database.models.MangaSync;
|
||||
import eu.kanade.mangafeed.data.mangasync.MangaSyncManager;
|
||||
import eu.kanade.mangafeed.data.mangasync.base.BaseMangaSync;
|
||||
import eu.kanade.mangafeed.event.UpdateMangaSyncEvent;
|
||||
import eu.kanade.mangafeed.util.EventBusHook;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
import rx.subscriptions.CompositeSubscription;
|
||||
|
||||
public class UpdateChapterSyncService extends Service {
|
||||
public class UpdateMangaSyncService extends Service {
|
||||
|
||||
@Inject ChapterSyncManager syncManager;
|
||||
@Inject NetworkHelper networkManager;
|
||||
@Inject MangaSyncManager syncManager;
|
||||
@Inject DatabaseHelper db;
|
||||
|
||||
private CompositeSubscription subscriptions;
|
||||
|
||||
public static void start(Context context) {
|
||||
context.startService(new Intent(context, UpdateChapterSyncService.class));
|
||||
context.startService(new Intent(context, UpdateMangaSyncService.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,15 +56,15 @@ public class UpdateChapterSyncService extends Service {
|
||||
}
|
||||
|
||||
@EventBusHook
|
||||
public void onEventMainThread(UpdateChapterSyncEvent event) {
|
||||
updateLastChapteRead(event.getChapterSync());
|
||||
public void onEventMainThread(UpdateMangaSyncEvent event) {
|
||||
updateLastChapteRead(event.getMangaSync());
|
||||
}
|
||||
|
||||
private void updateLastChapteRead(ChapterSync chapterSync) {
|
||||
BaseChapterSync sync = syncManager.getSyncService(chapterSync.sync_id);
|
||||
private void updateLastChapteRead(MangaSync mangaSync) {
|
||||
BaseMangaSync sync = syncManager.getSyncService(mangaSync.sync_id);
|
||||
|
||||
subscriptions.add(sync.update(chapterSync)
|
||||
.flatMap(response -> db.insertChapterSync(chapterSync).createObservable())
|
||||
subscriptions.add(sync.update(mangaSync)
|
||||
.flatMap(response -> db.insertMangaSync(mangaSync).createObservable())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
Reference in New Issue
Block a user