mirror of
https://github.com/Suwayomi/Tachidesk.git
synced 2025-12-10 06:42:07 +01:00
Add Source Meta (#875)
This commit is contained in:
@@ -12,9 +12,11 @@ import suwayomi.tachidesk.graphql.types.CategoryMetaType
|
||||
import suwayomi.tachidesk.graphql.types.ChapterMetaType
|
||||
import suwayomi.tachidesk.graphql.types.GlobalMetaType
|
||||
import suwayomi.tachidesk.graphql.types.MangaMetaType
|
||||
import suwayomi.tachidesk.graphql.types.SourceMetaType
|
||||
import suwayomi.tachidesk.manga.model.table.CategoryMetaTable
|
||||
import suwayomi.tachidesk.manga.model.table.ChapterMetaTable
|
||||
import suwayomi.tachidesk.manga.model.table.MangaMetaTable
|
||||
import suwayomi.tachidesk.manga.model.table.SourceMetaTable
|
||||
import suwayomi.tachidesk.server.JavalinSetup.future
|
||||
|
||||
class GlobalMetaDataLoader : KotlinDataLoader<String, GlobalMetaType?> {
|
||||
@@ -88,3 +90,21 @@ class CategoryMetaDataLoader : KotlinDataLoader<Int, List<CategoryMetaType>> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SourceMetaDataLoader : KotlinDataLoader<Long, List<SourceMetaType>> {
|
||||
override val dataLoaderName = "SourceMetaDataLoader"
|
||||
|
||||
override fun getDataLoader(): DataLoader<Long, List<SourceMetaType>> =
|
||||
DataLoaderFactory.newDataLoader<Long, List<SourceMetaType>> { ids ->
|
||||
future {
|
||||
transaction {
|
||||
addLogger(Slf4jSqlDebugLogger)
|
||||
val metasByRefId =
|
||||
SourceMetaTable.select { SourceMetaTable.ref inList ids }
|
||||
.map { SourceMetaType(it) }
|
||||
.groupBy { it.sourceId }
|
||||
ids.map { metasByRefId[it].orEmpty() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,15 @@ import androidx.preference.EditTextPreference
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.MultiSelectListPreference
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||
import org.jetbrains.exposed.sql.and
|
||||
import org.jetbrains.exposed.sql.deleteWhere
|
||||
import org.jetbrains.exposed.sql.select
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import suwayomi.tachidesk.graphql.types.FilterChange
|
||||
import suwayomi.tachidesk.graphql.types.MangaType
|
||||
import suwayomi.tachidesk.graphql.types.Preference
|
||||
import suwayomi.tachidesk.graphql.types.SourceMetaType
|
||||
import suwayomi.tachidesk.graphql.types.SourceType
|
||||
import suwayomi.tachidesk.graphql.types.preferenceOf
|
||||
import suwayomi.tachidesk.graphql.types.updateFilterList
|
||||
@@ -17,11 +21,69 @@ import suwayomi.tachidesk.manga.impl.MangaList.insertOrGet
|
||||
import suwayomi.tachidesk.manga.impl.Source
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource
|
||||
import suwayomi.tachidesk.manga.model.table.MangaTable
|
||||
import suwayomi.tachidesk.manga.model.table.SourceMetaTable
|
||||
import suwayomi.tachidesk.manga.model.table.SourceTable
|
||||
import suwayomi.tachidesk.server.JavalinSetup.future
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class SourceMutation {
|
||||
data class SetSourceMetaInput(
|
||||
val clientMutationId: String? = null,
|
||||
val meta: SourceMetaType,
|
||||
)
|
||||
|
||||
data class SetSourceMetaPayload(
|
||||
val clientMutationId: String?,
|
||||
val meta: SourceMetaType,
|
||||
)
|
||||
|
||||
fun setSourceMeta(input: SetSourceMetaInput): SetSourceMetaPayload {
|
||||
val (clientMutationId, meta) = input
|
||||
|
||||
Source.modifyMeta(meta.sourceId, meta.key, meta.value)
|
||||
|
||||
return SetSourceMetaPayload(clientMutationId, meta)
|
||||
}
|
||||
|
||||
data class DeleteSourceMetaInput(
|
||||
val clientMutationId: String? = null,
|
||||
val sourceId: Long,
|
||||
val key: String,
|
||||
)
|
||||
|
||||
data class DeleteSourceMetaPayload(
|
||||
val clientMutationId: String?,
|
||||
val meta: SourceMetaType?,
|
||||
val source: SourceType?,
|
||||
)
|
||||
|
||||
fun deleteSourceMeta(input: DeleteSourceMetaInput): DeleteSourceMetaPayload {
|
||||
val (clientMutationId, sourceId, key) = input
|
||||
|
||||
val (meta, source) =
|
||||
transaction {
|
||||
val meta =
|
||||
SourceMetaTable.select { (SourceMetaTable.ref eq sourceId) and (SourceMetaTable.key eq key) }
|
||||
.firstOrNull()
|
||||
|
||||
SourceMetaTable.deleteWhere { (SourceMetaTable.ref eq sourceId) and (SourceMetaTable.key eq key) }
|
||||
|
||||
val source =
|
||||
transaction {
|
||||
SourceTable.select { SourceTable.id eq sourceId }.firstOrNull()
|
||||
?.let { SourceType(it) }
|
||||
}
|
||||
|
||||
if (meta != null) {
|
||||
SourceMetaType(meta)
|
||||
} else {
|
||||
null
|
||||
} to source
|
||||
}
|
||||
|
||||
return DeleteSourceMetaPayload(clientMutationId, meta, source)
|
||||
}
|
||||
|
||||
enum class FetchSourceMangaType {
|
||||
SEARCH,
|
||||
POPULAR,
|
||||
|
||||
@@ -30,6 +30,7 @@ import suwayomi.tachidesk.graphql.dataLoaders.MangaForIdsDataLoader
|
||||
import suwayomi.tachidesk.graphql.dataLoaders.MangaForSourceDataLoader
|
||||
import suwayomi.tachidesk.graphql.dataLoaders.MangaMetaDataLoader
|
||||
import suwayomi.tachidesk.graphql.dataLoaders.SourceDataLoader
|
||||
import suwayomi.tachidesk.graphql.dataLoaders.SourceMetaDataLoader
|
||||
import suwayomi.tachidesk.graphql.dataLoaders.SourcesForExtensionDataLoader
|
||||
import suwayomi.tachidesk.graphql.dataLoaders.TrackRecordDataLoader
|
||||
import suwayomi.tachidesk.graphql.dataLoaders.TrackRecordsForMangaIdDataLoader
|
||||
@@ -64,6 +65,7 @@ class TachideskDataLoaderRegistryFactory {
|
||||
CategoriesForMangaDataLoader(),
|
||||
SourceDataLoader(),
|
||||
SourcesForExtensionDataLoader(),
|
||||
SourceMetaDataLoader(),
|
||||
ExtensionDataLoader(),
|
||||
ExtensionForSourceDataLoader(),
|
||||
TrackerDataLoader(),
|
||||
|
||||
@@ -12,6 +12,7 @@ import suwayomi.tachidesk.graphql.server.primitives.PageInfo
|
||||
import suwayomi.tachidesk.manga.model.table.CategoryMetaTable
|
||||
import suwayomi.tachidesk.manga.model.table.ChapterMetaTable
|
||||
import suwayomi.tachidesk.manga.model.table.MangaMetaTable
|
||||
import suwayomi.tachidesk.manga.model.table.SourceMetaTable
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
interface MetaType : Node {
|
||||
@@ -67,6 +68,22 @@ class CategoryMetaType(
|
||||
}
|
||||
}
|
||||
|
||||
class SourceMetaType(
|
||||
override val key: String,
|
||||
override val value: String,
|
||||
val sourceId: Long,
|
||||
) : MetaType {
|
||||
constructor(row: ResultRow) : this(
|
||||
key = row[SourceMetaTable.key],
|
||||
value = row[SourceMetaTable.value],
|
||||
sourceId = row[SourceMetaTable.ref],
|
||||
)
|
||||
|
||||
fun source(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<SourceType> {
|
||||
return dataFetchingEnvironment.getValueFromDataLoader<Long, SourceType>("SourceDataLoader", sourceId)
|
||||
}
|
||||
}
|
||||
|
||||
class GlobalMetaType(
|
||||
override val key: String,
|
||||
override val value: String,
|
||||
|
||||
@@ -82,6 +82,10 @@ class SourceType(
|
||||
fun filters(): List<Filter> {
|
||||
return getCatalogueSourceOrStub(id).getFilterList().map { filterOf(it) }
|
||||
}
|
||||
|
||||
fun meta(dataFetchingEnvironment: DataFetchingEnvironment): CompletableFuture<List<SourceMetaType>> {
|
||||
return dataFetchingEnvironment.getValueFromDataLoader<Long, List<SourceMetaType>>("SourceMetaDataLoader", id)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("ktlint:standard:function-naming")
|
||||
|
||||
@@ -13,9 +13,12 @@ import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import eu.kanade.tachiyomi.source.sourcePreferences
|
||||
import io.javalin.plugin.json.JsonMapper
|
||||
import mu.KotlinLogging
|
||||
import org.jetbrains.exposed.sql.and
|
||||
import org.jetbrains.exposed.sql.insert
|
||||
import org.jetbrains.exposed.sql.select
|
||||
import org.jetbrains.exposed.sql.selectAll
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import org.jetbrains.exposed.sql.update
|
||||
import org.kodein.di.DI
|
||||
import org.kodein.di.conf.global
|
||||
import org.kodein.di.instance
|
||||
@@ -25,6 +28,7 @@ import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogue
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.unregisterCatalogueSource
|
||||
import suwayomi.tachidesk.manga.model.dataclass.SourceDataClass
|
||||
import suwayomi.tachidesk.manga.model.table.ExtensionTable
|
||||
import suwayomi.tachidesk.manga.model.table.SourceMetaTable
|
||||
import suwayomi.tachidesk.manga.model.table.SourceTable
|
||||
import uy.kohesive.injekt.api.get
|
||||
import xyz.nulldev.androidcompat.androidimpl.CustomContext
|
||||
@@ -150,4 +154,29 @@ object Source {
|
||||
// must reload the source because a preference was changed
|
||||
unregisterCatalogueSource(sourceId)
|
||||
}
|
||||
|
||||
fun modifyMeta(
|
||||
sourceId: Long,
|
||||
key: String,
|
||||
value: String,
|
||||
) {
|
||||
transaction {
|
||||
val meta =
|
||||
transaction {
|
||||
SourceMetaTable.select { (SourceMetaTable.ref eq sourceId) and (SourceMetaTable.key eq key) }
|
||||
}.firstOrNull()
|
||||
|
||||
if (meta == null) {
|
||||
SourceMetaTable.insert {
|
||||
it[SourceMetaTable.key] = key
|
||||
it[SourceMetaTable.value] = value
|
||||
it[SourceMetaTable.ref] = sourceId
|
||||
}
|
||||
} else {
|
||||
SourceMetaTable.update({ (SourceMetaTable.ref eq sourceId) and (SourceMetaTable.key eq key) }) {
|
||||
it[SourceMetaTable.value] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package suwayomi.tachidesk.manga.model.table
|
||||
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import org.jetbrains.exposed.dao.id.IntIdTable
|
||||
import suwayomi.tachidesk.manga.model.table.ChapterMetaTable.ref
|
||||
|
||||
/**
|
||||
* Metadata storage for clients, about Source with id == [ref].
|
||||
*/
|
||||
object SourceMetaTable : IntIdTable() {
|
||||
val key = varchar("key", 256)
|
||||
val value = varchar("value", 4096)
|
||||
val ref = long("source_ref")
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package suwayomi.tachidesk.server.database.migration
|
||||
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import de.neonew.exposed.migrations.helpers.AddTableMigration
|
||||
import org.jetbrains.exposed.dao.id.IntIdTable
|
||||
import org.jetbrains.exposed.sql.Table
|
||||
|
||||
@Suppress("ClassName", "unused")
|
||||
class M0036_SourceMeta : AddTableMigration() {
|
||||
private class SourceMetaTable : IntIdTable() {
|
||||
val key = varchar("key", 256)
|
||||
val value = varchar("value", 4096)
|
||||
val ref = long("source_ref")
|
||||
}
|
||||
|
||||
override val tables: Array<Table>
|
||||
get() =
|
||||
arrayOf(
|
||||
SourceMetaTable(),
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user