Use network cache

This commit is contained in:
inorichi 2016-02-05 20:18:39 +01:00
parent eec2dcd981
commit 6435eeb251
5 changed files with 37 additions and 18 deletions

View File

@ -84,7 +84,7 @@ public class DownloadManager {
if (finished) { if (finished) {
DownloadService.stop(context); DownloadService.stop(context);
} }
}, e -> Timber.e(e.getCause(), e.getMessage())); }, e -> DownloadService.stop(context));
if (!isRunning) { if (!isRunning) {
isRunning = true; isRunning = true;

View File

@ -83,7 +83,7 @@ public class MyAnimeList extends MangaSyncService {
public Observable<Boolean> login(String username, String password) { public Observable<Boolean> login(String username, String password) {
createHeaders(username, password); createHeaders(username, password);
return networkService.getResponse(getLoginUrl(), headers, null) return networkService.getResponse(getLoginUrl(), headers, false)
.map(response -> response.code() == 200); .map(response -> response.code() == 200);
} }
@ -101,7 +101,7 @@ public class MyAnimeList extends MangaSyncService {
} }
public Observable<List<MangaSync>> search(String query) { public Observable<List<MangaSync>> search(String query) {
return networkService.getStringResponse(getSearchUrl(query), headers, null) return networkService.getStringResponse(getSearchUrl(query), headers, true)
.map(Jsoup::parse) .map(Jsoup::parse)
.flatMap(doc -> Observable.from(doc.select("entry"))) .flatMap(doc -> Observable.from(doc.select("entry")))
.filter(entry -> !entry.select("type").text().equals("Novel")) .filter(entry -> !entry.select("type").text().equals("Novel"))
@ -126,7 +126,7 @@ public class MyAnimeList extends MangaSyncService {
public Observable<List<MangaSync>> getList() { public Observable<List<MangaSync>> getList() {
// TODO cache this list for a few minutes // TODO cache this list for a few minutes
return networkService.getStringResponse(getListUrl(username), headers, null) return networkService.getStringResponse(getListUrl(username), headers, true)
.map(Jsoup::parse) .map(Jsoup::parse)
.flatMap(doc -> Observable.from(doc.select("manga"))) .flatMap(doc -> Observable.from(doc.select("manga")))
.map(entry -> { .map(entry -> {

View File

@ -7,11 +7,13 @@ import java.io.File;
import java.net.CookieManager; import java.net.CookieManager;
import java.net.CookiePolicy; import java.net.CookiePolicy;
import java.net.CookieStore; import java.net.CookieStore;
import java.util.concurrent.TimeUnit;
import okhttp3.Cache; import okhttp3.Cache;
import okhttp3.CacheControl; import okhttp3.CacheControl;
import okhttp3.FormBody; import okhttp3.FormBody;
import okhttp3.Headers; import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.JavaNetCookieJar; import okhttp3.JavaNetCookieJar;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
@ -22,12 +24,23 @@ import rx.Observable;
public final class NetworkHelper { public final class NetworkHelper {
private OkHttpClient client; private OkHttpClient client;
private OkHttpClient forceCacheClient;
private CookieManager cookieManager; private CookieManager cookieManager;
public final CacheControl NULL_CACHE_CONTROL = new CacheControl.Builder().noCache().build();
public final Headers NULL_HEADERS = new Headers.Builder().build(); public final Headers NULL_HEADERS = new Headers.Builder().build();
public final RequestBody NULL_REQUEST_BODY = new FormBody.Builder().build(); public final RequestBody NULL_REQUEST_BODY = new FormBody.Builder().build();
public final CacheControl CACHE_CONTROL = new CacheControl.Builder()
.maxAge(10, TimeUnit.MINUTES)
.build();
private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = chain -> {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "max-age=" + 600)
.build();
};
private static final int CACHE_SIZE = 5 * 1024 * 1024; // 5 MiB private static final int CACHE_SIZE = 5 * 1024 * 1024; // 5 MiB
private static final String CACHE_DIR_NAME = "network_cache"; private static final String CACHE_DIR_NAME = "network_cache";
@ -42,18 +55,24 @@ public final class NetworkHelper {
.cookieJar(new JavaNetCookieJar(cookieManager)) .cookieJar(new JavaNetCookieJar(cookieManager))
.cache(new Cache(cacheDir, CACHE_SIZE)) .cache(new Cache(cacheDir, CACHE_SIZE))
.build(); .build();
forceCacheClient = client.newBuilder()
.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
.build();
} }
public Observable<Response> getResponse(final String url, final Headers headers, final CacheControl cacheControl) { public Observable<Response> getResponse(final String url, final Headers headers, boolean forceCache) {
return Observable.defer(() -> { return Observable.defer(() -> {
try { try {
OkHttpClient c = forceCache ? forceCacheClient : client;
Request request = new Request.Builder() Request request = new Request.Builder()
.url(url) .url(url)
.cacheControl(cacheControl != null ? cacheControl : NULL_CACHE_CONTROL)
.headers(headers != null ? headers : NULL_HEADERS) .headers(headers != null ? headers : NULL_HEADERS)
.cacheControl(CACHE_CONTROL)
.build(); .build();
return Observable.just(client.newCall(request).execute()); return Observable.just(c.newCall(request).execute());
} catch (Throwable e) { } catch (Throwable e) {
return Observable.error(e); return Observable.error(e);
} }
@ -70,8 +89,8 @@ public final class NetworkHelper {
}); });
} }
public Observable<String> getStringResponse(final String url, final Headers headers, final CacheControl cacheControl) { public Observable<String> getStringResponse(final String url, final Headers headers, boolean forceCache) {
return getResponse(url, headers, cacheControl) return getResponse(url, headers, forceCache)
.flatMap(this::mapResponseToString); .flatMap(this::mapResponseToString);
} }
@ -95,7 +114,7 @@ public final class NetworkHelper {
try { try {
Request request = new Request.Builder() Request request = new Request.Builder()
.url(url) .url(url)
.cacheControl(NULL_CACHE_CONTROL) .cacheControl(CacheControl.FORCE_NETWORK)
.headers(headers != null ? headers : NULL_HEADERS) .headers(headers != null ? headers : NULL_HEADERS)
.build(); .build();

View File

@ -53,7 +53,7 @@ public abstract class Source extends BaseSource {
page.url = getInitialPopularMangasUrl(); page.url = getInitialPopularMangasUrl();
return networkService return networkService
.getStringResponse(page.url, requestHeaders, null) .getStringResponse(page.url, requestHeaders, true)
.map(Jsoup::parse) .map(Jsoup::parse)
.doOnNext(doc -> page.mangas = parsePopularMangasFromHtml(doc)) .doOnNext(doc -> page.mangas = parsePopularMangasFromHtml(doc))
.doOnNext(doc -> page.nextPageUrl = parseNextPopularMangasUrl(doc, page)) .doOnNext(doc -> page.nextPageUrl = parseNextPopularMangasUrl(doc, page))
@ -66,7 +66,7 @@ public abstract class Source extends BaseSource {
page.url = getInitialSearchUrl(query); page.url = getInitialSearchUrl(query);
return networkService return networkService
.getStringResponse(page.url, requestHeaders, null) .getStringResponse(page.url, requestHeaders, true)
.map(Jsoup::parse) .map(Jsoup::parse)
.doOnNext(doc -> page.mangas = parseSearchFromHtml(doc)) .doOnNext(doc -> page.mangas = parseSearchFromHtml(doc))
.doOnNext(doc -> page.nextPageUrl = parseNextSearchUrl(doc, page, query)) .doOnNext(doc -> page.nextPageUrl = parseNextSearchUrl(doc, page, query))
@ -76,14 +76,14 @@ public abstract class Source extends BaseSource {
// Get manga details from the source // Get manga details from the source
public Observable<Manga> pullMangaFromNetwork(final String mangaUrl) { public Observable<Manga> pullMangaFromNetwork(final String mangaUrl) {
return networkService return networkService
.getStringResponse(getBaseUrl() + overrideMangaUrl(mangaUrl), requestHeaders, null) .getStringResponse(getBaseUrl() + overrideMangaUrl(mangaUrl), requestHeaders, true)
.flatMap(unparsedHtml -> Observable.just(parseHtmlToManga(mangaUrl, unparsedHtml))); .flatMap(unparsedHtml -> Observable.just(parseHtmlToManga(mangaUrl, unparsedHtml)));
} }
// Get chapter list of a manga from the source // Get chapter list of a manga from the source
public Observable<List<Chapter>> pullChaptersFromNetwork(final String mangaUrl) { public Observable<List<Chapter>> pullChaptersFromNetwork(final String mangaUrl) {
return networkService return networkService
.getStringResponse(getBaseUrl() + mangaUrl, requestHeaders, null) .getStringResponse(getBaseUrl() + mangaUrl, requestHeaders, false)
.flatMap(unparsedHtml -> { .flatMap(unparsedHtml -> {
List<Chapter> chapters = parseHtmlToChapters(unparsedHtml); List<Chapter> chapters = parseHtmlToChapters(unparsedHtml);
return !chapters.isEmpty() ? return !chapters.isEmpty() ?
@ -102,7 +102,7 @@ public abstract class Source extends BaseSource {
public Observable<List<Page>> pullPageListFromNetwork(final String chapterUrl) { public Observable<List<Page>> pullPageListFromNetwork(final String chapterUrl) {
return networkService return networkService
.getStringResponse(getBaseUrl() + overrideChapterUrl(chapterUrl), requestHeaders, null) .getStringResponse(getBaseUrl() + overrideChapterUrl(chapterUrl), requestHeaders, false)
.flatMap(unparsedHtml -> { .flatMap(unparsedHtml -> {
List<Page> pages = convertToPages(parseHtmlToPageUrls(unparsedHtml)); List<Page> pages = convertToPages(parseHtmlToPageUrls(unparsedHtml));
return !pages.isEmpty() ? return !pages.isEmpty() ?
@ -127,7 +127,7 @@ public abstract class Source extends BaseSource {
public Observable<Page> getImageUrlFromPage(final Page page) { public Observable<Page> getImageUrlFromPage(final Page page) {
page.setStatus(Page.LOAD_PAGE); page.setStatus(Page.LOAD_PAGE);
return networkService return networkService
.getStringResponse(overridePageUrl(page.getUrl()), requestHeaders, null) .getStringResponse(overridePageUrl(page.getUrl()), requestHeaders, false)
.flatMap(unparsedHtml -> Observable.just(parseHtmlToImageUrl(unparsedHtml))) .flatMap(unparsedHtml -> Observable.just(parseHtmlToImageUrl(unparsedHtml)))
.onErrorResumeNext(e -> { .onErrorResumeNext(e -> {
page.setStatus(Page.ERROR); page.setStatus(Page.ERROR);

View File

@ -309,7 +309,7 @@ public class Batoto extends LoginSource {
@Override @Override
public Observable<Boolean> login(String username, String password) { public Observable<Boolean> login(String username, String password) {
return networkService.getStringResponse(LOGIN_URL, requestHeaders, null) return networkService.getStringResponse(LOGIN_URL, requestHeaders, false)
.flatMap(response -> doLogin(response, username, password)) .flatMap(response -> doLogin(response, username, password))
.map(this::isAuthenticationSuccessful); .map(this::isAuthenticationSuccessful);
} }