Add support to update strategy on global update

+ Requests: add `GET(HttpUrl)` overload

Starting line for Extensions on 1.5
This commit is contained in:
Jays2Kings 2022-12-13 00:15:03 -05:00
parent f411eafef9
commit 34869c20bb
12 changed files with 124 additions and 14 deletions

View file

@ -5,6 +5,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaImpl
import eu.kanade.tachiyomi.data.database.models.TrackImpl
import eu.kanade.tachiyomi.data.library.CustomMangaManager
import eu.kanade.tachiyomi.source.model.UpdateStrategy
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
@ -38,6 +39,7 @@ data class BackupManga(
@ProtoNumber(102) var brokenHistory: List<BrokenBackupHistory> = emptyList(),
@ProtoNumber(103) var viewer_flags: Int? = null,
@ProtoNumber(104) var history: List<BackupHistory> = emptyList(),
@ProtoNumber(105) var updateStrategy: UpdateStrategy = UpdateStrategy.ALWAYS_UPDATE,
// SY specific values
@ProtoNumber(602) var customStatus: Int = 0,
@ -69,6 +71,7 @@ data class BackupManga(
).takeIf { it != 0 }
?: -1
chapter_flags = this@BackupManga.chapterFlags
update_strategy = this@BackupManga.updateStrategy
}
}
@ -122,6 +125,7 @@ data class BackupManga(
viewer = manga.readingModeType,
viewer_flags = manga.viewer_flags.takeIf { it != -1 } ?: 0,
chapterFlags = manga.chapter_flags,
updateStrategy = manga.update_strategy,
).also { backupManga ->
customMangaManager?.getManga(manga)?.let {
backupManga.customTitle = it.title

View file

@ -0,0 +1,41 @@
package eu.kanade.tachiyomi.data.database
import eu.kanade.tachiyomi.source.model.UpdateStrategy
import java.util.Date
val dateAdapter = object : ColumnAdapter<Date, Long> {
override fun decode(databaseValue: Long): Date = Date(databaseValue)
override fun encode(value: Date): Long = value.time
}
private const val listOfStringsSeparator = ", "
val listOfStringsAdapter = object : ColumnAdapter<List<String>, String> {
override fun decode(databaseValue: String) =
if (databaseValue.isEmpty()) {
emptyList()
} else {
databaseValue.split(listOfStringsSeparator)
}
override fun encode(value: List<String>) = value.joinToString(separator = listOfStringsSeparator)
}
val updateStrategyAdapter = object : ColumnAdapter<UpdateStrategy, Int> {
private val enumValues by lazy { UpdateStrategy.values() }
override fun decode(databaseValue: Int): UpdateStrategy =
enumValues.getOrElse(databaseValue) { UpdateStrategy.ALWAYS_UPDATE }
override fun encode(value: UpdateStrategy): Int = value.ordinal
}
interface ColumnAdapter<T : Any, S> {
/**
* @return [databaseValue] decoded as type [T].
*/
fun decode(databaseValue: S): T
/**
* @return [value] encoded as database type [S].
*/
fun encode(value: T): S
}

View file

@ -20,7 +20,7 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
/**
* Version of the database.
*/
const val DATABASE_VERSION = 15
const val DATABASE_VERSION = 16
}
override fun onOpen(db: SupportSQLiteDatabase) {
@ -109,6 +109,9 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
db.execSQL(TrackTable.insertFromTempTable)
db.execSQL(TrackTable.dropTempTable)
}
if (oldVersion < 16) {
db.execSQL(MangaTable.addUpdateStrategy)
}
}
override fun onConfigure(db: SupportSQLiteDatabase) {

View file

@ -27,9 +27,11 @@ import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_SOURCE
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_STATUS
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_THUMBNAIL_URL
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_TITLE
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_UPDATE_STRATEGY
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_URL
import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_VIEWER
import eu.kanade.tachiyomi.data.database.tables.MangaTable.TABLE
import eu.kanade.tachiyomi.data.database.updateStrategyAdapter
class MangaTypeMapping : SQLiteTypeMapping<Manga>(
MangaPutResolver(),
@ -68,6 +70,7 @@ class MangaPutResolver : DefaultPutResolver<Manga>() {
put(COL_CHAPTER_FLAGS, obj.chapter_flags)
put(COL_DATE_ADDED, obj.date_added)
put(COL_FILTERED_SCANLATORS, obj.filtered_scanlators)
put(COL_UPDATE_STRATEGY, obj.update_strategy.let(updateStrategyAdapter::encode))
}
}
@ -91,6 +94,9 @@ interface BaseMangaGetResolver {
hide_title = cursor.getInt(cursor.getColumnIndex(COL_HIDE_TITLE)) == 1
date_added = cursor.getLong(cursor.getColumnIndex(COL_DATE_ADDED))
filtered_scanlators = cursor.getString(cursor.getColumnIndex(COL_FILTERED_SCANLATORS))
update_strategy = cursor.getInt(cursor.getColumnIndex(COL_UPDATE_STRATEGY)).let(
updateStrategyAdapter::decode,
)
}
}

View file

@ -4,6 +4,7 @@ import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.DownloadProvider
import eu.kanade.tachiyomi.data.library.CustomMangaManager
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.model.UpdateStrategy
import uy.kohesive.injekt.injectLazy
open class MangaImpl : Manga {
@ -68,6 +69,8 @@ open class MangaImpl : Manga {
override var date_added: Long = 0
override var update_strategy: UpdateStrategy = UpdateStrategy.ALWAYS_UPDATE
override var filtered_scanlators: String? = null
lateinit var ogTitle: String

View file

@ -46,6 +46,8 @@ object MangaTable {
const val COL_FILTERED_SCANLATORS = "filtered_scanlators"
const val COL_UPDATE_STRATEGY = "update_strategy"
val createTableQuery: String
get() =
"""CREATE TABLE $TABLE(
@ -66,7 +68,8 @@ object MangaTable {
$COL_HIDE_TITLE INTEGER NOT NULL,
$COL_CHAPTER_FLAGS INTEGER NOT NULL,
$COL_DATE_ADDED LONG,
$COL_FILTERED_SCANLATORS TEXT
$COL_FILTERED_SCANLATORS TEXT,
$COL_UPDATE_STRATEGY INTEGER AS UpdateStrategy NOT NULL DEFAULT 0
)"""
@ -85,4 +88,7 @@ object MangaTable {
val addFilteredScanlators: String
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_FILTERED_SCANLATORS TEXT"
val addUpdateStrategy: String
get() = "ALTER TABLE $TABLE ADD COLUMN $COL_UPDATE_STRATEGY INTEGER NOT NULL DEFAULT 0"
}

View file

@ -31,6 +31,7 @@ import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.UnmeteredSource
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.model.UpdateStrategy
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithTrackServiceTwoWay
@ -300,18 +301,24 @@ class LibraryUpdateService(
private fun filterMangaToUpdate(mangaToAdd: List<LibraryManga>): List<LibraryManga> {
val restrictions = preferences.libraryUpdateMangaRestriction().get()
return mangaToAdd.filter { manga ->
return@filter if (MANGA_NON_COMPLETED in restrictions && manga.status == SManga.COMPLETED) {
skippedUpdates[manga] = getString(R.string.skipped_reason_completed)
false
} else if (MANGA_HAS_UNREAD in restrictions && manga.unread != 0) {
skippedUpdates[manga] = getString(R.string.skipped_reason_not_caught_up)
false
} else if (MANGA_NON_READ in restrictions && manga.totalChapters > 0 && !manga.hasRead) {
skippedUpdates[manga] = getString(R.string.skipped_reason_not_started)
false
} else {
true
when {
MANGA_NON_COMPLETED in restrictions && manga.status == SManga.COMPLETED -> {
skippedUpdates[manga] = getString(R.string.skipped_reason_completed)
}
MANGA_HAS_UNREAD in restrictions && manga.unread != 0 -> {
skippedUpdates[manga] = getString(R.string.skipped_reason_not_caught_up)
}
MANGA_NON_READ in restrictions && manga.totalChapters > 0 && !manga.hasRead -> {
skippedUpdates[manga] = getString(R.string.skipped_reason_not_started)
}
manga.update_strategy != UpdateStrategy.ALWAYS_UPDATE -> {
skippedUpdates[manga] = getString(R.string.skipped_reason_not_always_update)
}
else -> {
return@filter true
}
}
return@filter false
}
}

View file

@ -39,7 +39,7 @@ internal object ExtensionLoader {
private const val METADATA_HAS_README = "tachiyomi.extension.hasReadme"
private const val METADATA_HAS_CHANGELOG = "tachiyomi.extension.hasChangelog"
const val LIB_VERSION_MIN = 1.2
const val LIB_VERSION_MAX = 1.3
const val LIB_VERSION_MAX = 1.4
private const val PACKAGE_FLAGS = PackageManager.GET_CONFIGURATIONS or PackageManager.GET_SIGNATURES

View file

@ -3,6 +3,8 @@ package eu.kanade.tachiyomi.network
import okhttp3.CacheControl
import okhttp3.FormBody
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import okhttp3.RequestBody
import java.util.concurrent.TimeUnit.MINUTES
@ -15,6 +17,17 @@ fun GET(
url: String,
headers: Headers = DEFAULT_HEADERS,
cache: CacheControl = DEFAULT_CACHE_CONTROL,
): Request {
return GET(url.toHttpUrl(), headers, cache)
}
/**
* @since extensions-lib 1.4
*/
fun GET(
url: HttpUrl,
headers: Headers = DEFAULT_HEADERS,
cache: CacheControl = DEFAULT_CACHE_CONTROL,
): Request {
return Request.Builder()
.url(url)

View file

@ -21,6 +21,8 @@ interface SManga : Serializable {
var thumbnail_url: String?
var update_strategy: UpdateStrategy
var initialized: Boolean
val originalTitle: String
@ -59,6 +61,8 @@ interface SManga : Serializable {
status = other.originalStatus
update_strategy = other.update_strategy
if (!initialized) {
initialized = other.initialized
}

View file

@ -0,0 +1,22 @@
package eu.kanade.tachiyomi.source.model
/**
* Define the update strategy for a single [SManga].
* The strategy used will only take effect on the library update.
*
* @since extensions-lib 1.4
*/
enum class UpdateStrategy {
/**
* Series marked as always update will be included in the library
* update if they aren't excluded by additional restrictions.
*/
ALWAYS_UPDATE,
/**
* Series marked as only fetch once will be automatically skipped
* during library updates. Useful for cases where the series is previously
* known to be finished and have only a single chapter, for example.
*/
ONLY_FETCH_ONCE,
}

View file

@ -211,6 +211,7 @@
<string name="skipped_reason_completed">Skipped because series is complete</string>
<string name="skipped_reason_not_caught_up">Skipped because there are unread chapters</string>
<string name="skipped_reason_not_started">Skipped because no chapters are read</string>
<string name="skipped_reason_not_always_update">Skipped because series does not require updates</string>
<string name="channel_errors">Errors</string>
<string name="channel_skipped">Skipped</string>