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:
parent
260fa59799
commit
c52c567eae
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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() {
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user