From 4445b666aab1fd09a86a5d2ef67533ceeffdfde7 Mon Sep 17 00:00:00 2001 From: Draken <131387159+dragonx943@users.noreply.github.com> Date: Thu, 1 May 2025 17:08:32 +0700 Subject: [PATCH] [site/iken] Small fixes (#1740) * Vortexscans (Broken): Need to fix list chaps + getPages function * Temporary fix for #1737, reference: keiyoushi/extensions-source#8645 --- .../kotatsu/parsers/site/iken/IkenParser.kt | 79 +++++++++++++++++-- .../kotatsu/parsers/site/iken/en/HiveComic.kt | 4 +- .../parsers/site/iken/en/MangaGalaxyParser.kt | 4 +- .../parsers/site/iken/en/PhiliaScans.kt | 21 ++++- .../parsers/site/iken/en/VortexScans.kt | 6 +- 5 files changed, 94 insertions(+), 20 deletions(-) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/IkenParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/IkenParser.kt index 382e42d2..f9dd847a 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/IkenParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/IkenParser.kt @@ -1,8 +1,12 @@ package org.koitharu.kotatsu.parsers.site.iken +import org.jsoup.Jsoup +import org.jsoup.nodes.Document import org.json.JSONObject +import org.json.JSONArray import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.config.ConfigKey +import org.koitharu.kotatsu.parsers.exception.ParseException import org.koitharu.kotatsu.parsers.core.LegacyPagedMangaParser import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.util.* @@ -15,10 +19,14 @@ internal abstract class IkenParser( source: MangaParserSource, domain: String, pageSize: Int = 18, + protected val useAPI: Boolean = false ) : LegacyPagedMangaParser(context, source, pageSize) { override val configKeyDomain = ConfigKey.Domain(domain) + protected val defaultDomain: String + get() = if (useAPI) "api.$domain" else domain + override fun onCreateConfig(keys: MutableCollection>) { super.onCreateConfig(keys) keys.add(userAgentKey) @@ -52,7 +60,7 @@ internal abstract class IkenParser( override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List { val url = buildString { append("https://") - append(domain) + append(defaultDomain) append("/api/query?page=") append(page) append("&perPage=18&searchTerm=") @@ -129,7 +137,7 @@ internal abstract class IkenParser( override suspend fun getDetails(manga: Manga): Manga { val seriesId = manga.id - val url = "https://$domain/api/chapters?postId=$seriesId&skip=0&take=1000&order=desc&userid=" + val url = "https://$defaultDomain/api/chapters?postId=$seriesId&skip=0&take=900&order=desc&userid=" val json = webClient.httpGet(url).parseJson().getJSONObject("post") val slug = json.getStringOrNull("slug") val data = json.getJSONArray("chapters").asTypedList() @@ -157,16 +165,23 @@ internal abstract class IkenParser( ) } - protected open val selectPages = "main section > img" + protected open val selectPages = "main section img" override suspend fun getPages(chapter: MangaChapter): List { val fullUrl = chapter.url.toAbsoluteUrl(domain) val doc = webClient.httpGet(fullUrl).parseHtml() - return doc.select(selectPages).map { img -> - val url = img.requireSrc() + + if (doc.selectFirst("svg.lucide-lock") != null) { + throw Exception("Need to unlock chapter!") + } + + val imagesJson = doc.getNextJson("images") + val images = parseImagesJson(imagesJson) + + return images.map { p -> MangaPage( - id = generateUid(url), - url = url, + id = generateUid(p), + url = p, preview = null, source = source, ) @@ -184,4 +199,52 @@ internal abstract class IkenParser( ) } } -} + + protected fun Document.getNextJson(key: String): String { + val scripts = select("script") + val scriptData = scripts.find { script -> + script.data()?.contains(key) == true + }?.data() ?: throw Exception("Unable to retrieve NEXT data") + + val keyIndex = scriptData.indexOf(key) + if (keyIndex == -1) throw Exception("Key $key not found in script data") + + val start = scriptData.indexOf('[', keyIndex) + if (start == -1) { + val objStart = scriptData.indexOf('{', keyIndex) + if (objStart == -1) throw Exception("No JSON data found after key") + + var depth = 1 + var i = objStart + 1 + while (i < scriptData.length && depth > 0) { + when (scriptData[i]) { + '{' -> depth++ + '}' -> depth-- + } + i++ + } + return scriptData.substring(objStart, i) + } + + var depth = 1 + var i = start + 1 + while (i < scriptData.length && depth > 0) { + when (scriptData[i]) { + '[' -> depth++ + ']' -> depth-- + } + i++ + } + + val jsonStr = scriptData.substring(start, i) + return jsonStr.replace("\\/", "/").replace("\\\"", "\"") + } + + private fun parseImagesJson(json: String): List { + val jsonArray = JSONArray(json) + return List(jsonArray.length()) { index -> + val item = jsonArray.getJSONObject(index) + item.getString("url") + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/HiveComic.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/HiveComic.kt index 90ac1f91..62c6121d 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/HiveComic.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/HiveComic.kt @@ -9,6 +9,4 @@ import org.koitharu.kotatsu.parsers.Broken @Broken("Need to fix getPages") @MangaSourceParser("HIVECOMIC", "HiveComic", "en") internal class HiveComic(context: MangaLoaderContext) : - IkenParser(context, MangaParserSource.HIVECOMIC, "hivecomic.com") { - override val selectPages = "main section img" -} + IkenParser(context, MangaParserSource.HIVECOMIC, "hivecomic.com", 18) \ No newline at end of file diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/MangaGalaxyParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/MangaGalaxyParser.kt index dad22aa7..09fb4da2 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/MangaGalaxyParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/MangaGalaxyParser.kt @@ -9,6 +9,4 @@ import org.koitharu.kotatsu.parsers.site.iken.IkenParser @Broken // Redirect to @VORTEXSCANS @MangaSourceParser("MANGAGALAXY", "MangaGalaxy", "en") internal class MangaGalaxyParser(context: MangaLoaderContext) : - IkenParser(context, MangaParserSource.MANGAGALAXY, "vortexscans.org") { - override val selectPages = "main section img" -} + IkenParser(context, MangaParserSource.MANGAGALAXY, "vortexscans.org", 18) \ No newline at end of file diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/PhiliaScans.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/PhiliaScans.kt index d517d513..dc1db5bf 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/PhiliaScans.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/PhiliaScans.kt @@ -4,9 +4,24 @@ import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.site.iken.IkenParser +import org.koitharu.kotatsu.parsers.model.* +import org.koitharu.kotatsu.parsers.util.* @MangaSourceParser("PHILIASCANS", "PhiliaScans", "en") internal class PhiliaScans(context: MangaLoaderContext) : - IkenParser(context, MangaParserSource.PHILIASCANS, "philiascans.org") { - override val selectPages = "main section img" -} + IkenParser(context, MangaParserSource.PHILIASCANS, "philiascans.org", 18) { + + override suspend fun getPages(chapter: MangaChapter): List { + val fullUrl = chapter.url.toAbsoluteUrl(domain) + val doc = webClient.httpGet(fullUrl).parseHtml() + return doc.select(selectPages).map { img -> + val url = img.requireSrc() + MangaPage( + id = generateUid(url), + url = url, + preview = null, + source = source, + ) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/VortexScans.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/VortexScans.kt index 4ef992e9..78ebcebc 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/VortexScans.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/iken/en/VortexScans.kt @@ -4,9 +4,9 @@ import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.site.iken.IkenParser +import org.koitharu.kotatsu.parsers.Broken +@Broken("Need to fix getPages") @MangaSourceParser("VORTEXSCANS", "VortexScans", "en") internal class VortexScans(context: MangaLoaderContext) : - IkenParser(context, MangaParserSource.VORTEXSCANS, "vortexscans.org") { - override val selectPages = "main section img" -} + IkenParser(context, MangaParserSource.VORTEXSCANS, "vortexscans.org", 18, true) \ No newline at end of file