From bdb7cf8c5de3716539071e505cc1758bedb3bc0a Mon Sep 17 00:00:00 2001 From: Sofie99 Date: Fri, 4 Aug 2023 20:42:49 +0700 Subject: [PATCH] Extractor: added Rabbitstream --- .../cloudstream3/extractors/Megacloud.kt | 167 ------------------ 1 file changed, 167 deletions(-) delete mode 100644 app/src/main/java/com/lagradost/cloudstream3/extractors/Megacloud.kt diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Megacloud.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Megacloud.kt deleted file mode 100644 index d1a19f3c..00000000 --- a/app/src/main/java/com/lagradost/cloudstream3/extractors/Megacloud.kt +++ /dev/null @@ -1,167 +0,0 @@ -package com.lagradost.cloudstream3.extractors - -import com.fasterxml.jackson.annotation.JsonProperty -import com.lagradost.cloudstream3.SubtitleFile -import com.lagradost.cloudstream3.app -import com.lagradost.cloudstream3.base64DecodeArray -import com.lagradost.cloudstream3.utils.AppUtils -import com.lagradost.cloudstream3.utils.AppUtils.parseJson -import com.lagradost.cloudstream3.utils.ExtractorApi -import com.lagradost.cloudstream3.utils.ExtractorLink -import com.lagradost.cloudstream3.utils.M3u8Helper -import java.nio.charset.StandardCharsets -import java.security.MessageDigest -import java.util.Objects -import javax.crypto.Cipher -import javax.crypto.spec.IvParameterSpec -import javax.crypto.spec.SecretKeySpec - -class Megacloud : Rabbitstream() { - override val name = "Megacloud" - override val mainUrl = "https://megacloud.tv" - override val embed = "embed-2/ajax/e-1" - override val key = "https://raw.githubusercontent.com/enimax-anime/key/e6/key.txt" -} - -class Dokicloud : Rabbitstream() { - override val name = "Dokicloud" - override val mainUrl = "https://dokicloud.one" -} - -open class Rabbitstream : ExtractorApi() { - override val name = "Rabbitstream" - override val mainUrl = "https://rabbitstream.net" - override val requiresReferer = false - open val embed = "ajax/embed-4" - open val key = "https://raw.githubusercontent.com/enimax-anime/key/e4/key.txt" - - override suspend fun getUrl( - url: String, - referer: String?, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { - val id = url.substringAfterLast("/").substringBefore("?") - val rawKey = app.get(key).text - val response = app.get( - "$mainUrl/$embed/getSources?id=$id", - referer = mainUrl, - headers = mapOf("X-Requested-With" to "XMLHttpRequest") - ) - val encryptedMap = response.parsedSafe() - val sources = encryptedMap?.sources - val decryptedSources = if (sources == null || encryptedMap.encrypted == false) { - response.parsedSafe() - } else { - val (key, encData) = extractRealKey(sources, rawKey) - val decrypted = decryptMapped>(encData, key) - SourcesResponses( - sources = decrypted, - tracks = encryptedMap.tracks - ) - } - - decryptedSources?.sources?.map { source -> - M3u8Helper.generateM3u8( - name, - source?.file ?: return@map, - "$mainUrl/", - ).forEach(callback) - } - - decryptedSources?.tracks?.map { track -> - subtitleCallback.invoke( - SubtitleFile( - track?.label ?: "", - track?.file ?: return@map - ) - ) - } - - } - - private fun extractRealKey(originalString: String?, stops: String): Pair { - val table = parseJson>>(stops) - val decryptedKey = StringBuilder() - var offset = 0 - var encryptedString = originalString - - table.forEach { (start, end) -> - decryptedKey.append(encryptedString?.substring(start - offset, end - offset)) - encryptedString = encryptedString?.substring( - 0, - start - offset - ) + encryptedString?.substring(end - offset) - offset += end - start - } - return decryptedKey.toString() to encryptedString.toString() - } - - private inline fun decryptMapped(input: String, key: String): T? { - val decrypt = decrypt(input, key) - return AppUtils.tryParseJson(decrypt) - } - - private fun decrypt(input: String, key: String): String { - return decryptSourceUrl( - generateKey( - base64DecodeArray(input).copyOfRange(8, 16), - key.toByteArray() - ), input - ) - } - - private fun generateKey(salt: ByteArray, secret: ByteArray): ByteArray { - var key = md5(secret + salt) - var currentKey = key - while (currentKey.size < 48) { - key = md5(key + secret + salt) - currentKey += key - } - return currentKey - } - - private fun md5(input: ByteArray): ByteArray { - return MessageDigest.getInstance("MD5").digest(input) - } - - private fun decryptSourceUrl(decryptionKey: ByteArray, sourceUrl: String): String { - val cipherData = base64DecodeArray(sourceUrl) - val encrypted = cipherData.copyOfRange(16, cipherData.size) - val aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding") - - Objects.requireNonNull(aesCBC).init( - Cipher.DECRYPT_MODE, SecretKeySpec( - decryptionKey.copyOfRange(0, 32), - "AES" - ), - IvParameterSpec(decryptionKey.copyOfRange(32, decryptionKey.size)) - ) - val decryptedData = aesCBC!!.doFinal(encrypted) - return String(decryptedData, StandardCharsets.UTF_8) - } - - data class Tracks( - @JsonProperty("file") val file: String? = null, - @JsonProperty("label") val label: String? = null, - @JsonProperty("kind") val kind: String? = null, - ) - - data class Sources( - @JsonProperty("file") val file: String? = null, - @JsonProperty("type") val type: String? = null, - @JsonProperty("label") val label: String? = null, - ) - - data class SourcesResponses( - @JsonProperty("sources") val sources: List? = emptyList(), - @JsonProperty("tracks") val tracks: List? = emptyList(), - ) - - data class SourcesEncrypted( - @JsonProperty("sources") val sources: String? = null, - @JsonProperty("encrypted") val encrypted: Boolean? = null, - @JsonProperty("tracks") val tracks: List? = emptyList(), - ) - -} \ No newline at end of file