Initial download manager

This commit is contained in:
inorichi
2015-11-03 16:21:50 +01:00
parent b3f12ae333
commit 13ff612ce0
23 changed files with 284 additions and 182 deletions

View File

@@ -0,0 +1,128 @@
package eu.kanade.mangafeed.data.helpers;
import android.content.Context;
import java.io.File;
import java.io.IOException;
import java.util.List;
import eu.kanade.mangafeed.data.models.Chapter;
import eu.kanade.mangafeed.data.models.Manga;
import eu.kanade.mangafeed.data.models.Page;
import eu.kanade.mangafeed.events.DownloadChapterEvent;
import eu.kanade.mangafeed.sources.base.Source;
import eu.kanade.mangafeed.util.DiskUtils;
import rx.Observable;
import rx.Subscription;
import rx.schedulers.Schedulers;
import rx.subjects.PublishSubject;
public class DownloadManager {
private PublishSubject<DownloadChapterEvent> downloadsSubject;
private Subscription downloadsSubscription;
private Context context;
private SourceManager sourceManager;
public DownloadManager(Context context, SourceManager sourceManager) {
this.context = context;
this.sourceManager = sourceManager;
initializeDownloadSubscription();
}
private void initializeDownloadSubscription() {
if (downloadsSubscription != null && !downloadsSubscription.isUnsubscribed()) {
downloadsSubscription.unsubscribe();
}
downloadsSubject = PublishSubject.create();
downloadsSubscription = downloadsSubject
.subscribeOn(Schedulers.io())
.concatMap(event -> downloadChapter(event.getManga(), event.getChapter()))
.onBackpressureBuffer()
.subscribe();
}
private Observable<Page> downloadChapter(Manga manga, Chapter chapter) {
final Source source = sourceManager.get(manga.source);
final File chapterDirectory = new File(getDownloadsDirectory(), getChapterDirectory(chapter));
return source
.pullPageListFromNetwork(chapter.url)
// Ensure we don't download a chapter already downloaded
.filter(pages -> !isChapterDownloaded(chapterDirectory, pages))
// Get all the URLs to the source images, fetch pages if necessary
.flatMap(pageList -> Observable.merge(
Observable.from(pageList).filter(page -> page.getImageUrl() != null),
source.getRemainingImageUrlsFromPageList(pageList)))
// Start downloading images
.flatMap(page -> getDownloadedImage(page, source, chapterDirectory));
}
private File getDownloadsDirectory() {
// TODO
return new File(DiskUtils.getStorageDirectories(context)[0]);
}
private String getChapterDirectory(Chapter chapter) {
return chapter.name.replaceAll("[^a-zA-Z0-9.-]", "_");
}
private String getImageFilename(Page page) {
return page.getImageUrl().substring(
page.getImageUrl().lastIndexOf("/") + 1,
page.getImageUrl().length());
}
private boolean isChapterDownloaded(File chapterDir, List<Page> pages) {
return chapterDir.exists() && chapterDir.listFiles().length == pages.size();
}
private boolean isImageDownloaded(File imagePath) {
return imagePath.exists() && !imagePath.isDirectory();
}
public Observable<Page> getDownloadedImage(final Page page, Source source, File chapterDir) {
Observable<Page> obs = Observable.just(page);
if (page.getImageUrl() == null)
return obs;
String imageFilename = getImageFilename(page);
File imagePath = new File(chapterDir, imageFilename);
if (!isImageDownloaded(imagePath)) {
page.setStatus(Page.DOWNLOAD_IMAGE);
obs = downloadImage(page, source, chapterDir, imageFilename);
}
return obs.flatMap(p -> {
page.setImagePath(imagePath.getAbsolutePath());
page.setStatus(Page.READY);
return Observable.just(page);
}).onErrorResumeNext(e -> {
page.setStatus(Page.ERROR);
return Observable.just(page);
});
}
private Observable<Page> downloadImage(final Page page, Source source, File chapterDir, String imageFilename) {
return source.getImageProgressResponse(page)
.flatMap(resp -> {
try {
DiskUtils.saveBufferedSourceToDirectory(resp.body().source(), chapterDir, imageFilename);
} catch (IOException e) {
e.printStackTrace();
throw new IllegalStateException("Unable to save image");
}
return Observable.just(page);
});
}
public PublishSubject<DownloadChapterEvent> getDownloadsSubject() {
return downloadsSubject;
}
}

View File

@@ -6,6 +6,7 @@ import android.preference.PreferenceManager;
import eu.kanade.mangafeed.R;
import eu.kanade.mangafeed.sources.base.Source;
import eu.kanade.mangafeed.util.DiskUtils;
public class PreferencesHelper {
@@ -53,4 +54,9 @@ public class PreferencesHelper {
.apply();
}
public String getDownloadsDirectory() {
return mPref.getString(getKey(R.string.pref_download_directory_key),
DiskUtils.getStorageDirectories(context)[0]);
}
}

View File

@@ -0,0 +1,58 @@
package eu.kanade.mangafeed.data.services;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
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.DownloadChapterEvent;
import eu.kanade.mangafeed.util.AndroidComponentUtil;
import eu.kanade.mangafeed.util.EventBusHook;
public class DownloadService extends Service {
@Inject DownloadManager downloadManager;
public static Intent getStartIntent(Context context) {
return new Intent(context, DownloadService.class);
}
public static boolean isRunning(Context context) {
return AndroidComponentUtil.isServiceRunning(context, DownloadService.class);
}
@Override
public void onCreate() {
super.onCreate();
App.get(this).getComponent().inject(this);
EventBus.getDefault().register(this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@EventBusHook
public void onEvent(DownloadChapterEvent event) {
downloadManager.getDownloadsSubject().onNext(event);
}
@Override
public void onDestroy() {
EventBus.getDefault().unregister(this);
super.onDestroy();
}
}