Implement a download cache

This commit is contained in:
inorichi
2017-11-28 00:32:51 +01:00
parent 604929d002
commit bff329a329
10 changed files with 327 additions and 149 deletions

View File

@@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.ui.library
import android.os.Bundle
import com.hippo.unifile.UniFile
import com.jakewharton.rxrelay.BehaviorRelay
import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper
@@ -107,12 +106,6 @@ class LibraryPresenter(
* @param map the map to filter.
*/
private fun applyFilters(map: LibraryMap): LibraryMap {
// Cached list of downloaded manga directories given a source id.
val mangaDirsForSource = mutableMapOf<Long, Map<String?, UniFile>>()
// Cached list of downloaded chapter directories for a manga.
val chapterDirectories = mutableMapOf<Long, Boolean>()
val filterDownloaded = preferences.filterDownloaded().getOrDefault()
val filterUnread = preferences.filterUnread().getOrDefault()
@@ -121,7 +114,7 @@ class LibraryPresenter(
val filterFn: (LibraryItem) -> Boolean = f@ { item ->
// Filter out manga without source.
val source = sourceManager.get(item.manga.source) ?: return@f false
sourceManager.get(item.manga.source) ?: return@f false
// Filter when there isn't unread chapters.
if (filterUnread && item.manga.unread == 0) {
@@ -132,28 +125,14 @@ class LibraryPresenter(
return@f false
}
// Filter when the download directory doesn't exist or is null.
// Filter when there are no downloads.
if (filterDownloaded) {
// Don't bother with directory checking if download count has been set.
if (item.downloadCount != -1) {
return@f item.downloadCount > 0
}
// Get the directories for the source of the manga.
val dirsForSource = mangaDirsForSource.getOrPut(source.id) {
val sourceDir = downloadManager.findSourceDir(source)
sourceDir?.listFiles()?.associateBy { it.name }.orEmpty()
}
val mangaDirName = downloadManager.getMangaDirName(item.manga)
val mangaDir = dirsForSource[mangaDirName] ?: return@f false
val hasDirs = chapterDirectories.getOrPut(item.manga.id!!) {
mangaDir.listFiles()?.isNotEmpty() ?: false
}
if (!hasDirs) {
return@f false
}
return@f downloadManager.getDownloadCount(item.manga) > 0
}
true
}
@@ -177,31 +156,9 @@ class LibraryPresenter(
return
}
// Cached list of downloaded manga directories given a source id.
val mangaDirsForSource = mutableMapOf<Long, Map<String?, UniFile>>()
// Cached list of downloaded chapter directories for a manga.
val chapterDirectories = mutableMapOf<Long, Int>()
val downloadCountFn: (LibraryItem) -> Int = f@ { item ->
val source = sourceManager.get(item.manga.source) ?: return@f 0
// Get the directories for the source of the manga.
val dirsForSource = mangaDirsForSource.getOrPut(source.id) {
val sourceDir = downloadManager.findSourceDir(source)
sourceDir?.listFiles()?.associateBy { it.name }.orEmpty()
}
val mangaDirName = downloadManager.getMangaDirName(item.manga)
val mangaDir = dirsForSource[mangaDirName] ?: return@f 0
chapterDirectories.getOrPut(item.manga.id!!) {
mangaDir.listFiles()?.size ?: 0
}
}
for ((_, itemList) in map) {
for (item in itemList) {
item.downloadCount = downloadCountFn(item)
item.downloadCount = downloadManager.getDownloadCount(item.manga)
}
}
}
@@ -360,7 +317,7 @@ class LibraryPresenter(
if (deleteChapters) {
val source = sourceManager.get(manga.source) as? HttpSource
if (source != null) {
downloadManager.findMangaDir(source, manga)?.delete()
downloadManager.deleteManga(manga, source)
}
}
}

View File

@@ -128,13 +128,11 @@ class ChaptersPresenter(
* @param chapters the list of chapter from the database.
*/
private fun setDownloadedChapters(chapters: List<ChapterItem>) {
val files = downloadManager.findMangaDir(source, manga)?.listFiles() ?: return
val cached = mutableMapOf<Chapter, String>()
files.mapNotNull { it.name }
.mapNotNull { name -> chapters.find {
name == cached.getOrPut(it) { downloadManager.getChapterDirName(it) }
} }
.forEach { it.status = Download.DOWNLOADED }
for (chapter in chapters) {
if (downloadManager.isChapterDownloaded(chapter, manga)) {
chapter.status = Download.DOWNLOADED
}
}
}
/**
@@ -283,7 +281,7 @@ class ChaptersPresenter(
*/
private fun deleteChapter(chapter: ChapterItem) {
downloadManager.queue.remove(chapter)
downloadManager.deleteChapter(source, manga, chapter)
downloadManager.deleteChapter(chapter, manga, source)
chapter.status = Download.NOT_DOWNLOADED
chapter.download = null
}

View File

@@ -115,14 +115,14 @@ class MangaInfoPresenter(
* Returns true if the manga has any downloads.
*/
fun hasDownloads(): Boolean {
return downloadManager.findMangaDir(source, manga) != null
return downloadManager.getDownloadCount(manga) > 0
}
/**
* Deletes all the downloads for the manga.
*/
fun deleteDownloads() {
downloadManager.findMangaDir(source, manga)?.delete()
downloadManager.deleteManga(manga, source)
}
/**

View File

@@ -79,7 +79,7 @@ class ChapterLoader(
private fun retrievePageList(chapter: ReaderChapter) = Observable.just(chapter)
.flatMap {
// Check if the chapter is downloaded.
chapter.isDownloaded = downloadManager.findChapterDir(source, manga, chapter) != null
chapter.isDownloaded = downloadManager.isChapterDownloaded(chapter, manga, true)
if (chapter.isDownloaded) {
// Fetch the page list from disk.

View File

@@ -411,7 +411,7 @@ class ReaderPresenter(
fun deleteChapter(chapter: ReaderChapter, manga: Manga) {
chapter.isDownloaded = false
chapter.pages?.forEach { it.status == Page.QUEUE }
downloadManager.deleteChapter(source, manga, chapter)
downloadManager.deleteChapter(chapter, manga, source)
}
/**

View File

@@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.ui.recent_updates
import android.os.Bundle
import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.MangaChapter
import eu.kanade.tachiyomi.data.download.DownloadManager
@@ -114,36 +113,11 @@ class RecentChaptersPresenter(
* @param items the list of chapter from the database.
*/
private fun setDownloadedChapters(items: List<RecentChapterItem>) {
// Cached list of downloaded manga directories. Directory name is also cached because
// it's slow when using SAF.
val mangaDirsForSource = mutableMapOf<Long, Map<String?, UniFile>>()
// Cached list of downloaded chapter directories for a manga.
val chapterDirsForManga = mutableMapOf<Long, Map<String?, UniFile>>()
for (item in items) {
val manga = item.manga
val chapter = item.chapter
val source = sourceManager.get(manga.source) ?: continue
// Get the directories for the source of the manga.
val dirsForSource = mangaDirsForSource.getOrPut(source.id) {
val sourceDir = downloadManager.findSourceDir(source)
sourceDir?.listFiles()?.associateBy { it.name }.orEmpty()
}
// Get the manga directory in the source or continue.
val mangaDirName = downloadManager.getMangaDirName(manga)
val mangaDir = dirsForSource[mangaDirName] ?: continue
// Get the directories for the manga.
val chapterDirs = chapterDirsForManga.getOrPut(manga.id!!) {
mangaDir.listFiles()?.associateBy { it.name }.orEmpty()
}
// Assign the download if the directory exists.
val chapterDirName = downloadManager.getChapterDirName(chapter)
if (chapterDirName in chapterDirs) {
if (downloadManager.isChapterDownloaded(chapter, manga)) {
item.status = Download.DOWNLOADED
}
}
@@ -216,7 +190,7 @@ class RecentChaptersPresenter(
private fun deleteChapter(item: RecentChapterItem) {
val source = sourceManager.get(item.manga.source) ?: return
downloadManager.queue.remove(item.chapter)
downloadManager.deleteChapter(source, item.manga, item.chapter)
downloadManager.deleteChapter(item.chapter, item.manga, source)
item.status = Download.NOT_DOWNLOADED
item.download = null
}