Skip to content

Commit

Permalink
Add logic to only update specific categories
Browse files Browse the repository at this point in the history
Makes it possible to only update specific categories.

In case a manga is in an excluded category it will be excluded even if it is also in an included category.
  • Loading branch information
schroda committed Mar 23, 2023
1 parent ec1d65f commit 2b6a751
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,15 @@ object CategoryController {
pathParam<Int>("categoryId"),
formParam<String?>("name"),
formParam<Boolean?>("default"),
formParam<Int?>("includeInUpdate"),
documentWith = {
withOperation {
summary("Category modify")
description("Modify a category")
}
},
behaviorOf = { ctx, categoryId, name, isDefault ->
Category.updateCategory(categoryId, name, isDefault)
behaviorOf = { ctx, categoryId, name, isDefault, includeInUpdate ->
Category.updateCategory(categoryId, name, isDefault, includeInUpdate)
ctx.status(200)
},
withResults = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ import suwayomi.tachidesk.manga.impl.Chapter
import suwayomi.tachidesk.manga.impl.update.IUpdater
import suwayomi.tachidesk.manga.impl.update.UpdateStatus
import suwayomi.tachidesk.manga.impl.update.UpdaterSocket
import suwayomi.tachidesk.manga.model.dataclass.CategoryDataClass
import suwayomi.tachidesk.manga.model.dataclass.MangaChapterDataClass
import suwayomi.tachidesk.manga.model.dataclass.MangaDataClass
import suwayomi.tachidesk.manga.model.dataclass.PaginatedList
import suwayomi.tachidesk.manga.model.dataclass.*
import suwayomi.tachidesk.server.JavalinSetup.future
import suwayomi.tachidesk.server.util.formParam
import suwayomi.tachidesk.server.util.handler
Expand Down Expand Up @@ -93,11 +90,25 @@ object UpdateController {
if (clear) {
updater.reset()
}
categories

val includeInUpdateStatusToCategoryMap = categories.groupBy { it.includeInUpdate }
val excludedCategories = includeInUpdateStatusToCategoryMap[IncludeInUpdate.EXCLUDE].orEmpty()
val includedCategories = includeInUpdateStatusToCategoryMap[IncludeInUpdate.INCLUDE].orEmpty()
val unsetCategories = includeInUpdateStatusToCategoryMap[IncludeInUpdate.UNSET].orEmpty()
val categoriesToUpdate = includedCategories.ifEmpty { unsetCategories }

logger.info { "Updating categories: '${categoriesToUpdate.joinToString("', '") { it.name }}'" }

val categoriesToUpdateMangas = categoriesToUpdate
.flatMap { CategoryManga.getCategoryMangaList(it.id) }
.distinctBy { it.id }
.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER, MangaDataClass::title))
val mangasToCategoriesMap = CategoryManga.getMangasCategories(categoriesToUpdateMangas.map { it.id })
val mangasToUpdate = categoriesToUpdateMangas
.filter { it.updateStrategy == UpdateStrategy.ALWAYS_UPDATE }
.filter { !excludedCategories.any { category -> mangasToCategoriesMap[it.id]?.contains(category) == true } }

mangasToUpdate
.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER, MangaDataClass::title))
.forEach { manga ->
updater.addMangaToQueue(manga)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import org.jetbrains.exposed.sql.update
import suwayomi.tachidesk.manga.impl.CategoryManga.removeMangaFromCategory
import suwayomi.tachidesk.manga.impl.util.lang.isNotEmpty
import suwayomi.tachidesk.manga.model.dataclass.CategoryDataClass
import suwayomi.tachidesk.manga.model.dataclass.IncludeInUpdate
import suwayomi.tachidesk.manga.model.table.CategoryMangaTable
import suwayomi.tachidesk.manga.model.table.CategoryMetaTable
import suwayomi.tachidesk.manga.model.table.CategoryTable
Expand Down Expand Up @@ -50,11 +51,12 @@ object Category {
}
}

fun updateCategory(categoryId: Int, name: String?, isDefault: Boolean?) {
fun updateCategory(categoryId: Int, name: String?, isDefault: Boolean?, includeInUpdate: Int?) {
transaction {
CategoryTable.update({ CategoryTable.id eq categoryId }) {
if (name != null && !name.equals(DEFAULT_CATEGORY_NAME, ignoreCase = true)) it[CategoryTable.name] = name
if (isDefault != null) it[CategoryTable.isDefault] = isDefault
if (includeInUpdate != null) it[CategoryTable.includeInUpdate] = includeInUpdate
}
}
}
Expand Down Expand Up @@ -100,7 +102,7 @@ object Category {
const val DEFAULT_CATEGORY_NAME = "Default"
private fun addDefaultIfNecessary(categories: List<CategoryDataClass>): List<CategoryDataClass> =
if (MangaTable.select { (MangaTable.inLibrary eq true) and (MangaTable.defaultCategory eq true) }.isNotEmpty()) {
listOf(CategoryDataClass(DEFAULT_CATEGORY_ID, 0, DEFAULT_CATEGORY_NAME, true)) + categories
listOf(CategoryDataClass(DEFAULT_CATEGORY_ID, 0, DEFAULT_CATEGORY_NAME, true, IncludeInUpdate.UNSET)) + categories
} else {
categories
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,20 @@ object CategoryManga {
}
}
}

fun getMangasCategories(mangaIDs: List<Int>): Map<Int, List<CategoryDataClass>> {
return buildMap {
transaction {
CategoryMangaTable.innerJoin(CategoryTable)
.select { CategoryMangaTable.manga inList mangaIDs }
.groupBy { it[CategoryMangaTable.manga] }
.forEach {
val mangaId = it.key.value
val categories = it.value

set(mangaId, categories.map { category -> CategoryTable.toDataClass(category) })
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
package suwayomi.tachidesk.manga.model.dataclass

import com.fasterxml.jackson.annotation.JsonValue

/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

enum class IncludeInUpdate(@JsonValue val value: Int) {
EXCLUDE(0), INCLUDE(1), UNSET(2);

companion object {
fun fromValue(value: Int) = IncludeInUpdate.values().find { it.value == value } ?: UNSET
}
}

data class CategoryDataClass(
val id: Int,
val order: Int,
val name: String,
val default: Boolean,
val includeInUpdate: IncludeInUpdate,
val meta: Map<String, String> = emptyMap()
)
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,20 @@ import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.ResultRow
import suwayomi.tachidesk.manga.impl.Category
import suwayomi.tachidesk.manga.model.dataclass.CategoryDataClass
import suwayomi.tachidesk.manga.model.dataclass.IncludeInUpdate

object CategoryTable : IntIdTable() {
val name = varchar("name", 64)
val order = integer("order").default(0)
val isDefault = bool("is_default").default(false)
val includeInUpdate = integer("include_in_update").default(IncludeInUpdate.UNSET.value)
}

fun CategoryTable.toDataClass(categoryEntry: ResultRow) = CategoryDataClass(
categoryEntry[id].value,
categoryEntry[order],
categoryEntry[name],
categoryEntry[isDefault],
IncludeInUpdate.fromValue(categoryEntry[includeInUpdate]),
Category.getCategoryMetaMap(categoryEntry[id].value)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package suwayomi.tachidesk.server.database.migration

/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

import de.neonew.exposed.migrations.helpers.AddColumnMigration
import suwayomi.tachidesk.manga.model.dataclass.IncludeInUpdate

@Suppress("ClassName", "unused")
class M0026_CategoryIncludeInUpdate : AddColumnMigration(
"Category",
"include_in_update",
"INT",
IncludeInUpdate.UNSET.value.toString()
)

0 comments on commit 2b6a751

Please sign in to comment.