From 4ac7d3559cd16955a1293a142fa366c434ad3e62 Mon Sep 17 00:00:00 2001 From: dngonz Date: Sat, 11 Oct 2025 15:44:36 +0200 Subject: [PATCH] Kagane: Fix MissingFieldException Error (#10981) * fix dto and small fixes * bump * fix authors * remove unused code and fix review comment * fix lint * fix lintx2 :( --- src/en/kagane/build.gradle | 2 +- .../tachiyomi/extension/en/kagane/Dto.kt | 120 +++++++----------- .../tachiyomi/extension/en/kagane/Kagane.kt | 30 ++--- 3 files changed, 56 insertions(+), 96 deletions(-) diff --git a/src/en/kagane/build.gradle b/src/en/kagane/build.gradle index f87f84378..379fd3bc2 100644 --- a/src/en/kagane/build.gradle +++ b/src/en/kagane/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'Kagane' extClass = '.Kagane' - extVersionCode = 3 + extVersionCode = 4 isNsfw = true } diff --git a/src/en/kagane/src/eu/kanade/tachiyomi/extension/en/kagane/Dto.kt b/src/en/kagane/src/eu/kanade/tachiyomi/extension/en/kagane/Dto.kt index 2751f2288..2f75d4b03 100644 --- a/src/en/kagane/src/eu/kanade/tachiyomi/extension/en/kagane/Dto.kt +++ b/src/en/kagane/src/eu/kanade/tachiyomi/extension/en/kagane/Dto.kt @@ -31,84 +31,68 @@ class SearchDto( @Serializable class DetailsDto( - val data: Data, + val source: String, + val authors: List, + val status: String, + val summary: String?, + val genres: List, + @SerialName("alternate_titles") + val alternateTitles: List, ) { @Serializable - class Data( - val metadata: Metadata, - val source: String, - ) { - @Serializable - class Metadata( - val genres: List, - val status: String, - val summary: String, - val alternateTitles: List, - ) { - @Serializable - class Title( - val title: String, - ) + class AlternateTitles( + val title: String, + ) + + fun toSManga(): SManga = SManga.create().apply { + val desc = StringBuilder() + if (!summary.isNullOrBlank()) desc.append(summary + "\n\n") + desc.append("Source: ").append(source + "\n\n") + + if (alternateTitles.isNotEmpty()) { + desc.append("Associated Name(s):\n\n") + alternateTitles.forEach { desc.append("• ${it.title}\n") } } - fun toSManga(): SManga = SManga.create().apply { - val summary = StringBuilder() - summary.append(metadata.summary) - .append("\n\n") - .append("Source: ") - .append(source) + author = authors.joinToString() + description = desc.toString() + genre = genres.joinToString() + status = this@DetailsDto.status.toStatus() + } - if (metadata.alternateTitles.isNotEmpty()) { - summary.append("\n\nAssociated Name(s):") - metadata.alternateTitles.forEach { summary.append("\n").append("• ${it.title}") } - } - - description = summary.toString() - genre = metadata.genres.joinToString() - status = metadata.status.toStatus() - } - - private fun String.toStatus(): Int { - return when (this) { - "ONGOING" -> SManga.ONGOING - else -> SManga.COMPLETED - } + private fun String.toStatus(): Int { + return when (this) { + "ONGOING" -> SManga.ONGOING + "ENDED" -> SManga.COMPLETED + else -> SManga.UNKNOWN } } } @Serializable class ChapterDto( - val data: Data, + val content: List<Book>, ) { @Serializable - class Data( - val content: List<Book>, + class Book( + val id: String, + @SerialName("series_id") + val seriesId: String, + val title: String, + @SerialName("release_date") + val releaseDate: String?, + @SerialName("pages_count") + val pagesCount: Int, ) { - @Serializable - class Book( - val metadata: Metadata, - val id: String, - val seriesId: String, - val created: String, - ) { - @Serializable - class Metadata( - val title: String, - ) - - fun toSChapter(): SChapter = SChapter.create().apply { - url = "$seriesId;$id" - name = metadata.title - date_upload = dateFormat.tryParse(created) - } + fun toSChapter(): SChapter = SChapter.create().apply { + url = "$seriesId;$id;$pagesCount" + name = title + date_upload = dateFormat.tryParse(releaseDate) } } companion object { - private val dateFormat by lazy { - SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH) - } + private val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH) } } @@ -117,19 +101,3 @@ class ChallengeDto( @SerialName("access_token") val accessToken: String, ) - -@Serializable -class PagesCountDto( - val data: Data, -) { - @Serializable - class Data( - val media: PagesCount, - ) { - @Serializable - class PagesCount( - @SerialName("pagesCount") - val pagesCount: Int, - ) - } -} diff --git a/src/en/kagane/src/eu/kanade/tachiyomi/extension/en/kagane/Kagane.kt b/src/en/kagane/src/eu/kanade/tachiyomi/extension/en/kagane/Kagane.kt index ffa45fe56..2b08e1f65 100644 --- a/src/en/kagane/src/eu/kanade/tachiyomi/extension/en/kagane/Kagane.kt +++ b/src/en/kagane/src/eu/kanade/tachiyomi/extension/en/kagane/Kagane.kt @@ -144,7 +144,7 @@ class Kagane : HttpSource(), ConfigurableSource { // =============================== Latest =============================== override fun latestUpdatesRequest(page: Int) = - searchMangaRequest(page, "", FilterList(SortFilter(1))) + searchMangaRequest(page, "", FilterList(SortFilter(2))) override fun latestUpdatesParse(response: Response) = searchMangaParse(response) @@ -188,7 +188,7 @@ class Kagane : HttpSource(), ConfigurableSource { override fun mangaDetailsParse(response: Response): SManga { val dto = response.parseAs<DetailsDto>() - return dto.data.toSManga() + return dto.toSManga() } override fun mangaDetailsRequest(manga: SManga): Request { @@ -203,7 +203,7 @@ class Kagane : HttpSource(), ConfigurableSource { override fun chapterListParse(response: Response): List<SChapter> { val dto = response.parseAs<ChapterDto>() - return dto.data.content.map { it.toSChapter() }.reversed() + return dto.content.map { it.toSChapter() }.reversed() } override fun chapterListRequest(manga: SManga): Request { @@ -224,15 +224,16 @@ class Kagane : HttpSource(), ConfigurableSource { } override fun fetchPageList(chapter: SChapter): Observable<List<Page>> { - var (seriesId, chapterId) = chapter.url.split(";") + if (chapter.url.count { it == ';' } == 2) throw Exception("Chapter url error, please refresh chapter list.") + var (seriesId, chapterId, pageCount) = chapter.url.split(";") val challengeResp = getChallengeResponse(seriesId, chapterId) accessToken = challengeResp.accessToken - val pageCount = getPageCountResponse(seriesId, chapterId) if (preferences.dataSaver) { chapterId = chapterId + "_ds" } - val pages = (0 until pageCount).map { page -> + + val pages = (0 until pageCount.toInt()).map { page -> val pageUrl = "$apiUrl/api/v1/books".toHttpUrl().newBuilder().apply { addPathSegment(seriesId) addPathSegment("file") @@ -363,15 +364,6 @@ class Kagane : HttpSource(), ConfigurableSource { .parseAs<ChallengeDto>() } - private fun getPageCountResponse(seriesId: String, chapterId: String): Int { - val challengeUrl = "$apiUrl/api/v1/books/$seriesId/metadata/$chapterId" - - val dto = client.newCall(GET(challengeUrl, apiHeaders)).execute() - .parseAs<PagesCountDto>() - - return dto.data.media.pagesCount - } - private fun concat(vararg arrays: ByteArray): ByteArray = arrays.reduce { acc, bytes -> acc + bytes } @@ -418,7 +410,7 @@ class Kagane : HttpSource(), ConfigurableSource { private val SharedPreferences.showNsfw get() = this.getBoolean(SHOW_NSFW_KEY, true) private val SharedPreferences.dataSaver - get() = this.getBoolean(DATA_SAVER, true) + get() = this.getBoolean(DATA_SAVER, false) override fun setupPreferenceScreen(screen: PreferenceScreen) { SwitchPreferenceCompat(screen.context).apply { @@ -429,7 +421,7 @@ class Kagane : HttpSource(), ConfigurableSource { SwitchPreferenceCompat(screen.context).apply { key = DATA_SAVER title = "Data saver" - setDefaultValue(true) + setDefaultValue(false) }.let(screen::addPreference) } @@ -437,7 +429,7 @@ class Kagane : HttpSource(), ConfigurableSource { companion object { private const val SHOW_NSFW_KEY = "pref_show_nsfw" - private const val DATA_SAVER = "data_saver" + private const val DATA_SAVER = "data_saver_default" } // ============================= Filters ============================== @@ -449,7 +441,7 @@ class Kagane : HttpSource(), ConfigurableSource { class SortFilter(state: Int = 0) : UriPartFilter( "Sort By", arrayOf( - Pair("Relevance", ""), + Pair("Relevance", "avg_views,desc"), Pair("Latest", "updated_at"), Pair("Latest Descending", "updated_at,desc"), Pair("By Name", "series_name"),