Fix page previews cache

This commit is contained in:
Jobobby04 2023-10-27 17:14:38 -04:00
parent d45563e58d
commit d600ddc11a
6 changed files with 108 additions and 59 deletions

View File

@ -26,7 +26,7 @@ android {
defaultConfig { defaultConfig {
applicationId = "eu.kanade.tachiyomi.sy" applicationId = "eu.kanade.tachiyomi.sy"
versionCode = 57 versionCode = 58
versionName = "1.9.3" versionName = "1.9.3"
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")

View File

@ -6,12 +6,13 @@ import com.jakewharton.disklrucache.DiskLruCache
import eu.kanade.tachiyomi.source.PagePreviewPage import eu.kanade.tachiyomi.source.PagePreviewPage
import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.storage.DiskUtil
import eu.kanade.tachiyomi.util.storage.saveTo import eu.kanade.tachiyomi.util.storage.saveTo
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import okhttp3.Response import logcat.LogPriority
import okio.Source
import okio.buffer import okio.buffer
import okio.sink import okio.sink
import tachiyomi.core.util.system.logcat
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.File import java.io.File
@ -159,7 +160,7 @@ class PagePreviewCache(private val context: Context) {
* @throws IOException page error. * @throws IOException page error.
*/ */
@Throws(IOException::class) @Throws(IOException::class)
fun putImageToCache(imageUrl: String, response: Response) { fun putImageToCache(imageUrl: String, source: Source) {
// Initialize editor (edits the values for an entry). // Initialize editor (edits the values for an entry).
var editor: DiskLruCache.Editor? = null var editor: DiskLruCache.Editor? = null
@ -169,12 +170,12 @@ class PagePreviewCache(private val context: Context) {
editor = diskCache.edit(key) ?: throw IOException("Unable to edit key") editor = diskCache.edit(key) ?: throw IOException("Unable to edit key")
// Get OutputStream and write page with Okio. // Get OutputStream and write page with Okio.
response.body.source().saveTo(editor.newOutputStream(0)) source.buffer().saveTo(editor.newOutputStream(0))
diskCache.flush() diskCache.flush()
editor.commit() editor.commit()
} finally { } finally {
response.body.close() source.close()
editor?.abortUnlessCommitted() editor?.abortUnlessCommitted()
} }
} }
@ -207,6 +208,7 @@ class PagePreviewCache(private val context: Context) {
// Remove file from cache. // Remove file from cache.
diskCache.remove(key) diskCache.remove(key)
} catch (e: Exception) { } catch (e: Exception) {
logcat(LogPriority.WARN, e) { "Failed to remove file from cache" }
false false
} }
} }

View File

@ -23,8 +23,6 @@ import okhttp3.Response
import okhttp3.internal.http.HTTP_NOT_MODIFIED import okhttp3.internal.http.HTTP_NOT_MODIFIED
import okio.Path.Companion.toOkioPath import okio.Path.Companion.toOkioPath
import okio.Source import okio.Source
import okio.buffer
import okio.sink
import tachiyomi.core.util.system.logcat import tachiyomi.core.util.system.logcat
import tachiyomi.domain.source.service.SourceManager import tachiyomi.domain.source.service.SourceManager
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -39,7 +37,9 @@ import java.io.File
class PagePreviewFetcher( class PagePreviewFetcher(
private val page: PagePreview, private val page: PagePreview,
private val options: Options, private val options: Options,
private val pagePreviewFileLazy: Lazy<File>, private val pagePreviewFile: () -> File,
private val isInCache: () -> Boolean,
private val writeToCache: (Source) -> Unit,
private val diskCacheKeyLazy: Lazy<String>, private val diskCacheKeyLazy: Lazy<String>,
private val sourceLazy: Lazy<PagePreviewSource?>, private val sourceLazy: Lazy<PagePreviewSource?>,
private val callFactoryLazy: Lazy<Call.Factory>, private val callFactoryLazy: Lazy<Call.Factory>,
@ -62,14 +62,14 @@ class PagePreviewFetcher(
} }
private suspend fun httpLoader(): FetchResult { private suspend fun httpLoader(): FetchResult {
if (pagePreviewFileLazy.value.exists() && options.diskCachePolicy.readEnabled) { if (isInCache() && options.diskCachePolicy.readEnabled) {
return fileLoader(pagePreviewFileLazy.value) return fileLoader(pagePreviewFile())
} }
var snapshot = readFromDiskCache() var snapshot = readFromDiskCache()
try { try {
// Fetch from disk cache // Fetch from disk cache
if (snapshot != null) { if (snapshot != null) {
val snapshotPagePreviewCache = moveSnapshotToPagePreviewCache(snapshot, pagePreviewFileLazy.value) val snapshotPagePreviewCache = moveSnapshotToPagePreviewCache(snapshot)
if (snapshotPagePreviewCache != null) { if (snapshotPagePreviewCache != null) {
// Read from page preview cache // Read from page preview cache
return fileLoader(snapshotPagePreviewCache) return fileLoader(snapshotPagePreviewCache)
@ -88,7 +88,7 @@ class PagePreviewFetcher(
val responseBody = checkNotNull(response.body) { "Null response source" } val responseBody = checkNotNull(response.body) { "Null response source" }
try { try {
// Read from page preview cache after page preview updated // Read from page preview cache after page preview updated
val responsePagePreviewCache = writeResponseToPagePreviewCache(response, pagePreviewFileLazy.value) val responsePagePreviewCache = writeResponseToPagePreviewCache(response)
if (responsePagePreviewCache != null) { if (responsePagePreviewCache != null) {
return fileLoader(responsePagePreviewCache) return fileLoader(responsePagePreviewCache)
} }
@ -153,60 +153,59 @@ class PagePreviewFetcher(
return request.build() return request.build()
} }
private fun moveSnapshotToPagePreviewCache(snapshot: DiskCache.Snapshot, cacheFile: File): File? { private fun moveSnapshotToPagePreviewCache(snapshot: DiskCache.Snapshot): File? {
return try { return try {
diskCacheLazy.value.run { diskCacheLazy.value.run {
fileSystem.source(snapshot.data).use { input -> fileSystem.source(snapshot.data).use { input ->
writeSourceToPagePreviewCache(input, cacheFile) writeSourceToPagePreviewCache(input)
} }
remove(diskCacheKey) remove(diskCacheKey)
} }
cacheFile.takeIf { it.exists() } return if (isInCache()) {
pagePreviewFile()
} else {
null
}
} catch (e: Exception) { } catch (e: Exception) {
logcat(LogPriority.ERROR, e) { "Failed to write snapshot data to page preview cache ${cacheFile.name}" } logcat(LogPriority.ERROR, e) { "Failed to write snapshot data to page preview cache $diskCacheKey" }
null null
} }
} }
private fun writeResponseToPagePreviewCache(response: Response, cacheFile: File): File? { private fun writeResponseToPagePreviewCache(response: Response): File? {
if (!options.diskCachePolicy.writeEnabled) return null if (!options.diskCachePolicy.writeEnabled) return null
return try { return try {
response.peekBody(Long.MAX_VALUE).source().use { input -> response.peekBody(Long.MAX_VALUE).source().use { input ->
writeSourceToPagePreviewCache(input, cacheFile) writeSourceToPagePreviewCache(input)
}
return if (isInCache()) {
pagePreviewFile()
} else {
null
} }
cacheFile.takeIf { it.exists() }
} catch (e: Exception) { } catch (e: Exception) {
logcat(LogPriority.ERROR, e) { "Failed to write response data to page preview cache ${cacheFile.name}" } logcat(LogPriority.ERROR, e) { "Failed to write response data to page preview cache $diskCacheKey" }
null null
} }
} }
private fun writeSourceToPagePreviewCache(input: Source, cacheFile: File) { private fun writeSourceToPagePreviewCache(input: Source) {
cacheFile.parentFile?.mkdirs() writeToCache(input)
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.openSnapshot(diskCacheKey) else null
} }
private fun writeToDiskCache( private fun writeToDiskCache(
response: Response, response: Response,
): DiskCache.Snapshot? { ): DiskCache.Snapshot? {
val editor = diskCacheLazy.value.edit(diskCacheKey) ?: return null val editor = diskCacheLazy.value.openEditor(diskCacheKey) ?: return null
try { try {
diskCacheLazy.value.fileSystem.write(editor.data) { diskCacheLazy.value.fileSystem.write(editor.data) {
response.body.source().readAll(this) response.body.source().readAll(this)
} }
return editor.commitAndGet() return editor.commitAndOpenSnapshot()
} catch (e: Exception) { } catch (e: Exception) {
try { try {
editor.abort() editor.abort()
@ -232,7 +231,9 @@ class PagePreviewFetcher(
return PagePreviewFetcher( return PagePreviewFetcher(
page = data, page = data,
options = options, options = options,
pagePreviewFileLazy = lazy { pagePreviewCache.getImageFile(data.imageUrl) }, pagePreviewFile = { pagePreviewCache.getImageFile(data.imageUrl) },
isInCache = { pagePreviewCache.isImageInCache(data.imageUrl) },
writeToCache = { pagePreviewCache.putImageToCache(data.imageUrl, it) },
diskCacheKeyLazy = lazy { PagePreviewKeyer().key(data, options) }, diskCacheKeyLazy = lazy { PagePreviewKeyer().key(data, options) },
sourceLazy = lazy { sourceManager.get(data.source) as? PagePreviewSource }, sourceLazy = lazy { sourceManager.get(data.source) as? PagePreviewSource },
callFactoryLazy = callFactoryLazy, callFactoryLazy = callFactoryLazy,

View File

@ -173,6 +173,7 @@ class MainActivity : BaseActivity() {
readerPreferences = Injekt.get(), readerPreferences = Injekt.get(),
backupPreferences = Injekt.get(), backupPreferences = Injekt.get(),
trackerManager = Injekt.get(), trackerManager = Injekt.get(),
pagePreviewCache = Injekt.get(),
) )
} else { } else {
false false

View File

@ -10,6 +10,7 @@ import eu.kanade.domain.ui.UiPreferences
import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.core.security.SecurityPreferences import eu.kanade.tachiyomi.core.security.SecurityPreferences
import eu.kanade.tachiyomi.data.backup.BackupCreateJob import eu.kanade.tachiyomi.data.backup.BackupCreateJob
import eu.kanade.tachiyomi.data.cache.PagePreviewCache
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.data.track.TrackerManager
import eu.kanade.tachiyomi.network.NetworkPreferences import eu.kanade.tachiyomi.network.NetworkPreferences
@ -39,6 +40,7 @@ import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.contentOrNull import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonPrimitive import kotlinx.serialization.json.jsonPrimitive
import logcat.LogPriority
import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.preference.PreferenceStore
import tachiyomi.core.preference.TriState import tachiyomi.core.preference.TriState
import tachiyomi.core.preference.getAndSet import tachiyomi.core.preference.getAndSet
@ -99,6 +101,7 @@ object EXHMigrations {
readerPreferences: ReaderPreferences, readerPreferences: ReaderPreferences,
backupPreferences: BackupPreferences, backupPreferences: BackupPreferences,
trackerManager: TrackerManager, trackerManager: TrackerManager,
pagePreviewCache: PagePreviewCache,
): Boolean { ): Boolean {
val lastVersionCode = preferenceStore.getInt("eh_last_version_code", 0) val lastVersionCode = preferenceStore.getInt("eh_last_version_code", 0)
val oldVersion = lastVersionCode.get() val oldVersion = lastVersionCode.get()
@ -559,6 +562,20 @@ object EXHMigrations {
uiPreferences.relativeTime().set(false) uiPreferences.relativeTime().set(false)
} }
} }
if (oldVersion under 58) {
pagePreviewCache.clear()
File(context.cacheDir, PagePreviewCache.PARAMETER_CACHE_DIRECTORY).listFiles()?.forEach {
if (it.name == "journal" || it.name.startsWith("journal.")) {
return@forEach
}
try {
it.delete()
} catch (e: Exception) {
logcat(LogPriority.WARN, e) { "Failed to remove file from cache" }
}
}
}
// if (oldVersion under 1) { } (1 is current release version) // if (oldVersion under 1) { } (1 is current release version)
// do stuff here when releasing changed crap // do stuff here when releasing changed crap

View File

@ -8,6 +8,7 @@ import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.domain.ui.UiPreferences import eu.kanade.domain.ui.UiPreferences
import eu.kanade.tachiyomi.core.security.SecurityPreferences import eu.kanade.tachiyomi.core.security.SecurityPreferences
import eu.kanade.tachiyomi.data.backup.models.Backup import eu.kanade.tachiyomi.data.backup.models.Backup
import eu.kanade.tachiyomi.data.cache.PagePreviewCache
import eu.kanade.tachiyomi.data.track.TrackerManager import eu.kanade.tachiyomi.data.track.TrackerManager
import eu.kanade.tachiyomi.network.NetworkPreferences import eu.kanade.tachiyomi.network.NetworkPreferences
import eu.kanade.tachiyomi.source.AndroidSourceManager import eu.kanade.tachiyomi.source.AndroidSourceManager
@ -40,37 +41,64 @@ import java.util.UUID
@Suppress("unused") @Suppress("unused")
object DebugFunctions { object DebugFunctions {
val app: Application by injectLazy() private val app: Application by injectLazy()
val handler: DatabaseHandler by injectLazy() private val handler: DatabaseHandler by injectLazy()
val prefsStore: PreferenceStore by injectLazy() private val prefsStore: PreferenceStore by injectLazy()
val basePrefs: BasePreferences by injectLazy() private val basePrefs: BasePreferences by injectLazy()
val uiPrefs: UiPreferences by injectLazy() private val uiPrefs: UiPreferences by injectLazy()
val networkPrefs: NetworkPreferences by injectLazy() private val networkPrefs: NetworkPreferences by injectLazy()
val sourcePrefs: SourcePreferences by injectLazy() private val sourcePrefs: SourcePreferences by injectLazy()
val securityPrefs: SecurityPreferences by injectLazy() private val securityPrefs: SecurityPreferences by injectLazy()
val libraryPrefs: LibraryPreferences by injectLazy() private val libraryPrefs: LibraryPreferences by injectLazy()
val readerPrefs: ReaderPreferences by injectLazy() private val readerPrefs: ReaderPreferences by injectLazy()
val backupPrefs: BackupPreferences by injectLazy() private val backupPrefs: BackupPreferences by injectLazy()
val trackerManager: TrackerManager by injectLazy() private val trackerManager: TrackerManager by injectLazy()
val sourceManager: SourceManager by injectLazy() private val sourceManager: SourceManager by injectLazy()
val updateManga: UpdateManga by injectLazy() private val updateManga: UpdateManga by injectLazy()
val getFavorites: GetFavorites by injectLazy() private val getFavorites: GetFavorites by injectLazy()
val getFlatMetadataById: GetFlatMetadataById by injectLazy() private val getFlatMetadataById: GetFlatMetadataById by injectLazy()
val insertFlatMetadata: InsertFlatMetadata by injectLazy() private val insertFlatMetadata: InsertFlatMetadata by injectLazy()
val getExhFavoriteMangaWithMetadata: GetExhFavoriteMangaWithMetadata by injectLazy() private val getExhFavoriteMangaWithMetadata: GetExhFavoriteMangaWithMetadata by injectLazy()
val getSearchMetadata: GetSearchMetadata by injectLazy() private val getSearchMetadata: GetSearchMetadata by injectLazy()
val getAllManga: GetAllManga by injectLazy() private val getAllManga: GetAllManga by injectLazy()
private val pagePreviewCache: PagePreviewCache by injectLazy()
fun forceUpgradeMigration() { fun forceUpgradeMigration() {
val lastVersionCode = prefsStore.getInt("eh_last_version_code", 0) val lastVersionCode = prefsStore.getInt("eh_last_version_code", 0)
lastVersionCode.set(1) lastVersionCode.set(1)
EXHMigrations.upgrade(app, prefsStore, basePrefs, uiPrefs, networkPrefs, sourcePrefs, securityPrefs, libraryPrefs, readerPrefs, backupPrefs, trackerManager) EXHMigrations.upgrade(
context = app,
preferenceStore = prefsStore,
basePreferences = basePrefs,
uiPreferences = uiPrefs,
networkPreferences = networkPrefs,
sourcePreferences = sourcePrefs,
securityPreferences = securityPrefs,
libraryPreferences = libraryPrefs,
readerPreferences = readerPrefs,
backupPreferences = backupPrefs,
trackerManager = trackerManager,
pagePreviewCache = pagePreviewCache,
)
} }
fun forceSetupJobs() { fun forceSetupJobs() {
val lastVersionCode = prefsStore.getInt("eh_last_version_code", 0) val lastVersionCode = prefsStore.getInt("eh_last_version_code", 0)
lastVersionCode.set(0) lastVersionCode.set(0)
EXHMigrations.upgrade(app, prefsStore, basePrefs, uiPrefs, networkPrefs, sourcePrefs, securityPrefs, libraryPrefs, readerPrefs, backupPrefs, trackerManager) EXHMigrations.upgrade(
context = app,
preferenceStore = prefsStore,
basePreferences = basePrefs,
uiPreferences = uiPrefs,
networkPreferences = networkPrefs,
sourcePreferences = sourcePrefs,
securityPreferences = securityPrefs,
libraryPreferences = libraryPrefs,
readerPreferences = readerPrefs,
backupPreferences = backupPrefs,
trackerManager = trackerManager,
pagePreviewCache = pagePreviewCache,
)
} }
fun resetAgedFlagInEXHManga() { fun resetAgedFlagInEXHManga() {
@ -190,7 +218,7 @@ object DebugFunctions {
""" """
{ {
id: ${info.id}, id: ${info.id},
isPeriodic: ${j.extras["EXTRA_IS_PERIODIC"]}, isPeriodic: ${j.extras.getBoolean("EXTRA_IS_PERIODIC")},
state: ${info.state.name}, state: ${info.state.name},
tags: [ tags: [
${info.tags.joinToString(separator = ",\n ")} ${info.tags.joinToString(separator = ",\n ")}