mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-03 23:58:55 +01:00 
			
		
		
		
	Change cover memory key (#7276)
Use different key for custom cover and add last modified time for updating cover without clearing the whole memory cache
This commit is contained in:
		@@ -1,7 +1,6 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.cache
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import coil.imageLoader
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
 | 
			
		||||
import java.io.File
 | 
			
		||||
@@ -100,13 +99,6 @@ class CoverCache(private val context: Context) {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clear coil's memory cache.
 | 
			
		||||
     */
 | 
			
		||||
    fun clearMemoryCache() {
 | 
			
		||||
        context.imageLoader.memoryCache?.clear()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getCacheDir(dir: String): File {
 | 
			
		||||
        return context.getExternalFilesDir(dir)
 | 
			
		||||
            ?: File(context.filesDir, dir).also { it.mkdirs() }
 | 
			
		||||
 
 | 
			
		||||
@@ -42,28 +42,32 @@ import java.net.HttpURLConnection
 | 
			
		||||
 * - [USE_CUSTOM_COVER]: Use custom cover if set by user, default is true
 | 
			
		||||
 */
 | 
			
		||||
class MangaCoverFetcher(
 | 
			
		||||
    private val manga: Manga,
 | 
			
		||||
    private val sourceLazy: Lazy<HttpSource?>,
 | 
			
		||||
    private val url: String?,
 | 
			
		||||
    private val isLibraryManga: Boolean,
 | 
			
		||||
    private val options: Options,
 | 
			
		||||
    private val coverCache: CoverCache,
 | 
			
		||||
    private val coverFileLazy: Lazy<File?>,
 | 
			
		||||
    private val customCoverFileLazy: Lazy<File>,
 | 
			
		||||
    private val diskCacheKeyLazy: Lazy<String>,
 | 
			
		||||
    private val sourceLazy: Lazy<HttpSource?>,
 | 
			
		||||
    private val callFactoryLazy: Lazy<Call.Factory>,
 | 
			
		||||
    private val diskCacheLazy: Lazy<DiskCache>,
 | 
			
		||||
) : Fetcher {
 | 
			
		||||
 | 
			
		||||
    // For non-custom cover
 | 
			
		||||
    private val diskCacheKey: String? by lazy { MangaCoverKeyer().key(manga, options) }
 | 
			
		||||
    private lateinit var url: String
 | 
			
		||||
    private val diskCacheKey: String
 | 
			
		||||
        get() = diskCacheKeyLazy.value
 | 
			
		||||
 | 
			
		||||
    override suspend fun fetch(): FetchResult {
 | 
			
		||||
        // Use custom cover if exists
 | 
			
		||||
        val useCustomCover = options.parameters.value(USE_CUSTOM_COVER) ?: true
 | 
			
		||||
        val customCoverFile = coverCache.getCustomCoverFile(manga.id)
 | 
			
		||||
        if (useCustomCover && customCoverFile.exists()) {
 | 
			
		||||
            return fileLoader(customCoverFile)
 | 
			
		||||
        if (useCustomCover) {
 | 
			
		||||
            val customCoverFile = customCoverFileLazy.value
 | 
			
		||||
            if (customCoverFile.exists()) {
 | 
			
		||||
                return fileLoader(customCoverFile)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // diskCacheKey is thumbnail_url
 | 
			
		||||
        url = diskCacheKey ?: error("No cover specified")
 | 
			
		||||
        if (url == null) error("No cover specified")
 | 
			
		||||
        return when (getResourceType(url)) {
 | 
			
		||||
            Type.URL -> httpLoader()
 | 
			
		||||
            Type.File -> fileLoader(File(url.substringAfter("file://")))
 | 
			
		||||
@@ -81,8 +85,8 @@ class MangaCoverFetcher(
 | 
			
		||||
 | 
			
		||||
    private suspend fun httpLoader(): FetchResult {
 | 
			
		||||
        // Only cache separately if it's a library item
 | 
			
		||||
        val libraryCoverCacheFile = if (manga.favorite) {
 | 
			
		||||
            coverCache.getCoverFile(manga.thumbnail_url) ?: error("No cover specified")
 | 
			
		||||
        val libraryCoverCacheFile = if (isLibraryManga) {
 | 
			
		||||
            coverFileLazy.value ?: error("No cover specified")
 | 
			
		||||
        } else {
 | 
			
		||||
            null
 | 
			
		||||
        }
 | 
			
		||||
@@ -156,7 +160,7 @@ class MangaCoverFetcher(
 | 
			
		||||
 | 
			
		||||
    private fun newRequest(): Request {
 | 
			
		||||
        val request = Request.Builder()
 | 
			
		||||
            .url(url)
 | 
			
		||||
            .url(url!!)
 | 
			
		||||
            .headers(sourceLazy.value?.headers ?: options.headers)
 | 
			
		||||
            // Support attaching custom data to the network request.
 | 
			
		||||
            .tag(Parameters::class.java, options.parameters)
 | 
			
		||||
@@ -188,7 +192,7 @@ class MangaCoverFetcher(
 | 
			
		||||
                fileSystem.source(snapshot.data).use { input ->
 | 
			
		||||
                    writeSourceToCoverCache(input, cacheFile)
 | 
			
		||||
                }
 | 
			
		||||
                remove(diskCacheKey!!)
 | 
			
		||||
                remove(diskCacheKey)
 | 
			
		||||
            }
 | 
			
		||||
            cacheFile.takeIf { it.exists() }
 | 
			
		||||
        } catch (e: Exception) {
 | 
			
		||||
@@ -224,7 +228,7 @@ class MangaCoverFetcher(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun readFromDiskCache(): DiskCache.Snapshot? {
 | 
			
		||||
        return if (options.diskCachePolicy.readEnabled) diskCacheLazy.value[diskCacheKey!!] else null
 | 
			
		||||
        return if (options.diskCachePolicy.readEnabled) diskCacheLazy.value[diskCacheKey] else null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun writeToDiskCache(
 | 
			
		||||
@@ -238,7 +242,7 @@ class MangaCoverFetcher(
 | 
			
		||||
        val editor = if (snapshot != null) {
 | 
			
		||||
            snapshot.closeAndEdit()
 | 
			
		||||
        } else {
 | 
			
		||||
            diskCacheLazy.value.edit(diskCacheKey!!)
 | 
			
		||||
            diskCacheLazy.value.edit(diskCacheKey)
 | 
			
		||||
        } ?: return null
 | 
			
		||||
        try {
 | 
			
		||||
            diskCacheLazy.value.fileSystem.write(editor.data) {
 | 
			
		||||
@@ -280,8 +284,17 @@ class MangaCoverFetcher(
 | 
			
		||||
        private val sourceManager: SourceManager by injectLazy()
 | 
			
		||||
 | 
			
		||||
        override fun create(data: Manga, options: Options, imageLoader: ImageLoader): Fetcher {
 | 
			
		||||
            val source = lazy { sourceManager.get(data.source) as? HttpSource }
 | 
			
		||||
            return MangaCoverFetcher(data, source, options, coverCache, callFactoryLazy, diskCacheLazy)
 | 
			
		||||
            return MangaCoverFetcher(
 | 
			
		||||
                url = data.thumbnail_url,
 | 
			
		||||
                isLibraryManga = data.favorite,
 | 
			
		||||
                options = options,
 | 
			
		||||
                coverFileLazy = lazy { coverCache.getCoverFile(data.thumbnail_url) },
 | 
			
		||||
                customCoverFileLazy = lazy { coverCache.getCustomCoverFile(data.id) },
 | 
			
		||||
                diskCacheKeyLazy = lazy { MangaCoverKeyer().key(data, options) },
 | 
			
		||||
                sourceLazy = lazy { sourceManager.get(data.source) as? HttpSource },
 | 
			
		||||
                callFactoryLazy = callFactoryLazy,
 | 
			
		||||
                diskCacheLazy = diskCacheLazy,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,14 @@ package eu.kanade.tachiyomi.data.coil
 | 
			
		||||
import coil.key.Keyer
 | 
			
		||||
import coil.request.Options
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.util.hasCustomCover
 | 
			
		||||
 | 
			
		||||
class MangaCoverKeyer : Keyer<Manga> {
 | 
			
		||||
    override fun key(data: Manga, options: Options): String? {
 | 
			
		||||
        return data.thumbnail_url?.takeIf { it.isNotBlank() }
 | 
			
		||||
    override fun key(data: Manga, options: Options): String {
 | 
			
		||||
        return if (data.hasCustomCover()) {
 | 
			
		||||
            "${data.id};${data.cover_last_modified}"
 | 
			
		||||
        } else {
 | 
			
		||||
            "${data.thumbnail_url};${data.cover_last_modified}"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -473,7 +473,6 @@ class LibraryUpdateService(
 | 
			
		||||
                .awaitAll()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        coverCache.clearMemoryCache()
 | 
			
		||||
        notifier.cancelProgressNotification()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -290,7 +290,6 @@ class LocalSource(
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
            .also { coverCache.clearMemoryCache() }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sealed class Format {
 | 
			
		||||
 
 | 
			
		||||
@@ -316,12 +316,11 @@ class MangaPresenter(
 | 
			
		||||
                        LocalSource.updateCover(context, manga, it)
 | 
			
		||||
                        manga.updateCoverLastModified(db)
 | 
			
		||||
                        db.insertManga(manga).executeAsBlocking()
 | 
			
		||||
                        coverCache.clearMemoryCache()
 | 
			
		||||
                    } else if (manga.favorite) {
 | 
			
		||||
                        coverCache.setCustomCoverToCache(manga, it)
 | 
			
		||||
                        manga.updateCoverLastModified(db)
 | 
			
		||||
                        coverCache.clearMemoryCache()
 | 
			
		||||
                    }
 | 
			
		||||
                    true
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .subscribeOn(Schedulers.io())
 | 
			
		||||
@@ -337,7 +336,6 @@ class MangaPresenter(
 | 
			
		||||
            .fromCallable {
 | 
			
		||||
                coverCache.deleteCustomCover(manga.id)
 | 
			
		||||
                manga.updateCoverLastModified(db)
 | 
			
		||||
                coverCache.clearMemoryCache()
 | 
			
		||||
            }
 | 
			
		||||
            .subscribeOn(Schedulers.io())
 | 
			
		||||
            .observeOn(AndroidSchedulers.mainThread())
 | 
			
		||||
 
 | 
			
		||||
@@ -704,13 +704,11 @@ class ReaderPresenter(
 | 
			
		||||
                        val context = Injekt.get<Application>()
 | 
			
		||||
                        LocalSource.updateCover(context, manga, it)
 | 
			
		||||
                        manga.updateCoverLastModified(db)
 | 
			
		||||
                        coverCache.clearMemoryCache()
 | 
			
		||||
                        SetAsCoverResult.Success
 | 
			
		||||
                    } else {
 | 
			
		||||
                        if (manga.favorite) {
 | 
			
		||||
                            coverCache.setCustomCoverToCache(manga, it)
 | 
			
		||||
                            manga.updateCoverLastModified(db)
 | 
			
		||||
                            coverCache.clearMemoryCache()
 | 
			
		||||
                            SetAsCoverResult.Success
 | 
			
		||||
                        } else {
 | 
			
		||||
                            SetAsCoverResult.AddToLibraryFirst
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,8 @@ import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 | 
			
		||||
import eu.kanade.tachiyomi.source.LocalSource
 | 
			
		||||
import eu.kanade.tachiyomi.source.model.SManga
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
import java.util.Date
 | 
			
		||||
 | 
			
		||||
fun Manga.isLocal() = source == LocalSource.ID
 | 
			
		||||
@@ -36,7 +38,7 @@ fun Manga.prepUpdateCover(coverCache: CoverCache, remoteManga: SManga, refreshSa
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun Manga.hasCustomCover(coverCache: CoverCache): Boolean {
 | 
			
		||||
fun Manga.hasCustomCover(coverCache: CoverCache = Injekt.get()): Boolean {
 | 
			
		||||
    return coverCache.getCustomCoverFile(id).exists()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user