From 93827aba34e98c6f70397d0e767580f3aaf5136b Mon Sep 17 00:00:00 2001 From: arkon Date: Thu, 20 Oct 2022 23:20:32 -0400 Subject: [PATCH] Defer library download counts if not needed --- .../tachiyomi/data/download/DownloadCache.kt | 75 +++++++++++-------- .../data/download/DownloadManager.kt | 5 +- .../tachiyomi/ui/library/LibraryPresenter.kt | 32 +++++--- 3 files changed, 65 insertions(+), 47 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt index 4c3d0a641..8338c6486 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt @@ -6,8 +6,10 @@ import com.hippo.unifile.UniFile import eu.kanade.domain.download.service.DownloadPreferences import eu.kanade.domain.manga.model.Manga import eu.kanade.tachiyomi.data.database.models.Chapter +import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceManager -import kotlinx.coroutines.MainScope +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import uy.kohesive.injekt.Injekt @@ -32,7 +34,7 @@ class DownloadCache( private val downloadPreferences: DownloadPreferences = Injekt.get(), ) { - private val scope = MainScope() + private val scope = CoroutineScope(Dispatchers.IO) /** * The interval after which this cache should be invalidated. 1 hour shouldn't cause major @@ -50,8 +52,10 @@ class DownloadCache( init { downloadPreferences.downloadsDirectory().changes() .onEach { - lastRenew = 0L // invalidate cache rootDownloadsDir = RootDirectory(getDirectoryFromPreference()) + + // Invalidate cache + lastRenew = 0L } .launchIn(scope) } @@ -79,11 +83,11 @@ class DownloadCache( renewCache() - val sourceDir = rootDownloadsDir.files[sourceId] + val sourceDir = rootDownloadsDir.sourceDirs[sourceId] if (sourceDir != null) { - val mangaDir = sourceDir.files[provider.getMangaDirName(mangaTitle)] + val mangaDir = sourceDir.mangaDirs[provider.getMangaDirName(mangaTitle)] if (mangaDir != null) { - return provider.getValidChapterDirNames(chapterName, chapterScanlator).any { it in mangaDir.files } + return provider.getValidChapterDirNames(chapterName, chapterScanlator).any { it in mangaDir.chapterDirs } } } return false @@ -97,11 +101,11 @@ class DownloadCache( fun getDownloadCount(manga: Manga): Int { renewCache() - val sourceDir = rootDownloadsDir.files[manga.source] + val sourceDir = rootDownloadsDir.sourceDirs[manga.source] if (sourceDir != null) { - val mangaDir = sourceDir.files[provider.getMangaDirName(manga.title)] + val mangaDir = sourceDir.mangaDirs[provider.getMangaDirName(manga.title)] if (mangaDir != null) { - return mangaDir.files.size + return mangaDir.chapterDirs.size } } return 0 @@ -117,24 +121,24 @@ class DownloadCache( @Synchronized fun addChapter(chapterDirName: String, mangaUniFile: UniFile, manga: Manga) { // Retrieve the cached source directory or cache a new one - var sourceDir = rootDownloadsDir.files[manga.source] + var sourceDir = rootDownloadsDir.sourceDirs[manga.source] if (sourceDir == null) { val source = sourceManager.get(manga.source) ?: return val sourceUniFile = provider.findSourceDir(source) ?: return sourceDir = SourceDirectory(sourceUniFile) - rootDownloadsDir.files += manga.source to sourceDir + rootDownloadsDir.sourceDirs += manga.source to sourceDir } // Retrieve the cached manga directory or cache a new one val mangaDirName = provider.getMangaDirName(manga.title) - var mangaDir = sourceDir.files[mangaDirName] + var mangaDir = sourceDir.mangaDirs[mangaDirName] if (mangaDir == null) { mangaDir = MangaDirectory(mangaUniFile) - sourceDir.files += mangaDirName to mangaDir + sourceDir.mangaDirs += mangaDirName to mangaDir } // Save the chapter directory - mangaDir.files += chapterDirName + mangaDir.chapterDirs += chapterDirName } /** @@ -145,11 +149,11 @@ class DownloadCache( */ @Synchronized fun removeChapter(chapter: Chapter, manga: Manga) { - val sourceDir = rootDownloadsDir.files[manga.source] ?: return - val mangaDir = sourceDir.files[provider.getMangaDirName(manga.title)] ?: return + val sourceDir = rootDownloadsDir.sourceDirs[manga.source] ?: return + val mangaDir = sourceDir.mangaDirs[provider.getMangaDirName(manga.title)] ?: return provider.getValidChapterDirNames(chapter.name, chapter.scanlator).forEach { - if (it in mangaDir.files) { - mangaDir.files -= it + if (it in mangaDir.chapterDirs) { + mangaDir.chapterDirs -= it } } } @@ -162,12 +166,12 @@ class DownloadCache( */ @Synchronized fun removeChapters(chapters: List, manga: Manga) { - val sourceDir = rootDownloadsDir.files[manga.source] ?: return - val mangaDir = sourceDir.files[provider.getMangaDirName(manga.title)] ?: return + val sourceDir = rootDownloadsDir.sourceDirs[manga.source] ?: return + val mangaDir = sourceDir.mangaDirs[provider.getMangaDirName(manga.title)] ?: return chapters.forEach { chapter -> provider.getValidChapterDirNames(chapter.name, chapter.scanlator).forEach { - if (it in mangaDir.files) { - mangaDir.files -= it + if (it in mangaDir.chapterDirs) { + mangaDir.chapterDirs -= it } } } @@ -180,10 +184,19 @@ class DownloadCache( */ @Synchronized fun removeManga(manga: Manga) { - val sourceDir = rootDownloadsDir.files[manga.source] ?: return + val sourceDir = rootDownloadsDir.sourceDirs[manga.source] ?: return val mangaDirName = provider.getMangaDirName(manga.title) - if (mangaDirName in sourceDir.files) { - sourceDir.files -= mangaDirName + if (mangaDirName in sourceDir.mangaDirs) { + sourceDir.mangaDirs -= mangaDirName + } + } + + @Synchronized + fun removeSourceIfEmpty(source: Source) { + val sourceDir = provider.findSourceDir(source) + if (sourceDir?.listFiles()?.isEmpty() == true) { + sourceDir.delete() + rootDownloadsDir.sourceDirs -= source.id } } @@ -220,14 +233,14 @@ class DownloadCache( }?.id } - rootDownloadsDir.files = sourceDirs + rootDownloadsDir.sourceDirs = sourceDirs sourceDirs.values.forEach { sourceDir -> val mangaDirs = sourceDir.dir.listFiles() .orEmpty() .associateNotNullKeys { it.name to MangaDirectory(it) } - sourceDir.files = mangaDirs + sourceDir.mangaDirs = mangaDirs mangaDirs.values.forEach { mangaDir -> val chapterDirs = mangaDir.dir.listFiles() @@ -239,7 +252,7 @@ class DownloadCache( } .toHashSet() - mangaDir.files = chapterDirs + mangaDir.chapterDirs = chapterDirs } } @@ -275,7 +288,7 @@ class DownloadCache( */ private class RootDirectory( val dir: UniFile, - var files: Map = hashMapOf(), + var sourceDirs: Map = hashMapOf(), ) /** @@ -283,7 +296,7 @@ private class RootDirectory( */ private class SourceDirectory( val dir: UniFile, - var files: Map = hashMapOf(), + var mangaDirs: Map = hashMapOf(), ) /** @@ -291,5 +304,5 @@ private class SourceDirectory( */ private class MangaDirectory( val dir: UniFile, - var files: Set = hashSetOf(), + var chapterDirs: Set = hashSetOf(), ) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt index 96951e82c..f8379d728 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt @@ -287,10 +287,7 @@ class DownloadManager( } // Delete source directory if empty - val sourceDir = provider.findSourceDir(source) - if (sourceDir?.listFiles()?.isEmpty() == true) { - sourceDir.delete() - } + cache.removeSourceIfEmpty(source) } return filteredChapters diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index 3e111f616..e73967ca8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -338,27 +338,35 @@ class LibraryPresenter( * @return an observable of the categories and its manga. */ private fun getLibraryFlow(): Flow { - val categoriesFlow = getCategories.subscribe() - val libraryMangasFlow = getLibraryManga.subscribe() - .map { list -> - list.map { libraryManga -> + val libraryMangasFlow = combine( + getLibraryManga.subscribe(), + libraryPreferences.downloadBadge().changes(), + ) { libraryMangaList, downloadBadgePref -> + libraryMangaList + .map { libraryManga -> // Display mode based on user preference: take it from global library setting or category LibraryItem(libraryManga).apply { - downloadCount = downloadManager.getDownloadCount(libraryManga.manga).toLong() + downloadCount = if (downloadBadgePref) { + downloadManager.getDownloadCount(libraryManga.manga).toLong() + } else { + 0 + } unreadCount = libraryManga.unreadCount isLocal = libraryManga.manga.isLocal() sourceLanguage = sourceManager.getOrStub(libraryManga.manga.source).lang } - }.groupBy { it.libraryManga.category } - } - return combine(categoriesFlow, libraryMangasFlow) { dbCategories, libraryManga -> - val categories = if (libraryManga.isNotEmpty() && libraryManga.containsKey(0).not()) { - dbCategories.filterNot { it.isSystemCategory } + } + .groupBy { it.libraryManga.category } + } + + return combine(getCategories.subscribe(), libraryMangasFlow) { categories, libraryManga -> + val displayCategories = if (libraryManga.isNotEmpty() && libraryManga.containsKey(0).not()) { + categories.filterNot { it.isSystemCategory } } else { - dbCategories + categories } - state.categories = categories + state.categories = displayCategories Library(categories, libraryManga) } }