mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-11 06:44:34 -05:00
Address Build Warnings and Cleanup (#707)
* Address build warnings and cleanup * Actual name of who defined the protocol * Remove uneeded detekt supression * GraphQL Before-After cleanup * Lint * Cleanup unused functions * Fix some discrepancies with the 1.5 source api and fix lang exception
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import de.undercouch.gradle.tasks.download.Download
|
import de.undercouch.gradle.tasks.download.Download
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
@@ -142,6 +143,15 @@ tasks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
withType<KotlinJvmCompile> {
|
||||||
|
kotlinOptions {
|
||||||
|
freeCompilerArgs +=
|
||||||
|
listOf(
|
||||||
|
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
named<Copy>("processResources") {
|
named<Copy>("processResources") {
|
||||||
duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
||||||
mustRunAfter("downloadWebUI")
|
mustRunAfter("downloadWebUI")
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ import kotlinx.coroutines.withContext
|
|||||||
/**
|
/**
|
||||||
* Util for evaluating JavaScript in sources.
|
* Util for evaluating JavaScript in sources.
|
||||||
*/
|
*/
|
||||||
class JavaScriptEngine(context: Context) {
|
class JavaScriptEngine(
|
||||||
|
@Suppress("UNUSED_PARAMETER") context: Context,
|
||||||
|
) {
|
||||||
/**
|
/**
|
||||||
* Evaluate arbitrary JavaScript code and get the result as a primitive type
|
* Evaluate arbitrary JavaScript code and get the result as a primitive type
|
||||||
* (e.g., String, Int).
|
* (e.g., String, Int).
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ class CloudflareInterceptor : Interceptor {
|
|||||||
|
|
||||||
private val network: NetworkHelper by injectLazy()
|
private val network: NetworkHelper by injectLazy()
|
||||||
|
|
||||||
|
@Suppress("UNUSED_VARIABLE", "UNREACHABLE_CODE")
|
||||||
override fun intercept(chain: Interceptor.Chain): Response {
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
val originalRequest = chain.request()
|
val originalRequest = chain.request()
|
||||||
|
|
||||||
@@ -141,6 +142,7 @@ object CFClearance {
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNREACHABLE_CODE")
|
||||||
fun getWebViewUserAgent(): String {
|
fun getWebViewUserAgent(): String {
|
||||||
return try {
|
return try {
|
||||||
throw PlaywrightException("playwrite is diabled for v0.6.7")
|
throw PlaywrightException("playwrite is diabled for v0.6.7")
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ interface CatalogueSource : Source {
|
|||||||
/**
|
/**
|
||||||
* An ISO 639-1 compliant language code (two letters in lower case).
|
* An ISO 639-1 compliant language code (two letters in lower case).
|
||||||
*/
|
*/
|
||||||
val lang: String
|
override val lang: String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the source has support for latest updates.
|
* Whether the source has support for latest updates.
|
||||||
|
|||||||
@@ -18,8 +18,10 @@ interface ConfigurableSource : Source {
|
|||||||
fun setupPreferenceScreen(screen: PreferenceScreen)
|
fun setupPreferenceScreen(screen: PreferenceScreen)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ConfigurableSource.preferenceKey(): String = "source_$id"
|
fun ConfigurableSource.preferenceKey(): String = "source_$id"
|
||||||
|
|
||||||
// TODO: use getSourcePreferences once all extensions are on ext-lib 1.5
|
// TODO: use getSourcePreferences once all extensions are on ext-lib 1.5
|
||||||
fun ConfigurableSource.sourcePreferences(): SharedPreferences =
|
fun ConfigurableSource.sourcePreferences(): SharedPreferences =
|
||||||
Injekt.get<Application>().getSharedPreferences(preferenceKey(), Context.MODE_PRIVATE)
|
Injekt.get<Application>().getSharedPreferences(preferenceKey(), Context.MODE_PRIVATE)
|
||||||
|
|
||||||
|
fun sourcePreferences(key: String): SharedPreferences = Injekt.get<Application>().getSharedPreferences(key, Context.MODE_PRIVATE)
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import rx.Observable
|
|||||||
import suwayomi.tachidesk.manga.impl.util.lang.awaitSingle
|
import suwayomi.tachidesk.manga.impl.util.lang.awaitSingle
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A basic interface for creating a source. It could be an online source, a local source, etc...
|
* A basic interface for creating a source. It could be an online source, a local source, etc.
|
||||||
*/
|
*/
|
||||||
interface Source {
|
interface Source {
|
||||||
/**
|
/**
|
||||||
* Id for the source. Must be unique.
|
* ID for the source. Must be unique.
|
||||||
*/
|
*/
|
||||||
val id: Long
|
val id: Long
|
||||||
|
|
||||||
@@ -20,6 +20,9 @@ interface Source {
|
|||||||
*/
|
*/
|
||||||
val name: String
|
val name: String
|
||||||
|
|
||||||
|
val lang: String
|
||||||
|
get() = ""
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the updated details for a manga.
|
* Get the updated details for a manga.
|
||||||
*
|
*
|
||||||
@@ -73,9 +76,7 @@ interface Source {
|
|||||||
"Use the non-RxJava API instead",
|
"Use the non-RxJava API instead",
|
||||||
ReplaceWith("getPageList"),
|
ReplaceWith("getPageList"),
|
||||||
)
|
)
|
||||||
fun fetchPageList(chapter: SChapter): Observable<List<Page>> = Observable.empty()
|
fun fetchPageList(chapter: SChapter): Observable<List<Page>> = throw IllegalStateException("Not used")
|
||||||
}
|
}
|
||||||
|
|
||||||
// fun Source.icon(): Drawable? = Injekt.get<ExtensionManager>().getAppIconForSource(this)
|
// fun Source.icon(): Drawable? = Injekt.get<ExtensionManager>().getAppIconForSource(this)
|
||||||
|
|
||||||
fun Source.getPreferenceKey(): String = "source_$id"
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import kotlinx.coroutines.withContext
|
|||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.decodeFromStream
|
import kotlinx.serialization.json.decodeFromStream
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
|
import nl.adaptivity.xmlutil.ExperimentalXmlUtilApi
|
||||||
import nl.adaptivity.xmlutil.core.KtXmlReader
|
import nl.adaptivity.xmlutil.core.KtXmlReader
|
||||||
import nl.adaptivity.xmlutil.serialization.XML
|
import nl.adaptivity.xmlutil.serialization.XML
|
||||||
import org.apache.commons.compress.archivers.zip.ZipFile
|
import org.apache.commons.compress.archivers.zip.ZipFile
|
||||||
@@ -271,6 +272,7 @@ class LocalSource(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalXmlUtilApi::class)
|
||||||
private fun setMangaDetailsFromComicInfoFile(
|
private fun setMangaDetailsFromComicInfoFile(
|
||||||
stream: InputStream,
|
stream: InputStream,
|
||||||
manga: SManga,
|
manga: SManga,
|
||||||
|
|||||||
@@ -26,18 +26,12 @@ import java.security.MessageDigest
|
|||||||
/**
|
/**
|
||||||
* A simple implementation for sources from a website.
|
* A simple implementation for sources from a website.
|
||||||
*/
|
*/
|
||||||
|
@Suppress("unused")
|
||||||
abstract class HttpSource : CatalogueSource {
|
abstract class HttpSource : CatalogueSource {
|
||||||
/**
|
/**
|
||||||
* Network service.
|
* Network service.
|
||||||
*/
|
*/
|
||||||
val network: NetworkHelper by injectLazy()
|
protected val network: NetworkHelper by injectLazy()
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Preferences that a source may need.
|
|
||||||
// */
|
|
||||||
// val preferences: SharedPreferences by lazy {
|
|
||||||
// Injekt.get<Application>().getSharedPreferences(source.getPreferenceKey(), Context.MODE_PRIVATE)
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base url of the website without the trailing slash, like: http://mysite.com
|
* Base url of the website without the trailing slash, like: http://mysite.com
|
||||||
@@ -60,7 +54,7 @@ abstract class HttpSource : CatalogueSource {
|
|||||||
*
|
*
|
||||||
* Note: the generated ID sets the sign bit to `0`.
|
* Note: the generated ID sets the sign bit to `0`.
|
||||||
*/
|
*/
|
||||||
override val id by lazy { generateId(name, lang, versionId) }
|
override val id by lazy { generateId() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Headers used for requests.
|
* Headers used for requests.
|
||||||
@@ -73,6 +67,10 @@ abstract class HttpSource : CatalogueSource {
|
|||||||
open val client: OkHttpClient
|
open val client: OkHttpClient
|
||||||
get() = network.client
|
get() = network.client
|
||||||
|
|
||||||
|
private fun generateId(): Long {
|
||||||
|
return generateId(name, lang, versionId)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a unique ID for the source based on the provided [name], [lang] and
|
* Generates a unique ID for the source based on the provided [name], [lang] and
|
||||||
* [versionId]. It will use the first 16 characters (64 bits) of the MD5 of the string
|
* [versionId]. It will use the first 16 characters (64 bits) of the MD5 of the string
|
||||||
@@ -89,6 +87,7 @@ abstract class HttpSource : CatalogueSource {
|
|||||||
* @param versionId [Int] the version ID of the source
|
* @param versionId [Int] the version ID of the source
|
||||||
* @return a unique ID for the source
|
* @return a unique ID for the source
|
||||||
*/
|
*/
|
||||||
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
protected fun generateId(
|
protected fun generateId(
|
||||||
name: String,
|
name: String,
|
||||||
lang: String,
|
lang: String,
|
||||||
@@ -155,8 +154,15 @@ abstract class HttpSource : CatalogueSource {
|
|||||||
query: String,
|
query: String,
|
||||||
filters: FilterList,
|
filters: FilterList,
|
||||||
): Observable<MangasPage> {
|
): Observable<MangasPage> {
|
||||||
return client.newCall(searchMangaRequest(page, query, filters))
|
return Observable.defer {
|
||||||
.asObservableSuccess()
|
try {
|
||||||
|
client.newCall(searchMangaRequest(page, query, filters)).asObservableSuccess()
|
||||||
|
} catch (e: NoClassDefFoundError) {
|
||||||
|
// RxJava doesn't handle Errors, which tends to happen during global searches
|
||||||
|
// if an old extension using non-existent classes is still around
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
.map { response ->
|
.map { response ->
|
||||||
searchMangaParse(response)
|
searchMangaParse(response)
|
||||||
}
|
}
|
||||||
@@ -387,7 +393,7 @@ abstract class HttpSource : CatalogueSource {
|
|||||||
*
|
*
|
||||||
* @param page the chapter whose page list has to be fetched
|
* @param page the chapter whose page list has to be fetched
|
||||||
*/
|
*/
|
||||||
open fun imageRequest(page: Page): Request {
|
protected open fun imageRequest(page: Page): Request {
|
||||||
return GET(page.imageUrl!!, headers)
|
return GET(page.imageUrl!!, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,7 +424,7 @@ abstract class HttpSource : CatalogueSource {
|
|||||||
*/
|
*/
|
||||||
private fun getUrlWithoutDomain(orig: String): String {
|
private fun getUrlWithoutDomain(orig: String): String {
|
||||||
return try {
|
return try {
|
||||||
val uri = URI(orig)
|
val uri = URI(orig.replace(" ", "%20"))
|
||||||
var out = uri.path
|
var out = uri.path
|
||||||
if (uri.query != null) {
|
if (uri.query != null) {
|
||||||
out += "?" + uri.query
|
out += "?" + uri.query
|
||||||
|
|||||||
@@ -12,15 +12,8 @@ import graphql.schema.DataFetchingEnvironment
|
|||||||
import org.jetbrains.exposed.sql.Column
|
import org.jetbrains.exposed.sql.Column
|
||||||
import org.jetbrains.exposed.sql.Op
|
import org.jetbrains.exposed.sql.Op
|
||||||
import org.jetbrains.exposed.sql.SortOrder
|
import org.jetbrains.exposed.sql.SortOrder
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC_NULLS_FIRST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC_NULLS_LAST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC_NULLS_FIRST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC_NULLS_LAST
|
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
|
||||||
import org.jetbrains.exposed.sql.andWhere
|
|
||||||
import org.jetbrains.exposed.sql.selectAll
|
import org.jetbrains.exposed.sql.selectAll
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
|
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
|
||||||
@@ -37,6 +30,7 @@ import suwayomi.tachidesk.graphql.server.primitives.Cursor
|
|||||||
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
|
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.PageInfo
|
import suwayomi.tachidesk.graphql.server.primitives.PageInfo
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.QueryResults
|
import suwayomi.tachidesk.graphql.server.primitives.QueryResults
|
||||||
|
import suwayomi.tachidesk.graphql.server.primitives.applyBeforeAfter
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.greaterNotUnique
|
import suwayomi.tachidesk.graphql.server.primitives.greaterNotUnique
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.lessNotUnique
|
import suwayomi.tachidesk.graphql.server.primitives.lessNotUnique
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
|
import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
|
||||||
@@ -157,21 +151,12 @@ class CategoryQuery {
|
|||||||
val firstResult = res.firstOrNull()?.get(CategoryTable.id)?.value
|
val firstResult = res.firstOrNull()?.get(CategoryTable.id)?.value
|
||||||
val lastResult = res.lastOrNull()?.get(CategoryTable.id)?.value
|
val lastResult = res.lastOrNull()?.get(CategoryTable.id)?.value
|
||||||
|
|
||||||
if (after != null) {
|
res.applyBeforeAfter(
|
||||||
res.andWhere {
|
before = before,
|
||||||
when (orderByType) {
|
after = after,
|
||||||
DESC, DESC_NULLS_FIRST, DESC_NULLS_LAST -> (orderBy ?: CategoryOrderBy.ID).less(after)
|
orderBy = orderBy ?: CategoryOrderBy.ID,
|
||||||
null, ASC, ASC_NULLS_FIRST, ASC_NULLS_LAST -> (orderBy ?: CategoryOrderBy.ID).greater(after)
|
orderByType = orderByType,
|
||||||
}
|
)
|
||||||
}
|
|
||||||
} else if (before != null) {
|
|
||||||
res.andWhere {
|
|
||||||
when (orderByType) {
|
|
||||||
DESC, DESC_NULLS_FIRST, DESC_NULLS_LAST -> (orderBy ?: CategoryOrderBy.ID).greater(before)
|
|
||||||
null, ASC, ASC_NULLS_FIRST, ASC_NULLS_LAST -> (orderBy ?: CategoryOrderBy.ID).less(before)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first != null) {
|
if (first != null) {
|
||||||
res.limit(first, offset?.toLong() ?: 0)
|
res.limit(first, offset?.toLong() ?: 0)
|
||||||
|
|||||||
@@ -12,18 +12,11 @@ import graphql.schema.DataFetchingEnvironment
|
|||||||
import org.jetbrains.exposed.sql.Column
|
import org.jetbrains.exposed.sql.Column
|
||||||
import org.jetbrains.exposed.sql.Op
|
import org.jetbrains.exposed.sql.Op
|
||||||
import org.jetbrains.exposed.sql.SortOrder
|
import org.jetbrains.exposed.sql.SortOrder
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC_NULLS_FIRST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC_NULLS_LAST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC_NULLS_FIRST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC_NULLS_LAST
|
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
|
||||||
import org.jetbrains.exposed.sql.andWhere
|
import org.jetbrains.exposed.sql.andWhere
|
||||||
import org.jetbrains.exposed.sql.selectAll
|
import org.jetbrains.exposed.sql.selectAll
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import suwayomi.tachidesk.graphql.queries.ChapterQuery.ChapterOrderBy.ID
|
|
||||||
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
|
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
|
||||||
import suwayomi.tachidesk.graphql.queries.filter.Filter
|
import suwayomi.tachidesk.graphql.queries.filter.Filter
|
||||||
import suwayomi.tachidesk.graphql.queries.filter.FloatFilter
|
import suwayomi.tachidesk.graphql.queries.filter.FloatFilter
|
||||||
@@ -40,6 +33,7 @@ import suwayomi.tachidesk.graphql.server.primitives.Cursor
|
|||||||
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
|
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.PageInfo
|
import suwayomi.tachidesk.graphql.server.primitives.PageInfo
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.QueryResults
|
import suwayomi.tachidesk.graphql.server.primitives.QueryResults
|
||||||
|
import suwayomi.tachidesk.graphql.server.primitives.applyBeforeAfter
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.greaterNotUnique
|
import suwayomi.tachidesk.graphql.server.primitives.greaterNotUnique
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.lessNotUnique
|
import suwayomi.tachidesk.graphql.server.primitives.lessNotUnique
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
|
import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
|
||||||
@@ -241,21 +235,12 @@ class ChapterQuery {
|
|||||||
val firstResult = res.firstOrNull()?.get(ChapterTable.id)?.value
|
val firstResult = res.firstOrNull()?.get(ChapterTable.id)?.value
|
||||||
val lastResult = res.lastOrNull()?.get(ChapterTable.id)?.value
|
val lastResult = res.lastOrNull()?.get(ChapterTable.id)?.value
|
||||||
|
|
||||||
if (after != null) {
|
res.applyBeforeAfter(
|
||||||
res.andWhere {
|
before = before,
|
||||||
when (orderByType) {
|
after = after,
|
||||||
DESC, DESC_NULLS_FIRST, DESC_NULLS_LAST -> (orderBy ?: ID).less(after)
|
orderBy = orderBy ?: ChapterOrderBy.ID,
|
||||||
null, ASC, ASC_NULLS_FIRST, ASC_NULLS_LAST -> (orderBy ?: ID).greater(after)
|
orderByType = orderByType,
|
||||||
}
|
)
|
||||||
}
|
|
||||||
} else if (before != null) {
|
|
||||||
res.andWhere {
|
|
||||||
when (orderByType) {
|
|
||||||
DESC, DESC_NULLS_FIRST, DESC_NULLS_LAST -> (orderBy ?: ID).greater(before)
|
|
||||||
null, ASC, ASC_NULLS_FIRST, ASC_NULLS_LAST -> (orderBy ?: ID).less(before)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first != null) {
|
if (first != null) {
|
||||||
res.limit(first, offset?.toLong() ?: 0)
|
res.limit(first, offset?.toLong() ?: 0)
|
||||||
|
|||||||
@@ -13,16 +13,9 @@ import graphql.schema.DataFetchingEnvironment
|
|||||||
import org.jetbrains.exposed.sql.Column
|
import org.jetbrains.exposed.sql.Column
|
||||||
import org.jetbrains.exposed.sql.Op
|
import org.jetbrains.exposed.sql.Op
|
||||||
import org.jetbrains.exposed.sql.SortOrder
|
import org.jetbrains.exposed.sql.SortOrder
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC_NULLS_FIRST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC_NULLS_LAST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC_NULLS_FIRST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC_NULLS_LAST
|
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.neq
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.neq
|
||||||
import org.jetbrains.exposed.sql.andWhere
|
|
||||||
import org.jetbrains.exposed.sql.selectAll
|
import org.jetbrains.exposed.sql.selectAll
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
|
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
|
||||||
@@ -38,6 +31,7 @@ import suwayomi.tachidesk.graphql.server.primitives.Cursor
|
|||||||
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
|
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.PageInfo
|
import suwayomi.tachidesk.graphql.server.primitives.PageInfo
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.QueryResults
|
import suwayomi.tachidesk.graphql.server.primitives.QueryResults
|
||||||
|
import suwayomi.tachidesk.graphql.server.primitives.applyBeforeAfter
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.greaterNotUnique
|
import suwayomi.tachidesk.graphql.server.primitives.greaterNotUnique
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.lessNotUnique
|
import suwayomi.tachidesk.graphql.server.primitives.lessNotUnique
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
|
import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
|
||||||
@@ -187,21 +181,12 @@ class ExtensionQuery {
|
|||||||
val firstResult = res.firstOrNull()?.get(ExtensionTable.pkgName)
|
val firstResult = res.firstOrNull()?.get(ExtensionTable.pkgName)
|
||||||
val lastResult = res.lastOrNull()?.get(ExtensionTable.pkgName)
|
val lastResult = res.lastOrNull()?.get(ExtensionTable.pkgName)
|
||||||
|
|
||||||
if (after != null) {
|
res.applyBeforeAfter(
|
||||||
res.andWhere {
|
before = before,
|
||||||
when (orderByType) {
|
after = after,
|
||||||
DESC, DESC_NULLS_FIRST, DESC_NULLS_LAST -> (orderBy ?: ExtensionOrderBy.PKG_NAME).less(after)
|
orderBy = orderBy ?: ExtensionOrderBy.PKG_NAME,
|
||||||
null, ASC, ASC_NULLS_FIRST, ASC_NULLS_LAST -> (orderBy ?: ExtensionOrderBy.PKG_NAME).greater(after)
|
orderByType = orderByType,
|
||||||
}
|
)
|
||||||
}
|
|
||||||
} else if (before != null) {
|
|
||||||
res.andWhere {
|
|
||||||
when (orderByType) {
|
|
||||||
DESC, DESC_NULLS_FIRST, DESC_NULLS_LAST -> (orderBy ?: ExtensionOrderBy.PKG_NAME).greater(before)
|
|
||||||
null, ASC, ASC_NULLS_FIRST, ASC_NULLS_LAST -> (orderBy ?: ExtensionOrderBy.PKG_NAME).less(before)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first != null) {
|
if (first != null) {
|
||||||
res.limit(first, offset?.toLong() ?: 0)
|
res.limit(first, offset?.toLong() ?: 0)
|
||||||
|
|||||||
@@ -12,15 +12,8 @@ import graphql.schema.DataFetchingEnvironment
|
|||||||
import org.jetbrains.exposed.sql.Column
|
import org.jetbrains.exposed.sql.Column
|
||||||
import org.jetbrains.exposed.sql.Op
|
import org.jetbrains.exposed.sql.Op
|
||||||
import org.jetbrains.exposed.sql.SortOrder
|
import org.jetbrains.exposed.sql.SortOrder
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC_NULLS_FIRST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC_NULLS_LAST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC_NULLS_FIRST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC_NULLS_LAST
|
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
|
||||||
import org.jetbrains.exposed.sql.andWhere
|
|
||||||
import org.jetbrains.exposed.sql.selectAll
|
import org.jetbrains.exposed.sql.selectAll
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
|
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
|
||||||
@@ -39,6 +32,7 @@ import suwayomi.tachidesk.graphql.server.primitives.Cursor
|
|||||||
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
|
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.PageInfo
|
import suwayomi.tachidesk.graphql.server.primitives.PageInfo
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.QueryResults
|
import suwayomi.tachidesk.graphql.server.primitives.QueryResults
|
||||||
|
import suwayomi.tachidesk.graphql.server.primitives.applyBeforeAfter
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.greaterNotUnique
|
import suwayomi.tachidesk.graphql.server.primitives.greaterNotUnique
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.lessNotUnique
|
import suwayomi.tachidesk.graphql.server.primitives.lessNotUnique
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
|
import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
|
||||||
@@ -245,21 +239,12 @@ class MangaQuery {
|
|||||||
val firstResult = res.firstOrNull()?.get(MangaTable.id)?.value
|
val firstResult = res.firstOrNull()?.get(MangaTable.id)?.value
|
||||||
val lastResult = res.lastOrNull()?.get(MangaTable.id)?.value
|
val lastResult = res.lastOrNull()?.get(MangaTable.id)?.value
|
||||||
|
|
||||||
if (after != null) {
|
res.applyBeforeAfter(
|
||||||
res.andWhere {
|
before = before,
|
||||||
when (orderByType) {
|
after = after,
|
||||||
DESC, DESC_NULLS_FIRST, DESC_NULLS_LAST -> (orderBy ?: MangaOrderBy.ID).less(after)
|
orderBy = orderBy ?: MangaOrderBy.ID,
|
||||||
null, ASC, ASC_NULLS_FIRST, ASC_NULLS_LAST -> (orderBy ?: MangaOrderBy.ID).greater(after)
|
orderByType = orderByType,
|
||||||
}
|
)
|
||||||
}
|
|
||||||
} else if (before != null) {
|
|
||||||
res.andWhere {
|
|
||||||
when (orderByType) {
|
|
||||||
DESC, DESC_NULLS_FIRST, DESC_NULLS_LAST -> (orderBy ?: MangaOrderBy.ID).greater(before)
|
|
||||||
null, ASC, ASC_NULLS_FIRST, ASC_NULLS_LAST -> (orderBy ?: MangaOrderBy.ID).less(before)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first != null) {
|
if (first != null) {
|
||||||
res.limit(first, offset?.toLong() ?: 0)
|
res.limit(first, offset?.toLong() ?: 0)
|
||||||
|
|||||||
@@ -12,15 +12,8 @@ import graphql.schema.DataFetchingEnvironment
|
|||||||
import org.jetbrains.exposed.sql.Column
|
import org.jetbrains.exposed.sql.Column
|
||||||
import org.jetbrains.exposed.sql.Op
|
import org.jetbrains.exposed.sql.Op
|
||||||
import org.jetbrains.exposed.sql.SortOrder
|
import org.jetbrains.exposed.sql.SortOrder
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC_NULLS_FIRST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC_NULLS_LAST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC_NULLS_FIRST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC_NULLS_LAST
|
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
|
||||||
import org.jetbrains.exposed.sql.andWhere
|
|
||||||
import org.jetbrains.exposed.sql.selectAll
|
import org.jetbrains.exposed.sql.selectAll
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import suwayomi.tachidesk.global.model.table.GlobalMetaTable
|
import suwayomi.tachidesk.global.model.table.GlobalMetaTable
|
||||||
@@ -34,6 +27,7 @@ import suwayomi.tachidesk.graphql.server.primitives.Cursor
|
|||||||
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
|
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.PageInfo
|
import suwayomi.tachidesk.graphql.server.primitives.PageInfo
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.QueryResults
|
import suwayomi.tachidesk.graphql.server.primitives.QueryResults
|
||||||
|
import suwayomi.tachidesk.graphql.server.primitives.applyBeforeAfter
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.greaterNotUnique
|
import suwayomi.tachidesk.graphql.server.primitives.greaterNotUnique
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.lessNotUnique
|
import suwayomi.tachidesk.graphql.server.primitives.lessNotUnique
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
|
import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
|
||||||
@@ -141,21 +135,12 @@ class MetaQuery {
|
|||||||
val firstResult = res.firstOrNull()?.get(GlobalMetaTable.key)
|
val firstResult = res.firstOrNull()?.get(GlobalMetaTable.key)
|
||||||
val lastResult = res.lastOrNull()?.get(GlobalMetaTable.key)
|
val lastResult = res.lastOrNull()?.get(GlobalMetaTable.key)
|
||||||
|
|
||||||
if (after != null) {
|
res.applyBeforeAfter(
|
||||||
res.andWhere {
|
before = before,
|
||||||
when (orderByType) {
|
after = after,
|
||||||
DESC, DESC_NULLS_FIRST, DESC_NULLS_LAST -> (orderBy ?: MetaOrderBy.KEY).less(after)
|
orderBy = orderBy ?: MetaOrderBy.KEY,
|
||||||
null, ASC, ASC_NULLS_FIRST, ASC_NULLS_LAST -> (orderBy ?: MetaOrderBy.KEY).greater(after)
|
orderByType = orderByType,
|
||||||
}
|
)
|
||||||
}
|
|
||||||
} else if (before != null) {
|
|
||||||
res.andWhere {
|
|
||||||
when (orderByType) {
|
|
||||||
DESC, DESC_NULLS_FIRST, DESC_NULLS_LAST -> (orderBy ?: MetaOrderBy.KEY).greater(before)
|
|
||||||
null, ASC, ASC_NULLS_FIRST, ASC_NULLS_LAST -> (orderBy ?: MetaOrderBy.KEY).less(before)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first != null) {
|
if (first != null) {
|
||||||
res.limit(first, offset?.toLong() ?: 0)
|
res.limit(first, offset?.toLong() ?: 0)
|
||||||
|
|||||||
@@ -12,15 +12,8 @@ import graphql.schema.DataFetchingEnvironment
|
|||||||
import org.jetbrains.exposed.sql.Column
|
import org.jetbrains.exposed.sql.Column
|
||||||
import org.jetbrains.exposed.sql.Op
|
import org.jetbrains.exposed.sql.Op
|
||||||
import org.jetbrains.exposed.sql.SortOrder
|
import org.jetbrains.exposed.sql.SortOrder
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC_NULLS_FIRST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.ASC_NULLS_LAST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC_NULLS_FIRST
|
|
||||||
import org.jetbrains.exposed.sql.SortOrder.DESC_NULLS_LAST
|
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
|
||||||
import org.jetbrains.exposed.sql.andWhere
|
|
||||||
import org.jetbrains.exposed.sql.selectAll
|
import org.jetbrains.exposed.sql.selectAll
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
|
import suwayomi.tachidesk.graphql.queries.filter.BooleanFilter
|
||||||
@@ -37,6 +30,7 @@ import suwayomi.tachidesk.graphql.server.primitives.Cursor
|
|||||||
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
|
import suwayomi.tachidesk.graphql.server.primitives.OrderBy
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.PageInfo
|
import suwayomi.tachidesk.graphql.server.primitives.PageInfo
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.QueryResults
|
import suwayomi.tachidesk.graphql.server.primitives.QueryResults
|
||||||
|
import suwayomi.tachidesk.graphql.server.primitives.applyBeforeAfter
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.greaterNotUnique
|
import suwayomi.tachidesk.graphql.server.primitives.greaterNotUnique
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.lessNotUnique
|
import suwayomi.tachidesk.graphql.server.primitives.lessNotUnique
|
||||||
import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
|
import suwayomi.tachidesk.graphql.server.primitives.maybeSwap
|
||||||
@@ -157,21 +151,12 @@ class SourceQuery {
|
|||||||
val firstResult = res.firstOrNull()?.get(SourceTable.id)?.value
|
val firstResult = res.firstOrNull()?.get(SourceTable.id)?.value
|
||||||
val lastResult = res.lastOrNull()?.get(SourceTable.id)?.value
|
val lastResult = res.lastOrNull()?.get(SourceTable.id)?.value
|
||||||
|
|
||||||
if (after != null) {
|
res.applyBeforeAfter(
|
||||||
res.andWhere {
|
before = before,
|
||||||
when (orderByType) {
|
after = after,
|
||||||
DESC, DESC_NULLS_FIRST, DESC_NULLS_LAST -> (orderBy ?: SourceOrderBy.ID).less(after)
|
orderBy = orderBy ?: SourceOrderBy.ID,
|
||||||
null, ASC, ASC_NULLS_FIRST, ASC_NULLS_LAST -> (orderBy ?: SourceOrderBy.ID).greater(after)
|
orderByType = orderByType,
|
||||||
}
|
)
|
||||||
}
|
|
||||||
} else if (before != null) {
|
|
||||||
res.andWhere {
|
|
||||||
when (orderByType) {
|
|
||||||
DESC, DESC_NULLS_FIRST, DESC_NULLS_LAST -> (orderBy ?: SourceOrderBy.ID).greater(before)
|
|
||||||
null, ASC, ASC_NULLS_FIRST, ASC_NULLS_LAST -> (orderBy ?: SourceOrderBy.ID).less(before)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first != null) {
|
if (first != null) {
|
||||||
res.limit(first, offset?.toLong() ?: 0)
|
res.limit(first, offset?.toLong() ?: 0)
|
||||||
|
|||||||
@@ -313,7 +313,7 @@ data class StringListFilter(
|
|||||||
val hasNoneInsensitive: List<String>? = null,
|
val hasNoneInsensitive: List<String>? = null,
|
||||||
) : ListScalarFilter<String, List<String>>
|
) : ListScalarFilter<String, List<String>>
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST", "FINAL_UPPER_BOUND")
|
||||||
fun <T : String, S : T?> andFilterWithCompareString(
|
fun <T : String, S : T?> andFilterWithCompareString(
|
||||||
column: Column<S>,
|
column: Column<S>,
|
||||||
filter: StringFilter?,
|
filter: StringFilter?,
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
@file:Suppress("DEPRECATION")
|
||||||
|
|
||||||
package suwayomi.tachidesk.graphql.server
|
package suwayomi.tachidesk.graphql.server
|
||||||
|
|
||||||
import com.expediagroup.graphql.generator.execution.GraphQLContext
|
import com.expediagroup.graphql.generator.execution.GraphQLContext
|
||||||
@@ -30,7 +32,9 @@ class TachideskGraphQLContextFactory : GraphQLContextFactory<GraphQLContext, Con
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
fun generateContextMap(request: WsContext): Map<*, Any> = emptyMap<Any, Any>()
|
fun generateContextMap(
|
||||||
|
@Suppress("UNUSED_PARAMETER") request: WsContext,
|
||||||
|
): Map<*, Any> = emptyMap<Any, Any>()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import graphql.GraphQL
|
|||||||
import io.javalin.http.Context
|
import io.javalin.http.Context
|
||||||
import io.javalin.websocket.WsCloseContext
|
import io.javalin.websocket.WsCloseContext
|
||||||
import io.javalin.websocket.WsMessageContext
|
import io.javalin.websocket.WsMessageContext
|
||||||
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
@@ -30,6 +31,7 @@ class TachideskGraphQLServer(
|
|||||||
private val objectMapper = jacksonObjectMapper()
|
private val objectMapper = jacksonObjectMapper()
|
||||||
private val subscriptionProtocolHandler = ApolloSubscriptionProtocolHandler(contextFactory, subscriptionHandler, objectMapper)
|
private val subscriptionProtocolHandler = ApolloSubscriptionProtocolHandler(contextFactory, subscriptionHandler, objectMapper)
|
||||||
|
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
fun handleSubscriptionMessage(context: WsMessageContext) {
|
fun handleSubscriptionMessage(context: WsMessageContext) {
|
||||||
subscriptionProtocolHandler.handleMessage(context)
|
subscriptionProtocolHandler.handleMessage(context)
|
||||||
.map { objectMapper.writeValueAsString(it) }
|
.map { objectMapper.writeValueAsString(it) }
|
||||||
|
|||||||
@@ -3,11 +3,13 @@ package suwayomi.tachidesk.graphql.server.primitives
|
|||||||
import org.jetbrains.exposed.dao.id.EntityID
|
import org.jetbrains.exposed.dao.id.EntityID
|
||||||
import org.jetbrains.exposed.sql.Column
|
import org.jetbrains.exposed.sql.Column
|
||||||
import org.jetbrains.exposed.sql.Op
|
import org.jetbrains.exposed.sql.Op
|
||||||
|
import org.jetbrains.exposed.sql.Query
|
||||||
import org.jetbrains.exposed.sql.SortOrder
|
import org.jetbrains.exposed.sql.SortOrder
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.greater
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.less
|
||||||
import org.jetbrains.exposed.sql.and
|
import org.jetbrains.exposed.sql.and
|
||||||
|
import org.jetbrains.exposed.sql.andWhere
|
||||||
import org.jetbrains.exposed.sql.or
|
import org.jetbrains.exposed.sql.or
|
||||||
|
|
||||||
interface OrderBy<T> {
|
interface OrderBy<T> {
|
||||||
@@ -36,6 +38,29 @@ fun SortOrder?.maybeSwap(value: Any?): SortOrder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T> Query.applyBeforeAfter(
|
||||||
|
before: Cursor?,
|
||||||
|
after: Cursor?,
|
||||||
|
orderBy: OrderBy<T>,
|
||||||
|
orderByType: SortOrder?,
|
||||||
|
) {
|
||||||
|
if (after != null) {
|
||||||
|
andWhere {
|
||||||
|
when (orderByType) {
|
||||||
|
SortOrder.DESC, SortOrder.DESC_NULLS_FIRST, SortOrder.DESC_NULLS_LAST -> orderBy.less(after)
|
||||||
|
null, SortOrder.ASC, SortOrder.ASC_NULLS_FIRST, SortOrder.ASC_NULLS_LAST -> orderBy.greater(after)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (before != null) {
|
||||||
|
andWhere {
|
||||||
|
when (orderByType) {
|
||||||
|
SortOrder.DESC, SortOrder.DESC_NULLS_FIRST, SortOrder.DESC_NULLS_LAST -> orderBy.greater(before)
|
||||||
|
null, SortOrder.ASC, SortOrder.ASC_NULLS_FIRST, SortOrder.ASC_NULLS_LAST -> orderBy.less(before)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@JvmName("greaterNotUniqueIntKey")
|
@JvmName("greaterNotUniqueIntKey")
|
||||||
fun <T : Comparable<T>> greaterNotUnique(
|
fun <T : Comparable<T>> greaterNotUnique(
|
||||||
column: Column<T>,
|
column: Column<T>,
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ import suwayomi.tachidesk.graphql.server.toGraphQLContext
|
|||||||
import suwayomi.tachidesk.server.serverConfig
|
import suwayomi.tachidesk.server.serverConfig
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the `graphql-ws` protocol defined by Apollo
|
* Implementation of the `graphql-transport-ws` protocol defined by Denis Badurina
|
||||||
* https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md
|
* https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md
|
||||||
* ported for Javalin
|
* ported for Javalin
|
||||||
*/
|
*/
|
||||||
class ApolloSubscriptionProtocolHandler(
|
class ApolloSubscriptionProtocolHandler(
|
||||||
@@ -47,6 +47,10 @@ class ApolloSubscriptionProtocolHandler(
|
|||||||
private val subscriptionHandler: GraphQLSubscriptionHandler,
|
private val subscriptionHandler: GraphQLSubscriptionHandler,
|
||||||
private val objectMapper: ObjectMapper,
|
private val objectMapper: ObjectMapper,
|
||||||
) {
|
) {
|
||||||
|
companion object {
|
||||||
|
private const val UNKNOWN_OPERATION_NAME = "__UNKNOWN__"
|
||||||
|
}
|
||||||
|
|
||||||
private val sessionState = ApolloSubscriptionSessionState()
|
private val sessionState = ApolloSubscriptionSessionState()
|
||||||
private val logger = KotlinLogging.logger {}
|
private val logger = KotlinLogging.logger {}
|
||||||
private val pongMessage = SubscriptionOperationMessage(type = GQL_PONG.type)
|
private val pongMessage = SubscriptionOperationMessage(type = GQL_PONG.type)
|
||||||
@@ -54,14 +58,10 @@ class ApolloSubscriptionProtocolHandler(
|
|||||||
private val acknowledgeMessage = SubscriptionOperationMessage(GQL_CONNECTION_ACK.type)
|
private val acknowledgeMessage = SubscriptionOperationMessage(GQL_CONNECTION_ACK.type)
|
||||||
|
|
||||||
private fun getOperationName(payload: Any?): String {
|
private fun getOperationName(payload: Any?): String {
|
||||||
val unknownOperationName = "__UNKNOWN__"
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return (payload as? Map<String, String>)
|
||||||
try {
|
.orEmpty()
|
||||||
@Suppress("UNCHECKED_CAST")
|
.getOrDefault("operationName", UNKNOWN_OPERATION_NAME)
|
||||||
return (payload as Map<String, String>)["operationName"] ?: unknownOperationName
|
|
||||||
} catch (e: Exception) {
|
|
||||||
return unknownOperationName
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleMessage(context: WsMessageContext): Flow<SubscriptionOperationMessage> {
|
fun handleMessage(context: WsMessageContext): Flow<SubscriptionOperationMessage> {
|
||||||
@@ -83,12 +83,12 @@ class ApolloSubscriptionProtocolHandler(
|
|||||||
|
|
||||||
return try {
|
return try {
|
||||||
when (operationMessage.type) {
|
when (operationMessage.type) {
|
||||||
GQL_CONNECTION_INIT.type -> onInit(operationMessage, context)
|
GQL_CONNECTION_INIT.type -> onInit(context)
|
||||||
GQL_SUBSCRIBE.type -> startSubscription(operationMessage, context)
|
GQL_SUBSCRIBE.type -> startSubscription(operationMessage, context)
|
||||||
GQL_COMPLETE.type -> onComplete(operationMessage, context)
|
GQL_COMPLETE.type -> onComplete(operationMessage)
|
||||||
GQL_PING.type -> onPing()
|
GQL_PING.type -> onPing()
|
||||||
GQL_PONG.type -> emptyFlow()
|
GQL_PONG.type -> emptyFlow()
|
||||||
else -> onUnknownOperation(operationMessage, context)
|
else -> onUnknownOperation(operationMessage)
|
||||||
}
|
}
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
onException(exception)
|
onException(exception)
|
||||||
@@ -108,7 +108,6 @@ class ApolloSubscriptionProtocolHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("Detekt.TooGenericExceptionCaught")
|
|
||||||
private fun startSubscription(
|
private fun startSubscription(
|
||||||
operationMessage: SubscriptionOperationMessage,
|
operationMessage: SubscriptionOperationMessage,
|
||||||
context: WsContext,
|
context: WsContext,
|
||||||
@@ -142,7 +141,7 @@ class ApolloSubscriptionProtocolHandler(
|
|||||||
SubscriptionOperationMessage(type = GQL_NEXT.type, id = operationMessage.id, payload = it)
|
SubscriptionOperationMessage(type = GQL_NEXT.type, id = operationMessage.id, payload = it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onCompletion { if (it == null) emitAll(onComplete(operationMessage, context)) }
|
.onCompletion { if (it == null) emitAll(onComplete(operationMessage)) }
|
||||||
.onStart { sessionState.saveOperation(context, operationMessage, currentCoroutineContext().job) }
|
.onStart { sessionState.saveOperation(context, operationMessage, currentCoroutineContext().job) }
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
logger.error("Error running graphql subscription", exception)
|
logger.error("Error running graphql subscription", exception)
|
||||||
@@ -152,21 +151,15 @@ class ApolloSubscriptionProtocolHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onInit(
|
private fun onInit(context: WsContext): Flow<SubscriptionOperationMessage> {
|
||||||
operationMessage: SubscriptionOperationMessage,
|
saveContext(context)
|
||||||
context: WsContext,
|
|
||||||
): Flow<SubscriptionOperationMessage> {
|
|
||||||
saveContext(operationMessage, context)
|
|
||||||
return flowOf(acknowledgeMessage)
|
return flowOf(acknowledgeMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the context and save it for all future messages.
|
* Generate the context and save it for all future messages.
|
||||||
*/
|
*/
|
||||||
private fun saveContext(
|
private fun saveContext(context: WsContext) {
|
||||||
operationMessage: SubscriptionOperationMessage,
|
|
||||||
context: WsContext,
|
|
||||||
) {
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val graphQLContext = contextFactory.generateContextMap(context).toGraphQLContext()
|
val graphQLContext = contextFactory.generateContextMap(context).toGraphQLContext()
|
||||||
sessionState.saveContext(context, graphQLContext)
|
sessionState.saveContext(context, graphQLContext)
|
||||||
@@ -176,10 +169,7 @@ class ApolloSubscriptionProtocolHandler(
|
|||||||
/**
|
/**
|
||||||
* Called with the publisher has completed on its own.
|
* Called with the publisher has completed on its own.
|
||||||
*/
|
*/
|
||||||
private fun onComplete(
|
private fun onComplete(operationMessage: SubscriptionOperationMessage): Flow<SubscriptionOperationMessage> {
|
||||||
operationMessage: SubscriptionOperationMessage,
|
|
||||||
context: WsContext,
|
|
||||||
): Flow<SubscriptionOperationMessage> {
|
|
||||||
return sessionState.completeOperation(operationMessage)
|
return sessionState.completeOperation(operationMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,10 +182,7 @@ class ApolloSubscriptionProtocolHandler(
|
|||||||
return emptyFlow()
|
return emptyFlow()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onUnknownOperation(
|
private fun onUnknownOperation(operationMessage: SubscriptionOperationMessage): Flow<SubscriptionOperationMessage> {
|
||||||
operationMessage: SubscriptionOperationMessage,
|
|
||||||
context: WsContext,
|
|
||||||
): Flow<SubscriptionOperationMessage> {
|
|
||||||
logger.error("Unknown subscription operation $operationMessage")
|
logger.error("Unknown subscription operation $operationMessage")
|
||||||
sessionState.completeOperation(operationMessage)
|
sessionState.completeOperation(operationMessage)
|
||||||
return emptyFlow()
|
return emptyFlow()
|
||||||
|
|||||||
@@ -22,11 +22,4 @@ interface Chapter : SChapter, Serializable {
|
|||||||
|
|
||||||
val isRecognizedNumber: Boolean
|
val isRecognizedNumber: Boolean
|
||||||
get() = chapter_number >= 0f
|
get() = chapter_number >= 0f
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun create(): Chapter =
|
|
||||||
ChapterImpl().apply {
|
|
||||||
chapter_number = -1f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
package suwayomi.tachidesk.manga.impl.backup.models
|
package suwayomi.tachidesk.manga.impl.backup.models
|
||||||
|
|
||||||
import org.jetbrains.exposed.sql.ResultRow
|
|
||||||
import suwayomi.tachidesk.manga.model.table.ChapterTable
|
|
||||||
|
|
||||||
class ChapterImpl : Chapter {
|
class ChapterImpl : Chapter {
|
||||||
override var id: Long? = null
|
override var id: Long? = null
|
||||||
|
|
||||||
@@ -42,17 +39,4 @@ class ChapterImpl : Chapter {
|
|||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
return url.hashCode() + id.hashCode()
|
return url.hashCode() + id.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tachidesk -->
|
|
||||||
companion object {
|
|
||||||
fun fromQuery(chapterRecord: ResultRow): ChapterImpl {
|
|
||||||
return ChapterImpl().apply {
|
|
||||||
url = chapterRecord[ChapterTable.url]
|
|
||||||
read = chapterRecord[ChapterTable.isRead]
|
|
||||||
bookmark = chapterRecord[ChapterTable.isBookmarked]
|
|
||||||
last_page_read = chapterRecord[ChapterTable.lastPageRead]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Tachidesk <--
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,22 +120,6 @@ interface Manga : SManga {
|
|||||||
const val CHAPTER_DISPLAY_NAME = 0x00000000
|
const val CHAPTER_DISPLAY_NAME = 0x00000000
|
||||||
const val CHAPTER_DISPLAY_NUMBER = 0x00100000
|
const val CHAPTER_DISPLAY_NUMBER = 0x00100000
|
||||||
const val CHAPTER_DISPLAY_MASK = 0x00100000
|
const val CHAPTER_DISPLAY_MASK = 0x00100000
|
||||||
|
|
||||||
fun create(source: Long): Manga =
|
|
||||||
MangaImpl().apply {
|
|
||||||
this.source = source
|
|
||||||
}
|
|
||||||
|
|
||||||
fun create(
|
|
||||||
pathUrl: String,
|
|
||||||
title: String,
|
|
||||||
source: Long = 0,
|
|
||||||
): Manga =
|
|
||||||
MangaImpl().apply {
|
|
||||||
url = pathUrl
|
|
||||||
this.title = title
|
|
||||||
this.source = source
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
package suwayomi.tachidesk.manga.impl.backup.models
|
package suwayomi.tachidesk.manga.impl.backup.models
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.UpdateStrategy
|
import eu.kanade.tachiyomi.source.model.UpdateStrategy
|
||||||
import org.jetbrains.exposed.sql.ResultRow
|
|
||||||
import suwayomi.tachidesk.manga.model.table.MangaTable
|
|
||||||
|
|
||||||
open class MangaImpl : Manga {
|
open class MangaImpl : Manga {
|
||||||
override var id: Long? = null
|
override var id: Long? = null
|
||||||
@@ -68,18 +66,4 @@ open class MangaImpl : Manga {
|
|||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
return url.hashCode() + id.hashCode()
|
return url.hashCode() + id.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tachidesk -->
|
|
||||||
companion object {
|
|
||||||
fun fromQuery(mangaRecord: ResultRow): MangaImpl {
|
|
||||||
return MangaImpl().apply {
|
|
||||||
url = mangaRecord[MangaTable.url]
|
|
||||||
title = mangaRecord[MangaTable.title]
|
|
||||||
source = mangaRecord[MangaTable.sourceReference]
|
|
||||||
viewer_flags = 0 // TODO: implement
|
|
||||||
chapter_flags = 0 // TODO: implement
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Tachidesk <--
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,19 +30,4 @@ interface Track : Serializable {
|
|||||||
var finished_reading_date: Long
|
var finished_reading_date: Long
|
||||||
|
|
||||||
var tracking_url: String
|
var tracking_url: String
|
||||||
|
|
||||||
fun copyPersonalFrom(other: Track) {
|
|
||||||
last_chapter_read = other.last_chapter_read
|
|
||||||
score = other.score
|
|
||||||
status = other.status
|
|
||||||
started_reading_date = other.started_reading_date
|
|
||||||
finished_reading_date = other.finished_reading_date
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun create(serviceId: Int): Track =
|
|
||||||
TrackImpl().apply {
|
|
||||||
sync_id = serviceId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package suwayomi.tachidesk.manga.impl.backup.proto.models
|
|||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.protobuf.ProtoNumber
|
import kotlinx.serialization.protobuf.ProtoNumber
|
||||||
import suwayomi.tachidesk.manga.impl.backup.models.Chapter
|
|
||||||
import suwayomi.tachidesk.manga.impl.backup.models.ChapterImpl
|
import suwayomi.tachidesk.manga.impl.backup.models.ChapterImpl
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@@ -36,21 +35,4 @@ data class BackupChapter(
|
|||||||
source_order = this@BackupChapter.sourceOrder
|
source_order = this@BackupChapter.sourceOrder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun copyFrom(chapter: Chapter): BackupChapter {
|
|
||||||
return BackupChapter(
|
|
||||||
url = chapter.url,
|
|
||||||
name = chapter.name,
|
|
||||||
chapterNumber = chapter.chapter_number,
|
|
||||||
scanlator = chapter.scanlator,
|
|
||||||
read = chapter.read,
|
|
||||||
bookmark = chapter.bookmark,
|
|
||||||
lastPageRead = chapter.last_page_read,
|
|
||||||
dateFetch = chapter.date_fetch,
|
|
||||||
dateUpload = chapter.date_upload,
|
|
||||||
sourceOrder = chapter.source_order,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import io.javalin.websocket.WsContext
|
|||||||
import io.javalin.websocket.WsMessageContext
|
import io.javalin.websocket.WsMessageContext
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.FlowPreview
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
@@ -51,6 +52,7 @@ import kotlin.time.Duration.Companion.seconds
|
|||||||
|
|
||||||
private val logger = KotlinLogging.logger {}
|
private val logger = KotlinLogging.logger {}
|
||||||
|
|
||||||
|
@OptIn(FlowPreview::class)
|
||||||
object DownloadManager {
|
object DownloadManager {
|
||||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
|
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
|
||||||
private val clients = ConcurrentHashMap<String, WsContext>()
|
private val clients = ConcurrentHashMap<String, WsContext>()
|
||||||
@@ -150,9 +152,6 @@ object DownloadManager {
|
|||||||
if (immediate) {
|
if (immediate) {
|
||||||
sendStatusToAllClients()
|
sendStatusToAllClients()
|
||||||
}
|
}
|
||||||
/*if (downloadChapter != null) { TODO GRAPHQL
|
|
||||||
downloadSubscriptionSource.publish(downloadChapter)
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getStatus(): DownloadStatus {
|
private fun getStatus(): DownloadStatus {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ fun interface FileDownload0Args : FileDownload {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun interface FileDownload3Args<A, B, C> : FileDownload {
|
fun interface FileDownload3Args<A, B, C> : FileDownload {
|
||||||
suspend fun execute(
|
suspend fun execute(
|
||||||
a: A,
|
a: A,
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ fun interface RetrieveFile0Args : RetrieveFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun interface RetrieveFile1Args<A> : RetrieveFile {
|
fun interface RetrieveFile1Args<A> : RetrieveFile {
|
||||||
fun execute(a: A): Pair<InputStream, String>
|
fun execute(a: A): Pair<InputStream, String>
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package suwayomi.tachidesk.manga.impl.util.network
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
import okhttp3.Call
|
import okhttp3.Call
|
||||||
import okhttp3.Callback
|
import okhttp3.Callback
|
||||||
@@ -16,6 +17,7 @@ import java.io.IOException
|
|||||||
import kotlin.coroutines.resumeWithException
|
import kotlin.coroutines.resumeWithException
|
||||||
|
|
||||||
// Based on https://github.com/gildor/kotlin-coroutines-okhttp
|
// Based on https://github.com/gildor/kotlin-coroutines-okhttp
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
suspend fun Call.await(): Response {
|
suspend fun Call.await(): Response {
|
||||||
return suspendCancellableCoroutine { continuation ->
|
return suspendCancellableCoroutine { continuation ->
|
||||||
enqueue(
|
enqueue(
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ package suwayomi.tachidesk.server
|
|||||||
import com.typesafe.config.Config
|
import com.typesafe.config.Config
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.channels.BufferOverflow
|
import kotlinx.coroutines.channels.BufferOverflow
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
@@ -111,6 +112,7 @@ class ServerConfig(getConfig: () -> Config, val moduleName: String = SERVER_CONF
|
|||||||
// local source
|
// local source
|
||||||
val localSourcePath: MutableStateFlow<String> by OverrideConfigValue(StringConfigAdapter)
|
val localSourcePath: MutableStateFlow<String> by OverrideConfigValue(StringConfigAdapter)
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
fun <T> subscribeTo(
|
fun <T> subscribeTo(
|
||||||
flow: Flow<T>,
|
flow: Flow<T>,
|
||||||
onChange: suspend (value: T) -> Unit,
|
onChange: suspend (value: T) -> Unit,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import eu.kanade.tachiyomi.network.NetworkHelper
|
|||||||
import eu.kanade.tachiyomi.network.awaitSuccess
|
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.FlowPreview
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.channels.BufferOverflow.DROP_OLDEST
|
import kotlinx.coroutines.channels.BufferOverflow.DROP_OLDEST
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
@@ -131,6 +132,8 @@ object WebInterfaceManager {
|
|||||||
|
|
||||||
private val notifyFlow =
|
private val notifyFlow =
|
||||||
MutableSharedFlow<WebUIUpdateStatus>(extraBufferCapacity = 1, onBufferOverflow = DROP_OLDEST)
|
MutableSharedFlow<WebUIUpdateStatus>(extraBufferCapacity = 1, onBufferOverflow = DROP_OLDEST)
|
||||||
|
|
||||||
|
@OptIn(FlowPreview::class)
|
||||||
val status =
|
val status =
|
||||||
notifyFlow.sample(1.seconds)
|
notifyFlow.sample(1.seconds)
|
||||||
.stateIn(
|
.stateIn(
|
||||||
|
|||||||
Reference in New Issue
Block a user