Reorganize data package

This commit is contained in:
inorichi
2015-11-14 19:20:39 +01:00
parent 67ab54ff3b
commit f63b7c8141
73 changed files with 248 additions and 242 deletions

View File

@@ -1,4 +1,4 @@
package eu.kanade.mangafeed.data.caches;
package eu.kanade.mangafeed.data.cache;
import android.content.Context;
@@ -15,7 +15,7 @@ import java.io.OutputStream;
import java.lang.reflect.Type;
import java.util.List;
import eu.kanade.mangafeed.data.models.Page;
import eu.kanade.mangafeed.data.source.model.Page;
import eu.kanade.mangafeed.util.DiskUtils;
import okio.BufferedSink;
import okio.Okio;

View File

@@ -1,4 +1,4 @@
package eu.kanade.mangafeed.data.helpers;
package eu.kanade.mangafeed.data.database;
import android.content.Context;
@@ -16,16 +16,16 @@ import com.pushtorefresh.storio.sqlite.queries.RawQuery;
import java.util.List;
import eu.kanade.mangafeed.data.models.Chapter;
import eu.kanade.mangafeed.data.models.ChapterStorIOSQLiteDeleteResolver;
import eu.kanade.mangafeed.data.models.ChapterStorIOSQLiteGetResolver;
import eu.kanade.mangafeed.data.models.ChapterStorIOSQLitePutResolver;
import eu.kanade.mangafeed.data.models.Manga;
import eu.kanade.mangafeed.data.models.MangaStorIOSQLiteDeleteResolver;
import eu.kanade.mangafeed.data.models.MangaStorIOSQLitePutResolver;
import eu.kanade.mangafeed.data.resolvers.MangaWithUnreadGetResolver;
import eu.kanade.mangafeed.data.tables.ChaptersTable;
import eu.kanade.mangafeed.data.tables.MangasTable;
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.Manga;
import eu.kanade.mangafeed.data.database.models.MangaStorIOSQLiteDeleteResolver;
import eu.kanade.mangafeed.data.database.models.MangaStorIOSQLitePutResolver;
import eu.kanade.mangafeed.data.database.resolvers.MangaWithUnreadGetResolver;
import eu.kanade.mangafeed.data.database.tables.ChaptersTable;
import eu.kanade.mangafeed.data.database.tables.MangasTable;
import eu.kanade.mangafeed.util.ChapterRecognition;
import eu.kanade.mangafeed.util.PostResult;
import rx.Observable;

View File

@@ -1,12 +1,12 @@
package eu.kanade.mangafeed.data.helpers;
package eu.kanade.mangafeed.data.database;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.support.annotation.NonNull;
import eu.kanade.mangafeed.data.tables.ChaptersTable;
import eu.kanade.mangafeed.data.tables.MangasTable;
import eu.kanade.mangafeed.data.database.tables.ChaptersTable;
import eu.kanade.mangafeed.data.database.tables.MangasTable;
public class DbOpenHelper extends SQLiteOpenHelper {

View File

@@ -1,9 +1,9 @@
package eu.kanade.mangafeed.data.models;
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.tables.ChaptersTable;
import eu.kanade.mangafeed.data.database.tables.ChaptersTable;
@StorIOSQLiteType(table = ChaptersTable.TABLE)
public class Chapter {

View File

@@ -1,9 +1,9 @@
package eu.kanade.mangafeed.data.models;
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.tables.MangasTable;
import eu.kanade.mangafeed.data.database.tables.MangasTable;
@StorIOSQLiteType(table = MangasTable.TABLE)
public class Manga {

View File

@@ -1,11 +1,11 @@
package eu.kanade.mangafeed.data.resolvers;
package eu.kanade.mangafeed.data.database.resolvers;
import android.database.Cursor;
import android.support.annotation.NonNull;
import eu.kanade.mangafeed.data.models.Manga;
import eu.kanade.mangafeed.data.models.MangaStorIOSQLiteGetResolver;
import eu.kanade.mangafeed.data.tables.MangasTable;
import eu.kanade.mangafeed.data.database.models.Manga;
import eu.kanade.mangafeed.data.database.models.MangaStorIOSQLiteGetResolver;
import eu.kanade.mangafeed.data.database.tables.MangasTable;
public class MangaWithUnreadGetResolver extends MangaStorIOSQLiteGetResolver {

View File

@@ -1,4 +1,4 @@
package eu.kanade.mangafeed.data.tables;
package eu.kanade.mangafeed.data.database.tables;
import android.support.annotation.NonNull;

View File

@@ -1,4 +1,4 @@
package eu.kanade.mangafeed.data.tables;
package eu.kanade.mangafeed.data.database.tables;
import android.support.annotation.NonNull;

View File

@@ -1,4 +1,4 @@
package eu.kanade.mangafeed.data.tables;
package eu.kanade.mangafeed.data.database.tables;
import android.support.annotation.NonNull;

View File

@@ -1,4 +1,4 @@
package eu.kanade.mangafeed.data.tables;
package eu.kanade.mangafeed.data.database.tables;
import android.support.annotation.NonNull;

View File

@@ -1,4 +1,4 @@
package eu.kanade.mangafeed.data.helpers;
package eu.kanade.mangafeed.data.download;
import android.content.Context;
@@ -16,14 +16,15 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import eu.kanade.mangafeed.data.models.Chapter;
import eu.kanade.mangafeed.data.models.Download;
import eu.kanade.mangafeed.data.models.DownloadQueue;
import eu.kanade.mangafeed.data.models.Manga;
import eu.kanade.mangafeed.data.models.Page;
import eu.kanade.mangafeed.data.services.DownloadService;
import eu.kanade.mangafeed.events.DownloadChaptersEvent;
import eu.kanade.mangafeed.sources.base.Source;
import eu.kanade.mangafeed.data.database.models.Chapter;
import eu.kanade.mangafeed.data.database.models.Manga;
import eu.kanade.mangafeed.data.download.model.Download;
import eu.kanade.mangafeed.data.download.model.DownloadQueue;
import eu.kanade.mangafeed.data.source.model.Page;
import eu.kanade.mangafeed.data.preference.PreferencesHelper;
import eu.kanade.mangafeed.data.source.SourceManager;
import eu.kanade.mangafeed.event.DownloadChaptersEvent;
import eu.kanade.mangafeed.data.source.base.Source;
import eu.kanade.mangafeed.util.DiskUtils;
import eu.kanade.mangafeed.util.DynamicConcurrentMergeOperator;
import rx.Observable;

View File

@@ -1,4 +1,4 @@
package eu.kanade.mangafeed.data.services;
package eu.kanade.mangafeed.data.download;
import android.app.Service;
import android.content.Context;
@@ -12,8 +12,7 @@ import javax.inject.Inject;
import de.greenrobot.event.EventBus;
import eu.kanade.mangafeed.App;
import eu.kanade.mangafeed.data.helpers.DownloadManager;
import eu.kanade.mangafeed.events.DownloadChaptersEvent;
import eu.kanade.mangafeed.event.DownloadChaptersEvent;
import eu.kanade.mangafeed.util.ContentObservable;
import eu.kanade.mangafeed.util.EventBusHook;
import eu.kanade.mangafeed.util.NetworkUtil;

View File

@@ -1,9 +1,12 @@
package eu.kanade.mangafeed.data.models;
package eu.kanade.mangafeed.data.download.model;
import java.io.File;
import java.util.List;
import eu.kanade.mangafeed.sources.base.Source;
import eu.kanade.mangafeed.data.database.models.Chapter;
import eu.kanade.mangafeed.data.database.models.Manga;
import eu.kanade.mangafeed.data.source.model.Page;
import eu.kanade.mangafeed.data.source.base.Source;
import rx.subjects.PublishSubject;
public class Download {

View File

@@ -1,8 +1,9 @@
package eu.kanade.mangafeed.data.models;
package eu.kanade.mangafeed.data.download.model;
import java.util.ArrayList;
import java.util.List;
import eu.kanade.mangafeed.data.download.model.Download;
import rx.Observable;
import rx.subjects.PublishSubject;

View File

@@ -1,25 +1,17 @@
package eu.kanade.mangafeed.data.helpers;
package eu.kanade.mangafeed.data.network;
import com.squareup.okhttp.CacheControl;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;
import java.io.IOException;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.CookieStore;
import okio.Buffer;
import okio.BufferedSource;
import okio.ForwardingSource;
import okio.Okio;
import okio.Source;
import rx.Observable;
public final class NetworkHelper {
@@ -121,48 +113,4 @@ public final class NetworkHelper {
return cookieManager.getCookieStore();
}
private static class ProgressResponseBody extends ResponseBody {
private final ResponseBody responseBody;
private final ProgressListener progressListener;
private BufferedSource bufferedSource;
public ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) {
this.responseBody = responseBody;
this.progressListener = progressListener;
}
@Override public MediaType contentType() {
return responseBody.contentType();
}
@Override public long contentLength() throws IOException {
return responseBody.contentLength();
}
@Override public BufferedSource source() throws IOException {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(responseBody.source()));
}
return bufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
long totalBytesRead = 0L;
@Override public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
// read() returns the number of bytes read, or -1 if this source is exhausted.
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
return bytesRead;
}
};
}
}
public interface ProgressListener {
void update(long bytesRead, long contentLength, boolean done);
}
}

View File

@@ -0,0 +1,5 @@
package eu.kanade.mangafeed.data.network;
public interface ProgressListener {
void update(long bytesRead, long contentLength, boolean done);
}

View File

@@ -0,0 +1,52 @@
package eu.kanade.mangafeed.data.network;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.ResponseBody;
import java.io.IOException;
import okio.Buffer;
import okio.BufferedSource;
import okio.ForwardingSource;
import okio.Okio;
import okio.Source;
public class ProgressResponseBody extends ResponseBody {
private final ResponseBody responseBody;
private final ProgressListener progressListener;
private BufferedSource bufferedSource;
public ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) {
this.responseBody = responseBody;
this.progressListener = progressListener;
}
@Override public MediaType contentType() {
return responseBody.contentType();
}
@Override public long contentLength() throws IOException {
return responseBody.contentLength();
}
@Override public BufferedSource source() throws IOException {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(responseBody.source()));
}
return bufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
long totalBytesRead = 0L;
@Override public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
// read() returns the number of bytes read, or -1 if this source is exhausted.
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
return bytesRead;
}
};
}
}

View File

@@ -1,4 +1,4 @@
package eu.kanade.mangafeed.data.helpers;
package eu.kanade.mangafeed.data.preference;
import android.content.Context;
import android.content.SharedPreferences;
@@ -7,7 +7,7 @@ import android.preference.PreferenceManager;
import com.f2prateek.rx.preferences.RxSharedPreferences;
import eu.kanade.mangafeed.R;
import eu.kanade.mangafeed.sources.base.Source;
import eu.kanade.mangafeed.data.source.base.Source;
import eu.kanade.mangafeed.util.DiskUtils;
import rx.Observable;

View File

@@ -1,4 +1,4 @@
package eu.kanade.mangafeed.data.helpers;
package eu.kanade.mangafeed.data.source;
import android.content.Context;
@@ -6,10 +6,10 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import eu.kanade.mangafeed.sources.Batoto;
import eu.kanade.mangafeed.sources.Mangahere;
import eu.kanade.mangafeed.sources.Mangafox;
import eu.kanade.mangafeed.sources.base.Source;
import eu.kanade.mangafeed.data.source.online.english.Batoto;
import eu.kanade.mangafeed.data.source.online.english.Mangahere;
import eu.kanade.mangafeed.data.source.online.english.Mangafox;
import eu.kanade.mangafeed.data.source.base.Source;
public class SourceManager {

View File

@@ -0,0 +1,91 @@
package eu.kanade.mangafeed.data.source.base;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.Response;
import java.util.List;
import eu.kanade.mangafeed.data.database.models.Chapter;
import eu.kanade.mangafeed.data.database.models.Manga;
import rx.Observable;
public abstract class BaseSource {
// Name of the source to display
public abstract String getName();
// Id of the source (must be declared and obtained from SourceManager to avoid conflicts)
public abstract int getSourceId();
// True if the source requires a login
public abstract boolean isLoginRequired();
// Given a page number, it should return the URL of the page where the manga list is found
protected abstract String getUrlFromPageNumber(int page);
// From the URL obtained before, this method must return a list of mangas
protected abstract List<Manga> parsePopularMangasFromHtml(String unparsedHtml);
// Given a query and a page number, return the URL of the results
protected abstract String getSearchUrl(String query, int page);
// From the URL obtained before, this method must return a list of mangas
protected abstract List<Manga> parseSearchFromHtml(String unparsedHtml);
// Given the URL of a manga and the result of the request, return the details of the manga
protected abstract Manga parseHtmlToManga(String mangaUrl, String unparsedHtml);
// Given the result of the request to mangas' chapters, return a list of chapters
protected abstract List<Chapter> parseHtmlToChapters(String unparsedHtml);
// Given the result of the request to a chapter, return the list of URLs of the chapter
protected abstract List<String> parseHtmlToPageUrls(String unparsedHtml);
// Given the result of the request to a chapter's page, return the URL of the image of the page
protected abstract String parseHtmlToImageUrl(String unparsedHtml);
// Login related methods, shouldn't be overriden if the source doesn't require it
public Observable<Boolean> login(String username, String password) {
throw new UnsupportedOperationException("Not implemented");
}
public boolean isLogged() {
throw new UnsupportedOperationException("Not implemented");
}
protected boolean isAuthenticationSuccessful(Response response) {
throw new UnsupportedOperationException("Not implemented");
}
// Default fields, they can be overriden by sources' implementation
// Get the URL to the details of a manga, useful if the source provides some kind of API or fast calls
protected String overrideMangaUrl(String defaultMangaUrl) {
return defaultMangaUrl;
}
// Get the URL of the first page that contains a source image and the page list
protected String overrideChapterPageUrl(String defaultPageUrl) {
return defaultPageUrl;
}
// Get the URL of the remaining pages that contains source images
protected String overrideRemainingPagesUrl(String defaultPageUrl) {
return defaultPageUrl;
}
// Default headers, it can be overriden by children or just add new keys
protected Headers.Builder headersBuilder() {
Headers.Builder builder = new Headers.Builder();
builder.add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)");
return builder;
}
// Number of images to download at the same time. 3 by default
protected int overrideNumberOfConcurrentPageDownloads() {
return 3;
}
}

View File

@@ -0,0 +1,161 @@
package eu.kanade.mangafeed.data.source.base;
import android.content.Context;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.Response;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import eu.kanade.mangafeed.App;
import eu.kanade.mangafeed.data.cache.CacheManager;
import eu.kanade.mangafeed.data.network.NetworkHelper;
import eu.kanade.mangafeed.data.preference.PreferencesHelper;
import eu.kanade.mangafeed.data.database.models.Chapter;
import eu.kanade.mangafeed.data.database.models.Manga;
import eu.kanade.mangafeed.data.source.model.Page;
import rx.Observable;
import rx.schedulers.Schedulers;
public abstract class Source extends BaseSource {
@Inject protected NetworkHelper mNetworkService;
@Inject protected CacheManager mCacheManager;
@Inject protected PreferencesHelper prefs;
protected Headers mRequestHeaders;
public Source(Context context) {
App.get(context).getComponent().inject(this);
mRequestHeaders = headersBuilder().build();
}
// Get the most popular mangas from the source
public Observable<List<Manga>> pullPopularMangasFromNetwork(int page) {
String url = getUrlFromPageNumber(page);
return mNetworkService
.getStringResponse(url, mRequestHeaders, null)
.flatMap(response -> Observable.just(parsePopularMangasFromHtml(response)));
}
// Get mangas from the source with a query
public Observable<List<Manga>> searchMangasFromNetwork(String query, int page) {
return mNetworkService
.getStringResponse(getSearchUrl(query, page), mRequestHeaders, null)
.flatMap(response -> Observable.just(parseSearchFromHtml(response)));
}
// Get manga details from the source
public Observable<Manga> pullMangaFromNetwork(final String mangaUrl) {
return mNetworkService
.getStringResponse(overrideMangaUrl(mangaUrl), mRequestHeaders, null)
.flatMap(unparsedHtml -> Observable.just(parseHtmlToManga(mangaUrl, unparsedHtml)));
}
// Get chapter list of a manga from the source
public Observable<List<Chapter>> pullChaptersFromNetwork(String mangaUrl) {
return mNetworkService
.getStringResponse(mangaUrl, mRequestHeaders, null)
.flatMap(unparsedHtml ->
Observable.just(parseHtmlToChapters(unparsedHtml)));
}
public Observable<List<Page>> getCachedPageListOrPullFromNetwork(final String chapterUrl) {
return mCacheManager.getPageUrlsFromDiskCache(chapterUrl)
.onErrorResumeNext(throwable -> {
return pullPageListFromNetwork(chapterUrl);
})
.onBackpressureBuffer();
}
public Observable<List<Page>> pullPageListFromNetwork(final String chapterUrl) {
return mNetworkService
.getStringResponse(overrideChapterPageUrl(chapterUrl), mRequestHeaders, null)
.flatMap(unparsedHtml -> {
List<String> pageUrls = parseHtmlToPageUrls(unparsedHtml);
return Observable.just(getFirstImageFromPageUrls(pageUrls, unparsedHtml));
});
}
// Get the URLs of the images of a chapter
public Observable<Page> getRemainingImageUrlsFromPageList(final List<Page> pages) {
return Observable.from(pages)
.filter(page -> page.getImageUrl() == null)
.window(overrideNumberOfConcurrentPageDownloads())
.concatMap(batchedPages -> batchedPages.concatMap(this::getImageUrlFromPage));
}
private Observable<Page> getImageUrlFromPage(final Page page) {
page.setStatus(Page.LOAD_PAGE);
return mNetworkService
.getStringResponse(overrideRemainingPagesUrl(page.getUrl()), mRequestHeaders, null)
.flatMap(unparsedHtml -> Observable.just(parseHtmlToImageUrl(unparsedHtml)))
.onErrorResumeNext(e -> {
page.setStatus(Page.ERROR);
return Observable.just(null);
})
.flatMap(imageUrl -> {
page.setImageUrl(imageUrl);
return Observable.just(page);
})
.subscribeOn(Schedulers.io());
}
public Observable<Page> getCachedImage(final Page page) {
Observable<Page> obs = Observable.just(page);
if (page.getImageUrl() == null)
return obs;
if (!mCacheManager.isImageInCache(page.getImageUrl())) {
page.setStatus(Page.DOWNLOAD_IMAGE);
obs = cacheImage(page);
}
return obs.flatMap(p -> {
page.setImagePath(mCacheManager.getImagePath(page.getImageUrl()));
page.setStatus(Page.READY);
return Observable.just(page);
}).onErrorResumeNext(e -> {
page.setStatus(Page.ERROR);
return Observable.just(page);
});
}
private Observable<Page> cacheImage(final Page page) {
return getImageProgressResponse(page)
.flatMap(resp -> {
if (!mCacheManager.putImageToDiskCache(page.getImageUrl(), resp)) {
throw new IllegalStateException("Unable to save image");
}
return Observable.just(page);
});
}
public Observable<Response> getImageProgressResponse(final Page page) {
return mNetworkService.getProgressResponse(page.getImageUrl(), mRequestHeaders, page);
}
public void savePageList(String chapterUrl, List<Page> pages) {
if (pages != null)
mCacheManager.putPageUrlsToDiskCache(chapterUrl, pages);
}
private List<Page> convertToPages(List<String> pageUrls) {
List<Page> pages = new ArrayList<>();
for (int i = 0; i < pageUrls.size(); i++) {
pages.add(new Page(i, pageUrls.get(i)));
}
return pages;
}
private List<Page> getFirstImageFromPageUrls(List<String> pageUrls, String unparsedHtml) {
List<Page> pages = convertToPages(pageUrls);
String firstImage = parseHtmlToImageUrl(unparsedHtml);
pages.get(0).setImageUrl(firstImage);
return pages;
}
}

View File

@@ -1,9 +1,9 @@
package eu.kanade.mangafeed.data.models;
package eu.kanade.mangafeed.data.source.model;
import eu.kanade.mangafeed.data.helpers.NetworkHelper;
import eu.kanade.mangafeed.data.network.ProgressListener;
import rx.subjects.PublishSubject;
public class Page implements NetworkHelper.ProgressListener {
public class Page implements ProgressListener {
private int pageNumber;
private String url;

View File

@@ -0,0 +1,402 @@
package eu.kanade.mangafeed.data.source.online.english;
import android.content.Context;
import com.squareup.okhttp.FormEncodingBuilder;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.Response;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.net.HttpCookie;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import eu.kanade.mangafeed.data.source.SourceManager;
import eu.kanade.mangafeed.data.database.models.Chapter;
import eu.kanade.mangafeed.data.database.models.Manga;
import eu.kanade.mangafeed.data.source.base.Source;
import rx.Observable;
public class Batoto extends Source {
public static final String NAME = "Batoto (EN)";
public static final String BASE_URL = "http://bato.to";
public static final String INITIAL_UPDATE_URL =
"http://bato.to/search_ajax?order_cond=views&order=desc&p=";
public static final String INITIAL_SEARCH_URL = "http://bato.to/search_ajax?";
public static final String INITIAL_PAGE_URL = "http://bato.to/areader?";
public static final String LOGIN_URL =
"https://bato.to/forums/index.php?app=core&module=global&section=login";
public Batoto(Context context) {
super(context);
}
@Override
public String getName() {
return NAME;
}
@Override
protected Headers.Builder headersBuilder() {
Headers.Builder builder = super.headersBuilder();
builder.add("Cookie", "lang_option=English");
builder.add("Referer", "http://bato.to/reader");
return builder;
}
public Observable<List<String>> getGenres() {
List<String> genres = new ArrayList<>(38);
genres.add("4-Koma");
genres.add("Action");
genres.add("Adventure");
genres.add("Award Winning");
genres.add("Comedy");
genres.add("Cooking");
genres.add("Doujinshi");
genres.add("Drama");
genres.add("Ecchi");
genres.add("Fantasy");
genres.add("Gender Bender");
genres.add("Harem");
genres.add("Historical");
genres.add("Horror");
genres.add("Josei");
genres.add("Martial Arts");
genres.add("Mecha");
genres.add("Medical");
genres.add("Music");
genres.add("Mystery");
genres.add("One Shot");
genres.add("Psychological");
genres.add("Romance");
genres.add("School Life");
genres.add("Sci-fi");
genres.add("Seinen");
genres.add("Shoujo");
genres.add("Shoujo Ai");
genres.add("Shounen");
genres.add("Shounen Ai");
genres.add("Slice of Life");
genres.add("Smut");
genres.add("Sports");
genres.add("Supernatural");
genres.add("Tragedy");
genres.add("Webtoon");
genres.add("Yaoi");
genres.add("Yuri");
return Observable.just(genres);
}
@Override
public int getSourceId() {
return SourceManager.BATOTO;
}
@Override
public boolean isLoginRequired() {
return true;
}
@Override
protected String getUrlFromPageNumber(int page) {
return INITIAL_UPDATE_URL + page;
}
@Override
protected String getSearchUrl(String query, int page) {
return INITIAL_SEARCH_URL + "name=" + query + "&p=" + page;
}
@Override
protected String overrideMangaUrl(String defaultMangaUrl) {
String mangaId = defaultMangaUrl.substring(defaultMangaUrl.lastIndexOf("r") + 1);
return "http://bato.to/comic_pop?id=" + mangaId;
}
@Override
protected String overrideChapterPageUrl(String defaultPageUrl) {
String id = defaultPageUrl.substring(defaultPageUrl.indexOf("#") + 1);
return INITIAL_PAGE_URL + "id=" + id + "&p=1";
}
@Override
protected String overrideRemainingPagesUrl(String defaultPageUrl) {
int start = defaultPageUrl.indexOf("#") + 1;
int end = defaultPageUrl.indexOf("_", start);
String id = defaultPageUrl.substring(start, end);
return INITIAL_PAGE_URL + "id=" + id + "&p=" + defaultPageUrl.substring(end+1);
}
private List<Manga> parseMangasFromHtml(String unparsedHtml) {
if (unparsedHtml.contains("No (more) comics found!")) {
return new ArrayList<>();
}
Document parsedDocument = Jsoup.parse(unparsedHtml);
List<Manga> updatedMangaList = new ArrayList<>();
Elements updatedHtmlBlocks = parsedDocument.select("tr:not([id]):not([class])");
for (Element currentHtmlBlock : updatedHtmlBlocks) {
Manga currentlyUpdatedManga = constructMangaFromHtmlBlock(currentHtmlBlock);
updatedMangaList.add(currentlyUpdatedManga);
}
return updatedMangaList;
}
@Override
public List<Manga> parsePopularMangasFromHtml(String unparsedHtml) {
return parseMangasFromHtml(unparsedHtml);
}
@Override
protected List<Manga> parseSearchFromHtml(String unparsedHtml) {
return parseMangasFromHtml(unparsedHtml);
}
private Manga constructMangaFromHtmlBlock(Element htmlBlock) {
Manga mangaFromHtmlBlock = new Manga();
Element urlElement = htmlBlock.select("a[href^=http://bato.to]").first();
Element nameElement = urlElement;
Element updateElement = htmlBlock.select("td").get(5);
mangaFromHtmlBlock.source = getSourceId();
if (urlElement != null) {
String fieldUrl = urlElement.attr("href");
mangaFromHtmlBlock.url = fieldUrl;
}
if (nameElement != null) {
String fieldName = nameElement.text().trim();
mangaFromHtmlBlock.title = fieldName;
}
if (updateElement != null) {
long fieldUpdate = parseUpdateFromElement(updateElement);
mangaFromHtmlBlock.last_update = fieldUpdate;
}
return mangaFromHtmlBlock;
}
private long parseUpdateFromElement(Element updateElement) {
String updatedDateAsString = updateElement.text();
try {
Date specificDate = new SimpleDateFormat("dd MMMMM yyyy - hh:mm a", Locale.ENGLISH).parse(updatedDateAsString);
return specificDate.getTime();
} catch (ParseException e) {
// Do Nothing.
}
return 0;
}
@Override
protected Manga parseHtmlToManga(String mangaUrl, String unparsedHtml) {
Document parsedDocument = Jsoup.parse(unparsedHtml);
Elements artistElements = parsedDocument.select("a[href^=http://bato.to/search?artist_name]");
Element descriptionElement = parsedDocument.select("tr").get(5);
Elements genreElements = parsedDocument.select("img[src=http://bato.to/forums/public/style_images/master/bullet_black.png]");
Element thumbnailUrlElement = parsedDocument.select("img[src^=http://img.bato.to/forums/uploads/]").first();
Manga newManga = new Manga();
newManga.url = mangaUrl;
if (artistElements != null) {
newManga.author = artistElements.get(0).text();
if (artistElements.size() > 1) {
newManga.artist = artistElements.get(1).text();
} else {
newManga.artist = newManga.author;
}
}
if (descriptionElement != null) {
String fieldDescription = descriptionElement.text().substring("Description:".length()).trim();
newManga.description = fieldDescription;
}
if (genreElements != null) {
String fieldGenres = "";
for (int index = 0; index < genreElements.size(); index++) {
String currentGenre = genreElements.get(index).attr("alt");
if (index < genreElements.size() - 1) {
fieldGenres += currentGenre + ", ";
} else {
fieldGenres += currentGenre;
}
}
newManga.genre = fieldGenres;
}
if (thumbnailUrlElement != null) {
String fieldThumbnailUrl = thumbnailUrlElement.attr("src");
newManga.thumbnail_url = fieldThumbnailUrl;
}
boolean fieldCompleted = unparsedHtml.contains("<td>Complete</td>");
//TODO fix
newManga.status = fieldCompleted + "";
newManga.initialized = true;
return newManga;
}
@Override
protected List<Chapter> parseHtmlToChapters(String unparsedHtml) {
Document parsedDocument = Jsoup.parse(unparsedHtml);
List<Chapter> chapterList = new ArrayList<>();
Elements chapterElements = parsedDocument.select("tr.row.lang_English.chapter_row");
for (Element chapterElement : chapterElements) {
Chapter currentChapter = constructChapterFromHtmlBlock(chapterElement);
chapterList.add(currentChapter);
}
//saveChaptersToDatabase(chapterList, mangaUrl);
return chapterList;
}
private Chapter constructChapterFromHtmlBlock(Element chapterElement) {
Chapter newChapter = Chapter.newChapter();
Element urlElement = chapterElement.select("a[href^=http://bato.to/reader").first();
Element nameElement = urlElement;
Element dateElement = chapterElement.select("td").get(4);
if (urlElement != null) {
String fieldUrl = urlElement.attr("href");
newChapter.url = fieldUrl;
}
if (nameElement != null) {
String fieldName = nameElement.text().trim();
newChapter.name = fieldName;
}
if (dateElement != null) {
long fieldDate = parseDateFromElement(dateElement);
newChapter.date_upload = fieldDate;
}
newChapter.date_fetch = new Date().getTime();
return newChapter;
}
private long parseDateFromElement(Element dateElement) {
String dateAsString = dateElement.text();
try {
Date specificDate = new SimpleDateFormat("dd MMMMM yyyy - hh:mm a", Locale.ENGLISH).parse(dateAsString);
return specificDate.getTime();
} catch (ParseException e) {
// Do Nothing.
}
return 0;
}
@Override
protected List<String> parseHtmlToPageUrls(String unparsedHtml) {
Document parsedDocument = Jsoup.parse(unparsedHtml);
List<String> pageUrlList = new ArrayList<>();
Elements pageUrlElements = parsedDocument.getElementById("page_select").getElementsByTag("option");
for (Element pageUrlElement : pageUrlElements) {
pageUrlList.add(pageUrlElement.attr("value"));
}
return pageUrlList;
}
@Override
protected String parseHtmlToImageUrl(String unparsedHtml) {
int beginIndex = unparsedHtml.indexOf("<img id=\"comic_page\"");
int endIndex = unparsedHtml.indexOf("</a>", beginIndex);
String trimmedHtml = unparsedHtml.substring(beginIndex, endIndex);
Document parsedDocument = Jsoup.parse(trimmedHtml);
Element imageElement = parsedDocument.getElementById("comic_page");
return imageElement.attr("src");
}
@Override
public Observable<Boolean> login(String username, String password) {
return mNetworkService.getStringResponse(LOGIN_URL, mRequestHeaders, null)
.flatMap(response -> doLogin(response, username, password))
.map(this::isAuthenticationSuccessful);
}
private Observable<Response> doLogin(String response, String username, String password) {
Document doc = Jsoup.parse(response);
Element form = doc.select("#login").first();
String postUrl = form.attr("action");
FormEncodingBuilder formBody = new FormEncodingBuilder();
Element authKey = form.select("input[name=auth_key").first();
formBody.add(authKey.attr("name"), authKey.attr("value"));
formBody.add("ips_username", username);
formBody.add("ips_password", password);
formBody.add("invisible", "1");
formBody.add("rememberMe", "1");
return mNetworkService.postData(postUrl, formBody.build(), mRequestHeaders);
}
@Override
protected boolean isAuthenticationSuccessful(Response response) {
return response.priorResponse() != null && response.priorResponse().code() == 302;
}
@Override
public boolean isLogged() {
try {
for ( HttpCookie cookie : mNetworkService.getCookies().get(new URI(BASE_URL)) ) {
if (cookie.getName().equals("pass_hash"))
return true;
}
} catch (URISyntaxException e) {
e.printStackTrace();
}
return false;
}
@Override
public Observable<List<Chapter>> pullChaptersFromNetwork(String mangaUrl) {
Observable<List<Chapter>> observable;
if (!isLogged()) {
observable = login(prefs.getSourceUsername(this), prefs.getSourcePassword(this))
.flatMap(result -> super.pullChaptersFromNetwork(mangaUrl));
}
else {
observable = super.pullChaptersFromNetwork(mangaUrl);
}
return observable;
}
}

View File

@@ -0,0 +1,179 @@
package eu.kanade.mangafeed.data.source.online.english;
import android.content.Context;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.List;
import eu.kanade.mangafeed.data.source.SourceManager;
import eu.kanade.mangafeed.data.database.models.Chapter;
import eu.kanade.mangafeed.data.database.models.Manga;
import eu.kanade.mangafeed.data.source.base.Source;
public class Mangafox extends Source {
public static final String NAME = "Mangafox (EN)";
private static final String INITIAL_UPDATE_URL = "http://mangafox.me/directory/";
private static final String INITIAL_SEARCH_URL =
"http://mangafox.me/search.php?name_method=cw&advopts=1&order=az&sort=name";
public Mangafox(Context context) {
super(context);
}
@Override
public String getName() {
return NAME;
}
@Override
public int getSourceId() {
return SourceManager.MANGAFOX;
}
@Override
public boolean isLoginRequired() {
return false;
}
@Override
protected String getUrlFromPageNumber(int page) {
return INITIAL_UPDATE_URL + page + ".htm";
}
@Override
public List<Manga> parsePopularMangasFromHtml(String unparsedHtml) {
Document parsedDocument = Jsoup.parse(unparsedHtml);
List<Manga> mangaList = new ArrayList<>();
Elements mangaHtmlBlocks = parsedDocument.select("div#mangalist > ul.list > li");
for (Element currentHtmlBlock : mangaHtmlBlocks) {
Manga currentManga = constructPopularMangaFromHtmlBlock(currentHtmlBlock);
mangaList.add(currentManga);
}
return mangaList;
}
private Manga constructPopularMangaFromHtmlBlock(Element htmlBlock) {
Manga mangaFromHtmlBlock = new Manga();
mangaFromHtmlBlock.source = getSourceId();
Element urlElement = htmlBlock.select("a.title").first();
if (urlElement != null) {
mangaFromHtmlBlock.url = urlElement.attr("href");
mangaFromHtmlBlock.title = urlElement.text();
}
return mangaFromHtmlBlock;
}
@Override
protected String getSearchUrl(String query, int page) {
return INITIAL_SEARCH_URL + "&name=" + query + "&page=" + page;
}
@Override
protected List<Manga> parseSearchFromHtml(String unparsedHtml) {
Document parsedDocument = Jsoup.parse(unparsedHtml);
List<Manga> mangaList = new ArrayList<>();
Elements mangaHtmlBlocks = parsedDocument.select("table#listing > tbody > tr:gt(0)");
for (Element currentHtmlBlock : mangaHtmlBlocks) {
Manga currentManga = constructSearchMangaFromHtmlBlock(currentHtmlBlock);
mangaList.add(currentManga);
}
return mangaList;
}
private Manga constructSearchMangaFromHtmlBlock(Element htmlBlock) {
Manga mangaFromHtmlBlock = new Manga();
mangaFromHtmlBlock.source = getSourceId();
Element urlElement = htmlBlock.select("a.series_preview").first();
if (urlElement != null) {
mangaFromHtmlBlock.url = urlElement.attr("href");
mangaFromHtmlBlock.title = urlElement.text();
}
return mangaFromHtmlBlock;
}
@Override
protected Manga parseHtmlToManga(String mangaUrl, String unparsedHtml) {
Document parsedDocument = Jsoup.parse(unparsedHtml);
Element infoElement = parsedDocument.select("div#title").first();
Element titleElement = infoElement.select("h2 > a").first();
Element rowElement = infoElement.select("table > tbody > tr:eq(1)").first();
Element authorElement = rowElement.select("td:eq(1)").first();
Element artistElement = rowElement.select("td:eq(2)").first();
Element genreElement = rowElement.select("td:eq(3)").first();
Element descriptionElement = infoElement.select("p.summary").first();
Element thumbnailUrlElement = parsedDocument.select("div.cover > img").first();
Manga newManga = new Manga();
newManga.url = mangaUrl;
if (titleElement != null) {
String title = titleElement.text();
// Strip the last word
title = title.substring(0, title.lastIndexOf(" "));
newManga.title = title;
}
if (artistElement != null) {
String fieldArtist = artistElement.text();
newManga.artist = fieldArtist;
}
if (authorElement != null) {
String fieldAuthor = authorElement.text();
newManga.author = fieldAuthor;
}
if (descriptionElement != null) {
String fieldDescription = descriptionElement.text();
newManga.description = fieldDescription;
}
if (genreElement != null) {
String fieldGenre = genreElement.text();
newManga.genre = fieldGenre;
}
if (thumbnailUrlElement != null) {
String fieldThumbnailUrl = thumbnailUrlElement.attr("src");
newManga.thumbnail_url = fieldThumbnailUrl;
}
// if (statusElement != null) {
// boolean fieldCompleted = statusElement.text().contains("Completed");
// newManga.status = fieldCompleted + "";
// }
newManga.initialized = true;
return newManga;
}
@Override
protected List<Chapter> parseHtmlToChapters(String unparsedHtml) {
return null;
}
@Override
protected List<String> parseHtmlToPageUrls(String unparsedHtml) {
return null;
}
@Override
protected String parseHtmlToImageUrl(String unparsedHtml) {
return null;
}
}

View File

@@ -0,0 +1,374 @@
package eu.kanade.mangafeed.data.source.online.english;
import android.content.Context;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import eu.kanade.mangafeed.data.source.SourceManager;
import eu.kanade.mangafeed.data.database.models.Chapter;
import eu.kanade.mangafeed.data.database.models.Manga;
import eu.kanade.mangafeed.data.source.base.Source;
import rx.Observable;
public class Mangahere extends Source {
public static final String NAME = "Mangahere (EN)";
public static final String BASE_URL = "www.mangahere.co";
private static final String INITIAL_UPDATE_URL = "http://www.mangahere.co/directory/";
private static final String INITIAL_SEARCH_URL = "http://www.mangahere.co/search.php?";
public Mangahere(Context context) {
super(context);
}
@Override
public String getName() {
return NAME;
}
@Override
public int getSourceId() {
return SourceManager.MANGAHERE;
}
@Override
protected String getUrlFromPageNumber(int page) {
return INITIAL_UPDATE_URL + page + ".htm?views.za";
}
@Override
protected String getSearchUrl(String query, int page) {
return INITIAL_SEARCH_URL + "name=" + query + "&page=" + page;
}
@Override
public boolean isLoginRequired() {
return false;
}
public Observable<List<String>> getGenres() {
List<String> genres = new ArrayList<>(30);
genres.add("Action");
genres.add("Adventure");
genres.add("Comedy");
genres.add("Drama");
genres.add("Ecchi");
genres.add("Fantasy");
genres.add("Gender Bender");
genres.add("Harem");
genres.add("Historical");
genres.add("Horror");
genres.add("Josei");
genres.add("Martial Arts");
genres.add("Mature");
genres.add("Mecha");
genres.add("Mystery");
genres.add("One Shot");
genres.add("Psychological");
genres.add("Romance");
genres.add("School Life");
genres.add("Sci-fi");
genres.add("Seinen");
genres.add("Shoujo");
genres.add("Shoujo Ai");
genres.add("Shounen");
genres.add("Shounen Ai");
genres.add("Slice of Life");
genres.add("Sports");
genres.add("Supernatural");
genres.add("Tragedy");
genres.add("Yaoi");
genres.add("Yuri");
return Observable.just(genres);
}
@Override
public List<Manga> parsePopularMangasFromHtml(String unparsedHtml) {
Document parsedDocument = Jsoup.parse(unparsedHtml);
List<Manga> mangaList = new ArrayList<>();
Elements mangaHtmlBlocks = parsedDocument.select("div.directory_list > ul > li");
for (Element currentHtmlBlock : mangaHtmlBlocks) {
Manga currentManga = constructPopularMangaFromHtmlBlock(currentHtmlBlock);
mangaList.add(currentManga);
}
return mangaList;
}
private Manga constructPopularMangaFromHtmlBlock(Element htmlBlock) {
Manga mangaFromHtmlBlock = new Manga();
mangaFromHtmlBlock.source = getSourceId();
Element urlElement = htmlBlock.select("div.title > a").first();
if (urlElement != null) {
mangaFromHtmlBlock.url = urlElement.attr("href");
mangaFromHtmlBlock.title = urlElement.attr("title");
}
return mangaFromHtmlBlock;
}
@Override
protected List<Manga> parseSearchFromHtml(String unparsedHtml) {
Document parsedDocument = Jsoup.parse(unparsedHtml);
List<Manga> mangaList = new ArrayList<>();
Elements mangaHtmlBlocks = parsedDocument.select("div.result_search > dl");
for (Element currentHtmlBlock : mangaHtmlBlocks) {
Manga currentManga = constructSearchMangaFromHtmlBlock(currentHtmlBlock);
mangaList.add(currentManga);
}
return mangaList;
}
private Manga constructSearchMangaFromHtmlBlock(Element htmlBlock) {
Manga mangaFromHtmlBlock = new Manga();
mangaFromHtmlBlock.source = getSourceId();
Element urlElement = htmlBlock.select("a.manga_info").first();
if (urlElement != null) {
mangaFromHtmlBlock.url = urlElement.attr("href");
mangaFromHtmlBlock.title = urlElement.text();
}
return mangaFromHtmlBlock;
}
private long parseUpdateFromElement(Element updateElement) {
String updatedDateAsString = updateElement.text();
if (updatedDateAsString.contains("Today")) {
Calendar today = Calendar.getInstance();
today.set(Calendar.HOUR_OF_DAY, 0);
today.set(Calendar.MINUTE, 0);
today.set(Calendar.SECOND, 0);
today.set(Calendar.MILLISECOND, 0);
try {
Date withoutDay = new SimpleDateFormat("MMM d, yyyy h:mma", Locale.ENGLISH).parse(updatedDateAsString.replace("Today", ""));
return today.getTimeInMillis() + withoutDay.getTime();
} catch (ParseException e) {
return today.getTimeInMillis();
}
} else if (updatedDateAsString.contains("Yesterday")) {
Calendar yesterday = Calendar.getInstance();
yesterday.add(Calendar.DATE, -1);
yesterday.set(Calendar.HOUR_OF_DAY, 0);
yesterday.set(Calendar.MINUTE, 0);
yesterday.set(Calendar.SECOND, 0);
yesterday.set(Calendar.MILLISECOND, 0);
try {
Date withoutDay = new SimpleDateFormat("MMM d, yyyy h:mma", Locale.ENGLISH).parse(updatedDateAsString.replace("Yesterday", ""));
return yesterday.getTimeInMillis() + withoutDay.getTime();
} catch (ParseException e) {
return yesterday.getTimeInMillis();
}
} else {
try {
Date specificDate = new SimpleDateFormat("MMM d, yyyy h:mma", Locale.ENGLISH).parse(updatedDateAsString);
return specificDate.getTime();
} catch (ParseException e) {
// Do Nothing.
}
}
return 0;
}
public Manga parseHtmlToManga(String mangaUrl, String unparsedHtml) {
int beginIndex = unparsedHtml.indexOf("<ul class=\"detail_topText\">");
int endIndex = unparsedHtml.indexOf("</ul>", beginIndex);
String trimmedHtml = unparsedHtml.substring(beginIndex, endIndex);
Document parsedDocument = Jsoup.parse(trimmedHtml);
Elements detailElements = parsedDocument.select("ul.detail_topText li");
Element artistElement = parsedDocument.select("a[href^=http://www.mangahere.co/artist/]").first();
Element authorElement = parsedDocument.select("a[href^=http://www.mangahere.co/author/]").first();
Element descriptionElement = detailElements.select("#show").first();
Element genreElement = detailElements.get(3);
Element statusElement = detailElements.get(6);
Manga newManga = new Manga();
newManga.url = mangaUrl;
if (artistElement != null) {
String fieldArtist = artistElement.text();
newManga.artist = fieldArtist;
}
if (authorElement != null) {
String fieldAuthor = authorElement.text();
newManga.author = fieldAuthor;
}
if (descriptionElement != null) {
String fieldDescription = descriptionElement.text().substring(0, descriptionElement.text().length() - "Show less".length());
newManga.description = fieldDescription;
}
if (genreElement != null) {
String fieldGenre = genreElement.text().substring("Genre(s):".length());
newManga.genre = fieldGenre;
}
if (statusElement != null) {
boolean fieldCompleted = statusElement.text().contains("Completed");
newManga.status = fieldCompleted + "";
}
beginIndex = unparsedHtml.indexOf("<img");
endIndex = unparsedHtml.indexOf("/>", beginIndex);
trimmedHtml = unparsedHtml.substring(beginIndex, endIndex + 2);
parsedDocument = Jsoup.parse(trimmedHtml);
Element thumbnailUrlElement = parsedDocument.select("img").first();
if (thumbnailUrlElement != null) {
String fieldThumbnailUrl = thumbnailUrlElement.attr("src");
newManga.thumbnail_url = fieldThumbnailUrl;
}
newManga.initialized = true;
return newManga;
}
@Override
public List<Chapter> parseHtmlToChapters(String unparsedHtml) {
int beginIndex = unparsedHtml.indexOf("<ul>");
int endIndex = unparsedHtml.indexOf("</ul>", beginIndex);
String trimmedHtml = unparsedHtml.substring(beginIndex, endIndex);
Document parsedDocument = Jsoup.parse(trimmedHtml);
List<Chapter> chapterList = new ArrayList<Chapter>();
Elements chapterElements = parsedDocument.getElementsByTag("li");
for (Element chapterElement : chapterElements) {
Chapter currentChapter = constructChapterFromHtmlBlock(chapterElement);
chapterList.add(currentChapter);
}
return chapterList;
}
private Chapter constructChapterFromHtmlBlock(Element chapterElement) {
Chapter newChapter = Chapter.newChapter();
Element urlElement = chapterElement.select("a").first();
Element nameElement = chapterElement.select("a").first();
Element dateElement = chapterElement.select("span.right").first();
if (urlElement != null) {
String fieldUrl = urlElement.attr("href");
newChapter.url = fieldUrl;
}
if (nameElement != null) {
String fieldName = nameElement.text();
newChapter.name = fieldName;
}
if (dateElement != null) {
long fieldDate = parseDateFromElement(dateElement);
newChapter.date_upload = fieldDate;
}
newChapter.date_fetch = new Date().getTime();
return newChapter;
}
private long parseDateFromElement(Element dateElement) {
String dateAsString = dateElement.text();
if (dateAsString.contains("Today")) {
Calendar today = Calendar.getInstance();
today.set(Calendar.HOUR_OF_DAY, 0);
today.set(Calendar.MINUTE, 0);
today.set(Calendar.SECOND, 0);
today.set(Calendar.MILLISECOND, 0);
try {
Date withoutDay = new SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(dateAsString.replace("Today", ""));
return today.getTimeInMillis() + withoutDay.getTime();
} catch (ParseException e) {
return today.getTimeInMillis();
}
} else if (dateAsString.contains("Yesterday")) {
Calendar yesterday = Calendar.getInstance();
yesterday.add(Calendar.DATE, -1);
yesterday.set(Calendar.HOUR_OF_DAY, 0);
yesterday.set(Calendar.MINUTE, 0);
yesterday.set(Calendar.SECOND, 0);
yesterday.set(Calendar.MILLISECOND, 0);
try {
Date withoutDay = new SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(dateAsString.replace("Yesterday", ""));
return yesterday.getTimeInMillis() + withoutDay.getTime();
} catch (ParseException e) {
return yesterday.getTimeInMillis();
}
} else {
try {
Date date = new SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(dateAsString);
return date.getTime();
} catch (ParseException e) {
// Do Nothing.
}
}
return 0;
}
@Override
public List<String> parseHtmlToPageUrls(String unparsedHtml) {
int beginIndex = unparsedHtml.indexOf("<div class=\"go_page clearfix\">");
int endIndex = unparsedHtml.indexOf("</div>", beginIndex);
String trimmedHtml = unparsedHtml.substring(beginIndex, endIndex);
Document parsedDocument = Jsoup.parse(trimmedHtml);
List<String> pageUrlList = new ArrayList<String>();
Elements pageUrlElements = parsedDocument.select("select.wid60").first().getElementsByTag("option");
for (Element pageUrlElement : pageUrlElements) {
pageUrlList.add(pageUrlElement.attr("value"));
}
return pageUrlList;
}
@Override
public String parseHtmlToImageUrl(String unparsedHtml) {
int beginIndex = unparsedHtml.indexOf("<section class=\"read_img\" id=\"viewer\">");
int endIndex = unparsedHtml.indexOf("</section>", beginIndex);
String trimmedHtml = unparsedHtml.substring(beginIndex, endIndex);
Document parsedDocument = Jsoup.parse(trimmedHtml);
Element imageElement = parsedDocument.getElementById("image");
return imageElement.attr("src");
}
}

View File

@@ -1,4 +1,4 @@
package eu.kanade.mangafeed.data.services;
package eu.kanade.mangafeed.data.sync;
import android.app.Service;
import android.content.BroadcastReceiver;
@@ -15,9 +15,9 @@ import javax.inject.Inject;
import eu.kanade.mangafeed.App;
import eu.kanade.mangafeed.BuildConfig;
import eu.kanade.mangafeed.R;
import eu.kanade.mangafeed.data.helpers.DatabaseHelper;
import eu.kanade.mangafeed.data.helpers.SourceManager;
import eu.kanade.mangafeed.data.models.Manga;
import eu.kanade.mangafeed.data.database.DatabaseHelper;
import eu.kanade.mangafeed.data.source.SourceManager;
import eu.kanade.mangafeed.data.database.models.Manga;
import eu.kanade.mangafeed.util.AndroidComponentUtil;
import eu.kanade.mangafeed.util.NetworkUtil;
import eu.kanade.mangafeed.util.NotificationUtil;