forked from aniyomiorg/aniyomi-extensions
-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #81 from Dark25/updates
feat(lib/src/es/de/en): refactor, implement and fixed extensions/libs
- Loading branch information
Showing
54 changed files
with
1,284 additions
and
1,380 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
plugins { | ||
id("lib-android") | ||
} | ||
|
||
dependencies { | ||
implementation(project(":lib:playlist-utils")) | ||
} |
86 changes: 86 additions & 0 deletions
86
...treamsilk-extractor/src/main/java/eu/kanade/tachiyomi/lib/streamsilkextractor/JsHunter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
62 changes: 62 additions & 0 deletions
62
...xtractor/src/main/java/eu/kanade/tachiyomi/lib/streamsilkextractor/StreamSilkExtractor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | ||
} |
104 changes: 104 additions & 0 deletions
104
...rd-extractor/src/main/java/eu/kanade/tachiyomi/lib/vidguardextractor/VidGuardExtractor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.