fix(tr/turkanime): fix key extraction (#1881)
This commit is contained in:
@ -19,7 +19,7 @@ ext {
|
|||||||
extName = 'Türk Anime TV'
|
extName = 'Türk Anime TV'
|
||||||
pkgNameSuffix = 'tr.turkanime'
|
pkgNameSuffix = 'tr.turkanime'
|
||||||
extClass = '.TurkAnime'
|
extClass = '.TurkAnime'
|
||||||
extVersionCode = 4
|
extVersionCode = 5
|
||||||
libVersion = '13'
|
libVersion = '13'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,18 +38,14 @@ import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
|||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.POST
|
import eu.kanade.tachiyomi.network.POST
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.JsonPrimitive
|
|
||||||
import okhttp3.FormBody
|
import okhttp3.FormBody
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
@ -80,9 +76,6 @@ class TurkAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val key: String
|
|
||||||
get() = preferences.getString(PREF_KEY_KEY, DEFAULT_KEY)!!
|
|
||||||
|
|
||||||
// ============================== Popular ===============================
|
// ============================== Popular ===============================
|
||||||
|
|
||||||
override fun popularAnimeRequest(page: Int) = GET("$baseUrl/ajax/rankagore?sayfa=$page", xmlHeader)
|
override fun popularAnimeRequest(page: Int) = GET("$baseUrl/ajax/rankagore?sayfa=$page", xmlHeader)
|
||||||
@ -208,17 +201,21 @@ class TurkAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
override fun videoListParse(response: Response): List<Video> {
|
override fun videoListParse(response: Response): List<Video> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
val fansubbers = document.select("div#videodetay div.pull-right button")
|
val fansubbers = document.select("div#videodetay div.pull-right button")
|
||||||
return if (fansubbers.size == 1) {
|
val videoList = if (fansubbers.size == 1) {
|
||||||
getVideosFromHosters(document, fansubbers.first()!!.text().trim())
|
getVideosFromHosters(document, fansubbers.first()!!.text().trim())
|
||||||
} else {
|
} else {
|
||||||
val videoList = mutableListOf<Video>()
|
val videos = mutableListOf<Video>()
|
||||||
fansubbers.parallelMap {
|
fansubbers.parallelMap {
|
||||||
val url = it.attr("onclick").trimOnClick()
|
val url = it.attr("onclick").trimOnClick()
|
||||||
val subDoc = client.newCall(GET(url, xmlHeader)).execute().asJsoup()
|
val subDoc = client.newCall(GET(url, xmlHeader)).execute().asJsoup()
|
||||||
videoList.addAll(getVideosFromHosters(subDoc, it.text().trim()))
|
videos.addAll(getVideosFromHosters(subDoc, it.text().trim()))
|
||||||
}
|
}
|
||||||
videoList
|
videos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
require(videoList.isNotEmpty()) { "Failed to extract videos" }
|
||||||
|
|
||||||
|
return videoList
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getVideosFromHosters(document: Document, subber: String): List<Video> {
|
private fun getVideosFromHosters(document: Document, subber: String): List<Video> {
|
||||||
@ -240,9 +237,7 @@ class TurkAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
val url = it.attr("onclick").trimOnClick()
|
val url = it.attr("onclick").trimOnClick()
|
||||||
val videoDoc = client.newCall(GET(url, xmlHeader)).execute().asJsoup()
|
val videoDoc = client.newCall(GET(url, xmlHeader)).execute().asJsoup()
|
||||||
val src = videoDoc.select("iframe").attr("src").replace("^//".toRegex(), "https://")
|
val src = videoDoc.select("iframe").attr("src").replace("^//".toRegex(), "https://")
|
||||||
runCatching {
|
videoList.addAll(getVideosFromSource(src, hosterName, subber))
|
||||||
videoList.addAll(getVideosFromSource(src, hosterName, subber))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return videoList
|
return videoList
|
||||||
}
|
}
|
||||||
@ -259,79 +254,77 @@ class TurkAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
val hosterLink = "https:" + json.decodeFromString<JsonPrimitive>(
|
val hosterLink = "https:" + decryptParams(cipherParams)
|
||||||
CryptoAES.decryptWithSalt(
|
|
||||||
cipherParams.ct,
|
|
||||||
cipherParams.s,
|
|
||||||
key,
|
|
||||||
),
|
|
||||||
).content
|
|
||||||
|
|
||||||
when (hosterName) {
|
runCatching {
|
||||||
"ALUCARD(BETA)" -> {
|
when (hosterName) {
|
||||||
videoList.addAll(AlucardExtractor(client, json, baseUrl).extractVideos(hosterLink, subber))
|
"ALUCARD(BETA)" -> {
|
||||||
}
|
videoList.addAll(AlucardExtractor(client, json, baseUrl).extractVideos(hosterLink, subber))
|
||||||
"DOODSTREAM" -> {
|
|
||||||
videoList.addAll(DoodExtractor(client).videosFromUrl(hosterLink, "$subber: DOODSTREAM", redirect = false))
|
|
||||||
}
|
|
||||||
"EMBEDGRAM" -> {
|
|
||||||
videoList.addAll(EmbedgramExtractor(client, headers).videosFromUrl(hosterLink, prefix = "$subber: "))
|
|
||||||
}
|
|
||||||
"FILEMOON" -> {
|
|
||||||
videoList.addAll(FilemoonExtractor(client, headers).videosFromUrl(hosterLink, prefix = "$subber: "))
|
|
||||||
}
|
|
||||||
"GDRIVE" -> {
|
|
||||||
Regex("""[\w-]{28,}""").find(hosterLink)?.groupValues?.get(0)?.let {
|
|
||||||
videoList.addAll(GoogleDriveExtractor(client, headers).videosFromUrl("https://drive.google.com/uc?id=$it", "$subber: Gdrive"))
|
|
||||||
}
|
}
|
||||||
}
|
"DOODSTREAM" -> {
|
||||||
"MAIL" -> {
|
videoList.addAll(DoodExtractor(client).videosFromUrl(hosterLink, "$subber: DOODSTREAM", redirect = false))
|
||||||
videoList.addAll(MailRuExtractor(client, headers).videosFromUrl(hosterLink, prefix = "$subber: "))
|
}
|
||||||
}
|
"EMBEDGRAM" -> {
|
||||||
"MP4UPLOAD" -> {
|
videoList.addAll(EmbedgramExtractor(client, headers).videosFromUrl(hosterLink, prefix = "$subber: "))
|
||||||
videoList.addAll(Mp4uploadExtractor(client).videosFromUrl(hosterLink, headers, prefix = "$subber: "))
|
}
|
||||||
}
|
"FILEMOON" -> {
|
||||||
"MYVI" -> {
|
videoList.addAll(FilemoonExtractor(client, headers).videosFromUrl(hosterLink, prefix = "$subber: "))
|
||||||
videoList.addAll(MytvExtractor(client).videosFromUrl(hosterLink, prefix = "$subber: "))
|
}
|
||||||
}
|
"GDRIVE" -> {
|
||||||
"MVIDOO" -> {
|
Regex("""[\w-]{28,}""").find(hosterLink)?.groupValues?.get(0)?.let {
|
||||||
videoList.addAll(MVidooExtractor(client).videosFromUrl(hosterLink, prefix = "$subber: "))
|
videoList.addAll(GoogleDriveExtractor(client, headers).videosFromUrl("https://drive.google.com/uc?id=$it", "$subber: Gdrive"))
|
||||||
}
|
}
|
||||||
"ODNOKLASSNIKI" -> {
|
}
|
||||||
videoList.addAll(OkruExtractor(client).videosFromUrl(hosterLink, prefix = "$subber: "))
|
"MAIL" -> {
|
||||||
}
|
videoList.addAll(MailRuExtractor(client, headers).videosFromUrl(hosterLink, prefix = "$subber: "))
|
||||||
"SENDVID" -> {
|
}
|
||||||
videoList.addAll(SendvidExtractor(client, headers).videosFromUrl(hosterLink, prefix = "$subber: "))
|
"MP4UPLOAD" -> {
|
||||||
}
|
videoList.addAll(Mp4uploadExtractor(client).videosFromUrl(hosterLink, headers, prefix = "$subber: "))
|
||||||
"SIBNET" -> {
|
}
|
||||||
videoList.addAll(SibnetExtractor(client).getVideosFromUrl(hosterLink, prefix = "$subber: "))
|
"MYVI" -> {
|
||||||
}
|
videoList.addAll(MytvExtractor(client).videosFromUrl(hosterLink, prefix = "$subber: "))
|
||||||
"STREAMSB" -> {
|
}
|
||||||
videoList.addAll(StreamSBExtractor(client).videosFromUrl(hosterLink, refererHeader, prefix = "$subber: "))
|
"MVIDOO" -> {
|
||||||
}
|
videoList.addAll(MVidooExtractor(client).videosFromUrl(hosterLink, prefix = "$subber: "))
|
||||||
"STREAMVID" -> {
|
}
|
||||||
videoList.addAll(StreamVidExtractor(client).videosFromUrl(hosterLink, headers, prefix = "$subber: "))
|
"ODNOKLASSNIKI" -> {
|
||||||
}
|
videoList.addAll(OkruExtractor(client).videosFromUrl(hosterLink, prefix = "$subber: "))
|
||||||
"UQLOAD" -> {
|
}
|
||||||
videoList.addAll(UqloadExtractor(client).videosFromUrl(hosterLink, headers, "$subber: Uqload"))
|
"SENDVID" -> {
|
||||||
}
|
videoList.addAll(SendvidExtractor(client, headers).videosFromUrl(hosterLink, prefix = "$subber: "))
|
||||||
"VK" -> {
|
}
|
||||||
val vkUrl = "https://vk.com" + hosterLink.substringAfter("vk.com")
|
"SIBNET" -> {
|
||||||
videoList.addAll(VkExtractor(client).getVideosFromUrl(vkUrl, prefix = "$subber: "))
|
videoList.addAll(SibnetExtractor(client).getVideosFromUrl(hosterLink, prefix = "$subber: "))
|
||||||
}
|
}
|
||||||
"VOE" -> {
|
"STREAMSB" -> {
|
||||||
VoeExtractor(client).videoFromUrl(hosterLink, "$subber: VOE")?.let { video -> videoList.add(video) }
|
videoList.addAll(StreamSBExtractor(client).videosFromUrl(hosterLink, refererHeader, prefix = "$subber: "))
|
||||||
}
|
}
|
||||||
"VTUBE" -> {
|
"STREAMVID" -> {
|
||||||
videoList.addAll(VTubeExtractor(client, headers).videosFromUrl(hosterLink, baseUrl, prefix = "$subber: "))
|
videoList.addAll(StreamVidExtractor(client).videosFromUrl(hosterLink, headers, prefix = "$subber: "))
|
||||||
}
|
}
|
||||||
"VUDEA" -> {
|
"UQLOAD" -> {
|
||||||
videoList.addAll(VudeoExtractor(client).videosFromUrl(hosterLink, prefix = "$subber: "))
|
videoList.addAll(UqloadExtractor(client).videosFromUrl(hosterLink, headers, "$subber: Uqload"))
|
||||||
}
|
}
|
||||||
"WOLFSTREAM" -> {
|
"VK" -> {
|
||||||
videoList.addAll(WolfstreamExtractor(client).videosFromUrl(hosterLink, prefix = "$subber: "))
|
val vkUrl = "https://vk.com" + hosterLink.substringAfter("vk.com")
|
||||||
|
videoList.addAll(VkExtractor(client).getVideosFromUrl(vkUrl, prefix = "$subber: "))
|
||||||
|
}
|
||||||
|
"VOE" -> {
|
||||||
|
VoeExtractor(client).videoFromUrl(hosterLink, "$subber: VOE")?.let { video -> videoList.add(video) }
|
||||||
|
}
|
||||||
|
"VTUBE" -> {
|
||||||
|
videoList.addAll(VTubeExtractor(client, headers).videosFromUrl(hosterLink, baseUrl, prefix = "$subber: "))
|
||||||
|
}
|
||||||
|
"VUDEA" -> {
|
||||||
|
videoList.addAll(VudeoExtractor(client).videosFromUrl(hosterLink, prefix = "$subber: "))
|
||||||
|
}
|
||||||
|
"WOLFSTREAM" -> {
|
||||||
|
videoList.addAll(WolfstreamExtractor(client).videosFromUrl(hosterLink, prefix = "$subber: "))
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return videoList
|
return videoList
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,27 +367,56 @@ class TurkAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
|||||||
map { async { f(it) } }.awaitAll()
|
map { async { f(it) } }.awaitAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getKey() {
|
private val mutex = Mutex()
|
||||||
|
private var shouldUpdateKey = false
|
||||||
|
|
||||||
|
private val key: String
|
||||||
|
get() {
|
||||||
|
return runBlocking(Dispatchers.IO) {
|
||||||
|
mutex.withLock {
|
||||||
|
if (shouldUpdateKey) {
|
||||||
|
updateKey()
|
||||||
|
shouldUpdateKey = false
|
||||||
|
}
|
||||||
|
preferences.getString(PREF_KEY_KEY, DEFAULT_KEY)!!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun decryptParams(params: CipherParams, tried: Boolean = false): String {
|
||||||
|
val decrypted = CryptoAES.decryptWithSalt(
|
||||||
|
params.ct,
|
||||||
|
params.s,
|
||||||
|
key,
|
||||||
|
).ifEmpty {
|
||||||
|
if (tried) {
|
||||||
|
""
|
||||||
|
} else {
|
||||||
|
shouldUpdateKey = true
|
||||||
|
decryptParams(params, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.decodeFromString<String>(decrypted)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateKey() {
|
||||||
val script4 = client.newCall(GET("$baseUrl/embed/#/")).execute().asJsoup()
|
val script4 = client.newCall(GET("$baseUrl/embed/#/")).execute().asJsoup()
|
||||||
.select("script[defer]").getOrNull(1)
|
.select("script[defer]").getOrNull(1)
|
||||||
?.attr("src") ?: return
|
?.attr("src") ?: return
|
||||||
val embeds4 = client.newCall(GET(baseUrl + script4)).execute().body.string()
|
val embeds4 = client.newCall(GET(baseUrl + script4)).execute().body.string()
|
||||||
val name = "(?<=')[0-9a-f]{16}(?=')".toRegex().findAll(embeds4).toList().firstOrNull()?.value
|
val name = JS_NAME_REGEX.findAll(embeds4).toList().firstOrNull()?.value
|
||||||
|
|
||||||
val file5 = client.newCall(GET("$baseUrl/embed/js/embeds.$name.js")).execute().body.string()
|
val file5 = client.newCall(GET("$baseUrl/embed/js/embeds.$name.js")).execute().body.string()
|
||||||
val embeds5 = Deobfuscator.deobfuscateScript(file5) ?: return
|
val embeds5 = Deobfuscator.deobfuscateScript(file5) ?: return
|
||||||
val key = "(?<=')\\S{100}(?=')".toRegex().find(embeds5)?.value ?: return
|
val key = KEY_REGEX.find(embeds5)?.value ?: return
|
||||||
preferences.edit().putString(PREF_KEY_KEY, key).apply()
|
preferences.edit().putString(PREF_KEY_KEY, key).apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
|
||||||
@OptIn(DelicateCoroutinesApi::class)
|
|
||||||
GlobalScope.launch {
|
|
||||||
withContext(Dispatchers.IO) { getKey() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private val JS_NAME_REGEX by lazy { "(?<=')[0-9a-f]{16}(?=')".toRegex() }
|
||||||
|
private val KEY_REGEX by lazy { "(?<=')\\S{100}(?=')".toRegex() }
|
||||||
|
|
||||||
private val SUPPORTED_HOSTERS = listOf(
|
private val SUPPORTED_HOSTERS = listOf(
|
||||||
// TODO: Fix Alucard
|
// TODO: Fix Alucard
|
||||||
// "ALUCARD(BETA)",
|
// "ALUCARD(BETA)",
|
||||||
|
Reference in New Issue
Block a user