mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-04 11:24:35 -05:00
Implement Non-Final 1.5 Extensions API (#699)
* Implement non-final 1.5 extensions API * Bump lib version max * Add visibility to preferences * Add preference visibility
This commit is contained in:
@@ -14,7 +14,6 @@ import suwayomi.tachidesk.graphql.types.preferenceOf
|
||||
import suwayomi.tachidesk.graphql.types.updateFilterList
|
||||
import suwayomi.tachidesk.manga.impl.MangaList.insertOrGet
|
||||
import suwayomi.tachidesk.manga.impl.Source
|
||||
import suwayomi.tachidesk.manga.impl.util.lang.awaitSingle
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource
|
||||
import suwayomi.tachidesk.manga.model.table.MangaTable
|
||||
import suwayomi.tachidesk.server.JavalinSetup.future
|
||||
@@ -50,18 +49,18 @@ class SourceMutation {
|
||||
val source = GetCatalogueSource.getCatalogueSourceOrNull(sourceId)!!
|
||||
val mangasPage = when (type) {
|
||||
FetchSourceMangaType.SEARCH -> {
|
||||
source.fetchSearchManga(
|
||||
source.getSearchManga(
|
||||
page = page,
|
||||
query = query.orEmpty(),
|
||||
filters = updateFilterList(source, filters)
|
||||
).awaitSingle()
|
||||
)
|
||||
}
|
||||
FetchSourceMangaType.POPULAR -> {
|
||||
source.fetchPopularManga(page).awaitSingle()
|
||||
source.getPopularManga(page)
|
||||
}
|
||||
FetchSourceMangaType.LATEST -> {
|
||||
if (!source.supportsLatest) throw Exception("Source does not support latest")
|
||||
source.fetchLatestUpdates(page).awaitSingle()
|
||||
source.getLatestUpdates(page)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -299,6 +299,7 @@ data class SwitchPreference(
|
||||
val key: String,
|
||||
val title: String,
|
||||
val summary: String?,
|
||||
val visible: Boolean,
|
||||
val currentValue: Boolean?,
|
||||
val default: Boolean
|
||||
) : Preference
|
||||
@@ -307,6 +308,7 @@ data class CheckBoxPreference(
|
||||
val key: String,
|
||||
val title: String,
|
||||
val summary: String?,
|
||||
val visible: Boolean,
|
||||
val currentValue: Boolean?,
|
||||
val default: Boolean
|
||||
) : Preference
|
||||
@@ -315,6 +317,7 @@ data class EditTextPreference(
|
||||
val key: String,
|
||||
val title: String?,
|
||||
val summary: String?,
|
||||
val visible: Boolean,
|
||||
val currentValue: String?,
|
||||
val default: String?,
|
||||
val dialogTitle: String?,
|
||||
@@ -326,6 +329,7 @@ data class ListPreference(
|
||||
val key: String,
|
||||
val title: String?,
|
||||
val summary: String?,
|
||||
val visible: Boolean,
|
||||
val currentValue: String?,
|
||||
val default: String?,
|
||||
val entries: List<String>,
|
||||
@@ -336,6 +340,7 @@ data class MultiSelectListPreference(
|
||||
val key: String,
|
||||
val title: String?,
|
||||
val summary: String?,
|
||||
val visible: Boolean,
|
||||
val currentValue: List<String>?,
|
||||
val default: List<String>?,
|
||||
val dialogTitle: String?,
|
||||
@@ -350,13 +355,15 @@ fun preferenceOf(preference: SourcePreference): Preference {
|
||||
preference.key,
|
||||
preference.title.toString(),
|
||||
preference.summary?.toString(),
|
||||
preference.visible,
|
||||
preference.currentValue as Boolean,
|
||||
preference.defaultValue as Boolean
|
||||
preference.defaultValue as Boolean,
|
||||
)
|
||||
is SourceCheckBoxPreference -> CheckBoxPreference(
|
||||
preference.key,
|
||||
preference.title.toString(),
|
||||
preference.summary?.toString(),
|
||||
preference.visible,
|
||||
preference.currentValue as Boolean,
|
||||
preference.defaultValue as Boolean
|
||||
)
|
||||
@@ -364,6 +371,7 @@ fun preferenceOf(preference: SourcePreference): Preference {
|
||||
preference.key,
|
||||
preference.title?.toString(),
|
||||
preference.summary?.toString(),
|
||||
preference.visible,
|
||||
(preference.currentValue as CharSequence?)?.toString(),
|
||||
(preference.defaultValue as CharSequence?)?.toString(),
|
||||
preference.dialogTitle?.toString(),
|
||||
@@ -374,6 +382,7 @@ fun preferenceOf(preference: SourcePreference): Preference {
|
||||
preference.key,
|
||||
preference.title?.toString(),
|
||||
preference.summary?.toString(),
|
||||
preference.visible,
|
||||
(preference.currentValue as CharSequence?)?.toString(),
|
||||
(preference.defaultValue as CharSequence?)?.toString(),
|
||||
preference.entries.map { it.toString() },
|
||||
@@ -383,6 +392,7 @@ fun preferenceOf(preference: SourcePreference): Preference {
|
||||
preference.key,
|
||||
preference.title?.toString(),
|
||||
preference.summary?.toString(),
|
||||
preference.visible,
|
||||
(preference.currentValue as Collection<*>?)?.map { it.toString() },
|
||||
(preference.defaultValue as Collection<*>?)?.map { it.toString() },
|
||||
preference.dialogTitle?.toString(),
|
||||
|
||||
@@ -14,7 +14,6 @@ import org.jetbrains.exposed.sql.insertAndGetId
|
||||
import org.jetbrains.exposed.sql.select
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import suwayomi.tachidesk.manga.impl.Manga.getMangaMetaMap
|
||||
import suwayomi.tachidesk.manga.impl.util.lang.awaitSingle
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub
|
||||
import suwayomi.tachidesk.manga.model.dataclass.MangaDataClass
|
||||
import suwayomi.tachidesk.manga.model.dataclass.PagedMangaListDataClass
|
||||
@@ -33,10 +32,10 @@ object MangaList {
|
||||
}
|
||||
val source = getCatalogueSourceOrStub(sourceId)
|
||||
val mangasPage = if (popular) {
|
||||
source.fetchPopularManga(pageNum).awaitSingle()
|
||||
source.getPopularManga(pageNum)
|
||||
} else {
|
||||
if (source.supportsLatest) {
|
||||
source.fetchLatestUpdates(pageNum).awaitSingle()
|
||||
source.getLatestUpdates(pageNum)
|
||||
} else {
|
||||
throw Exception("Source $source doesn't support latest")
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import org.jetbrains.exposed.sql.select
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
import org.jetbrains.exposed.sql.update
|
||||
import suwayomi.tachidesk.manga.impl.util.getChapterCachePath
|
||||
import suwayomi.tachidesk.manga.impl.util.lang.awaitSingle
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub
|
||||
import suwayomi.tachidesk.manga.impl.util.storage.ImageResponse.getImageResponse
|
||||
import suwayomi.tachidesk.manga.impl.util.storage.ImageUtil
|
||||
@@ -34,7 +33,7 @@ object Page {
|
||||
*/
|
||||
suspend fun getTrueImageUrl(page: Page, source: HttpSource): String {
|
||||
if (page.imageUrl == null) {
|
||||
page.imageUrl = source.fetchImageUrl(page).awaitSingle()
|
||||
page.imageUrl = source.getImageUrl(page)
|
||||
}
|
||||
return page.imageUrl!!
|
||||
}
|
||||
@@ -100,7 +99,7 @@ object Page {
|
||||
|
||||
// Note: don't care about invalidating cache because OS cache is not permanent
|
||||
return getImageResponse(cacheSaveDir, fileName) {
|
||||
source.fetchImage(tachiyomiPage).awaitSingle()
|
||||
source.getImage(tachiyomiPage)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,21 +16,20 @@ import org.kodein.di.DI
|
||||
import org.kodein.di.conf.global
|
||||
import org.kodein.di.instance
|
||||
import suwayomi.tachidesk.manga.impl.MangaList.processEntries
|
||||
import suwayomi.tachidesk.manga.impl.util.lang.awaitSingle
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.getCatalogueSourceOrStub
|
||||
import suwayomi.tachidesk.manga.model.dataclass.PagedMangaListDataClass
|
||||
|
||||
object Search {
|
||||
suspend fun sourceSearch(sourceId: Long, searchTerm: String, pageNum: Int): PagedMangaListDataClass {
|
||||
val source = getCatalogueSourceOrStub(sourceId)
|
||||
val searchManga = source.fetchSearchManga(pageNum, searchTerm, getFilterListOf(source)).awaitSingle()
|
||||
val searchManga = source.getSearchManga(pageNum, searchTerm, getFilterListOf(source))
|
||||
return searchManga.processEntries(sourceId)
|
||||
}
|
||||
|
||||
suspend fun sourceFilter(sourceId: Long, pageNum: Int, filter: FilterData): PagedMangaListDataClass {
|
||||
val source = getCatalogueSourceOrStub(sourceId)
|
||||
val filterList = if (filter.filter != null) buildFilterList(sourceId, filter.filter) else source.getFilterList()
|
||||
val searchManga = source.fetchSearchManga(pageNum, filter.searchTerm ?: "", filterList).awaitSingle()
|
||||
val searchManga = source.getSearchManga(pageNum, filter.searchTerm ?: "", filterList)
|
||||
return searchManga.processEntries(sourceId)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,10 @@ 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 android.app.Application
|
||||
import android.content.Context
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import eu.kanade.tachiyomi.source.getPreferenceKey
|
||||
import eu.kanade.tachiyomi.source.sourcePreferences
|
||||
import io.javalin.plugin.json.JsonMapper
|
||||
import mu.KotlinLogging
|
||||
import org.jetbrains.exposed.sql.select
|
||||
@@ -28,7 +26,6 @@ import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.unregisterCa
|
||||
import suwayomi.tachidesk.manga.model.dataclass.SourceDataClass
|
||||
import suwayomi.tachidesk.manga.model.table.ExtensionTable
|
||||
import suwayomi.tachidesk.manga.model.table.SourceTable
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import xyz.nulldev.androidcompat.androidimpl.CustomContext
|
||||
|
||||
@@ -106,8 +103,7 @@ object Source {
|
||||
val source = getCatalogueSourceOrStub(sourceId)
|
||||
|
||||
if (source is ConfigurableSource) {
|
||||
val sourceShardPreferences =
|
||||
Injekt.get<Application>().getSharedPreferences(source.getPreferenceKey(), Context.MODE_PRIVATE)
|
||||
val sourceShardPreferences = source.sourcePreferences()
|
||||
|
||||
val screen = PreferenceScreen(context)
|
||||
screen.sharedPreferences = sourceShardPreferences
|
||||
|
||||
@@ -48,7 +48,7 @@ object ProtoBackupImport : ProtoBackupBase() {
|
||||
|
||||
private val backupMutex = Mutex()
|
||||
sealed class BackupRestoreState {
|
||||
object Idle : BackupRestoreState()
|
||||
data object Idle : BackupRestoreState()
|
||||
data class RestoringCategories(val totalManga: Int) : BackupRestoreState()
|
||||
data class RestoringManga(val current: Int, val totalManga: Int, val title: String) : BackupRestoreState()
|
||||
}
|
||||
|
||||
@@ -9,9 +9,10 @@ package suwayomi.tachidesk.manga.impl.extension.github
|
||||
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.network.await
|
||||
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||
import eu.kanade.tachiyomi.network.parseAs
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import mu.KotlinLogging
|
||||
import suwayomi.tachidesk.manga.impl.util.PackageTools.LIB_VERSION_MAX
|
||||
import suwayomi.tachidesk.manga.impl.util.PackageTools.LIB_VERSION_MIN
|
||||
@@ -22,6 +23,7 @@ object ExtensionGithubApi {
|
||||
private const val REPO_URL_PREFIX = "https://raw.githubusercontent.com/tachiyomiorg/tachiyomi-extensions/repo/"
|
||||
private const val FALLBACK_REPO_URL_PREFIX = "https://gcore.jsdelivr.net/gh/tachiyomiorg/tachiyomi-extensions@repo/"
|
||||
private val logger = KotlinLogging.logger {}
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
@Serializable
|
||||
private data class ExtensionJsonObject(
|
||||
@@ -52,7 +54,7 @@ object ExtensionGithubApi {
|
||||
null
|
||||
} else {
|
||||
try {
|
||||
client.newCall(GET("${REPO_URL_PREFIX}index.min.json")).await()
|
||||
client.newCall(GET("${REPO_URL_PREFIX}index.min.json")).awaitSuccess()
|
||||
} catch (e: Throwable) {
|
||||
logger.error(e) { "Failed to get extensions from GitHub" }
|
||||
requiresFallbackSource = true
|
||||
@@ -61,12 +63,14 @@ object ExtensionGithubApi {
|
||||
}
|
||||
|
||||
val response = githubResponse ?: run {
|
||||
client.newCall(GET("${FALLBACK_REPO_URL_PREFIX}index.min.json")).await()
|
||||
client.newCall(GET("${FALLBACK_REPO_URL_PREFIX}index.min.json")).awaitSuccess()
|
||||
}
|
||||
|
||||
return response
|
||||
.parseAs<List<ExtensionJsonObject>>()
|
||||
.toExtensions()
|
||||
return with(json) {
|
||||
response
|
||||
.parseAs<List<ExtensionJsonObject>>()
|
||||
.toExtensions()
|
||||
}
|
||||
}
|
||||
|
||||
fun getApkUrl(extension: ExtensionDataClass): String {
|
||||
|
||||
@@ -41,7 +41,7 @@ object PackageTools {
|
||||
const val METADATA_SOURCE_FACTORY = "tachiyomi.extension.factory"
|
||||
const val METADATA_NSFW = "tachiyomi.extension.nsfw"
|
||||
const val LIB_VERSION_MIN = 1.3
|
||||
const val LIB_VERSION_MAX = 1.4
|
||||
const val LIB_VERSION_MAX = 1.5
|
||||
|
||||
private const val officialSignature = "7ce04da7773d41b489f4693a366c36bcd0a11fc39b547168553c285bd7348e23" // inorichi's key
|
||||
private const val unofficialSignature = "64feb21075ba97ebc9cc981243645b331595c111cef1b0d084236a0403b00581" // ArMor's key
|
||||
|
||||
@@ -21,14 +21,17 @@ open class StubSource(override val id: Long) : CatalogueSource {
|
||||
override val name: String
|
||||
get() = id.toString()
|
||||
|
||||
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getPopularManga"))
|
||||
override fun fetchPopularManga(page: Int): Observable<MangasPage> {
|
||||
return Observable.error(getSourceNotInstalledException())
|
||||
}
|
||||
|
||||
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getSearchManga"))
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||
return Observable.error(getSourceNotInstalledException())
|
||||
}
|
||||
|
||||
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getLatestUpdates"))
|
||||
override fun fetchLatestUpdates(page: Int): Observable<MangasPage> {
|
||||
return Observable.error(getSourceNotInstalledException())
|
||||
}
|
||||
@@ -37,14 +40,17 @@ open class StubSource(override val id: Long) : CatalogueSource {
|
||||
return FilterList()
|
||||
}
|
||||
|
||||
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getMangaDetails"))
|
||||
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
||||
return Observable.error(getSourceNotInstalledException())
|
||||
}
|
||||
|
||||
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getChapterList"))
|
||||
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
|
||||
return Observable.error(getSourceNotInstalledException())
|
||||
}
|
||||
|
||||
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getPageList"))
|
||||
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
|
||||
return Observable.error(getSourceNotInstalledException())
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ package suwayomi.tachidesk.server.util
|
||||
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.network.await
|
||||
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
@@ -408,7 +408,7 @@ object WebInterfaceManager {
|
||||
private suspend fun fetchMD5SumFor(version: String): String {
|
||||
return try {
|
||||
executeWithRetry(KotlinLogging.logger("${logger.name} fetchMD5SumFor($version)"), {
|
||||
network.client.newCall(GET("${getDownloadUrlFor(version)}/md5sum")).await().body.string().trim()
|
||||
network.client.newCall(GET("${getDownloadUrlFor(version)}/md5sum")).awaitSuccess().body.string().trim()
|
||||
})
|
||||
} catch (e: Exception) {
|
||||
""
|
||||
@@ -422,7 +422,7 @@ object WebInterfaceManager {
|
||||
|
||||
private suspend fun fetchPreviewVersion(): String {
|
||||
return executeWithRetry(KotlinLogging.logger("${logger.name} fetchPreviewVersion"), {
|
||||
val releaseInfoJson = network.client.newCall(GET(WebUIFlavor.WEBUI.latestReleaseInfoUrl)).await().body.string()
|
||||
val releaseInfoJson = network.client.newCall(GET(WebUIFlavor.WEBUI.latestReleaseInfoUrl)).awaitSuccess().body.string()
|
||||
Json.decodeFromString<JsonObject>(releaseInfoJson)["tag_name"]?.jsonPrimitive?.content
|
||||
?: throw Exception("Failed to get the preview version tag")
|
||||
})
|
||||
@@ -433,7 +433,7 @@ object WebInterfaceManager {
|
||||
KotlinLogging.logger("$logger fetchServerMappingFile"),
|
||||
{
|
||||
json.parseToJsonElement(
|
||||
network.client.newCall(GET(WebUIFlavor.WEBUI.versionMappingUrl)).await().body.string()
|
||||
network.client.newCall(GET(WebUIFlavor.WEBUI.versionMappingUrl)).awaitSuccess().body.string()
|
||||
).jsonArray
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user