Skip to content

Commit

Permalink
Merge pull request #81 from Dark25/updates
Browse files Browse the repository at this point in the history
feat(lib/src/es/de/en): refactor, implement and fixed extensions/libs
  • Loading branch information
Dark25 authored Sep 15, 2024
2 parents b86f2b9 + 2baea69 commit aebf8cb
Show file tree
Hide file tree
Showing 54 changed files with 1,284 additions and 1,380 deletions.
7 changes: 7 additions & 0 deletions lib/streamsilk-extractor/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugins {
id("lib-android")
}

dependencies {
implementation(project(":lib:playlist-utils"))
}
Original file line number Diff line number Diff line change
@@ -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
}
}
Original file line number Diff line number Diff line change
@@ -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 changes: 8 additions & 0 deletions lib/vidguard-extractor/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
plugins {
id("lib-android")
}

dependencies {
implementation(project(":lib:playlist-utils"))
implementation("org.mozilla:rhino:1.7.14")
}
Original file line number Diff line number Diff line change
@@ -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,
)
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}

Expand Down
5 changes: 3 additions & 2 deletions src/de/animebase/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
ext {
extName = 'Anime-Base'
extClass = '.AnimeBase'
extVersionCode = 29
extVersionCode = 30
isNsfw = true
}

Expand All @@ -10,6 +10,7 @@ apply from: "$rootDir/common.gradle"
dependencies {
implementation(project(":lib:voe-extractor"))
implementation(project(":lib:streamwish-extractor"))
implementation(project(":lib:vidguard-extractor"))
implementation(project(":lib:playlist-utils"))
implementation("dev.datlag.jsunpacker:jsunpacker:1.0.1")
implementation(libs.jsunpacker)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import android.app.Application
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.de.animebase.extractors.UnpackerExtractor
import eu.kanade.tachiyomi.animeextension.de.animebase.extractors.VidGuardExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.AnimesPage
Expand All @@ -13,6 +12,7 @@ import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
import eu.kanade.tachiyomi.lib.vidguardextractor.VidGuardExtractor
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
Expand Down
Loading

0 comments on commit aebf8cb

Please sign in to comment.