Compare commits

...

20 Commits

Author SHA1 Message Date
schroda
c0618fcc5c Try to keep cached images usable on manga rename (#2052) 2026-05-18 14:17:52 -04:00
schroda
9686f75a2d Fix/losing downloads on manga rename during update (#2051)
* Fix renaming manga download dir

* Simplify manga download dir rename function

---------

Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
2026-05-18 14:05:21 -04:00
schroda
4d5307f15b Fix/chapter list update preserving download state (#2050)
* Fix preserving chapter download state of deleted chapters

* Fix preserving chapter download state of updated chapters
2026-05-18 14:04:49 -04:00
Constantin Piber
779229a48a Fix tests (#2049)
* Fix test setup

* Fix tests

* Disable broken CloudflareTest

* Add a basic test for Android's Looper
2026-05-18 14:04:39 -04:00
Constantin Piber
762d5bdbe6 [skip ci] Add workflow_dispatch trigger to wiki upload (#2046) 2026-05-17 12:32:25 -04:00
schroda
41bb6d3dc1 Fix sorting of gql mangas query (#2043)
Regression fbb383b1f1

Broke sorting due to ordering the manga by their id first, thus, the other orderings were never applied
2026-05-16 20:16:27 -04:00
schroda
fbb383b1f1 Fix mangas query with active sorting and postgresql db (#2042)
fixes #2036
2026-05-16 19:41:37 -04:00
Constantin Piber
558407d92c Update Troubleshooting (#2029)
* Simplify general section

* Troubleshooting: Document some common problems and their solutions

* Remove icon since it's not rendered anyways

[skip ci]

* Update corrupt DB examples

[skip ci]
2026-05-16 19:08:47 -04:00
schroda
6870922784 Fix chapter update failure db rollback (#2040)
The deletion of chapter data was done in its own transaction. Thus, when the update or insertion failed later on, the deletion was not rolled back

fixes #2031

Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
2026-05-16 19:08:38 -04:00
AeonLucid
a4b647972e Add default pageCount value to fix PSQLException (#2039)
* Add default pageCount value to fix PSQLException

* Update CHANGELOG.md
2026-05-16 19:07:56 -04:00
Constantin Piber
16a14e6ac2 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
```
2026-05-14 11:45:30 -04:00
Constantin Piber
a2f29ec9dc 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": "<hidden>",
  "isNsfw": true,
  "isInstalled": false,
  "isObsolete": false,
  "hasUpdate": true,
  "__typename": "ExtensionType"
},
```

* Update changelog
2026-05-14 11:44:59 -04:00
Mitchell Syer
82df985201 Crash on startup if an unrecoverable error happens (#2019)
* Crash on startup if an unrecoverable error happens

* Changelog
2026-05-14 11:44:52 -04:00
renovate[bot]
740db4f1ab Update javalin to v7.2.2 (#2026)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-14 11:44:34 -04:00
renovate[bot]
c4711dec00 Update dependency com.github.junrar:junrar to v7.6.0 (#2022)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-14 11:44:18 -04:00
renovate[bot]
75d8d172aa Update dependency org.slf4j:slf4j-api to v2.0.18 (#2017)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-14 11:44:00 -04:00
renovate[bot]
81fb8c395d Update Gradle to v9.5.1 (#2015)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-14 11:43:46 -04:00
Mitchell Syer
e93efa9627 Fix Database Types as Needed (#2020) 2026-05-12 19:59:06 -04:00
Mitchell Syer
03a95e6652 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
2026-05-12 17:22:35 -04:00
renovate[bot]
c117d380a3 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 <syer10@users.noreply.github.com>
2026-05-12 12:53:41 -04:00
136 changed files with 1440 additions and 865 deletions

View File

@@ -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"

View File

@@ -1,6 +1,7 @@
name: GitHub Wiki upload
on:
workflow_dispatch:
push:
branches:
- master

View File

@@ -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

View File

@@ -10,13 +10,20 @@ 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
- (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
- (**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
- (**Downloads**) Fix being unable to find downloads after manga was renamed during an update
- (**Downloads**) Fix preserving chapter download states during an update
- (**Extension**) Do not indicate an update is available when the extension is not installed
- (**Chapter**) Fix losing chapter data on failed chapter list update
- (**Chapter**) Fix database error when fetching chapter updates
- (**Manga/API**) Fix "mangas" graphql query with active sorting and using a postgresql database (QUERY "mangas")
## [v2.2.2100] + [WebUI: v20260508.01] - 2026-05-08

View File

@@ -1,19 +1,69 @@
# Troubleshooting
This page is laid out in several sections, where each section describes a specific problem, followed by one or more possible solutions.
At the end, you will find a General section, which is the nuclear option if nothing else works.
For further support, visit the [official Suwayomi Discord server](https://discord.gg/DDZdqZWaHA).
In such cases, it will be helpful to have logs ready. You can find them in [The Data Directory](./The-Data-Directory) in the logs directory.
**All steps below assume that you have stopped Suwayomi**.
## Broken database
- `failed due to
org.jetbrains.exposed.exceptions.ExposedSQLException: org.h2.jdbc.JdbcSQLSyntaxErrorException: Column "CATEGORY.SORT_ORDER" not found`
- `org.h2.jdbc.JdbcSQLSyntaxErrorException: Column "CHAPTER.KOREADER_HASH" not found`
- `java.lang.IllegalStateException: Unable to read the page at position 96170708817765466`
- Any other error text that includes "SQL Statement"
Your database is either corrupted or incompatible.
One of these is the cause:
- You were running a preview version and decided to downgrade to stable.
- You did not shut down Suwayomi properly.
- Suwayomi crashed in an unexpected way.
Solutions:
- If you downgraded, upgrade to preview again.
- Otherwise, you will need to reset and restore from a backup. See [General Troubleshooting](#general-troubleshooting) below.
## `HTTP error 429`
The source (or, if trackers are enabled, possibly the tracker) has blocked you for sending too many requests.
Note that Mass-Migration can result in an unexpectedly high number of requests to both the source and any configured trackers.
Solution: Use other/more sources, download less, and wait between request-heavy actions.
## Extension times out
- `Timed out waiting for 20000 ms…`
- `Timed out waiting for page list`
First, check if this is an extension issue or a Suwayomi issue.
On the manga page of the problematic entry, click "Open in WebView".
Solutions:
- If the WebView loads: The issue is with the extension. Search [the issues](https://github.com/Suwayomi/Suwayomi-Server/issues) and discord if there are known problems with that extension.
- If the WebView errors: Go to [The Data Directory](./The-Data-Directory) and remove the `bin` and `cache` folders.
- If the WebView still does not work after a restart, your installation is incomplete. On Linux, refer to [the README](https://github.com/Suwayomi/Suwayomi-Server#webview-support-gnulinux).
## General Troubleshooting
This guide will try to fix Suwayomi by reseting it to a clean installation state.
> [!WARNING]
> This will remove all your data, including the library.
> Make sure you have copied your backups as described above!
- Make sure you have a recent backup of your library or create one in the app (if possible) because we **are going to wipe all Suwayomi data**.
- Make sure Suwayomi is not running (right click on tray icon and quit or kill it through the way your Operating System provides)
- Clear all browsing data on your browser if you use Suwayomi from a browser.
- Delete the Suwayomi data directory located below and re-run the app.
Note: Replace `<Account>` with the currently logged in account/username on your pc.
On Mac OS X : `/Users/<Account>/Library/Application Support/Tachidesk`
On Windows XP : `C:\Documents and Settings\<Account>\Application Data\Local Settings\Tachidesk`
On Windows 7 and later : `C:\Users\<Account>\AppData\Local\Tachidesk`
On Unix/Linux : `/home/<account>/.local/share/Tachidesk`
- Delete the Suwayomi data directory located below and re-run the app. See the article [The Data Directory](./The-Data-Directory) for information on how to find it.
- If you wish to keep your downloads, you may also attempt to surgically remove only parts. You will need to remove `database.mv.db`, `database.trace.db`, `bin`, `cache`, `extensions`, `settings`, `webUI`. Removing only a subset of these files and folders may fail to resolve the problem.
- Open Suwayomi and go to Settings > Backup > Restore Backup, and select the latest backup you have.
- Restoring from backup does not restore your downloads. If you chose to keep them in the above step, you will now need to re-download all manga. Suwayomi will pick up on the existing files and not actually download anything that isn't new.
- In the case that you have to periodically perform this fix or the problem persists or the method failed to fix it, open an issue or Join the [Suwayomi discord server](https://discord.gg/DDZdqZWaHA) to hang out with the community and to receive support and help.

View File

@@ -4,10 +4,10 @@ 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 = "0.61.0"
exposed = "1.2.0"
dex2jar = "2.4.36"
polyglot = "25.0.3"
settings = "1.3.0"
@@ -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"
@@ -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" }
@@ -115,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"
@@ -242,6 +243,7 @@ exposed = [
"exposed-dao",
"exposed-jdbc",
"exposed-javatime",
"exposed-kotlintime",
]
systemtray = [
"systemtray-core",

View File

@@ -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

View File

@@ -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(

View File

@@ -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(

View File

@@ -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(

View File

@@ -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<AuthMode> by EnumSetting(

View File

@@ -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
/**
@@ -89,4 +88,6 @@ object SettingsRegistry {
fun get(name: String): SettingMetadata? = settings[name]
fun getAll(): Map<String, SettingMetadata> = settings.toMap()
fun clear() = settings.clear()
}

View File

@@ -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

View File

@@ -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

View File

@@ -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()) {

View File

@@ -7,12 +7,12 @@ 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.
*/
object GlobalMetaTable : IntIdTable() {
val key = varchar("key", 256)
val key = varchar("meta_key", 256)
val value = varchar("value", 4096)
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -10,12 +10,17 @@ 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.inSubQuery
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.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.ComparableScalarFilter
@@ -240,13 +245,16 @@ class MangaQuery {
): MangaNodeList {
val queryResults =
transaction {
val res =
val mangaIdsQuery =
MangaTable
.leftJoin(CategoryMangaTable)
.select(MangaTable.columns)
.withDistinctOn(MangaTable.id)
.select(MangaTable.id)
.withDistinct()
res.applyOps(condition, filter)
mangaIdsQuery.applyOps(condition, filter)
val res =
MangaTable.selectAll().where { MangaTable.id inSubQuery mangaIdsQuery }
if (order != null || orderBy != null || (last != null || before != null)) {
val baseSort = listOf(MangaOrder(MangaOrderBy.ID, SortOrder.ASC))

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 <T> andWhere(
value: T?,
andPart: SqlExpressionBuilder.(T & Any) -> Op<Boolean>,
andPart: (T & Any) -> Op<Boolean>,
) {
value ?: return
val expr = Op.build { andPart(value) }
val expr = andPart(value)
op = if (op == null) expr else (op!! and expr)
}
fun <T : Any> andWhere(
values: List<T>?,
andPart: SqlExpressionBuilder.(List<T>) -> Op<Boolean>,
andPart: (List<T>) -> Op<Boolean>,
) {
@Suppress("UNCHECKED_CAST")
return andWhere(values as T?, andPart as SqlExpressionBuilder.(Any) -> Op<Boolean>)
return andWhere(values as T?, andPart as (Any) -> Op<Boolean>)
}
fun <T : Any> andWhere(
valueDefault: T?,
valueAll: List<T>?,
valueAny: List<T>?,
expr: SqlExpressionBuilder.(T) -> Op<Boolean>,
expr: (T) -> Op<Boolean>,
) {
andWhere(valueDefault, expr)
andWhereAll(valueAll, expr)
@@ -533,17 +537,17 @@ class OpAnd(
fun <T : Any> andWhereAll(
values: List<T>?,
andPart: SqlExpressionBuilder.(T) -> Op<Boolean>,
andPart: (T) -> Op<Boolean>,
) {
values?.map { andWhere(it, andPart) }
}
fun <T : Any> andWhereAny(
values: List<T>?,
andPart: SqlExpressionBuilder.(T) -> Op<Boolean>,
andPart: (T) -> Op<Boolean>,
) {
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)
}

View File

@@ -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

View File

@@ -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

View File

@@ -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<T> {
val column: Column<*>

View File

@@ -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<T>(
val total: Long,

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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()) {

View File

@@ -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

View File

@@ -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
@@ -232,7 +236,7 @@ object Chapter {
val deletedChapterNumbers = TreeSet<Float>()
val deletedReadChapterNumbers = TreeSet<Float>()
val deletedBookmarkedChapterNumbers = TreeSet<Float>()
val deletedDownloadedChapterNumberInfoMap = mutableMapOf<Float, MutableMap<String?, Int>>()
val deletedDownloadedChapterNumberToChapter = mutableMapOf<Float, ChapterDataClass>()
val deletedChapterNumberDateFetchMap = mutableMapOf<Float, Long>()
// clear any orphaned/duplicate chapters that are in the db but not in `chapterList`
@@ -243,13 +247,7 @@ object Chapter {
if (!chapterUrls.contains(dbChapter.url)) {
if (dbChapter.read) deletedReadChapterNumbers.add(dbChapter.chapterNumber)
if (dbChapter.bookmarked) deletedBookmarkedChapterNumbers.add(dbChapter.chapterNumber)
if (dbChapter.downloaded) {
val pageCountByScanlator =
deletedDownloadedChapterNumberInfoMap.getOrPut(
dbChapter.chapterNumber,
) { mutableMapOf() }
pageCountByScanlator[dbChapter.scanlator] = dbChapter.pageCount
}
if (dbChapter.downloaded) deletedDownloadedChapterNumberToChapter[dbChapter.chapterNumber] = dbChapter
deletedChapterNumbers.add(dbChapter.chapterNumber)
deletedChapterNumberDateFetchMap[dbChapter.chapterNumber] = dbChapter.fetchedAt
dbChapter.id
@@ -258,16 +256,14 @@ object Chapter {
}
}
// we got some clean up due
if (chaptersIdsToDelete.isNotEmpty()) {
DownloadManager.dequeue(chaptersIdsToDelete)
transaction {
transaction {
// we got some clean up due
if (chaptersIdsToDelete.isNotEmpty()) {
DownloadManager.dequeue(chaptersIdsToDelete)
PageTable.deleteWhere { chapter inList chaptersIdsToDelete }
ChapterTable.deleteWhere { id inList chaptersIdsToDelete }
}
}
transaction {
if (chaptersToInsert.isNotEmpty()) {
ChapterTable
.batchInsert(chaptersToInsert) { chapter ->
@@ -283,41 +279,67 @@ object Chapter {
this[ChapterTable.isRead] = false
this[ChapterTable.isBookmarked] = false
this[ChapterTable.isDownloaded] = false
this[ChapterTable.pageCount] = -1
// is recognized chapter number
if (chapter.chapterNumber >= 0f && chapter.chapterNumber in deletedChapterNumbers) {
this[ChapterTable.isRead] = chapter.chapterNumber in deletedReadChapterNumbers
this[ChapterTable.isBookmarked] = chapter.chapterNumber in deletedBookmarkedChapterNumbers
// only preserve download status for chapters of the same scanlator, otherwise,
// the downloaded files won't be found anyway
val downloadedChapterInfo = deletedDownloadedChapterNumberInfoMap[chapter.chapterNumber]
val pageCount = downloadedChapterInfo?.get(chapter.scanlator)
if (pageCount != null) {
this[ChapterTable.isDownloaded] = true
this[ChapterTable.pageCount] = pageCount
}
// Try to use the fetch date of the original entry to not pollute 'Updates' tab
deletedChapterNumberDateFetchMap[chapter.chapterNumber]?.let {
this[ChapterTable.fetchedAt] = it
}
val deletedChapter = deletedDownloadedChapterNumberToChapter[chapter.chapterNumber]!!
val hasDownloadedPages = deletedChapter.pageCount > 0
val isSameName = deletedChapter.name == chapter.name
val isSameScanlator = deletedChapter.scanlator == chapter.scanlator
// Only preserve download status for chapters with the same name and of the same scanlator; otherwise,
// the downloaded files won't be found anyway
val isDownloadPreservable = hasDownloadedPages && isSameName && isSameScanlator
if (isDownloadPreservable) {
this[ChapterTable.isDownloaded] = true
this[ChapterTable.pageCount] = deletedChapter.pageCount
}
}
}.forEach { insertedChapters.add(ChapterTable.toDataClass(it)) }
}
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))
val currentChapter = chaptersInDb.find { dbChapter -> dbChapter.id == it.id }!!
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
this[ChapterTable.isDownloaded] = currentChapter.downloaded
this[ChapterTable.pageCount] = currentChapter.pageCount
if (!currentChapter.downloaded) {
return@forEach
}
val isSameScanlator = currentChapter.scanlator == it.scanlator
val isSameName = currentChapter.name == it.name
val isDownloadPreservable = isSameName && isSameScanlator
if (!isDownloadPreservable) {
this[ChapterTable.isDownloaded] = false
this[ChapterTable.pageCount] = -1
}
}
}.toExecutable()
.execute(this@transaction)
}
MangaTable.update({ MangaTable.id eq mangaId }) {
@@ -517,11 +539,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 +556,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 +672,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()) {

View File

@@ -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

View File

@@ -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

View File

@@ -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
@@ -130,7 +133,7 @@ object Manga {
""
}
if (remoteTitle.isNotEmpty() && remoteTitle != mangaEntry[MangaTable.title]) {
val canUpdateTitle = updateMangaDownloadDir(mangaId, remoteTitle)
val canUpdateTitle = updateMangaDownloadDir(mangaEntry[MangaTable.title], source.toString(), remoteTitle)
if (canUpdateTitle) {
it[MangaTable.title] = remoteTitle
@@ -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()) {

View File

@@ -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 =

View File

@@ -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

View File

@@ -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()) {

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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) {

View File

@@ -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

View File

@@ -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

View File

@@ -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)))

View File

@@ -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

View File

@@ -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(

View File

@@ -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

View File

@@ -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

View File

@@ -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 {}
@@ -359,6 +358,7 @@ object Extension {
} else {
ExtensionTable.update({ ExtensionTable.pkgName eq pkgName }) {
it[isInstalled] = false
it[hasUpdate] = false
}
}

View File

@@ -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()) {

View File

@@ -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

View File

@@ -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<Track>) =
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)
}
}

View File

@@ -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 =

View File

@@ -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
@@ -24,14 +24,22 @@ private val applicationDirs: ApplicationDirs by injectLazy()
private val logger = KotlinLogging.logger { }
private fun getMangaDir(
title: String,
sourceName: String,
): String {
val sourceDir = SafePath.buildValidFilename(sourceName)
val mangaDir = SafePath.buildValidFilename(title)
return "$sourceDir/$mangaDir"
}
private fun getMangaDir(mangaId: Int): String =
transaction {
val mangaEntry = MangaTable.selectAll().where { MangaTable.id eq mangaId }.first()
val source = GetCatalogueSource.getCatalogueSourceOrStub(mangaEntry[MangaTable.sourceReference])
val sourceDir = SafePath.buildValidFilename(source.toString())
val mangaDir = SafePath.buildValidFilename(mangaEntry[MangaTable.title])
"$sourceDir/$mangaDir"
getMangaDir(mangaEntry[MangaTable.title], source.toString())
}
private fun getChapterDir(
@@ -62,8 +70,18 @@ private fun getChapterDir(
fun getThumbnailDownloadPath(mangaId: Int): String = applicationDirs.thumbnailDownloadsRoot + "/$mangaId"
fun getMangaDownloadDir(
title: String,
sourceName: String,
): String = applicationDirs.mangaDownloadsRoot + "/" + getMangaDir(title, sourceName)
fun getMangaDownloadDir(mangaId: Int): String = applicationDirs.mangaDownloadsRoot + "/" + getMangaDir(mangaId)
fun getMangaCacheDir(
title: String,
sourceName: String,
): String = applicationDirs.tempMangaCacheRoot + "/" + getMangaDir(title, sourceName)
fun getChapterDownloadPath(
mangaId: Int,
chapterId: Int,
@@ -79,38 +97,21 @@ fun getChapterCachePath(
chapterId: Int,
): String = applicationDirs.tempMangaCacheRoot + "/" + getChapterDir(mangaId, chapterId)
/** return value says if rename/move was successful */
fun updateMangaDownloadDir(
mangaId: Int,
newTitle: String,
private fun updateDownloadDir(
currentDir: String,
newDir: String,
): Boolean {
// Get current manga directory (uses its own transaction)
val currentMangaDir = getMangaDir(mangaId)
// Build new directory path
val newMangaDir =
transaction {
val mangaEntry = MangaTable.selectAll().where { MangaTable.id eq mangaId }.first()
val source = GetCatalogueSource.getCatalogueSourceOrStub(mangaEntry[MangaTable.sourceReference])
val sourceDir = SafePath.buildValidFilename(source.toString())
val newMangaDirName = SafePath.buildValidFilename(newTitle)
"$sourceDir/$newMangaDirName"
}
val oldDir = "${applicationDirs.downloadsRoot}/$currentMangaDir"
val newDir = "${applicationDirs.downloadsRoot}/$newMangaDir"
val oldDirFile = File(oldDir)
val currentDirFile = File(currentDir)
val newDirFile = File(newDir)
if (!oldDirFile.exists()) {
if (!currentDirFile.exists()) {
return true
}
return try {
Files.move(oldDirFile.toPath(), newDirFile.toPath())
Files.move(currentDirFile.toPath(), newDirFile.toPath())
if (oldDirFile.exists()) {
if (currentDirFile.exists()) {
return false
}
@@ -118,9 +119,31 @@ fun updateMangaDownloadDir(
return false
}
true
return true
} catch (e: Exception) {
logger.error(e) { "updateMangaDownloadDir: failed to rename manga download folder from \"$oldDir\" to \"$newDir\"" }
logger.error(e) { "updateDownloadDir: failed to rename download folder from \"$currentDir\" to \"$newDir\"" }
false
}
}
/** return value says if rename/move was successful */
fun updateMangaDownloadDir(
title: String,
sourceName: String,
newTitle: String,
): Boolean {
val currentDownloadDir = getMangaDownloadDir(title, sourceName)
val newDownloadDir = getMangaDownloadDir(newTitle, sourceName)
val renamed = updateDownloadDir(currentDownloadDir, newDownloadDir)
val tryToKeepCachedFilesUsable = renamed
if (tryToKeepCachedFilesUsable) {
val currentCacheDir = getMangaCacheDir(title, sourceName)
val newCacheDir = getMangaCacheDir(newTitle, sourceName)
updateDownloadDir(currentCacheDir, newCacheDir)
}
return renamed
}

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -7,12 +7,21 @@ package suwayomi.tachidesk.manga.model.dataclass
* 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 java.util.Objects
import kotlin.math.min
open class PaginatedList<T>(
val page: List<T>,
val hasNextPage: Boolean,
)
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is PaginatedList<T>) return false
return page == other.page && hasNextPage == other.hasNextPage
}
override fun hashCode(): Int = Objects.hash(page, hasNextPage)
}
const val PAGINATION_FACTOR = 50

View File

@@ -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)

View File

@@ -7,15 +7,15 @@ 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
/**
* 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)
}

View File

@@ -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

View File

@@ -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
/**
@@ -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)
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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
/**
@@ -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)
}

View File

@@ -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

View File

@@ -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() {

View File

@@ -7,14 +7,14 @@ 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].
*/
object SourceMetaTable : IntIdTable() {
val key = varchar("key", 256)
val key = varchar("meta_key", 256)
val value = varchar("value", 4096)
val ref = long("source_ref")
}

View File

@@ -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<Long>() {
override val id = long("id").entityId()

View File

@@ -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() {

View File

@@ -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<TrackSearch>.insertAll(): List<ResultRow> {
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()) {

View File

@@ -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

View File

@@ -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

Some files were not shown because too many files have changed in this diff Show More