Change method of work (#15140)

* Change method of work

* always update bytecode
This commit is contained in:
beerpsi 2023-01-28 03:06:33 +07:00 committed by GitHub
parent d67b542c21
commit ff22db6290
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 18 deletions

View File

@ -8,11 +8,13 @@ import android.graphics.ColorMatrixColorFilter
import android.graphics.Paint
import android.graphics.Rect
import android.util.Log
import app.cash.quickjs.QuickJs
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
@ -97,20 +99,14 @@ class ConstellarScans : MangaThemesia("Constellar Scans", "https://constellarsca
val tsDataEncrypted = TS_DATA_RE.find(obfuscatedCode)?.groupValues?.get(1)
if (tsDataEncrypted != null) {
val descrambledData = descrambleString(tsDataEncrypted).trim()
Log.d("constellarscans", "decrypted chapter, data: $descrambledData")
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")
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 tsData = descrambleString(getDecryptionKey(document)).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://"))
@ -124,16 +120,63 @@ 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 var descramblingBytecode: ByteArray? = null
private fun descrambleString(input: String): String =
input.replace(NOT_DIGIT_RE, "")
.chunked(6)
.map {
val charCode = sumOfDigits(it.substring(0..2)) * 10 + sumOfDigits(it.substring(3)) + 32
charCode.toChar()
/**
* Also updates `descramblingBytecode` as a side effect
*/
private fun getDecryptionKey(document: Document?): String {
val doc = if (document == null) {
val req = pageListRequest(
SChapter.create().apply {
url = "/the-dignity-of-sister-in-law-chapter-60/"
}
)
client.newCall(req).execute().asJsoup()
} else {
document
}
val obfuscatedScript = doc.selectFirst("script:containsData(_0x)").data()
val scripts = doc.select("script:containsData(_0x) ~ script").html()
val (decodingSymbol, tsData) = JS_FUNC_RE.findAll(obfuscatedScript).firstNotNullOf {
val func = it.groupValues[1]
val tsDataFuncRe = Regex("""$func\s*\(\s*['"]([\da-z]+?)['"]\s*\)""", RegexOption.IGNORE_CASE)
val tsData = tsDataFuncRe.find(scripts)?.groupValues?.get(1)
?: return@firstNotNullOf null
func to tsData
}
Log.d("constellarscans", "decoding symbol: $decodingSymbol")
descramblingBytecode = QuickJs.create().use {
it.compile(
"""
ts_reader = {}
ts_reader.run = arg => { throw Error(arg) }
JSON.parse = arg => arg
${obfuscatedScript.replace(decodingSymbol, "decode")}
""".trimIndent(),
"#"
)
}
return tsData
}
private fun descrambleString(input: String): String {
if (descramblingBytecode == null) getDecryptionKey(null)
return QuickJs.create().use {
it.execute(descramblingBytecode!!)
it.evaluate(
"""
try {
decode("$input")
} catch (e) {
e.message
}
""".trimIndent()
)
} as String
}
.joinToString("")
private fun decodeDeviceLimitedChapter(fullKey: String): List<Page> {
if (!DESCRAMBLING_KEY_RE.matches(fullKey)) {

View File

@ -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 = 7),
SingleLang("Constellar Scans", "https://constellarscans.com", "en", isNsfw = true, overrideVersionCode = 8),
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"),