fix 9anime vrf stuff (#1399)
This commit is contained in:
@ -6,7 +6,7 @@ ext {
|
|||||||
extName = '9anime'
|
extName = '9anime'
|
||||||
pkgNameSuffix = 'en.nineanime'
|
pkgNameSuffix = 'en.nineanime'
|
||||||
extClass = '.NineAnime'
|
extClass = '.NineAnime'
|
||||||
extVersionCode = 37
|
extVersionCode = 38
|
||||||
libVersion = '13'
|
libVersion = '13'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,99 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.animeextension.en.nineanime
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Application
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import android.webkit.WebResourceRequest
|
|
||||||
import android.webkit.WebView
|
|
||||||
import android.webkit.WebViewClient
|
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.util.concurrent.CountDownLatch
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
class JsVrfInterceptor(private val baseUrl: String) {
|
|
||||||
|
|
||||||
private val context = Injekt.get<Application>()
|
|
||||||
private val handler by lazy { Handler(Looper.getMainLooper()) }
|
|
||||||
private val vrfWebView = createWebView()
|
|
||||||
|
|
||||||
fun getVrf(query: String): String {
|
|
||||||
if (query.isBlank()) return ""
|
|
||||||
val jscript = getJs(query)
|
|
||||||
val cdl = CountDownLatch(1)
|
|
||||||
var vrf = ""
|
|
||||||
handler.post {
|
|
||||||
vrfWebView?.evaluateJavascript(jscript) {
|
|
||||||
vrf = it?.removeSurrounding("\"") ?: ""
|
|
||||||
cdl.countDown()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cdl.await(12, TimeUnit.SECONDS)
|
|
||||||
if (vrf.isBlank()) throw Exception("vrf could not be retrieved")
|
|
||||||
return vrf
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("SetJavaScriptEnabled")
|
|
||||||
private fun createWebView(): WebView? {
|
|
||||||
val latch = CountDownLatch(1)
|
|
||||||
var webView: WebView? = null
|
|
||||||
|
|
||||||
handler.post {
|
|
||||||
val webview = WebView(context)
|
|
||||||
webView = webview
|
|
||||||
with(webview.settings) {
|
|
||||||
javaScriptEnabled = true
|
|
||||||
domStorageEnabled = true
|
|
||||||
databaseEnabled = true
|
|
||||||
useWideViewPort = false
|
|
||||||
loadWithOverviewMode = false
|
|
||||||
userAgentString = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:106.0) Gecko/20100101 Firefox/106.0"
|
|
||||||
|
|
||||||
webview.webViewClient = object : WebViewClient() {
|
|
||||||
override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
|
|
||||||
if (request?.url.toString().contains("$baseUrl/filter")) {
|
|
||||||
return super.shouldOverrideUrlLoading(view, request)
|
|
||||||
} else {
|
|
||||||
// Block the request
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
override fun onPageFinished(view: WebView?, url: String?) {
|
|
||||||
latch.countDown()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
webView?.loadUrl("$baseUrl/filter")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
latch.await()
|
|
||||||
|
|
||||||
handler.post {
|
|
||||||
webView?.stopLoading()
|
|
||||||
}
|
|
||||||
return webView
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getJs(query: String): String {
|
|
||||||
return """
|
|
||||||
(function() {
|
|
||||||
document.querySelector("form.filters input.form-control").value = '$query';
|
|
||||||
let inputElemente = document.querySelector('form.filters input.form-control');
|
|
||||||
let e = document.createEvent('HTMLEvents');
|
|
||||||
e.initEvent('keyup', true, true);
|
|
||||||
inputElemente.dispatchEvent(e);
|
|
||||||
let val = "";
|
|
||||||
while (val == "") {
|
|
||||||
let element = document.querySelector('form.filters input[type="hidden"]').value;
|
|
||||||
if (element) {
|
|
||||||
val = element;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
document.querySelector("form.filters input.form-control").value = '';
|
|
||||||
return val;
|
|
||||||
})();
|
|
||||||
""".trimIndent()
|
|
||||||
}
|
|
||||||
}
|
|
@ -51,8 +51,6 @@ class NineAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
private val vrfInterceptor by lazy { JsVrfInterceptor(baseUrl) }
|
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
private val preferences: SharedPreferences by lazy {
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
@ -105,10 +103,7 @@ class NineAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
throw Exception("Not used")
|
throw Exception("Not used")
|
||||||
|
|
||||||
private fun searchAnimeRequest(page: Int, query: String, filters: NineAnimeFilters.FilterSearchParams): Request {
|
private fun searchAnimeRequest(page: Int, query: String, filters: NineAnimeFilters.FilterSearchParams): Request {
|
||||||
val vrf = (if (query.isNotBlank()) vrfInterceptor.getVrf(query) else "").let {
|
val vrf = if (query.isNotBlank()) callConsumet(query, "searchVrf") else ""
|
||||||
java.net.URLEncoder.encode(it, "utf-8")
|
|
||||||
}
|
|
||||||
|
|
||||||
var url = "$baseUrl/filter?keyword=$query"
|
var url = "$baseUrl/filter?keyword=$query"
|
||||||
|
|
||||||
if (filters.genre.isNotBlank()) url += filters.genre
|
if (filters.genre.isNotBlank()) url += filters.genre
|
||||||
@ -121,7 +116,7 @@ class NineAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
if (filters.rating.isNotBlank()) url += filters.rating
|
if (filters.rating.isNotBlank()) url += filters.rating
|
||||||
|
|
||||||
return GET(
|
return GET(
|
||||||
"$url&sort=${filters.sort}&$VRF_NAME=$vrf&page=$page",
|
"$url&sort=${filters.sort}&$vrf&page=$page",
|
||||||
headers = Headers.headersOf("Referer", "$baseUrl/"),
|
headers = Headers.headersOf("Referer", "$baseUrl/"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -162,9 +157,9 @@ class NineAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
override fun episodeListRequest(anime: SAnime): Request {
|
override fun episodeListRequest(anime: SAnime): Request {
|
||||||
val id = client.newCall(GET(baseUrl + anime.url)).execute().asJsoup()
|
val id = client.newCall(GET(baseUrl + anime.url)).execute().asJsoup()
|
||||||
.selectFirst("div[data-id]")!!.attr("data-id")
|
.selectFirst("div[data-id]")!!.attr("data-id")
|
||||||
val vrf = java.net.URLEncoder.encode(callConsumet(id, "vrf"), "utf-8")
|
val vrf = callConsumet(id, "vrf")
|
||||||
return GET(
|
return GET(
|
||||||
"$baseUrl/ajax/episode/list/$id?$VRF_NAME=$vrf",
|
"$baseUrl/ajax/episode/list/$id?$vrf",
|
||||||
headers = Headers.headersOf("url", anime.url),
|
headers = Headers.headersOf("url", anime.url),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -201,8 +196,8 @@ class NineAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
|
|
||||||
override fun videoListRequest(episode: SEpisode): Request {
|
override fun videoListRequest(episode: SEpisode): Request {
|
||||||
val ids = episode.url.substringBefore("&")
|
val ids = episode.url.substringBefore("&")
|
||||||
val vrf = java.net.URLEncoder.encode(callConsumet(ids, "vrf"), "utf-8")
|
val vrf = callConsumet(ids, "vrf")
|
||||||
val url = "/ajax/server/list/$ids?$VRF_NAME=$vrf"
|
val url = "/ajax/server/list/$ids?$vrf"
|
||||||
val epurl = episode.url.substringAfter("epurl=")
|
val epurl = episode.url.substringAfter("epurl=")
|
||||||
return GET(baseUrl + url, headers = Headers.headersOf("url", epurl))
|
return GET(baseUrl + url, headers = Headers.headersOf("url", epurl))
|
||||||
}
|
}
|
||||||
@ -264,10 +259,10 @@ class NineAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun extractVideoConsumet(server: Triple<String, String, String>, epUrl: String): List<Video> {
|
private fun extractVideoConsumet(server: Triple<String, String, String>, epUrl: String): List<Video> {
|
||||||
val vrf = java.net.URLEncoder.encode(callConsumet(server.second, "vrf"), "utf-8")
|
val vrf = callConsumet(server.second, "vrf")
|
||||||
val referer = Headers.headersOf("referer", epUrl)
|
val referer = Headers.headersOf("referer", epUrl)
|
||||||
val response = client.newCall(
|
val response = client.newCall(
|
||||||
GET("$baseUrl/ajax/server/${server.second}?$VRF_NAME=$vrf", headers = referer),
|
GET("$baseUrl/ajax/server/${server.second}?$vrf", headers = referer),
|
||||||
).execute()
|
).execute()
|
||||||
if (response.code != 200) return emptyList()
|
if (response.code != 200) return emptyList()
|
||||||
val videoList = mutableListOf<Video>()
|
val videoList = mutableListOf<Video>()
|
||||||
@ -322,10 +317,18 @@ class NineAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
return client.newCall(
|
return client.newCall(
|
||||||
GET("https://api.consumet.org/anime/9anime/helper?query=$query&action=$action"),
|
GET("https://api.consumet.org/anime/9anime/helper?query=$query&action=$action"),
|
||||||
).execute().body.string().let {
|
).execute().body.string().let {
|
||||||
if (action == "vizcloud") {
|
when (action) {
|
||||||
it.substringAfter("file\":\"").substringBefore("\"")
|
"vizcloud" -> {
|
||||||
} else {
|
it.substringAfter("file\":\"").substringBefore("\"")
|
||||||
it.substringAfter("vrf\":\"").substringBefore("\"")
|
}
|
||||||
|
"decrypt" -> {
|
||||||
|
json.decodeFromString<VrfResponse>(it).url
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
json.decodeFromString<VrfResponse>(it).let { vrf ->
|
||||||
|
"${vrf.vrfQuery}=${java.net.URLEncoder.encode(vrf.url, "utf-8")}"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -362,6 +365,12 @@ class NineAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class VrfResponse(
|
||||||
|
val url: String,
|
||||||
|
val vrfQuery: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||||
val domainPref = ListPreference(screen.context).apply {
|
val domainPref = ListPreference(screen.context).apply {
|
||||||
key = "preferred_domain"
|
key = "preferred_domain"
|
||||||
@ -416,8 +425,4 @@ class NineAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
private fun <A, B> Iterable<A>.parallelMap(f: suspend (A) -> B): List<B> = runBlocking {
|
private fun <A, B> Iterable<A>.parallelMap(f: suspend (A) -> B): List<B> = runBlocking {
|
||||||
map { async(Dispatchers.Default) { f(it) } }.awaitAll()
|
map { async(Dispatchers.Default) { f(it) } }.awaitAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val VRF_NAME = "vrf250"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user