Avoid filename conflicts (not sure if it will be totally fixed). Check if a chapter is properly downloaded after download finishes.

This commit is contained in:
inorichi 2015-12-04 18:03:56 +01:00
parent 260fa59799
commit c52c567eae
6 changed files with 34 additions and 37 deletions

View File

@ -179,7 +179,7 @@ public class CacheManager {
return null; return null;
} }
public boolean putImageToDiskCache(final String imageUrl, final Response response) { public void putImageToDiskCache(final String imageUrl, final Response response) throws IOException {
DiskLruCache.Editor editor = null; DiskLruCache.Editor editor = null;
BufferedSink sink = null; BufferedSink sink = null;
@ -187,33 +187,26 @@ public class CacheManager {
String key = DiskUtils.hashKeyForDisk(imageUrl); String key = DiskUtils.hashKeyForDisk(imageUrl);
editor = mDiskCache.edit(key); editor = mDiskCache.edit(key);
if (editor == null) { if (editor == null) {
return false; throw new IOException("Unable to edit key");
} }
OutputStream outputStream = new BufferedOutputStream(editor.newOutputStream(0)); OutputStream outputStream = new BufferedOutputStream(editor.newOutputStream(0));
sink = Okio.buffer(Okio.sink(outputStream)); sink = Okio.buffer(Okio.sink(outputStream));
sink.writeAll(response.body().source()); sink.writeAll(response.body().source());
sink.flush();
mDiskCache.flush(); mDiskCache.flush();
editor.commit(); editor.commit();
} catch (IOException e) { } catch (Exception e) {
e.printStackTrace(); throw new IOException("Unable to save image");
return false;
} finally { } finally {
if (editor != null) { if (editor != null) {
editor.abortUnlessCommitted(); editor.abortUnlessCommitted();
} }
if (sink != null) { if (sink != null) {
try { sink.close();
sink.close();
} catch (IOException e) {
e.printStackTrace();
}
} }
} }
return true;
} }
} }

View File

@ -12,8 +12,6 @@ import java.io.FileOutputStream;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List; import java.util.List;
import eu.kanade.mangafeed.data.database.models.Chapter; import eu.kanade.mangafeed.data.database.models.Chapter;
@ -27,6 +25,7 @@ import eu.kanade.mangafeed.data.source.model.Page;
import eu.kanade.mangafeed.event.DownloadChaptersEvent; import eu.kanade.mangafeed.event.DownloadChaptersEvent;
import eu.kanade.mangafeed.util.DiskUtils; import eu.kanade.mangafeed.util.DiskUtils;
import eu.kanade.mangafeed.util.DynamicConcurrentMergeOperator; import eu.kanade.mangafeed.util.DynamicConcurrentMergeOperator;
import eu.kanade.mangafeed.util.UrlUtil;
import rx.Observable; import rx.Observable;
import rx.Subscription; import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers; import rx.android.schedulers.AndroidSchedulers;
@ -81,6 +80,7 @@ public class DownloadManager {
.lift(new DynamicConcurrentMergeOperator<>(this::downloadChapter, threadsNumber)) .lift(new DynamicConcurrentMergeOperator<>(this::downloadChapter, threadsNumber))
.onBackpressureBuffer() .onBackpressureBuffer()
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.map(download -> areAllDownloadsFinished())
.subscribe(finished -> { .subscribe(finished -> {
if (finished) { if (finished) {
DownloadService.stop(context); DownloadService.stop(context);
@ -164,7 +164,7 @@ public class DownloadManager {
} }
// Download the entire chapter // Download the entire chapter
private Observable<Boolean> downloadChapter(Download download) { private Observable<Download> downloadChapter(Download download) {
try { try {
DiskUtils.createDirectory(download.directory); DiskUtils.createDirectory(download.directory);
} catch (IOException e) { } catch (IOException e) {
@ -182,7 +182,6 @@ public class DownloadManager {
return pageListObservable return pageListObservable
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.doOnError(error -> download.setStatus(Download.ERROR))
.doOnNext(pages -> download.setStatus(Download.DOWNLOADING)) .doOnNext(pages -> download.setStatus(Download.DOWNLOADING))
.doOnNext(pages -> download.downloadedImages = 0) .doOnNext(pages -> download.downloadedImages = 0)
// Get all the URLs to the source images, fetch pages if necessary // Get all the URLs to the source images, fetch pages if necessary
@ -194,8 +193,10 @@ public class DownloadManager {
.toList() .toList()
.flatMap(pages -> Observable.just(download)) .flatMap(pages -> Observable.just(download))
// If the page list threw, it will resume here // If the page list threw, it will resume here
.onErrorResumeNext(error -> Observable.just(download)) .onErrorResumeNext(error -> {
.map(d -> areAllDownloadsFinished()); download.setStatus(Download.ERROR);
return Observable.just(download);
});
} }
// Get the image from the filesystem if it exists or download from network // Get the image from the filesystem if it exists or download from network
@ -215,9 +216,9 @@ public class DownloadManager {
return pageObservable return pageObservable
// When the image is ready, set image path, progress (just in case) and status // When the image is ready, set image path, progress (just in case) and status
.doOnNext(p -> { .doOnNext(p -> {
p.setImagePath(imagePath.getAbsolutePath()); page.setImagePath(imagePath.getAbsolutePath());
p.setProgress(100); page.setProgress(100);
p.setStatus(Page.READY); page.setStatus(Page.READY);
download.downloadedImages++; download.downloadedImages++;
}) })
// If the download fails, mark this page as error // If the download fails, mark this page as error
@ -226,6 +227,7 @@ public class DownloadManager {
.onErrorResumeNext(e -> Observable.just(page)); .onErrorResumeNext(e -> Observable.just(page));
} }
// Save image on disk
private Observable<Page> downloadImage(Page page, Source source, File directory, String filename) { private Observable<Page> downloadImage(Page page, Source source, File directory, String filename) {
page.setStatus(Page.DOWNLOAD_IMAGE); page.setStatus(Page.DOWNLOAD_IMAGE);
return source.getImageProgressResponse(page) return source.getImageProgressResponse(page)
@ -261,12 +263,7 @@ public class DownloadManager {
// Get the filename for an image given the page // Get the filename for an image given the page
private String getImageFilename(Page page) { private String getImageFilename(Page page) {
String url; String url = UrlUtil.getPath(page.getImageUrl());
try {
url = new URL(page.getImageUrl()).getPath();
} catch (MalformedURLException e) {
url = page.getImageUrl();
}
return url.substring( return url.substring(
url.lastIndexOf("/") + 1, url.lastIndexOf("/") + 1,
url.length()); url.length());
@ -288,7 +285,11 @@ public class DownloadManager {
// If any page has an error, the download result will be error // If any page has an error, the download result will be error
for (Page page : download.pages) { for (Page page : download.pages) {
actualProgress += page.getProgress(); actualProgress += page.getProgress();
if (page.getStatus() == Page.ERROR) status = Download.ERROR; if (page.getStatus() != Page.READY) status = Download.ERROR;
}
// Ensure that the chapter folder has all the images
if (!isChapterDownloaded(download.directory, download.pages)) {
status = Download.ERROR;
} }
download.totalProgress = actualProgress; download.totalProgress = actualProgress;
download.setStatus(status); download.setStatus(status);

View File

@ -42,7 +42,7 @@ public final class NetworkHelper {
} catch (Throwable e) { } catch (Throwable e) {
return Observable.error(e); return Observable.error(e);
} }
}).retry(3); }).retry(2);
} }
public Observable<String> mapResponseToString(final Response response) { public Observable<String> mapResponseToString(final Response response) {
@ -72,7 +72,7 @@ public final class NetworkHelper {
} catch (Throwable e) { } catch (Throwable e) {
return Observable.error(e); return Observable.error(e);
} }
}).retry(3); }).retry(2);
} }
public Observable<Response> getProgressResponse(final String url, final Headers headers, final ProgressListener listener) { public Observable<Response> getProgressResponse(final String url, final Headers headers, final ProgressListener listener) {
@ -96,7 +96,7 @@ public final class NetworkHelper {
} catch (Throwable e) { } catch (Throwable e) {
return Observable.error(e); return Observable.error(e);
} }
}).retry(3); }).retry(2);
} }
public CookieStore getCookies() { public CookieStore getCookies() {

View File

@ -8,6 +8,7 @@ import com.squareup.okhttp.Response;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -153,8 +154,10 @@ public abstract class Source extends BaseSource {
page.setStatus(Page.DOWNLOAD_IMAGE); page.setStatus(Page.DOWNLOAD_IMAGE);
return getImageProgressResponse(page) return getImageProgressResponse(page)
.flatMap(resp -> { .flatMap(resp -> {
if (!cacheManager.putImageToDiskCache(page.getImageUrl(), resp)) { try {
throw new IllegalStateException("Unable to save image"); cacheManager.putImageToDiskCache(page.getImageUrl(), resp);
} catch (IOException e) {
return Observable.error(e);
} }
return Observable.just(page); return Observable.just(page);
}); });

View File

@ -8,7 +8,7 @@ public class Page implements ProgressListener {
private int pageNumber; private int pageNumber;
private String url; private String url;
private String imageUrl; private String imageUrl;
private String imagePath; private transient String imagePath;
private transient volatile int status; private transient volatile int status;
private transient volatile int progress; private transient volatile int progress;

View File

@ -130,13 +130,13 @@ public final class DiskUtils {
try { try {
bufferedSink = Okio.buffer(Okio.sink(writeFile)); bufferedSink = Okio.buffer(Okio.sink(writeFile));
bufferedSink.writeAll(bufferedSource); bufferedSink.writeAll(bufferedSource);
bufferedSink.close();
} catch (Exception e) { } catch (Exception e) {
writeFile.delete();
throw new IOException("Unable to save image");
} finally {
if (bufferedSink != null) { if (bufferedSink != null) {
bufferedSink.close(); bufferedSink.close();
} }
writeFile.delete();
throw new IOException("Failed saving image");
} }
return writeFile; return writeFile;