Skip to content

Commit

Permalink
Merge pull request #1 from Suwayomi/master
Browse files Browse the repository at this point in the history
update
  • Loading branch information
WillDera authored Apr 7, 2023
2 parents 7e8fa62 + f2a650b commit bc50eb0
Show file tree
Hide file tree
Showing 11 changed files with 109 additions and 25 deletions.
7 changes: 4 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
## Where should I start?
Checkout [This Kanban Board](https://github.com/Suwayomi/Tachidesk/projects/1) to see the rough development roadmap.

**Note 1:** Notify the developers on [Suwayomi discord](https://discord.gg/DDZdqZWaHA) (#tachidesk-server and #tachidesk-webui channels) or open a WIP pull request before starting if you decide to take on working on anything from/not from the roadmap in order to avoid parallel efforts on the same issue/feature.

**Note 2:** Your pull request will be squashed into a single commit.
### Important notes
- Notify the developers on [Suwayomi discord](https://discord.gg/DDZdqZWaHA) (#tachidesk-server and #tachidesk-webui channels) or open a WIP pull request before starting if you decide to take on working on anything from/not from the roadmap in order to avoid parallel efforts on the same issue/feature.
- Your pull request will be squashed into a single commit.
- We hate big pull requests, make them as small as possible, change one meaningful thing. Spam pull requests, we don't mind.

### Project goals and vision
- Porting Tachiyomi and covering it's features
Expand Down
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,14 +90,33 @@ 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.debug { "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 }
.forEach { manga ->
updater.addMangaToQueue(manga)
}
.filter { !excludedCategories.any { category -> mangasToCategoriesMap[it.id]?.contains(category) == true } }

// In case no manga gets updated and no update job was running before, the client would never receive an info about its update request
if (mangasToUpdate.isEmpty()) {
UpdaterSocket.notifyAllClients(UpdateStatus())
return
}

updater.addMangasToQueue(
mangasToUpdate
.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER, MangaDataClass::title)),
)
}

fun categoryUpdateWS(ws: WsConfig) {
Expand Down
21 changes: 16 additions & 5 deletions server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Category.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import org.jetbrains.exposed.sql.selectAll
import org.jetbrains.exposed.sql.transactions.transaction
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 +50,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 @@ -98,12 +99,14 @@ object Category {

const val DEFAULT_CATEGORY_ID = 0
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
private fun addDefaultIfNecessary(categories: List<CategoryDataClass>): List<CategoryDataClass> {
val defaultCategorySize = MangaTable.select { (MangaTable.inLibrary eq true) and (MangaTable.defaultCategory eq true) }.count().toInt()
return if (defaultCategorySize > 0) {
listOf(CategoryDataClass(DEFAULT_CATEGORY_ID, 0, DEFAULT_CATEGORY_NAME, true, defaultCategorySize, IncludeInUpdate.UNSET)) + categories
} else {
categories
}
}

fun getCategoryList(): List<CategoryDataClass> {
return transaction {
Expand All @@ -123,6 +126,14 @@ object Category {
}
}

fun getCategorySize(categoryId: Int): Int {
return transaction {
CategoryMangaTable.select {
CategoryMangaTable.category eq categoryId
}.count().toInt()
}
}

fun getCategoryMetaMap(categoryId: Int): Map<String, String> {
return transaction {
CategoryMetaTable.select { CategoryMetaTable.ref eq categoryId }
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
Expand Up @@ -4,7 +4,7 @@ import kotlinx.coroutines.flow.StateFlow
import suwayomi.tachidesk.manga.model.dataclass.MangaDataClass

interface IUpdater {
fun addMangaToQueue(manga: MangaDataClass)
fun addMangasToQueue(mangas: List<MangaDataClass>)
val status: StateFlow<UpdateStatus>
fun reset()
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,17 @@ class Updater : IUpdater {
return tracker.values.toList()
}

override fun addMangaToQueue(manga: MangaDataClass) {
override fun addMangasToQueue(mangas: List<MangaDataClass>) {
mangas.forEach { tracker[it.id] = UpdateJob(it) }
_status.update { UpdateStatus(tracker.values.toList(), mangas.isNotEmpty()) }
mangas.forEach { addMangaToQueue(it) }
}

private fun addMangaToQueue(manga: MangaDataClass) {
val updateChannel = getOrCreateUpdateChannelFor(manga.sourceId)
scope.launch {
updateChannel.send(UpdateJob(manga))
}
tracker[manga.id] = UpdateJob(manga)
_status.update { UpdateStatus(tracker.values.toList(), true) }
}

override fun reset() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
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(-1);

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 size: Int,
val includeInUpdate: IncludeInUpdate,
val meta: Map<String, String> = emptyMap()
)
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,21 @@ 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],
Category.getCategorySize(categoryEntry[id].value),
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()
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ class TestUpdater : IUpdater {
private val _status = MutableStateFlow(UpdateStatus())
override val status: StateFlow<UpdateStatus> = _status.asStateFlow()

override fun addMangaToQueue(manga: MangaDataClass) {
updateQueue.add(UpdateJob(manga))
override fun addMangasToQueue(mangas: List<MangaDataClass>) {
mangas.forEach { updateQueue.add(UpdateJob(it)) }
isRunning = true
updateStatus()
}
Expand Down

0 comments on commit bc50eb0

Please sign in to comment.