MangaCoverFetcher: Handle moving cover cache after adding to library (#6885)

Move cover cache to separate cache dir after the parent manga is added to library
This commit is contained in:
Ivan Iskandar 2022-04-08 23:10:06 +07:00 committed by GitHub
parent a8b53499af
commit ac980a4dbf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -16,12 +16,15 @@ import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.network.await
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.util.system.logcat
import logcat.LogPriority
import okhttp3.CacheControl import okhttp3.CacheControl
import okhttp3.Call import okhttp3.Call
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import okhttp3.internal.closeQuietly import okhttp3.internal.closeQuietly
import okio.Path.Companion.toOkioPath import okio.Path.Companion.toOkioPath
import okio.Source
import okio.buffer import okio.buffer
import okio.sink import okio.sink
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -78,19 +81,26 @@ class MangaCoverFetcher(
private suspend fun httpLoader(): FetchResult { private suspend fun httpLoader(): FetchResult {
// Only cache separately if it's a library item // Only cache separately if it's a library item
val coverCacheFile = if (manga.favorite) { val libraryCoverCacheFile = if (manga.favorite) {
coverCache.getCoverFile(manga) ?: error("No cover specified") coverCache.getCoverFile(manga) ?: error("No cover specified")
} else { } else {
null null
} }
if (coverCacheFile?.exists() == true && options.diskCachePolicy.readEnabled) { if (libraryCoverCacheFile?.exists() == true && options.diskCachePolicy.readEnabled) {
return fileLoader(coverCacheFile) return fileLoader(libraryCoverCacheFile)
} }
var snapshot = readFromDiskCache() var snapshot = readFromDiskCache()
try { try {
// Fetch from disk cache // Fetch from disk cache
if (snapshot != null) { if (snapshot != null) {
val snapshotCoverCache = moveSnapshotToCoverCache(snapshot, libraryCoverCacheFile)
if (snapshotCoverCache != null) {
// Read from cover cache after added to library
return fileLoader(snapshotCoverCache)
}
// Read from snapshot
return SourceResult( return SourceResult(
source = snapshot.toImageSource(), source = snapshot.toImageSource(),
mimeType = "image/*", mimeType = "image/*",
@ -102,13 +112,14 @@ class MangaCoverFetcher(
val response = executeNetworkRequest() val response = executeNetworkRequest()
val responseBody = checkNotNull(response.body) { "Null response source" } val responseBody = checkNotNull(response.body) { "Null response source" }
try { try {
snapshot = writeToDiskCache(snapshot, response) // Read from cover cache after library manga cover updated
val responseCoverCache = writeResponseToCoverCache(response, libraryCoverCacheFile)
if (coverCacheFile != null) { if (responseCoverCache != null) {
writeToCoverCache(coverCacheFile, response) return fileLoader(responseCoverCache)
} }
// Read from disk cache // Read from disk cache
snapshot = writeToDiskCache(snapshot, response)
if (snapshot != null) { if (snapshot != null) {
return SourceResult( return SourceResult(
source = snapshot.toImageSource(), source = snapshot.toImageSource(),
@ -133,21 +144,6 @@ class MangaCoverFetcher(
} }
} }
private fun writeToCoverCache(cacheFile: File, response: Response) {
if (!options.diskCachePolicy.writeEnabled) return
try {
response.body!!.source().use { input ->
cacheFile.parentFile?.mkdirs()
if (cacheFile.exists()) {
cacheFile.delete()
}
cacheFile.sink().buffer().use { output ->
output.writeAll(input)
}
}
} catch (_: Exception) {}
}
private suspend fun executeNetworkRequest(): Response { private suspend fun executeNetworkRequest(): Response {
val client = sourceLazy.value?.client ?: callFactoryLazy.value val client = sourceLazy.value?.client ?: callFactoryLazy.value
val response = client.newCall(newRequest()).await() val response = client.newCall(newRequest()).await()
@ -185,6 +181,48 @@ class MangaCoverFetcher(
return request.build() return request.build()
} }
private fun moveSnapshotToCoverCache(snapshot: DiskCache.Snapshot, cacheFile: File?): File? {
if (cacheFile == null) return null
return try {
diskCacheLazy.value.run {
fileSystem.source(snapshot.data).use { input ->
writeSourceToCoverCache(input, cacheFile)
}
remove(diskCacheKey!!)
}
cacheFile.takeIf { it.exists() }
} catch (e: Exception) {
logcat(LogPriority.ERROR, e) { "Failed to write snapshot data to cover cache ${cacheFile.name}" }
null
}
}
private fun writeResponseToCoverCache(response: Response, cacheFile: File?): File? {
if (cacheFile == null || !options.diskCachePolicy.writeEnabled) return null
return try {
response.peekBody(Long.MAX_VALUE).source().use { input ->
writeSourceToCoverCache(input, cacheFile)
}
cacheFile.takeIf { it.exists() }
} catch (e: Exception) {
logcat(LogPriority.ERROR, e) { "Failed to write response data to cover cache ${cacheFile.name}" }
null
}
}
private fun writeSourceToCoverCache(input: Source, cacheFile: File) {
cacheFile.parentFile?.mkdirs()
cacheFile.delete()
try {
cacheFile.sink().buffer().use { output ->
output.writeAll(input)
}
} catch (e: Exception) {
cacheFile.delete()
throw e
}
}
private fun readFromDiskCache(): DiskCache.Snapshot? { 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
} }