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' extName = '9anime'
pkgNameSuffix = 'en.nineanime' pkgNameSuffix = 'en.nineanime'
extClass = '.NineAnime' extClass = '.NineAnime'
extVersionCode = 20 extVersionCode = 21
libVersion = '13' libVersion = '13'
} }
dependencies {
compileOnly libs.bundles.coroutines
}
apply from: "$rootDir/common.gradle" 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.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.coroutines.runBlocking
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive import kotlinx.serialization.json.jsonPrimitive
import okhttp3.CacheControl
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -31,7 +32,6 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ExperimentalSerializationApi
class NineAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class NineAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val name = "9anime" 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 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 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 nineAnimeKey = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
private const val cipherKey = "Ml6DEBjOkhWXxXg4"
private const val decipherKey = "hlPeNwkncH0fq9so"
// will implement the new algorithm soon (TM)