mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 14:27:57 +01:00 
			
		
		
		
	Defer library download counts if not needed
This commit is contained in:
		| @@ -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<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 | ||||
|         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<Long, SourceDirectory> = hashMapOf(), | ||||
|     var sourceDirs: Map<Long, SourceDirectory> = hashMapOf(), | ||||
| ) | ||||
|  | ||||
| /** | ||||
| @@ -283,7 +296,7 @@ private class RootDirectory( | ||||
|  */ | ||||
| private class SourceDirectory( | ||||
|     val dir: UniFile, | ||||
|     var files: Map<String, MangaDirectory> = hashMapOf(), | ||||
|     var mangaDirs: Map<String, MangaDirectory> = hashMapOf(), | ||||
| ) | ||||
|  | ||||
| /** | ||||
| @@ -291,5 +304,5 @@ private class SourceDirectory( | ||||
|  */ | ||||
| private class MangaDirectory( | ||||
|     val dir: UniFile, | ||||
|     var files: Set<String> = hashSetOf(), | ||||
|     var chapterDirs: Set<String> = hashSetOf(), | ||||
| ) | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -338,27 +338,35 @@ class LibraryPresenter( | ||||
|      * @return an observable of the categories and its manga. | ||||
|      */ | ||||
|     private fun getLibraryFlow(): Flow<Library> { | ||||
|         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) | ||||
|         } | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user