fix RCO (#16900)
* lib-synchrony ported from aniyomiorg/aniyomi-extensions Co-authored-by: jmir1 <43830312+jmir1@users.noreply.github.com> * RCO: deobfuscate and extract beau function from rguard script * fix genre filter * bump --------- Co-authored-by: jmir1 <43830312+jmir1@users.noreply.github.com>
This commit is contained in:
parent
e429326371
commit
6a106c8648
|
@ -0,0 +1,22 @@
|
|||
plugins {
|
||||
id("com.android.library")
|
||||
kotlin("android")
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk = AndroidConfig.compileSdk
|
||||
namespace = "eu.kanade.tachiyomi.lib.synchrony"
|
||||
|
||||
defaultConfig {
|
||||
minSdk = AndroidConfig.minSdk
|
||||
targetSdk = AndroidConfig.targetSdk
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.bundles.common)
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,43 @@
|
|||
package eu.kanade.tachiyomi.lib.synchrony
|
||||
|
||||
import app.cash.quickjs.QuickJs
|
||||
|
||||
/**
|
||||
* Helper class to deobfuscate JavaScript strings with synchrony.
|
||||
*/
|
||||
object Deobfuscator {
|
||||
fun deobfuscateScript(source: String): String? {
|
||||
val originalScript = javaClass.getResource("/assets/$SCRIPT_NAME")
|
||||
?.readText() ?: return null
|
||||
|
||||
// Sadly needed until QuickJS properly supports module imports:
|
||||
// Regex for finding one and two in "export{one as Deobfuscator,two as Transformer};"
|
||||
val regex = """export\{(.*) as Deobfuscator,(.*) as Transformer\};""".toRegex()
|
||||
val synchronyScript = regex.find(originalScript)?.let { match ->
|
||||
val (deob, trans) = match.destructured
|
||||
val replacement = "const Deobfuscator = $deob, Transformer = $trans;"
|
||||
originalScript.replace(match.value, replacement)
|
||||
} ?: return null
|
||||
|
||||
return QuickJs.create().use { engine ->
|
||||
engine.evaluate("globalThis.console = { log: () => {}, warn: () => {}, error: () => {}, trace: () => {} };")
|
||||
engine.evaluate(synchronyScript)
|
||||
|
||||
engine.set(
|
||||
"source", TestInterface::class.java,
|
||||
object : TestInterface {
|
||||
override fun getValue() = source
|
||||
},
|
||||
)
|
||||
engine.evaluate("new Deobfuscator().deobfuscateSource(source.getValue())") as? String
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
private interface TestInterface {
|
||||
fun getValue(): String
|
||||
}
|
||||
}
|
||||
|
||||
// Update this when the script is updated!
|
||||
private const val SCRIPT_NAME = "synchrony-v2.4.2.1.js"
|
|
@ -1,6 +1,6 @@
|
|||
include(":core")
|
||||
|
||||
listOf("dataimage", "unpacker", "cryptoaes", "textinterceptor").forEach {
|
||||
listOf("dataimage", "unpacker", "cryptoaes", "textinterceptor", "synchrony").forEach {
|
||||
include(":lib-$it")
|
||||
project(":lib-$it").projectDir = File("lib/$it")
|
||||
}
|
||||
|
|
|
@ -5,7 +5,11 @@ ext {
|
|||
extName = 'ReadComicOnline'
|
||||
pkgNameSuffix = 'en.readcomiconline'
|
||||
extClass = '.Readcomiconline'
|
||||
extVersionCode = 14
|
||||
extVersionCode = 15
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":lib-synchrony"))
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
||||
|
|
|
@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.extension.en.readcomiconline
|
|||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import app.cash.quickjs.QuickJs
|
||||
import eu.kanade.tachiyomi.lib.synchrony.Deobfuscator
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
|
@ -16,8 +16,8 @@ import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
|||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.encodeToJsonElement
|
||||
import okhttp3.CacheControl
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
|
@ -100,19 +100,22 @@ class Readcomiconline : ConfigurableSource, ParsedHttpSource() {
|
|||
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val form = FormBody.Builder().apply {
|
||||
add("comicName", query)
|
||||
add("page", page.toString())
|
||||
|
||||
val url = "$baseUrl/AdvanceSearch".toHttpUrl().newBuilder().apply {
|
||||
addQueryParameter("comicName", query.trim())
|
||||
addQueryParameter("page", page.toString())
|
||||
for (filter in if (filters.isEmpty()) getFilterList() else filters) {
|
||||
when (filter) {
|
||||
is Status -> add("status", arrayOf("", "Completed", "Ongoing")[filter.state])
|
||||
is GenreList -> filter.state.forEach { genre -> add("genres", genre.state.toString()) }
|
||||
is Status -> addQueryParameter("status", arrayOf("", "Completed", "Ongoing")[filter.state])
|
||||
is GenreList -> {
|
||||
addQueryParameter("ig", filter.included.joinToString(","))
|
||||
addQueryParameter("eg", filter.excluded.joinToString(","))
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
return POST("$baseUrl/AdvanceSearch", headers, form.build())
|
||||
}.build()
|
||||
|
||||
return GET(url, headers)
|
||||
}
|
||||
|
||||
override fun searchMangaSelector() = popularMangaSelector()
|
||||
|
@ -192,8 +195,14 @@ class Readcomiconline : ConfigurableSource, ParsedHttpSource() {
|
|||
override fun imageUrlParse(document: Document) = ""
|
||||
|
||||
private class Status : Filter.TriState("Completed")
|
||||
private class Genre(name: String) : Filter.TriState(name)
|
||||
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
|
||||
private class Genre(name: String, val gid: String) : Filter.TriState(name)
|
||||
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres) {
|
||||
val included: List<String>
|
||||
get() = state.filter { it.isIncluded() }.map { it.gid }
|
||||
|
||||
val excluded: List<String>
|
||||
get() = state.filter { it.isExcluded() }.map { it.gid }
|
||||
}
|
||||
|
||||
override fun getFilterList() = FilterList(
|
||||
Status(),
|
||||
|
@ -203,54 +212,55 @@ class Readcomiconline : ConfigurableSource, ParsedHttpSource() {
|
|||
// $("select[name=\"genres\"]").map((i,el) => `Genre("${$(el).next().text().trim()}", ${i})`).get().join(',\n')
|
||||
// on https://readcomiconline.li/AdvanceSearch
|
||||
private fun getGenreList() = listOf(
|
||||
Genre("Action"),
|
||||
Genre("Adventure"),
|
||||
Genre("Anthology"),
|
||||
Genre("Anthropomorphic"),
|
||||
Genre("Biography"),
|
||||
Genre("Children"),
|
||||
Genre("Comedy"),
|
||||
Genre("Crime"),
|
||||
Genre("Drama"),
|
||||
Genre("Family"),
|
||||
Genre("Fantasy"),
|
||||
Genre("Fighting"),
|
||||
Genre("Graphic Novels"),
|
||||
Genre("Historical"),
|
||||
Genre("Horror"),
|
||||
Genre("Leading Ladies"),
|
||||
Genre("LGBTQ"),
|
||||
Genre("Literature"),
|
||||
Genre("Manga"),
|
||||
Genre("Martial Arts"),
|
||||
Genre("Mature"),
|
||||
Genre("Military"),
|
||||
Genre("Movies & TV"),
|
||||
Genre("Music"),
|
||||
Genre("Mystery"),
|
||||
Genre("Mythology"),
|
||||
Genre("Personal"),
|
||||
Genre("Political"),
|
||||
Genre("Post-Apocalyptic"),
|
||||
Genre("Psychological"),
|
||||
Genre("Pulp"),
|
||||
Genre("Religious"),
|
||||
Genre("Robots"),
|
||||
Genre("Romance"),
|
||||
Genre("School Life"),
|
||||
Genre("Sci-Fi"),
|
||||
Genre("Slice of Life"),
|
||||
Genre("Sport"),
|
||||
Genre("Spy"),
|
||||
Genre("Superhero"),
|
||||
Genre("Supernatural"),
|
||||
Genre("Suspense"),
|
||||
Genre("Thriller"),
|
||||
Genre("Vampires"),
|
||||
Genre("Video Games"),
|
||||
Genre("War"),
|
||||
Genre("Western"),
|
||||
Genre("Zombies"),
|
||||
Genre("Action", "1"),
|
||||
Genre("Adventure", "2"),
|
||||
Genre("Anthology", "38"),
|
||||
Genre("Anthropomorphic", "46"),
|
||||
Genre("Biography", "41"),
|
||||
Genre("Children", "49"),
|
||||
Genre("Comedy", "3"),
|
||||
Genre("Crime", "17"),
|
||||
Genre("Drama", "19"),
|
||||
Genre("Family", "25"),
|
||||
Genre("Fantasy", "20"),
|
||||
Genre("Fighting", "31"),
|
||||
Genre("Graphic Novels", "5"),
|
||||
Genre("Historical", "28"),
|
||||
Genre("Horror", "15"),
|
||||
Genre("Leading Ladies", "35"),
|
||||
Genre("LGBTQ", "51"),
|
||||
Genre("Literature", "44"),
|
||||
Genre("Manga", "40"),
|
||||
Genre("Martial Arts", "4"),
|
||||
Genre("Mature", "8"),
|
||||
Genre("Military", "33"),
|
||||
Genre("Mini-Series", "56"),
|
||||
Genre("Movies & TV", "47"),
|
||||
Genre("Music", "55"),
|
||||
Genre("Mystery", "23"),
|
||||
Genre("Mythology", "21"),
|
||||
Genre("Personal", "48"),
|
||||
Genre("Political", "42"),
|
||||
Genre("Post-Apocalyptic", "43"),
|
||||
Genre("Psychological", "27"),
|
||||
Genre("Pulp", "39"),
|
||||
Genre("Religious", "53"),
|
||||
Genre("Robots", "9"),
|
||||
Genre("Romance", "32"),
|
||||
Genre("School Life", "52"),
|
||||
Genre("Sci-Fi", "16"),
|
||||
Genre("Slice of Life", "50"),
|
||||
Genre("Sport", "54"),
|
||||
Genre("Spy", "30"),
|
||||
Genre("Superhero", "22"),
|
||||
Genre("Supernatural", "24"),
|
||||
Genre("Suspense", "29"),
|
||||
Genre("Thriller", "18"),
|
||||
Genre("Vampires", "34"),
|
||||
Genre("Video Games", "37"),
|
||||
Genre("War", "26"),
|
||||
Genre("Western", "45"),
|
||||
Genre("Zombies", "36"),
|
||||
)
|
||||
// Preferences Code
|
||||
|
||||
|
@ -287,11 +297,14 @@ class Readcomiconline : ConfigurableSource, ParsedHttpSource() {
|
|||
val scriptResponse = client.newCall(scriptRequest).execute()
|
||||
val scriptBody = scriptResponse.body.string()
|
||||
|
||||
val scriptParts = RGUARD_REGEX.find(scriptBody)?.groupValues?.drop(1)
|
||||
val deobfuscatedBody = Deobfuscator.deobfuscateScript(scriptBody)
|
||||
?: throw Exception("Unable to de-obfuscate rguard script")
|
||||
|
||||
val beauFunc = RGUARD_REGEX.find(deobfuscatedBody)?.groupValues
|
||||
?: throw Exception("Unable to parse rguard script")
|
||||
|
||||
QuickJs.create().use {
|
||||
it.compile(scriptParts.joinToString("") + ATOB_SCRIPT, "?")
|
||||
it.compile(beauFunc.joinToString("") + ATOB_SCRIPT, "?")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,7 +327,7 @@ class Readcomiconline : ConfigurableSource, ParsedHttpSource() {
|
|||
private const val QUALITY_PREF = "qualitypref"
|
||||
|
||||
private val CHAPTER_IMAGES_REGEX = "lstImages\\.push\\([\"'](.*)[\"']\\)".toRegex()
|
||||
private val RGUARD_REGEX = "(^.+?)var \\w=\\(function\\(\\).+?;(function \\w+.+?\\})if.+?(function beau.+)".toRegex()
|
||||
private val RGUARD_REGEX = Regex("""(function beau[\s\S]*\})""")
|
||||
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
|
|
Loading…
Reference in New Issue