Skip to content

Commit 1fc6597

Browse files
Last Sync: 2026-07-08 06:50 (Mobile)
1 parent d660cfc commit 1fc6597

1 file changed

Lines changed: 81 additions & 54 deletions

File tree

KuramanimeProvider/src/main/kotlin/com/hexated/KuramanimeProvider.kt

Lines changed: 81 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@ import com.lagradost.cloudstream3.utils.INFER_TYPE
99
import com.lagradost.cloudstream3.utils.Qualities
1010
import com.lagradost.cloudstream3.utils.loadExtractor
1111
import com.lagradost.cloudstream3.utils.newExtractorLink
12+
import kotlinx.coroutines.Dispatchers
1213
import kotlinx.coroutines.delay
14+
import kotlinx.coroutines.withContext
1315
import org.jsoup.Jsoup
1416
import org.jsoup.nodes.Element
1517
import org.mozilla.javascript.BaseFunction
1618
import org.mozilla.javascript.Context
19+
import org.mozilla.javascript.ContextFactory
1720
import org.mozilla.javascript.Function
1821
import org.mozilla.javascript.Scriptable
1922
import org.mozilla.javascript.ScriptableObject
@@ -249,7 +252,7 @@ class KuramanimeProvider : MainAPI() {
249252
suspend fun fetchAuth(): String {
250253
val url = "$mainUrl/storage/leviathan.js?v=${System.currentTimeMillis()}"
251254
val res = app.get(url).text
252-
return extractAuthToken(res) ?: throw ErrorLoadingException()
255+
return withContext(Dispatchers.IO) { extractAuthToken(res) } ?: throw ErrorLoadingException()
253256
}
254257

255258
private fun extractAuthToken(rawScript: String): String? {
@@ -269,65 +272,89 @@ class KuramanimeProvider : MainAPI() {
269272
}
270273
}
271274

272-
val rhino = Context.enter()
273-
try {
274-
rhino.optimizationLevel = -1 // interpreted mode: avoids JVM method-size limits on big scripts
275-
rhino.setLanguageVersion(Context.VERSION_ES6)
276-
val scope: Scriptable = rhino.initSafeStandardObjects()
275+
val factory = object : ContextFactory() {
276+
override fun observeInstructionCount(cx: Context, instructionCount: Int) {
277+
if (Thread.currentThread().isInterrupted) {
278+
throw InterruptedException("aborted")
279+
}
280+
}
277281

278-
val noop = object : BaseFunction() {
279-
override fun call(cx: Context, scope: Scriptable, thisObj: Scriptable, args: Array<Any?>): Any =
280-
Undefined.instance
282+
override fun makeContext(): Context {
283+
val cx = super.makeContext()
284+
cx.instructionObserverThreshold = 2000
285+
return cx
281286
}
282-
val fetchStub = object : BaseFunction() {
283-
override fun call(cx: Context, scope: Scriptable, thisObj: Scriptable, args: Array<Any?>): Any {
284-
captureFromOptions(args.getOrNull(1))
285-
return Undefined.instance
287+
}
288+
289+
val worker = Thread(null, {
290+
val rhino = factory.enterContext()
291+
try {
292+
rhino.optimizationLevel = -1 // interpreted mode: avoids JVM method-size limits on big scripts + enables the kill switch above
293+
rhino.setLanguageVersion(Context.VERSION_ES6)
294+
val scope: Scriptable = rhino.initSafeStandardObjects()
295+
296+
val noop = object : BaseFunction() {
297+
override fun call(cx: Context, scope: Scriptable, thisObj: Scriptable, args: Array<Any?>): Any =
298+
Undefined.instance
286299
}
287-
}
288-
val ajaxStub = object : BaseFunction() {
289-
override fun call(cx: Context, scope: Scriptable, thisObj: Scriptable, args: Array<Any?>): Any {
290-
captureFromOptions(args.getOrNull(0))
291-
return Undefined.instance
300+
val fetchStub = object : BaseFunction() {
301+
override fun call(cx: Context, scope: Scriptable, thisObj: Scriptable, args: Array<Any?>): Any {
302+
captureFromOptions(args.getOrNull(1))
303+
return Undefined.instance
304+
}
292305
}
293-
}
294-
val dollarStub = object : BaseFunction() {
295-
override fun call(cx: Context, scope: Scriptable, thisObj: Scriptable, args: Array<Any?>): Any = scope
296-
}
297-
ScriptableObject.putProperty(dollarStub, "ajax", ajaxStub)
298-
299-
scope.put("fetch", scope, fetchStub)
300-
scope.put("$", scope, dollarStub)
301-
scope.put("setInterval", scope, noop)
302-
scope.put("setTimeout", scope, noop)
303-
scope.put("clearInterval", scope, noop)
304-
scope.put("clearTimeout", scope, noop)
305-
scope.put("document", scope, rhino.newObject(scope))
306-
scope.put("navigator", scope, rhino.newObject(scope))
307-
scope.put("window", scope, scope)
308-
309-
val preExisting = scope.ids.toSet()
310-
311-
rhino.evaluateString(scope, script, "leviathan.js", 1, null)
312-
313-
val dummyOpts = rhino.newObject(scope)
314-
val candidateArgs = arrayOf<Any?>(
315-
"$mainUrl/probe", "POST", "json", dummyOpts, noop, noop, noop
316-
)
317-
318-
for (id in scope.ids) {
319-
if (captured != null) break
320-
val name = id as? String ?: continue
321-
if (name in preExisting) continue
322-
val fn = ScriptableObject.getProperty(scope, name) as? Function ?: continue
323-
try {
324-
fn.call(rhino, scope, scope, candidateArgs)
325-
} catch (_: Exception) {
306+
val ajaxStub = object : BaseFunction() {
307+
override fun call(cx: Context, scope: Scriptable, thisObj: Scriptable, args: Array<Any?>): Any {
308+
captureFromOptions(args.getOrNull(0))
309+
return Undefined.instance
310+
}
311+
}
312+
val dollarStub = object : BaseFunction() {
313+
override fun call(cx: Context, scope: Scriptable, thisObj: Scriptable, args: Array<Any?>): Any = scope
314+
}
315+
ScriptableObject.putProperty(dollarStub, "ajax", ajaxStub)
316+
317+
scope.put("fetch", scope, fetchStub)
318+
scope.put("$", scope, dollarStub)
319+
scope.put("setInterval", scope, noop)
320+
scope.put("setTimeout", scope, noop)
321+
scope.put("clearInterval", scope, noop)
322+
scope.put("clearTimeout", scope, noop)
323+
scope.put("document", scope, rhino.newObject(scope))
324+
scope.put("navigator", scope, rhino.newObject(scope))
325+
scope.put("window", scope, scope)
326+
327+
val preExisting = scope.ids.toSet()
328+
329+
rhino.evaluateString(scope, script, "leviathan.js", 1, null)
330+
331+
val dummyOpts = rhino.newObject(scope)
332+
val candidateArgs = arrayOf<Any?>(
333+
"$mainUrl/probe", "POST", "json", dummyOpts, noop, noop, noop
334+
)
335+
336+
for (id in scope.ids) {
337+
if (captured != null) break
338+
val name = id as? String ?: continue
339+
if (name in preExisting) continue
340+
val fn = ScriptableObject.getProperty(scope, name) as? Function ?: continue
341+
try {
342+
fn.call(rhino, scope, scope, candidateArgs)
343+
} catch (_: Throwable) {
344+
}
326345
}
346+
} catch (_: Throwable) {
347+
} finally {
348+
Context.exit()
327349
}
328-
} catch (_: Exception) {
329-
} finally {
330-
Context.exit()
350+
}, "kuramanime-leviathan-js", 8 * 1024 * 1024)
351+
352+
worker.isDaemon = true
353+
worker.start()
354+
worker.join(10_000L)
355+
if (worker.isAlive) {
356+
worker.interrupt()
357+
worker.join(1_000L)
331358
}
332359

333360
return captured

0 commit comments

Comments
 (0)