forked from recloudstream/cloudstream
		
	Merge remote-tracking branch 'origin/master'
This commit is contained in:
		
						commit
						d38f36e617
					
				
					 4 changed files with 201 additions and 1 deletions
				
			
		|  | @ -7,6 +7,10 @@ import com.lagradost.cloudstream3.utils.Qualities | ||||||
| import com.lagradost.cloudstream3.utils.getQualityFromName | import com.lagradost.cloudstream3.utils.getQualityFromName | ||||||
| import kotlinx.coroutines.delay | import kotlinx.coroutines.delay | ||||||
| 
 | 
 | ||||||
|  | class DoodWfExtractor : DoodLaExtractor() { | ||||||
|  |     override var mainUrl = "https://dood.wf" | ||||||
|  | } | ||||||
|  | 
 | ||||||
| class DoodCxExtractor : DoodLaExtractor() { | class DoodCxExtractor : DoodLaExtractor() { | ||||||
|     override var mainUrl = "https://dood.cx" |     override var mainUrl = "https://dood.cx" | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,178 @@ | ||||||
|  | package com.lagradost.cloudstream3.extractors | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.annotation.JsonProperty | ||||||
|  | import com.lagradost.cloudstream3.* | ||||||
|  | import com.lagradost.cloudstream3.utils.* | ||||||
|  | import org.jsoup.nodes.Element | ||||||
|  | import java.security.DigestException | ||||||
|  | import java.security.MessageDigest | ||||||
|  | import javax.crypto.Cipher | ||||||
|  | import javax.crypto.spec.IvParameterSpec | ||||||
|  | import javax.crypto.spec.SecretKeySpec | ||||||
|  | 
 | ||||||
|  | class Gdriveplayerapi: Gdriveplayer() { | ||||||
|  |     override val mainUrl: String = "https://gdriveplayerapi.com" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class Gdriveplayerapp: Gdriveplayer() { | ||||||
|  |     override val mainUrl: String = "https://gdriveplayer.app" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class Gdriveplayerfun: Gdriveplayer() { | ||||||
|  |     override val mainUrl: String = "https://gdriveplayer.fun" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class Gdriveplayerio: Gdriveplayer() { | ||||||
|  |     override val mainUrl: String = "https://gdriveplayer.io" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class Gdriveplayerme: Gdriveplayer() { | ||||||
|  |     override val mainUrl: String = "https://gdriveplayer.me" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class Gdriveplayerbiz: Gdriveplayer() { | ||||||
|  |     override val mainUrl: String = "https://gdriveplayer.biz" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class Gdriveplayerorg: Gdriveplayer() { | ||||||
|  |     override val mainUrl: String = "https://gdriveplayer.org" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class Gdriveplayerus: Gdriveplayer() { | ||||||
|  |     override val mainUrl: String = "https://gdriveplayer.us" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class Gdriveplayerco: Gdriveplayer() { | ||||||
|  |     override val mainUrl: String = "https://gdriveplayer.co" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | open class Gdriveplayer : ExtractorApi() { | ||||||
|  |     override val name = "Gdrive" | ||||||
|  |     override val mainUrl = "https://gdriveplayer.to" | ||||||
|  |     override val requiresReferer = false | ||||||
|  | 
 | ||||||
|  |     private fun unpackJs(script: Element): String? { | ||||||
|  |         return script.select("script").find { it.data().contains("eval(function(p,a,c,k,e,d)") } | ||||||
|  |             ?.data()?.let { getAndUnpack(it) } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun String.decodeHex(): ByteArray { | ||||||
|  |         check(length % 2 == 0) { "Must have an even length" } | ||||||
|  |         return chunked(2) | ||||||
|  |             .map { it.toInt(16).toByte() } | ||||||
|  |             .toByteArray() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // https://stackoverflow.com/a/41434590/8166854 | ||||||
|  |     private fun GenerateKeyAndIv( | ||||||
|  |         password: ByteArray, | ||||||
|  |         salt: ByteArray, | ||||||
|  |         hashAlgorithm: String = "MD5", | ||||||
|  |         keyLength: Int = 32, | ||||||
|  |         ivLength: Int = 16, | ||||||
|  |         iterations: Int = 1 | ||||||
|  |     ): List<ByteArray>? { | ||||||
|  | 
 | ||||||
|  |         val md = MessageDigest.getInstance(hashAlgorithm) | ||||||
|  |         val digestLength = md.digestLength | ||||||
|  |         val targetKeySize = keyLength + ivLength | ||||||
|  |         val requiredLength = (targetKeySize + digestLength - 1) / digestLength * digestLength | ||||||
|  |         val generatedData = ByteArray(requiredLength) | ||||||
|  |         var generatedLength = 0 | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             md.reset() | ||||||
|  | 
 | ||||||
|  |             while (generatedLength < targetKeySize) { | ||||||
|  |                 if (generatedLength > 0) | ||||||
|  |                     md.update( | ||||||
|  |                         generatedData, | ||||||
|  |                         generatedLength - digestLength, | ||||||
|  |                         digestLength | ||||||
|  |                     ) | ||||||
|  | 
 | ||||||
|  |                 md.update(password) | ||||||
|  |                 md.update(salt, 0, 8) | ||||||
|  |                 md.digest(generatedData, generatedLength, digestLength) | ||||||
|  | 
 | ||||||
|  |                 for (i in 1 until iterations) { | ||||||
|  |                     md.update(generatedData, generatedLength, digestLength) | ||||||
|  |                     md.digest(generatedData, generatedLength, digestLength) | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 generatedLength += digestLength | ||||||
|  |             } | ||||||
|  |             return listOf( | ||||||
|  |                 generatedData.copyOfRange(0, keyLength), | ||||||
|  |                 generatedData.copyOfRange(keyLength, targetKeySize) | ||||||
|  |             ) | ||||||
|  |         } catch (e: DigestException) { | ||||||
|  |             return null | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun cryptoAESHandler( | ||||||
|  |         data: AesData, | ||||||
|  |         pass: ByteArray, | ||||||
|  |         encrypt: Boolean = true | ||||||
|  |     ): String? { | ||||||
|  |         val (key, iv) = GenerateKeyAndIv(pass, data.s.decodeHex()) ?: return null | ||||||
|  |         val cipher = Cipher.getInstance("AES/CBC/NoPadding") | ||||||
|  |         return if (!encrypt) { | ||||||
|  |             cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv)) | ||||||
|  |             String(cipher.doFinal(base64DecodeArray(data.ct))) | ||||||
|  |         } else { | ||||||
|  |             cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv)) | ||||||
|  |             base64Encode(cipher.doFinal(data.ct.toByteArray())) | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun Regex.first(str: String): String? { | ||||||
|  |         return find(str)?.groupValues?.getOrNull(1) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override suspend fun getUrl( | ||||||
|  |         url: String, | ||||||
|  |         referer: String?, | ||||||
|  |         subtitleCallback: (SubtitleFile) -> Unit, | ||||||
|  |         callback: (ExtractorLink) -> Unit | ||||||
|  |     ) { | ||||||
|  |         val document = app.get(url).document | ||||||
|  | 
 | ||||||
|  |         val eval = unpackJs(document)?.replace("\\", "") ?: return | ||||||
|  |         val data = AppUtils.tryParseJson<AesData>(Regex("data='(\\S+?)'").first(eval)) ?: return | ||||||
|  |         val password = Regex("null,['|\"](\\w+)['|\"]").first(eval) | ||||||
|  |             ?.split(Regex("\\D+")) | ||||||
|  |             ?.joinToString("") { | ||||||
|  |                 Char(it.toInt()).toString() | ||||||
|  |             }.let { Regex("var pass = \"(\\S+?)\"").first(it ?: return)?.toByteArray() } | ||||||
|  |             ?: throw ErrorLoadingException("can't find password") | ||||||
|  |         val decryptedData = | ||||||
|  |             cryptoAESHandler(data, password, false)?.let { getAndUnpack(it) }?.replace("\\", "") | ||||||
|  |                 ?.substringAfter("sources:[")?.substringBefore("],") | ||||||
|  | 
 | ||||||
|  |         Regex("\"file\":\"(\\S+?)\".*?res=(\\d+)").findAll(decryptedData ?: return).map { | ||||||
|  |             it.groupValues[1] to it.groupValues[2] | ||||||
|  |         }.toList().distinctBy { it.second }.map { (link, quality) -> | ||||||
|  |             callback.invoke( | ||||||
|  |                 ExtractorLink( | ||||||
|  |                     source = this.name, | ||||||
|  |                     name = this.name, | ||||||
|  |                     url = "${httpsify(link)}&res=$quality", | ||||||
|  |                     referer = mainUrl, | ||||||
|  |                     quality = quality.toIntOrNull() ?: Qualities.Unknown.value, | ||||||
|  |                     headers = mapOf("Range" to "bytes=0-") | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     data class AesData( | ||||||
|  |         @JsonProperty("ct") val ct: String, | ||||||
|  |         @JsonProperty("iv") val iv: String, | ||||||
|  |         @JsonProperty("s") val s: String | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -7,6 +7,11 @@ import com.lagradost.cloudstream3.utils.ExtractorApi | ||||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
| import com.lagradost.cloudstream3.utils.M3u8Helper | import com.lagradost.cloudstream3.utils.M3u8Helper | ||||||
| 
 | 
 | ||||||
|  | class Sbflix : StreamSB() { | ||||||
|  |     override var mainUrl = "https://sbflix.xyz" | ||||||
|  |     override var name = "Sbflix" | ||||||
|  | } | ||||||
|  | 
 | ||||||
| class Vidgomunime : StreamSB() { | class Vidgomunime : StreamSB() { | ||||||
|     override var mainUrl = "https://vidgomunime.xyz" |     override var mainUrl = "https://vidgomunime.xyz" | ||||||
| } | } | ||||||
|  | @ -111,7 +116,7 @@ open class StreamSB : ExtractorApi() { | ||||||
|         }.first() |         }.first() | ||||||
|         val bytes = id.toByteArray() |         val bytes = id.toByteArray() | ||||||
|         val bytesToHex = bytesToHex(bytes) |         val bytesToHex = bytesToHex(bytes) | ||||||
|         val master = "$mainUrl/sources43/6d6144797752744a454267617c7c${bytesToHex.lowercase()}7c7c4e61755a56456f34385243727c7c73747265616d7362/6b4a33767968506e4e71374f7c7c343837323439333133333462353935333633373836643638376337633462333634663539343137373761333635313533333835333763376333393636363133393635366136323733343435323332376137633763373337343732363536313664373336327c7c504d754478413835306633797c7c73747265616d7362" |         val master = "$mainUrl/sources44/6d6144797752744a454267617c7c${bytesToHex.lowercase()}7c7c4e61755a56456f34385243727c7c73747265616d7362/6b4a33767968506e4e71374f7c7c343837323439333133333462353935333633373836643638376337633462333634663539343137373761333635313533333835333763376333393636363133393635366136323733343435323332376137633763373337343732363536313664373336327c7c504d754478413835306633797c7c73747265616d7362" | ||||||
|         val headers = mapOf( |         val headers = mapOf( | ||||||
|             "watchsb" to "streamsb", |             "watchsb" to "streamsb", | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|  | @ -236,6 +236,7 @@ val extractorApis: MutableList<ExtractorApi> = arrayListOf( | ||||||
|     Ssbstream(), |     Ssbstream(), | ||||||
|     Sbthe(), |     Sbthe(), | ||||||
|     Vidgomunime(), |     Vidgomunime(), | ||||||
|  |     Sbflix(), | ||||||
| 
 | 
 | ||||||
|     Fastream(), |     Fastream(), | ||||||
| 
 | 
 | ||||||
|  | @ -269,6 +270,7 @@ val extractorApis: MutableList<ExtractorApi> = arrayListOf( | ||||||
|     DoodWsExtractor(), |     DoodWsExtractor(), | ||||||
|     DoodShExtractor(), |     DoodShExtractor(), | ||||||
|     DoodWatchExtractor(), |     DoodWatchExtractor(), | ||||||
|  |     DoodWfExtractor(), | ||||||
| 
 | 
 | ||||||
|     AsianLoad(), |     AsianLoad(), | ||||||
| 
 | 
 | ||||||
|  | @ -321,6 +323,17 @@ val extractorApis: MutableList<ExtractorApi> = arrayListOf( | ||||||
|     Mvidoo(), |     Mvidoo(), | ||||||
|     Streamplay(), |     Streamplay(), | ||||||
| 
 | 
 | ||||||
|  |     Gdriveplayerapi(), | ||||||
|  |     Gdriveplayerapp(), | ||||||
|  |     Gdriveplayerfun(), | ||||||
|  |     Gdriveplayerio(), | ||||||
|  |     Gdriveplayerme(), | ||||||
|  |     Gdriveplayerbiz(), | ||||||
|  |     Gdriveplayerorg(), | ||||||
|  |     Gdriveplayerus(), | ||||||
|  |     Gdriveplayerco(), | ||||||
|  |     Gdriveplayer(), | ||||||
|  | 
 | ||||||
|     YoutubeExtractor(), |     YoutubeExtractor(), | ||||||
|     YoutubeShortLinkExtractor(), |     YoutubeShortLinkExtractor(), | ||||||
|     YoutubeMobileExtractor(), |     YoutubeMobileExtractor(), | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue