Add Source Meta (#875)

This commit is contained in:
Mitchell Syer
2024-02-17 11:24:01 -05:00
committed by GitHub
parent ea6edaecc4
commit af0dde5ae8
8 changed files with 181 additions and 0 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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