9anime: automatic keys

This commit is contained in:
jmir1
2022-08-12 16:47:45 +02:00
parent 263ad88b92
commit 589bde3eb6
3 changed files with 93 additions and 6 deletions

View File

@ -5,8 +5,12 @@ ext {
extName = '9anime'
pkgNameSuffix = 'en.nineanime'
extClass = '.NineAnime'
extVersionCode = 20
extVersionCode = 21
libVersion = '13'
}
dependencies {
compileOnly libs.bundles.coroutines
}
apply from: "$rootDir/common.gradle"

View File

@ -0,0 +1,69 @@
package eu.kanade.tachiyomi.animeextension.en.nineanime
import app.cash.quickjs.QuickJs
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonPrimitive
const val fallbackcipherKey = "xtbmecCv4faAOSLV"
const val fallbackdecipherKey = "hlPeNwkncH0fq9so"
fun getKeys(allJsScript: String, json: Json): Pair<String, String> {
val quickJs = QuickJs.create()
val keys = try {
val scriptResult = quickJs.evaluate(finderScript(allJsScript)).toString()
val returnObject = json.decodeFromString<JsonObject>(scriptResult)
val cipherKey = returnObject["cipher"]!!.jsonPrimitive.content
val decipherKey = returnObject["decipher"]!!.jsonPrimitive.content
Pair(cipherKey, decipherKey)
} catch (t: Throwable) {
Pair(fallbackcipherKey, fallbackdecipherKey)
}
quickJs.close()
return keys
}
private fun finderScript(script: String) = """
let secret0 = "";
let secret1 = "";
const script = String.raw`$script`;
const prefix = `$prefix`;
var newscript = prefix + script;
const fn_regex = /or(?=:function\(.*?\) {var \w=.*?return .;})/gm
let fn_name = script.match(fn_regex);
const regex = RegExp(String.raw`(?<=this\["${'$'}{fn_name}"]\().+?(?=,)`, "gm");
let res = [...script.matchAll(regex)];
for (var index of [1,0]) {
let match = res[index][0];
let varnames = match.split("+");
for (var varnameindex = 0; varnameindex < varnames.length; varnameindex++) {
let varname = varnames[varnameindex];
let search = `${'$'}{varname}=`;
// variables are declared on line 2
let line2index = script.indexOf("\n") + prefix.length;
let line2 = newscript.substring(line2index + 1);
let i = line2index + line2.indexOf(search) + search.length;
let after = newscript.substring(i + 1);
let j = after.indexOf(";") + i + 1;
let before = newscript.substring(0, j + 1);
let after_semicolon = newscript.substring(j + 1);
newscript = before + `secret${'$'}{index}=${'$'}{res[index][0]};` + after_semicolon;
}
};
try { eval(newscript); } catch(e) {}
let return_object = {cipher: secret0, decipher: secret1};
JSON.stringify(return_object);
"""
private const val prefix = """const document = { documentElement: {} };
const jQuery = function () { return { off: function () { return { on: function(e) { return { on: function() { return { on: function() { return { on: function() { return { on: function() { return { }; } }; } }; } }; } }; } }; }, ready: function (e) {} } };
jQuery.fn = { dropdown: {}, extend: {} };
const window = { fn: { extend: {} } };
const navigator = {};
const setTimeout = {};
const clearTimeout = {};
const setInterval = {};
const clearInterval = {};
"""

View File

@ -12,13 +12,14 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.CacheControl
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
@ -31,7 +32,6 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
@ExperimentalSerializationApi
class NineAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val name = "9anime"
@ -372,9 +372,23 @@ class NineAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
private fun encode(input: String): String = java.net.URLEncoder.encode(input, "utf-8").replace("+", "%20")
private fun decode(input: String): String = java.net.URLDecoder.decode(input, "utf-8")
private val cipherKey: String
private val decipherKey: String
init {
val allJsScript = runBlocking {
client.newCall(
GET(
url = "https://s2.bunnycdn.ru/assets/_9anime/min/all.js",
cache = CacheControl.FORCE_NETWORK
)
).execute().body!!.string()
}
val keys = getKeys(allJsScript, json)
cipherKey = keys.first
decipherKey = keys.second
}
}
private const val nineAnimeKey = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
private const val cipherKey = "Ml6DEBjOkhWXxXg4"
private const val decipherKey = "hlPeNwkncH0fq9so"
// will implement the new algorithm soon (TM)