- Add a new cache to store library covers without relying on Glide's cache, making sure they are always available.
- Use Observable's defer instead of create in NetworkHelper.
- Fix Kissmanga showing only one genre.
This commit is contained in:
inorichi
2015-12-01 14:20:14 +01:00
parent b66809b2b2
commit 04a61edb38
9 changed files with 205 additions and 76 deletions

View File

@@ -0,0 +1,129 @@
package eu.kanade.mangafeed.data.cache;
import android.content.Context;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.LazyHeaders;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import eu.kanade.mangafeed.util.DiskUtils;
public class CoverCache {
private static final String PARAMETER_CACHE_DIRECTORY = "cover_disk_cache";
private Context context;
private File cacheDir;
public CoverCache(Context context) {
this.context = context;
cacheDir = new File(context.getCacheDir(), PARAMETER_CACHE_DIRECTORY);
createCacheDir();
}
private boolean createCacheDir() {
return !cacheDir.exists() && cacheDir.mkdirs();
}
// Download the cover with Glide (it can avoid repeating requests) and save the file on this cache
public void save(String cover, LazyHeaders headers) {
GlideUrl url = new GlideUrl(cover, headers);
Glide.with(context)
.load(url)
.downloadOnly(new SimpleTarget<File>() {
@Override
public void onResourceReady(File resource, GlideAnimation<? super File> anim) {
try {
add(cover, resource);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
// Copy the cover from Glide's cache to this cache
public void add(String key, File source) throws IOException {
File dest = new File(cacheDir, DiskUtils.hashKeyForDisk(key));
if (dest.exists())
dest.delete();
InputStream in = new FileInputStream(source);
try {
OutputStream out = new FileOutputStream(dest);
try {
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
} finally {
out.close();
}
} finally {
in.close();
}
}
// Get the cover from cache
public File get(String key) {
return new File(cacheDir, DiskUtils.hashKeyForDisk(key));
}
// Delete the cover from cache
public boolean delete(String key) {
File file = new File(cacheDir, DiskUtils.hashKeyForDisk(key));
return file.exists() && file.delete();
}
// Load the cover from cache or network if it doesn't exist
public void loadOrFetchInto(ImageView imageView, String cover, LazyHeaders headers) {
File localCover = get(cover);
if (localCover.exists()) {
loadLocalInto(context, imageView, localCover);
} else {
loadRemoteInto(context, imageView, cover, headers);
}
}
// Load the cover from cache
public static void loadLocalInto(Context context, ImageView imageView, String cover) {
File cacheDir = new File(context.getCacheDir(), PARAMETER_CACHE_DIRECTORY);
File localCover = new File(cacheDir, DiskUtils.hashKeyForDisk(cover));
if (localCover.exists()) {
loadLocalInto(context, imageView, localCover);
}
}
// Load the cover from the cache directory into the specified image view
private static void loadLocalInto(Context context, ImageView imageView, File file) {
Glide.with(context)
.load(file)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.centerCrop()
.into(imageView);
}
// Load the cover from network into the specified image view. It does NOT save the image in cache
private static void loadRemoteInto(Context context, ImageView imageView, String cover, LazyHeaders headers) {
GlideUrl url = new GlideUrl(cover, headers);
Glide.with(context)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.centerCrop()
.into(imageView);
}
}

View File

@@ -16,95 +16,85 @@ import rx.Observable;
public final class NetworkHelper {
private OkHttpClient mClient;
private OkHttpClient client;
private CookieManager cookieManager;
public final CacheControl NULL_CACHE_CONTROL = new CacheControl.Builder().noCache().build();
public final Headers NULL_HEADERS = new Headers.Builder().build();
public NetworkHelper() {
mClient = new OkHttpClient();
client = new OkHttpClient();
cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
mClient.setCookieHandler(cookieManager);
client.setCookieHandler(cookieManager);
}
public Observable<Response> getResponse(final String url, final Headers headers, final CacheControl cacheControl) {
return Observable.<Response>create(subscriber -> {
return Observable.defer(() -> {
try {
if (!subscriber.isUnsubscribed()) {
Request request = new Request.Builder()
.url(url)
.cacheControl(cacheControl != null ? cacheControl : NULL_CACHE_CONTROL)
.headers(headers != null ? headers : NULL_HEADERS)
.build();
subscriber.onNext(mClient.newCall(request).execute());
}
subscriber.onCompleted();
Request request = new Request.Builder()
.url(url)
.cacheControl(cacheControl != null ? cacheControl : NULL_CACHE_CONTROL)
.headers(headers != null ? headers : NULL_HEADERS)
.build();
return Observable.just(client.newCall(request).execute());
} catch (Throwable e) {
subscriber.onError(e);
return Observable.error(e);
}
}).retry(3);
}
public Observable<String> mapResponseToString(final Response response) {
return Observable.create(subscriber -> {
return Observable.defer(() -> {
try {
subscriber.onNext(response.body().string());
subscriber.onCompleted();
return Observable.just(response.body().string());
} catch (Throwable e) {
subscriber.onError(e);
return Observable.error(e);
}
});
}
public Observable<String> getStringResponse(final String url, final Headers headers, final CacheControl cacheControl) {
return getResponse(url, headers, cacheControl)
.flatMap(this::mapResponseToString);
}
public Observable<Response> postData(final String url, final RequestBody formBody, final Headers headers) {
return Observable.create(subscriber -> {
return Observable.defer(() -> {
try {
if (!subscriber.isUnsubscribed()) {
Request request = new Request.Builder()
.url(url)
.post(formBody)
.headers(headers != null ? headers : NULL_HEADERS)
.build();
subscriber.onNext(mClient.newCall(request).execute());
}
subscriber.onCompleted();
Request request = new Request.Builder()
.url(url)
.post(formBody)
.headers(headers != null ? headers : NULL_HEADERS)
.build();
return Observable.just(client.newCall(request).execute());
} catch (Throwable e) {
subscriber.onError(e);
return Observable.error(e);
}
});
}).retry(3);
}
public Observable<Response> getProgressResponse(final String url, final Headers headers, final ProgressListener listener) {
return Observable.<Response>create(subscriber -> {
return Observable.defer(() -> {
try {
if (!subscriber.isUnsubscribed()) {
Request request = new Request.Builder()
.url(url)
.cacheControl(NULL_CACHE_CONTROL)
.headers(headers != null ? headers : NULL_HEADERS)
Request request = new Request.Builder()
.url(url)
.cacheControl(NULL_CACHE_CONTROL)
.headers(headers != null ? headers : NULL_HEADERS)
.build();
OkHttpClient progressClient = client.clone();
progressClient.networkInterceptors().add(chain -> {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), listener))
.build();
OkHttpClient progressClient = mClient.clone();
progressClient.networkInterceptors().add(chain -> {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), listener))
.build();
});
subscriber.onNext(progressClient.newCall(request).execute());
}
subscriber.onCompleted();
});
return Observable.just(progressClient.newCall(request).execute());
} catch (Throwable e) {
subscriber.onError(e);
return Observable.error(e);
}
}).retry(3);
}

View File

@@ -151,7 +151,7 @@ public class Kissmanga extends Source {
Element infoElement = parsedDocument.select("div.barContent").first();
Element titleElement = infoElement.select("a.bigChar").first();
Element authorElement = infoElement.select("p:has(span:contains(Author:)) > a").first();
Element genreElement = infoElement.select("p:has(span:contains(Genres:)) > *:gt(0)").first();
Elements genreElement = infoElement.select("p:has(span:contains(Genres:)) > *:gt(0)");
Elements descriptionElement = infoElement.select("p:has(span:contains(Summary:)) ~ p");
Element thumbnailUrlElement = parsedDocument.select(".rightBox:eq(0) img").first();