From 84a1235b5df244fa6ef286fea9a21eed40b1ddaf Mon Sep 17 00:00:00 2001 From: jailbreak-bypass-forms <96935083+jailbreak-bypass-forms@users.noreply.github.com> Date: Wed, 25 Jan 2023 17:32:11 +0700 Subject: [PATCH] fix page list (#15098) * fix page list * guard with whitespace * replace http with https to skip 301s --- .../constellarscans/src/ConstellarScans.kt | 52 ++++++++++--------- .../mangathemesia/MangaThemesiaGenerator.kt | 2 +- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/multisrc/overrides/mangathemesia/constellarscans/src/ConstellarScans.kt b/multisrc/overrides/mangathemesia/constellarscans/src/ConstellarScans.kt index 0a29f7c32..7b70a8807 100644 --- a/multisrc/overrides/mangathemesia/constellarscans/src/ConstellarScans.kt +++ b/multisrc/overrides/mangathemesia/constellarscans/src/ConstellarScans.kt @@ -93,25 +93,27 @@ class ConstellarScans : MangaThemesia("Constellar Scans", "https://constellarsca .build() override fun pageListParse(document: Document): List { - val tsData = TS_DATA_RE.find(document.select("script").html())?.groupValues?.get(1) - ?: return super.pageListParse(document) - val descrambledData = descrambleString(tsData).trim() - - // check if the object can be parsed with JSON, else assume it is encrypted - // - // done because constellarscans have shit code and would sometimes give us an invalid key - // for no reason - return try { - val parsedTsData = json.parseToJsonElement(descrambledData).jsonObject - val imageList = parsedTsData["sources"]!!.jsonArray[0].jsonObject["images"]!!.jsonArray - imageList.mapIndexed { idx, it -> - Page(idx, imageUrl = it.jsonPrimitive.content) - } - } catch (_: IllegalArgumentException) { + val obfuscatedCode = document.select("script:containsData(_0x)").html() + val tsDataEncrypted = TS_DATA_RE.find(obfuscatedCode)?.groupValues?.get(1) + if (tsDataEncrypted != null) { + val descrambledData = descrambleString(tsDataEncrypted).trim() val match = DESCRAMBLING_KEY_RE.find(descrambledData)?.value ?: throw Exception("Did not receive valid decryption key. Try opening the chapter again.") Log.d("constellarscans", "device-limited chapter: $match") - decodeDeviceLimitedChapter(match) + return decodeDeviceLimitedChapter(match) + } + + val scripts = document.select("script").html() + val tsData = JS_FUNC_RE.findAll(obfuscatedCode).firstNotNullOf { + val func = it.groupValues[1] + val tsDataFuncRe = Regex("""$func\s*\(\s*['"]([\da-z]+?)['"]\s*\)""", RegexOption.IGNORE_CASE) + val match = tsDataFuncRe.find(scripts)?.groupValues?.get(1) + ?: return@firstNotNullOf null + descrambleString(match).trim() + } + val tsDataObject = json.parseToJsonElement(tsData).jsonObject + return tsDataObject["sources"]!!.jsonArray[0].jsonObject["images"]!!.jsonArray.mapIndexed { index, jsonElement -> + Page(index, imageUrl = jsonElement.jsonPrimitive.content.replace("http://", "https://")) } } @@ -122,10 +124,16 @@ class ConstellarScans : MangaThemesia("Constellar Scans", "https://constellarsca .header("Sec-Fetch-Site", "same-origin") .build() + private fun sumOfDigits(input: String): Int = input.sumOf { it.toString().toInt() } + private fun descrambleString(input: String): String = input.replace(NOT_DIGIT_RE, "") - .chunked(2) - .joinToString("") { (it.toInt() + 32).toChar().toString() } + .chunked(6) + .map { + val charCode = sumOfDigits(it.substring(0..2)) * 10 + sumOfDigits(it.substring(3)) + 32 + charCode.toChar() + } + .joinToString("") private fun decodeDeviceLimitedChapter(fullKey: String): List { if (!DESCRAMBLING_KEY_RE.matches(fullKey)) { @@ -215,13 +223,9 @@ class ConstellarScans : MangaThemesia("Constellar Scans", "https://constellarsca const val LOOKUP_STRING_ALNUM = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" val NOT_DIGIT_RE = Regex("""\D""") + val JS_FUNC_RE = Regex("""function (.+?)\s*\(""") - // We know that `ts_reader.run` accepts a JSON object, which contains `{"`, or in Constellar's - // encoding scheme, 91 02. - val TS_DATA_RE = Regex( - """['"]([\da-z]*?9[a-z]*?1[a-z]*?0[a-z]*?2[\da-z]+?)['"]""", - RegexOption.IGNORE_CASE - ) + val TS_DATA_RE = Regex("""\(\s*['"]([\da-z]+?)['"]\s*\)""", RegexOption.IGNORE_CASE) // The decoding algorithm looks for a hex number in 32..33, so we write our regex accordingly val DESCRAMBLING_KEY_RE = diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangathemesia/MangaThemesiaGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangathemesia/MangaThemesiaGenerator.kt index 05af21d45..9ecab2dd4 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangathemesia/MangaThemesiaGenerator.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangathemesia/MangaThemesiaGenerator.kt @@ -25,7 +25,7 @@ class MangaThemesiaGenerator : ThemeSourceGenerator { SingleLang("Azure Scans", "https://azuremanga.com", "en", overrideVersionCode = 1), SingleLang("Boosei", "https://boosei.net", "id", overrideVersionCode = 2), SingleLang("Clayrer", "https://clayrer.net", "es"), - SingleLang("Constellar Scans", "https://constellarscans.com", "en", isNsfw = true, overrideVersionCode = 6), + SingleLang("Constellar Scans", "https://constellarscans.com", "en", isNsfw = true, overrideVersionCode = 7), SingleLang("Cosmic Scans", "https://cosmicscans.com", "en", overrideVersionCode = 1), SingleLang("Diskus Scan", "https://diskusscan.com", "pt-BR", overrideVersionCode = 7), SingleLang("Dojing.net", "https://dojing.net", "id", isNsfw = true, className = "DojingNet"),