Extension API 1.6 (#2120)

* Non-Extension Index changes for 1.6

* Changelog

* Minor fixes

* Implement extension store

* Test build fix

* Docs

* Simplify fetching manga and chapters

* Use EMPTY JsonObject

* Update docs/Configuring-Suwayomi‐Server.md

Co-authored-by: Constantin Piber <59023762+cpiber@users.noreply.github.com>

* Improve Fetch Extension Store

* Fixes

* Simplify deprecated isNsfw in SourceQuery

* Simplify ContentRating in Source.kt

* Simplify isNsfw in SourceType

* No magic numbers for ContentRating, improves safety for future versions of extension api

* Fix SearchTest

* Lint

* Lint

* Optimize imports and fix unchecked cast warning

* Proper extension store queries

* Optimize import fixes

* Add ContentRatingFilter

* Improve extension store sync

* fix: re-sync (#2121)

* Lint

* Add ExtenionStores to the fetchExtensions result since its possible for the stores to change.

* Use a single version of ContentRating

* Exclude ServerConfig.extensionStores from GraphQL

* Use syncDbToPrefs in ExtensionStoreMutation

* Optimize Imports

* Update server/server-config/src/main/kotlin/suwayomi/tachidesk/server/ServerConfig.kt

Co-authored-by: Constantin Piber <59023762+cpiber@users.noreply.github.com>

* Remove replaceWith and add specific description for GQL APIs

* Include OkHttp ZSTD

* Update to latest Mihon extension lib

* Fix latest Mihon Extension Lib

* Lint

* Optimize imports

* Lint

* Review fixes

* Add a index to extesnion table store url

* Lint

---------

Co-authored-by: Constantin Piber <59023762+cpiber@users.noreply.github.com>
This commit is contained in:
Mitchell Syer
2026-06-27 13:39:28 -04:00
committed by GitHub
parent c8f5d83e9c
commit 2d535b44d8
84 changed files with 2576 additions and 1007 deletions

View File

@@ -48,7 +48,6 @@ class TestExtensionCompatibility {
private val failedToFetch = mutableListOf<Pair<HttpSource, Exception>>()
private val mangaFailedToFetch = mutableListOf<Triple<HttpSource, SManga, Exception>>()
private val chaptersToFetch = mutableListOf<Triple<HttpSource, SManga, SChapter>>()
private val chaptersFailedToFetch = mutableListOf<Triple<HttpSource, SManga, Throwable>>()
private val chaptersPageListFailedToFetch = mutableListOf<Triple<HttpSource, Pair<SManga, SChapter>, Exception>>()
@BeforeAll
@@ -133,10 +132,10 @@ class TestExtensionCompatibility {
semaphore.withPermit {
logger.info { "${mangaCount.getAndIncrement()} - Now fetching manga from $source" }
try {
repeat { source.getMangaDetails(manga) }
repeat { source.getMangaUpdate(manga, emptyList(), true, true) }
} catch (e: Exception) {
logger.warn {
"Failed to fetch manga info from $source for ${manga.title} (${source.mangaDetailsRequest(
"Failed to fetch manga info and chapters from $source for ${manga.title} (${source.mangaDetailsRequest(
manga,
).url}): ${e.message}"
}
@@ -154,50 +153,6 @@ class TestExtensionCompatibility {
)
logger.info { "Now fetching manga chapters from ${mangaToFetch.size} sources" }
val chapterCount = AtomicInteger(1)
mangaToFetch
.filter { it.second.initialized }
.map { (source, manga) ->
async {
semaphore.withPermit {
logger.info { "${chapterCount.getAndIncrement()} - Now fetching manga chapters from $source" }
try {
chaptersToFetch +=
Triple(
source,
manga,
repeat {
source.getChapterList(manga)
}.firstOrNull()
?: throw Exception("Source returned no chapters"),
)
} catch (e: Exception) {
logger.warn {
"Failed to fetch manga chapters from $source for ${manga.title} (${source.mangaDetailsRequest(
manga,
).url}): ${e.message}"
}
chaptersFailedToFetch += Triple(source, manga, e)
} catch (e: NoClassDefFoundError) {
logger.warn {
"Failed to fetch manga chapters from $source for ${manga.title} (${source.mangaDetailsRequest(
manga,
).url}): ${e.message}"
}
chaptersFailedToFetch += Triple(source, manga, e)
}
}
}
}.awaitAll()
File("$BASE_PATH/ChaptersFailedToFetch.txt").writeText(
chaptersFailedToFetch.joinToString("\n") { (source, manga, exception) ->
"${source.name} (${source.lang}, ${source.id}):" +
" ${manga.title} (${source.mangaDetailsRequest(manga).url}):" +
" ${exception.message}"
},
)
val pageListCount = AtomicInteger(1)
chaptersToFetch
.map { (source, manga, chapter) ->

View File

@@ -18,7 +18,6 @@ import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import rx.Observable
import suwayomi.tachidesk.manga.impl.Search.FilterChange
import suwayomi.tachidesk.manga.impl.Search.FilterObject
import suwayomi.tachidesk.manga.impl.Search.SerializableGroup
@@ -41,12 +40,11 @@ class SearchTest : ApplicationTest() {
) : StubSource(id) {
var mangas: List<SManga> = emptyList()
@Deprecated("Use the non-RxJava API instead", replaceWith = ReplaceWith("getSearchManga"))
override fun fetchSearchManga(
override suspend fun getSearchManga(
page: Int,
query: String,
filters: FilterList,
): Observable<MangasPage> = Observable.just(MangasPage(mangas, false))
): MangasPage = MangasPage(mangas, false)
}
private val sourceId = 1L

View File

@@ -66,6 +66,7 @@ fun createChapters(
this[ChapterTable.sourceOrder] = it
this[ChapterTable.isRead] = read
this[ChapterTable.manga] = mangaId
this[ChapterTable.memo] = "{}"
}
}
}