mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
refactor: Add cover_last_modified
This commit is contained in:
parent
653b2d7839
commit
c9b302ab21
23 changed files with 158 additions and 104 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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))
|
||||||
|
}
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE mangas
|
||||||
|
ADD COLUMN cover_last_modified INTEGER NOT NULL DEFAULT 0;
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue