From 38d2bdbb59a048fd5a54d2f86b207a97f85085c9 Mon Sep 17 00:00:00 2001 From: AlmightyHak Date: Thu, 19 Jun 2025 13:32:58 -0500 Subject: [PATCH] revert e2f32478fc5ec0cc402e1368d3fc2726e3f5cb26 revert megacloud fix (#1020) yoinked from yuzono --- .../src/main/assets/megacloud.getsrcs.js | 26 ++--- .../megacloudextractor/MegaCloudExtractor.kt | 108 +++--------------- 2 files changed, 26 insertions(+), 108 deletions(-) diff --git a/lib/megacloud-extractor/src/main/assets/megacloud.getsrcs.js b/lib/megacloud-extractor/src/main/assets/megacloud.getsrcs.js index a8b05bf3..68b29a79 100644 --- a/lib/megacloud-extractor/src/main/assets/megacloud.getsrcs.js +++ b/lib/megacloud-extractor/src/main/assets/megacloud.getsrcs.js @@ -2,7 +2,7 @@ // solution inspired from https://github.com/drblgn/rabbit_wasm/blob/main/rabbit.ts // solution inspired from https://github.com/shimizudev/consumet.ts/blob/master/dist/extractors/megacloud/megacloud.getsrcs.js -const embed_url = 'https://megacloud.tv/embed-2/v2/e-1/'; +const embed_url = 'https://megacloud.tv/embed-2/e-1/'; const referrer = 'https://hianime.to'; const user_agent = navigator.userAgent; let wasm; @@ -31,7 +31,7 @@ const image_data = { data: window.decoded_png, }; const canvas = { - baseUrl: 'https://megacloud.tv/embed-2/v2/e-1/1hnXq7VzX0Ex?k=1', + baseUrl: 'https://megacloud.tv/embed-2/e-1/1hnXq7VzX0Ex?k=1', width: 0, height: 0, style: { @@ -58,7 +58,7 @@ const fake_window = { }, origin: 'https://megacloud.tv', location: { - href: 'https://megacloud.tv/embed-2/v2/e-1/1hnXq7VzX0Ex?k=1', + href: 'https://megacloud.tv/embed-2/e-1/1hnXq7VzX0Ex?k=1', origin: 'https://megacloud.tv', }, performance: { @@ -327,9 +327,9 @@ function initWasm() { __wbg_createElement_03cf347ddad1c8c0: function () { return applyToWindow(function ( // @ts-ignore - index, + index, // @ts-ignore - decodeIndex, + decodeIndex, // @ts-ignore decodeIndexOffset) { return addToStack(canvas); @@ -338,9 +338,9 @@ function initWasm() { __wbg_querySelector_118a0639aa1f51cd: function () { return applyToWindow(function ( // @ts-ignore - index, + index, // @ts-ignore - decodeIndex, + decodeIndex, // @ts-ignore decodeOffset) { //let item = get(index).querySelector(decodeSub(decodeIndex, decodeOffset)); @@ -353,11 +353,11 @@ function initWasm() { return addToStack(nodeList); }, arguments); }, - __wbg_getAttribute_706ae88bd37410fa: function (offset, + __wbg_getAttribute_706ae88bd37410fa: function (offset, // @ts-ignore - index, + index, // @ts-ignore - decodeIndex, + decodeIndex, // @ts-ignore decodeOffset) { //let attr = get(index).getAttribute(decodeSub(decodeIndex, decodeOffset)); @@ -676,7 +676,7 @@ async function getSources(xrax) { let res = {}; try { await V(); - let getSourcesUrl = 'https://megacloud.tv/embed-2/v2/e-1/getSources?id=' + + let getSourcesUrl = 'https://megacloud.tv/embed-2/ajax/e-1/getSources?id=' + fake_window.pid + '&v=' + fake_window.localStorage.kversion + @@ -688,7 +688,7 @@ async function getSources(xrax) { headers: { 'User-Agent': user_agent, //"Referrer": fake_window.origin + "/v2/embed-4/" + xrax + "?z=", - Referer: embed_url + xrax + '?k=1&autoPlay=1&oa=0&asi=1', + Referer: embed_url + xrax + '?k=1', 'X-Requested-With': 'XMLHttpRequest', }, method: 'GET', @@ -711,4 +711,4 @@ async function getSources(xrax) { catch (err) { console.error(err); } -} \ No newline at end of file +} diff --git a/lib/megacloud-extractor/src/main/java/eu/kanade/tachiyomi/lib/megacloudextractor/MegaCloudExtractor.kt b/lib/megacloud-extractor/src/main/java/eu/kanade/tachiyomi/lib/megacloudextractor/MegaCloudExtractor.kt index 2494ccef..6b4d2fcf 100644 --- a/lib/megacloud-extractor/src/main/java/eu/kanade/tachiyomi/lib/megacloudextractor/MegaCloudExtractor.kt +++ b/lib/megacloud-extractor/src/main/java/eu/kanade/tachiyomi/lib/megacloudextractor/MegaCloudExtractor.kt @@ -1,8 +1,6 @@ package eu.kanade.tachiyomi.lib.megacloudextractor import android.content.SharedPreferences -import android.util.Base64 -import android.util.Log import eu.kanade.tachiyomi.animesource.model.Track import eu.kanade.tachiyomi.animesource.model.Video import eu.kanade.tachiyomi.lib.cryptoaes.CryptoAES @@ -22,10 +20,6 @@ import okhttp3.Headers import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.OkHttpClient import uy.kohesive.injekt.injectLazy -import java.security.MessageDigest -import javax.crypto.Cipher -import javax.crypto.spec.IvParameterSpec -import javax.crypto.spec.SecretKeySpec class MegaCloudExtractor( private val client: OkHttpClient, @@ -44,16 +38,16 @@ class MegaCloudExtractor( companion object { private val SERVER_URL = arrayOf("https://megacloud.tv", "https://rapid-cloud.co") - private val SOURCES_URL = arrayOf("/embed-2/v2/e-1/getSources?id=", "/ajax/embed-6-v2/getSources?id=") + private val SOURCES_URL = arrayOf("/embed-2/ajax/e-1/getSources?id=", "/ajax/embed-6-v2/getSources?id=") private val SOURCES_SPLITTER = arrayOf("/e-1/", "/embed-6-v2/") private val SOURCES_KEY = arrayOf("1", "6") - private const val E1_SCRIPT_URL = "/js/player/a/v2/pro/embed-1.min.js" - private const val E6_SCRIPT_URL = "/js/player/e6-player-v2.min.js" + private const val E1_SCRIPT_URL = "https://megacloud.tv/js/player/a/prod/e1-player.min.js" + private const val E6_SCRIPT_URL = "https://rapid-cloud.co/js/player/prod/e6-player-v2.min.js" private val MUTEX = Mutex() private var shouldUpdateKey = false private const val PREF_KEY_KEY = "megacloud_key_" private const val PREF_KEY_DEFAULT = "[[0, 0]]" - + private inline fun runLocked(crossinline block: () -> R) = runBlocking(Dispatchers.IO) { MUTEX.withLock { block() } } @@ -72,8 +66,8 @@ class MegaCloudExtractor( private fun updateKey(type: String) { val scriptUrl = when (type) { - "1" -> "${SERVER_URL[0]}$E1_SCRIPT_URL" - "6" -> "${SERVER_URL[1]}$E6_SCRIPT_URL" + "1" -> E1_SCRIPT_URL + "6" -> E6_SCRIPT_URL else -> throw Exception("Unknown key type") } val script = noCacheClient.newCall(GET(scriptUrl, cache = cacheControl)) @@ -148,21 +142,16 @@ class MegaCloudExtractor( } private fun getVideoDto(url: String): VideoDto { - val type = if ( - url.startsWith("https://megacloud.tv") || - url.startsWith("https://megacloud.blog") - ) 0 else 1 + val type = if (url.startsWith("https://megacloud.tv") or url.startsWith("https://megacloud.blog")) 0 else 1 val keyType = SOURCES_KEY[type] val id = url.substringAfter(SOURCES_SPLITTER[type], "") - .substringBefore("?", "") - .ifEmpty { throw Exception("Failed to extract ID from URL") } + .substringBefore("?", "").ifEmpty { throw Exception("I HATE THE ANTICHRIST") } - // Previous method using WebViewResolver to get key - // if (type == 0) { - // return webViewResolver.getSources(id)!! - // } + if (type == 0) { + return webViewResolver.getSources(id)!! + } val srcRes = client.newCall(GET(SERVER_URL[type] + SOURCES_URL[type] + id)) .execute() @@ -173,82 +162,11 @@ class MegaCloudExtractor( if (!data.encrypted) return json.decodeFromString(srcRes) val ciphered = data.sources.jsonPrimitive.content - val decrypted = json.decodeFromString>( - // tryDecrypting(ciphered, keyType), - tryDecrypting(ciphered), - ) + val decrypted = json.decodeFromString>(tryDecrypting(ciphered, keyType)) return VideoDto(decrypted, data.tracks) } - var megaKey: String? = null - - private fun tryDecrypting(ciphered: String): String { - return megaKey?.let { key -> - try { - decryptOpenSSL(ciphered, key).also { - Log.i("MegaCloudExtractor", "Decrypted URL: $it") - } - } catch (e: RuntimeException) { - Log.e("MegaCloudExtractor", "Decryption failed with existing key: ${e.message}") - decryptWithNewKey(ciphered) - } - } ?: decryptWithNewKey(ciphered) - } - - private fun decryptWithNewKey(ciphered: String): String { - val newKey = requestNewKey() - megaKey = newKey - return decryptOpenSSL(ciphered, newKey).also { - Log.i("MegaCloudExtractor", "Decrypted URL with new key: $it") - } - } - - private fun requestNewKey(): String = - client.newCall(GET("https://raw.githubusercontent.com/yogesh-hacker/MegacloudKeys/refs/heads/main/keys.json")) - .execute() - .use { response -> - if (!response.isSuccessful) throw IllegalStateException("Failed to fetch keys.json") - val jsonStr = response.body.string() - if (jsonStr.isEmpty()) throw IllegalStateException("keys.json is empty") - val key = json.decodeFromString>(jsonStr)["mega"] - ?: throw IllegalStateException("Mega key not found in keys.json") - Log.i("MegaCloudExtractor", "Using Mega Key: $key") - megaKey = key - key - } - - private fun decryptOpenSSL(encBase64: String, password: String): String { - try { - val data = Base64.decode(encBase64, Base64.NO_WRAP) // Base64.DEFAULT or Base64.NO_WRAP - require(data.copyOfRange(0, 8).contentEquals("Salted__".toByteArray())) - val salt = data.copyOfRange(8, 16) - val (key, iv) = opensslKeyIv(password.toByteArray(), salt) - - val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") - val secretKey = SecretKeySpec(key, "AES") - val ivSpec = IvParameterSpec(iv) - cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec) - - val decrypted = cipher.doFinal(data.copyOfRange(16, data.size)) - return String(decrypted) - } catch (e: Exception) { - Log.e("DecryptOpenSSL", "Decryption failed: ${e.message}") - throw RuntimeException("Decryption failed: ${e.message}", e) - } - } - - private fun opensslKeyIv(password: ByteArray, salt: ByteArray, keyLen: Int = 32, ivLen: Int = 16): Pair { - var d = ByteArray(0) - var d_i = ByteArray(0) - while (d.size < keyLen + ivLen) { - val md = MessageDigest.getInstance("MD5") - d_i = md.digest(d_i + password + salt) - d += d_i - } - return Pair(d.copyOfRange(0, keyLen), d.copyOfRange(keyLen, keyLen + ivLen)) - } - @Serializable data class VideoDto( val sources: List, @@ -267,4 +185,4 @@ class MegaCloudExtractor( @Serializable data class TrackDto(val file: String, val kind: String, val label: String = "") -} \ No newline at end of file +}