refactor: Add cover_last_modified

This commit is contained in:
Ahmad Ansori Palembani 2024-08-17 14:13:49 +07:00
parent 653b2d7839
commit c9b302ab21
Signed by: null2264
GPG key ID: BA64F8B60AF3EFB6
23 changed files with 158 additions and 104 deletions

View file

@ -4,8 +4,8 @@ import android.content.Context
import android.text.format.Formatter import android.text.format.Formatter
import co.touchlab.kermit.Logger import co.touchlab.kermit.Logger
import coil3.imageLoader import coil3.imageLoader
import coil3.memory.MemoryCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.updateCoverLastModified
import eu.kanade.tachiyomi.domain.manga.models.Manga import eu.kanade.tachiyomi.domain.manga.models.Manga
import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.storage.DiskUtil
import eu.kanade.tachiyomi.util.system.e import eu.kanade.tachiyomi.util.system.e
@ -71,7 +71,10 @@ class CoverCache(val context: Context) {
val db = Injekt.get<DatabaseHelper>() val db = Injekt.get<DatabaseHelper>()
var deletedSize = 0L var deletedSize = 0L
val urls = db.getFavoriteMangas().executeOnIO().mapNotNull { val urls = db.getFavoriteMangas().executeOnIO().mapNotNull {
it.thumbnail_url?.let { url -> return@mapNotNull DiskUtil.hashKeyForDisk(url) } it.thumbnail_url?.let { url ->
it.updateCoverLastModified()
return@mapNotNull DiskUtil.hashKeyForDisk(url)
}
null null
} }
val files = cacheDir.listFiles()?.iterator() ?: return val files = cacheDir.listFiles()?.iterator() ?: return
@ -170,7 +173,6 @@ class CoverCache(val context: Context) {
fun setCustomCoverToCache(manga: Manga, inputStream: InputStream) { fun setCustomCoverToCache(manga: Manga, inputStream: InputStream) {
getCustomCoverFile(manga).outputStream().use { getCustomCoverFile(manga).outputStream().use {
inputStream.copyTo(it) inputStream.copyTo(it)
removeFromMemory(manga, true)
} }
} }
@ -184,14 +186,13 @@ class CoverCache(val context: Context) {
val result = getCustomCoverFile(manga).let { val result = getCustomCoverFile(manga).let {
it.exists() && it.delete() it.exists() && it.delete()
} }
removeFromMemory(manga, true)
return result return result
} }
/** /**
* Returns the cover from cache. * Returns the cover from cache.
* *
* @param thumbnailUrl the thumbnail url. * @param mangaThumbnailUrl the thumbnail url.
* @return cover image. * @return cover image.
*/ */
fun getCoverFile(mangaThumbnailUrl: String?, isOnline: Boolean = false): File? { fun getCoverFile(mangaThumbnailUrl: String?, isOnline: Boolean = false): File? {
@ -200,26 +201,6 @@ class CoverCache(val context: Context) {
} }
} }
fun removeFromMemory(manga: Manga, custom: Boolean = false) {
if (custom) {
context.imageLoader.memoryCache?.remove(MemoryCache.Key(manga.key()))
return
}
manga.thumbnail_url?.let {
if (it.isEmpty()) return
context.imageLoader.memoryCache
?.remove(MemoryCache.Key(if (!manga.favorite) it else DiskUtil.hashKeyForDisk(it)))
}
}
fun deleteFromCache(name: String?) {
if (name.isNullOrEmpty()) return
val file = getCoverFile(name, true) ?: return
context.imageLoader.memoryCache?.remove(MemoryCache.Key(file.name))
if (file.exists()) file.delete()
}
/** /**
* Delete the cover file from the disk cache and optional from memory cache * Delete the cover file from the disk cache and optional from memory cache
* *
@ -235,8 +216,7 @@ class CoverCache(val context: Context) {
// Remove file // Remove file
getCoverFile(manga.thumbnail_url, !manga.favorite)?.let { getCoverFile(manga.thumbnail_url, !manga.favorite)?.let {
removeFromMemory(manga) if (it.exists()) it.delete()
it.delete()
} }
if (deleteCustom) deleteCustomCover(manga) if (deleteCustom) deleteCustomCover(manga)
} }

View file

@ -10,6 +10,7 @@ import coil3.request.Disposable
import coil3.request.ImageRequest import coil3.request.ImageRequest
import coil3.target.ImageViewTarget import coil3.target.ImageViewTarget
import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.models.updateCoverLastModified
import eu.kanade.tachiyomi.domain.manga.models.Manga import eu.kanade.tachiyomi.domain.manga.models.Manga
import eu.kanade.tachiyomi.util.system.launchIO import eu.kanade.tachiyomi.util.system.launchIO
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -32,7 +33,7 @@ class LibraryMangaImageTarget(
options.inJustDecodeBounds = true options.inJustDecodeBounds = true
BitmapFactory.decodeFile(file.path, options) BitmapFactory.decodeFile(file.path, options)
if (options.outWidth == -1 || options.outHeight == -1) { if (options.outWidth == -1 || options.outHeight == -1) {
coverCache.removeFromMemory(manga) manga.updateCoverLastModified()
file.delete() file.delete()
} }
} }

View file

@ -9,13 +9,15 @@ import eu.kanade.tachiyomi.util.storage.DiskUtil
class MangaCoverKeyer : Keyer<Manga> { class MangaCoverKeyer : Keyer<Manga> {
override fun key(data: Manga, options: Options): String? { override fun key(data: Manga, options: Options): String? {
val hasCustomCover by lazy { data.hasCustomCover() } val hasCustomCover by lazy { data.hasCustomCover() }
val suffix by lazy { ";${data.cover_last_modified}" }
if (data.thumbnail_url.isNullOrBlank() && !hasCustomCover) return null if (data.thumbnail_url.isNullOrBlank() && !hasCustomCover) return null
if (hasCustomCover) return data.key() if (hasCustomCover) return "${data.id}$suffix"
return if (!data.favorite) { return if (!data.favorite) {
data.thumbnail_url!! data.thumbnail_url!!
} else { } else {
DiskUtil.hashKeyForDisk(data.thumbnail_url!!) DiskUtil.hashKeyForDisk(data.thumbnail_url!!)
} } + suffix
} }
} }

View file

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.data.database package eu.kanade.tachiyomi.data.database
import android.database.Cursor
import com.pushtorefresh.storio.sqlite.StorIOSQLite import com.pushtorefresh.storio.sqlite.StorIOSQLite
inline fun StorIOSQLite.inTransaction(block: () -> Unit) { inline fun StorIOSQLite.inTransaction(block: () -> Unit) {
@ -22,3 +23,5 @@ inline fun <T> StorIOSQLite.inTransactionReturn(block: () -> T): T {
lowLevel().endTransaction() lowLevel().endTransaction()
} }
} }
fun Cursor.getBoolean(index: Int) = getLong(index) > 0

View file

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.data.database.mappers package eu.kanade.tachiyomi.data.database.mappers
import android.annotation.SuppressLint
import android.content.ContentValues import android.content.ContentValues
import android.database.Cursor import android.database.Cursor
import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping
@ -9,10 +10,12 @@ import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
import com.pushtorefresh.storio.sqlite.queries.InsertQuery import com.pushtorefresh.storio.sqlite.queries.InsertQuery
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
import eu.kanade.tachiyomi.data.database.models.MangaImpl import eu.kanade.tachiyomi.data.database.getBoolean
import eu.kanade.tachiyomi.data.database.models.mapper
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_ARTIST import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_ARTIST
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_AUTHOR import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_AUTHOR
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_CHAPTER_FLAGS import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_CHAPTER_FLAGS
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_COVER_LAST_MODIFIED
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_DATE_ADDED import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_DATE_ADDED
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_DESCRIPTION import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_DESCRIPTION
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_FAVORITE import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_FAVORITE
@ -59,8 +62,8 @@ class MangaPutResolver : DefaultPutResolver<Manga>() {
put(COL_AUTHOR, obj.originalAuthor) put(COL_AUTHOR, obj.originalAuthor)
put(COL_DESCRIPTION, obj.originalDescription) put(COL_DESCRIPTION, obj.originalDescription)
put(COL_GENRE, obj.originalGenre) put(COL_GENRE, obj.originalGenre)
put(COL_TITLE, obj.originalTitle) put(COL_TITLE, obj.ogTitle)
put(COL_STATUS, obj.originalStatus) put(COL_STATUS, obj.ogStatus)
put(COL_THUMBNAIL_URL, obj.thumbnail_url) put(COL_THUMBNAIL_URL, obj.thumbnail_url)
put(COL_FAVORITE, obj.favorite) put(COL_FAVORITE, obj.favorite)
put(COL_LAST_UPDATE, obj.last_update) put(COL_LAST_UPDATE, obj.last_update)
@ -70,40 +73,41 @@ class MangaPutResolver : DefaultPutResolver<Manga>() {
put(COL_CHAPTER_FLAGS, obj.chapter_flags) put(COL_CHAPTER_FLAGS, obj.chapter_flags)
put(COL_DATE_ADDED, obj.date_added) put(COL_DATE_ADDED, obj.date_added)
put(COL_FILTERED_SCANLATORS, obj.filtered_scanlators) put(COL_FILTERED_SCANLATORS, obj.filtered_scanlators)
put(COL_UPDATE_STRATEGY, obj.update_strategy.let(updateStrategyAdapter::encode).toInt()) put(COL_UPDATE_STRATEGY, obj.update_strategy.let(updateStrategyAdapter::encode))
put(COL_COVER_LAST_MODIFIED, obj.cover_last_modified)
} }
} }
interface BaseMangaGetResolver { interface BaseMangaGetResolver {
fun mapBaseFromCursor(manga: Manga, cursor: Cursor) = manga.apply { @SuppressLint("Range")
id = cursor.getLong(cursor.getColumnIndex(COL_ID)) fun mapBaseFromCursor(cursor: Cursor) = Manga.mapper(
source = cursor.getLong(cursor.getColumnIndex(COL_SOURCE)) id = cursor.getLong(cursor.getColumnIndex(COL_ID)),
url = cursor.getString(cursor.getColumnIndex(COL_URL)) source = cursor.getLong(cursor.getColumnIndex(COL_SOURCE)),
artist = cursor.getString(cursor.getColumnIndex(COL_ARTIST)) url = cursor.getString(cursor.getColumnIndex(COL_URL)),
author = cursor.getString(cursor.getColumnIndex(COL_AUTHOR)) artist = cursor.getString(cursor.getColumnIndex(COL_ARTIST)),
description = cursor.getString(cursor.getColumnIndex(COL_DESCRIPTION)) author = cursor.getString(cursor.getColumnIndex(COL_AUTHOR)),
genre = cursor.getString(cursor.getColumnIndex(COL_GENRE)) description = cursor.getString(cursor.getColumnIndex(COL_DESCRIPTION)),
title = cursor.getString(cursor.getColumnIndex(COL_TITLE)) genre = cursor.getString(cursor.getColumnIndex(COL_GENRE)),
status = cursor.getInt(cursor.getColumnIndex(COL_STATUS)) title = cursor.getString(cursor.getColumnIndex(COL_TITLE)),
thumbnail_url = cursor.getString(cursor.getColumnIndex(COL_THUMBNAIL_URL)) status = cursor.getLong(cursor.getColumnIndex(COL_STATUS)),
favorite = cursor.getInt(cursor.getColumnIndex(COL_FAVORITE)) == 1 thumbnailUrl = cursor.getString(cursor.getColumnIndex(COL_THUMBNAIL_URL)),
last_update = cursor.getLong(cursor.getColumnIndex(COL_LAST_UPDATE)) favorite = cursor.getBoolean(cursor.getColumnIndex(COL_FAVORITE)),
initialized = cursor.getInt(cursor.getColumnIndex(COL_INITIALIZED)) == 1 lastUpdate = cursor.getLong(cursor.getColumnIndex(COL_LAST_UPDATE)),
viewer_flags = cursor.getInt(cursor.getColumnIndex(COL_VIEWER)) initialized = cursor.getBoolean(cursor.getColumnIndex(COL_INITIALIZED)),
chapter_flags = cursor.getInt(cursor.getColumnIndex(COL_CHAPTER_FLAGS)) viewerFlags = cursor.getLong(cursor.getColumnIndex(COL_VIEWER)),
hide_title = cursor.getInt(cursor.getColumnIndex(COL_HIDE_TITLE)) == 1 chapterFlags = cursor.getLong(cursor.getColumnIndex(COL_CHAPTER_FLAGS)),
date_added = cursor.getLong(cursor.getColumnIndex(COL_DATE_ADDED)) hideTitle = cursor.getBoolean(cursor.getColumnIndex(COL_HIDE_TITLE)),
filtered_scanlators = cursor.getString(cursor.getColumnIndex(COL_FILTERED_SCANLATORS)) dateAdded = cursor.getLong(cursor.getColumnIndex(COL_DATE_ADDED)),
update_strategy = cursor.getInt(cursor.getColumnIndex(COL_UPDATE_STRATEGY)).let { filteredScanlators = cursor.getString(cursor.getColumnIndex(COL_FILTERED_SCANLATORS)),
updateStrategyAdapter.decode(it.toLong()) updateStrategy = cursor.getLong(cursor.getColumnIndex(COL_UPDATE_STRATEGY)),
} coverLastModified = cursor.getLong(cursor.getColumnIndex(COL_COVER_LAST_MODIFIED)),
} )
} }
open class MangaGetResolver : DefaultGetResolver<Manga>(), BaseMangaGetResolver { open class MangaGetResolver : DefaultGetResolver<Manga>(), BaseMangaGetResolver {
override fun mapFromCursor(cursor: Cursor): Manga { override fun mapFromCursor(cursor: Cursor): Manga {
return mapBaseFromCursor(MangaImpl(), cursor) return mapBaseFromCursor(cursor)
} }
} }

View file

@ -1,8 +1,8 @@
package eu.kanade.tachiyomi.data.database.models package eu.kanade.tachiyomi.data.database.models
import eu.kanade.tachiyomi.ui.library.LibraryItem import eu.kanade.tachiyomi.ui.library.LibraryItem
import yokai.data.updateStrategyAdapter
import kotlin.math.roundToInt import kotlin.math.roundToInt
import yokai.data.updateStrategyAdapter
data class LibraryManga( data class LibraryManga(
var unread: Int = 0, var unread: Int = 0,
@ -49,6 +49,7 @@ data class LibraryManga(
} }
fun mapper( fun mapper(
// manga
id: Long, id: Long,
source: Long, source: Long,
url: String, url: String,
@ -59,15 +60,17 @@ data class LibraryManga(
title: String, title: String,
status: Long, status: Long,
thumbnailUrl: String?, thumbnailUrl: String?,
favorite: Long, favorite: Boolean,
lastUpdate: Long?, lastUpdate: Long?,
initialized: Boolean, initialized: Boolean,
viewerFlags: Long, viewerFlags: Long,
hideTitle: Long, hideTitle: Boolean,
chapterFlags: Long, chapterFlags: Long,
dateAdded: Long?, dateAdded: Long?,
filteredScanlators: String?, filteredScanlators: String?,
updateStrategy: Long, updateStrategy: Long,
coverLastModified: Long,
// libraryManga
total: Long, total: Long,
readCount: Double, readCount: Double,
bookmarkCount: Double, bookmarkCount: Double,
@ -86,15 +89,16 @@ data class LibraryManga(
this.title = title this.title = title
this.status = status.toInt() this.status = status.toInt()
this.thumbnail_url = thumbnailUrl this.thumbnail_url = thumbnailUrl
this.favorite = favorite > 0 this.favorite = favorite
this.last_update = lastUpdate ?: 0L this.last_update = lastUpdate ?: 0L
this.initialized = initialized this.initialized = initialized
this.viewer_flags = viewerFlags.toInt() this.viewer_flags = viewerFlags.toInt()
this.hide_title = hideTitle > 0 this.hide_title = hideTitle
this.chapter_flags = chapterFlags.toInt() this.chapter_flags = chapterFlags.toInt()
this.date_added = dateAdded ?: 0L this.date_added = dateAdded ?: 0L
this.filtered_scanlators = filteredScanlators this.filtered_scanlators = filteredScanlators
this.update_strategy = updateStrategy.let(updateStrategyAdapter::decode) this.update_strategy = updateStrategy.let(updateStrategyAdapter::decode)
this.cover_last_modified = coverLastModified
this.read = readCount.roundToInt() this.read = readCount.roundToInt()
this.unread = maxOf((total - readCount).roundToInt(), 0) this.unread = maxOf((total - readCount).roundToInt(), 0)
this.totalChapters = total.toInt() this.totalChapters = total.toInt()

View file

@ -13,6 +13,7 @@ import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.ui.reader.settings.OrientationType import eu.kanade.tachiyomi.ui.reader.settings.OrientationType
import eu.kanade.tachiyomi.ui.reader.settings.ReadingModeType import eu.kanade.tachiyomi.ui.reader.settings.ReadingModeType
import eu.kanade.tachiyomi.util.isLocal
import eu.kanade.tachiyomi.util.manga.MangaCoverMetadata import eu.kanade.tachiyomi.util.manga.MangaCoverMetadata
import eu.kanade.tachiyomi.util.system.withIOContext import eu.kanade.tachiyomi.util.system.withIOContext
import java.util.Locale import java.util.Locale
@ -21,6 +22,8 @@ import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import yokai.data.updateStrategyAdapter import yokai.data.updateStrategyAdapter
import yokai.domain.chapter.interactor.GetChapter import yokai.domain.chapter.interactor.GetChapter
import yokai.domain.manga.interactor.UpdateManga
import yokai.domain.manga.models.MangaUpdate
import yokai.i18n.MR import yokai.i18n.MR
import yokai.util.lang.getString import yokai.util.lang.getString
@ -193,15 +196,16 @@ fun Manga.Companion.mapper(
title: String, title: String,
status: Long, status: Long,
thumbnailUrl: String?, thumbnailUrl: String?,
favorite: Long, favorite: Boolean,
lastUpdate: Long?, lastUpdate: Long?,
initialized: Boolean, initialized: Boolean,
viewerFlags: Long, viewerFlags: Long,
hideTitle: Long, hideTitle: Boolean,
chapterFlags: Long, chapterFlags: Long,
dateAdded: Long?, dateAdded: Long?,
filteredScanlators: String?, filteredScanlators: String?,
updateStrategy: Long updateStrategy: Long,
coverLastModified: Long,
) = create(source).apply { ) = create(source).apply {
this.id = id this.id = id
this.url = url this.url = url
@ -212,17 +216,41 @@ fun Manga.Companion.mapper(
this.title = title this.title = title
this.status = status.toInt() this.status = status.toInt()
this.thumbnail_url = thumbnailUrl this.thumbnail_url = thumbnailUrl
this.favorite = favorite > 0 this.favorite = favorite
this.last_update = lastUpdate ?: 0L this.last_update = lastUpdate ?: 0L
this.initialized = initialized this.initialized = initialized
this.viewer_flags = viewerFlags.toInt() this.viewer_flags = viewerFlags.toInt()
this.chapter_flags = chapterFlags.toInt() this.chapter_flags = chapterFlags.toInt()
this.hide_title = hideTitle > 0 this.hide_title = hideTitle
this.date_added = dateAdded ?: 0L this.date_added = dateAdded ?: 0L
this.filtered_scanlators = filteredScanlators this.filtered_scanlators = filteredScanlators
this.update_strategy = updateStrategy.let(updateStrategyAdapter::decode) this.update_strategy = updateStrategy.let(updateStrategyAdapter::decode)
this.cover_last_modified = coverLastModified
} }
fun Manga.hasCustomCover(coverCache: CoverCache = Injekt.get()): Boolean { fun Manga.hasCustomCover(coverCache: CoverCache = Injekt.get()): Boolean {
return coverCache.getCustomCoverFile(this).exists() return coverCache.getCustomCoverFile(this).exists()
} }
/**
* Call before updating [Manga.thumbnail_url] to ensure old cover can be cleared from cache
*/
fun Manga.prepareCoverUpdate(coverCache: CoverCache = Injekt.get()) {
cover_last_modified = System.currentTimeMillis()
if (!isLocal()) {
coverCache.deleteFromCache(this, true)
}
}
fun Manga.removeCover(coverCache: CoverCache = Injekt.get(), deleteCustom: Boolean = true) {
if (isLocal()) return
cover_last_modified = System.currentTimeMillis()
coverCache.deleteFromCache(this, deleteCustom)
}
suspend fun Manga.updateCoverLastModified(updateManga: UpdateManga = Injekt.get()) {
cover_last_modified = System.currentTimeMillis()
updateManga.await(MangaUpdate(id = id!!, coverLastModified = cover_last_modified))
}

View file

@ -5,6 +5,7 @@ import eu.kanade.tachiyomi.domain.manga.models.Manga
class MangaChapter(val manga: Manga, val chapter: Chapter) { class MangaChapter(val manga: Manga, val chapter: Chapter) {
companion object { companion object {
fun mapper( fun mapper(
// manga
mangaId: Long, mangaId: Long,
source: Long, source: Long,
mangaUrl: String, mangaUrl: String,
@ -15,15 +16,17 @@ class MangaChapter(val manga: Manga, val chapter: Chapter) {
title: String, title: String,
status: Long, status: Long,
thumbnailUrl: String?, thumbnailUrl: String?,
favorite: Long, favorite: Boolean,
lastUpdate: Long?, lastUpdate: Long?,
initialized: Boolean, initialized: Boolean,
viewer: Long, viewer: Long,
hideTitle: Long, hideTitle: Boolean,
chapterFlags: Long, chapterFlags: Long,
dateAdded: Long?, dateAdded: Long?,
filteredScanlators: String?, filteredScanlators: String?,
updateStrategy: Long, updateStrategy: Long,
coverLastModified: Long,
// chapter
chapterId: Long, chapterId: Long,
_mangaId: Long, _mangaId: Long,
chapterUrl: String, chapterUrl: String,
@ -58,6 +61,7 @@ class MangaChapter(val manga: Manga, val chapter: Chapter) {
dateAdded = dateAdded, dateAdded = dateAdded,
filteredScanlators = filteredScanlators, filteredScanlators = filteredScanlators,
updateStrategy = updateStrategy, updateStrategy = updateStrategy,
coverLastModified = coverLastModified,
), ),
Chapter.mapper( Chapter.mapper(
id = chapterId, id = chapterId,

View file

@ -81,6 +81,8 @@ open class MangaImpl : Manga {
override var ogGenre: String? = null override var ogGenre: String? = null
override var ogStatus: Int = 0 override var ogStatus: Int = 0
override var cover_last_modified: Long = 0L
override fun copyFrom(other: SManga) { override fun copyFrom(other: SManga) {
if (other is MangaImpl && other::ogTitle.isInitialized && if (other is MangaImpl && other::ogTitle.isInitialized &&
other.title.isNotBlank() && other.ogTitle != ogTitle other.title.isNotBlank() && other.ogTitle != ogTitle

View file

@ -42,4 +42,5 @@ object MangaTable {
const val COL_UPDATE_STRATEGY = "update_strategy" const val COL_UPDATE_STRATEGY = "update_strategy"
const val COL_COVER_LAST_MODIFIED = "cover_last_modified"
} }

View file

@ -25,6 +25,7 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.prepareCoverUpdate
import eu.kanade.tachiyomi.data.download.DownloadJob import eu.kanade.tachiyomi.data.download.DownloadJob
import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.notification.Notifications import eu.kanade.tachiyomi.data.notification.Notifications
@ -55,6 +56,12 @@ import eu.kanade.tachiyomi.util.system.isConnectedToWifi
import eu.kanade.tachiyomi.util.system.localeContext import eu.kanade.tachiyomi.util.system.localeContext
import eu.kanade.tachiyomi.util.system.tryToSetForeground import eu.kanade.tachiyomi.util.system.tryToSetForeground
import eu.kanade.tachiyomi.util.system.withIOContext import eu.kanade.tachiyomi.util.system.withIOContext
import java.io.File
import java.lang.ref.WeakReference
import java.util.Date
import java.util.concurrent.CancellationException
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -79,11 +86,6 @@ import yokai.domain.manga.interactor.GetLibraryManga
import yokai.domain.manga.interactor.UpdateManga import yokai.domain.manga.interactor.UpdateManga
import yokai.i18n.MR import yokai.i18n.MR
import yokai.util.lang.getString import yokai.util.lang.getString
import java.io.File
import java.lang.ref.WeakReference
import java.util.*
import java.util.concurrent.*
import java.util.concurrent.atomic.*
class LibraryUpdateJob(private val context: Context, workerParams: WorkerParameters) : class LibraryUpdateJob(private val context: Context, workerParams: WorkerParameters) :
CoroutineWorker(context, workerParams) { CoroutineWorker(context, workerParams) {
@ -267,11 +269,13 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
} }
if (networkManga != null) { if (networkManga != null) {
val thumbnailUrl = manga.thumbnail_url val thumbnailUrl = manga.thumbnail_url
if (thumbnailUrl != networkManga.thumbnail_url) {
manga.prepareCoverUpdate()
}
manga.copyFrom(networkManga) manga.copyFrom(networkManga)
manga.initialized = true manga.initialized = true
val request: ImageRequest = val request: ImageRequest =
if (thumbnailUrl != manga.thumbnail_url) { if (thumbnailUrl != manga.thumbnail_url) {
coverCache.deleteFromCache(thumbnailUrl)
// load new covers in background // load new covers in background
ImageRequest.Builder(context).data(manga) ImageRequest.Builder(context).data(manga)
.memoryCachePolicy(CachePolicy.DISABLED).build() .memoryCachePolicy(CachePolicy.DISABLED).build()

View file

@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.data.database.models.Chapter.Companion.copy
import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.MangaCategory import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.database.models.removeCover
import eu.kanade.tachiyomi.data.database.models.seriesType import eu.kanade.tachiyomi.data.database.models.seriesType
import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.download.model.Download
@ -1260,7 +1261,7 @@ class LibraryPresenter(
val mangaToDelete = mangas.distinctBy { it.id } val mangaToDelete = mangas.distinctBy { it.id }
mangaToDelete.forEach { manga -> mangaToDelete.forEach { manga ->
if (coverCacheToo) { if (coverCacheToo) {
coverCache.deleteFromCache(manga) manga.removeCover(coverCache)
} }
val source = sourceManager.get(manga.source) as? HttpSource val source = sourceManager.get(manga.source) as? HttpSource
if (source != null) { if (source != null) {

View file

@ -20,9 +20,11 @@ import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.database.models.bookmarkedFilter import eu.kanade.tachiyomi.data.database.models.bookmarkedFilter
import eu.kanade.tachiyomi.data.database.models.chapterOrder import eu.kanade.tachiyomi.data.database.models.chapterOrder
import eu.kanade.tachiyomi.data.database.models.downloadedFilter import eu.kanade.tachiyomi.data.database.models.downloadedFilter
import eu.kanade.tachiyomi.data.database.models.hasCustomCover import eu.kanade.tachiyomi.data.database.models.prepareCoverUpdate
import eu.kanade.tachiyomi.data.database.models.readFilter import eu.kanade.tachiyomi.data.database.models.readFilter
import eu.kanade.tachiyomi.data.database.models.removeCover
import eu.kanade.tachiyomi.data.database.models.sortDescending import eu.kanade.tachiyomi.data.database.models.sortDescending
import eu.kanade.tachiyomi.data.database.models.updateCoverLastModified
import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.download.model.DownloadQueue import eu.kanade.tachiyomi.data.download.model.DownloadQueue
@ -59,6 +61,7 @@ import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
import eu.kanade.tachiyomi.util.storage.DiskUtil import eu.kanade.tachiyomi.util.storage.DiskUtil
import eu.kanade.tachiyomi.util.system.ImageUtil import eu.kanade.tachiyomi.util.system.ImageUtil
import eu.kanade.tachiyomi.util.system.launchIO import eu.kanade.tachiyomi.util.system.launchIO
import eu.kanade.tachiyomi.util.system.launchNonCancellableIO
import eu.kanade.tachiyomi.util.system.launchNow import eu.kanade.tachiyomi.util.system.launchNow
import eu.kanade.tachiyomi.util.system.launchUI import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.system.withIOContext import eu.kanade.tachiyomi.util.system.withIOContext
@ -375,7 +378,6 @@ class MangaDetailsPresenter(
emptyList() emptyList()
} }
} }
val thumbnailUrl = manga.thumbnail_url
val nManga = async(Dispatchers.IO) { val nManga = async(Dispatchers.IO) {
try { try {
source.getMangaDetails(manga.copy()) source.getMangaDetails(manga.copy())
@ -387,12 +389,13 @@ class MangaDetailsPresenter(
val networkManga = nManga.await() val networkManga = nManga.await()
if (networkManga != null) { if (networkManga != null) {
if (manga.thumbnail_url != networkManga.thumbnail_url) {
manga.prepareCoverUpdate()
}
manga.copyFrom(networkManga) manga.copyFrom(networkManga)
manga.initialized = true manga.initialized = true
if (thumbnailUrl != networkManga.thumbnail_url) {
coverCache.deleteFromCache(thumbnailUrl)
}
db.insertManga(manga).executeAsBlocking() db.insertManga(manga).executeAsBlocking()
launchIO { launchIO {
@ -403,7 +406,6 @@ class MangaDetailsPresenter(
.build() .build()
if (preferences.context.imageLoader.execute(request) is SuccessResult) { if (preferences.context.imageLoader.execute(request) is SuccessResult) {
coverCache.removeFromMemory(manga, manga.hasCustomCover(coverCache))
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
view?.setPaletteColor() view?.setPaletteColor()
} }
@ -735,7 +737,7 @@ class MangaDetailsPresenter(
fun confirmDeletion() { fun confirmDeletion() {
launchIO { launchIO {
coverCache.deleteFromCache(manga) manga.removeCover(coverCache)
customMangaManager.saveMangaInfo(CustomMangaInfo( customMangaManager.saveMangaInfo(CustomMangaInfo(
mangaId = manga.id!!, mangaId = manga.id!!,
title = null, title = null,
@ -858,6 +860,7 @@ class MangaDetailsPresenter(
editCoverWithStream(uri) editCoverWithStream(uri)
} else if (resetCover) { } else if (resetCover) {
coverCache.deleteCustomCover(manga) coverCache.deleteCustomCover(manga)
presenterScope.launchIO { manga.updateCoverLastModified() }
view?.setPaletteColor() view?.setPaletteColor()
} }
view?.updateHeader() view?.updateHeader()
@ -881,12 +884,14 @@ class MangaDetailsPresenter(
downloadManager.context.contentResolver.openInputStream(uri) ?: return false downloadManager.context.contentResolver.openInputStream(uri) ?: return false
if (manga.isLocal()) { if (manga.isLocal()) {
LocalSource.updateCover(manga, inputStream) LocalSource.updateCover(manga, inputStream)
presenterScope.launchNonCancellableIO { manga.updateCoverLastModified() }
view?.setPaletteColor() view?.setPaletteColor()
return true return true
} }
if (manga.favorite) { if (manga.favorite) {
coverCache.setCustomCoverToCache(manga, inputStream) coverCache.setCustomCoverToCache(manga, inputStream)
presenterScope.launchNonCancellableIO { manga.updateCoverLastModified() }
view?.setPaletteColor() view?.setPaletteColor()
return true return true
} }

View file

@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.History import eu.kanade.tachiyomi.data.database.models.History
import eu.kanade.tachiyomi.data.database.models.MangaCategory import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.data.database.models.updateCoverLastModified
import eu.kanade.tachiyomi.data.library.CustomMangaManager import eu.kanade.tachiyomi.data.library.CustomMangaManager
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.EnhancedTrackService import eu.kanade.tachiyomi.data.track.EnhancedTrackService
@ -229,6 +230,7 @@ class MigrationProcessAdapter(
if (MigrationFlags.hasCustomMangaInfo(flags)) { if (MigrationFlags.hasCustomMangaInfo(flags)) {
if (coverCache.getCustomCoverFile(prevManga).exists()) { if (coverCache.getCustomCoverFile(prevManga).exists()) {
coverCache.setCustomCoverToCache(manga, coverCache.getCustomCoverFile(prevManga).inputStream()) coverCache.setCustomCoverToCache(manga, coverCache.getCustomCoverFile(prevManga).inputStream())
launchNow { manga.updateCoverLastModified() }
} }
customMangaManager.getManga(prevManga)?.let { customManga -> customMangaManager.getManga(prevManga)?.let { customManga ->
launchNow { launchNow {

View file

@ -16,6 +16,7 @@ import eu.kanade.tachiyomi.data.database.models.History
import eu.kanade.tachiyomi.data.database.models.defaultReaderType import eu.kanade.tachiyomi.data.database.models.defaultReaderType
import eu.kanade.tachiyomi.data.database.models.orientationType import eu.kanade.tachiyomi.data.database.models.orientationType
import eu.kanade.tachiyomi.data.database.models.readingModeType import eu.kanade.tachiyomi.data.database.models.readingModeType
import eu.kanade.tachiyomi.data.database.models.updateCoverLastModified
import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.DownloadProvider import eu.kanade.tachiyomi.data.download.DownloadProvider
import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.download.model.Download
@ -938,14 +939,15 @@ class ReaderViewModel(
viewModelScope.launchNonCancellableIO { viewModelScope.launchNonCancellableIO {
val result = try { val result = try {
if (manga.isLocal()) { if (manga.isLocal()) {
val context = Injekt.get<Application>()
coverCache.deleteFromCache(manga) coverCache.deleteFromCache(manga)
LocalSource.updateCover(manga, stream()) LocalSource.updateCover(manga, stream())
manga.updateCoverLastModified()
MR.strings.cover_updated MR.strings.cover_updated
SetAsCoverResult.Success SetAsCoverResult.Success
} else { } else {
if (manga.favorite) { if (manga.favorite) {
coverCache.setCustomCoverToCache(manga, stream()) coverCache.setCustomCoverToCache(manga, stream())
manga.updateCoverLastModified()
SetAsCoverResult.Success SetAsCoverResult.Success
} else { } else {
SetAsCoverResult.AddToLibraryFirst SetAsCoverResult.AddToLibraryFirst

View file

@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.database.models.create import eu.kanade.tachiyomi.data.database.models.create
import eu.kanade.tachiyomi.data.database.models.removeCover
import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.domain.manga.models.Manga import eu.kanade.tachiyomi.domain.manga.models.Manga
@ -283,7 +284,7 @@ open class BrowseSourcePresenter(
fun confirmDeletion(manga: Manga) { fun confirmDeletion(manga: Manga) {
launchIO { launchIO {
coverCache.deleteFromCache(manga) manga.removeCover(coverCache)
val downloadManager: DownloadManager = Injekt.get() val downloadManager: DownloadManager = Injekt.get()
downloadManager.deleteManga(manga, source) downloadManager.deleteManga(manga, source)
} }

View file

@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.source.globalsearch
import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.create import eu.kanade.tachiyomi.data.database.models.create
import eu.kanade.tachiyomi.data.database.models.removeCover
import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.domain.manga.models.Manga import eu.kanade.tachiyomi.domain.manga.models.Manga
@ -16,6 +17,8 @@ import eu.kanade.tachiyomi.ui.base.presenter.BaseCoroutinePresenter
import eu.kanade.tachiyomi.util.system.launchIO import eu.kanade.tachiyomi.util.system.launchIO
import eu.kanade.tachiyomi.util.system.launchUI import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.system.withUIContext import eu.kanade.tachiyomi.util.system.withUIContext
import java.util.Date
import java.util.Locale
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
@ -26,7 +29,6 @@ import kotlinx.coroutines.sync.withPermit
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.util.*
/** /**
* Presenter of [GlobalSearchController] * Presenter of [GlobalSearchController]
@ -138,7 +140,7 @@ open class GlobalSearchPresenter(
} }
fun confirmDeletion(manga: Manga) { fun confirmDeletion(manga: Manga) {
coverCache.deleteFromCache(manga) manga.removeCover(coverCache)
val downloadManager: DownloadManager = Injekt.get() val downloadManager: DownloadManager = Injekt.get()
sourceManager.get(manga.source)?.let { source -> sourceManager.get(manga.source)?.let { source ->
downloadManager.deleteManga(manga, source) downloadManager.deleteManga(manga, source)

View file

@ -4,7 +4,6 @@ import co.touchlab.kermit.Logger
import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.mapper import eu.kanade.tachiyomi.data.database.models.mapper
import eu.kanade.tachiyomi.domain.manga.models.Manga import eu.kanade.tachiyomi.domain.manga.models.Manga
import eu.kanade.tachiyomi.util.system.toInt
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import yokai.data.DatabaseHandler import yokai.data.DatabaseHandler
import yokai.data.updateStrategyAdapter import yokai.data.updateStrategyAdapter
@ -66,15 +65,16 @@ class MangaRepositoryImpl(private val handler: DatabaseHandler) : MangaRepositor
title = update.title, title = update.title,
status = update.status?.toLong(), status = update.status?.toLong(),
thumbnailUrl = update.thumbnailUrl, thumbnailUrl = update.thumbnailUrl,
favorite = update.favorite?.toInt()?.toLong(), favorite = update.favorite,
lastUpdate = update.lastUpdate, lastUpdate = update.lastUpdate,
initialized = update.initialized, initialized = update.initialized,
viewer = update.viewerFlags?.toLong(), viewer = update.viewerFlags?.toLong(),
hideTitle = update.hideTitle?.toInt()?.toLong(), hideTitle = update.hideTitle,
chapterFlags = update.chapterFlags?.toLong(), chapterFlags = update.chapterFlags?.toLong(),
dateAdded = update.dateAdded, dateAdded = update.dateAdded,
filteredScanlators = update.filteredScanlators, filteredScanlators = update.filteredScanlators,
updateStrategy = update.updateStrategy?.let(updateStrategyAdapter::encode), updateStrategy = update.updateStrategy?.let(updateStrategyAdapter::encode),
coverLastModified = update.coverLastModified,
mangaId = update.id, mangaId = update.id,
) )
} }
@ -93,15 +93,16 @@ class MangaRepositoryImpl(private val handler: DatabaseHandler) : MangaRepositor
title = manga.title, title = manga.title,
status = manga.status.toLong(), status = manga.status.toLong(),
thumbnailUrl = manga.thumbnail_url, thumbnailUrl = manga.thumbnail_url,
favorite = manga.favorite.toInt().toLong(), favorite = manga.favorite,
lastUpdate = manga.last_update, lastUpdate = manga.last_update,
initialized = manga.initialized, initialized = manga.initialized,
viewer = manga.viewer_flags.toLong(), viewer = manga.viewer_flags.toLong(),
hideTitle = manga.hide_title.toInt().toLong(), hideTitle = manga.hide_title,
chapterFlags = manga.chapter_flags.toLong(), chapterFlags = manga.chapter_flags.toLong(),
dateAdded = manga.date_added, dateAdded = manga.date_added,
filteredScanlators = manga.filtered_scanlators, filteredScanlators = manga.filtered_scanlators,
updateStrategy = manga.update_strategy.let(updateStrategyAdapter::encode), updateStrategy = manga.update_strategy.let(updateStrategyAdapter::encode),
coverLastModified = manga.cover_last_modified,
) )
mangasQueries.selectLastInsertedRowId() mangasQueries.selectLastInsertedRowId()
} }

View file

@ -5,6 +5,7 @@ import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.IO
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch import kotlinx.coroutines.launch

View file

@ -1,5 +1,4 @@
import kotlin.Boolean; import kotlin.Boolean;
import kotlin.Long;
CREATE TABLE mangas( CREATE TABLE mangas(
_id INTEGER NOT NULL PRIMARY KEY, _id INTEGER NOT NULL PRIMARY KEY,
@ -12,15 +11,16 @@ CREATE TABLE mangas(
title TEXT NOT NULL, title TEXT NOT NULL,
status INTEGER NOT NULL, status INTEGER NOT NULL,
thumbnail_url TEXT, thumbnail_url TEXT,
favorite INTEGER NOT NULL, favorite INTEGER AS Boolean NOT NULL,
last_update INTEGER AS Long, last_update INTEGER,
initialized INTEGER AS Boolean NOT NULL, initialized INTEGER AS Boolean NOT NULL,
viewer INTEGER NOT NULL, viewer INTEGER NOT NULL,
hide_title INTEGER NOT NULL, hide_title INTEGER AS Boolean NOT NULL,
chapter_flags INTEGER NOT NULL, chapter_flags INTEGER NOT NULL,
date_added INTEGER AS Long, date_added INTEGER,
filtered_scanlators TEXT, filtered_scanlators TEXT,
update_strategy INTEGER NOT NULL DEFAULT 0 update_strategy INTEGER NOT NULL DEFAULT 0,
cover_last_modified INTEGER NOT NULL DEFAULT 0
); );
CREATE INDEX mangas_url_index ON mangas(url); CREATE INDEX mangas_url_index ON mangas(url);
@ -51,8 +51,8 @@ FROM mangas
WHERE favorite = 1; WHERE favorite = 1;
insert: insert:
INSERT INTO mangas (source, url, artist, author, description, genre, title, status, thumbnail_url, favorite, last_update, initialized, viewer, hide_title, chapter_flags, date_added, filtered_scanlators, update_strategy) INSERT INTO mangas (source, url, artist, author, description, genre, title, status, thumbnail_url, favorite, last_update, initialized, viewer, hide_title, chapter_flags, date_added, filtered_scanlators, update_strategy, cover_last_modified)
VALUES (:source, :url, :artist, :author, :description, :genre, :title, :status, :thumbnailUrl, :favorite, :lastUpdate, :initialized, :viewer, :hideTitle, :chapterFlags, :dateAdded, :filteredScanlators, :updateStrategy); VALUES (:source, :url, :artist, :author, :description, :genre, :title, :status, :thumbnailUrl, :favorite, :lastUpdate, :initialized, :viewer, :hideTitle, :chapterFlags, :dateAdded, :filteredScanlators, :updateStrategy, :coverLastModified);
update: update:
UPDATE mangas SET UPDATE mangas SET
@ -73,7 +73,8 @@ UPDATE mangas SET
chapter_flags = coalesce(:chapterFlags, chapter_flags), chapter_flags = coalesce(:chapterFlags, chapter_flags),
date_added = coalesce(:dateAdded, date_added), date_added = coalesce(:dateAdded, date_added),
filtered_scanlators = coalesce(:filteredScanlators, filtered_scanlators), filtered_scanlators = coalesce(:filteredScanlators, filtered_scanlators),
update_strategy = coalesce(:updateStrategy, update_strategy) update_strategy = coalesce(:updateStrategy, update_strategy),
cover_last_modified = coalesce(:coverLastModified, cover_last_modified)
WHERE _id = :mangaId; WHERE _id = :mangaId;
selectLastInsertedRowId: selectLastInsertedRowId:

View file

@ -0,0 +1,2 @@
ALTER TABLE mangas
ADD COLUMN cover_last_modified INTEGER NOT NULL DEFAULT 0;

View file

@ -1,9 +1,9 @@
package eu.kanade.tachiyomi.domain.manga.models package eu.kanade.tachiyomi.domain.manga.models
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import yokai.domain.manga.models.MangaUpdate import java.util.Locale
import java.util.*
import kotlin.collections.set import kotlin.collections.set
import yokai.domain.manga.models.MangaUpdate
// TODO: Transform into data class // TODO: Transform into data class
interface Manga : SManga { interface Manga : SManga {
@ -33,6 +33,8 @@ interface Manga : SManga {
var ogGenre: String? var ogGenre: String?
var ogStatus: Int var ogStatus: Int
var cover_last_modified: Long
@Deprecated("Use ogTitle directly instead", ReplaceWith("ogTitle")) @Deprecated("Use ogTitle directly instead", ReplaceWith("ogTitle"))
val originalTitle: String val originalTitle: String
get() = ogTitle get() = ogTitle

View file

@ -22,4 +22,5 @@ data class MangaUpdate(
var chapterFlags: Int? = null, var chapterFlags: Int? = null,
var hideTitle: Boolean? = null, var hideTitle: Boolean? = null,
var filteredScanlators: String? = null, var filteredScanlators: String? = null,
var coverLastModified: Long? = null,
) )