forked from AlmightyHak/extensions-source
chore(src): Multiple improvements and fixes (#233)
* Hackstore improvements * VerAnimes improvements * Pelisplushd improvements * AnimeFenix improvements * AnimeFlv Improvements * AsiaLiveAction improvements * TioAnime improvements and VidGuardExtractor added * Replacing VidGuardExtractor files in extensions * oppstrem fixed Closes #220
This commit is contained in:
parent
6dc7b288e6
commit
41a6b6c788
60 changed files with 1213 additions and 1432 deletions
7
lib/streamsilk-extractor/build.gradle.kts
Normal file
7
lib/streamsilk-extractor/build.gradle.kts
Normal file
|
@ -0,0 +1,7 @@
|
|||
plugins {
|
||||
id("lib-android")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":lib:playlist-utils"))
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package eu.kanade.tachiyomi.lib.streamsilkextractor
|
||||
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.math.pow
|
||||
|
||||
class JsHunter(private val hunterJS: String) {
|
||||
|
||||
/**
|
||||
* Detects whether the javascript is H.U.N.T.E.R coded.
|
||||
*
|
||||
* @return true if it's H.U.N.T.E.R coded.
|
||||
*/
|
||||
fun detect(): Boolean {
|
||||
val p = Pattern.compile("eval\\(function\\(h,u,n,t,e,r\\)")
|
||||
val searchResults = p.matcher(hunterJS)
|
||||
return searchResults.find()
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpack the javascript
|
||||
*
|
||||
* @return the javascript unhunt or null.
|
||||
*/
|
||||
|
||||
fun dehunt(): String? {
|
||||
try {
|
||||
val p: Pattern =
|
||||
Pattern.compile(
|
||||
"""\}\("([^"]+)",[^,]+,\s*"([^"]+)",\s*(\d+),\s*(\d+)""",
|
||||
Pattern.DOTALL
|
||||
)
|
||||
val searchResults: Matcher = p.matcher(hunterJS)
|
||||
if (searchResults.find() && searchResults.groupCount() == 4) {
|
||||
val h = searchResults.group(1)!!.toString()
|
||||
val n = searchResults.group(2)!!.toString()
|
||||
val t = searchResults.group(3)!!.toInt()
|
||||
val e = searchResults.group(4)!!.toInt()
|
||||
return hunter(h, n, t, e)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun duf(d: String, e: Int, f: Int = 10): Int {
|
||||
val str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/"
|
||||
val g = str.toList()
|
||||
val h = g.take(e)
|
||||
val i = g.take(f)
|
||||
val dList = d.reversed().toList()
|
||||
var j = 0.0
|
||||
for ((c, b) in dList.withIndex()) {
|
||||
if (b in h) {
|
||||
j += h.indexOf(b) * e.toDouble().pow(c)
|
||||
}
|
||||
}
|
||||
var k = ""
|
||||
while (j > 0) {
|
||||
k = i[(j % f).toInt()] + k
|
||||
j = (j - j % f) / f
|
||||
}
|
||||
return k.toIntOrNull() ?: 0
|
||||
}
|
||||
|
||||
private fun hunter(h: String, n: String, t: Int, e: Int): String {
|
||||
var result = ""
|
||||
var i = 0
|
||||
while (i < h.length) {
|
||||
var j = 0
|
||||
var s = ""
|
||||
while (h[i] != n[e]) {
|
||||
s += h[i]
|
||||
i++
|
||||
}
|
||||
while (j < n.length) {
|
||||
s = s.replace(n[j], j.digitToChar())
|
||||
j++
|
||||
}
|
||||
result += (duf(s, e) - t).toChar()
|
||||
i++
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package eu.kanade.tachiyomi.lib.streamsilkextractor
|
||||
|
||||
import eu.kanade.tachiyomi.animesource.model.Track
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.internal.commonEmptyHeaders
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class StreamSilkExtractor(private val client: OkHttpClient, private val headers: Headers = commonEmptyHeaders) {
|
||||
|
||||
private val srcRegex = Regex("var urlPlay =\\s*\"(.*?m3u8.*?)\"")
|
||||
|
||||
private val subsRegex = Regex("jsonUrl = `([^`]*)`")
|
||||
|
||||
private val videoHeaders by lazy {
|
||||
headers.newBuilder()
|
||||
.set("Referer", "$STREAM_SILK_URL/")
|
||||
.set("Origin", STREAM_SILK_URL)
|
||||
.build()
|
||||
}
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
private val playlistUtils by lazy { PlaylistUtils(client, videoHeaders) }
|
||||
|
||||
fun videosFromUrl(url: String, prefix: String) = videosFromUrl(url) { "${prefix}StreamSilk:$it" }
|
||||
|
||||
fun videosFromUrl(url: String, videoNameGen: (String) -> String = { quality -> "StreamSilk:$quality" }): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val scriptData = document.select("script").firstOrNull { it.html().contains("h,u,n,t,e,r") }?.data() ?: return emptyList()
|
||||
val deHunt = JsHunter(scriptData).dehunt() ?: return emptyList()
|
||||
val link = extractLink(deHunt) ?: return emptyList()
|
||||
|
||||
val subs = buildList {
|
||||
val subUrl = extractSubs(deHunt)
|
||||
if (!subUrl.isNullOrEmpty()) {
|
||||
runCatching {
|
||||
client.newCall(GET(subUrl, videoHeaders)).execute().body.string()
|
||||
.let { json.decodeFromString<List<SubtitleDto>>(it) }
|
||||
.forEach { add(Track(it.file, it.label)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return playlistUtils.extractFromHls(link, videoNameGen = videoNameGen, subtitleList = subs)
|
||||
}
|
||||
|
||||
private fun extractLink(script: String) = srcRegex.find(script)?.groupValues?.get(1)?.trim()
|
||||
|
||||
private fun extractSubs(script: String) = subsRegex.find(script)?.groupValues?.get(1)?.trim()
|
||||
|
||||
@Serializable
|
||||
data class SubtitleDto(val file: String, val label: String)
|
||||
}
|
||||
|
||||
private const val STREAM_SILK_URL = "https://streamsilk.com"
|
8
lib/vidguard-extractor/build.gradle.kts
Normal file
8
lib/vidguard-extractor/build.gradle.kts
Normal file
|
@ -0,0 +1,8 @@
|
|||
plugins {
|
||||
id("lib-android")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":lib:playlist-utils"))
|
||||
implementation("org.mozilla:rhino:1.7.14")
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package eu.kanade.tachiyomi.lib.vidguardextractor
|
||||
|
||||
import android.util.Base64
|
||||
import android.util.Log
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.OkHttpClient
|
||||
import org.mozilla.javascript.Context
|
||||
import org.mozilla.javascript.NativeJSON
|
||||
import org.mozilla.javascript.NativeObject
|
||||
import org.mozilla.javascript.Scriptable
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class VidGuardExtractor(private val client: OkHttpClient) {
|
||||
|
||||
private val playlistUtils by lazy { PlaylistUtils(client) }
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
fun videosFromUrl(url: String, prefix: String) = videosFromUrl(url) { "${prefix}VidGuard:$it" }
|
||||
|
||||
fun videosFromUrl(url: String, videoNameGen: (String) -> String = { quality -> "VidGuard:$quality" }): List<Video> {
|
||||
val res = client.newCall(GET(url)).execute().asJsoup()
|
||||
val scriptData = res.selectFirst("script:containsData(eval)")?.data() ?: return emptyList()
|
||||
|
||||
val jsonStr2 = json.decodeFromString<SvgObject>(runJS2(scriptData))
|
||||
val playlistUrl = sigDecode(jsonStr2.stream)
|
||||
|
||||
return playlistUtils.extractFromHls(playlistUrl, videoNameGen = videoNameGen)
|
||||
}
|
||||
|
||||
private fun sigDecode(url: String): String {
|
||||
val sig = url.split("sig=")[1].split("&")[0]
|
||||
val t = sig.chunked(2)
|
||||
.joinToString("") { (Integer.parseInt(it, 16) xor 2).toChar().toString() }
|
||||
.let {
|
||||
val padding = when (it.length % 4) {
|
||||
2 -> "=="
|
||||
3 -> "="
|
||||
else -> ""
|
||||
}
|
||||
String(Base64.decode((it + padding).toByteArray(Charsets.UTF_8), Base64.DEFAULT))
|
||||
}
|
||||
.dropLast(5)
|
||||
.reversed()
|
||||
.toCharArray()
|
||||
.apply {
|
||||
for (i in indices step 2) {
|
||||
if (i + 1 < size) {
|
||||
this[i] = this[i + 1].also { this[i + 1] = this[i] }
|
||||
}
|
||||
}
|
||||
}
|
||||
.concatToString()
|
||||
.dropLast(5)
|
||||
return url.replace(sig, t)
|
||||
}
|
||||
|
||||
private fun runJS2(hideMyHtmlContent: String): String {
|
||||
var result = ""
|
||||
val r = Runnable {
|
||||
val rhino = Context.enter()
|
||||
rhino.initSafeStandardObjects()
|
||||
rhino.optimizationLevel = -1
|
||||
val scope: Scriptable = rhino.initSafeStandardObjects()
|
||||
scope.put("window", scope, scope)
|
||||
try {
|
||||
rhino.evaluateString(
|
||||
scope,
|
||||
hideMyHtmlContent,
|
||||
"JavaScript",
|
||||
1,
|
||||
null,
|
||||
)
|
||||
val svgObject = scope.get("svg", scope)
|
||||
result = if (svgObject is NativeObject) {
|
||||
NativeJSON.stringify(Context.getCurrentContext(), scope, svgObject, null, null)
|
||||
.toString()
|
||||
} else {
|
||||
Context.toString(svgObject)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.i("Error", e.toString())
|
||||
} finally {
|
||||
Context.exit()
|
||||
}
|
||||
}
|
||||
val t = Thread(ThreadGroup("A"), r, "thread_rhino", 2000000) // StackSize 2Mb: Run in a thread because rhino requires more stack size for large scripts.
|
||||
t.start()
|
||||
t.join()
|
||||
t.interrupt()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class SvgObject(
|
||||
val stream: String,
|
||||
val hash: String,
|
||||
)
|
|
@ -20,14 +20,15 @@ class VkExtractor(private val client: OkHttpClient, private val headers: Headers
|
|||
.build()
|
||||
}
|
||||
|
||||
fun videosFromUrl(url: String, prefix: String = ""): List<Video> {
|
||||
val data = client.newCall(GET(url, documentHeaders)).execute()
|
||||
.body.string()
|
||||
fun videosFromUrl(url: String, prefix: String) = videosFromUrl(url) { "${prefix}Vk:$it" }
|
||||
|
||||
fun videosFromUrl(url: String, videoNameGen: (String) -> String = { quality -> "Vk:$quality" }): List<Video> {
|
||||
val data = client.newCall(GET(url, documentHeaders)).execute().body.string()
|
||||
|
||||
return REGEX_VIDEO.findAll(data).map {
|
||||
val quality = it.groupValues[1]
|
||||
val videoUrl = it.groupValues[2].replace("\\/", "/")
|
||||
Video(videoUrl, "${prefix}vk.com - ${quality}p", videoUrl, videoHeaders)
|
||||
Video(videoUrl, videoNameGen("${quality}p"), videoUrl, videoHeaders)
|
||||
}.toList()
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue