diff --git a/lib/streamsilk-extractor/build.gradle.kts b/lib/streamsilk-extractor/build.gradle.kts new file mode 100644 index 000000000..d31dd9ff6 --- /dev/null +++ b/lib/streamsilk-extractor/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + id("lib-android") +} + +dependencies { + implementation(project(":lib:playlist-utils")) +} diff --git a/lib/streamsilk-extractor/src/main/java/eu/kanade/tachiyomi/lib/streamsilkextractor/JsHunter.kt b/lib/streamsilk-extractor/src/main/java/eu/kanade/tachiyomi/lib/streamsilkextractor/JsHunter.kt new file mode 100644 index 000000000..8fff8ef09 --- /dev/null +++ b/lib/streamsilk-extractor/src/main/java/eu/kanade/tachiyomi/lib/streamsilkextractor/JsHunter.kt @@ -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 + } +} diff --git a/lib/streamsilk-extractor/src/main/java/eu/kanade/tachiyomi/lib/streamsilkextractor/StreamSilkExtractor.kt b/lib/streamsilk-extractor/src/main/java/eu/kanade/tachiyomi/lib/streamsilkextractor/StreamSilkExtractor.kt new file mode 100644 index 000000000..2c80ab483 --- /dev/null +++ b/lib/streamsilk-extractor/src/main/java/eu/kanade/tachiyomi/lib/streamsilkextractor/StreamSilkExtractor.kt @@ -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