From edf376e3dd668b111a592d65d91880b650072720 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 10 May 2026 19:01:34 -0400 Subject: [PATCH 01/13] Update graphqlkotlin to v10 alpha (major) (#1923) * Update graphqlkotlin to v9 * Update to the v10 alpha due to nullability issues in v9 * Fixes * Remove asDataFetcherResult --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Syer10 --- gradle/libs.versions.toml | 2 +- .../tachidesk/graphql/AsDataFetcherResult.kt | 27 - .../tachidesk/graphql/cache/CustomCacheMap.kt | 16 +- .../graphql/dataLoaders/ChapterDataLoader.kt | 50 +- .../dataLoaders/ExtensionDataLoader.kt | 8 +- .../graphql/dataLoaders/MangaDataLoader.kt | 6 +- .../graphql/dataLoaders/MetaDataLoader.kt | 6 +- .../graphql/dataLoaders/SourceDataLoader.kt | 4 +- .../graphql/mutations/BackupMutation.kt | 2 + .../graphql/mutations/CategoryMutation.kt | 559 +++++++++--------- .../graphql/mutations/ChapterMutation.kt | 402 ++++++------- .../graphql/mutations/DownloadMutation.kt | 291 +++++---- .../graphql/mutations/ExtensionMutation.kt | 109 ++-- .../graphql/mutations/ImageMutation.kt | 2 + .../graphql/mutations/InfoMutation.kt | 67 +-- .../graphql/mutations/KoreaderSyncMutation.kt | 99 ++-- .../graphql/mutations/MangaMutation.kt | 278 +++++---- .../graphql/mutations/MetaMutation.kt | 133 ++--- .../graphql/mutations/SettingsMutation.kt | 2 + .../graphql/mutations/SourceMutation.kt | 332 +++++------ .../graphql/mutations/TrackMutation.kt | 31 +- .../graphql/mutations/UpdateMutation.kt | 61 +- .../graphql/mutations/UserMutation.kt | 2 + .../server/JavalinGraphQLRequestParser.kt | 7 +- .../graphql/server/TachideskGraphQLServer.kt | 2 +- .../graphql/server/primitives/Cursor.kt | 2 +- .../server/primitives/DurationAsString.kt | 2 +- .../graphql/server/primitives/LongAsString.kt | 2 +- .../ApolloSubscriptionProtocolHandler.kt | 6 +- 29 files changed, 1197 insertions(+), 1313 deletions(-) delete mode 100644 server/src/main/kotlin/suwayomi/tachidesk/graphql/AsDataFetcherResult.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 13c45dbe..01244fb8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ dex2jar = "2.4.36" polyglot = "25.0.3" settings = "1.3.0" twelvemonkeys = "3.13.1" -graphqlkotlin = "8.9.0" +graphqlkotlin = "10.0.0-alpha.3" xmlserialization = "0.91.3" ktlint = "1.8.0" koin = "4.2.1" diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/AsDataFetcherResult.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/AsDataFetcherResult.kt deleted file mode 100644 index 6c3a0f74..00000000 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/AsDataFetcherResult.kt +++ /dev/null @@ -1,27 +0,0 @@ -package suwayomi.tachidesk.graphql - -import com.expediagroup.graphql.server.extensions.toGraphQLError -import graphql.execution.DataFetcherResult -import io.github.oshai.kotlinlogging.KotlinLogging - -val logger = KotlinLogging.logger { } - -inline fun asDataFetcherResult(block: () -> T): DataFetcherResult { - val result = - runCatching { - block() - } - - if (result.isFailure) { - logger.error(result.exceptionOrNull()) { "asDataFetcherResult: failed due to" } - return DataFetcherResult - .newResult() - .error(result.exceptionOrNull()?.toGraphQLError()) - .build() - } - - return DataFetcherResult - .newResult() - .data(result.getOrNull()) - .build() -} diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/cache/CustomCacheMap.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/cache/CustomCacheMap.kt index 742da59a..6fd089b3 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/cache/CustomCacheMap.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/cache/CustomCacheMap.kt @@ -3,12 +3,8 @@ package suwayomi.tachidesk.graphql.cache import org.dataloader.CacheMap import java.util.concurrent.CompletableFuture -class CustomCacheMap : CacheMap { - private val cache: MutableMap> - - init { - cache = HashMap() - } +class CustomCacheMap : CacheMap { + private val cache: MutableMap> = HashMap() override fun containsKey(key: K): Boolean = cache.containsKey(key) @@ -18,12 +14,12 @@ class CustomCacheMap : CacheMap { override fun getAll(): Collection> = cache.values - override fun set( + override fun putIfAbsentAtomically( key: K, value: CompletableFuture, - ): CacheMap { + ): CompletableFuture { cache[key] = value - return this + return value } override fun delete(key: K): CacheMap { @@ -35,4 +31,6 @@ class CustomCacheMap : CacheMap { cache.clear() return this } + + override fun size(): Int = cache.size } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/ChapterDataLoader.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/ChapterDataLoader.kt index f0fe0a89..44ef6de3 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/ChapterDataLoader.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/ChapterDataLoader.kt @@ -24,11 +24,11 @@ import suwayomi.tachidesk.graphql.types.ChapterType import suwayomi.tachidesk.manga.model.table.ChapterTable import suwayomi.tachidesk.server.JavalinSetup.future -class ChapterDataLoader : KotlinDataLoader { +class ChapterDataLoader : KotlinDataLoader { override val dataLoaderName = "ChapterDataLoader" - override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = - DataLoaderFactory.newDataLoader { ids -> + override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = + DataLoaderFactory.newDataLoader { ids -> future { transaction { addLogger(Slf4jSqlDebugLogger) @@ -48,7 +48,7 @@ class ChaptersForMangaDataLoader : KotlinDataLoader { override val dataLoaderName = "ChaptersForMangaDataLoader" override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = - DataLoaderFactory.newDataLoader { ids -> + DataLoaderFactory.newDataLoader { ids -> future { transaction { addLogger(Slf4jSqlDebugLogger) @@ -68,7 +68,7 @@ class DownloadedChapterCountForMangaDataLoader : KotlinDataLoader { override val dataLoaderName = "DownloadedChapterCountForMangaDataLoader" override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = - DataLoaderFactory.newDataLoader { ids -> + DataLoaderFactory.newDataLoader { ids -> future { transaction { addLogger(Slf4jSqlDebugLogger) @@ -90,7 +90,7 @@ class UnreadChapterCountForMangaDataLoader : KotlinDataLoader { override val dataLoaderName = "UnreadChapterCountForMangaDataLoader" override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = - DataLoaderFactory.newDataLoader { ids -> + DataLoaderFactory.newDataLoader { ids -> future { transaction { addLogger(Slf4jSqlDebugLogger) @@ -112,7 +112,7 @@ class BookmarkedChapterCountForMangaDataLoader : KotlinDataLoader { override val dataLoaderName = "BookmarkedChapterCountForMangaDataLoader" override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = - DataLoaderFactory.newDataLoader { ids -> + DataLoaderFactory.newDataLoader { ids -> future { transaction { addLogger(Slf4jSqlDebugLogger) @@ -157,11 +157,11 @@ class HasDuplicateChaptersForMangaDataLoader : KotlinDataLoader { } } -class LastReadChapterForMangaDataLoader : KotlinDataLoader { +class LastReadChapterForMangaDataLoader : KotlinDataLoader { override val dataLoaderName = "LastReadChapterForMangaDataLoader" - override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = - DataLoaderFactory.newDataLoader { ids -> + override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = + DataLoaderFactory.newDataLoader { ids -> future { transaction { addLogger(Slf4jSqlDebugLogger) @@ -177,11 +177,11 @@ class LastReadChapterForMangaDataLoader : KotlinDataLoader { } } -class LatestReadChapterForMangaDataLoader : KotlinDataLoader { +class LatestReadChapterForMangaDataLoader : KotlinDataLoader { override val dataLoaderName = "LatestReadChapterForMangaDataLoader" - override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = - DataLoaderFactory.newDataLoader { ids -> + override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = + DataLoaderFactory.newDataLoader { ids -> future { transaction { addLogger(Slf4jSqlDebugLogger) @@ -197,11 +197,11 @@ class LatestReadChapterForMangaDataLoader : KotlinDataLoader } } -class LatestFetchedChapterForMangaDataLoader : KotlinDataLoader { +class LatestFetchedChapterForMangaDataLoader : KotlinDataLoader { override val dataLoaderName = "LatestFetchedChapterForMangaDataLoader" - override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = - DataLoaderFactory.newDataLoader { ids -> + override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = + DataLoaderFactory.newDataLoader { ids -> future { transaction { addLogger(Slf4jSqlDebugLogger) @@ -217,11 +217,11 @@ class LatestFetchedChapterForMangaDataLoader : KotlinDataLoader { +class LatestUploadedChapterForMangaDataLoader : KotlinDataLoader { override val dataLoaderName = "LatestUploadedChapterForMangaDataLoader" - override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = - DataLoaderFactory.newDataLoader { ids -> + override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = + DataLoaderFactory.newDataLoader { ids -> future { transaction { addLogger(Slf4jSqlDebugLogger) @@ -237,11 +237,11 @@ class LatestUploadedChapterForMangaDataLoader : KotlinDataLoader { +class FirstUnreadChapterForMangaDataLoader : KotlinDataLoader { override val dataLoaderName = "FirstUnreadChapterForMangaDataLoader" - override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = - DataLoaderFactory.newDataLoader { ids -> + override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = + DataLoaderFactory.newDataLoader { ids -> future { transaction { addLogger(Slf4jSqlDebugLogger) @@ -257,11 +257,11 @@ class FirstUnreadChapterForMangaDataLoader : KotlinDataLoader } } -class HighestNumberedChapterForMangaDataLoader : KotlinDataLoader { +class HighestNumberedChapterForMangaDataLoader : KotlinDataLoader { override val dataLoaderName = "HighestNumberedChapterForMangaDataLoader" - override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = - DataLoaderFactory.newDataLoader { ids -> + override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = + DataLoaderFactory.newDataLoader { ids -> future { transaction { addLogger(Slf4jSqlDebugLogger) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/ExtensionDataLoader.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/ExtensionDataLoader.kt index 2c7be2fa..c3b4b695 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/ExtensionDataLoader.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/ExtensionDataLoader.kt @@ -20,10 +20,10 @@ import suwayomi.tachidesk.manga.model.table.ExtensionTable import suwayomi.tachidesk.manga.model.table.SourceTable import suwayomi.tachidesk.server.JavalinSetup.future -class ExtensionDataLoader : KotlinDataLoader { +class ExtensionDataLoader : KotlinDataLoader { override val dataLoaderName = "ExtensionDataLoader" - override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = + override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = DataLoaderFactory.newDataLoader { ids -> future { transaction { @@ -40,10 +40,10 @@ class ExtensionDataLoader : KotlinDataLoader { } } -class ExtensionForSourceDataLoader : KotlinDataLoader { +class ExtensionForSourceDataLoader : KotlinDataLoader { override val dataLoaderName = "ExtensionForSourceDataLoader" - override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = + override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = DataLoaderFactory.newDataLoader { ids -> future { transaction { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/MangaDataLoader.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/MangaDataLoader.kt index 0775d71a..a49b3260 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/MangaDataLoader.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/MangaDataLoader.kt @@ -25,10 +25,10 @@ import suwayomi.tachidesk.manga.model.table.CategoryMangaTable import suwayomi.tachidesk.manga.model.table.MangaTable import suwayomi.tachidesk.server.JavalinSetup.future -class MangaDataLoader : KotlinDataLoader { +class MangaDataLoader : KotlinDataLoader { override val dataLoaderName = "MangaDataLoader" - override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = + override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = DataLoaderFactory.newDataLoader { ids -> future { transaction { @@ -122,6 +122,6 @@ class MangaForIdsDataLoader : KotlinDataLoader, MangaNodeList> { } } }, - DataLoaderOptions.newOptions().setCacheMap(CustomCacheMap, MangaNodeList>()), + DataLoaderOptions.newOptions().setCacheMap(CustomCacheMap, MangaNodeList>()).build(), ) } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/MetaDataLoader.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/MetaDataLoader.kt index a01f2392..d2515bca 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/MetaDataLoader.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/MetaDataLoader.kt @@ -20,11 +20,11 @@ import suwayomi.tachidesk.manga.model.table.MangaMetaTable import suwayomi.tachidesk.manga.model.table.SourceMetaTable import suwayomi.tachidesk.server.JavalinSetup.future -class GlobalMetaDataLoader : KotlinDataLoader { +class GlobalMetaDataLoader : KotlinDataLoader { override val dataLoaderName = "GlobalMetaDataLoader" - override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = - DataLoaderFactory.newDataLoader { ids -> + override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = + DataLoaderFactory.newDataLoader { ids -> future { transaction { addLogger(Slf4jSqlDebugLogger) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/SourceDataLoader.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/SourceDataLoader.kt index be3c60e0..3fc2269c 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/SourceDataLoader.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/SourceDataLoader.kt @@ -22,10 +22,10 @@ import suwayomi.tachidesk.manga.model.table.ExtensionTable import suwayomi.tachidesk.manga.model.table.SourceTable import suwayomi.tachidesk.server.JavalinSetup.future -class SourceDataLoader : KotlinDataLoader { +class SourceDataLoader : KotlinDataLoader { override val dataLoaderName = "SourceDataLoader" - override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = + override fun getDataLoader(graphQLContext: GraphQLContext): DataLoader = DataLoaderFactory.newDataLoader { ids -> future { transaction { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/BackupMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/BackupMutation.kt index 3f8b6af2..19ba10cc 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/BackupMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/BackupMutation.kt @@ -1,3 +1,5 @@ +@file:Suppress("RedundantNullableReturnType", "unused") + package suwayomi.tachidesk.graphql.mutations import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/CategoryMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/CategoryMutation.kt index 132a399e..dd988fd1 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/CategoryMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/CategoryMutation.kt @@ -1,3 +1,5 @@ +@file:Suppress("RedundantNullableReturnType", "unused") + package suwayomi.tachidesk.graphql.mutations import graphql.execution.DataFetcherResult @@ -15,7 +17,6 @@ import org.jetbrains.exposed.sql.or import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.update -import suwayomi.tachidesk.graphql.asDataFetcherResult import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.CategoryMetaType import suwayomi.tachidesk.graphql.types.CategoryType @@ -42,14 +43,13 @@ class CategoryMutation { ) @RequireAuth - fun setCategoryMeta(input: SetCategoryMetaInput): DataFetcherResult = - asDataFetcherResult { - val (clientMutationId, meta) = input + fun setCategoryMeta(input: SetCategoryMetaInput): SetCategoryMetaPayload? { + val (clientMutationId, meta) = input - Category.modifyMeta(meta.categoryId, meta.key, meta.value) + Category.modifyMeta(meta.categoryId, meta.key, meta.value) - SetCategoryMetaPayload(clientMutationId, meta) - } + return SetCategoryMetaPayload(clientMutationId, meta) + } data class DeleteCategoryMetaInput( val clientMutationId: String? = null, @@ -64,34 +64,33 @@ class CategoryMutation { ) @RequireAuth - fun deleteCategoryMeta(input: DeleteCategoryMetaInput): DataFetcherResult = - asDataFetcherResult { - val (clientMutationId, categoryId, key) = input + fun deleteCategoryMeta(input: DeleteCategoryMetaInput): DeleteCategoryMetaPayload? { + val (clientMutationId, categoryId, key) = input - val (meta, category) = - transaction { - val meta = - CategoryMetaTable - .selectAll() - .where { (CategoryMetaTable.ref eq categoryId) and (CategoryMetaTable.key eq key) } - .firstOrNull() + val (meta, category) = + transaction { + val meta = + CategoryMetaTable + .selectAll() + .where { (CategoryMetaTable.ref eq categoryId) and (CategoryMetaTable.key eq key) } + .firstOrNull() - CategoryMetaTable.deleteWhere { (CategoryMetaTable.ref eq categoryId) and (CategoryMetaTable.key eq key) } + CategoryMetaTable.deleteWhere { (CategoryMetaTable.ref eq categoryId) and (CategoryMetaTable.key eq key) } - val category = - transaction { - CategoryType(CategoryTable.selectAll().where { CategoryTable.id eq categoryId }.first()) - } + val category = + transaction { + CategoryType(CategoryTable.selectAll().where { CategoryTable.id eq categoryId }.first()) + } - if (meta != null) { - CategoryMetaType(meta) - } else { - null - } to category - } + if (meta != null) { + CategoryMetaType(meta) + } else { + null + } to category + } - DeleteCategoryMetaPayload(clientMutationId, meta, category) - } + return DeleteCategoryMetaPayload(clientMutationId, meta, category) + } data class SetCategoryMetasItem( val categoryIds: List, @@ -110,43 +109,42 @@ class CategoryMutation { ) @RequireAuth - fun setCategoryMetas(input: SetCategoryMetasInput): DataFetcherResult = - asDataFetcherResult { - val (clientMutationId, items) = input + fun setCategoryMetas(input: SetCategoryMetasInput): SetCategoryMetasPayload? { + val (clientMutationId, items) = input - val metaByCategoryId = - items - .flatMap { item -> - val metaMap = item.metas.associate { it.key to it.value } - item.categoryIds.map { categoryId -> categoryId to metaMap } - }.groupBy({ it.first }, { it.second }) - .mapValues { (_, maps) -> maps.reduce { acc, map -> acc + map } } + val metaByCategoryId = + items + .flatMap { item -> + val metaMap = item.metas.associate { it.key to it.value } + item.categoryIds.map { categoryId -> categoryId to metaMap } + }.groupBy({ it.first }, { it.second }) + .mapValues { (_, maps) -> maps.reduce { acc, map -> acc + map } } - Category.modifyCategoriesMetas(metaByCategoryId) + Category.modifyCategoriesMetas(metaByCategoryId) - val allCategoryIds = metaByCategoryId.keys - val allMetaKeys = metaByCategoryId.values.flatMap { item -> item.keys }.distinct() + val allCategoryIds = metaByCategoryId.keys + val allMetaKeys = metaByCategoryId.values.flatMap { item -> item.keys }.distinct() - val (updatedMetas, categories) = - transaction { - val updatedMetas = - CategoryMetaTable - .selectAll() - .where { (CategoryMetaTable.ref inList allCategoryIds) and (CategoryMetaTable.key inList allMetaKeys) } - .map { CategoryMetaType(it) } + val (updatedMetas, categories) = + transaction { + val updatedMetas = + CategoryMetaTable + .selectAll() + .where { (CategoryMetaTable.ref inList allCategoryIds) and (CategoryMetaTable.key inList allMetaKeys) } + .map { CategoryMetaType(it) } - val categories = - CategoryTable - .selectAll() - .where { CategoryTable.id inList allCategoryIds } - .map { CategoryType(it) } - .distinctBy { it.id } + val categories = + CategoryTable + .selectAll() + .where { CategoryTable.id inList allCategoryIds } + .map { CategoryType(it) } + .distinctBy { it.id } - updatedMetas to categories - } + updatedMetas to categories + } - SetCategoryMetasPayload(clientMutationId, updatedMetas, categories) - } + return SetCategoryMetasPayload(clientMutationId, updatedMetas, categories) + } data class DeleteCategoryMetasItem( val categoryIds: List, @@ -166,64 +164,63 @@ class CategoryMutation { ) @RequireAuth - fun deleteCategoryMetas(input: DeleteCategoryMetasInput): DataFetcherResult = - asDataFetcherResult { - val (clientMutationId, items) = input + fun deleteCategoryMetas(input: DeleteCategoryMetasInput): DeleteCategoryMetasPayload? { + val (clientMutationId, items) = input - items.forEach { item -> - require(!item.keys.isNullOrEmpty() || !item.prefixes.isNullOrEmpty()) { - "Either 'keys' or 'prefixes' must be provided for each item" + items.forEach { item -> + require(!item.keys.isNullOrEmpty() || !item.prefixes.isNullOrEmpty()) { + "Either 'keys' or 'prefixes' must be provided for each item" + } + } + + val (allDeletedMetas, allCategoryIds) = + transaction { + val deletedMetas = mutableListOf() + val categoryIds = mutableSetOf() + + items.forEach { item -> + val keyCondition: Op? = + item.keys?.takeIf { it.isNotEmpty() }?.let { CategoryMetaTable.key inList it } + + val prefixCondition: Op? = + item.prefixes + ?.filter { it.isNotEmpty() } + ?.map { (CategoryMetaTable.key like LikePattern("$it%")) as Op } + ?.reduceOrNull { acc, op -> acc or op } + + val metaKeyCondition = + if (keyCondition != null && prefixCondition != null) { + keyCondition or prefixCondition + } else { + keyCondition ?: prefixCondition!! + } + + val condition = (CategoryMetaTable.ref inList item.categoryIds) and metaKeyCondition + + deletedMetas += + CategoryMetaTable + .selectAll() + .where { condition } + .map { CategoryMetaType(it) } + + CategoryMetaTable.deleteWhere { condition } + categoryIds += item.categoryIds } + + deletedMetas to categoryIds } - val (allDeletedMetas, allCategoryIds) = - transaction { - val deletedMetas = mutableListOf() - val categoryIds = mutableSetOf() + val categories = + transaction { + CategoryTable + .selectAll() + .where { CategoryTable.id inList allCategoryIds } + .map { CategoryType(it) } + .distinctBy { it.id } + } - items.forEach { item -> - val keyCondition: Op? = - item.keys?.takeIf { it.isNotEmpty() }?.let { CategoryMetaTable.key inList it } - - val prefixCondition: Op? = - item.prefixes - ?.filter { it.isNotEmpty() } - ?.map { (CategoryMetaTable.key like LikePattern("$it%")) as Op } - ?.reduceOrNull { acc, op -> acc or op } - - val metaKeyCondition = - if (keyCondition != null && prefixCondition != null) { - keyCondition or prefixCondition - } else { - keyCondition ?: prefixCondition!! - } - - val condition = (CategoryMetaTable.ref inList item.categoryIds) and metaKeyCondition - - deletedMetas += - CategoryMetaTable - .selectAll() - .where { condition } - .map { CategoryMetaType(it) } - - CategoryMetaTable.deleteWhere { condition } - categoryIds += item.categoryIds - } - - deletedMetas to categoryIds - } - - val categories = - transaction { - CategoryTable - .selectAll() - .where { CategoryTable.id inList allCategoryIds } - .map { CategoryType(it) } - .distinctBy { it.id } - } - - DeleteCategoryMetasPayload(clientMutationId, allDeletedMetas, categories) - } + return DeleteCategoryMetasPayload(clientMutationId, allDeletedMetas, categories) + } data class UpdateCategoryPatch( val name: String? = null, @@ -291,40 +288,38 @@ class CategoryMutation { } @RequireAuth - fun updateCategory(input: UpdateCategoryInput): DataFetcherResult = - asDataFetcherResult { - val (clientMutationId, id, patch) = input + fun updateCategory(input: UpdateCategoryInput): UpdateCategoryPayload? { + val (clientMutationId, id, patch) = input - updateCategories(listOf(id), patch) + updateCategories(listOf(id), patch) - val category = - transaction { - CategoryType(CategoryTable.selectAll().where { CategoryTable.id eq id }.first()) - } + val category = + transaction { + CategoryType(CategoryTable.selectAll().where { CategoryTable.id eq id }.first()) + } - UpdateCategoryPayload( - clientMutationId = clientMutationId, - category = category, - ) - } + return UpdateCategoryPayload( + clientMutationId = clientMutationId, + category = category, + ) + } @RequireAuth - fun updateCategories(input: UpdateCategoriesInput): DataFetcherResult = - asDataFetcherResult { - val (clientMutationId, ids, patch) = input + fun updateCategories(input: UpdateCategoriesInput): UpdateCategoriesPayload? { + val (clientMutationId, ids, patch) = input - updateCategories(ids, patch) + updateCategories(ids, patch) - val categories = - transaction { - CategoryTable.selectAll().where { CategoryTable.id inList ids }.map { CategoryType(it) } - } + val categories = + transaction { + CategoryTable.selectAll().where { CategoryTable.id inList ids }.map { CategoryType(it) } + } - UpdateCategoriesPayload( - clientMutationId = clientMutationId, - categories = categories, - ) - } + return UpdateCategoriesPayload( + clientMutationId = clientMutationId, + categories = categories, + ) + } data class UpdateCategoryOrderPayload( val clientMutationId: String?, @@ -338,50 +333,49 @@ class CategoryMutation { ) @RequireAuth - fun updateCategoryOrder(input: UpdateCategoryOrderInput): DataFetcherResult = - asDataFetcherResult { - val (clientMutationId, categoryId, position) = input - require(position > 0) { - "'order' must not be <= 0" - } - - transaction { - val currentOrder = - CategoryTable - .selectAll() - .where { CategoryTable.id eq categoryId } - .first()[CategoryTable.order] - - if (currentOrder != position) { - if (position < currentOrder) { - CategoryTable.update({ CategoryTable.order greaterEq position }) { - it[CategoryTable.order] = CategoryTable.order + 1 - } - } else { - CategoryTable.update({ CategoryTable.order lessEq position }) { - it[CategoryTable.order] = CategoryTable.order - 1 - } - } - - CategoryTable.update({ CategoryTable.id eq categoryId }) { - it[CategoryTable.order] = position - } - } - } - - Category.normalizeCategories() - - val categories = - transaction { - CategoryTable.selectAll().orderBy(CategoryTable.order).map { CategoryType(it) } - } - - UpdateCategoryOrderPayload( - clientMutationId = clientMutationId, - categories = categories, - ) + fun updateCategoryOrder(input: UpdateCategoryOrderInput): UpdateCategoryOrderPayload? { + val (clientMutationId, categoryId, position) = input + require(position > 0) { + "'order' must not be <= 0" } + transaction { + val currentOrder = + CategoryTable + .selectAll() + .where { CategoryTable.id eq categoryId } + .first()[CategoryTable.order] + + if (currentOrder != position) { + if (position < currentOrder) { + CategoryTable.update({ CategoryTable.order greaterEq position }) { + it[CategoryTable.order] = CategoryTable.order + 1 + } + } else { + CategoryTable.update({ CategoryTable.order lessEq position }) { + it[CategoryTable.order] = CategoryTable.order - 1 + } + } + + CategoryTable.update({ CategoryTable.id eq categoryId }) { + it[CategoryTable.order] = position + } + } + } + + Category.normalizeCategories() + + val categories = + transaction { + CategoryTable.selectAll().orderBy(CategoryTable.order).map { CategoryType(it) } + } + + return UpdateCategoryOrderPayload( + clientMutationId = clientMutationId, + categories = categories, + ) + } + data class CreateCategoryInput( val clientMutationId: String? = null, val name: String, @@ -397,53 +391,52 @@ class CategoryMutation { ) @RequireAuth - fun createCategory(input: CreateCategoryInput): DataFetcherResult = - asDataFetcherResult { - val (clientMutationId, name, order, default, includeInUpdate, includeInDownload) = input - transaction { - require(CategoryTable.selectAll().where { CategoryTable.name eq input.name }.isEmpty()) { - "'name' must be unique" - } + fun createCategory(input: CreateCategoryInput): CreateCategoryPayload? { + val (clientMutationId, name, order, default, includeInUpdate, includeInDownload) = input + transaction { + require(CategoryTable.selectAll().where { CategoryTable.name eq input.name }.isEmpty()) { + "'name' must be unique" } - require(!name.equals(Category.DEFAULT_CATEGORY_NAME, ignoreCase = true)) { - "'name' must not be ${Category.DEFAULT_CATEGORY_NAME}" - } - if (order != null) { - require(order > 0) { - "'order' must not be <= 0" - } + } + require(!name.equals(Category.DEFAULT_CATEGORY_NAME, ignoreCase = true)) { + "'name' must not be ${Category.DEFAULT_CATEGORY_NAME}" + } + if (order != null) { + require(order > 0) { + "'order' must not be <= 0" } + } - val category = - transaction { - if (order != null) { - CategoryTable.update({ CategoryTable.order greaterEq order }) { - it[CategoryTable.order] = CategoryTable.order + 1 + val category = + transaction { + if (order != null) { + CategoryTable.update({ CategoryTable.order greaterEq order }) { + it[CategoryTable.order] = CategoryTable.order + 1 + } + } + + val id = + CategoryTable.insertAndGetId { + it[CategoryTable.name] = input.name + it[CategoryTable.order] = order ?: Int.MAX_VALUE + if (default != null) { + it[CategoryTable.isDefault] = default + } + if (includeInUpdate != null) { + it[CategoryTable.includeInUpdate] = includeInUpdate.value + } + if (includeInDownload != null) { + it[CategoryTable.includeInDownload] = includeInDownload.value } } - val id = - CategoryTable.insertAndGetId { - it[CategoryTable.name] = input.name - it[CategoryTable.order] = order ?: Int.MAX_VALUE - if (default != null) { - it[CategoryTable.isDefault] = default - } - if (includeInUpdate != null) { - it[CategoryTable.includeInUpdate] = includeInUpdate.value - } - if (includeInDownload != null) { - it[CategoryTable.includeInDownload] = includeInDownload.value - } - } + Category.normalizeCategories() - Category.normalizeCategories() + CategoryType(CategoryTable.selectAll().where { CategoryTable.id eq id }.first()) + } - CategoryType(CategoryTable.selectAll().where { CategoryTable.id eq id }.first()) - } - - CreateCategoryPayload(clientMutationId, category) - } + return CreateCategoryPayload(clientMutationId, category) + } data class DeleteCategoryInput( val clientMutationId: String? = null, @@ -457,47 +450,45 @@ class CategoryMutation { ) @RequireAuth - fun deleteCategory(input: DeleteCategoryInput): DataFetcherResult { - return asDataFetcherResult { - val (clientMutationId, categoryId) = input - if (categoryId == 0) { // Don't delete default category - return@asDataFetcherResult DeleteCategoryPayload( - clientMutationId, - null, - emptyList(), - ) + fun deleteCategory(input: DeleteCategoryInput): DeleteCategoryPayload? { + val (clientMutationId, categoryId) = input + if (categoryId == 0) { // Don't delete default category + return DeleteCategoryPayload( + clientMutationId, + null, + emptyList(), + ) + } + + val (category, mangas) = + transaction { + val category = + CategoryTable + .selectAll() + .where { CategoryTable.id eq categoryId } + .firstOrNull() + + val mangas = + transaction { + MangaTable + .innerJoin(CategoryMangaTable) + .selectAll() + .where { CategoryMangaTable.category eq categoryId } + .map { MangaType(it) } + } + + CategoryTable.deleteWhere { CategoryTable.id eq categoryId } + + Category.normalizeCategories() + + if (category != null) { + CategoryType(category) + } else { + null + } to mangas } - val (category, mangas) = - transaction { - val category = - CategoryTable - .selectAll() - .where { CategoryTable.id eq categoryId } - .firstOrNull() - - val mangas = - transaction { - MangaTable - .innerJoin(CategoryMangaTable) - .selectAll() - .where { CategoryMangaTable.category eq categoryId } - .map { MangaType(it) } - } - - CategoryTable.deleteWhere { CategoryTable.id eq categoryId } - - Category.normalizeCategories() - - if (category != null) { - CategoryType(category) - } else { - null - } to mangas - } - - DeleteCategoryPayload(clientMutationId, category, mangas) - } + return DeleteCategoryPayload(clientMutationId, category, mangas) } data class UpdateMangaCategoriesPatch( @@ -547,38 +538,36 @@ class CategoryMutation { } @RequireAuth - fun updateMangaCategories(input: UpdateMangaCategoriesInput): DataFetcherResult = - asDataFetcherResult { - val (clientMutationId, id, patch) = input + fun updateMangaCategories(input: UpdateMangaCategoriesInput): UpdateMangaCategoriesPayload? { + val (clientMutationId, id, patch) = input - updateMangas(listOf(id), patch) + updateMangas(listOf(id), patch) - val manga = - transaction { - MangaType(MangaTable.selectAll().where { MangaTable.id eq id }.first()) - } + val manga = + transaction { + MangaType(MangaTable.selectAll().where { MangaTable.id eq id }.first()) + } - UpdateMangaCategoriesPayload( - clientMutationId = clientMutationId, - manga = manga, - ) - } + return UpdateMangaCategoriesPayload( + clientMutationId = clientMutationId, + manga = manga, + ) + } @RequireAuth - fun updateMangasCategories(input: UpdateMangasCategoriesInput): DataFetcherResult = - asDataFetcherResult { - val (clientMutationId, ids, patch) = input + fun updateMangasCategories(input: UpdateMangasCategoriesInput): UpdateMangasCategoriesPayload? { + val (clientMutationId, ids, patch) = input - updateMangas(ids, patch) + updateMangas(ids, patch) - val mangas = - transaction { - MangaTable.selectAll().where { MangaTable.id inList ids }.map { MangaType(it) } - } + val mangas = + transaction { + MangaTable.selectAll().where { MangaTable.id inList ids }.map { MangaType(it) } + } - UpdateMangasCategoriesPayload( - clientMutationId = clientMutationId, - mangas = mangas, - ) - } + return UpdateMangasCategoriesPayload( + clientMutationId = clientMutationId, + mangas = mangas, + ) + } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ChapterMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ChapterMutation.kt index 9d33fcf3..a3ac94af 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ChapterMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ChapterMutation.kt @@ -1,6 +1,7 @@ +@file:Suppress("RedundantNullableReturnType", "unused") + package suwayomi.tachidesk.graphql.mutations -import graphql.execution.DataFetcherResult import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import org.jetbrains.exposed.dao.id.EntityID @@ -16,7 +17,6 @@ import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.statements.BatchUpdateStatement import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.update -import suwayomi.tachidesk.graphql.asDataFetcherResult import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.ChapterMetaType import suwayomi.tachidesk.graphql.types.ChapterType @@ -120,40 +120,38 @@ class ChapterMutation { } @RequireAuth - fun updateChapter(input: UpdateChapterInput): DataFetcherResult = - asDataFetcherResult { - val (clientMutationId, id, patch) = input + fun updateChapter(input: UpdateChapterInput): UpdateChapterPayload? { + val (clientMutationId, id, patch) = input - updateChapters(listOf(id), patch) + updateChapters(listOf(id), patch) - val chapter = - transaction { - ChapterType(ChapterTable.selectAll().where { ChapterTable.id eq id }.first()) - } + val chapter = + transaction { + ChapterType(ChapterTable.selectAll().where { ChapterTable.id eq id }.first()) + } - UpdateChapterPayload( - clientMutationId = clientMutationId, - chapter = chapter, - ) - } + return UpdateChapterPayload( + clientMutationId = clientMutationId, + chapter = chapter, + ) + } @RequireAuth - fun updateChapters(input: UpdateChaptersInput): DataFetcherResult = - asDataFetcherResult { - val (clientMutationId, ids, patch) = input + fun updateChapters(input: UpdateChaptersInput): UpdateChaptersPayload? { + val (clientMutationId, ids, patch) = input - updateChapters(ids, patch) + updateChapters(ids, patch) - val chapters = - transaction { - ChapterTable.selectAll().where { ChapterTable.id inList ids }.map { ChapterType(it) } - } + val chapters = + transaction { + ChapterTable.selectAll().where { ChapterTable.id inList ids }.map { ChapterType(it) } + } - UpdateChaptersPayload( - clientMutationId = clientMutationId, - chapters = chapters, - ) - } + return UpdateChaptersPayload( + clientMutationId = clientMutationId, + chapters = chapters, + ) + } data class FetchChaptersInput( val clientMutationId: String? = null, @@ -166,27 +164,25 @@ class ChapterMutation { ) @RequireAuth - fun fetchChapters(input: FetchChaptersInput): CompletableFuture> { + fun fetchChapters(input: FetchChaptersInput): CompletableFuture { val (clientMutationId, mangaId) = input return future { - asDataFetcherResult { - Chapter.fetchChapterList(mangaId) + Chapter.fetchChapterList(mangaId) - val chapters = - transaction { - ChapterTable - .selectAll() - .where { ChapterTable.manga eq mangaId } - .orderBy(ChapterTable.sourceOrder) - .map { ChapterType(it) } - } + val chapters = + transaction { + ChapterTable + .selectAll() + .where { ChapterTable.manga eq mangaId } + .orderBy(ChapterTable.sourceOrder) + .map { ChapterType(it) } + } - FetchChaptersPayload( - clientMutationId = clientMutationId, - chapters = chapters, - ) - } + FetchChaptersPayload( + clientMutationId = clientMutationId, + chapters = chapters, + ) } } @@ -201,14 +197,13 @@ class ChapterMutation { ) @RequireAuth - fun setChapterMeta(input: SetChapterMetaInput): DataFetcherResult = - asDataFetcherResult { - val (clientMutationId, meta) = input + fun setChapterMeta(input: SetChapterMetaInput): SetChapterMetaPayload? { + val (clientMutationId, meta) = input - Chapter.modifyChapterMeta(meta.chapterId, meta.key, meta.value) + Chapter.modifyChapterMeta(meta.chapterId, meta.key, meta.value) - SetChapterMetaPayload(clientMutationId, meta) - } + return SetChapterMetaPayload(clientMutationId, meta) + } data class DeleteChapterMetaInput( val clientMutationId: String? = null, @@ -223,34 +218,33 @@ class ChapterMutation { ) @RequireAuth - fun deleteChapterMeta(input: DeleteChapterMetaInput): DataFetcherResult = - asDataFetcherResult { - val (clientMutationId, chapterId, key) = input + fun deleteChapterMeta(input: DeleteChapterMetaInput): DeleteChapterMetaPayload? { + val (clientMutationId, chapterId, key) = input - val (meta, chapter) = - transaction { - val meta = - ChapterMetaTable - .selectAll() - .where { (ChapterMetaTable.ref eq chapterId) and (ChapterMetaTable.key eq key) } - .firstOrNull() + val (meta, chapter) = + transaction { + val meta = + ChapterMetaTable + .selectAll() + .where { (ChapterMetaTable.ref eq chapterId) and (ChapterMetaTable.key eq key) } + .firstOrNull() - ChapterMetaTable.deleteWhere { (ChapterMetaTable.ref eq chapterId) and (ChapterMetaTable.key eq key) } + ChapterMetaTable.deleteWhere { (ChapterMetaTable.ref eq chapterId) and (ChapterMetaTable.key eq key) } - val chapter = - transaction { - ChapterType(ChapterTable.selectAll().where { ChapterTable.id eq chapterId }.first()) - } + val chapter = + transaction { + ChapterType(ChapterTable.selectAll().where { ChapterTable.id eq chapterId }.first()) + } - if (meta != null) { - ChapterMetaType(meta) - } else { - null - } to chapter - } + if (meta != null) { + ChapterMetaType(meta) + } else { + null + } to chapter + } - DeleteChapterMetaPayload(clientMutationId, meta, chapter) - } + return DeleteChapterMetaPayload(clientMutationId, meta, chapter) + } data class SetChapterMetasItem( val chapterIds: List, @@ -269,43 +263,42 @@ class ChapterMutation { ) @RequireAuth - fun setChapterMetas(input: SetChapterMetasInput): DataFetcherResult = - asDataFetcherResult { - val (clientMutationId, items) = input + fun setChapterMetas(input: SetChapterMetasInput): SetChapterMetasPayload? { + val (clientMutationId, items) = input - val metaByChapterId = - items - .flatMap { item -> - val metaMap = item.metas.associate { it.key to it.value } - item.chapterIds.map { chapterId -> chapterId to metaMap } - }.groupBy({ it.first }, { it.second }) - .mapValues { (_, maps) -> maps.reduce { acc, map -> acc + map } } + val metaByChapterId = + items + .flatMap { item -> + val metaMap = item.metas.associate { it.key to it.value } + item.chapterIds.map { chapterId -> chapterId to metaMap } + }.groupBy({ it.first }, { it.second }) + .mapValues { (_, maps) -> maps.reduce { acc, map -> acc + map } } - Chapter.modifyChaptersMetas(metaByChapterId) + Chapter.modifyChaptersMetas(metaByChapterId) - val allChapterIds = metaByChapterId.keys - val allMetaKeys = metaByChapterId.values.flatMap { it.keys }.distinct() + val allChapterIds = metaByChapterId.keys + val allMetaKeys = metaByChapterId.values.flatMap { it.keys }.distinct() - val (updatedMetas, chapters) = - transaction { - val updatedMetas = - ChapterMetaTable - .selectAll() - .where { (ChapterMetaTable.ref inList allChapterIds) and (ChapterMetaTable.key inList allMetaKeys) } - .map { ChapterMetaType(it) } + val (updatedMetas, chapters) = + transaction { + val updatedMetas = + ChapterMetaTable + .selectAll() + .where { (ChapterMetaTable.ref inList allChapterIds) and (ChapterMetaTable.key inList allMetaKeys) } + .map { ChapterMetaType(it) } - val chapters = - ChapterTable - .selectAll() - .where { ChapterTable.id inList allChapterIds } - .map { ChapterType(it) } - .distinctBy { it.id } + val chapters = + ChapterTable + .selectAll() + .where { ChapterTable.id inList allChapterIds } + .map { ChapterType(it) } + .distinctBy { it.id } - updatedMetas to chapters - } + updatedMetas to chapters + } - SetChapterMetasPayload(clientMutationId, updatedMetas, chapters) - } + return SetChapterMetasPayload(clientMutationId, updatedMetas, chapters) + } data class DeleteChapterMetasItem( val chapterIds: List, @@ -325,64 +318,63 @@ class ChapterMutation { ) @RequireAuth - fun deleteChapterMetas(input: DeleteChapterMetasInput): DataFetcherResult = - asDataFetcherResult { - val (clientMutationId, items) = input + fun deleteChapterMetas(input: DeleteChapterMetasInput): DeleteChapterMetasPayload? { + val (clientMutationId, items) = input - items.forEach { item -> - require(!item.keys.isNullOrEmpty() || !item.prefixes.isNullOrEmpty()) { - "Either 'keys' or 'prefixes' must be provided for each item" + items.forEach { item -> + require(!item.keys.isNullOrEmpty() || !item.prefixes.isNullOrEmpty()) { + "Either 'keys' or 'prefixes' must be provided for each item" + } + } + + val (allDeletedMetas, allChapterIds) = + transaction { + val deletedMetas = mutableListOf() + val chapterIds = mutableSetOf() + + items.forEach { item -> + val keyCondition: Op? = + item.keys?.takeIf { it.isNotEmpty() }?.let { ChapterMetaTable.key inList it } + + val prefixCondition: Op? = + item.prefixes + ?.filter { it.isNotEmpty() } + ?.map { (ChapterMetaTable.key like LikePattern("$it%")) as Op } + ?.reduceOrNull { acc, op -> acc or op } + + val metaKeyCondition = + if (keyCondition != null && prefixCondition != null) { + keyCondition or prefixCondition + } else { + keyCondition ?: prefixCondition!! + } + + val condition = (ChapterMetaTable.ref inList item.chapterIds) and metaKeyCondition + + deletedMetas += + ChapterMetaTable + .selectAll() + .where { condition } + .map { ChapterMetaType(it) } + + ChapterMetaTable.deleteWhere { condition } + chapterIds += item.chapterIds } + + deletedMetas to chapterIds } - val (allDeletedMetas, allChapterIds) = - transaction { - val deletedMetas = mutableListOf() - val chapterIds = mutableSetOf() + val chapters = + transaction { + ChapterTable + .selectAll() + .where { ChapterTable.id inList allChapterIds } + .map { ChapterType(it) } + .distinctBy { it.id } + } - items.forEach { item -> - val keyCondition: Op? = - item.keys?.takeIf { it.isNotEmpty() }?.let { ChapterMetaTable.key inList it } - - val prefixCondition: Op? = - item.prefixes - ?.filter { it.isNotEmpty() } - ?.map { (ChapterMetaTable.key like LikePattern("$it%")) as Op } - ?.reduceOrNull { acc, op -> acc or op } - - val metaKeyCondition = - if (keyCondition != null && prefixCondition != null) { - keyCondition or prefixCondition - } else { - keyCondition ?: prefixCondition!! - } - - val condition = (ChapterMetaTable.ref inList item.chapterIds) and metaKeyCondition - - deletedMetas += - ChapterMetaTable - .selectAll() - .where { condition } - .map { ChapterMetaType(it) } - - ChapterMetaTable.deleteWhere { condition } - chapterIds += item.chapterIds - } - - deletedMetas to chapterIds - } - - val chapters = - transaction { - ChapterTable - .selectAll() - .where { ChapterTable.id inList allChapterIds } - .map { ChapterType(it) } - .distinctBy { it.id } - } - - DeleteChapterMetasPayload(clientMutationId, allDeletedMetas, chapters) - } + return DeleteChapterMetasPayload(clientMutationId, allDeletedMetas, chapters) + } data class FetchChapterPagesInput( val clientMutationId: String? = null, @@ -405,67 +397,65 @@ class ChapterMutation { ) @RequireAuth - fun fetchChapterPages(input: FetchChapterPagesInput): CompletableFuture> { + fun fetchChapterPages(input: FetchChapterPagesInput): CompletableFuture { val (clientMutationId, chapterId) = input val paramsMap = input.toParams() return future { - asDataFetcherResult { - var chapter = getChapterDownloadReadyById(chapterId) - val syncResult = KoreaderSyncService.checkAndPullProgress(chapter.id) - var syncConflictInfo: SyncConflictInfoType? = null + var chapter = getChapterDownloadReadyById(chapterId) + val syncResult = KoreaderSyncService.checkAndPullProgress(chapter.id) + var syncConflictInfo: SyncConflictInfoType? = null - if (syncResult != null) { - if (syncResult.isConflict) { - syncConflictInfo = - SyncConflictInfoType( - deviceName = syncResult.device, - remotePage = syncResult.pageRead, - ) - } - - if (syncResult.shouldUpdate) { - // Update DB for SILENT and RECEIVE - transaction { - ChapterTable.update({ ChapterTable.id eq chapter.id }) { - it[lastPageRead] = syncResult.pageRead - it[lastReadAt] = syncResult.timestamp - } - } - } - // For PROMPT, SILENT, and RECEIVE, return the remote progress - chapter = - chapter.copy( - lastPageRead = if (syncResult.shouldUpdate) syncResult.pageRead else chapter.lastPageRead, - lastReadAt = if (syncResult.shouldUpdate) syncResult.timestamp else chapter.lastReadAt, + if (syncResult != null) { + if (syncResult.isConflict) { + syncConflictInfo = + SyncConflictInfoType( + deviceName = syncResult.device, + remotePage = syncResult.pageRead, ) } - val params = - buildString { - if (paramsMap.isNotEmpty()) { - append("?") - paramsMap.entries.forEach { entry -> - if (length > 1) { - append("&") - } - append(entry.key) - append("=") - append(URLEncoder.encode(entry.value, Charsets.UTF_8)) - } + if (syncResult.shouldUpdate) { + // Update DB for SILENT and RECEIVE + transaction { + ChapterTable.update({ ChapterTable.id eq chapter.id }) { + it[lastPageRead] = syncResult.pageRead + it[lastReadAt] = syncResult.timestamp } } - - FetchChapterPagesPayload( - clientMutationId = clientMutationId, - pages = - List(chapter.pageCount) { index -> - "/api/v1/manga/${chapter.mangaId}/chapter/${chapter.index}/page/${index}$params" - }, - chapter = ChapterType(chapter), - syncConflict = syncConflictInfo, - ) + } + // For PROMPT, SILENT, and RECEIVE, return the remote progress + chapter = + chapter.copy( + lastPageRead = if (syncResult.shouldUpdate) syncResult.pageRead else chapter.lastPageRead, + lastReadAt = if (syncResult.shouldUpdate) syncResult.timestamp else chapter.lastReadAt, + ) } + + val params = + buildString { + if (paramsMap.isNotEmpty()) { + append("?") + paramsMap.entries.forEach { entry -> + if (length > 1) { + append("&") + } + append(entry.key) + append("=") + append(URLEncoder.encode(entry.value, Charsets.UTF_8)) + } + } + } + + FetchChapterPagesPayload( + clientMutationId = clientMutationId, + pages = + List(chapter.pageCount) { index -> + "/api/v1/manga/${chapter.mangaId}/chapter/${chapter.index}/page/${index}$params" + }, + chapter = ChapterType(chapter), + syncConflict = syncConflictInfo, + ) } } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/DownloadMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/DownloadMutation.kt index 57e5dfdf..7bb0fea5 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/DownloadMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/DownloadMutation.kt @@ -1,3 +1,5 @@ +@file:Suppress("RedundantNullableReturnType", "unused") + package suwayomi.tachidesk.graphql.mutations import graphql.execution.DataFetcherResult @@ -5,7 +7,6 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.withTimeout import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.transactions.transaction -import suwayomi.tachidesk.graphql.asDataFetcherResult import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.ChapterType import suwayomi.tachidesk.graphql.types.DownloadStatus @@ -30,23 +31,21 @@ class DownloadMutation { ) @RequireAuth - fun deleteDownloadedChapters(input: DeleteDownloadedChaptersInput): DataFetcherResult { + fun deleteDownloadedChapters(input: DeleteDownloadedChaptersInput): DeleteDownloadedChaptersPayload? { val (clientMutationId, chapters) = input - return asDataFetcherResult { - Chapter.deleteChapters(chapters) + Chapter.deleteChapters(chapters) - DeleteDownloadedChaptersPayload( - clientMutationId = clientMutationId, - chapters = - transaction { - ChapterTable - .selectAll() - .where { ChapterTable.id inList chapters } - .map { ChapterType(it) } - }, - ) - } + return DeleteDownloadedChaptersPayload( + clientMutationId = clientMutationId, + chapters = + transaction { + ChapterTable + .selectAll() + .where { ChapterTable.id inList chapters } + .map { ChapterType(it) } + }, + ) } data class DeleteDownloadedChapterInput( @@ -60,20 +59,18 @@ class DownloadMutation { ) @RequireAuth - fun deleteDownloadedChapter(input: DeleteDownloadedChapterInput): DataFetcherResult { + fun deleteDownloadedChapter(input: DeleteDownloadedChapterInput): DeleteDownloadedChapterPayload? { val (clientMutationId, chapter) = input - return asDataFetcherResult { - Chapter.deleteChapters(listOf(chapter)) + Chapter.deleteChapters(listOf(chapter)) - DeleteDownloadedChapterPayload( - clientMutationId = clientMutationId, - chapters = - transaction { - ChapterType(ChapterTable.selectAll().where { ChapterTable.id eq chapter }.first()) - }, - ) - } + return DeleteDownloadedChapterPayload( + clientMutationId = clientMutationId, + chapters = + transaction { + ChapterType(ChapterTable.selectAll().where { ChapterTable.id eq chapter }.first()) + }, + ) } data class EnqueueChapterDownloadsInput( @@ -87,28 +84,24 @@ class DownloadMutation { ) @RequireAuth - fun enqueueChapterDownloads( - input: EnqueueChapterDownloadsInput, - ): CompletableFuture> { + fun enqueueChapterDownloads(input: EnqueueChapterDownloadsInput): CompletableFuture { val (clientMutationId, chapters) = input return future { - asDataFetcherResult { - DownloadManager.enqueue(DownloadManager.EnqueueInput(chapters)) + DownloadManager.enqueue(DownloadManager.EnqueueInput(chapters)) - EnqueueChapterDownloadsPayload( - clientMutationId = clientMutationId, - downloadStatus = - withTimeout(30.seconds) { - DownloadStatus( - DownloadManager.updates - .first { - DownloadManager.getStatus().queue.any { it.chapterId in chapters } - }.let { DownloadManager.getStatus() }, - ) - }, - ) - } + EnqueueChapterDownloadsPayload( + clientMutationId = clientMutationId, + downloadStatus = + withTimeout(30.seconds) { + DownloadStatus( + DownloadManager.updates + .first { + DownloadManager.getStatus().queue.any { it.chapterId in chapters } + }.let { DownloadManager.getStatus() }, + ) + }, + ) } } @@ -123,25 +116,23 @@ class DownloadMutation { ) @RequireAuth - fun enqueueChapterDownload(input: EnqueueChapterDownloadInput): CompletableFuture> { + fun enqueueChapterDownload(input: EnqueueChapterDownloadInput): CompletableFuture { val (clientMutationId, chapter) = input return future { - asDataFetcherResult { - DownloadManager.enqueue(DownloadManager.EnqueueInput(listOf(chapter))) + DownloadManager.enqueue(DownloadManager.EnqueueInput(listOf(chapter))) - EnqueueChapterDownloadPayload( - clientMutationId = clientMutationId, - downloadStatus = - withTimeout(30.seconds) { - DownloadStatus( - DownloadManager.updates - .first { it.updates.any { it.downloadQueueItem.chapterId == chapter } } - .let { DownloadManager.getStatus() }, - ) - }, - ) - } + EnqueueChapterDownloadPayload( + clientMutationId = clientMutationId, + downloadStatus = + withTimeout(30.seconds) { + DownloadStatus( + DownloadManager.updates + .first { it.updates.any { it.downloadQueueItem.chapterId == chapter } } + .let { DownloadManager.getStatus() }, + ) + }, + ) } } @@ -156,30 +147,26 @@ class DownloadMutation { ) @RequireAuth - fun dequeueChapterDownloads( - input: DequeueChapterDownloadsInput, - ): CompletableFuture> { + fun dequeueChapterDownloads(input: DequeueChapterDownloadsInput): CompletableFuture { val (clientMutationId, chapters) = input return future { - asDataFetcherResult { - DownloadManager.dequeue(DownloadManager.EnqueueInput(chapters)) + DownloadManager.dequeue(DownloadManager.EnqueueInput(chapters)) - DequeueChapterDownloadsPayload( - clientMutationId = clientMutationId, - downloadStatus = - withTimeout(30.seconds) { - DownloadStatus( - DownloadManager.updates - .first { - it.updates.any { - it.downloadQueueItem.chapterId in chapters && it.type == DEQUEUED - } - }.let { DownloadManager.getStatus() }, - ) - }, - ) - } + DequeueChapterDownloadsPayload( + clientMutationId = clientMutationId, + downloadStatus = + withTimeout(30.seconds) { + DownloadStatus( + DownloadManager.updates + .first { + it.updates.any { + it.downloadQueueItem.chapterId in chapters && it.type == DEQUEUED + } + }.let { DownloadManager.getStatus() }, + ) + }, + ) } } @@ -194,28 +181,26 @@ class DownloadMutation { ) @RequireAuth - fun dequeueChapterDownload(input: DequeueChapterDownloadInput): CompletableFuture> { + fun dequeueChapterDownload(input: DequeueChapterDownloadInput): CompletableFuture { val (clientMutationId, chapter) = input return future { - asDataFetcherResult { - DownloadManager.dequeue(DownloadManager.EnqueueInput(listOf(chapter))) + DownloadManager.dequeue(DownloadManager.EnqueueInput(listOf(chapter))) - DequeueChapterDownloadPayload( - clientMutationId = clientMutationId, - downloadStatus = - withTimeout(30.seconds) { - DownloadStatus( - DownloadManager.updates - .first { - it.updates.any { - it.downloadQueueItem.chapterId == chapter && it.type == DEQUEUED - } - }.let { DownloadManager.getStatus() }, - ) - }, - ) - } + DequeueChapterDownloadPayload( + clientMutationId = clientMutationId, + downloadStatus = + withTimeout(30.seconds) { + DownloadStatus( + DownloadManager.updates + .first { + it.updates.any { + it.downloadQueueItem.chapterId == chapter && it.type == DEQUEUED + } + }.let { DownloadManager.getStatus() }, + ) + }, + ) } } @@ -229,23 +214,21 @@ class DownloadMutation { ) @RequireAuth - fun startDownloader(input: StartDownloaderInput): CompletableFuture> = + fun startDownloader(input: StartDownloaderInput): CompletableFuture = future { - asDataFetcherResult { - DownloadManager.start() + DownloadManager.start() - StartDownloaderPayload( - input.clientMutationId, - downloadStatus = - withTimeout(30.seconds) { - DownloadStatus( - DownloadManager.updates - .first { it.status == Status.Started } - .let { DownloadManager.getStatus() }, - ) - }, - ) - } + StartDownloaderPayload( + input.clientMutationId, + downloadStatus = + withTimeout(30.seconds) { + DownloadStatus( + DownloadManager.updates + .first { it.status == Status.Started } + .let { DownloadManager.getStatus() }, + ) + }, + ) } data class StopDownloaderInput( @@ -258,23 +241,21 @@ class DownloadMutation { ) @RequireAuth - fun stopDownloader(input: StopDownloaderInput): CompletableFuture> = + fun stopDownloader(input: StopDownloaderInput): CompletableFuture = future { - asDataFetcherResult { - DownloadManager.stop() + DownloadManager.stop() - StopDownloaderPayload( - input.clientMutationId, - downloadStatus = - withTimeout(30.seconds) { - DownloadStatus( - DownloadManager.updates - .first { it.status == Status.Stopped } - .let { DownloadManager.getStatus() }, - ) - }, - ) - } + StopDownloaderPayload( + input.clientMutationId, + downloadStatus = + withTimeout(30.seconds) { + DownloadStatus( + DownloadManager.updates + .first { it.status == Status.Stopped } + .let { DownloadManager.getStatus() }, + ) + }, + ) } data class ClearDownloaderInput( @@ -287,23 +268,21 @@ class DownloadMutation { ) @RequireAuth - fun clearDownloader(input: ClearDownloaderInput): CompletableFuture> = + fun clearDownloader(input: ClearDownloaderInput): CompletableFuture = future { - asDataFetcherResult { - DownloadManager.clear() + DownloadManager.clear() - ClearDownloaderPayload( - input.clientMutationId, - downloadStatus = - withTimeout(30.seconds) { - DownloadStatus( - DownloadManager.updates - .first { it.status == Status.Stopped } - .let { DownloadManager.getStatus() }, - ) - }, - ) - } + ClearDownloaderPayload( + input.clientMutationId, + downloadStatus = + withTimeout(30.seconds) { + DownloadStatus( + DownloadManager.updates + .first { it.status == Status.Stopped } + .let { DownloadManager.getStatus() }, + ) + }, + ) } data class ReorderChapterDownloadInput( @@ -318,25 +297,23 @@ class DownloadMutation { ) @RequireAuth - fun reorderChapterDownload(input: ReorderChapterDownloadInput): CompletableFuture> { + fun reorderChapterDownload(input: ReorderChapterDownloadInput): CompletableFuture { val (clientMutationId, chapter, to) = input return future { - asDataFetcherResult { - DownloadManager.reorder(chapter, to) + DownloadManager.reorder(chapter, to) - ReorderChapterDownloadPayload( - clientMutationId, - downloadStatus = - withTimeout(30.seconds) { - DownloadStatus( - DownloadManager.updates - .first { it.updates.indexOfFirst { it.downloadQueueItem.chapterId == chapter } <= to } - .let { DownloadManager.getStatus() }, - ) - }, - ) - } + ReorderChapterDownloadPayload( + clientMutationId, + downloadStatus = + withTimeout(30.seconds) { + DownloadStatus( + DownloadManager.updates + .first { it.updates.indexOfFirst { it.downloadQueueItem.chapterId == chapter } <= to } + .let { DownloadManager.getStatus() }, + ) + }, + ) } } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ExtensionMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ExtensionMutation.kt index b484890c..78965755 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ExtensionMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ExtensionMutation.kt @@ -1,3 +1,5 @@ +@file:Suppress("RedundantNullableReturnType", "unused") + package suwayomi.tachidesk.graphql.mutations import eu.kanade.tachiyomi.source.local.LocalSource @@ -5,7 +7,6 @@ import graphql.execution.DataFetcherResult import io.javalin.http.UploadedFile import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.transactions.transaction -import suwayomi.tachidesk.graphql.asDataFetcherResult import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.ExtensionType import suwayomi.tachidesk.manga.impl.extension.Extension @@ -75,51 +76,47 @@ class ExtensionMutation { } @RequireAuth - fun updateExtension(input: UpdateExtensionInput): CompletableFuture> { + fun updateExtension(input: UpdateExtensionInput): CompletableFuture { val (clientMutationId, id, patch) = input return future { - asDataFetcherResult { - updateExtensions(listOf(id), patch) + updateExtensions(listOf(id), patch) - val extension = - transaction { - ExtensionTable - .selectAll() - .where { ExtensionTable.pkgName eq id } - .firstOrNull() - ?.let { ExtensionType(it) } - } + val extension = + transaction { + ExtensionTable + .selectAll() + .where { ExtensionTable.pkgName eq id } + .firstOrNull() + ?.let { ExtensionType(it) } + } - UpdateExtensionPayload( - clientMutationId = clientMutationId, - extension = extension, - ) - } + UpdateExtensionPayload( + clientMutationId = clientMutationId, + extension = extension, + ) } } @RequireAuth - fun updateExtensions(input: UpdateExtensionsInput): CompletableFuture> { + fun updateExtensions(input: UpdateExtensionsInput): CompletableFuture { val (clientMutationId, ids, patch) = input return future { - asDataFetcherResult { - updateExtensions(ids, patch) + updateExtensions(ids, patch) - val extensions = - transaction { - ExtensionTable - .selectAll() - .where { ExtensionTable.pkgName inList ids } - .map { ExtensionType(it) } - } + val extensions = + transaction { + ExtensionTable + .selectAll() + .where { ExtensionTable.pkgName inList ids } + .map { ExtensionType(it) } + } - UpdateExtensionsPayload( - clientMutationId = clientMutationId, - extensions = extensions, - ) - } + UpdateExtensionsPayload( + clientMutationId = clientMutationId, + extensions = extensions, + ) } } @@ -133,26 +130,24 @@ class ExtensionMutation { ) @RequireAuth - fun fetchExtensions(input: FetchExtensionsInput): CompletableFuture> { + fun fetchExtensions(input: FetchExtensionsInput): CompletableFuture { val (clientMutationId) = input return future { - asDataFetcherResult { - ExtensionsList.fetchExtensions() + ExtensionsList.fetchExtensions() - val extensions = - transaction { - ExtensionTable - .selectAll() - .where { ExtensionTable.name neq LocalSource.EXTENSION_NAME } - .map { ExtensionType(it) } - } + val extensions = + transaction { + ExtensionTable + .selectAll() + .where { ExtensionTable.name neq LocalSource.EXTENSION_NAME } + .map { ExtensionType(it) } + } - FetchExtensionsPayload( - clientMutationId = clientMutationId, - extensions = extensions, - ) - } + FetchExtensionsPayload( + clientMutationId = clientMutationId, + extensions = extensions, + ) } } @@ -167,23 +162,19 @@ class ExtensionMutation { ) @RequireAuth - fun installExternalExtension( - input: InstallExternalExtensionInput, - ): CompletableFuture> { + fun installExternalExtension(input: InstallExternalExtensionInput): CompletableFuture { val (clientMutationId, extensionFile) = input return future { - asDataFetcherResult { - Extension.installExternalExtension(extensionFile.content(), extensionFile.filename()) + Extension.installExternalExtension(extensionFile.content(), extensionFile.filename()) - val dbExtension = - transaction { ExtensionTable.selectAll().where { ExtensionTable.apkName eq extensionFile.filename() }.first() } + val dbExtension = + transaction { ExtensionTable.selectAll().where { ExtensionTable.apkName eq extensionFile.filename() }.first() } - InstallExternalExtensionPayload( - clientMutationId, - extension = ExtensionType(dbExtension), - ) - } + InstallExternalExtensionPayload( + clientMutationId, + extension = ExtensionType(dbExtension), + ) } } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ImageMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ImageMutation.kt index f899fe86..bff20e71 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ImageMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ImageMutation.kt @@ -1,3 +1,5 @@ +@file:Suppress("RedundantNullableReturnType", "unused") + package suwayomi.tachidesk.graphql.mutations import suwayomi.tachidesk.graphql.directives.RequireAuth diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/InfoMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/InfoMutation.kt index 519f6aa7..3735024f 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/InfoMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/InfoMutation.kt @@ -1,9 +1,10 @@ +@file:Suppress("RedundantNullableReturnType", "unused") + package suwayomi.tachidesk.graphql.mutations import graphql.execution.DataFetcherResult import kotlinx.coroutines.flow.first import kotlinx.coroutines.withTimeout -import suwayomi.tachidesk.graphql.asDataFetcherResult import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.UpdateState.DOWNLOADING import suwayomi.tachidesk.graphql.types.UpdateState.ERROR @@ -26,55 +27,51 @@ class InfoMutation { ) @RequireAuth - fun updateWebUI(input: WebUIUpdateInput): CompletableFuture> { + fun updateWebUI(input: WebUIUpdateInput): CompletableFuture { return future { - asDataFetcherResult { - withTimeout(30.seconds) { - if (WebInterfaceManager.status.value.state === DOWNLOADING) { - return@withTimeout WebUIUpdatePayload(input.clientMutationId, WebInterfaceManager.status.value) - } + withTimeout(30.seconds) { + if (WebInterfaceManager.status.value.state === DOWNLOADING) { + return@withTimeout WebUIUpdatePayload(input.clientMutationId, WebInterfaceManager.status.value) + } - val flavor = WebUIFlavor.current + val flavor = WebUIFlavor.current - val (version, updateAvailable) = WebInterfaceManager.isUpdateAvailable(flavor) + val (version, updateAvailable) = WebInterfaceManager.isUpdateAvailable(flavor) - if (!updateAvailable) { - val didUpdateCheckFail = version.isEmpty() + if (!updateAvailable) { + val didUpdateCheckFail = version.isEmpty() - return@withTimeout WebUIUpdatePayload( - input.clientMutationId, - WebInterfaceManager.getStatus(version, if (didUpdateCheckFail) ERROR else IDLE), - ) - } - try { - WebInterfaceManager.startDownloadInScope(flavor, version) - } catch (e: Exception) { - // ignore since we use the status anyway - } - - WebUIUpdatePayload( + return@withTimeout WebUIUpdatePayload( input.clientMutationId, - updateStatus = WebInterfaceManager.status.first { it.state == DOWNLOADING }, + WebInterfaceManager.getStatus(version, if (didUpdateCheckFail) ERROR else IDLE), ) } + try { + WebInterfaceManager.startDownloadInScope(flavor, version) + } catch (e: Exception) { + // ignore since we use the status anyway + } + + WebUIUpdatePayload( + input.clientMutationId, + updateStatus = WebInterfaceManager.status.first { it.state == DOWNLOADING }, + ) } } } @RequireAuth - fun resetWebUIUpdateStatus(): CompletableFuture> = + fun resetWebUIUpdateStatus(): CompletableFuture = future { - asDataFetcherResult { - withTimeout(30.seconds) { - val isUpdateFinished = WebInterfaceManager.status.value.state != DOWNLOADING - if (!isUpdateFinished) { - throw Exception("Status reset is not allowed during status \"$DOWNLOADING\"") - } - - WebInterfaceManager.resetStatus() - - WebInterfaceManager.status.first { it.state == IDLE } + withTimeout(30.seconds) { + val isUpdateFinished = WebInterfaceManager.status.value.state != DOWNLOADING + if (!isUpdateFinished) { + throw Exception("Status reset is not allowed during status \"$DOWNLOADING\"") } + + WebInterfaceManager.resetStatus() + + WebInterfaceManager.status.first { it.state == IDLE } } } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/KoreaderSyncMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/KoreaderSyncMutation.kt index e1ae1e4c..d509a688 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/KoreaderSyncMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/KoreaderSyncMutation.kt @@ -1,10 +1,11 @@ +@file:Suppress("RedundantNullableReturnType", "unused") + package suwayomi.tachidesk.graphql.mutations import graphql.execution.DataFetcherResult import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.update -import suwayomi.tachidesk.graphql.asDataFetcherResult import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.ChapterType import suwayomi.tachidesk.graphql.types.KoSyncConnectPayload @@ -62,26 +63,24 @@ class KoreaderSyncMutation { ) @RequireAuth - fun pushKoSyncProgress(input: PushKoSyncProgressInput): CompletableFuture> = + fun pushKoSyncProgress(input: PushKoSyncProgressInput): CompletableFuture = future { - asDataFetcherResult { - KoreaderSyncService.pushProgress(input.chapterId) + KoreaderSyncService.pushProgress(input.chapterId) - val chapter = - transaction { - ChapterTable - .selectAll() - .where { ChapterTable.id eq input.chapterId } - .firstOrNull() - ?.let { ChapterType(it) } - } + val chapter = + transaction { + ChapterTable + .selectAll() + .where { ChapterTable.id eq input.chapterId } + .firstOrNull() + ?.let { ChapterType(it) } + } - PushKoSyncProgressPayload( - clientMutationId = input.clientMutationId, - success = true, - chapter = chapter, - ) - } + PushKoSyncProgressPayload( + clientMutationId = input.clientMutationId, + success = true, + chapter = chapter, + ) } data class PullKoSyncProgressInput( @@ -96,45 +95,43 @@ class KoreaderSyncMutation { ) @RequireAuth - fun pullKoSyncProgress(input: PullKoSyncProgressInput): CompletableFuture> = + fun pullKoSyncProgress(input: PullKoSyncProgressInput): CompletableFuture = future { - asDataFetcherResult { - val syncResult = KoreaderSyncService.checkAndPullProgress(input.chapterId) - var syncConflictInfo: SyncConflictInfoType? = null + val syncResult = KoreaderSyncService.checkAndPullProgress(input.chapterId) + var syncConflictInfo: SyncConflictInfoType? = null - if (syncResult != null) { - if (syncResult.isConflict) { - syncConflictInfo = - SyncConflictInfoType( - deviceName = syncResult.device, - remotePage = syncResult.pageRead, - ) - } + if (syncResult != null) { + if (syncResult.isConflict) { + syncConflictInfo = + SyncConflictInfoType( + deviceName = syncResult.device, + remotePage = syncResult.pageRead, + ) + } - if (syncResult.shouldUpdate) { - transaction { - ChapterTable.update({ ChapterTable.id eq input.chapterId }) { - it[lastPageRead] = syncResult.pageRead - it[lastReadAt] = syncResult.timestamp - } + if (syncResult.shouldUpdate) { + transaction { + ChapterTable.update({ ChapterTable.id eq input.chapterId }) { + it[lastPageRead] = syncResult.pageRead + it[lastReadAt] = syncResult.timestamp } } } - - val chapter = - transaction { - ChapterTable - .selectAll() - .where { ChapterTable.id eq input.chapterId } - .firstOrNull() - ?.let { ChapterType(it) } - } - - PullKoSyncProgressPayload( - clientMutationId = input.clientMutationId, - chapter = chapter, - syncConflict = syncConflictInfo, - ) } + + val chapter = + transaction { + ChapterTable + .selectAll() + .where { ChapterTable.id eq input.chapterId } + .firstOrNull() + ?.let { ChapterType(it) } + } + + PullKoSyncProgressPayload( + clientMutationId = input.clientMutationId, + chapter = chapter, + syncConflict = syncConflictInfo, + ) } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/MangaMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/MangaMutation.kt index 175c790f..20df97bf 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/MangaMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/MangaMutation.kt @@ -1,6 +1,7 @@ +@file:Suppress("RedundantNullableReturnType", "unused") + package suwayomi.tachidesk.graphql.mutations -import graphql.execution.DataFetcherResult import org.jetbrains.exposed.sql.LikePattern import org.jetbrains.exposed.sql.Op import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq @@ -12,7 +13,6 @@ import org.jetbrains.exposed.sql.or import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.transactions.transaction import org.jetbrains.exposed.sql.update -import suwayomi.tachidesk.graphql.asDataFetcherResult import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.MangaMetaType import suwayomi.tachidesk.graphql.types.MangaType @@ -98,44 +98,40 @@ class MangaMutation { } @RequireAuth - fun updateManga(input: UpdateMangaInput): CompletableFuture> { + fun updateManga(input: UpdateMangaInput): CompletableFuture { val (clientMutationId, id, patch) = input return future { - asDataFetcherResult { - updateMangas(listOf(id), patch) + updateMangas(listOf(id), patch) - val manga = - transaction { - MangaType(MangaTable.selectAll().where { MangaTable.id eq id }.first()) - } + val manga = + transaction { + MangaType(MangaTable.selectAll().where { MangaTable.id eq id }.first()) + } - UpdateMangaPayload( - clientMutationId = clientMutationId, - manga = manga, - ) - } + UpdateMangaPayload( + clientMutationId = clientMutationId, + manga = manga, + ) } } @RequireAuth - fun updateMangas(input: UpdateMangasInput): CompletableFuture> { + fun updateMangas(input: UpdateMangasInput): CompletableFuture { val (clientMutationId, ids, patch) = input return future { - asDataFetcherResult { - updateMangas(ids, patch) + updateMangas(ids, patch) - val mangas = - transaction { - MangaTable.selectAll().where { MangaTable.id inList ids }.map { MangaType(it) } - } + val mangas = + transaction { + MangaTable.selectAll().where { MangaTable.id inList ids }.map { MangaType(it) } + } - UpdateMangasPayload( - clientMutationId = clientMutationId, - mangas = mangas, - ) - } + UpdateMangasPayload( + clientMutationId = clientMutationId, + mangas = mangas, + ) } } @@ -150,22 +146,20 @@ class MangaMutation { ) @RequireAuth - fun fetchManga(input: FetchMangaInput): CompletableFuture> { + fun fetchManga(input: FetchMangaInput): CompletableFuture { val (clientMutationId, id) = input return future { - asDataFetcherResult { - Manga.fetchManga(id) + Manga.fetchManga(id) - val manga = - transaction { - MangaTable.selectAll().where { MangaTable.id eq id }.first() - } - FetchMangaPayload( - clientMutationId = clientMutationId, - manga = MangaType(manga), - ) - } + val manga = + transaction { + MangaTable.selectAll().where { MangaTable.id eq id }.first() + } + FetchMangaPayload( + clientMutationId = clientMutationId, + manga = MangaType(manga), + ) } } @@ -180,14 +174,12 @@ class MangaMutation { ) @RequireAuth - fun setMangaMeta(input: SetMangaMetaInput): DataFetcherResult { + fun setMangaMeta(input: SetMangaMetaInput): SetMangaMetaPayload? { val (clientMutationId, meta) = input - return asDataFetcherResult { - Manga.modifyMangaMeta(meta.mangaId, meta.key, meta.value) + Manga.modifyMangaMeta(meta.mangaId, meta.key, meta.value) - SetMangaMetaPayload(clientMutationId, meta) - } + return SetMangaMetaPayload(clientMutationId, meta) } data class DeleteMangaMetaInput( @@ -203,34 +195,32 @@ class MangaMutation { ) @RequireAuth - fun deleteMangaMeta(input: DeleteMangaMetaInput): DataFetcherResult { + fun deleteMangaMeta(input: DeleteMangaMetaInput): DeleteMangaMetaPayload? { val (clientMutationId, mangaId, key) = input - return asDataFetcherResult { - val (meta, manga) = - transaction { - val meta = - MangaMetaTable - .selectAll() - .where { (MangaMetaTable.ref eq mangaId) and (MangaMetaTable.key eq key) } - .firstOrNull() + val (meta, manga) = + transaction { + val meta = + MangaMetaTable + .selectAll() + .where { (MangaMetaTable.ref eq mangaId) and (MangaMetaTable.key eq key) } + .firstOrNull() - MangaMetaTable.deleteWhere { (MangaMetaTable.ref eq mangaId) and (MangaMetaTable.key eq key) } + MangaMetaTable.deleteWhere { (MangaMetaTable.ref eq mangaId) and (MangaMetaTable.key eq key) } - val manga = - transaction { - MangaType(MangaTable.selectAll().where { MangaTable.id eq mangaId }.first()) - } + val manga = + transaction { + MangaType(MangaTable.selectAll().where { MangaTable.id eq mangaId }.first()) + } - if (meta != null) { - MangaMetaType(meta) - } else { - null - } to manga - } + if (meta != null) { + MangaMetaType(meta) + } else { + null + } to manga + } - DeleteMangaMetaPayload(clientMutationId, meta, manga) - } + return DeleteMangaMetaPayload(clientMutationId, meta, manga) } data class SetMangaMetasItem( @@ -250,43 +240,41 @@ class MangaMutation { ) @RequireAuth - fun setMangaMetas(input: SetMangaMetasInput): DataFetcherResult { + fun setMangaMetas(input: SetMangaMetasInput): SetMangaMetasPayload? { val (clientMutationId, items) = input - return asDataFetcherResult { - val metaByMangaId = - items - .flatMap { item -> - val metaMap = item.metas.associate { it.key to it.value } - item.mangaIds.map { mangaId -> mangaId to metaMap } - }.groupBy({ it.first }, { it.second }) - .mapValues { (_, maps) -> maps.reduce { acc, map -> acc + map } } + val metaByMangaId = + items + .flatMap { item -> + val metaMap = item.metas.associate { it.key to it.value } + item.mangaIds.map { mangaId -> mangaId to metaMap } + }.groupBy({ it.first }, { it.second }) + .mapValues { (_, maps) -> maps.reduce { acc, map -> acc + map } } - Manga.modifyMangasMetas(metaByMangaId) + Manga.modifyMangasMetas(metaByMangaId) - val allMangaIds = metaByMangaId.keys - val allMetaKeys = metaByMangaId.values.flatMap { it.keys }.distinct() + val allMangaIds = metaByMangaId.keys + val allMetaKeys = metaByMangaId.values.flatMap { it.keys }.distinct() - val (updatedMetas, mangas) = - transaction { - val updatedMetas = - MangaMetaTable - .selectAll() - .where { (MangaMetaTable.ref inList allMangaIds) and (MangaMetaTable.key inList allMetaKeys) } - .map { MangaMetaType(it) } + val (updatedMetas, mangas) = + transaction { + val updatedMetas = + MangaMetaTable + .selectAll() + .where { (MangaMetaTable.ref inList allMangaIds) and (MangaMetaTable.key inList allMetaKeys) } + .map { MangaMetaType(it) } - val mangas = - MangaTable - .selectAll() - .where { MangaTable.id inList allMangaIds } - .map { MangaType(it) } - .distinctBy { it.id } + val mangas = + MangaTable + .selectAll() + .where { MangaTable.id inList allMangaIds } + .map { MangaType(it) } + .distinctBy { it.id } - updatedMetas to mangas - } + updatedMetas to mangas + } - SetMangaMetasPayload(clientMutationId, updatedMetas, mangas) - } + return SetMangaMetasPayload(clientMutationId, updatedMetas, mangas) } data class DeleteMangaMetasItem( @@ -307,63 +295,61 @@ class MangaMutation { ) @RequireAuth - fun deleteMangaMetas(input: DeleteMangaMetasInput): DataFetcherResult { + fun deleteMangaMetas(input: DeleteMangaMetasInput): DeleteMangaMetasPayload? { val (clientMutationId, items) = input - return asDataFetcherResult { - items.forEach { item -> - require(!item.keys.isNullOrEmpty() || !item.prefixes.isNullOrEmpty()) { - "Either 'keys' or 'prefixes' must be provided for each item" + items.forEach { item -> + require(!item.keys.isNullOrEmpty() || !item.prefixes.isNullOrEmpty()) { + "Either 'keys' or 'prefixes' must be provided for each item" + } + } + + val (allDeletedMetas, allMangaIds) = + transaction { + val deletedMetas = mutableListOf() + val mangaIds = mutableSetOf() + + items.forEach { item -> + val keyCondition: Op? = + item.keys?.takeIf { it.isNotEmpty() }?.let { MangaMetaTable.key inList it } + + val prefixCondition: Op? = + item.prefixes + ?.filter { it.isNotEmpty() } + ?.map { (MangaMetaTable.key like LikePattern("$it%")) as Op } + ?.reduceOrNull { acc, op -> acc or op } + + val metaKeyCondition = + if (keyCondition != null && prefixCondition != null) { + keyCondition or prefixCondition + } else { + keyCondition ?: prefixCondition!! + } + + val condition = (MangaMetaTable.ref inList item.mangaIds) and metaKeyCondition + + deletedMetas += + MangaMetaTable + .selectAll() + .where { condition } + .map { MangaMetaType(it) } + + MangaMetaTable.deleteWhere { condition } + mangaIds += item.mangaIds } + + deletedMetas to mangaIds } - val (allDeletedMetas, allMangaIds) = - transaction { - val deletedMetas = mutableListOf() - val mangaIds = mutableSetOf() + val mangas = + transaction { + MangaTable + .selectAll() + .where { MangaTable.id inList allMangaIds } + .map { MangaType(it) } + .distinctBy { it.id } + } - items.forEach { item -> - val keyCondition: Op? = - item.keys?.takeIf { it.isNotEmpty() }?.let { MangaMetaTable.key inList it } - - val prefixCondition: Op? = - item.prefixes - ?.filter { it.isNotEmpty() } - ?.map { (MangaMetaTable.key like LikePattern("$it%")) as Op } - ?.reduceOrNull { acc, op -> acc or op } - - val metaKeyCondition = - if (keyCondition != null && prefixCondition != null) { - keyCondition or prefixCondition - } else { - keyCondition ?: prefixCondition!! - } - - val condition = (MangaMetaTable.ref inList item.mangaIds) and metaKeyCondition - - deletedMetas += - MangaMetaTable - .selectAll() - .where { condition } - .map { MangaMetaType(it) } - - MangaMetaTable.deleteWhere { condition } - mangaIds += item.mangaIds - } - - deletedMetas to mangaIds - } - - val mangas = - transaction { - MangaTable - .selectAll() - .where { MangaTable.id inList allMangaIds } - .map { MangaType(it) } - .distinctBy { it.id } - } - - DeleteMangaMetasPayload(clientMutationId, allDeletedMetas, mangas) - } + return DeleteMangaMetasPayload(clientMutationId, allDeletedMetas, mangas) } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/MetaMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/MetaMutation.kt index f2926528..cb14d2e7 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/MetaMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/MetaMutation.kt @@ -1,3 +1,5 @@ +@file:Suppress("RedundantNullableReturnType", "unused") + package suwayomi.tachidesk.graphql.mutations import graphql.execution.DataFetcherResult @@ -12,7 +14,6 @@ import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.transactions.transaction import suwayomi.tachidesk.global.impl.GlobalMeta import suwayomi.tachidesk.global.model.table.GlobalMetaTable -import suwayomi.tachidesk.graphql.asDataFetcherResult import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.GlobalMetaType import suwayomi.tachidesk.graphql.types.MetaInput @@ -29,14 +30,12 @@ class MetaMutation { ) @RequireAuth - fun setGlobalMeta(input: SetGlobalMetaInput): DataFetcherResult { + fun setGlobalMeta(input: SetGlobalMetaInput): SetGlobalMetaPayload? { val (clientMutationId, meta) = input - return asDataFetcherResult { - GlobalMeta.modifyMeta(meta.key, meta.value) + GlobalMeta.modifyMeta(meta.key, meta.value) - SetGlobalMetaPayload(clientMutationId, meta) - } + return SetGlobalMetaPayload(clientMutationId, meta) } data class DeleteGlobalMetaInput( @@ -50,29 +49,27 @@ class MetaMutation { ) @RequireAuth - fun deleteGlobalMeta(input: DeleteGlobalMetaInput): DataFetcherResult { + fun deleteGlobalMeta(input: DeleteGlobalMetaInput): DeleteGlobalMetaPayload? { val (clientMutationId, key) = input - return asDataFetcherResult { - val meta = - transaction { - val meta = - GlobalMetaTable - .selectAll() - .where { GlobalMetaTable.key eq key } - .firstOrNull() + val meta = + transaction { + val meta = + GlobalMetaTable + .selectAll() + .where { GlobalMetaTable.key eq key } + .firstOrNull() - GlobalMetaTable.deleteWhere { GlobalMetaTable.key eq key } + GlobalMetaTable.deleteWhere { GlobalMetaTable.key eq key } - if (meta != null) { - GlobalMetaType(meta) - } else { - null - } + if (meta != null) { + GlobalMetaType(meta) + } else { + null } + } - DeleteGlobalMetaPayload(clientMutationId, meta) - } + return DeleteGlobalMetaPayload(clientMutationId, meta) } data class SetGlobalMetasInput( @@ -86,23 +83,21 @@ class MetaMutation { ) @RequireAuth - fun setGlobalMetas(input: SetGlobalMetasInput): DataFetcherResult { + fun setGlobalMetas(input: SetGlobalMetasInput): SetGlobalMetasPayload? { val (clientMutationId, metas) = input - return asDataFetcherResult { - val metaMap = metas.associate { it.key to it.value } - GlobalMeta.modifyMetas(metaMap) + val metaMap = metas.associate { it.key to it.value } + GlobalMeta.modifyMetas(metaMap) - val updatedMetas = - transaction { - GlobalMetaTable - .selectAll() - .where { GlobalMetaTable.key inList metaMap.keys } - .map { GlobalMetaType(it) } - } + val updatedMetas = + transaction { + GlobalMetaTable + .selectAll() + .where { GlobalMetaTable.key inList metaMap.keys } + .map { GlobalMetaType(it) } + } - SetGlobalMetasPayload(clientMutationId, updatedMetas) - } + return SetGlobalMetasPayload(clientMutationId, updatedMetas) } data class DeleteGlobalMetasInput( @@ -117,43 +112,41 @@ class MetaMutation { ) @RequireAuth - fun deleteGlobalMetas(input: DeleteGlobalMetasInput): DataFetcherResult { + fun deleteGlobalMetas(input: DeleteGlobalMetasInput): DeleteGlobalMetasPayload? { val (clientMutationId, keys, prefixes) = input - return asDataFetcherResult { - require(!keys.isNullOrEmpty() || !prefixes.isNullOrEmpty()) { - "Either 'keys' or 'prefixes' must be provided" + require(!keys.isNullOrEmpty() || !prefixes.isNullOrEmpty()) { + "Either 'keys' or 'prefixes' must be provided" + } + + val metas = + transaction { + val keyCondition: Op? = keys?.takeIf { it.isNotEmpty() }?.let { GlobalMetaTable.key inList it } + + val prefixCondition: Op? = + prefixes + ?.filter { it.isNotEmpty() } + ?.map { (GlobalMetaTable.key like LikePattern("$it%")) as Op } + ?.reduceOrNull { acc, op -> acc or op } + + val finalCondition = + if (keyCondition != null && prefixCondition != null) { + keyCondition or prefixCondition + } else { + keyCondition ?: prefixCondition!! + } + + val metas = + GlobalMetaTable + .selectAll() + .where { finalCondition } + .map { GlobalMetaType(it) } + + GlobalMetaTable.deleteWhere { finalCondition } + + metas } - val metas = - transaction { - val keyCondition: Op? = keys?.takeIf { it.isNotEmpty() }?.let { GlobalMetaTable.key inList it } - - val prefixCondition: Op? = - prefixes - ?.filter { it.isNotEmpty() } - ?.map { (GlobalMetaTable.key like LikePattern("$it%")) as Op } - ?.reduceOrNull { acc, op -> acc or op } - - val finalCondition = - if (keyCondition != null && prefixCondition != null) { - keyCondition or prefixCondition - } else { - keyCondition ?: prefixCondition!! - } - - val metas = - GlobalMetaTable - .selectAll() - .where { finalCondition } - .map { GlobalMetaType(it) } - - GlobalMetaTable.deleteWhere { finalCondition } - - metas - } - - DeleteGlobalMetasPayload(clientMutationId, metas) - } + return DeleteGlobalMetasPayload(clientMutationId, metas) } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/SettingsMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/SettingsMutation.kt index 7a97f95c..42244be1 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/SettingsMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/SettingsMutation.kt @@ -1,3 +1,5 @@ +@file:Suppress("RedundantNullableReturnType", "unused") + package suwayomi.tachidesk.graphql.mutations import com.expediagroup.graphql.generator.annotations.GraphQLIgnore diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/SourceMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/SourceMutation.kt index c9b619e7..62b83906 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/SourceMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/SourceMutation.kt @@ -1,3 +1,5 @@ +@file:Suppress("RedundantNullableReturnType", "unused") + package suwayomi.tachidesk.graphql.mutations import androidx.preference.CheckBoxPreference @@ -5,7 +7,6 @@ import androidx.preference.EditTextPreference import androidx.preference.ListPreference import androidx.preference.MultiSelectListPreference import androidx.preference.SwitchPreferenceCompat -import graphql.execution.DataFetcherResult import org.jetbrains.exposed.sql.LikePattern import org.jetbrains.exposed.sql.Op import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq @@ -16,7 +17,6 @@ import org.jetbrains.exposed.sql.deleteWhere import org.jetbrains.exposed.sql.or import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.transactions.transaction -import suwayomi.tachidesk.graphql.asDataFetcherResult import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.FilterChange import suwayomi.tachidesk.graphql.types.MangaType @@ -47,14 +47,12 @@ class SourceMutation { ) @RequireAuth - fun setSourceMeta(input: SetSourceMetaInput): DataFetcherResult { + fun setSourceMeta(input: SetSourceMetaInput): SetSourceMetaPayload? { val (clientMutationId, meta) = input - return asDataFetcherResult { - Source.modifyMeta(meta.sourceId, meta.key, meta.value) + Source.modifyMeta(meta.sourceId, meta.key, meta.value) - SetSourceMetaPayload(clientMutationId, meta) - } + return SetSourceMetaPayload(clientMutationId, meta) } data class DeleteSourceMetaInput( @@ -70,38 +68,36 @@ class SourceMutation { ) @RequireAuth - fun deleteSourceMeta(input: DeleteSourceMetaInput): DataFetcherResult { + fun deleteSourceMeta(input: DeleteSourceMetaInput): DeleteSourceMetaPayload? { val (clientMutationId, sourceId, key) = input - return asDataFetcherResult { - val (meta, source) = - transaction { - val meta = - SourceMetaTable + val (meta, source) = + transaction { + val meta = + SourceMetaTable + .selectAll() + .where { (SourceMetaTable.ref eq sourceId) and (SourceMetaTable.key eq key) } + .firstOrNull() + + SourceMetaTable.deleteWhere { (SourceMetaTable.ref eq sourceId) and (SourceMetaTable.key eq key) } + + val source = + transaction { + SourceTable .selectAll() - .where { (SourceMetaTable.ref eq sourceId) and (SourceMetaTable.key eq key) } + .where { SourceTable.id eq sourceId } .firstOrNull() + ?.let { SourceType(it) } + } - SourceMetaTable.deleteWhere { (SourceMetaTable.ref eq sourceId) and (SourceMetaTable.key eq key) } + if (meta != null) { + SourceMetaType(meta) + } else { + null + } to source + } - val source = - transaction { - SourceTable - .selectAll() - .where { SourceTable.id eq sourceId } - .firstOrNull() - ?.let { SourceType(it) } - } - - if (meta != null) { - SourceMetaType(meta) - } else { - null - } to source - } - - DeleteSourceMetaPayload(clientMutationId, meta, source) - } + return DeleteSourceMetaPayload(clientMutationId, meta, source) } data class SetSourceMetasItem( @@ -121,43 +117,41 @@ class SourceMutation { ) @RequireAuth - fun setSourceMetas(input: SetSourceMetasInput): DataFetcherResult { + fun setSourceMetas(input: SetSourceMetasInput): SetSourceMetasPayload? { val (clientMutationId, items) = input - return asDataFetcherResult { - val metaBySourceId = - items - .flatMap { item -> - val metaMap = item.metas.associate { it.key to it.value } - item.sourceIds.map { sourceId -> sourceId to metaMap } - }.groupBy({ it.first }, { it.second }) - .mapValues { (_, maps) -> maps.reduce { acc, map -> acc + map } } + val metaBySourceId = + items + .flatMap { item -> + val metaMap = item.metas.associate { it.key to it.value } + item.sourceIds.map { sourceId -> sourceId to metaMap } + }.groupBy({ it.first }, { it.second }) + .mapValues { (_, maps) -> maps.reduce { acc, map -> acc + map } } - Source.modifySourceMetas(metaBySourceId) + Source.modifySourceMetas(metaBySourceId) - val allSourceIds = metaBySourceId.keys - val allMetaKeys = metaBySourceId.values.flatMap { it.keys }.distinct() + val allSourceIds = metaBySourceId.keys + val allMetaKeys = metaBySourceId.values.flatMap { it.keys }.distinct() - val (updatedMetas, sources) = - transaction { - val updatedMetas = - SourceMetaTable - .selectAll() - .where { (SourceMetaTable.ref inList allSourceIds) and (SourceMetaTable.key inList allMetaKeys) } - .map { SourceMetaType(it) } + val (updatedMetas, sources) = + transaction { + val updatedMetas = + SourceMetaTable + .selectAll() + .where { (SourceMetaTable.ref inList allSourceIds) and (SourceMetaTable.key inList allMetaKeys) } + .map { SourceMetaType(it) } - val sources = - SourceTable - .selectAll() - .where { SourceTable.id inList allSourceIds } - .mapNotNull { SourceType(it) } - .distinctBy { it.id } + val sources = + SourceTable + .selectAll() + .where { SourceTable.id inList allSourceIds } + .mapNotNull { SourceType(it) } + .distinctBy { it.id } - updatedMetas to sources - } + updatedMetas to sources + } - SetSourceMetasPayload(clientMutationId, updatedMetas, sources) - } + return SetSourceMetasPayload(clientMutationId, updatedMetas, sources) } data class DeleteSourceMetasItem( @@ -178,64 +172,62 @@ class SourceMutation { ) @RequireAuth - fun deleteSourceMetas(input: DeleteSourceMetasInput): DataFetcherResult { + fun deleteSourceMetas(input: DeleteSourceMetasInput): DeleteSourceMetasPayload? { val (clientMutationId, items) = input - return asDataFetcherResult { - items.forEach { item -> - require(!item.keys.isNullOrEmpty() || !item.prefixes.isNullOrEmpty()) { - "Either 'keys' or 'prefixes' must be provided for each item" + items.forEach { item -> + require(!item.keys.isNullOrEmpty() || !item.prefixes.isNullOrEmpty()) { + "Either 'keys' or 'prefixes' must be provided for each item" + } + } + + val (allDeletedMetas, allSourceIds) = + transaction { + val deletedMetas = mutableListOf() + val sourceIds = mutableSetOf() + + items.forEach { item -> + val keyCondition: Op? = + item.keys?.takeIf { it.isNotEmpty() }?.let { SourceMetaTable.key inList it } + + val prefixCondition: Op? = + item.prefixes + ?.filter { it.isNotEmpty() } + ?.map { (SourceMetaTable.key like LikePattern("$it%")) as Op } + ?.reduceOrNull { acc, op -> acc or op } + + val metaKeyCondition = + if (keyCondition != null && prefixCondition != null) { + keyCondition or prefixCondition + } else { + keyCondition ?: prefixCondition!! + } + + val condition = (SourceMetaTable.ref inList item.sourceIds) and metaKeyCondition + + deletedMetas += + SourceMetaTable + .selectAll() + .where { condition } + .map { SourceMetaType(it) } + + SourceMetaTable.deleteWhere { condition } + sourceIds += item.sourceIds } + + deletedMetas to sourceIds } - val (allDeletedMetas, allSourceIds) = - transaction { - val deletedMetas = mutableListOf() - val sourceIds = mutableSetOf() + val sources = + transaction { + SourceTable + .selectAll() + .where { SourceTable.id inList allSourceIds } + .mapNotNull { SourceType(it) } + .distinctBy { it.id } + } - items.forEach { item -> - val keyCondition: Op? = - item.keys?.takeIf { it.isNotEmpty() }?.let { SourceMetaTable.key inList it } - - val prefixCondition: Op? = - item.prefixes - ?.filter { it.isNotEmpty() } - ?.map { (SourceMetaTable.key like LikePattern("$it%")) as Op } - ?.reduceOrNull { acc, op -> acc or op } - - val metaKeyCondition = - if (keyCondition != null && prefixCondition != null) { - keyCondition or prefixCondition - } else { - keyCondition ?: prefixCondition!! - } - - val condition = (SourceMetaTable.ref inList item.sourceIds) and metaKeyCondition - - deletedMetas += - SourceMetaTable - .selectAll() - .where { condition } - .map { SourceMetaType(it) } - - SourceMetaTable.deleteWhere { condition } - sourceIds += item.sourceIds - } - - deletedMetas to sourceIds - } - - val sources = - transaction { - SourceTable - .selectAll() - .where { SourceTable.id inList allSourceIds } - .mapNotNull { SourceType(it) } - .distinctBy { it.id } - } - - DeleteSourceMetasPayload(clientMutationId, allDeletedMetas, sources) - } + return DeleteSourceMetasPayload(clientMutationId, allDeletedMetas, sources) } enum class FetchSourceMangaType { @@ -260,50 +252,48 @@ class SourceMutation { ) @RequireAuth - fun fetchSourceManga(input: FetchSourceMangaInput): CompletableFuture> { + fun fetchSourceManga(input: FetchSourceMangaInput): CompletableFuture { val (clientMutationId, sourceId, type, page, query, filters) = input return future { - asDataFetcherResult { - val source = GetCatalogueSource.getCatalogueSourceOrNull(sourceId)!! - val mangasPage = - when (type) { - FetchSourceMangaType.SEARCH -> { - source.getSearchManga( - page = page, - query = query.orEmpty(), - filters = updateFilterList(source, filters), - ) - } - - FetchSourceMangaType.POPULAR -> { - source.getPopularManga(page) - } - - FetchSourceMangaType.LATEST -> { - if (!source.supportsLatest) throw Exception("Source does not support latest") - source.getLatestUpdates(page) - } + val source = GetCatalogueSource.getCatalogueSourceOrNull(sourceId)!! + val mangasPage = + when (type) { + FetchSourceMangaType.SEARCH -> { + source.getSearchManga( + page = page, + query = query.orEmpty(), + filters = updateFilterList(source, filters), + ) } - val mangaIds = mangasPage.insertOrUpdate(sourceId) - - val mangas = - transaction { - MangaTable - .selectAll() - .where { MangaTable.id inList mangaIds } - .map { MangaType(it) } - }.sortedBy { - mangaIds.indexOf(it.id) + FetchSourceMangaType.POPULAR -> { + source.getPopularManga(page) } - FetchSourceMangaPayload( - clientMutationId = clientMutationId, - mangas = mangas, - hasNextPage = mangasPage.hasNextPage, - ) - } + FetchSourceMangaType.LATEST -> { + if (!source.supportsLatest) throw Exception("Source does not support latest") + source.getLatestUpdates(page) + } + } + + val mangaIds = mangasPage.insertOrUpdate(sourceId) + + val mangas = + transaction { + MangaTable + .selectAll() + .where { MangaTable.id inList mangaIds } + .map { MangaType(it) } + }.sortedBy { + mangaIds.indexOf(it.id) + } + + FetchSourceMangaPayload( + clientMutationId = clientMutationId, + mangas = mangas, + hasNextPage = mangasPage.hasNextPage, + ) } } @@ -329,29 +319,27 @@ class SourceMutation { ) @RequireAuth - fun updateSourcePreference(input: UpdateSourcePreferenceInput): DataFetcherResult { + fun updateSourcePreference(input: UpdateSourcePreferenceInput): UpdateSourcePreferencePayload? { val (clientMutationId, sourceId, change) = input - return asDataFetcherResult { - Source.setSourcePreference(sourceId, change.position, "") { preference -> - when (preference) { - is SwitchPreferenceCompat -> change.switchState - is CheckBoxPreference -> change.checkBoxState - is EditTextPreference -> change.editTextState - is ListPreference -> change.listState - is MultiSelectListPreference -> change.multiSelectState?.toSet() - else -> throw RuntimeException("sealed class cannot have more subtypes!") - } ?: throw Exception("Expected change to ${preference::class.simpleName}") - } - - UpdateSourcePreferencePayload( - clientMutationId = clientMutationId, - preferences = Source.getSourcePreferencesRaw(sourceId).map { preferenceOf(it) }, - source = - transaction { - SourceType(SourceTable.selectAll().where { SourceTable.id eq sourceId }.first())!! - }, - ) + Source.setSourcePreference(sourceId, change.position, "") { preference -> + when (preference) { + is SwitchPreferenceCompat -> change.switchState + is CheckBoxPreference -> change.checkBoxState + is EditTextPreference -> change.editTextState + is ListPreference -> change.listState + is MultiSelectListPreference -> change.multiSelectState?.toSet() + else -> throw RuntimeException("sealed class cannot have more subtypes!") + } ?: throw Exception("Expected change to ${preference::class.simpleName}") } + + return UpdateSourcePreferencePayload( + clientMutationId = clientMutationId, + preferences = Source.getSourcePreferencesRaw(sourceId).map { preferenceOf(it) }, + source = + transaction { + SourceType(SourceTable.selectAll().where { SourceTable.id eq sourceId }.first())!! + }, + ) } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/TrackMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/TrackMutation.kt index ac618133..41e06dde 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/TrackMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/TrackMutation.kt @@ -1,3 +1,5 @@ +@file:Suppress("RedundantNullableReturnType", "unused") + package suwayomi.tachidesk.graphql.mutations import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated @@ -6,7 +8,6 @@ import graphql.execution.DataFetcherResult import org.jetbrains.exposed.sql.and import org.jetbrains.exposed.sql.selectAll import org.jetbrains.exposed.sql.transactions.transaction -import suwayomi.tachidesk.graphql.asDataFetcherResult import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.TrackRecordType import suwayomi.tachidesk.graphql.types.TrackerType @@ -222,24 +223,22 @@ class TrackMutation { ) @RequireAuth - fun trackProgress(input: TrackProgressInput): CompletableFuture> { + fun trackProgress(input: TrackProgressInput): CompletableFuture { val (clientMutationId, mangaId) = input return future { - asDataFetcherResult { - Track.trackChapter(mangaId) - val trackRecords = - transaction { - TrackRecordTable - .selectAll() - .where { TrackRecordTable.mangaId eq mangaId } - .toList() - } - TrackProgressPayload( - clientMutationId, - trackRecords.map { TrackRecordType(it) }, - ) - } + Track.trackChapter(mangaId) + val trackRecords = + transaction { + TrackRecordTable + .selectAll() + .where { TrackRecordTable.mangaId eq mangaId } + .toList() + } + TrackProgressPayload( + clientMutationId, + trackRecords.map { TrackRecordType(it) }, + ) } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/UpdateMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/UpdateMutation.kt index d8cbaa76..4f668362 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/UpdateMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/UpdateMutation.kt @@ -1,9 +1,10 @@ +@file:Suppress("RedundantNullableReturnType", "unused") + package suwayomi.tachidesk.graphql.mutations import graphql.execution.DataFetcherResult import kotlinx.coroutines.flow.first import kotlinx.coroutines.withTimeout -import suwayomi.tachidesk.graphql.asDataFetcherResult import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.LibraryUpdateStatus import suwayomi.tachidesk.graphql.types.UpdateStatus @@ -28,7 +29,7 @@ class UpdateMutation { ) @RequireAuth - fun updateLibrary(input: UpdateLibraryInput): CompletableFuture> { + fun updateLibrary(input: UpdateLibraryInput): CompletableFuture { updater.addCategoriesToUpdateQueue( Category.getCategoryList().filter { input.categories?.contains(it.id) ?: true }, clear = true, @@ -36,17 +37,15 @@ class UpdateMutation { ) return future { - asDataFetcherResult { - UpdateLibraryPayload( - input.clientMutationId, - updateStatus = - withTimeout(30.seconds) { - LibraryUpdateStatus( - updater.updates.first(), - ) - }, - ) - } + UpdateLibraryPayload( + input.clientMutationId, + updateStatus = + withTimeout(30.seconds) { + LibraryUpdateStatus( + updater.updates.first(), + ) + }, + ) } } @@ -60,7 +59,7 @@ class UpdateMutation { ) @RequireAuth - fun updateLibraryManga(input: UpdateLibraryMangaInput): CompletableFuture> { + fun updateLibraryManga(input: UpdateLibraryMangaInput): CompletableFuture { updateLibrary( UpdateLibraryInput( clientMutationId = input.clientMutationId, @@ -69,15 +68,13 @@ class UpdateMutation { ) return future { - asDataFetcherResult { - UpdateLibraryMangaPayload( - input.clientMutationId, - updateStatus = - withTimeout(30.seconds) { - UpdateStatus(updater.status.first()) - }, - ) - } + UpdateLibraryMangaPayload( + input.clientMutationId, + updateStatus = + withTimeout(30.seconds) { + UpdateStatus(updater.status.first()) + }, + ) } } @@ -92,7 +89,7 @@ class UpdateMutation { ) @RequireAuth - fun updateCategoryManga(input: UpdateCategoryMangaInput): CompletableFuture> { + fun updateCategoryManga(input: UpdateCategoryMangaInput): CompletableFuture { updateLibrary( UpdateLibraryInput( clientMutationId = input.clientMutationId, @@ -101,15 +98,13 @@ class UpdateMutation { ) return future { - asDataFetcherResult { - UpdateCategoryMangaPayload( - input.clientMutationId, - updateStatus = - withTimeout(30.seconds) { - UpdateStatus(updater.status.first()) - }, - ) - } + UpdateCategoryMangaPayload( + input.clientMutationId, + updateStatus = + withTimeout(30.seconds) { + UpdateStatus(updater.status.first()) + }, + ) } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/UserMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/UserMutation.kt index af0f86dc..20f640c9 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/UserMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/UserMutation.kt @@ -1,3 +1,5 @@ +@file:Suppress("RedundantNullableReturnType", "unused") + package suwayomi.tachidesk.graphql.mutations import graphql.schema.DataFetchingEnvironment diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/JavalinGraphQLRequestParser.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/JavalinGraphQLRequestParser.kt index e8fefcb9..f07d9962 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/JavalinGraphQLRequestParser.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/JavalinGraphQLRequestParser.kt @@ -11,6 +11,7 @@ import com.expediagroup.graphql.server.execution.GraphQLRequestParser import com.expediagroup.graphql.server.types.GraphQLBatchRequest import com.expediagroup.graphql.server.types.GraphQLRequest import com.expediagroup.graphql.server.types.GraphQLServerRequest +import io.github.oshai.kotlinlogging.KotlinLogging import io.javalin.http.Context import io.javalin.http.UploadedFile import io.javalin.json.JavalinJackson @@ -19,11 +20,12 @@ import io.javalin.json.fromJsonString import java.io.IOException class JavalinGraphQLRequestParser : GraphQLRequestParser { - val jsonMapper = JavalinJackson() + private val logger = KotlinLogging.logger {} @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") override suspend fun parseRequest(context: Context): GraphQLServerRequest? { return try { + val jsonMapper = context.jsonMapper() val contentType = context.contentType() val formParam = if ( @@ -77,7 +79,8 @@ class JavalinGraphQLRequestParser : GraphQLRequestParser { ) } } - } catch (_: IOException) { + } catch (e: IOException) { + logger.error(e) { "Error when parsing request" } null } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLServer.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLServer.kt index fbfd6945..0b640b5e 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLServer.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLServer.kt @@ -10,7 +10,6 @@ package suwayomi.tachidesk.graphql.server import com.expediagroup.graphql.generator.execution.FlowSubscriptionExecutionStrategy import com.expediagroup.graphql.server.execution.GraphQLRequestHandler import com.expediagroup.graphql.server.execution.GraphQLServer -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import graphql.ExceptionWhileDataFetching import graphql.GraphQL import graphql.execution.AsyncExecutionStrategy @@ -27,6 +26,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import suwayomi.tachidesk.graphql.server.subscriptions.ApolloSubscriptionProtocolHandler import suwayomi.tachidesk.server.JavalinSetup.future +import tools.jackson.module.kotlin.jacksonObjectMapper class TachideskGraphQLServer( requestParser: JavalinGraphQLRequestParser, diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/Cursor.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/Cursor.kt index 413c23dd..7029663c 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/Cursor.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/Cursor.kt @@ -58,7 +58,7 @@ private class GraphqlCursorCoercing : Coercing { ), ) } - return Cursor(input.value) + return Cursor(input.value!!) } private fun valueToLiteralImpl(input: Any): StringValue = StringValue.newStringValue(input.toString()).build() diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/DurationAsString.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/DurationAsString.kt index 3469900a..633ed85b 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/DurationAsString.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/DurationAsString.kt @@ -71,7 +71,7 @@ private class GraphqlDurationAsStringCoercing : Coercing { ) } return try { - Duration.parse(input.value) + Duration.parse(input.value!!) } catch (e: IllegalArgumentException) { throw CoercingParseLiteralException( "Invalid duration format: ${input.value}. Expected ISO-8601 duration string (e.g., 'PT30M', 'P1D')", diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/LongAsString.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/LongAsString.kt index 651c4fb8..6563c08f 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/LongAsString.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/LongAsString.kt @@ -53,7 +53,7 @@ private class GraphqlLongAsStringCoercing : Coercing { ), ) } - return input.value.toLong() + return input.value!!.toLong() } private fun valueToLiteralImpl(input: Any): StringValue = StringValue.newStringValue(input.toString()).build() diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/subscriptions/ApolloSubscriptionProtocolHandler.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/subscriptions/ApolloSubscriptionProtocolHandler.kt index aea05df0..72ec0b7d 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/subscriptions/ApolloSubscriptionProtocolHandler.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/subscriptions/ApolloSubscriptionProtocolHandler.kt @@ -9,9 +9,6 @@ package suwayomi.tachidesk.graphql.server.subscriptions import com.expediagroup.graphql.server.execution.GraphQLRequestHandler import com.expediagroup.graphql.server.types.GraphQLRequest -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.module.kotlin.convertValue -import com.fasterxml.jackson.module.kotlin.readValue import io.github.oshai.kotlinlogging.KotlinLogging import io.javalin.http.Header import io.javalin.websocket.WsContext @@ -41,6 +38,9 @@ import suwayomi.tachidesk.server.JavalinSetup.Attribute import suwayomi.tachidesk.server.JavalinSetup.getAttributeOrSet import suwayomi.tachidesk.server.user.UserType import suwayomi.tachidesk.server.user.getUserFromToken +import tools.jackson.databind.ObjectMapper +import tools.jackson.module.kotlin.convertValue +import tools.jackson.module.kotlin.readValue /** * Implementation of the `graphql-transport-ws` protocol defined by Denis Badurina From 3064f51d256bc64eb37e71115375e162de482545 Mon Sep 17 00:00:00 2001 From: David Brochero <65723952+D-Brox@users.noreply.github.com> Date: Sun, 10 May 2026 20:01:51 -0300 Subject: [PATCH 02/13] fix: don't resuse invalidated `cf_clearance` cookie on `CloudFlareInterceptor` (#1916) * fix: let FlareSolverr handle it's own `cf_clearance` cookie also dedups cookies * linting * suggested changes * my bad * add to changelog --- CHANGELOG.md | 1 + .../network/interceptor/CloudflareInterceptor.kt | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54e24186..b1ffaddd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - . ### Fixed +- (CloudFlareInterceptor) Don't send the `cf_clearance` cookie back to Flaresolverr - (WebUI) Handle serving non-default webui with "bundled" - (WebUI) Wait until WebUI is ready to open in browser diff --git a/server/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt b/server/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt index cae62706..c19ee0f3 100644 --- a/server/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt +++ b/server/src/main/kotlin/eu/kanade/tachiyomi/network/interceptor/CloudflareInterceptor.kt @@ -103,7 +103,7 @@ class CloudflareInterceptor( companion object { private val ERROR_CODES = listOf(403, 503) private val SERVER_CHECK = arrayOf("cloudflare-nginx", "cloudflare") - private val COOKIE_NAMES = listOf("cf_clearance") + val COOKIE_NAMES = listOf("cf_clearance") private val CHROME_IMAGE_TEMPLATE_REGEX = Regex("""(.*?) \(\d+×\d+\)""") } } @@ -205,9 +205,12 @@ object CFClearance { session = serverConfig.flareSolverrSessionName.value, sessionTtlMinutes = serverConfig.flareSolverrSessionTtl.value, cookies = - network.cookieStore.get(originalRequest.url).map { - FlareSolverCookie(it.name, it.value) - }, + network.cookieStore + .get(originalRequest.url) + .filter { it.name !in CloudflareInterceptor.COOKIE_NAMES } + .map { cookie -> + FlareSolverCookie(cookie.name, cookie.value) + }, returnOnlyCookies = onlyCookies, maxTimeout = timeout.inWholeMilliseconds.toInt(), postData = From 5bdb945406d92c6ea067d1e7f313a3926bf95631 Mon Sep 17 00:00:00 2001 From: Akiaki0324 Date: Mon, 11 May 2026 07:02:11 +0800 Subject: [PATCH 03/13] fix: truncate filenames by bytes instead of characters to avoid File name too long (#1933) * fix: truncate filenames by bytes instead of characters to avoid IOException File name too long * add a CHANGELOG.md entry. --- .../nulldev/androidcompat/util/SafePath.kt | 39 +++++++++++++-- CHANGELOG.md | 1 + .../kotlin/suwayomi/tachidesk/SafePathTest.kt | 50 +++++++++++++++++++ 3 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 server/src/test/kotlin/suwayomi/tachidesk/SafePathTest.kt diff --git a/AndroidCompat/src/main/java/xyz/nulldev/androidcompat/util/SafePath.kt b/AndroidCompat/src/main/java/xyz/nulldev/androidcompat/util/SafePath.kt index 7d722b9e..691a4fbf 100644 --- a/AndroidCompat/src/main/java/xyz/nulldev/androidcompat/util/SafePath.kt +++ b/AndroidCompat/src/main/java/xyz/nulldev/androidcompat/util/SafePath.kt @@ -9,6 +9,9 @@ package xyz.nulldev.androidcompat.util // adopted from: https://github.com/tachiyomiorg/tachiyomi/blob/4cefbce7c34e724b409b6ba127f3c6c5c346ad8d/app/src/main/java/eu/kanade/tachiyomi/util/storage/DiskUtil.kt object SafePath { + private const val MAX_FILENAME_CHARS = 240 + private const val MAX_FILENAME_UTF8_BYTES = 240 + /** * Mutate the given filename to make it valid for a FAT filesystem, * replacing any invalid characters with "_". This method doesn't allow hidden files (starting @@ -27,11 +30,41 @@ object SafePath { sb.append('_') } } - // Even though vfat allows 255 UCS-2 chars, we might eventually write to - // ext4 through a FUSE layer, so use that limit minus 15 reserved characters. - return sb.toString().take(240) + + return truncateFilename(sb.toString()) } + private fun truncateFilename(filename: String): String { + // Keep a safety margin under common filesystem limits and satisfy both + // character count and UTF-8 byte-length constraints. + val output = StringBuilder(minOf(filename.length, MAX_FILENAME_CHARS)) + var usedBytes = 0 + var index = 0 + + while (index < filename.length && output.length < MAX_FILENAME_CHARS) { + val codePoint = Character.codePointAt(filename, index) + val codePointBytes = utf8ByteCount(codePoint) + + if (usedBytes + codePointBytes > MAX_FILENAME_UTF8_BYTES) { + break + } + + output.appendCodePoint(codePoint) + usedBytes += codePointBytes + index += Character.charCount(codePoint) + } + + return output.toString() + } + + private fun utf8ByteCount(codePoint: Int): Int = + when { + codePoint <= 0x7f -> 1 + codePoint <= 0x7ff -> 2 + codePoint <= 0xffff -> 3 + else -> 4 + } + /** * Returns true if the given character is a valid filename character, false otherwise. */ diff --git a/CHANGELOG.md b/CHANGELOG.md index b1ffaddd..659e9e2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - (CloudFlareInterceptor) Don't send the `cf_clearance` cookie back to Flaresolverr - (WebUI) Handle serving non-default webui with "bundled" - (WebUI) Wait until WebUI is ready to open in browser +- (Downloads) Truncate filenames by byte length to prevent "File name too long" IO errors ## [v2.2.2100] + [WebUI: v20260508.01] - 2026-05-08 diff --git a/server/src/test/kotlin/suwayomi/tachidesk/SafePathTest.kt b/server/src/test/kotlin/suwayomi/tachidesk/SafePathTest.kt new file mode 100644 index 00000000..a50807f5 --- /dev/null +++ b/server/src/test/kotlin/suwayomi/tachidesk/SafePathTest.kt @@ -0,0 +1,50 @@ +package suwayomi.tachidesk + +import xyz.nulldev.androidcompat.util.SafePath +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class SafePathTest { + @Test + fun invalidCharactersAreReplacedAndEdgesAreTrimmed() { + val input = " .a:b*c?df|g\\h/i. " + + val result = SafePath.buildValidFilename(input) + + assertEquals("a_b_c_d_e_f_g_h_i", result) + } + + @Test + fun emptyAfterTrimReturnsInvalidMarker() { + assertEquals("(invalid)", SafePath.buildValidFilename(" ... . ")) + } + + @Test + fun resultIsTruncatedTo240Characters() { + val input = "a".repeat(300) + + val result = SafePath.buildValidFilename(input) + + assertEquals(240, result.length) + assertEquals("a".repeat(240), result) + } + + @Test + fun mixed256CharactersCanExceed255Utf8Bytes() { + val mixed256 = + buildString { + repeat(128) { + append('a') + append('你') + } + } + + val result = SafePath.buildValidFilename(mixed256) + + assertEquals(120, result.length) + assertEquals(mixed256.take(120), result) + assertEquals(240, result.toByteArray(Charsets.UTF_8).size) + assertTrue(result.toByteArray(Charsets.UTF_8).size == 240) + } +} \ No newline at end of file From c117d380a39dffdc35dddfe7ec074b8388d9ed93 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 12:53:41 -0400 Subject: [PATCH 04/13] Update exposed to v1 (major) (#1868) * Update exposed to v1 * Update Exposed * Add Kotlinx.DateTime extensions * Update H2 * Review comments --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Syer10 --- .../webkit/KcefWebViewProvider.kt | 2 - gradle/libs.versions.toml | 8 +- .../SettingsBackupServerSettingsGenerator.kt | 1 - .../SettingsBackupSettingsHandlerGenerator.kt | 1 - .../SettingsGraphqlTypeGenerator.kt | 1 - .../suwayomi/tachidesk/server/ServerConfig.kt | 8 +- .../server/settings/SettingsRegistry.kt | 1 - .../tachiyomi/network/OkHttpExtensions.kt | 1 - .../tachiyomi/source/local/LocalSource.kt | 9 +- .../tachidesk/global/impl/GlobalMeta.kt | 27 +-- .../global/model/table/GlobalMetaTable.kt | 2 +- .../graphql/dataLoaders/CategoryDataLoader.kt | 8 +- .../graphql/dataLoaders/ChapterDataLoader.kt | 18 +- .../dataLoaders/ExtensionDataLoader.kt | 8 +- .../graphql/dataLoaders/MangaDataLoader.kt | 12 +- .../graphql/dataLoaders/MetaDataLoader.kt | 8 +- .../graphql/dataLoaders/SourceDataLoader.kt | 8 +- .../graphql/dataLoaders/TrackDataLoader.kt | 8 +- .../graphql/mutations/CategoryMutation.kt | 31 ++-- .../graphql/mutations/ChapterMutation.kt | 59 ++++--- .../graphql/mutations/DownloadMutation.kt | 7 +- .../graphql/mutations/ExtensionMutation.kt | 8 +- .../graphql/mutations/InfoMutation.kt | 1 - .../graphql/mutations/KoreaderSyncMutation.kt | 8 +- .../graphql/mutations/MangaMutation.kt | 22 +-- .../graphql/mutations/MetaMutation.kt | 19 +- .../graphql/mutations/SourceMutation.kt | 20 +-- .../graphql/mutations/TrackMutation.kt | 8 +- .../graphql/mutations/UpdateMutation.kt | 1 - .../graphql/mutations/UserMutation.kt | 1 - .../graphql/queries/CategoryQuery.kt | 14 +- .../tachidesk/graphql/queries/ChapterQuery.kt | 16 +- .../graphql/queries/ExtensionQuery.kt | 16 +- .../tachidesk/graphql/queries/MangaQuery.kt | 15 +- .../tachidesk/graphql/queries/MetaQuery.kt | 14 +- .../tachidesk/graphql/queries/SourceQuery.kt | 14 +- .../tachidesk/graphql/queries/TrackQuery.kt | 14 +- .../graphql/queries/filter/Filter.kt | 76 ++++---- .../server/JavalinGraphQLRequestParser.kt | 1 - .../graphql/server/TachideskGraphQLServer.kt | 1 - .../graphql/server/primitives/OrderBy.kt | 22 +-- .../graphql/server/primitives/QueryResults.kt | 2 +- .../tachidesk/graphql/types/CategoryType.kt | 2 +- .../tachidesk/graphql/types/ChapterType.kt | 2 +- .../tachidesk/graphql/types/ExtensionType.kt | 2 +- .../tachidesk/graphql/types/MangaType.kt | 2 +- .../tachidesk/graphql/types/MetaType.kt | 2 +- .../tachidesk/graphql/types/SourceType.kt | 5 +- .../tachidesk/graphql/types/TrackType.kt | 2 +- .../manga/controller/MangaController.kt | 5 +- .../suwayomi/tachidesk/manga/impl/Category.kt | 43 ++--- .../tachidesk/manga/impl/CategoryManga.kt | 29 +-- .../suwayomi/tachidesk/manga/impl/Chapter.kt | 72 ++++---- .../manga/impl/ChapterDownloadHelper.kt | 4 +- .../suwayomi/tachidesk/manga/impl/Library.kt | 13 +- .../suwayomi/tachidesk/manga/impl/Manga.kt | 36 ++-- .../tachidesk/manga/impl/MangaList.kt | 56 +++--- .../suwayomi/tachidesk/manga/impl/Page.kt | 11 +- .../suwayomi/tachidesk/manga/impl/Source.kt | 31 ++-- .../impl/backup/proto/ProtoBackupExport.kt | 2 +- .../impl/backup/proto/ProtoBackupValidator.kt | 5 +- .../proto/handlers/BackupCategoryHandler.kt | 4 +- .../proto/handlers/BackupMangaHandler.kt | 55 +++--- .../proto/handlers/BackupSourceHandler.kt | 3 +- .../manga/impl/chapter/ChapterForDownload.kt | 16 +- .../manga/impl/download/DownloadManager.kt | 11 +- .../manga/impl/download/Downloader.kt | 5 +- .../fileProvider/ChaptersFilesProvider.kt | 14 +- .../fileProvider/impl/ArchiveProvider.kt | 5 +- .../fileProvider/impl/FolderProvider.kt | 5 +- .../manga/impl/extension/Extension.kt | 13 +- .../manga/impl/extension/ExtensionsList.kt | 105 +++++------ .../manga/impl/sync/KoreaderSyncService.kt | 6 +- .../tachidesk/manga/impl/track/Track.kt | 56 +++--- .../track/tracker/model/TrackConvertor.kt | 4 +- .../tachidesk/manga/impl/util/DirName.kt | 6 +- .../tachidesk/manga/impl/util/GetComicInfo.kt | 9 +- .../manga/impl/util/lang/ExposedExtensions.kt | 2 +- .../impl/util/source/GetCatalogueSource.kt | 5 +- .../manga/model/table/CategoryMangaTable.kt | 4 +- .../manga/model/table/CategoryMetaTable.kt | 4 +- .../manga/model/table/CategoryTable.kt | 4 +- .../manga/model/table/ChapterMetaTable.kt | 4 +- .../manga/model/table/ChapterTable.kt | 11 +- .../manga/model/table/ExtensionTable.kt | 2 +- .../manga/model/table/MangaMetaTable.kt | 4 +- .../tachidesk/manga/model/table/MangaTable.kt | 4 +- .../tachidesk/manga/model/table/PageTable.kt | 4 +- .../manga/model/table/SourceMetaTable.kt | 4 +- .../manga/model/table/SourceTable.kt | 2 +- .../manga/model/table/TrackRecordTable.kt | 4 +- .../manga/model/table/TrackSearchTable.kt | 67 +++---- .../table/columns/TruncatingVarCharColumn.kt | 6 +- .../tachidesk/opds/impl/OpdsFeedBuilder.kt | 2 +- .../opds/repository/ChapterRepository.kt | 20 ++- .../opds/repository/MangaRepository.kt | 37 ++-- .../opds/repository/NavigationRepository.kt | 14 +- .../suwayomi/tachidesk/server/JavalinSetup.kt | 1 - .../suwayomi/tachidesk/server/Migration.kt | 14 +- .../suwayomi/tachidesk/server/ServerSetup.kt | 4 +- .../tachidesk/server/database/DBManager.kt | 16 +- .../server/database/DBTransaction.util.kt | 9 +- .../tachidesk/server/database/H2Migration.kt | 167 ++++++++++++++++++ .../database/migration/M0001_Initial.kt | 6 +- .../migration/M0004_AnimeTablesBatch1.kt | 6 +- .../migration/M0005_AnimeTablesBatch2.kt | 4 +- .../migration/M0006_AnimeTablesBatch3.kt | 4 +- .../migration/M0010_MangaAndChapterMeta.kt | 6 +- .../migration/M0021_GlobalAndCategoryMeta.kt | 6 +- .../migration/M0023_CategoryMetaRefFix.kt | 2 +- .../database/migration/M0033_TrackRecord.kt | 6 +- .../database/migration/M0035_TrackSearch.kt | 4 +- .../database/migration/M0036_SourceMeta.kt | 4 +- .../migration/M0053_TrackersFixIds.kt | 2 - .../migration/helpers/RenameFieldMigration.kt | 2 +- .../suwayomi/tachidesk/util/ConversionUtil.kt | 2 - .../kotlin/suwayomi/tachidesk/SafePathTest.kt | 2 +- .../manga/controller/UpdateControllerTest.kt | 4 +- .../manga/impl/update/TestUpdater.kt | 1 - .../tachidesk/test/ApplicationTest.kt | 2 +- .../suwayomi/tachidesk/test/TestUtils.kt | 10 +- 121 files changed, 944 insertions(+), 706 deletions(-) create mode 100644 server/src/main/kotlin/suwayomi/tachidesk/server/database/H2Migration.kt diff --git a/AndroidCompat/src/main/java/xyz/nulldev/androidcompat/webkit/KcefWebViewProvider.kt b/AndroidCompat/src/main/java/xyz/nulldev/androidcompat/webkit/KcefWebViewProvider.kt index bd3c9a76..4d0c8dcb 100644 --- a/AndroidCompat/src/main/java/xyz/nulldev/androidcompat/webkit/KcefWebViewProvider.kt +++ b/AndroidCompat/src/main/java/xyz/nulldev/androidcompat/webkit/KcefWebViewProvider.kt @@ -55,7 +55,6 @@ import dev.datlag.kcef.KCEF import dev.datlag.kcef.KCEFBrowser import dev.datlag.kcef.KCEFClient import kotlinx.serialization.Serializable -import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import org.cef.CefSettings import org.cef.browser.CefBrowser @@ -88,7 +87,6 @@ import java.io.BufferedWriter import java.io.File import java.io.IOException import java.util.concurrent.Executor -import kotlin.collections.Map import kotlin.reflect.KClass import kotlin.reflect.KFunction import kotlin.reflect.full.declaredMemberFunctions diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 01244fb8..9ba2c0fc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ okhttp = "5.3.2" # Major version is locked by Tachiyomi extensions javalin = "7.2.0" jte = "3.2.4" jackson = "3.1.3" # jackson version locked by javalin, ref: `io.javalin.core.util.OptionalDependency` -exposed = "0.61.0" +exposed = "1.2.0" dex2jar = "2.4.36" polyglot = "25.0.3" settings = "1.3.0" @@ -68,12 +68,13 @@ exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "e exposed-dao = { module = "org.jetbrains.exposed:exposed-dao", version.ref = "exposed" } exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "exposed" } exposed-javatime = { module = "org.jetbrains.exposed:exposed-java-time", version.ref = "exposed" } +exposed-kotlintime = { module = "org.jetbrains.exposed:exposed-kotlin-datetime", version.ref = "exposed" } postgres = "org.postgresql:postgresql:42.7.11" -h2 = "com.h2database:h2:1.4.200" # current database driver, can't update to h2 v2 without sql migration +h2 = "com.h2database:h2:2.4.240" hikaricp = "com.zaxxer:HikariCP:7.0.2" # Exposed Migrations -exposed-migrations = "com.github.Suwayomi:exposed-migrations:3.8.0" +exposed-migrations = "com.github.Suwayomi:exposed-migrations:3.10.1" # Dependency Injection koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" } @@ -242,6 +243,7 @@ exposed = [ "exposed-dao", "exposed-jdbc", "exposed-javatime", + "exposed-kotlintime", ] systemtray = [ "systemtray-core", diff --git a/server/server-config-generate/src/main/kotlin/suwayomi/tachidesk/server/settings/generation/SettingsBackupServerSettingsGenerator.kt b/server/server-config-generate/src/main/kotlin/suwayomi/tachidesk/server/settings/generation/SettingsBackupServerSettingsGenerator.kt index 21c432be..00cec785 100644 --- a/server/server-config-generate/src/main/kotlin/suwayomi/tachidesk/server/settings/generation/SettingsBackupServerSettingsGenerator.kt +++ b/server/server-config-generate/src/main/kotlin/suwayomi/tachidesk/server/settings/generation/SettingsBackupServerSettingsGenerator.kt @@ -2,7 +2,6 @@ package suwayomi.tachidesk.server.settings.generation import suwayomi.tachidesk.server.settings.SettingsRegistry import java.io.File -import kotlin.text.appendLine object SettingsBackupServerSettingsGenerator { fun generate( diff --git a/server/server-config-generate/src/main/kotlin/suwayomi/tachidesk/server/settings/generation/SettingsBackupSettingsHandlerGenerator.kt b/server/server-config-generate/src/main/kotlin/suwayomi/tachidesk/server/settings/generation/SettingsBackupSettingsHandlerGenerator.kt index ab942acf..e74e3aeb 100644 --- a/server/server-config-generate/src/main/kotlin/suwayomi/tachidesk/server/settings/generation/SettingsBackupSettingsHandlerGenerator.kt +++ b/server/server-config-generate/src/main/kotlin/suwayomi/tachidesk/server/settings/generation/SettingsBackupSettingsHandlerGenerator.kt @@ -2,7 +2,6 @@ package suwayomi.tachidesk.server.settings.generation import suwayomi.tachidesk.server.settings.SettingsRegistry import java.io.File -import kotlin.text.appendLine object SettingsBackupSettingsHandlerGenerator { fun generate( diff --git a/server/server-config-generate/src/main/kotlin/suwayomi/tachidesk/server/settings/generation/SettingsGraphqlTypeGenerator.kt b/server/server-config-generate/src/main/kotlin/suwayomi/tachidesk/server/settings/generation/SettingsGraphqlTypeGenerator.kt index 56501c53..051f0c5d 100644 --- a/server/server-config-generate/src/main/kotlin/suwayomi/tachidesk/server/settings/generation/SettingsGraphqlTypeGenerator.kt +++ b/server/server-config-generate/src/main/kotlin/suwayomi/tachidesk/server/settings/generation/SettingsGraphqlTypeGenerator.kt @@ -2,7 +2,6 @@ package suwayomi.tachidesk.server.settings.generation import suwayomi.tachidesk.server.settings.SettingsRegistry import java.io.File -import kotlin.text.appendLine object SettingsGraphqlTypeGenerator { fun generate( diff --git a/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/ServerConfig.kt b/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/ServerConfig.kt index 6f94b4c5..3b23f0b3 100644 --- a/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/ServerConfig.kt +++ b/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/ServerConfig.kt @@ -25,7 +25,7 @@ import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.onEach -import org.jetbrains.exposed.sql.SortOrder +import org.jetbrains.exposed.v1.core.SortOrder import suwayomi.tachidesk.graphql.types.AuthMode import suwayomi.tachidesk.graphql.types.CbzMediaType import suwayomi.tachidesk.graphql.types.DatabaseType @@ -56,16 +56,14 @@ import suwayomi.tachidesk.server.settings.PathSetting import suwayomi.tachidesk.server.settings.SettingGroup import suwayomi.tachidesk.server.settings.SettingsRegistry import suwayomi.tachidesk.server.settings.StringSetting +import uy.kohesive.injekt.injectLazy import xyz.nulldev.ts.config.GlobalConfigManager import xyz.nulldev.ts.config.SystemPropertyOverridableConfigModule -import kotlin.collections.associate -import kotlin.getValue import kotlin.time.Duration import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.hours import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds -import uy.kohesive.injekt.injectLazy val mutableConfigValueScope = CoroutineScope(SupervisorJob() + Dispatchers.Default) @@ -582,7 +580,7 @@ class ServerConfig( privacySafe = true, defaultValue = SortOrder.DESC, enumClass = SortOrder::class, - typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("org.jetbrains.exposed.sql.SortOrder")), + typeInfo = SettingsRegistry.PartialTypeInfo(imports = listOf("org.jetbrains.exposed.v1.core.SortOrder")), ) val authMode: MutableStateFlow by EnumSetting( diff --git a/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/settings/SettingsRegistry.kt b/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/settings/SettingsRegistry.kt index 8a439e61..3347a847 100644 --- a/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/settings/SettingsRegistry.kt +++ b/server/server-config/src/main/kotlin/suwayomi/tachidesk/server/settings/SettingsRegistry.kt @@ -2,7 +2,6 @@ package suwayomi.tachidesk.server.settings import com.typesafe.config.ConfigValue import com.typesafe.config.parser.ConfigDocument -import kotlin.collections.find import kotlin.reflect.KClass /** diff --git a/server/src/main/kotlin/eu/kanade/tachiyomi/network/OkHttpExtensions.kt b/server/src/main/kotlin/eu/kanade/tachiyomi/network/OkHttpExtensions.kt index 3cf2ecad..8e6e3f70 100644 --- a/server/src/main/kotlin/eu/kanade/tachiyomi/network/OkHttpExtensions.kt +++ b/server/src/main/kotlin/eu/kanade/tachiyomi/network/OkHttpExtensions.kt @@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.network import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.serialization.DeserializationStrategy -import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json import kotlinx.serialization.json.okio.decodeFromBufferedSource import kotlinx.serialization.serializer diff --git a/server/src/main/kotlin/eu/kanade/tachiyomi/source/local/LocalSource.kt b/server/src/main/kotlin/eu/kanade/tachiyomi/source/local/LocalSource.kt index a6a6cb78..41035e2c 100644 --- a/server/src/main/kotlin/eu/kanade/tachiyomi/source/local/LocalSource.kt +++ b/server/src/main/kotlin/eu/kanade/tachiyomi/source/local/LocalSource.kt @@ -36,10 +36,11 @@ import nl.adaptivity.xmlutil.ExperimentalXmlUtilApi import nl.adaptivity.xmlutil.core.KtXmlReader import nl.adaptivity.xmlutil.serialization.XML import org.apache.commons.compress.archivers.zip.ZipFile -import org.jetbrains.exposed.sql.insert -import org.jetbrains.exposed.sql.insertAndGetId -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.insert +import org.jetbrains.exposed.v1.jdbc.insertAndGetId +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.registerCatalogueSource import suwayomi.tachidesk.manga.impl.util.storage.ImageUtil import suwayomi.tachidesk.manga.model.table.ExtensionTable diff --git a/server/src/main/kotlin/suwayomi/tachidesk/global/impl/GlobalMeta.kt b/server/src/main/kotlin/suwayomi/tachidesk/global/impl/GlobalMeta.kt index 8d51d055..0c9e6040 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/global/impl/GlobalMeta.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/global/impl/GlobalMeta.kt @@ -1,10 +1,12 @@ package suwayomi.tachidesk.global.impl -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.batchInsert -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.statements.BatchUpdateStatement -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.statements.BatchUpdateStatement +import org.jetbrains.exposed.v1.jdbc.batchInsert +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.statements.toExecutable +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.global.model.table.GlobalMetaTable /* @@ -32,13 +34,14 @@ object GlobalMeta { val (existingMeta, newMeta) = meta.toList().partition { (key) -> key in dbMetaMap.keys } if (existingMeta.isNotEmpty()) { - BatchUpdateStatement(GlobalMetaTable).apply { - existingMeta.forEach { (key, value) -> - addBatch(EntityID(dbMetaMap[key]!![GlobalMetaTable.id].value, GlobalMetaTable)) - this[GlobalMetaTable.value] = value - } - execute(this@transaction) - } + BatchUpdateStatement(GlobalMetaTable) + .apply { + existingMeta.forEach { (key, value) -> + addBatch(EntityID(dbMetaMap[key]!![GlobalMetaTable.id].value, GlobalMetaTable)) + this[GlobalMetaTable.value] = value + } + }.toExecutable() + .execute(this@transaction) } if (newMeta.isNotEmpty()) { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/global/model/table/GlobalMetaTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/global/model/table/GlobalMetaTable.kt index 4872f5c1..ee99bf5d 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/global/model/table/GlobalMetaTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/global/model/table/GlobalMetaTable.kt @@ -7,7 +7,7 @@ package suwayomi.tachidesk.global.model.table * 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 org.jetbrains.exposed.dao.id.IntIdTable +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable /** * Metadata storage for clients, server/global level. diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/CategoryDataLoader.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/CategoryDataLoader.kt index 12c83b62..1767706e 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/CategoryDataLoader.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/CategoryDataLoader.kt @@ -11,10 +11,10 @@ import com.expediagroup.graphql.dataloader.KotlinDataLoader import graphql.GraphQLContext import org.dataloader.DataLoader import org.dataloader.DataLoaderFactory -import org.jetbrains.exposed.sql.Slf4jSqlDebugLogger -import org.jetbrains.exposed.sql.addLogger -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.Slf4jSqlDebugLogger +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.graphql.types.CategoryNodeList import suwayomi.tachidesk.graphql.types.CategoryNodeList.Companion.toNodeList import suwayomi.tachidesk.graphql.types.CategoryType diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/ChapterDataLoader.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/ChapterDataLoader.kt index 44ef6de3..63b6079f 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/ChapterDataLoader.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/ChapterDataLoader.kt @@ -11,13 +11,17 @@ import com.expediagroup.graphql.dataloader.KotlinDataLoader import graphql.GraphQLContext import org.dataloader.DataLoader import org.dataloader.DataLoaderFactory -import org.jetbrains.exposed.sql.Slf4jSqlDebugLogger -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.addLogger -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.count -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.Slf4jSqlDebugLogger +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.count +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.greater +import org.jetbrains.exposed.v1.core.greaterEq +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.jdbc.select +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.graphql.types.ChapterNodeList import suwayomi.tachidesk.graphql.types.ChapterNodeList.Companion.toNodeList import suwayomi.tachidesk.graphql.types.ChapterType diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/ExtensionDataLoader.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/ExtensionDataLoader.kt index c3b4b695..7701e4e5 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/ExtensionDataLoader.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/ExtensionDataLoader.kt @@ -11,10 +11,10 @@ import com.expediagroup.graphql.dataloader.KotlinDataLoader import graphql.GraphQLContext import org.dataloader.DataLoader import org.dataloader.DataLoaderFactory -import org.jetbrains.exposed.sql.Slf4jSqlDebugLogger -import org.jetbrains.exposed.sql.addLogger -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.Slf4jSqlDebugLogger +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.graphql.types.ExtensionType import suwayomi.tachidesk.manga.model.table.ExtensionTable import suwayomi.tachidesk.manga.model.table.SourceTable diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/MangaDataLoader.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/MangaDataLoader.kt index a49b3260..08243657 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/MangaDataLoader.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/MangaDataLoader.kt @@ -12,11 +12,13 @@ import graphql.GraphQLContext import org.dataloader.DataLoader import org.dataloader.DataLoaderFactory import org.dataloader.DataLoaderOptions -import org.jetbrains.exposed.sql.Slf4jSqlDebugLogger -import org.jetbrains.exposed.sql.addLogger -import org.jetbrains.exposed.sql.andWhere -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.Slf4jSqlDebugLogger +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.isNull +import org.jetbrains.exposed.v1.jdbc.andWhere +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.graphql.cache.CustomCacheMap import suwayomi.tachidesk.graphql.types.MangaNodeList import suwayomi.tachidesk.graphql.types.MangaNodeList.Companion.toNodeList diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/MetaDataLoader.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/MetaDataLoader.kt index d2515bca..009de4be 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/MetaDataLoader.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/MetaDataLoader.kt @@ -4,10 +4,10 @@ import com.expediagroup.graphql.dataloader.KotlinDataLoader import graphql.GraphQLContext import org.dataloader.DataLoader import org.dataloader.DataLoaderFactory -import org.jetbrains.exposed.sql.Slf4jSqlDebugLogger -import org.jetbrains.exposed.sql.addLogger -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.Slf4jSqlDebugLogger +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.global.model.table.GlobalMetaTable import suwayomi.tachidesk.graphql.types.CategoryMetaType import suwayomi.tachidesk.graphql.types.ChapterMetaType diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/SourceDataLoader.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/SourceDataLoader.kt index 3fc2269c..6b9dd05a 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/SourceDataLoader.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/SourceDataLoader.kt @@ -11,10 +11,10 @@ import com.expediagroup.graphql.dataloader.KotlinDataLoader import graphql.GraphQLContext import org.dataloader.DataLoader import org.dataloader.DataLoaderFactory -import org.jetbrains.exposed.sql.Slf4jSqlDebugLogger -import org.jetbrains.exposed.sql.addLogger -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.Slf4jSqlDebugLogger +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.graphql.types.SourceNodeList import suwayomi.tachidesk.graphql.types.SourceNodeList.Companion.toNodeList import suwayomi.tachidesk.graphql.types.SourceType diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/TrackDataLoader.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/TrackDataLoader.kt index cfe9ebab..02f7653c 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/TrackDataLoader.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/dataLoaders/TrackDataLoader.kt @@ -11,10 +11,10 @@ import com.expediagroup.graphql.dataloader.KotlinDataLoader import graphql.GraphQLContext import org.dataloader.DataLoader import org.dataloader.DataLoaderFactory -import org.jetbrains.exposed.sql.Slf4jSqlDebugLogger -import org.jetbrains.exposed.sql.addLogger -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.Slf4jSqlDebugLogger +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.graphql.types.TrackRecordNodeList import suwayomi.tachidesk.graphql.types.TrackRecordNodeList.Companion.toNodeList import suwayomi.tachidesk.graphql.types.TrackRecordType diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/CategoryMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/CategoryMutation.kt index dd988fd1..18350fd8 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/CategoryMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/CategoryMutation.kt @@ -2,21 +2,22 @@ package suwayomi.tachidesk.graphql.mutations -import graphql.execution.DataFetcherResult -import org.jetbrains.exposed.sql.LikePattern -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList -import org.jetbrains.exposed.sql.SqlExpressionBuilder.like -import org.jetbrains.exposed.sql.SqlExpressionBuilder.minus -import org.jetbrains.exposed.sql.SqlExpressionBuilder.plus -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.insertAndGetId -import org.jetbrains.exposed.sql.or -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.LikePattern +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.greaterEq +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.lessEq +import org.jetbrains.exposed.v1.core.like +import org.jetbrains.exposed.v1.core.minus +import org.jetbrains.exposed.v1.core.or +import org.jetbrains.exposed.v1.core.plus +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.insertAndGetId +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.CategoryMetaType import suwayomi.tachidesk.graphql.types.CategoryType diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ChapterMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ChapterMutation.kt index a3ac94af..0c91186e 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ChapterMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ChapterMutation.kt @@ -4,19 +4,21 @@ package suwayomi.tachidesk.graphql.mutations import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.LikePattern -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList -import org.jetbrains.exposed.sql.SqlExpressionBuilder.like -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.or -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.statements.BatchUpdateStatement -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.LikePattern +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.like +import org.jetbrains.exposed.v1.core.or +import org.jetbrains.exposed.v1.core.statements.BatchUpdateStatement +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.select +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.statements.toExecutable +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.ChapterMetaType import suwayomi.tachidesk.graphql.types.ChapterType @@ -90,22 +92,23 @@ class ChapterMutation { if (patch.isRead != null || patch.isBookmarked != null || patch.lastPageRead != null) { val now = Instant.now().epochSecond - BatchUpdateStatement(ChapterTable).apply { - ids.forEach { chapterId -> - addBatch(EntityID(chapterId, ChapterTable)) - patch.isRead?.also { - this[ChapterTable.isRead] = it + BatchUpdateStatement(ChapterTable) + .apply { + ids.forEach { chapterId -> + addBatch(EntityID(chapterId, ChapterTable)) + patch.isRead?.also { + this[ChapterTable.isRead] = it + } + patch.isBookmarked?.also { + this[ChapterTable.isBookmarked] = it + } + patch.lastPageRead?.also { + this[ChapterTable.lastPageRead] = it.coerceAtMost(chapterIdToPageCount[chapterId] ?: 0).coerceAtLeast(0) + this[ChapterTable.lastReadAt] = now + } } - patch.isBookmarked?.also { - this[ChapterTable.isBookmarked] = it - } - patch.lastPageRead?.also { - this[ChapterTable.lastPageRead] = it.coerceAtMost(chapterIdToPageCount[chapterId] ?: 0).coerceAtLeast(0) - this[ChapterTable.lastReadAt] = now - } - } - execute(this@transaction) - } + }.toExecutable() + .execute(this@transaction) } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/DownloadMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/DownloadMutation.kt index 7bb0fea5..b5bd24d8 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/DownloadMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/DownloadMutation.kt @@ -2,11 +2,12 @@ package suwayomi.tachidesk.graphql.mutations -import graphql.execution.DataFetcherResult import kotlinx.coroutines.flow.first import kotlinx.coroutines.withTimeout -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.ChapterType import suwayomi.tachidesk.graphql.types.DownloadStatus diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ExtensionMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ExtensionMutation.kt index 78965755..663f32c5 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ExtensionMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/ExtensionMutation.kt @@ -3,10 +3,12 @@ package suwayomi.tachidesk.graphql.mutations import eu.kanade.tachiyomi.source.local.LocalSource -import graphql.execution.DataFetcherResult import io.javalin.http.UploadedFile -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.neq +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.ExtensionType import suwayomi.tachidesk.manga.impl.extension.Extension diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/InfoMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/InfoMutation.kt index 3735024f..2d2f2553 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/InfoMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/InfoMutation.kt @@ -2,7 +2,6 @@ package suwayomi.tachidesk.graphql.mutations -import graphql.execution.DataFetcherResult import kotlinx.coroutines.flow.first import kotlinx.coroutines.withTimeout import suwayomi.tachidesk.graphql.directives.RequireAuth diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/KoreaderSyncMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/KoreaderSyncMutation.kt index d509a688..ff605fa1 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/KoreaderSyncMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/KoreaderSyncMutation.kt @@ -2,10 +2,10 @@ package suwayomi.tachidesk.graphql.mutations -import graphql.execution.DataFetcherResult -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.ChapterType import suwayomi.tachidesk.graphql.types.KoSyncConnectPayload diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/MangaMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/MangaMutation.kt index 20df97bf..975f5567 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/MangaMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/MangaMutation.kt @@ -2,17 +2,17 @@ package suwayomi.tachidesk.graphql.mutations -import org.jetbrains.exposed.sql.LikePattern -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList -import org.jetbrains.exposed.sql.SqlExpressionBuilder.like -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.or -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.LikePattern +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.like +import org.jetbrains.exposed.v1.core.or +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.MangaMetaType import suwayomi.tachidesk.graphql.types.MangaType diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/MetaMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/MetaMutation.kt index cb14d2e7..3d363f7a 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/MetaMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/MetaMutation.kt @@ -2,16 +2,15 @@ package suwayomi.tachidesk.graphql.mutations -import graphql.execution.DataFetcherResult -import org.jetbrains.exposed.sql.LikePattern -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList -import org.jetbrains.exposed.sql.SqlExpressionBuilder.like -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.or -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.LikePattern +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.like +import org.jetbrains.exposed.v1.core.or +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.global.impl.GlobalMeta import suwayomi.tachidesk.global.model.table.GlobalMetaTable import suwayomi.tachidesk.graphql.directives.RequireAuth diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/SourceMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/SourceMutation.kt index 62b83906..54bbfcb3 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/SourceMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/SourceMutation.kt @@ -7,16 +7,16 @@ import androidx.preference.EditTextPreference import androidx.preference.ListPreference import androidx.preference.MultiSelectListPreference import androidx.preference.SwitchPreferenceCompat -import org.jetbrains.exposed.sql.LikePattern -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList -import org.jetbrains.exposed.sql.SqlExpressionBuilder.like -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.or -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.LikePattern +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.like +import org.jetbrains.exposed.v1.core.or +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.FilterChange import suwayomi.tachidesk.graphql.types.MangaType diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/TrackMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/TrackMutation.kt index 41e06dde..b1bf2e7b 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/TrackMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/TrackMutation.kt @@ -4,10 +4,10 @@ package suwayomi.tachidesk.graphql.mutations import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated import com.expediagroup.graphql.generator.annotations.GraphQLDescription -import graphql.execution.DataFetcherResult -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.types.TrackRecordType import suwayomi.tachidesk.graphql.types.TrackerType diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/UpdateMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/UpdateMutation.kt index 4f668362..614f9bbb 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/UpdateMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/UpdateMutation.kt @@ -2,7 +2,6 @@ package suwayomi.tachidesk.graphql.mutations -import graphql.execution.DataFetcherResult import kotlinx.coroutines.flow.first import kotlinx.coroutines.withTimeout import suwayomi.tachidesk.graphql.directives.RequireAuth diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/UserMutation.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/UserMutation.kt index 20f640c9..46c2e1eb 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/UserMutation.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/mutations/UserMutation.kt @@ -4,7 +4,6 @@ package suwayomi.tachidesk.graphql.mutations import graphql.schema.DataFetchingEnvironment import suwayomi.tachidesk.global.impl.util.Jwt -import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.server.getAttribute import suwayomi.tachidesk.server.JavalinSetup.Attribute import suwayomi.tachidesk.server.serverConfig diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/CategoryQuery.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/CategoryQuery.kt index 8aae3926..d936e2d6 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/CategoryQuery.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/CategoryQuery.kt @@ -10,13 +10,13 @@ package suwayomi.tachidesk.graphql.queries import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated import com.expediagroup.graphql.server.extensions.getValueFromDataLoader import graphql.schema.DataFetchingEnvironment -import org.jetbrains.exposed.sql.Column -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater -import org.jetbrains.exposed.sql.SqlExpressionBuilder.less -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.Column +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.greater +import org.jetbrains.exposed.v1.core.less +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter import suwayomi.tachidesk.graphql.queries.filter.Filter diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/ChapterQuery.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/ChapterQuery.kt index 9965fabd..3c40dc76 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/ChapterQuery.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/ChapterQuery.kt @@ -10,14 +10,14 @@ package suwayomi.tachidesk.graphql.queries import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated import com.expediagroup.graphql.server.extensions.getValueFromDataLoader import graphql.schema.DataFetchingEnvironment -import org.jetbrains.exposed.sql.Column -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater -import org.jetbrains.exposed.sql.SqlExpressionBuilder.less -import org.jetbrains.exposed.sql.andWhere -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.Column +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.greater +import org.jetbrains.exposed.v1.core.less +import org.jetbrains.exposed.v1.jdbc.andWhere +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter import suwayomi.tachidesk.graphql.queries.filter.DoubleFilter diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/ExtensionQuery.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/ExtensionQuery.kt index 50a5be2f..c2b1a8da 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/ExtensionQuery.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/ExtensionQuery.kt @@ -11,14 +11,14 @@ import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated import com.expediagroup.graphql.server.extensions.getValueFromDataLoader import eu.kanade.tachiyomi.source.local.LocalSource import graphql.schema.DataFetchingEnvironment -import org.jetbrains.exposed.sql.Column -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater -import org.jetbrains.exposed.sql.SqlExpressionBuilder.less -import org.jetbrains.exposed.sql.SqlExpressionBuilder.neq -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.Column +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.greater +import org.jetbrains.exposed.v1.core.less +import org.jetbrains.exposed.v1.core.neq +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter import suwayomi.tachidesk.graphql.queries.filter.Filter diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/MangaQuery.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/MangaQuery.kt index 44b9d2e5..fdbd790b 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/MangaQuery.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/MangaQuery.kt @@ -10,12 +10,15 @@ package suwayomi.tachidesk.graphql.queries import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated import com.expediagroup.graphql.server.extensions.getValueFromDataLoader import graphql.schema.DataFetchingEnvironment -import org.jetbrains.exposed.sql.Column -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater -import org.jetbrains.exposed.sql.SqlExpressionBuilder.less -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.Column +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.greater +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.less +import org.jetbrains.exposed.v1.core.like +import org.jetbrains.exposed.v1.jdbc.select +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter import suwayomi.tachidesk.graphql.queries.filter.ComparableScalarFilter diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/MetaQuery.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/MetaQuery.kt index e853891a..95edb246 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/MetaQuery.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/MetaQuery.kt @@ -10,13 +10,13 @@ package suwayomi.tachidesk.graphql.queries import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated import com.expediagroup.graphql.server.extensions.getValueFromDataLoader import graphql.schema.DataFetchingEnvironment -import org.jetbrains.exposed.sql.Column -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater -import org.jetbrains.exposed.sql.SqlExpressionBuilder.less -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.Column +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.greater +import org.jetbrains.exposed.v1.core.less +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.global.model.table.GlobalMetaTable import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.queries.filter.Filter diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/SourceQuery.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/SourceQuery.kt index 2aab3d29..216ee41b 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/SourceQuery.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/SourceQuery.kt @@ -10,13 +10,13 @@ package suwayomi.tachidesk.graphql.queries import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated import com.expediagroup.graphql.server.extensions.getValueFromDataLoader import graphql.schema.DataFetchingEnvironment -import org.jetbrains.exposed.sql.Column -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater -import org.jetbrains.exposed.sql.SqlExpressionBuilder.less -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.Column +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.greater +import org.jetbrains.exposed.v1.core.less +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter import suwayomi.tachidesk.graphql.queries.filter.Filter diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/TrackQuery.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/TrackQuery.kt index 296eb72b..5eed6321 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/TrackQuery.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/TrackQuery.kt @@ -3,13 +3,13 @@ package suwayomi.tachidesk.graphql.queries import com.expediagroup.graphql.generator.annotations.GraphQLDeprecated import com.expediagroup.graphql.server.extensions.getValueFromDataLoader import graphql.schema.DataFetchingEnvironment -import org.jetbrains.exposed.sql.Column -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater -import org.jetbrains.exposed.sql.SqlExpressionBuilder.less -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.Column +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.greater +import org.jetbrains.exposed.v1.core.less +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.graphql.directives.RequireAuth import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter import suwayomi.tachidesk.graphql.queries.filter.DoubleFilter diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/filter/Filter.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/filter/Filter.kt index a06cf445..f1086ca4 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/filter/Filter.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/queries/filter/Filter.kt @@ -1,21 +1,33 @@ package suwayomi.tachidesk.graphql.queries.filter -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.Column -import org.jetbrains.exposed.sql.ComparisonOp -import org.jetbrains.exposed.sql.Expression -import org.jetbrains.exposed.sql.ExpressionWithColumnType -import org.jetbrains.exposed.sql.LikePattern -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.Query -import org.jetbrains.exposed.sql.QueryBuilder -import org.jetbrains.exposed.sql.SqlExpressionBuilder -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.andWhere -import org.jetbrains.exposed.sql.not -import org.jetbrains.exposed.sql.or -import org.jetbrains.exposed.sql.stringParam -import org.jetbrains.exposed.sql.upperCase +import org.jetbrains.exposed.v1.core.Column +import org.jetbrains.exposed.v1.core.ComparisonOp +import org.jetbrains.exposed.v1.core.Expression +import org.jetbrains.exposed.v1.core.ExpressionWithColumnType +import org.jetbrains.exposed.v1.core.LikePattern +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.QueryBuilder +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.greater +import org.jetbrains.exposed.v1.core.greaterEq +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.isNotNull +import org.jetbrains.exposed.v1.core.isNull +import org.jetbrains.exposed.v1.core.less +import org.jetbrains.exposed.v1.core.lessEq +import org.jetbrains.exposed.v1.core.like +import org.jetbrains.exposed.v1.core.neq +import org.jetbrains.exposed.v1.core.not +import org.jetbrains.exposed.v1.core.notInList +import org.jetbrains.exposed.v1.core.notLike +import org.jetbrains.exposed.v1.core.or +import org.jetbrains.exposed.v1.core.stringParam +import org.jetbrains.exposed.v1.core.upperCase +import org.jetbrains.exposed.v1.core.wrap +import org.jetbrains.exposed.v1.jdbc.Query +import org.jetbrains.exposed.v1.jdbc.andWhere class ILikeEscapeOp( expr1: Expression<*>, @@ -88,9 +100,7 @@ class DistinctFromOp( ): DistinctFromOp = DistinctFromOp( expression, - with(SqlExpressionBuilder) { - expression.wrap(t) - }, + expression.wrap(t), false, ) @@ -100,9 +110,7 @@ class DistinctFromOp( ): DistinctFromOp = DistinctFromOp( expression, - with(SqlExpressionBuilder) { - expression.wrap(t) - }, + expression.wrap(t), true, ) @@ -112,9 +120,7 @@ class DistinctFromOp( ): DistinctFromOp = DistinctFromOp( expression, - with(SqlExpressionBuilder) { - expression.wrap(t) - }, + expression.wrap(t), false, ) @@ -124,9 +130,7 @@ class DistinctFromOp( ): DistinctFromOp = DistinctFromOp( expression, - with(SqlExpressionBuilder) { - expression.wrap(t) - }, + expression.wrap(t), true, ) } @@ -505,26 +509,26 @@ class OpAnd( ) { fun andWhere( value: T?, - andPart: SqlExpressionBuilder.(T & Any) -> Op, + andPart: (T & Any) -> Op, ) { value ?: return - val expr = Op.build { andPart(value) } + val expr = andPart(value) op = if (op == null) expr else (op!! and expr) } fun andWhere( values: List?, - andPart: SqlExpressionBuilder.(List) -> Op, + andPart: (List) -> Op, ) { @Suppress("UNCHECKED_CAST") - return andWhere(values as T?, andPart as SqlExpressionBuilder.(Any) -> Op) + return andWhere(values as T?, andPart as (Any) -> Op) } fun andWhere( valueDefault: T?, valueAll: List?, valueAny: List?, - expr: SqlExpressionBuilder.(T) -> Op, + expr: (T) -> Op, ) { andWhere(valueDefault, expr) andWhereAll(valueAll, expr) @@ -533,17 +537,17 @@ class OpAnd( fun andWhereAll( values: List?, - andPart: SqlExpressionBuilder.(T) -> Op, + andPart: (T) -> Op, ) { values?.map { andWhere(it, andPart) } } fun andWhereAny( values: List?, - andPart: SqlExpressionBuilder.(T) -> Op, + andPart: (T) -> Op, ) { values ?: return - val expr = values.map { Op.build { andPart(it) } }.reduce { acc, op -> acc or op } + val expr = values.map { andPart(it) }.reduce { acc, op -> acc or op } op = if (op == null) expr else (op!! and expr) } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/JavalinGraphQLRequestParser.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/JavalinGraphQLRequestParser.kt index f07d9962..5844d6b3 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/JavalinGraphQLRequestParser.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/JavalinGraphQLRequestParser.kt @@ -14,7 +14,6 @@ import com.expediagroup.graphql.server.types.GraphQLServerRequest import io.github.oshai.kotlinlogging.KotlinLogging import io.javalin.http.Context import io.javalin.http.UploadedFile -import io.javalin.json.JavalinJackson import io.javalin.json.fromJsonStream import io.javalin.json.fromJsonString import java.io.IOException diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLServer.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLServer.kt index 0b640b5e..162228f9 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLServer.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLServer.kt @@ -15,7 +15,6 @@ import graphql.GraphQL import graphql.execution.AsyncExecutionStrategy import graphql.execution.DataFetcherExceptionHandler import graphql.execution.DataFetcherExceptionHandlerResult -import graphql.schema.idl.RuntimeWiring import io.github.oshai.kotlinlogging.KotlinLogging import io.javalin.http.Context import io.javalin.websocket.WsCloseContext diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/OrderBy.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/OrderBy.kt index d0b495c3..c8a1393e 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/OrderBy.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/OrderBy.kt @@ -1,16 +1,16 @@ package suwayomi.tachidesk.graphql.server.primitives -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.Column -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.Query -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater -import org.jetbrains.exposed.sql.SqlExpressionBuilder.less -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.andWhere -import org.jetbrains.exposed.sql.or +import org.jetbrains.exposed.v1.core.Column +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.greater +import org.jetbrains.exposed.v1.core.less +import org.jetbrains.exposed.v1.core.or +import org.jetbrains.exposed.v1.jdbc.Query +import org.jetbrains.exposed.v1.jdbc.andWhere interface OrderBy { val column: Column<*> diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/QueryResults.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/QueryResults.kt index 27874b7f..9abb6b67 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/QueryResults.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/primitives/QueryResults.kt @@ -1,6 +1,6 @@ package suwayomi.tachidesk.graphql.server.primitives -import org.jetbrains.exposed.sql.ResultRow +import org.jetbrains.exposed.v1.core.ResultRow data class QueryResults( val total: Long, diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/CategoryType.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/CategoryType.kt index 21b04ea0..650e0e89 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/CategoryType.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/CategoryType.kt @@ -9,7 +9,7 @@ package suwayomi.tachidesk.graphql.types import com.expediagroup.graphql.server.extensions.getValueFromDataLoader import graphql.schema.DataFetchingEnvironment -import org.jetbrains.exposed.sql.ResultRow +import org.jetbrains.exposed.v1.core.ResultRow import suwayomi.tachidesk.graphql.server.primitives.Cursor import suwayomi.tachidesk.graphql.server.primitives.Edge import suwayomi.tachidesk.graphql.server.primitives.Node diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/ChapterType.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/ChapterType.kt index 09c30f90..7020db46 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/ChapterType.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/ChapterType.kt @@ -9,7 +9,7 @@ package suwayomi.tachidesk.graphql.types import com.expediagroup.graphql.server.extensions.getValueFromDataLoader import graphql.schema.DataFetchingEnvironment -import org.jetbrains.exposed.sql.ResultRow +import org.jetbrains.exposed.v1.core.ResultRow import suwayomi.tachidesk.graphql.server.primitives.Cursor import suwayomi.tachidesk.graphql.server.primitives.Edge import suwayomi.tachidesk.graphql.server.primitives.Node diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/ExtensionType.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/ExtensionType.kt index 7c6a3fd7..97d6a59a 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/ExtensionType.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/ExtensionType.kt @@ -9,7 +9,7 @@ package suwayomi.tachidesk.graphql.types import com.expediagroup.graphql.server.extensions.getValueFromDataLoader import graphql.schema.DataFetchingEnvironment -import org.jetbrains.exposed.sql.ResultRow +import org.jetbrains.exposed.v1.core.ResultRow import suwayomi.tachidesk.graphql.server.primitives.Cursor import suwayomi.tachidesk.graphql.server.primitives.Edge import suwayomi.tachidesk.graphql.server.primitives.Node diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/MangaType.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/MangaType.kt index dc6a6424..7ac70b86 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/MangaType.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/MangaType.kt @@ -10,7 +10,7 @@ package suwayomi.tachidesk.graphql.types import com.expediagroup.graphql.server.extensions.getValueFromDataLoader import eu.kanade.tachiyomi.source.model.UpdateStrategy import graphql.schema.DataFetchingEnvironment -import org.jetbrains.exposed.sql.ResultRow +import org.jetbrains.exposed.v1.core.ResultRow import suwayomi.tachidesk.graphql.cache.CustomCacheMap import suwayomi.tachidesk.graphql.server.primitives.Cursor import suwayomi.tachidesk.graphql.server.primitives.Edge diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/MetaType.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/MetaType.kt index 4b1aaef6..1f4d7bec 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/MetaType.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/MetaType.kt @@ -2,7 +2,7 @@ package suwayomi.tachidesk.graphql.types import com.expediagroup.graphql.server.extensions.getValueFromDataLoader import graphql.schema.DataFetchingEnvironment -import org.jetbrains.exposed.sql.ResultRow +import org.jetbrains.exposed.v1.core.ResultRow import suwayomi.tachidesk.global.model.table.GlobalMetaTable import suwayomi.tachidesk.graphql.server.primitives.Cursor import suwayomi.tachidesk.graphql.server.primitives.Edge diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/SourceType.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/SourceType.kt index 56f85259..f6c4744a 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/SourceType.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/SourceType.kt @@ -13,8 +13,9 @@ import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.online.HttpSource import graphql.schema.DataFetchingEnvironment -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.selectAll +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.selectAll import suwayomi.tachidesk.graphql.server.primitives.Cursor import suwayomi.tachidesk.graphql.server.primitives.Edge import suwayomi.tachidesk.graphql.server.primitives.Node diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/TrackType.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/TrackType.kt index 11ae7e2d..9923df32 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/TrackType.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/types/TrackType.kt @@ -2,7 +2,7 @@ package suwayomi.tachidesk.graphql.types import com.expediagroup.graphql.server.extensions.getValueFromDataLoader import graphql.schema.DataFetchingEnvironment -import org.jetbrains.exposed.sql.ResultRow +import org.jetbrains.exposed.v1.core.ResultRow import suwayomi.tachidesk.graphql.server.primitives.Cursor import suwayomi.tachidesk.graphql.server.primitives.Edge import suwayomi.tachidesk.graphql.server.primitives.Node diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/controller/MangaController.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/controller/MangaController.kt index f41a7b59..d82c97ed 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/controller/MangaController.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/controller/MangaController.kt @@ -12,8 +12,9 @@ import io.javalin.http.HttpStatus import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.serialization.json.Json -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.manga.impl.CategoryManga import suwayomi.tachidesk.manga.impl.Chapter import suwayomi.tachidesk.manga.impl.ChapterDownloadHelper diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Category.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Category.kt index ea1ba176..23c1ba11 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Category.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Category.kt @@ -7,25 +7,27 @@ package suwayomi.tachidesk.manga.impl * 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 org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.andWhere -import org.jetbrains.exposed.sql.batchInsert -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.statements.BatchUpdateStatement -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.isNull +import org.jetbrains.exposed.v1.core.neq +import org.jetbrains.exposed.v1.core.statements.BatchUpdateStatement +import org.jetbrains.exposed.v1.jdbc.andWhere +import org.jetbrains.exposed.v1.jdbc.batchInsert +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.statements.toExecutable +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.manga.model.dataclass.CategoryDataClass import suwayomi.tachidesk.manga.model.table.CategoryMangaTable import suwayomi.tachidesk.manga.model.table.CategoryMetaTable import suwayomi.tachidesk.manga.model.table.CategoryTable import suwayomi.tachidesk.manga.model.table.MangaTable import suwayomi.tachidesk.manga.model.table.toDataClass -import kotlin.collections.component1 -import kotlin.collections.orEmpty object Category { /** @@ -248,13 +250,14 @@ object Category { } if (existingMetaByMetaId.isNotEmpty()) { - BatchUpdateStatement(CategoryMetaTable).apply { - existingMetaByMetaId.forEach { (metaId, entry) -> - addBatch(EntityID(metaId, CategoryMetaTable)) - this[CategoryMetaTable.value] = entry.value - } - execute(this@transaction) - } + BatchUpdateStatement(CategoryMetaTable) + .apply { + existingMetaByMetaId.forEach { (metaId, entry) -> + addBatch(EntityID(metaId, CategoryMetaTable)) + this[CategoryMetaTable.value] = entry.value + } + }.toExecutable() + .execute(this@transaction) } if (newMetaByCategoryId.isNotEmpty()) { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/CategoryManga.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/CategoryManga.kt index 68852e6b..515858fb 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/CategoryManga.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/CategoryManga.kt @@ -7,19 +7,22 @@ package suwayomi.tachidesk.manga.impl * 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 org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.alias -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.batchInsert -import org.jetbrains.exposed.sql.count -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.leftJoin -import org.jetbrains.exposed.sql.max -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.wrapAsExpression +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.alias +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.count +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.isNull +import org.jetbrains.exposed.v1.core.leftJoin +import org.jetbrains.exposed.v1.core.max +import org.jetbrains.exposed.v1.core.wrapAsExpression +import org.jetbrains.exposed.v1.jdbc.batchInsert +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.select +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.manga.impl.Category.DEFAULT_CATEGORY_ID import suwayomi.tachidesk.manga.model.dataclass.CategoryDataClass import suwayomi.tachidesk.manga.model.dataclass.MangaDataClass diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt index b5f7d415..e0748000 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Chapter.kt @@ -17,17 +17,21 @@ import io.github.reactivecircus.cache4k.Cache import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.serialization.Serializable -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.batchInsert -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.statements.BatchUpdateStatement -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.greater +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.less +import org.jetbrains.exposed.v1.core.statements.BatchUpdateStatement +import org.jetbrains.exposed.v1.jdbc.batchInsert +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.select +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.statements.toExecutable +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.manga.impl.Manga.getManga import suwayomi.tachidesk.manga.impl.download.DownloadManager import suwayomi.tachidesk.manga.impl.download.DownloadManager.EnqueueInput @@ -306,18 +310,19 @@ object Chapter { } if (chaptersToUpdate.isNotEmpty()) { - BatchUpdateStatement(ChapterTable).apply { - chaptersToUpdate.forEach { - addBatch(EntityID(it.id, ChapterTable)) - this[ChapterTable.name] = it.name - this[ChapterTable.date_upload] = it.uploadDate - this[ChapterTable.chapter_number] = it.chapterNumber - this[ChapterTable.scanlator] = it.scanlator - this[ChapterTable.sourceOrder] = it.index - this[ChapterTable.realUrl] = it.realUrl - } - execute(this@transaction) - } + BatchUpdateStatement(ChapterTable) + .apply { + chaptersToUpdate.forEach { + addBatch(EntityID(it.id, ChapterTable)) + this[ChapterTable.name] = it.name + this[ChapterTable.date_upload] = it.uploadDate + this[ChapterTable.chapter_number] = it.chapterNumber + this[ChapterTable.scanlator] = it.scanlator + this[ChapterTable.sourceOrder] = it.index + this[ChapterTable.realUrl] = it.realUrl + } + }.toExecutable() + .execute(this@transaction) } MangaTable.update({ MangaTable.id eq mangaId }) { @@ -517,11 +522,11 @@ object Chapter { // mangaId is not null, scope query under manga when { input.chapterIds != null -> { - Op.build { (ChapterTable.manga eq mangaId) and (ChapterTable.id inList input.chapterIds) } + (ChapterTable.manga eq mangaId) and (ChapterTable.id inList input.chapterIds) } input.chapterIndexes != null -> { - Op.build { (ChapterTable.manga eq mangaId) and (ChapterTable.sourceOrder inList input.chapterIndexes) } + (ChapterTable.manga eq mangaId) and (ChapterTable.sourceOrder inList input.chapterIndexes) } else -> { @@ -534,7 +539,7 @@ object Chapter { // mangaId is null, only chapterIndexes is valid for this case when { input.chapterIds != null -> { - Op.build { (ChapterTable.id inList input.chapterIds) } + (ChapterTable.id inList input.chapterIds) } else -> { @@ -650,13 +655,14 @@ object Chapter { } if (existingMetaByMetaId.isNotEmpty()) { - BatchUpdateStatement(ChapterMetaTable).apply { - existingMetaByMetaId.forEach { (metaId, entry) -> - addBatch(EntityID(metaId, ChapterMetaTable)) - this[ChapterMetaTable.value] = entry.value - } - execute(this@transaction) - } + BatchUpdateStatement(ChapterMetaTable) + .apply { + existingMetaByMetaId.forEach { (metaId, entry) -> + addBatch(EntityID(metaId, ChapterMetaTable)) + this[ChapterMetaTable.value] = entry.value + } + }.toExecutable() + .execute(this@transaction) } if (newMetaByChapterId.isNotEmpty()) { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/ChapterDownloadHelper.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/ChapterDownloadHelper.kt index 5898534b..d4fa60ea 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/ChapterDownloadHelper.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/ChapterDownloadHelper.kt @@ -1,7 +1,9 @@ package suwayomi.tachidesk.manga.impl import kotlinx.coroutines.CoroutineScope -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.select +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.manga.impl.chapter.getChapterDownloadReady import suwayomi.tachidesk.manga.impl.download.fileProvider.ChaptersFilesProvider import suwayomi.tachidesk.manga.impl.download.fileProvider.impl.ArchiveProvider diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Library.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Library.kt index 9b047e72..63439e2b 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Library.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Library.kt @@ -12,11 +12,14 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.insert -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.neq +import org.jetbrains.exposed.v1.jdbc.insert +import org.jetbrains.exposed.v1.jdbc.select +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.manga.impl.Manga.getManga import suwayomi.tachidesk.manga.model.table.CategoryMangaTable import suwayomi.tachidesk.manga.model.table.CategoryTable diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Manga.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Manga.kt index a52c29d9..c76eee88 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Manga.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Manga.kt @@ -20,15 +20,18 @@ import io.github.oshai.kotlinlogging.KotlinLogging import io.javalin.http.HttpStatus import okhttp3.CacheControl import okhttp3.Response -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.batchInsert -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.statements.BatchUpdateStatement -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.statements.BatchUpdateStatement +import org.jetbrains.exposed.v1.jdbc.batchInsert +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.statements.toExecutable +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.manga.impl.MangaList.proxyThumbnailUrl import suwayomi.tachidesk.manga.impl.Source.getSource import suwayomi.tachidesk.manga.impl.download.fileProvider.impl.MissingThumbnailException @@ -295,13 +298,14 @@ object Manga { } if (existingMetaByMetaId.isNotEmpty()) { - BatchUpdateStatement(MangaMetaTable).apply { - existingMetaByMetaId.forEach { (metaId, entry) -> - addBatch(EntityID(metaId, MangaMetaTable)) - this[MangaMetaTable.value] = entry.value - } - execute(this@transaction) - } + BatchUpdateStatement(MangaMetaTable) + .apply { + existingMetaByMetaId.forEach { (metaId, entry) -> + addBatch(EntityID(metaId, MangaMetaTable)) + this[MangaMetaTable.value] = entry.value + } + }.toExecutable() + .execute(this@transaction) } if (newMetaByMangaId.isNotEmpty()) { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/MangaList.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/MangaList.kt index bdc66ea6..9d405c50 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/MangaList.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/MangaList.kt @@ -9,12 +9,15 @@ package suwayomi.tachidesk.manga.impl import eu.kanade.tachiyomi.source.local.LocalSource import eu.kanade.tachiyomi.source.model.MangasPage -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.batchInsert -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.statements.BatchUpdateStatement -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.statements.BatchUpdateStatement +import org.jetbrains.exposed.v1.jdbc.batchInsert +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.statements.toExecutable +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub import suwayomi.tachidesk.manga.model.dataclass.PagedMangaListDataClass import suwayomi.tachidesk.manga.model.table.MangaTable @@ -88,27 +91,28 @@ object MangaList { } if (mangaToUpdate.isNotEmpty()) { - BatchUpdateStatement(MangaTable).apply { - mangaToUpdate.forEach { (sManga, manga) -> - addBatch(EntityID(manga[MangaTable.id].value, MangaTable)) - this[MangaTable.title] = sManga.title - this[MangaTable.artist] = sManga.artist ?: manga[MangaTable.artist] - this[MangaTable.author] = sManga.author ?: manga[MangaTable.author] - this[MangaTable.description] = sManga.description ?: manga[MangaTable.description] - this[MangaTable.genre] = sManga.genre ?: manga[MangaTable.genre] - this[MangaTable.status] = sManga.status - this[MangaTable.thumbnail_url] = sManga.thumbnail_url ?: manga[MangaTable.thumbnail_url] - this[MangaTable.updateStrategy] = sManga.update_strategy.name - if (!sManga.thumbnail_url.isNullOrEmpty() && manga[MangaTable.thumbnail_url] != sManga.thumbnail_url) { - this[MangaTable.thumbnailUrlLastFetched] = Instant.now().epochSecond - Manga.clearThumbnail(manga[MangaTable.id].value) - } else { - this[MangaTable.thumbnailUrlLastFetched] = - manga[MangaTable.thumbnailUrlLastFetched] + BatchUpdateStatement(MangaTable) + .apply { + mangaToUpdate.forEach { (sManga, manga) -> + addBatch(EntityID(manga[MangaTable.id].value, MangaTable)) + this[MangaTable.title] = sManga.title + this[MangaTable.artist] = sManga.artist ?: manga[MangaTable.artist] + this[MangaTable.author] = sManga.author ?: manga[MangaTable.author] + this[MangaTable.description] = sManga.description ?: manga[MangaTable.description] + this[MangaTable.genre] = sManga.genre ?: manga[MangaTable.genre] + this[MangaTable.status] = sManga.status + this[MangaTable.thumbnail_url] = sManga.thumbnail_url ?: manga[MangaTable.thumbnail_url] + this[MangaTable.updateStrategy] = sManga.update_strategy.name + if (!sManga.thumbnail_url.isNullOrEmpty() && manga[MangaTable.thumbnail_url] != sManga.thumbnail_url) { + this[MangaTable.thumbnailUrlLastFetched] = Instant.now().epochSecond + Manga.clearThumbnail(manga[MangaTable.id].value) + } else { + this[MangaTable.thumbnailUrlLastFetched] = + manga[MangaTable.thumbnailUrlLastFetched] + } } - } - execute(this@transaction) - } + }.toExecutable() + .execute(this@transaction) } val mangaUrlsToId = diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Page.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Page.kt index cf7915e3..7addcb92 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Page.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Page.kt @@ -13,11 +13,12 @@ import eu.kanade.tachiyomi.source.online.HttpSource import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.coroutines.flow.StateFlow import libcore.net.MimeUtils -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.graphql.types.DownloadConversion import suwayomi.tachidesk.manga.impl.util.getChapterCachePath import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Source.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Source.kt index 3fcf1b0b..fbf5e6d1 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Source.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/Source.kt @@ -15,12 +15,16 @@ import eu.kanade.tachiyomi.source.sourcePreferences import io.github.oshai.kotlinlogging.KotlinLogging import io.javalin.json.JsonMapper import io.javalin.json.fromJsonString -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.batchInsert -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.statements.BatchUpdateStatement -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.statements.BatchUpdateStatement +import org.jetbrains.exposed.v1.jdbc.batchInsert +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.statements.toExecutable +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import suwayomi.tachidesk.manga.impl.Source.preferenceScreenMap import suwayomi.tachidesk.manga.impl.extension.Extension.getExtensionIconUrl import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrNull import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub @@ -210,13 +214,14 @@ object Source { } if (existingMetaByMetaId.isNotEmpty()) { - BatchUpdateStatement(SourceMetaTable).apply { - existingMetaByMetaId.forEach { (metaId, entry) -> - addBatch(EntityID(metaId, SourceMetaTable)) - this[SourceMetaTable.value] = entry.value - } - execute(this@transaction) - } + BatchUpdateStatement(SourceMetaTable) + .apply { + existingMetaByMetaId.forEach { (metaId, entry) -> + addBatch(EntityID(metaId, SourceMetaTable)) + this[SourceMetaTable.value] = entry.value + } + }.toExecutable() + .execute(this@transaction) } if (newMetaBySourceId.isNotEmpty()) { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/ProtoBackupExport.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/ProtoBackupExport.kt index cabf6742..bae65f7d 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/ProtoBackupExport.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/ProtoBackupExport.kt @@ -19,7 +19,7 @@ import okio.Buffer import okio.Sink import okio.buffer import okio.gzip -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.manga.impl.backup.BackupFlags import suwayomi.tachidesk.manga.impl.backup.proto.handlers.BackupCategoryHandler import suwayomi.tachidesk.manga.impl.backup.proto.handlers.BackupGlobalMetaHandler diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/ProtoBackupValidator.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/ProtoBackupValidator.kt index 7bcb7dfb..9f036a51 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/ProtoBackupValidator.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/ProtoBackupValidator.kt @@ -11,8 +11,9 @@ import com.fasterxml.jackson.annotation.JsonIgnore import okio.buffer import okio.gzip import okio.source -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.manga.impl.backup.proto.models.Backup import suwayomi.tachidesk.manga.impl.track.tracker.TrackerManager import suwayomi.tachidesk.manga.model.table.SourceTable diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/handlers/BackupCategoryHandler.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/handlers/BackupCategoryHandler.kt index 2603fe0c..60f2cc1c 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/handlers/BackupCategoryHandler.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/handlers/BackupCategoryHandler.kt @@ -7,8 +7,8 @@ package suwayomi.tachidesk.manga.impl.backup.proto.handlers * 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 org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.selectAll +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.jdbc.selectAll import suwayomi.tachidesk.manga.impl.Category import suwayomi.tachidesk.manga.impl.Category.modifyCategoriesMetas import suwayomi.tachidesk.manga.impl.backup.BackupFlags diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/handlers/BackupMangaHandler.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/handlers/BackupMangaHandler.kt index 4c0f2bbb..9fb0d8e2 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/handlers/BackupMangaHandler.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/handlers/BackupMangaHandler.kt @@ -8,16 +8,18 @@ package suwayomi.tachidesk.manga.impl.backup.proto.handlers * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import eu.kanade.tachiyomi.source.model.UpdateStrategy -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.batchInsert -import org.jetbrains.exposed.sql.insertAndGetId -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.statements.BatchUpdateStatement -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.statements.BatchUpdateStatement +import org.jetbrains.exposed.v1.jdbc.batchInsert +import org.jetbrains.exposed.v1.jdbc.insertAndGetId +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.statements.toExecutable +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.manga.impl.CategoryManga import suwayomi.tachidesk.manga.impl.Chapter import suwayomi.tachidesk.manga.impl.Chapter.modifyChaptersMetas @@ -343,24 +345,25 @@ object BackupMangaHandler { } if (chaptersToUpdateToDbChapter.isNotEmpty()) { - BatchUpdateStatement(ChapterTable).apply { - chaptersToUpdateToDbChapter.forEach { (backupChapter, dbChapter) -> - addBatch(EntityID(dbChapter[ChapterTable.id].value, ChapterTable)) - if (flags.includeChapters) { - this[ChapterTable.isRead] = backupChapter.read || dbChapter[ChapterTable.isRead] - this[ChapterTable.lastPageRead] = - max(backupChapter.lastPageRead, dbChapter[ChapterTable.lastPageRead]).coerceAtLeast(0) - this[ChapterTable.isBookmarked] = backupChapter.bookmark || dbChapter[ChapterTable.isBookmarked] - } + BatchUpdateStatement(ChapterTable) + .apply { + chaptersToUpdateToDbChapter.forEach { (backupChapter, dbChapter) -> + addBatch(EntityID(dbChapter[ChapterTable.id].value, ChapterTable)) + if (flags.includeChapters) { + this[ChapterTable.isRead] = backupChapter.read || dbChapter[ChapterTable.isRead] + this[ChapterTable.lastPageRead] = + max(backupChapter.lastPageRead, dbChapter[ChapterTable.lastPageRead]).coerceAtLeast(0) + this[ChapterTable.isBookmarked] = backupChapter.bookmark || dbChapter[ChapterTable.isBookmarked] + } - if (flags.includeHistory) { - this[ChapterTable.lastReadAt] = - (historyByChapter[backupChapter.url]?.maxOrNull()?.milliseconds?.inWholeSeconds ?: 0) - .coerceAtLeast(dbChapter[ChapterTable.lastReadAt]) + if (flags.includeHistory) { + this[ChapterTable.lastReadAt] = + (historyByChapter[backupChapter.url]?.maxOrNull()?.milliseconds?.inWholeSeconds ?: 0) + .coerceAtLeast(dbChapter[ChapterTable.lastReadAt]) + } } - } - execute(this@dbTransaction) - } + }.toExecutable() + .execute(this@dbTransaction) } if (flags.includeClientData) { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/handlers/BackupSourceHandler.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/handlers/BackupSourceHandler.kt index f940217a..4fe46db2 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/handlers/BackupSourceHandler.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/backup/proto/handlers/BackupSourceHandler.kt @@ -7,7 +7,8 @@ package suwayomi.tachidesk.manga.impl.backup.proto.handlers * 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 org.jetbrains.exposed.sql.selectAll +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.jdbc.selectAll import suwayomi.tachidesk.manga.impl.Source import suwayomi.tachidesk.manga.impl.Source.modifySourceMetas import suwayomi.tachidesk.manga.impl.backup.BackupFlags diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/chapter/ChapterForDownload.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/chapter/ChapterForDownload.kt index 47481668..76e9045e 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/chapter/ChapterForDownload.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/chapter/ChapterForDownload.kt @@ -14,14 +14,14 @@ import io.github.oshai.kotlinlogging.KotlinLogging import io.github.reactivecircus.cache4k.Cache import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.batchInsert -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.batchInsert +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.manga.impl.ChapterDownloadHelper import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub import suwayomi.tachidesk.manga.model.dataclass.ChapterDataClass diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/DownloadManager.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/DownloadManager.kt index 7d66561f..7b3dd103 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/DownloadManager.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/DownloadManager.kt @@ -27,9 +27,12 @@ import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.sample import kotlinx.coroutines.launch import kotlinx.serialization.Serializable -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.jdbc.select +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.manga.impl.download.model.DownloadChapter import suwayomi.tachidesk.manga.impl.download.model.DownloadQueueItem import suwayomi.tachidesk.manga.impl.download.model.DownloadState.Error @@ -343,7 +346,7 @@ object DownloadManager { transaction { ChapterTable .select(ChapterTable.id) - .where { ChapterTable.manga.eq(mangaId) and ChapterTable.sourceOrder.eq(chapterIndex) } + .where { (ChapterTable.manga eq mangaId) and (ChapterTable.sourceOrder eq chapterIndex) } .first() } enqueue(EnqueueInput(chapterIds = listOf(chapter[ChapterTable.id].value))) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/Downloader.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/Downloader.kt index fb8b5337..4ed66ec6 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/Downloader.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/Downloader.kt @@ -17,8 +17,9 @@ import kotlinx.coroutines.currentCoroutineContext import kotlinx.coroutines.ensureActive import kotlinx.coroutines.isActive import kotlinx.coroutines.launch -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.manga.impl.ChapterDownloadHelper import suwayomi.tachidesk.manga.impl.chapter.getChapterDownloadReadyById import suwayomi.tachidesk.manga.impl.download.model.DownloadQueueItem diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/fileProvider/ChaptersFilesProvider.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/fileProvider/ChaptersFilesProvider.kt index 77d38f14..f66db074 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/fileProvider/ChaptersFilesProvider.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/fileProvider/ChaptersFilesProvider.kt @@ -11,10 +11,10 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.sample import libcore.net.MimeUtils import org.apache.commons.compress.archivers.zip.ZipArchiveEntry -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update -import suwayomi.tachidesk.graphql.types.DownloadConversion +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.manga.impl.Page import suwayomi.tachidesk.manga.impl.chapter.getChapterDownloadReady import suwayomi.tachidesk.manga.impl.download.model.DownloadQueueItem @@ -26,14 +26,8 @@ import suwayomi.tachidesk.manga.impl.util.getChapterDownloadPath import suwayomi.tachidesk.manga.impl.util.storage.ImageResponse import suwayomi.tachidesk.manga.model.table.ChapterTable import suwayomi.tachidesk.manga.model.table.MangaTable -import suwayomi.tachidesk.server.serverConfig -import suwayomi.tachidesk.util.ConversionUtil import java.io.File import java.io.InputStream -import javax.imageio.IIOImage -import javax.imageio.ImageIO -import javax.imageio.ImageWriteParam -import javax.imageio.ImageWriter sealed class FileType { data class RegularFile( diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/fileProvider/impl/ArchiveProvider.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/fileProvider/impl/ArchiveProvider.kt index 99e62654..a9f37d9f 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/fileProvider/impl/ArchiveProvider.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/fileProvider/impl/ArchiveProvider.kt @@ -6,8 +6,9 @@ import org.apache.commons.compress.archivers.zip.ZipArchiveEntry import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream import org.apache.commons.compress.archivers.zip.ZipFile -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.manga.impl.download.fileProvider.ChaptersFilesProvider import suwayomi.tachidesk.manga.impl.download.fileProvider.FileType import suwayomi.tachidesk.manga.impl.util.getChapterCachePath diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/fileProvider/impl/FolderProvider.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/fileProvider/impl/FolderProvider.kt index 9d457f01..90be1624 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/fileProvider/impl/FolderProvider.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/fileProvider/impl/FolderProvider.kt @@ -2,8 +2,9 @@ package suwayomi.tachidesk.manga.impl.download.fileProvider.impl import org.apache.commons.compress.archivers.zip.ZipArchiveEntry import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.manga.impl.download.fileProvider.ChaptersFilesProvider import suwayomi.tachidesk.manga.impl.download.fileProvider.FileType.RegularFile import suwayomi.tachidesk.manga.impl.util.getChapterCachePath diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/extension/Extension.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/extension/Extension.kt index 83e307ea..51d3c45e 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/extension/Extension.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/extension/Extension.kt @@ -20,12 +20,12 @@ import okhttp3.CacheControl import okio.buffer import okio.sink import okio.source -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.insert -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.insert +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.manga.impl.extension.ExtensionsList.extensionTableAsDataClass import suwayomi.tachidesk.manga.impl.extension.github.ExtensionGithubApi import suwayomi.tachidesk.manga.impl.util.PackageTools @@ -55,7 +55,6 @@ import java.util.zip.ZipOutputStream import kotlin.io.path.Path import kotlin.io.path.absolutePathString import kotlin.io.path.outputStream -import kotlin.io.path.relativeTo object Extension { private val logger = KotlinLogging.logger {} diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/extension/ExtensionsList.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/extension/ExtensionsList.kt index 5371ba08..0398f1f5 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/extension/ExtensionsList.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/extension/ExtensionsList.kt @@ -11,15 +11,16 @@ import eu.kanade.tachiyomi.source.local.LocalSource import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.SqlExpressionBuilder.inList -import org.jetbrains.exposed.sql.batchInsert -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.statements.BatchUpdateStatement -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.statements.BatchUpdateStatement +import org.jetbrains.exposed.v1.jdbc.batchInsert +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.statements.toExecutable +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.manga.impl.extension.Extension.getExtensionIconUrl import suwayomi.tachidesk.manga.impl.extension.github.ExtensionGithubApi import suwayomi.tachidesk.manga.impl.extension.github.OnlineExtension @@ -125,57 +126,59 @@ object ExtensionsList { .groupBy { it.second[ExtensionTable.isInstalled] } val installedExtensionsToUpdate = extensionsInstalled[true].orEmpty() if (installedExtensionsToUpdate.isNotEmpty()) { - BatchUpdateStatement(ExtensionTable).apply { - installedExtensionsToUpdate.forEach { (foundExtension, extensionRecord) -> - addBatch(EntityID(extensionRecord[ExtensionTable.id].value, ExtensionTable)) - // Always update icon url and repo - this[ExtensionTable.iconUrl] = foundExtension.iconUrl - this[ExtensionTable.repo] = foundExtension.repo + BatchUpdateStatement(ExtensionTable) + .apply { + installedExtensionsToUpdate.forEach { (foundExtension, extensionRecord) -> + addBatch(EntityID(extensionRecord[ExtensionTable.id].value, ExtensionTable)) + // Always update icon url and repo + this[ExtensionTable.iconUrl] = foundExtension.iconUrl + this[ExtensionTable.repo] = foundExtension.repo - // add these because batch updates need matching columns - this[ExtensionTable.hasUpdate] = extensionRecord[ExtensionTable.hasUpdate] - this[ExtensionTable.isObsolete] = extensionRecord[ExtensionTable.isObsolete] + // add these because batch updates need matching columns + this[ExtensionTable.hasUpdate] = extensionRecord[ExtensionTable.hasUpdate] + this[ExtensionTable.isObsolete] = extensionRecord[ExtensionTable.isObsolete] - // a previously removed extension is now available again - if (extensionRecord[ExtensionTable.isObsolete] && - foundExtension.versionCode >= extensionRecord[ExtensionTable.versionCode] - ) { - this[ExtensionTable.isObsolete] = false - } - - when { - foundExtension.versionCode > extensionRecord[ExtensionTable.versionCode] -> { - // there is an update - this[ExtensionTable.hasUpdate] = true - updateMap.putIfAbsent(foundExtension.pkgName, foundExtension) + // a previously removed extension is now available again + if (extensionRecord[ExtensionTable.isObsolete] && + foundExtension.versionCode >= extensionRecord[ExtensionTable.versionCode] + ) { + this[ExtensionTable.isObsolete] = false } - foundExtension.versionCode < extensionRecord[ExtensionTable.versionCode] -> { - // somehow the user installed an invalid version - this[ExtensionTable.isObsolete] = true + when { + foundExtension.versionCode > extensionRecord[ExtensionTable.versionCode] -> { + // there is an update + this[ExtensionTable.hasUpdate] = true + updateMap.putIfAbsent(foundExtension.pkgName, foundExtension) + } + + foundExtension.versionCode < extensionRecord[ExtensionTable.versionCode] -> { + // somehow the user installed an invalid version + this[ExtensionTable.isObsolete] = true + } } } - } - execute(this@transaction) - } + }.toExecutable() + .execute(this@transaction) } val extensionsToFullyUpdate = extensionsInstalled[false].orEmpty() if (extensionsToFullyUpdate.isNotEmpty()) { - BatchUpdateStatement(ExtensionTable).apply { - extensionsToFullyUpdate.forEach { (foundExtension, extensionRecord) -> - addBatch(EntityID(extensionRecord[ExtensionTable.id].value, ExtensionTable)) - // extension is not installed, so we can overwrite the data without a care - this[ExtensionTable.repo] = foundExtension.repo - this[ExtensionTable.name] = foundExtension.name - this[ExtensionTable.versionName] = foundExtension.versionName - this[ExtensionTable.versionCode] = foundExtension.versionCode - this[ExtensionTable.lang] = foundExtension.lang - this[ExtensionTable.isNsfw] = foundExtension.isNsfw - this[ExtensionTable.apkName] = foundExtension.apkName - this[ExtensionTable.iconUrl] = foundExtension.iconUrl - } - execute(this@transaction) - } + BatchUpdateStatement(ExtensionTable) + .apply { + extensionsToFullyUpdate.forEach { (foundExtension, extensionRecord) -> + addBatch(EntityID(extensionRecord[ExtensionTable.id].value, ExtensionTable)) + // extension is not installed, so we can overwrite the data without a care + this[ExtensionTable.repo] = foundExtension.repo + this[ExtensionTable.name] = foundExtension.name + this[ExtensionTable.versionName] = foundExtension.versionName + this[ExtensionTable.versionCode] = foundExtension.versionCode + this[ExtensionTable.lang] = foundExtension.lang + this[ExtensionTable.isNsfw] = foundExtension.isNsfw + this[ExtensionTable.apkName] = foundExtension.apkName + this[ExtensionTable.iconUrl] = foundExtension.iconUrl + } + }.toExecutable() + .execute(this@transaction) } } if (extensionsToInsert.isNotEmpty()) { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/sync/KoreaderSyncService.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/sync/KoreaderSyncService.kt index cf9a03e4..a0ca9db8 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/sync/KoreaderSyncService.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/sync/KoreaderSyncService.kt @@ -14,8 +14,10 @@ import kotlinx.serialization.json.put import okhttp3.MediaType.Companion.toMediaType import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.update +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.select +import org.jetbrains.exposed.v1.jdbc.transactions.transaction +import org.jetbrains.exposed.v1.jdbc.update import suwayomi.tachidesk.graphql.types.KoSyncStatusPayload import suwayomi.tachidesk.graphql.types.KoreaderSyncChecksumMethod import suwayomi.tachidesk.graphql.types.KoreaderSyncConflictStrategy diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/track/Track.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/track/Track.kt index 094188b4..a08e8605 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/track/Track.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/track/Track.kt @@ -6,16 +6,17 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch import kotlinx.serialization.Serializable -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.batchInsert -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.statements.BatchUpdateStatement -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.statements.BatchUpdateStatement +import org.jetbrains.exposed.v1.jdbc.batchInsert +import org.jetbrains.exposed.v1.jdbc.deleteWhere +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.statements.toExecutable +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.jsoup.Jsoup import suwayomi.tachidesk.manga.impl.track.tracker.DeletableTracker import suwayomi.tachidesk.manga.impl.track.tracker.TrackerManager @@ -427,23 +428,24 @@ object Track { fun updateTrackRecords(tracks: List) = transaction { if (tracks.isNotEmpty()) { - BatchUpdateStatement(TrackRecordTable).apply { - tracks.forEach { - addBatch(EntityID(it.id!!, TrackRecordTable)) - this[remoteId] = it.remote_id - this[libraryId] = it.library_id - this[title] = it.title - this[lastChapterRead] = it.last_chapter_read - this[totalChapters] = it.total_chapters - this[status] = it.status - this[score] = it.score - this[remoteUrl] = it.tracking_url - this[startDate] = it.started_reading_date - this[finishDate] = it.finished_reading_date - this[private] = it.private - } - execute(this@transaction) - } + BatchUpdateStatement(TrackRecordTable) + .apply { + tracks.forEach { + addBatch(EntityID(it.id!!, TrackRecordTable)) + this[remoteId] = it.remote_id + this[libraryId] = it.library_id + this[title] = it.title + this[lastChapterRead] = it.last_chapter_read + this[totalChapters] = it.total_chapters + this[status] = it.status + this[score] = it.score + this[remoteUrl] = it.tracking_url + this[startDate] = it.started_reading_date + this[finishDate] = it.finished_reading_date + this[private] = it.private + } + }.toExecutable() + .execute(this@transaction) } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/track/tracker/model/TrackConvertor.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/track/tracker/model/TrackConvertor.kt index a6fb389b..7f1bd36e 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/track/tracker/model/TrackConvertor.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/track/tracker/model/TrackConvertor.kt @@ -1,11 +1,9 @@ package suwayomi.tachidesk.manga.impl.track.tracker.model -import org.jetbrains.exposed.sql.ResultRow +import org.jetbrains.exposed.v1.core.ResultRow import suwayomi.tachidesk.manga.impl.backup.proto.models.BackupTracking import suwayomi.tachidesk.manga.model.dataclass.TrackRecordDataClass import suwayomi.tachidesk.manga.model.table.TrackRecordTable -import suwayomi.tachidesk.manga.model.table.TrackRecordTable.lastChapterRead -import suwayomi.tachidesk.manga.model.table.TrackRecordTable.remoteUrl import suwayomi.tachidesk.manga.model.table.TrackSearchTable fun ResultRow.toTrackRecordDataClass(): TrackRecordDataClass = diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/DirName.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/DirName.kt index 276a7f75..82d14d3f 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/DirName.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/DirName.kt @@ -7,10 +7,10 @@ package suwayomi.tachidesk.manga.impl.util * 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 io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource import suwayomi.tachidesk.manga.model.table.ChapterTable import suwayomi.tachidesk.manga.model.table.MangaTable diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/GetComicInfo.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/GetComicInfo.kt index ce29925e..89631f0c 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/GetComicInfo.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/GetComicInfo.kt @@ -4,10 +4,11 @@ import eu.kanade.tachiyomi.source.local.metadata.COMIC_INFO_FILE import eu.kanade.tachiyomi.source.local.metadata.ComicInfo import eu.kanade.tachiyomi.source.local.metadata.ComicInfoPublishingStatus import nl.adaptivity.xmlutil.serialization.XML -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.manga.model.table.CategoryMangaTable import suwayomi.tachidesk.manga.model.table.CategoryTable import suwayomi.tachidesk.manga.model.table.ChapterTable diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/lang/ExposedExtensions.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/lang/ExposedExtensions.kt index 91c06aa0..e92e0eec 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/lang/ExposedExtensions.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/lang/ExposedExtensions.kt @@ -7,7 +7,7 @@ package suwayomi.tachidesk.manga.impl.util.lang * 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 org.jetbrains.exposed.sql.Query +import org.jetbrains.exposed.v1.jdbc.Query fun Query.isEmpty() = this.empty() diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/source/GetCatalogueSource.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/source/GetCatalogueSource.kt index e6f88ed3..99952deb 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/source/GetCatalogueSource.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/util/source/GetCatalogueSource.kt @@ -12,8 +12,9 @@ import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceFactory import eu.kanade.tachiyomi.source.online.HttpSource import io.github.oshai.kotlinlogging.KotlinLogging -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.manga.impl.util.PackageTools.loadExtensionSources import suwayomi.tachidesk.manga.model.table.ExtensionTable import suwayomi.tachidesk.manga.model.table.SourceTable diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryMangaTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryMangaTable.kt index 5cf445ab..033e31da 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryMangaTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryMangaTable.kt @@ -7,8 +7,8 @@ package suwayomi.tachidesk.manga.model.table * 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 org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.ReferenceOption +import org.jetbrains.exposed.v1.core.ReferenceOption +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable object CategoryMangaTable : IntIdTable() { val category = reference("category", CategoryTable, ReferenceOption.CASCADE) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryMetaTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryMetaTable.kt index ba45aaf8..5067e931 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryMetaTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryMetaTable.kt @@ -7,8 +7,8 @@ package suwayomi.tachidesk.manga.model.table * 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 org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.ReferenceOption +import org.jetbrains.exposed.v1.core.ReferenceOption +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable import suwayomi.tachidesk.manga.model.table.CategoryMetaTable.ref /** diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryTable.kt index c60facca..e234467b 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryTable.kt @@ -7,8 +7,8 @@ package suwayomi.tachidesk.manga.model.table * 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 org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.ResultRow +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable import suwayomi.tachidesk.manga.impl.Category import suwayomi.tachidesk.manga.model.dataclass.CategoryDataClass import suwayomi.tachidesk.manga.model.dataclass.IncludeOrExclude diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/ChapterMetaTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/ChapterMetaTable.kt index 6584679f..d400faac 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/ChapterMetaTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/ChapterMetaTable.kt @@ -7,8 +7,8 @@ package suwayomi.tachidesk.manga.model.table * 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 org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.ReferenceOption +import org.jetbrains.exposed.v1.core.ReferenceOption +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable import suwayomi.tachidesk.manga.model.table.ChapterMetaTable.ref /** diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/ChapterTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/ChapterTable.kt index 6b27729a..73517429 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/ChapterTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/ChapterTable.kt @@ -7,11 +7,12 @@ package suwayomi.tachidesk.manga.model.table * 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 org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.ReferenceOption -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.ReferenceOption +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.manga.impl.Chapter.getChapterMetaMap import suwayomi.tachidesk.manga.model.dataclass.ChapterDataClass import suwayomi.tachidesk.manga.model.table.columns.truncatingVarchar diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/ExtensionTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/ExtensionTable.kt index 9aa02d1e..b73cfef2 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/ExtensionTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/ExtensionTable.kt @@ -7,7 +7,7 @@ package suwayomi.tachidesk.manga.model.table * 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 org.jetbrains.exposed.dao.id.IntIdTable +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable object ExtensionTable : IntIdTable() { val apkName = varchar("apk_name", 1024) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/MangaMetaTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/MangaMetaTable.kt index b4a7098a..cda6b7af 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/MangaMetaTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/MangaMetaTable.kt @@ -7,8 +7,8 @@ package suwayomi.tachidesk.manga.model.table * 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 org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.ReferenceOption +import org.jetbrains.exposed.v1.core.ReferenceOption +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable import suwayomi.tachidesk.manga.model.table.MangaMetaTable.ref /** diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/MangaTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/MangaTable.kt index e17b73b7..06c13931 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/MangaTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/MangaTable.kt @@ -9,8 +9,8 @@ package suwayomi.tachidesk.manga.model.table import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.UpdateStrategy -import org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.ResultRow +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable import suwayomi.tachidesk.manga.impl.Manga.getMangaMetaMap import suwayomi.tachidesk.manga.impl.MangaList.proxyThumbnailUrl import suwayomi.tachidesk.manga.model.dataclass.MangaDataClass diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/PageTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/PageTable.kt index 6135dc91..8e3bd582 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/PageTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/PageTable.kt @@ -7,8 +7,8 @@ package suwayomi.tachidesk.manga.model.table * 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 org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.ReferenceOption +import org.jetbrains.exposed.v1.core.ReferenceOption +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable import suwayomi.tachidesk.manga.model.table.columns.unlimitedVarchar object PageTable : IntIdTable() { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/SourceMetaTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/SourceMetaTable.kt index 3e6bc8a8..bc2eaa8f 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/SourceMetaTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/SourceMetaTable.kt @@ -7,8 +7,8 @@ package suwayomi.tachidesk.manga.model.table * 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 org.jetbrains.exposed.dao.id.IntIdTable -import suwayomi.tachidesk.manga.model.table.ChapterMetaTable.ref +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable +import suwayomi.tachidesk.manga.model.table.SourceMetaTable.ref /** * Metadata storage for clients, about Source with id == [ref]. diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/SourceTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/SourceTable.kt index 77a68e95..bdbaa547 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/SourceTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/SourceTable.kt @@ -7,7 +7,7 @@ package suwayomi.tachidesk.manga.model.table * 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 org.jetbrains.exposed.dao.id.IdTable +import org.jetbrains.exposed.v1.core.dao.id.IdTable object SourceTable : IdTable() { override val id = long("id").entityId() diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/TrackRecordTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/TrackRecordTable.kt index 392ab5cb..3d922fd4 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/TrackRecordTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/TrackRecordTable.kt @@ -7,8 +7,8 @@ package suwayomi.tachidesk.manga.model.table * 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 org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.ReferenceOption +import org.jetbrains.exposed.v1.core.ReferenceOption +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable import suwayomi.tachidesk.manga.model.table.columns.truncatingVarchar object TrackRecordTable : IntIdTable() { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/TrackSearchTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/TrackSearchTable.kt index 32572d5b..aae4ef43 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/TrackSearchTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/TrackSearchTable.kt @@ -7,14 +7,16 @@ package suwayomi.tachidesk.manga.model.table * 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 org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.batchInsert -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.statements.BatchUpdateStatement -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.dao.id.EntityID +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.statements.BatchUpdateStatement +import org.jetbrains.exposed.v1.jdbc.batchInsert +import org.jetbrains.exposed.v1.jdbc.selectAll +import org.jetbrains.exposed.v1.jdbc.statements.toExecutable +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.manga.impl.track.tracker.model.TrackSearch import suwayomi.tachidesk.manga.model.table.columns.truncatingVarchar @@ -69,30 +71,31 @@ fun List.insertAll(): List { val toUpdate = grouped[true] val toInsert = grouped[false]?.map { it.second } if (!toUpdate.isNullOrEmpty()) { - BatchUpdateStatement(TrackSearchTable).apply { - toUpdate.forEach { (id, trackSearch) -> - id ?: return@forEach - addBatch(EntityID(id, TrackSearchTable)) - this[TrackSearchTable.title] = trackSearch.title - this[TrackSearchTable.totalChapters] = trackSearch.total_chapters - this[TrackSearchTable.trackingUrl] = trackSearch.tracking_url - this[TrackSearchTable.coverUrl] = trackSearch.cover_url - this[TrackSearchTable.summary] = trackSearch.summary - this[TrackSearchTable.publishingStatus] = trackSearch.publishing_status - this[TrackSearchTable.publishingType] = trackSearch.publishing_type - this[TrackSearchTable.startDate] = trackSearch.start_date - this[TrackSearchTable.libraryId] = trackSearch.library_id - this[TrackSearchTable.lastChapterRead] = trackSearch.last_chapter_read - this[TrackSearchTable.status] = trackSearch.status - this[TrackSearchTable.score] = trackSearch.score - this[TrackSearchTable.startedReadingDate] = trackSearch.started_reading_date - this[TrackSearchTable.finishedReadingDate] = trackSearch.finished_reading_date - this[TrackSearchTable.private] = trackSearch.private - this[TrackSearchTable.authors] = trackSearch.authors.ifEmpty { null }?.joinToString(",") - this[TrackSearchTable.artists] = trackSearch.artists.ifEmpty { null }?.joinToString(",") - } - execute(this@transaction) - } + BatchUpdateStatement(TrackSearchTable) + .apply { + toUpdate.forEach { (id, trackSearch) -> + id ?: return@forEach + addBatch(EntityID(id, TrackSearchTable)) + this[TrackSearchTable.title] = trackSearch.title + this[TrackSearchTable.totalChapters] = trackSearch.total_chapters + this[TrackSearchTable.trackingUrl] = trackSearch.tracking_url + this[TrackSearchTable.coverUrl] = trackSearch.cover_url + this[TrackSearchTable.summary] = trackSearch.summary + this[TrackSearchTable.publishingStatus] = trackSearch.publishing_status + this[TrackSearchTable.publishingType] = trackSearch.publishing_type + this[TrackSearchTable.startDate] = trackSearch.start_date + this[TrackSearchTable.libraryId] = trackSearch.library_id + this[TrackSearchTable.lastChapterRead] = trackSearch.last_chapter_read + this[TrackSearchTable.status] = trackSearch.status + this[TrackSearchTable.score] = trackSearch.score + this[TrackSearchTable.startedReadingDate] = trackSearch.started_reading_date + this[TrackSearchTable.finishedReadingDate] = trackSearch.finished_reading_date + this[TrackSearchTable.private] = trackSearch.private + this[TrackSearchTable.authors] = trackSearch.authors.ifEmpty { null }?.joinToString(",") + this[TrackSearchTable.artists] = trackSearch.artists.ifEmpty { null }?.joinToString(",") + } + }.toExecutable() + .execute(this@transaction) } val insertedRows = if (!toInsert.isNullOrEmpty()) { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/columns/TruncatingVarCharColumn.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/columns/TruncatingVarCharColumn.kt index b5c897fa..fb6006f4 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/columns/TruncatingVarCharColumn.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/columns/TruncatingVarCharColumn.kt @@ -1,9 +1,9 @@ package suwayomi.tachidesk.manga.model.table.columns import io.github.oshai.kotlinlogging.KotlinLogging -import org.jetbrains.exposed.sql.Column -import org.jetbrains.exposed.sql.Table -import org.jetbrains.exposed.sql.VarCharColumnType +import org.jetbrains.exposed.v1.core.Column +import org.jetbrains.exposed.v1.core.Table +import org.jetbrains.exposed.v1.core.VarCharColumnType import suwayomi.tachidesk.graphql.types.DatabaseType import suwayomi.tachidesk.server.serverConfig diff --git a/server/src/main/kotlin/suwayomi/tachidesk/opds/impl/OpdsFeedBuilder.kt b/server/src/main/kotlin/suwayomi/tachidesk/opds/impl/OpdsFeedBuilder.kt index af759c27..595ae64f 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/opds/impl/OpdsFeedBuilder.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/opds/impl/OpdsFeedBuilder.kt @@ -1,7 +1,7 @@ package suwayomi.tachidesk.opds.impl import io.github.oshai.kotlinlogging.KotlinLogging -import org.jetbrains.exposed.sql.SortOrder +import org.jetbrains.exposed.v1.core.SortOrder import suwayomi.tachidesk.i18n.MR import suwayomi.tachidesk.manga.impl.MangaList.proxyThumbnailUrl import suwayomi.tachidesk.manga.model.table.ChapterTable diff --git a/server/src/main/kotlin/suwayomi/tachidesk/opds/repository/ChapterRepository.kt b/server/src/main/kotlin/suwayomi/tachidesk/opds/repository/ChapterRepository.kt index ed347de0..735f0778 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/opds/repository/ChapterRepository.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/opds/repository/ChapterRepository.kt @@ -1,14 +1,16 @@ package suwayomi.tachidesk.opds.repository -import org.jetbrains.exposed.sql.Column -import org.jetbrains.exposed.sql.JoinType -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.andWhere -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.Column +import org.jetbrains.exposed.v1.core.JoinType +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.greater +import org.jetbrains.exposed.v1.jdbc.andWhere +import org.jetbrains.exposed.v1.jdbc.select +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.manga.impl.chapter.getChapterDownloadReady import suwayomi.tachidesk.manga.model.table.ChapterTable import suwayomi.tachidesk.manga.model.table.MangaTable diff --git a/server/src/main/kotlin/suwayomi/tachidesk/opds/repository/MangaRepository.kt b/server/src/main/kotlin/suwayomi/tachidesk/opds/repository/MangaRepository.kt index d0b57c37..433aef3d 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/opds/repository/MangaRepository.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/opds/repository/MangaRepository.kt @@ -1,23 +1,26 @@ package suwayomi.tachidesk.opds.repository import eu.kanade.tachiyomi.source.model.MangasPage -import org.jetbrains.exposed.sql.Case -import org.jetbrains.exposed.sql.JoinType -import org.jetbrains.exposed.sql.Op -import org.jetbrains.exposed.sql.Query -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.SqlExpressionBuilder.like -import org.jetbrains.exposed.sql.alias -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.andWhere -import org.jetbrains.exposed.sql.intLiteral -import org.jetbrains.exposed.sql.lowerCase -import org.jetbrains.exposed.sql.max -import org.jetbrains.exposed.sql.or -import org.jetbrains.exposed.sql.sum -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.Case +import org.jetbrains.exposed.v1.core.JoinType +import org.jetbrains.exposed.v1.core.Op +import org.jetbrains.exposed.v1.core.ResultRow +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.alias +import org.jetbrains.exposed.v1.core.and +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.core.greater +import org.jetbrains.exposed.v1.core.inList +import org.jetbrains.exposed.v1.core.intLiteral +import org.jetbrains.exposed.v1.core.like +import org.jetbrains.exposed.v1.core.lowerCase +import org.jetbrains.exposed.v1.core.max +import org.jetbrains.exposed.v1.core.or +import org.jetbrains.exposed.v1.core.sum +import org.jetbrains.exposed.v1.jdbc.Query +import org.jetbrains.exposed.v1.jdbc.andWhere +import org.jetbrains.exposed.v1.jdbc.select +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.manga.impl.MangaList.insertOrUpdate import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource import suwayomi.tachidesk.manga.model.dataclass.toGenreList diff --git a/server/src/main/kotlin/suwayomi/tachidesk/opds/repository/NavigationRepository.kt b/server/src/main/kotlin/suwayomi/tachidesk/opds/repository/NavigationRepository.kt index 9b3a6daa..dca5ab4a 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/opds/repository/NavigationRepository.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/opds/repository/NavigationRepository.kt @@ -1,12 +1,14 @@ package suwayomi.tachidesk.opds.repository import dev.icerock.moko.resources.StringResource -import org.jetbrains.exposed.sql.JoinType -import org.jetbrains.exposed.sql.SortOrder -import org.jetbrains.exposed.sql.alias -import org.jetbrains.exposed.sql.count -import org.jetbrains.exposed.sql.countDistinct -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.JoinType +import org.jetbrains.exposed.v1.core.SortOrder +import org.jetbrains.exposed.v1.core.alias +import org.jetbrains.exposed.v1.core.count +import org.jetbrains.exposed.v1.core.countDistinct +import org.jetbrains.exposed.v1.core.eq +import org.jetbrains.exposed.v1.jdbc.select +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.i18n.MR import suwayomi.tachidesk.manga.impl.extension.Extension import suwayomi.tachidesk.manga.model.table.CategoryMangaTable diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/JavalinSetup.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/JavalinSetup.kt index 3cca3236..1f2835af 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/JavalinSetup.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/JavalinSetup.kt @@ -52,7 +52,6 @@ import java.net.URLEncoder import java.util.Locale import java.util.concurrent.CompletableFuture import kotlin.concurrent.thread -import kotlin.text.get import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.seconds diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/Migration.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/Migration.kt index c21e8c05..b7d07f1a 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/Migration.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/Migration.kt @@ -4,12 +4,11 @@ import android.app.Application import android.content.Context import io.github.oshai.kotlinlogging.KotlinLogging import suwayomi.tachidesk.manga.impl.update.IUpdater +import suwayomi.tachidesk.server.database.H2Migration import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.io.File import java.util.prefs.Preferences -import kotlin.collections.isNotEmpty -import kotlin.collections.orEmpty private fun migratePreferences( parent: String?, @@ -76,6 +75,14 @@ private fun migrateMangaDownloadDir(applicationDirs: ApplicationDirs) { } } +fun migrateH2DatabaseToV24240(applicationDirs: ApplicationDirs) { + H2Migration.migrate( + applicationDirs.dataRoot, + "1.4.200", + "2.4.240", + ) +} + private val MIGRATIONS = listOf Unit>>( "InitialMigration" to { applicationDirs -> @@ -85,6 +92,9 @@ private val MIGRATIONS = "FixGlobalUpdateScheduling" to { Injekt.get().deleteLastAutomatedUpdateTimestamp() }, + "MigrateH2DatabaseToV2.4.240" to { applicationDirs -> + migrateH2DatabaseToV24240(applicationDirs) + }, ) fun runMigrations(applicationDirs: ApplicationDirs) { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt index 7e1f5912..c293c558 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt @@ -391,6 +391,8 @@ fun applicationSetup() { "Localization service initialized. Supported languages: ${LocalizationHelper.getSupportedLocales()}" } + runMigrations(applicationDirs) + databaseUp() LocalSource.register() @@ -440,8 +442,6 @@ fun applicationSetup() { ignoreInitialValue = false, ) - runMigrations(applicationDirs) - setLogLevelFor("org.eclipse.jetty", Level.OFF) setLogLevelFor("com.zaxxer.hikari", Level.WARN) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBManager.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBManager.kt index 0345c303..34a12f1e 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBManager.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBManager.kt @@ -12,13 +12,13 @@ import com.zaxxer.hikari.HikariDataSource import de.neonew.exposed.migrations.loadMigrationsFrom import de.neonew.exposed.migrations.runMigrations import io.github.oshai.kotlinlogging.KotlinLogging -import org.jetbrains.exposed.sql.Database -import org.jetbrains.exposed.sql.DatabaseConfig -import org.jetbrains.exposed.sql.ExperimentalKeywordApi -import org.jetbrains.exposed.sql.Schema -import org.jetbrains.exposed.sql.SchemaUtils -import org.jetbrains.exposed.sql.transactions.TransactionManager -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.DatabaseConfig +import org.jetbrains.exposed.v1.core.ExperimentalKeywordApi +import org.jetbrains.exposed.v1.core.Schema +import org.jetbrains.exposed.v1.jdbc.Database +import org.jetbrains.exposed.v1.jdbc.SchemaUtils +import org.jetbrains.exposed.v1.jdbc.transactions.TransactionManager +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import suwayomi.tachidesk.graphql.types.DatabaseType import suwayomi.tachidesk.server.ApplicationDirs import suwayomi.tachidesk.server.ServerConfig @@ -79,7 +79,7 @@ object DBManager { fun setupDatabase(): Database { // Clean up existing connections - if (TransactionManager.isInitialized()) { + if (TransactionManager.currentOrNull() != null) { val currentDatabase = TransactionManager.currentOrNull()?.db if (currentDatabase != null) { TransactionManager.closeAndUnregister(currentDatabase) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBTransaction.util.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBTransaction.util.kt index 5c475df2..d468ad4e 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBTransaction.util.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBTransaction.util.kt @@ -1,15 +1,16 @@ package suwayomi.tachidesk.server.database -import org.jetbrains.exposed.sql.Transaction -import org.jetbrains.exposed.sql.transactions.TransactionManager -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.Transaction +import org.jetbrains.exposed.v1.jdbc.JdbcTransaction +import org.jetbrains.exposed.v1.jdbc.transactions.TransactionManager +import org.jetbrains.exposed.v1.jdbc.transactions.transaction /** * Performs the given transaction block inside the parent transaction or creates a new transaction if necessary. * * Any rollback or exception in the inner transaction will be propagated to the parent transaction. */ -fun dbTransaction(block: Transaction.() -> T): T { +fun dbTransaction(block: JdbcTransaction.() -> T): T { val currentTransaction = TransactionManager.currentOrNull() return if (currentTransaction == null) { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/H2Migration.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/H2Migration.kt new file mode 100644 index 00000000..b9029f40 --- /dev/null +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/H2Migration.kt @@ -0,0 +1,167 @@ +package suwayomi.tachidesk.server.database + +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.NetworkHelper +import io.github.oshai.kotlinlogging.KotlinLogging +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get +import java.net.URLClassLoader +import java.nio.file.Path +import kotlin.io.path.Path +import kotlin.io.path.absolutePathString +import kotlin.io.path.copyTo +import kotlin.io.path.createDirectories +import kotlin.io.path.deleteExisting +import kotlin.io.path.div +import kotlin.io.path.exists +import kotlin.io.path.name +import kotlin.io.path.notExists +import kotlin.io.path.outputStream + +object H2Migration { + private val logger = KotlinLogging.logger {} + + private val client by lazy { + Injekt.get().client + } + + private const val TOOL_VERSION = "1.8" + + private const val TOOL_URL = + "https://manticore-projects.com/download/H2MigrationTool-$TOOL_VERSION/H2MigrationTool-$TOOL_VERSION-all.jar" + + private const val MAVEN_BASE = + "https://repo1.maven.org/maven2/com/h2database/h2" + + fun migrate( + rootDir: String, + h2Old: String, + h2New: String, + ) { + val dbBase = "$rootDir/database" + val mvStore = Path("$dbBase.mv.db") + if (mvStore.notExists()) { + logger.info { "No H2 database found. Skipping migration." } + return + } + + val script = Path("$dbBase.${h2Old.substringAfterLast('.')}.sql") + + // Backup original database. + val backup = Path("$dbBase.mv.db.${h2Old.substringAfterLast('.')}.backup") + mvStore.copyTo(backup, overwrite = true) + logger.info { "Created backup: ${backup.absolutePathString()}" } + + val toolsDir = Path(rootDir) / "bin" / "h2-migration-tools" + val libsDir = toolsDir / "h2libs" + libsDir.createDirectories() + + // Download migration tool + val migrationJar = + toolsDir.resolve("H2MigrationTool-$TOOL_VERSION-all.jar") + downloadIfNeeded( + TOOL_URL, + migrationJar, + ) + downloadIfNeeded( + "$MAVEN_BASE/$h2Old/h2-$h2Old.jar", + libsDir.resolve("h2-$h2Old.bin"), + ) + downloadIfNeeded( + "$MAVEN_BASE/$h2New/h2-$h2New.jar", + libsDir.resolve("h2-$h2New.bin"), + ) + + runMigrationTool( + migrationJar = migrationJar, + libsDir = libsDir, + mvStore = mvStore, + script = script, + h2Old = h2Old, + h2New = h2New, + ) + + // Move database to proper path + val newDatabase = Path(rootDir, "database.${h2New.substringAfterLast('.')}.mv.db") + newDatabase.copyTo(mvStore, overwrite = true) + newDatabase.deleteExisting() + + logger.info { "H2 migration completed successfully." } + } + + private fun downloadIfNeeded( + url: String, + output: Path, + ) { + if (output.exists()) { + logger.debug { "Already downloaded: ${output.name}" } + return + } + + client + .newCall(GET(url)) + .execute() + .use { response -> + + if (!response.isSuccessful) { + throw RuntimeException( + "Failed to download $url " + + "(HTTP ${response.code})", + ) + } + + output.outputStream().use { out -> + response.body.byteStream().copyTo(out) + } + } + + logger.info { "Saved: ${output.absolutePathString()}" } + } + + private fun runMigrationTool( + migrationJar: Path, + libsDir: Path, + mvStore: Path, + script: Path, + h2Old: String, + h2New: String, + ) { + URLClassLoader( + arrayOf(migrationJar.toUri().toURL()), + javaClass.classLoader, + ).use { classLoader -> + val clazz = + classLoader.loadClass("com.manticore.h2.H2MigrationTool") + + val main = + clazz.getMethod("main", Array::class.java) + + main.invoke( + null, + arrayOf( + // h2 driver dir + "-l", + libsDir.absolutePathString(), + // from version + "-f", + h2Old, + // to version + "-t", + h2New, + // user + "-u", + "", + // password + "-p", + "", + // database.mv.db + "-d", + mvStore.absolutePathString(), + // database backup in SQL + "-s", + script.absolutePathString(), + ), + ) + } + } +} diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0001_Initial.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0001_Initial.kt index bb18c621..294575b3 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0001_Initial.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0001_Initial.kt @@ -9,9 +9,9 @@ package suwayomi.tachidesk.server.database.migration import de.neonew.exposed.migrations.helpers.AddTableMigration import eu.kanade.tachiyomi.source.model.SManga -import org.jetbrains.exposed.dao.id.IdTable -import org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.Table +import org.jetbrains.exposed.v1.core.Table +import org.jetbrains.exposed.v1.core.dao.id.IdTable +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable /** initial migration, create all tables */ @Suppress("ClassName", "unused") diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0004_AnimeTablesBatch1.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0004_AnimeTablesBatch1.kt index 7b3379c5..9e3121db 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0004_AnimeTablesBatch1.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0004_AnimeTablesBatch1.kt @@ -8,9 +8,9 @@ package suwayomi.tachidesk.server.database.migration * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import de.neonew.exposed.migrations.helpers.AddTableMigration -import org.jetbrains.exposed.dao.id.IdTable -import org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.Table +import org.jetbrains.exposed.v1.core.Table +import org.jetbrains.exposed.v1.core.dao.id.IdTable +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable @Suppress("ClassName", "unused") class M0004_AnimeTablesBatch1 : AddTableMigration() { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0005_AnimeTablesBatch2.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0005_AnimeTablesBatch2.kt index a1aba284..f664e38d 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0005_AnimeTablesBatch2.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0005_AnimeTablesBatch2.kt @@ -10,8 +10,8 @@ package suwayomi.tachidesk.server.database.migration * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import de.neonew.exposed.migrations.helpers.AddTableMigration -import org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.Table +import org.jetbrains.exposed.v1.core.Table +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable @Suppress("ClassName", "unused") class M0005_AnimeTablesBatch2 : AddTableMigration() { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0006_AnimeTablesBatch3.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0006_AnimeTablesBatch3.kt index 4ab592b1..f6db0488 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0006_AnimeTablesBatch3.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0006_AnimeTablesBatch3.kt @@ -10,8 +10,8 @@ package suwayomi.tachidesk.server.database.migration * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import de.neonew.exposed.migrations.helpers.AddTableMigration -import org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.Table +import org.jetbrains.exposed.v1.core.Table +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable @Suppress("ClassName", "unused") class M0006_AnimeTablesBatch3 : AddTableMigration() { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0010_MangaAndChapterMeta.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0010_MangaAndChapterMeta.kt index 9808b8b7..014788c1 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0010_MangaAndChapterMeta.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0010_MangaAndChapterMeta.kt @@ -8,9 +8,9 @@ package suwayomi.tachidesk.server.database.migration * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import de.neonew.exposed.migrations.helpers.AddTableMigration -import org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.ReferenceOption -import org.jetbrains.exposed.sql.Table +import org.jetbrains.exposed.v1.core.ReferenceOption +import org.jetbrains.exposed.v1.core.Table +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable import suwayomi.tachidesk.manga.model.table.ChapterTable import suwayomi.tachidesk.manga.model.table.MangaTable diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0021_GlobalAndCategoryMeta.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0021_GlobalAndCategoryMeta.kt index 2bd69e96..98c75e1e 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0021_GlobalAndCategoryMeta.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0021_GlobalAndCategoryMeta.kt @@ -8,9 +8,9 @@ package suwayomi.tachidesk.server.database.migration * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import de.neonew.exposed.migrations.helpers.AddTableMigration -import org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.ReferenceOption -import org.jetbrains.exposed.sql.Table +import org.jetbrains.exposed.v1.core.ReferenceOption +import org.jetbrains.exposed.v1.core.Table +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable import suwayomi.tachidesk.manga.model.table.ChapterTable @Suppress("ClassName", "unused") diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0023_CategoryMetaRefFix.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0023_CategoryMetaRefFix.kt index 3fe87ab7..f0807181 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0023_CategoryMetaRefFix.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0023_CategoryMetaRefFix.kt @@ -10,7 +10,7 @@ package suwayomi.tachidesk.server.database.migration * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import de.neonew.exposed.migrations.helpers.SQLMigration -import org.jetbrains.exposed.sql.transactions.TransactionManager +import org.jetbrains.exposed.v1.jdbc.transactions.TransactionManager @Suppress("ClassName", "unused") class M0023_CategoryMetaRefFix : SQLMigration() { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0033_TrackRecord.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0033_TrackRecord.kt index 7485fde4..b89407ea 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0033_TrackRecord.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0033_TrackRecord.kt @@ -8,9 +8,9 @@ package suwayomi.tachidesk.server.database.migration * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import de.neonew.exposed.migrations.helpers.AddTableMigration -import org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.ReferenceOption -import org.jetbrains.exposed.sql.Table +import org.jetbrains.exposed.v1.core.ReferenceOption +import org.jetbrains.exposed.v1.core.Table +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable import suwayomi.tachidesk.manga.model.table.MangaTable @Suppress("ClassName", "unused") diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0035_TrackSearch.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0035_TrackSearch.kt index 1aed1dfc..9e364b43 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0035_TrackSearch.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0035_TrackSearch.kt @@ -8,8 +8,8 @@ package suwayomi.tachidesk.server.database.migration * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import de.neonew.exposed.migrations.helpers.AddTableMigration -import org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.Table +import org.jetbrains.exposed.v1.core.Table +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable @Suppress("ClassName", "unused") class M0035_TrackSearch : AddTableMigration() { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0036_SourceMeta.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0036_SourceMeta.kt index 7595d463..bc711d3e 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0036_SourceMeta.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0036_SourceMeta.kt @@ -8,8 +8,8 @@ package suwayomi.tachidesk.server.database.migration * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import de.neonew.exposed.migrations.helpers.AddTableMigration -import org.jetbrains.exposed.dao.id.IntIdTable -import org.jetbrains.exposed.sql.Table +import org.jetbrains.exposed.v1.core.Table +import org.jetbrains.exposed.v1.core.dao.id.IntIdTable @Suppress("ClassName", "unused") class M0036_SourceMeta : AddTableMigration() { diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0053_TrackersFixIds.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0053_TrackersFixIds.kt index 8ad83881..b3475461 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0053_TrackersFixIds.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0053_TrackersFixIds.kt @@ -4,8 +4,6 @@ package suwayomi.tachidesk.server.database.migration import de.neonew.exposed.migrations.helpers.SQLMigration import suwayomi.tachidesk.graphql.types.DatabaseType -import suwayomi.tachidesk.server.database.migration.helpers.MAYBE_TYPE_PREFIX -import suwayomi.tachidesk.server.database.migration.helpers.UNLIMITED_TEXT import suwayomi.tachidesk.server.database.migration.helpers.toSqlName import suwayomi.tachidesk.server.serverConfig diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/RenameFieldMigration.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/RenameFieldMigration.kt index c2f5bb79..45a50e66 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/RenameFieldMigration.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/RenameFieldMigration.kt @@ -1,7 +1,7 @@ package suwayomi.tachidesk.server.database.migration.helpers import de.neonew.exposed.migrations.helpers.SQLMigration -import org.jetbrains.exposed.sql.transactions.TransactionManager +import org.jetbrains.exposed.v1.jdbc.transactions.TransactionManager import suwayomi.tachidesk.graphql.types.DatabaseType import suwayomi.tachidesk.server.serverConfig diff --git a/server/src/main/kotlin/suwayomi/tachidesk/util/ConversionUtil.kt b/server/src/main/kotlin/suwayomi/tachidesk/util/ConversionUtil.kt index 46051ab8..8d1b9e26 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/util/ConversionUtil.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/util/ConversionUtil.kt @@ -10,14 +10,12 @@ import okhttp3.MediaType.Companion.toMediaType import okhttp3.MultipartBody import okhttp3.RequestBody.Companion.asRequestBody import suwayomi.tachidesk.graphql.types.DownloadConversion -import suwayomi.tachidesk.manga.impl.util.storage.ImageUtil import uy.kohesive.injekt.injectLazy import java.awt.image.BufferedImage import java.io.File import java.io.InputStream import java.nio.file.Files import javax.imageio.ImageIO -import kotlin.getValue object ConversionUtil { val logger = KotlinLogging.logger {} diff --git a/server/src/test/kotlin/suwayomi/tachidesk/SafePathTest.kt b/server/src/test/kotlin/suwayomi/tachidesk/SafePathTest.kt index a50807f5..c9842d77 100644 --- a/server/src/test/kotlin/suwayomi/tachidesk/SafePathTest.kt +++ b/server/src/test/kotlin/suwayomi/tachidesk/SafePathTest.kt @@ -47,4 +47,4 @@ class SafePathTest { assertEquals(240, result.toByteArray(Charsets.UTF_8).size) assertTrue(result.toByteArray(Charsets.UTF_8).size == 240) } -} \ No newline at end of file +} diff --git a/server/src/test/kotlin/suwayomi/tachidesk/manga/controller/UpdateControllerTest.kt b/server/src/test/kotlin/suwayomi/tachidesk/manga/controller/UpdateControllerTest.kt index 919a66d2..577b13bc 100644 --- a/server/src/test/kotlin/suwayomi/tachidesk/manga/controller/UpdateControllerTest.kt +++ b/server/src/test/kotlin/suwayomi/tachidesk/manga/controller/UpdateControllerTest.kt @@ -8,8 +8,8 @@ import suwayomi.tachidesk.test.ApplicationTest // import io.mockk.mockk // import io.mockk.verify // import kotlinx.coroutines.runBlocking -// import org.jetbrains.exposed.sql.insertAndGetId -// import org.jetbrains.exposed.sql.transactions.transaction +// import org.jetbrains.exposed.v1.jdbc.insertAndGetId +// import org.jetbrains.exposed.v1.jdbc.transactions.transaction // import org.junit.jupiter.api.AfterEach // import org.junit.jupiter.api.Assertions.assertEquals // import org.junit.jupiter.api.Test diff --git a/server/src/test/kotlin/suwayomi/tachidesk/manga/impl/update/TestUpdater.kt b/server/src/test/kotlin/suwayomi/tachidesk/manga/impl/update/TestUpdater.kt index c600cb91..a1c2842d 100644 --- a/server/src/test/kotlin/suwayomi/tachidesk/manga/impl/update/TestUpdater.kt +++ b/server/src/test/kotlin/suwayomi/tachidesk/manga/impl/update/TestUpdater.kt @@ -2,7 +2,6 @@ package suwayomi.tachidesk.manga.impl.update import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.update import suwayomi.tachidesk.manga.model.dataclass.CategoryDataClass import suwayomi.tachidesk.manga.model.dataclass.MangaDataClass diff --git a/server/src/test/kotlin/suwayomi/tachidesk/test/ApplicationTest.kt b/server/src/test/kotlin/suwayomi/tachidesk/test/ApplicationTest.kt index d97275ef..9adab3bc 100644 --- a/server/src/test/kotlin/suwayomi/tachidesk/test/ApplicationTest.kt +++ b/server/src/test/kotlin/suwayomi/tachidesk/test/ApplicationTest.kt @@ -12,7 +12,7 @@ import eu.kanade.tachiyomi.createAppModule import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.source.local.LocalSource import io.github.oshai.kotlinlogging.KotlinLogging -import org.jetbrains.exposed.sql.Database +import org.jetbrains.exposed.v1.jdbc.Database import org.junit.jupiter.api.BeforeAll import org.koin.core.context.startKoin import suwayomi.tachidesk.server.ApplicationDirs diff --git a/server/src/test/kotlin/suwayomi/tachidesk/test/TestUtils.kt b/server/src/test/kotlin/suwayomi/tachidesk/test/TestUtils.kt index 64ea67ec..eb59d937 100644 --- a/server/src/test/kotlin/suwayomi/tachidesk/test/TestUtils.kt +++ b/server/src/test/kotlin/suwayomi/tachidesk/test/TestUtils.kt @@ -11,11 +11,11 @@ import ch.qos.logback.classic.Level import eu.kanade.tachiyomi.source.model.SManga import io.github.oshai.kotlinlogging.DelegatingKLogger import io.github.oshai.kotlinlogging.KotlinLogging -import org.jetbrains.exposed.dao.id.IdTable -import org.jetbrains.exposed.sql.batchInsert -import org.jetbrains.exposed.sql.deleteAll -import org.jetbrains.exposed.sql.insertAndGetId -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.v1.core.dao.id.IdTable +import org.jetbrains.exposed.v1.jdbc.batchInsert +import org.jetbrains.exposed.v1.jdbc.deleteAll +import org.jetbrains.exposed.v1.jdbc.insertAndGetId +import org.jetbrains.exposed.v1.jdbc.transactions.transaction import org.slf4j.Logger import suwayomi.tachidesk.manga.model.table.ChapterTable import suwayomi.tachidesk.manga.model.table.MangaTable From 03a95e66523cb82012ad3f9563d2c61569f625f6 Mon Sep 17 00:00:00 2001 From: Mitchell Syer Date: Tue, 12 May 2026 17:22:35 -0400 Subject: [PATCH 05/13] Fix New Databases (#2016) * Standardize toSqlName * Rename Meta Key db field since KEY is now a reserved name in H2 * Changelog entry * Use toSqlName * Forgot this key * Catch any exception --- CHANGELOG.md | 2 +- .../global/model/table/GlobalMetaTable.kt | 2 +- .../manga/model/table/CategoryMetaTable.kt | 2 +- .../manga/model/table/ChapterMetaTable.kt | 2 +- .../manga/model/table/MangaMetaTable.kt | 2 +- .../manga/model/table/SourceMetaTable.kt | 2 +- .../tachidesk/server/database/DBManager.kt | 3 +- .../migration/M0023_CategoryMetaRefFix.kt | 9 +---- .../migration/M0049_FixDuplicatedMetas.kt | 6 ++- .../migration/M0055_RenameMetaKeys.kt | 38 +++++++++++++++++++ .../migration/helpers/RenameFieldMigration.kt | 8 ---- .../database/migration/helpers/ToSqlName.kt | 10 +++++ 12 files changed, 60 insertions(+), 26 deletions(-) create mode 100644 server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0055_RenameMetaKeys.kt create mode 100644 server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/ToSqlName.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 659e9e2e..8c833651 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - . ### Changed -- . +- (Database/H2) Use the latest H2 database engine ### Fixed - (CloudFlareInterceptor) Don't send the `cf_clearance` cookie back to Flaresolverr diff --git a/server/src/main/kotlin/suwayomi/tachidesk/global/model/table/GlobalMetaTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/global/model/table/GlobalMetaTable.kt index ee99bf5d..e3f079da 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/global/model/table/GlobalMetaTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/global/model/table/GlobalMetaTable.kt @@ -13,6 +13,6 @@ import org.jetbrains.exposed.v1.core.dao.id.IntIdTable * Metadata storage for clients, server/global level. */ object GlobalMetaTable : IntIdTable() { - val key = varchar("key", 256) + val key = varchar("meta_key", 256) val value = varchar("value", 4096) } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryMetaTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryMetaTable.kt index 5067e931..d1513f35 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryMetaTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/CategoryMetaTable.kt @@ -15,7 +15,7 @@ import suwayomi.tachidesk.manga.model.table.CategoryMetaTable.ref * Metadata storage for clients, about Category with id == [ref]. */ object CategoryMetaTable : IntIdTable() { - val key = varchar("key", 256) + val key = varchar("meta_key", 256) val value = varchar("value", 4096) val ref = reference("category_ref", CategoryTable, ReferenceOption.CASCADE) } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/ChapterMetaTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/ChapterMetaTable.kt index d400faac..24a90fc3 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/ChapterMetaTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/ChapterMetaTable.kt @@ -26,7 +26,7 @@ import suwayomi.tachidesk.manga.model.table.ChapterMetaTable.ref * } */ object ChapterMetaTable : IntIdTable() { - val key = varchar("key", 256) + val key = varchar("meta_key", 256) val value = varchar("value", 4096) val ref = reference("chapter_ref", ChapterTable, ReferenceOption.CASCADE) } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/MangaMetaTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/MangaMetaTable.kt index cda6b7af..b89b4597 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/MangaMetaTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/MangaMetaTable.kt @@ -26,7 +26,7 @@ import suwayomi.tachidesk.manga.model.table.MangaMetaTable.ref * } */ object MangaMetaTable : IntIdTable() { - val key = varchar("key", 256) + val key = varchar("meta_key", 256) val value = varchar("value", 4096) val ref = reference("manga_ref", MangaTable, ReferenceOption.CASCADE) } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/SourceMetaTable.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/SourceMetaTable.kt index bc2eaa8f..359da81e 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/SourceMetaTable.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/model/table/SourceMetaTable.kt @@ -14,7 +14,7 @@ import suwayomi.tachidesk.manga.model.table.SourceMetaTable.ref * Metadata storage for clients, about Source with id == [ref]. */ object SourceMetaTable : IntIdTable() { - val key = varchar("key", 256) + val key = varchar("meta_key", 256) val value = varchar("value", 4096) val ref = long("source_ref") } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBManager.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBManager.kt index 34a12f1e..a1cc41d2 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBManager.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBManager.kt @@ -27,7 +27,6 @@ import suwayomi.tachidesk.server.util.ExitCode import suwayomi.tachidesk.server.util.shutdownApp import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get -import java.sql.SQLException import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds @@ -184,7 +183,7 @@ fun databaseUp() { } val migrations = loadMigrationsFrom("suwayomi.tachidesk.server.database.migration", ServerConfig::class.java) runMigrations(migrations) - } catch (e: SQLException) { + } catch (e: Exception) { logger.error(e) { "Error up-to-database migration" } if (System.getProperty("crashOnFailedMigration").toBoolean()) { shutdownApp(ExitCode.DbMigrationFailure) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0023_CategoryMetaRefFix.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0023_CategoryMetaRefFix.kt index f0807181..6292553f 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0023_CategoryMetaRefFix.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0023_CategoryMetaRefFix.kt @@ -10,17 +10,10 @@ package suwayomi.tachidesk.server.database.migration * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import de.neonew.exposed.migrations.helpers.SQLMigration -import org.jetbrains.exposed.v1.jdbc.transactions.TransactionManager +import suwayomi.tachidesk.server.database.migration.helpers.toSqlName @Suppress("ClassName", "unused") class M0023_CategoryMetaRefFix : SQLMigration() { - fun String.toSqlName(): String = - TransactionManager.defaultDatabase!!.identifierManager.let { - it.quoteIfNecessary( - it.inProperCase(this), - ) - } - private val CategoryMetaTable by lazy { "CategoryMeta".toSqlName() } private val CategoryRefColumn by lazy { "category_ref".toSqlName() } private val CategoryTable by lazy { "Category".toSqlName() } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0049_FixDuplicatedMetas.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0049_FixDuplicatedMetas.kt index a35ff941..1916ddd1 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0049_FixDuplicatedMetas.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0049_FixDuplicatedMetas.kt @@ -8,6 +8,7 @@ package suwayomi.tachidesk.server.database.migration * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import de.neonew.exposed.migrations.helpers.SQLMigration +import suwayomi.tachidesk.server.database.migration.helpers.toSqlName @Suppress("ClassName", "unused") class M0049_FixDuplicatedMetas : SQLMigration() { @@ -15,7 +16,7 @@ class M0049_FixDuplicatedMetas : SQLMigration() { table: String, refColumn: String? = null, ): String { - val groupBy = listOfNotNull(refColumn, "KEY").joinToString(", ") + val groupBy = listOfNotNull(refColumn, "KEY".toSqlName()).joinToString(", ") return """ DELETE FROM $table @@ -30,10 +31,11 @@ class M0049_FixDuplicatedMetas : SQLMigration() { """.trimIndent() } - override val sql: String = + override val sql: String by lazy { createMigrationForTable("CATEGORYMETA", "CATEGORY_REF") + createMigrationForTable("CHAPTERMETA", "CHAPTER_REF") + createMigrationForTable("GLOBALMETA") + createMigrationForTable("MANGAMETA", "MANGA_REF") + createMigrationForTable("SOURCEMETA", "SOURCE_REF") + } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0055_RenameMetaKeys.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0055_RenameMetaKeys.kt new file mode 100644 index 00000000..3e6d9f46 --- /dev/null +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/M0055_RenameMetaKeys.kt @@ -0,0 +1,38 @@ +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.SQLMigration +import suwayomi.tachidesk.graphql.types.DatabaseType +import suwayomi.tachidesk.server.database.migration.helpers.toSqlName +import suwayomi.tachidesk.server.serverConfig + +@Suppress("ClassName", "unused") +class M0055_RenameMetaKeys : SQLMigration() { + fun postgresRename(table: String): String = + "ALTER TABLE $table " + + "RENAME COLUMN " + "KEY".toSqlName() + " TO META_KEY;" + + fun h2Rename(table: String): String = + "ALTER TABLE $table " + + "ALTER COLUMN " + "KEY".toSqlName() + " RENAME TO META_KEY;" + + fun createRenameMigration(table: String): String = + when (serverConfig.databaseType.value) { + DatabaseType.H2 -> h2Rename(table.toSqlName()) + DatabaseType.POSTGRESQL -> postgresRename(table.toSqlName()) + } + + override val sql: String by lazy { + createRenameMigration("CATEGORYMETA") + + createRenameMigration("CHAPTERMETA") + + createRenameMigration("GLOBALMETA") + + createRenameMigration("MANGAMETA") + + createRenameMigration("SOURCEMETA") + } +} diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/RenameFieldMigration.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/RenameFieldMigration.kt index 45a50e66..6717e69c 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/RenameFieldMigration.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/RenameFieldMigration.kt @@ -1,17 +1,9 @@ package suwayomi.tachidesk.server.database.migration.helpers import de.neonew.exposed.migrations.helpers.SQLMigration -import org.jetbrains.exposed.v1.jdbc.transactions.TransactionManager import suwayomi.tachidesk.graphql.types.DatabaseType import suwayomi.tachidesk.server.serverConfig -fun String.toSqlName(): String = - TransactionManager.current().db.identifierManager.let { - it.quoteIfNecessary( - it.inProperCase(this), - ) - } - abstract class RenameFieldMigration( tableName: String, originalName: String, diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/ToSqlName.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/ToSqlName.kt new file mode 100644 index 00000000..4e94f438 --- /dev/null +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/migration/helpers/ToSqlName.kt @@ -0,0 +1,10 @@ +package suwayomi.tachidesk.server.database.migration.helpers + +import org.jetbrains.exposed.v1.jdbc.transactions.TransactionManager + +fun String.toSqlName(): String = + TransactionManager.current().db.identifierManager.let { + it.quoteIfNecessary( + it.inProperCase(this), + ) + } From e93efa9627fbcd60c33a589d6698fbf3434f0961 Mon Sep 17 00:00:00 2001 From: Mitchell Syer Date: Tue, 12 May 2026 19:59:06 -0400 Subject: [PATCH 06/13] Fix Database Types as Needed (#2020) --- .../tachidesk/server/database/H2Migration.kt | 124 ++++++++++++++---- 1 file changed, 95 insertions(+), 29 deletions(-) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/H2Migration.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/H2Migration.kt index b9029f40..9e828ecd 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/H2Migration.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/H2Migration.kt @@ -9,9 +9,12 @@ import java.net.URLClassLoader import java.nio.file.Path import kotlin.io.path.Path import kotlin.io.path.absolutePathString +import kotlin.io.path.bufferedReader +import kotlin.io.path.bufferedWriter import kotlin.io.path.copyTo import kotlin.io.path.createDirectories import kotlin.io.path.deleteExisting +import kotlin.io.path.deleteIfExists import kotlin.io.path.div import kotlin.io.path.exists import kotlin.io.path.name @@ -46,6 +49,10 @@ object H2Migration { } val script = Path("$dbBase.${h2Old.substringAfterLast('.')}.sql") + script.deleteIfExists() + + val modifiedScript = Path("$dbBase.${h2Old.substringAfterLast('.')}.modified.sql") + modifiedScript.deleteIfExists() // Backup original database. val backup = Path("$dbBase.mv.db.${h2Old.substringAfterLast('.')}.backup") @@ -72,19 +79,32 @@ object H2Migration { libsDir.resolve("h2-$h2New.bin"), ) + // Delete attempted migration if failed previously + val newDatabase = Path(rootDir, "database.${h2New.substringAfterLast('.')}.mv.db") + newDatabase.deleteIfExists() + + val modifiedNewDatabase = Path(rootDir, "database.${h2Old.substringAfterLast('.')}.modified.${h2New.substringAfterLast('.')}.mv.db") + modifiedNewDatabase.deleteIfExists() + runMigrationTool( migrationJar = migrationJar, libsDir = libsDir, mvStore = mvStore, script = script, + modifiedScript = modifiedScript, h2Old = h2Old, h2New = h2New, ) // Move database to proper path - val newDatabase = Path(rootDir, "database.${h2New.substringAfterLast('.')}.mv.db") - newDatabase.copyTo(mvStore, overwrite = true) - newDatabase.deleteExisting() + if (modifiedNewDatabase.exists()) { + modifiedNewDatabase.copyTo(mvStore, overwrite = true) + modifiedNewDatabase.deleteExisting() + newDatabase.deleteIfExists() + } else { + newDatabase.copyTo(mvStore, overwrite = true) + newDatabase.deleteExisting() + } logger.info { "H2 migration completed successfully." } } @@ -123,6 +143,7 @@ object H2Migration { libsDir: Path, mvStore: Path, script: Path, + modifiedScript: Path, h2Old: String, h2New: String, ) { @@ -136,32 +157,77 @@ object H2Migration { val main = clazz.getMethod("main", Array::class.java) - main.invoke( - null, - arrayOf( - // h2 driver dir - "-l", - libsDir.absolutePathString(), - // from version - "-f", - h2Old, - // to version - "-t", - h2New, - // user - "-u", - "", - // password - "-p", - "", - // database.mv.db - "-d", - mvStore.absolutePathString(), - // database backup in SQL - "-s", - script.absolutePathString(), - ), - ) + try { + main.invoke( + null, + arrayOf( + // h2 driver dir + "-l", + libsDir.absolutePathString(), + // from version + "-f", + h2Old, + // to version + "-t", + h2New, + // user + "-u", + "", + // password + "-p", + "", + // database.mv.db + "-d", + mvStore.absolutePathString(), + // database backup in SQL + "-s", + script.absolutePathString(), + ), + ) + } catch (e: Exception) { + // Modify raw .sql file as needed for compatibility + if (e.stackTraceToString().contains("Unknown data type: \"DATETIME\"; SQL statement:") && script.exists()) { + script.bufferedReader().use { reader -> + modifiedScript.bufferedWriter().use { writer -> + reader.forEachLine { line -> + writer.write( + line.replace( + " \"EXECUTED_AT\" DATETIME(9) NOT NULL", + " \"EXECUTED_AT\" TIMESTAMP(9) NOT NULL", + ), + ) + writer.newLine() + } + } + } + + main.invoke( + null, + arrayOf( + // h2 driver dir + "-l", + libsDir.absolutePathString(), + // from version + "-f", + h2Old, + // to version + "-t", + h2New, + // user + "-u", + "", + // password + "-p", + "", + // database.mv.db + "-d", + modifiedScript.absolutePathString(), + ), + ) + } else { + throw e + } + } } } } From 81fb8c395d79834f0d1dfe47fe31140a3929a3b1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 May 2026 11:43:46 -0400 Subject: [PATCH 07/13] Update Gradle to v9.5.1 (#2015) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b52fb7e7..df6a6ad7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip networkTimeout=10000 retries=0 retryBackOffMs=500 From 75d8d172aa9194c56223a806ef50141672152488 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 May 2026 11:44:00 -0400 Subject: [PATCH 08/13] Update dependency org.slf4j:slf4j-api to v2.0.18 (#2017) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9ba2c0fc..359fa83b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -37,7 +37,7 @@ serialization-xml-core = { module = "io.github.pdvrieze.xmlutil:core", version.r serialization-xml = { module = "io.github.pdvrieze.xmlutil:serialization-jvm", version.ref = "xmlserialization" } # Logging -slf4japi = "org.slf4j:slf4j-api:2.0.17" +slf4japi = "org.slf4j:slf4j-api:2.0.18" logback = "ch.qos.logback:logback-classic:1.5.32" kotlinlogging = "io.github.oshai:kotlin-logging-jvm:8.0.02" From c4711dec00e8cc21ab451bff05fa1eb72ffa4fcc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 May 2026 11:44:18 -0400 Subject: [PATCH 09/13] Update dependency com.github.junrar:junrar to v7.6.0 (#2022) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 359fa83b..222e7fb2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -116,7 +116,7 @@ appdirs = "ca.gosyer:kotlin-multiplatform-appdirs:2.0.0" cache4k = "io.github.reactivecircus.cache4k:cache4k:0.14.0" zip4j = "net.lingala.zip4j:zip4j:2.11.6" commonscompress = "org.apache.commons:commons-compress:1.28.0" -junrar = "com.github.junrar:junrar:7.5.10" +junrar = "com.github.junrar:junrar:7.6.0" # AES/CBC/PKCS7Padding Cypher provider bouncycastle = "org.bouncycastle:bcprov-jdk18on:1.84" From 740db4f1ab0bbf3b646ab462af489295896f9bdc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 14 May 2026 11:44:34 -0400 Subject: [PATCH 10/13] Update javalin to v7.2.2 (#2026) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 222e7fb2..b38ee281 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,7 +4,7 @@ coroutines = "1.11.0" serialization = "1.11.0" jvmTarget = "21" okhttp = "5.3.2" # Major version is locked by Tachiyomi extensions -javalin = "7.2.0" +javalin = "7.2.2" jte = "3.2.4" jackson = "3.1.3" # jackson version locked by javalin, ref: `io.javalin.core.util.OptionalDependency` exposed = "1.2.0" From 82df985201d07460201ea49fba74fd4d2f3e0562 Mon Sep 17 00:00:00 2001 From: Mitchell Syer Date: Thu, 14 May 2026 11:44:52 -0400 Subject: [PATCH 11/13] Crash on startup if an unrecoverable error happens (#2019) * Crash on startup if an unrecoverable error happens * Changelog --- .github/workflows/build_pull_request.yml | 4 +- CHANGELOG.md | 1 + .../suwayomi/tachidesk/server/Migration.kt | 48 +++++++++++-------- .../suwayomi/tachidesk/server/ServerSetup.kt | 9 +++- .../tachidesk/server/database/DBManager.kt | 4 +- .../suwayomi/tachidesk/server/util/AppExit.kt | 4 ++ 6 files changed, 43 insertions(+), 27 deletions(-) diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml index 24b4b05d..210e1135 100644 --- a/.github/workflows/build_pull_request.yml +++ b/.github/workflows/build_pull_request.yml @@ -67,7 +67,7 @@ jobs: export LD_PRELOAD="$(pwd)/scripts/resources/catch_abort.so" JAR=$(ls ./server/build/*.jar| head -1) set +e - timeout 30s java -DcrashOnFailedMigration=true \ + timeout 30s java \ -Dsuwayomi.tachidesk.config.server.systemTrayEnabled=false \ -Dsuwayomi.tachidesk.config.server.initialOpenInBrowserEnabled=false \ -Dsuwayomi.tachidesk.config.server.databaseType=POSTGRESQL \ @@ -83,7 +83,7 @@ jobs: exit "$ecode" fi - timeout 30s java -DcrashOnFailedMigration=true \ + timeout 30s java \ -Dsuwayomi.tachidesk.config.server.systemTrayEnabled=false \ -Dsuwayomi.tachidesk.config.server.initialOpenInBrowserEnabled=false \ -jar "$JAR" diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c833651..4dc155f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Changed - (Database/H2) Use the latest H2 database engine +- (Startup) Crash on startup if an unrecoverable error happens ### Fixed - (CloudFlareInterceptor) Don't send the `cf_clearance` cookie back to Flaresolverr diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/Migration.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/Migration.kt index b7d07f1a..445fc42a 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/Migration.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/Migration.kt @@ -5,6 +5,8 @@ import android.content.Context import io.github.oshai.kotlinlogging.KotlinLogging import suwayomi.tachidesk.manga.impl.update.IUpdater import suwayomi.tachidesk.server.database.H2Migration +import suwayomi.tachidesk.server.util.ExitCode +import suwayomi.tachidesk.server.util.shutdownApp import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.io.File @@ -99,31 +101,35 @@ private val MIGRATIONS = fun runMigrations(applicationDirs: ApplicationDirs) { val logger = KotlinLogging.logger("Migration") + try { + val migrationPreferences = + Injekt + .get() + .getSharedPreferences( + "migrations", + Context.MODE_PRIVATE, + ) + val version = migrationPreferences.getInt("version", 0) - val migrationPreferences = - Injekt - .get() - .getSharedPreferences( - "migrations", - Context.MODE_PRIVATE, - ) - val version = migrationPreferences.getInt("version", 0) + logger.info { "Running migrations, previous version $version, target version ${MIGRATIONS.size}" } - logger.info { "Running migrations, previous version $version, target version ${MIGRATIONS.size}" } + MIGRATIONS.forEachIndexed { index, (migrationName, migrationFunction) -> + val migrationVersion = index + 1 - MIGRATIONS.forEachIndexed { index, (migrationName, migrationFunction) -> - val migrationVersion = index + 1 + val isMigrationRequired = version < migrationVersion + if (!isMigrationRequired) { + logger.info { "Skipping migration version $migrationVersion: $migrationName" } + return@forEachIndexed + } - val isMigrationRequired = version < migrationVersion - if (!isMigrationRequired) { - logger.info { "Skipping migration version $migrationVersion: $migrationName" } - return@forEachIndexed + logger.info { "Running migration version $migrationVersion: $migrationName" } + + migrationFunction(applicationDirs) + + migrationPreferences.edit().putInt("version", migrationVersion).apply() } - - logger.info { "Running migration version $migrationVersion: $migrationName" } - - migrationFunction(applicationDirs) - - migrationPreferences.edit().putInt("version", migrationVersion).apply() + } catch (e: Exception) { + logger.error(e) { "Failed to run migrations" } + shutdownApp(ExitCode.MigrationsRunFailure) } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt index c293c558..da4bf573 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt @@ -366,6 +366,7 @@ fun applicationSetup() { } } catch (e: Exception) { logger.error(e) { "Exception while creating initial server.conf" } + shutdownApp(ExitCode.SetupConfFileFailed) } // copy local source icon @@ -378,6 +379,7 @@ fun applicationSetup() { } } catch (e: Exception) { logger.error(e) { "Exception while copying Local source's icon" } + shutdownApp(ExitCode.LocalSourceIconCopyFailure) } // fixes #119 , ref: @@ -395,7 +397,12 @@ fun applicationSetup() { databaseUp() - LocalSource.register() + try { + LocalSource.register() + } catch (e: Exception) { + logger.error(e) { "Failed to setup LocalSource" } + shutdownApp(ExitCode.LocalSourceSetupFailure) + } serverConfig.subscribeTo( combine( diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBManager.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBManager.kt index a1cc41d2..d83b35a2 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBManager.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/database/DBManager.kt @@ -185,8 +185,6 @@ fun databaseUp() { runMigrations(migrations) } catch (e: Exception) { logger.error(e) { "Error up-to-database migration" } - if (System.getProperty("crashOnFailedMigration").toBoolean()) { - shutdownApp(ExitCode.DbMigrationFailure) - } + shutdownApp(ExitCode.DbMigrationFailure) } } diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/util/AppExit.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/util/AppExit.kt index 283aa566..020c0b5c 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/util/AppExit.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/util/AppExit.kt @@ -21,6 +21,10 @@ enum class ExitCode( WebUISetupFailure(3), ConfigMigrationMisconfiguredFailure(4), DbMigrationFailure(5), + SetupConfFileFailed(6), + LocalSourceIconCopyFailure(7), + LocalSourceSetupFailure(8), + MigrationsRunFailure(9), } fun shutdownApp(exitCode: ExitCode) { From a2f29ec9dcdd82bd8dd13bcb3c90482a502f526f Mon Sep 17 00:00:00 2001 From: Constantin Piber <59023762+cpiber@users.noreply.github.com> Date: Thu, 14 May 2026 17:44:59 +0200 Subject: [PATCH 12/13] Reset update-flag on uninstall (#2025) * Reset update-flag on uninstall If there is an update available when the extension is uninstalled, the table will still have the update flag, which makes no sense if it is not installed. Example: ``` { "pkgName": "eu.kanade.tachiyomi.extension.en.comix", "name": "Comix", "lang": "en", "versionCode": 20, "versionName": "1.4.20", "iconUrl": "/api/v1/extension/icon/tachiyomi-en.comix-v1.4.20.apk", "repo": "", "isNsfw": true, "isInstalled": false, "isObsolete": false, "hasUpdate": true, "__typename": "ExtensionType" }, ``` * Update changelog --- CHANGELOG.md | 1 + .../kotlin/suwayomi/tachidesk/manga/impl/extension/Extension.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dc155f2..601f1a12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - (WebUI) Handle serving non-default webui with "bundled" - (WebUI) Wait until WebUI is ready to open in browser - (Downloads) Truncate filenames by byte length to prevent "File name too long" IO errors +- (Extension) Do not indicate an update is available when the extension is not installed ## [v2.2.2100] + [WebUI: v20260508.01] - 2026-05-08 diff --git a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/extension/Extension.kt b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/extension/Extension.kt index 51d3c45e..b2a0379b 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/extension/Extension.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/manga/impl/extension/Extension.kt @@ -358,6 +358,7 @@ object Extension { } else { ExtensionTable.update({ ExtensionTable.pkgName eq pkgName }) { it[isInstalled] = false + it[hasUpdate] = false } } From 16a14e6ac2dcfe028290beaf32e5c33b32ee213d Mon Sep 17 00:00:00 2001 From: Constantin Piber <59023762+cpiber@users.noreply.github.com> Date: Thu, 14 May 2026 17:45:30 +0200 Subject: [PATCH 13/13] Pin CEF version to one known to work with KCEF (#2027) Fixes problems like ``` java.lang.ClassNotFoundException: org.cef.callback.CefResourceReadCallback_N ``` and ``` Exception in thread "Thread-584" java.lang.NoSuchMethodError: open ``` --- server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt b/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt index da4bf573..4e12490a 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt @@ -532,7 +532,7 @@ fun applicationSetup() { } } } - download { github() } + download { github { release("jbr-release-21.0.10b1163.108") } } settings { windowlessRenderingEnabled = true cachePath = (Path(applicationDirs.dataRoot) / "cache/kcef").toString()