diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index be1b0e82..456bfceb 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -706,17 +706,5 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { // } // } -/* - - val relativePath = (Environment.DIRECTORY_DOWNLOADS) + File.separatorChar - val displayName = "output.dex" //""output.dex" - val file = getExternalFilesDir(null)?.absolutePath + File.separatorChar + displayName//"${Environment.getExternalStorageDirectory()}${File.separatorChar}$relativePath$displayName" - println(file) - - val realFile = File(file) - println("REAALFILE: ${realFile.exists()} at ${realFile.length()}" ) - val src = ExtensionManager.getSourceFromDex(this, "com.example.testdex2.TestClassToDex", File(file)) - val output = src?.doMath() - println("MASTER OUTPUT = $output")*/ } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Acefile.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Acefile.kt new file mode 100644 index 00000000..fe46791b --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Acefile.kt @@ -0,0 +1,40 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.base64Decode +import com.lagradost.cloudstream3.utils.* + +class Acefile : ExtractorApi() { + override val name = "Acefile" + override val mainUrl = "https://acefile.co" + override val requiresReferer = false + + override suspend fun getUrl(url: String, referer: String?): List { + val sources = mutableListOf() + app.get(url).document.select("script").map { script -> + if (script.data().contains("eval(function(p,a,c,k,e,d)")) { + val data = getAndUnpack(script.data()) + val id = data.substringAfter("{\"id\":\"").substringBefore("\",") + val key = data.substringAfter("var nfck=\"").substringBefore("\";") + app.get("https://acefile.co/local/$id?key=$key").text.let { + base64Decode( + it.substringAfter("JSON.parse(atob(\"").substringBefore("\"))") + ).let { res -> + sources.add( + ExtractorLink( + name, + name, + res.substringAfter("\"file\":\"").substringBefore("\","), + "$mainUrl/", + Qualities.Unknown.value, + headers = mapOf("range" to "bytes=0-") + ) + ) + } + } + } + } + return sources + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/AsianLoad.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/AsianLoad.kt new file mode 100644 index 00000000..cf16f200 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/AsianLoad.kt @@ -0,0 +1,46 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper +import com.lagradost.cloudstream3.utils.getQualityFromName +import java.net.URI + +class AsianLoad : ExtractorApi() { + override var name = "AsianLoad" + override var mainUrl = "https://asianembed.io" + override val requiresReferer = true + + private val sourceRegex = Regex("""sources:[\W\w]*?file:\s*?["'](.*?)["']""") + override suspend fun getUrl(url: String, referer: String?): List { + val extractedLinksList: MutableList = mutableListOf() + with(app.get(url, referer = referer)) { + sourceRegex.findAll(this.text).forEach { sourceMatch -> + val extractedUrl = sourceMatch.groupValues[1] + // Trusting this isn't mp4, may fuck up stuff + if (URI(extractedUrl).path.endsWith(".m3u8")) { + M3u8Helper.generateM3u8( + name, + extractedUrl, + url, + headers = mapOf("referer" to this.url) + ).forEach { link -> + extractedLinksList.add(link) + } + } else if (extractedUrl.endsWith(".mp4")) { + extractedLinksList.add( + ExtractorLink( + name, + name, + extractedUrl, + url.replace(" ", "%20"), + getQualityFromName(sourceMatch.groupValues[2]), + ) + ) + } + } + return extractedLinksList + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Blogger.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Blogger.kt new file mode 100644 index 00000000..cae77322 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Blogger.kt @@ -0,0 +1,45 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.* +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson + +class Blogger : ExtractorApi() { + override val name = "Blogger" + override val mainUrl = "https://www.blogger.com" + override val requiresReferer = false + + override suspend fun getUrl(url: String, referer: String?): List { + val sources = mutableListOf() + with(app.get(url).document) { + this.select("script").map { script -> + if (script.data().contains("\"streams\":[")) { + val data = script.data().substringAfter("\"streams\":[") + .substringBefore("]") + tryParseJson>("[$data]")?.map { + sources.add( + ExtractorLink( + name, + name, + it.play_url, + referer = "https://www.youtube.com/", + quality = when (it.format_id) { + 18 -> 360 + 22 -> 720 + else -> Qualities.Unknown.value + } + ) + ) + } + } + } + } + return sources + } + + private data class ResponseSource( + @JsonProperty("play_url") val play_url: String, + @JsonProperty("format_id") val format_id: Int + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/BullStream.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/BullStream.kt new file mode 100644 index 00000000..d4f87f4c --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/BullStream.kt @@ -0,0 +1,29 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper + +class BullStream : ExtractorApi() { + override val name = "BullStream" + override val mainUrl = "https://bullstream.xyz" + override val requiresReferer = false + val regex = Regex("(?<=sniff\\()(.*)(?=\\)\\);)") + + override suspend fun getUrl(url: String, referer: String?): List? { + val data = regex.find(app.get(url).text)?.value + ?.replace("\"", "") + ?.split(",") + ?: return null + + val m3u8 = "$mainUrl/m3u8/${data[1]}/${data[2]}/master.txt?s=1&cache=${data[4]}" + println("shiv : $m3u8") + return M3u8Helper.generateM3u8( + name, + m3u8, + url, + headers = mapOf("referer" to url, "accept" to "*/*") + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/DoodExtractor.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/DoodExtractor.kt new file mode 100644 index 00000000..c5eaf40e --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/DoodExtractor.kt @@ -0,0 +1,64 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities +import com.lagradost.cloudstream3.utils.getQualityFromName +import kotlinx.coroutines.delay + +class DoodCxExtractor : DoodLaExtractor() { + override var mainUrl = "https://dood.cx" +} + +class DoodShExtractor : DoodLaExtractor() { + override var mainUrl = "https://dood.sh" +} +class DoodWatchExtractor : DoodLaExtractor() { + override var mainUrl = "https://dood.watch" +} + +class DoodPmExtractor : DoodLaExtractor() { + override var mainUrl = "https://dood.pm" +} + +class DoodToExtractor : DoodLaExtractor() { + override var mainUrl = "https://dood.to" +} + +class DoodSoExtractor : DoodLaExtractor() { + override var mainUrl = "https://dood.so" +} + +class DoodWsExtractor : DoodLaExtractor() { + override var mainUrl = "https://dood.ws" +} + + +open class DoodLaExtractor : ExtractorApi() { + override var name = "DoodStream" + override var mainUrl = "https://dood.la" + override val requiresReferer = false + + override fun getExtractorUrl(id: String): String { + return "$mainUrl/d/$id" + } + + override suspend fun getUrl(url: String, referer: String?): List? { + val response0 = app.get(url).text // html of DoodStream page to look for /pass_md5/... + val md5 =mainUrl+(Regex("/pass_md5/[^']*").find(response0)?.value ?: return null) // get https://dood.ws/pass_md5/... + val trueUrl = app.get(md5, referer = url).text + "zUEJeL3mUN?token=" + md5.substringAfterLast("/") //direct link to extract (zUEJeL3mUN is random) + val quality = Regex("\\d{3,4}p").find(response0.substringAfter("").substringBefore(""))?.groupValues?.get(0) + return listOf( + ExtractorLink( + trueUrl, + this.name, + trueUrl, + mainUrl, + getQualityFromName(quality), + false + ) + ) // links are valid in 8h + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Evolaod.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Evolaod.kt new file mode 100644 index 00000000..4a9f2f52 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Evolaod.kt @@ -0,0 +1,54 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.utils.* +import com.lagradost.cloudstream3.app + +class Evoload1 : Evoload() { + override var mainUrl = "https://evoload.io" +} + +open class Evoload : ExtractorApi() { + override val name: String = "Evoload" + override val mainUrl: String = "https://www.evoload.io" + //private val srcRegex = Regex("""video .*src="(.*)""""") // would be possible to use the parse and find src attribute + override val requiresReferer = true + + + + override suspend fun getUrl(url: String, referer: String?): List { + val lang = url.substring(0, 2) + val flag = + if (lang == "vo") { + " \uD83C\uDDEC\uD83C\uDDE7" + } + else if (lang == "vf"){ + " \uD83C\uDDE8\uD83C\uDDF5" + } else { + "" + } + + val cleaned_url = if (lang == "ht") { // if url doesn't contain a flag and the url starts with http:// + url + } else { + url.substring(2, url.length) + } + //println(lang) + //println(cleaned_url) + + val id = cleaned_url.replace("https://evoload.io/e/", "") // wanted media id + val csrv_token = app.get("https://csrv.evosrv.com/captcha?m412548=").text // whatever that is + val captchaPass = app.get("https://cd2.evosrv.com/html/jsx/e.jsx").text.take(300).split("captcha_pass = '")[1].split("\'")[0] //extract the captcha pass from the js response (located in the 300 first chars) + val payload = mapOf("code" to id, "csrv_token" to csrv_token, "pass" to captchaPass) + val r = app.post("https://evoload.io/SecurePlayer", data=(payload)).text + val link = Regex("src\":\"(.*?)\"").find(r)?.destructured?.component1() ?: return listOf() + return listOf( + ExtractorLink( + name, + name + flag, + link, + cleaned_url, + Qualities.Unknown.value, + ) + ) + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Fastream.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Fastream.kt new file mode 100644 index 00000000..16b109be --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Fastream.kt @@ -0,0 +1,39 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.apmap +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8 + +class Fastream: ExtractorApi() { + override var mainUrl = "https://fastream.to" + override var name = "Fastream" + override val requiresReferer = false + + + override suspend fun getUrl(url: String, referer: String?): List? { + val id = Regex("emb\\.html\\?(.*)\\=(enc|)").find(url)?.destructured?.component1() ?: return emptyList() + val sources = mutableListOf() + val response = app.post("$mainUrl/dl", + data = mapOf( + Pair("op","embed"), + Pair("file_code",id), + Pair("auto","1") + )).document + response.select("script").apmap { script -> + if (script.data().contains("sources")) { + val m3u8regex = Regex("((https:|http:)\\/\\/.*\\.m3u8)") + val m3u8 = m3u8regex.find(script.data())?.value ?: return@apmap + generateM3u8( + name, + m3u8, + mainUrl + ).forEach { link -> + sources.add(link) + } + } + } + return sources + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Filesim.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Filesim.kt new file mode 100644 index 00000000..5c8af1c5 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Filesim.kt @@ -0,0 +1,38 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.* +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson + +class Filesim : ExtractorApi() { + override val name = "Filesim" + override val mainUrl = "https://files.im" + override val requiresReferer = false + + override suspend fun getUrl(url: String, referer: String?): List { + val sources = mutableListOf() + with(app.get(url).document) { + this.select("script").map { script -> + if (script.data().contains("eval(function(p,a,c,k,e,d)")) { + val data = getAndUnpack(script.data()).substringAfter("sources:[").substringBefore("]") + tryParseJson>("[$data]")?.map { + M3u8Helper.generateM3u8( + name, + it.file, + "$mainUrl/", + ).forEach { m3uData -> sources.add(m3uData) } + } + } + } + } + return sources + } + + private data class ResponseSource( + @JsonProperty("file") val file: String, + @JsonProperty("type") val type: String?, + @JsonProperty("label") val label: String? + ) + +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/GMPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/GMPlayer.kt new file mode 100644 index 00000000..e36a03d3 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/GMPlayer.kt @@ -0,0 +1,39 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper + +class GMPlayer : ExtractorApi() { + override val name = "GM Player" + override val mainUrl = "https://gmplayer.xyz" + override val requiresReferer = true + + override suspend fun getUrl(url: String, referer: String?): List? { + val ref = referer ?: return null + val id = url.substringAfter("/video/").substringBefore("/") + + val m3u8 = app.post( + "$mainUrl/player/index.php?data=$id&do=getVideo", + mapOf( + "accept" to "*/*", + "referer" to ref, + "x-requested-with" to "XMLHttpRequest", + "origin" to mainUrl + ), + data = mapOf("hash" to id, "r" to ref) + ).parsed().videoSource ?: return null + + return M3u8Helper.generateM3u8( + name, + m3u8, + ref, + headers = mapOf("accept" to "*/*") + ) + } + + private data class GmResponse( + val videoSource: String? = null + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/GenericM3U8.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/GenericM3U8.kt new file mode 100644 index 00000000..65cf1be4 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/GenericM3U8.kt @@ -0,0 +1,33 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.network.WebViewResolver +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper + + +open class GenericM3U8 : ExtractorApi() { + override var name = "Upstream" + override var mainUrl = "https://upstream.to" + override val requiresReferer = false + + override suspend fun getUrl(url: String, referer: String?): List { + val response = app.get( + url, interceptor = WebViewResolver( + Regex("""master\.m3u8""") + ) + ) + val sources = mutableListOf() + if (response.url.contains("m3u8")) + M3u8Helper.generateM3u8( + name, + response.url, + url, + headers = response.headers.toMap() + ).forEach { link -> + sources.add(link) + } + return sources + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/GuardareStream.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/GuardareStream.kt new file mode 100644 index 00000000..57435161 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/GuardareStream.kt @@ -0,0 +1,36 @@ +package com.lagradost.cloudstream3.extractors +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.* + +open class GuardareStream : ExtractorApi() { + override var name = "Guardare" + override var mainUrl = "https://guardare.stream" + override val requiresReferer = false + + data class GuardareJsonData ( + @JsonProperty("data") val data : List, + ) + + data class GuardareData ( + @JsonProperty("file") val file : String, + @JsonProperty("label") val label : String, + @JsonProperty("type") val type : String + ) + + override suspend fun getUrl(url: String, referer: String?): List? { + val response = app.post(url.replace("/v/","/api/source/"), data = mapOf("d" to mainUrl)).text + val jsonvideodata = AppUtils.parseJson(response) + return jsonvideodata.data.map { + ExtractorLink( + it.file+".${it.type}", + this.name, + it.file+".${it.type}", + mainUrl, + it.label.filter{ it.isDigit() }.toInt(), + false + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Hxfile.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Hxfile.kt new file mode 100644 index 00000000..f5dde774 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Hxfile.kt @@ -0,0 +1,100 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.* +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson + +class Neonime7n : Hxfile() { + override val name = "Neonime7n" + override val mainUrl = "https://7njctn.neonime.watch" + override val redirect = false +} + +class Neonime8n : Hxfile() { + override val name = "Neonime8n" + override val mainUrl = "https://8njctn.neonime.net" + override val redirect = false +} + +class KotakAnimeid : Hxfile() { + override val name = "KotakAnimeid" + override val mainUrl = "https://kotakanimeid.com" + override val requiresReferer = true +} + +class Yufiles : Hxfile() { + override val name = "Yufiles" + override val mainUrl = "https://yufiles.com" +} + +class Aico : Hxfile() { + override val name = "Aico" + override val mainUrl = "https://aico.pw" +} + +open class Hxfile : ExtractorApi() { + override val name = "Hxfile" + override val mainUrl = "https://hxfile.co" + override val requiresReferer = false + open val redirect = true + + override suspend fun getUrl(url: String, referer: String?): List? { + val sources = mutableListOf() + val document = app.get(url, allowRedirects = redirect, referer = referer).document + with(document) { + this.select("script").map { script -> + if (script.data().contains("eval(function(p,a,c,k,e,d)")) { + val data = + getAndUnpack(script.data()).substringAfter("sources:[").substringBefore("]") + tryParseJson>("[$data]")?.map { + sources.add( + ExtractorLink( + name, + name, + it.file, + referer = mainUrl, + quality = when { + url.contains("hxfile.co") -> getQualityFromName( + Regex("\\d\\.(.*?).mp4").find( + document.select("title").text() + )?.groupValues?.get(1).toString() + ) + else -> getQualityFromName(it.label) + } + ) + ) + } + } else if (script.data().contains("\"sources\":[")) { + val data = script.data().substringAfter("\"sources\":[").substringBefore("]") + tryParseJson>("[$data]")?.map { + sources.add( + ExtractorLink( + name, + name, + it.file, + referer = mainUrl, + quality = when { + it.label?.contains("HD") == true -> Qualities.P720.value + it.label?.contains("SD") == true -> Qualities.P480.value + else -> getQualityFromName(it.label) + } + ) + ) + } + } + else { + null + } + } + } + return sources + } + + private data class ResponseSource( + @JsonProperty("file") val file: String, + @JsonProperty("type") val type: String?, + @JsonProperty("label") val label: String? + ) + +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/JWPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/JWPlayer.kt new file mode 100644 index 00000000..6e6f6516 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/JWPlayer.kt @@ -0,0 +1,81 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities +import com.lagradost.cloudstream3.utils.getQualityFromName + +class Meownime : JWPlayer() { + override val name = "Meownime" + override val mainUrl = "https://meownime.ltd" +} + +class DesuOdchan : JWPlayer() { + override val name = "DesuOdchan" + override val mainUrl = "https://desustream.me/odchan/" +} + +class DesuArcg : JWPlayer() { + override val name = "DesuArcg" + override val mainUrl = "https://desustream.me/arcg/" +} + +class DesuDrive : JWPlayer() { + override val name = "DesuDrive" + override val mainUrl = "https://desustream.me/desudrive/" +} + +class DesuOdvip : JWPlayer() { + override val name = "DesuOdvip" + override val mainUrl = "https://desustream.me/odvip/" +} + +open class JWPlayer : ExtractorApi() { + override val name = "JWPlayer" + override val mainUrl = "https://www.jwplayer.com" + override val requiresReferer = false + + override suspend fun getUrl(url: String, referer: String?): List? { + val sources = mutableListOf() + with(app.get(url).document) { + val data = this.select("script").mapNotNull { script -> + if (script.data().contains("sources: [")) { + script.data().substringAfter("sources: [") + .substringBefore("],").replace("'", "\"") + } else if (script.data().contains("otakudesu('")) { + script.data().substringAfter("otakudesu('") + .substringBefore("');") + } else { + null + } + } + + tryParseJson>("$data")?.map { + sources.add( + ExtractorLink( + name, + name, + it.file, + referer = url, + quality = getQualityFromName( + Regex("(\\d{3,4}p)").find(it.file)?.groupValues?.get( + 1 + ) + ) + ) + ) + } + } + return sources + } + + private data class ResponseSource( + @JsonProperty("file") val file: String, + @JsonProperty("type") val type: String?, + @JsonProperty("label") val label: String? + ) + +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Jawcloud.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Jawcloud.kt new file mode 100644 index 00000000..203a266c --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Jawcloud.kt @@ -0,0 +1,27 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper + + +open class Jawcloud : ExtractorApi() { + override var name = "Jawcloud" + override var mainUrl = "https://jawcloud.co" + override val requiresReferer = false + + override suspend fun getUrl(url: String, referer: String?): List? { + val doc = app.get(url).document + val urlString = doc.select("html body div source").attr("src") + val sources = mutableListOf() + if (urlString.contains("m3u8")) + M3u8Helper.generateM3u8( + name, + urlString, + url, + headers = app.get(url).headers.toMap() + ).forEach { link -> sources.add(link) } + return sources + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Linkbox.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Linkbox.kt new file mode 100644 index 00000000..52fc5532 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Linkbox.kt @@ -0,0 +1,46 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.getQualityFromName + +class Linkbox : ExtractorApi() { + override val name = "Linkbox" + override val mainUrl = "https://www.linkbox.to" + override val requiresReferer = true + + override suspend fun getUrl(url: String, referer: String?): List { + val id = url.substringAfter("id=") + val sources = mutableListOf() + + app.get("$mainUrl/api/open/get_url?itemId=$id", referer=url).parsedSafe()?.data?.rList?.map { link -> + sources.add( + ExtractorLink( + name, + name, + link.url, + url, + getQualityFromName(link.resolution) + ) + ) + } + + return sources + } + + data class RList( + @JsonProperty("url") val url: String, + @JsonProperty("resolution") val resolution: String?, + ) + + data class Data( + @JsonProperty("rList") val rList: List?, + ) + + data class Responses( + @JsonProperty("data") val data: Data?, + ) + +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/M3u8Manifest.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/M3u8Manifest.kt new file mode 100644 index 00000000..545dc309 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/M3u8Manifest.kt @@ -0,0 +1,16 @@ +package com.lagradost.cloudstream3.extractors + +//{"auto":"/manifests/movies/15559/1624728920/qDwu5BOsfAwfTmnnjmkmXA/master.m3u8","1080p":"https://vdoc3.sallenes.space/qDwu5BOsfAwfTmnnjmkmXA/1624728920/storage6/movies/the-man-with-the-iron-heart-2017/1080p/index.m3u8","720p":"https://vdoc3.sallenes.space/qDwu5BOsfAwfTmnnjmkmXA/1624728920/storage6/movies/the-man-with-the-iron-heart-2017/720p/index.m3u8","360p":"https://vdoc3.sallenes.space/qDwu5BOsfAwfTmnnjmkmXA/1624728920/storage6/movies/the-man-with-the-iron-heart-2017/360p/index.m3u8","480p":"https://vdoc3.sallenes.space/qDwu5BOsfAwfTmnnjmkmXA/1624728920/storage6/movies/the-man-with-the-iron-heart-2017/480p/index.m3u8"} +object M3u8Manifest { + // URL = first, QUALITY = second + fun extractLinks(m3u8Data: String): ArrayList> { + val data: ArrayList> = ArrayList() + Regex("\"(.*?)\":\"(.*?)\"").findAll(m3u8Data).forEach { + var quality = it.groupValues[1].replace("auto", "Auto") + if (quality != "Auto" && !quality.endsWith('p')) quality += "p" + val url = it.groupValues[2] + data.add(Pair(url, quality)) + } + return data + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Maxstream.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Maxstream.kt new file mode 100644 index 00000000..51b0827d --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Maxstream.kt @@ -0,0 +1,29 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.* + +open class Maxstream : ExtractorApi() { + override var name = "Maxstream" + override var mainUrl = "https://maxstream.video/" + override val requiresReferer = false + override suspend fun getUrl(url: String, referer: String?): List? { + val extractedLinksList: MutableList = mutableListOf() + val response = app.get(url).text + val jstounpack = Regex("cript\">eval((.|\\n)*?)").find(response)?.groups?.get(1)?.value + val unpacjed = JsUnpacker(jstounpack).unpack() + val extractedUrl = unpacjed?.let { Regex("""src:"((.|\n)*?)",type""").find(it) }?.groups?.get(1)?.value.toString() + + M3u8Helper.generateM3u8( + name, + extractedUrl, + url, + headers = mapOf("referer" to url) + ).forEach { link -> + extractedLinksList.add(link) + } + + return extractedLinksList + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Mcloud.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Mcloud.kt new file mode 100644 index 00000000..29d98557 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Mcloud.kt @@ -0,0 +1,7 @@ +package com.lagradost.cloudstream3.extractors + +open class Mcloud : WcoStream() { + override var name = "Mcloud" + override var mainUrl = "https://mcloud.to" + override val requiresReferer = true +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/MixDrop.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/MixDrop.kt new file mode 100644 index 00000000..cd7e2e26 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/MixDrop.kt @@ -0,0 +1,45 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.* + +class MixDropBz : MixDrop(){ + override var mainUrl = "https://mixdrop.bz" +} + +class MixDropCh : MixDrop(){ + override var mainUrl = "https://mixdrop.ch" +} +class MixDropTo : MixDrop(){ + override var mainUrl = "https://mixdrop.to" +} + +open class MixDrop : ExtractorApi() { + override var name = "MixDrop" + override var mainUrl = "https://mixdrop.co" + private val srcRegex = Regex("""wurl.*?=.*?"(.*?)";""") + override val requiresReferer = false + + override fun getExtractorUrl(id: String): String { + return "$mainUrl/e/$id" + } + + override suspend fun getUrl(url: String, referer: String?): List? { + with(app.get(url)) { + getAndUnpack(this.text).let { unpackedText -> + srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link -> + return listOf( + ExtractorLink( + name, + name, + httpsify(link), + url, + Qualities.Unknown.value, + ) + ) + } + } + } + return null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Mp4Upload.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Mp4Upload.kt new file mode 100644 index 00000000..68a4a103 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Mp4Upload.kt @@ -0,0 +1,34 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities +import com.lagradost.cloudstream3.utils.getAndUnpack + +class Mp4Upload : ExtractorApi() { + override var name = "Mp4Upload" + override var mainUrl = "https://www.mp4upload.com" + private val srcRegex = Regex("""player\.src\("(.*?)"""") + override val requiresReferer = true + + override suspend fun getUrl(url: String, referer: String?): List? { + with(app.get(url)) { + getAndUnpack(this.text).let { unpackedText -> + val quality = unpackedText.lowercase().substringAfter(" height=").substringBefore(" ").toIntOrNull() + srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link -> + return listOf( + ExtractorLink( + name, + name, + link, + url, + quality ?: Qualities.Unknown.value, + ) + ) + } + } + } + return null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/MultiQuality.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/MultiQuality.kt new file mode 100644 index 00000000..0c0b5c68 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/MultiQuality.kt @@ -0,0 +1,59 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities +import com.lagradost.cloudstream3.utils.getQualityFromName +import java.net.URI + +class MultiQuality : ExtractorApi() { + override var name = "MultiQuality" + override var mainUrl = "https://gogo-play.net" + private val sourceRegex = Regex("""file:\s*['"](.*?)['"],label:\s*['"](.*?)['"]""") + private val m3u8Regex = Regex(""".*?(\d*).m3u8""") + private val urlRegex = Regex("""(.*?)([^/]+$)""") + override val requiresReferer = false + + override fun getExtractorUrl(id: String): String { + return "$mainUrl/loadserver.php?id=$id" + } + + override suspend fun getUrl(url: String, referer: String?): List { + val extractedLinksList: MutableList = mutableListOf() + with(app.get(url)) { + sourceRegex.findAll(this.text).forEach { sourceMatch -> + val extractedUrl = sourceMatch.groupValues[1] + // Trusting this isn't mp4, may fuck up stuff + if (URI(extractedUrl).path.endsWith(".m3u8")) { + with(app.get(extractedUrl)) { + m3u8Regex.findAll(this.text).forEach { match -> + extractedLinksList.add( + ExtractorLink( + name, + name = name, + urlRegex.find(this.url)!!.groupValues[1] + match.groupValues[0], + url, + getQualityFromName(match.groupValues[1]), + isM3u8 = true + ) + ) + } + + } + } else if (extractedUrl.endsWith(".mp4")) { + extractedLinksList.add( + ExtractorLink( + name, + "$name ${sourceMatch.groupValues[2]}", + extractedUrl, + url.replace(" ", "%20"), + Qualities.Unknown.value, + ) + ) + } + } + return extractedLinksList + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/OkRuExtractor.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/OkRuExtractor.kt new file mode 100644 index 00000000..70e87fbf --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/OkRuExtractor.kt @@ -0,0 +1,67 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.utils.* +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.AppUtils.parseJson + +data class DataOptionsJson ( + @JsonProperty("flashvars") var flashvars : Flashvars? = Flashvars(), +) +data class Flashvars ( + @JsonProperty("metadata") var metadata : String? = null, + @JsonProperty("hlsManifestUrl") var hlsManifestUrl : String? = null, //m3u8 +) + +data class MetadataOkru ( + @JsonProperty("videos") var videos: ArrayList = arrayListOf(), +) + +data class Videos ( + @JsonProperty("name") var name : String, + @JsonProperty("url") var url : String, + @JsonProperty("seekSchema") var seekSchema : Int? = null, + @JsonProperty("disallowed") var disallowed : Boolean? = null +) + +class OkRuHttps: OkRu(){ + override var mainUrl = "https://ok.ru" +} + +open class OkRu : ExtractorApi() { + override var name = "Okru" + override var mainUrl = "http://ok.ru" + override val requiresReferer = false + + override suspend fun getUrl(url: String, referer: String?): List? { + val doc = app.get(url).document + val sources = ArrayList() + val datajson = doc.select("div[data-options]").attr("data-options") + if (datajson.isNotBlank()) { + val main = parseJson(datajson) + val metadatajson = parseJson(main.flashvars?.metadata!!) + val servers = metadatajson.videos + servers.forEach { + val quality = it.name.uppercase() + .replace("MOBILE","144p") + .replace("LOWEST","240p") + .replace("LOW","360p") + .replace("SD","480p") + .replace("HD","720p") + .replace("FULL","1080p") + .replace("QUAD","1440p") + .replace("ULTRA","4k") + val extractedurl = it.url.replace("\\\\u0026", "&") + sources.add(ExtractorLink( + name, + name = this.name, + extractedurl, + url, + getQualityFromName(quality), + isM3u8 = false + )) + } + } + return sources + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Pelisplus.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Pelisplus.kt new file mode 100644 index 00000000..cc743d5e --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Pelisplus.kt @@ -0,0 +1,99 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.apmap +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.extractorApis +import com.lagradost.cloudstream3.utils.getQualityFromName +import com.lagradost.cloudstream3.utils.loadExtractor +import org.jsoup.Jsoup + +/** + * overrideMainUrl is necessary for for other vidstream clones like vidembed.cc + * If they diverge it'd be better to make them separate. + * */ +class Pelisplus(val mainUrl: String) { + val name: String = "Vidstream" + + private fun getExtractorUrl(id: String): String { + return "$mainUrl/play?id=$id" + } + + private fun getDownloadUrl(id: String): String { + return "$mainUrl/download?id=$id" + } + + private val normalApis = arrayListOf(MultiQuality()) + + // https://gogo-stream.com/streaming.php?id=MTE3NDg5 + suspend fun getUrl( + id: String, + isCasting: Boolean = false, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + try { + normalApis.apmap { api -> + val url = api.getExtractorUrl(id) + api.getSafeUrl(url, subtitleCallback = subtitleCallback, callback = callback) + } + val extractorUrl = getExtractorUrl(id) + + /** Stolen from GogoanimeProvider.kt extractor */ + suspendSafeApiCall { + val link = getDownloadUrl(id) + println("Generated vidstream download link: $link") + val page = app.get(link, referer = extractorUrl) + + val pageDoc = Jsoup.parse(page.text) + val qualityRegex = Regex("(\\d+)P") + + //a[download] + pageDoc.select(".dowload > a")?.apmap { element -> + val href = element.attr("href") ?: return@apmap + val qual = if (element.text() + .contains("HDP") + ) "1080" else qualityRegex.find(element.text())?.destructured?.component1() + .toString() + + if (!loadExtractor(href, link, subtitleCallback, callback)) { + callback.invoke( + ExtractorLink( + this.name, + name = this.name, + href, + page.url, + getQualityFromName(qual), + element.attr("href").contains(".m3u8") + ) + ) + } + } + } + + with(app.get(extractorUrl)) { + val document = Jsoup.parse(this.text) + val primaryLinks = document.select("ul.list-server-items > li.linkserver") + //val extractedLinksList: MutableList = mutableListOf() + + // All vidstream links passed to extractors + primaryLinks.distinctBy { it.attr("data-video") }.forEach { element -> + val link = element.attr("data-video") + //val name = element.text() + + // Matches vidstream links with extractors + extractorApis.filter { !it.requiresReferer || !isCasting }.apmap { api -> + if (link.startsWith(api.mainUrl)) { + api.getSafeUrl(link, extractorUrl, subtitleCallback, callback) + } + } + } + return true + } + } catch (e: Exception) { + return false + } + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/PlayerVoxzer.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/PlayerVoxzer.kt new file mode 100644 index 00000000..950dbfef --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/PlayerVoxzer.kt @@ -0,0 +1,31 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper + + +open class PlayerVoxzer : ExtractorApi() { + override var name = "Voxzer" + override var mainUrl = "https://player.voxzer.org" + override val requiresReferer = false + + override suspend fun getUrl(url: String, referer: String?): List? { + val listurl = url.replace("/view/","/list/") + val urltext = app.get(listurl, referer = url).text + val m3u8regex = Regex("((https:|http:)\\/\\/.*\\.m3u8)") + val sources = mutableListOf() + val listm3 = m3u8regex.find(urltext)?.value + if (listm3?.contains("m3u8") == true) + M3u8Helper.generateM3u8( + name, + listm3, + url, + headers = app.get(url).headers.toMap() + ).forEach { link -> + sources.add(link) + } + return sources + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/SBPlay.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/SBPlay.kt new file mode 100644 index 00000000..6bc768df --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/SBPlay.kt @@ -0,0 +1,86 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.APIHolder.unixTimeMS +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.mvvm.logError +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities +import com.lagradost.cloudstream3.utils.getPostForm +import org.jsoup.Jsoup + +//class SBPlay1 : SBPlay() { +// override var mainUrl = "https://sbplay1.com" +//} + +//class SBPlay2 : SBPlay() { +// override var mainUrl = "https://sbplay2.com" +//} + +open class SBPlay : ExtractorApi() { + override var mainUrl = "https://sbplay.one" + override var name = "SBPlay" + override val requiresReferer = false + + override suspend fun getUrl(url: String, referer: String?): List { + val response = app.get(url, referer = referer).text + val document = Jsoup.parse(response) + + val links = ArrayList() + + val tree = document.select("table > tbody > tr > td > a") + for (item in tree) { + val onDownload = item.attr("onclick") + val name = "${this.name} - ${item.text()}" + try { + Regex("download_video\\('(.*?)','(.*?)','(.*?)'\\)").matchEntire(onDownload)?.let { + val id = it.groupValues[1] + val mode = it.groupValues[2] + val hash = it.groupValues[3] + val href = "https://sbplay.one/dl?op=download_orig&id=$id&mode=$mode&hash=$hash" + val hrefResponse = app.get(href).text + app.post("https://sbplay.one/?op=notifications&open=&_=$unixTimeMS", referer = href) + val hrefDocument = Jsoup.parse(hrefResponse) + val hrefSpan = hrefDocument.selectFirst("span > a") + if (hrefSpan == null) { + getPostForm(href, hrefResponse)?.let { form -> + val postDocument = Jsoup.parse(form) + val downloadBtn = postDocument.selectFirst("a.downloadbtn")?.attr("href") + if (downloadBtn.isNullOrEmpty()) { + val hrefSpan2 = postDocument.selectFirst("span > a")?.attr("href") + if (hrefSpan2?.startsWith("https://") == true) { + links.add( + ExtractorLink( + this.name, name, + hrefSpan2, "", Qualities.Unknown.value, false + ) + ) + } else { + // no link found!!! + } + } else { + links.add( + ExtractorLink( + this.name, + name, + downloadBtn, + "", + Qualities.Unknown.value, + false + ) + ) + } + } + } else { + val link = hrefSpan.attr("href") + links.add(ExtractorLink(this.name, name, link, "", Qualities.Unknown.value, false)) + } + } + } catch (e: Exception) { + logError(e) + } + } + + return links + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Solidfiles.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Solidfiles.kt new file mode 100644 index 00000000..849f5fc8 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Solidfiles.kt @@ -0,0 +1,45 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.getQualityFromName + + +class Solidfiles : ExtractorApi() { + override val name = "Solidfiles" + override val mainUrl = "https://www.solidfiles.com" + override val requiresReferer = false + + override suspend fun getUrl(url: String, referer: String?): List { + val sources = mutableListOf() + with(app.get(url).document) { + this.select("script").map { script -> + if (script.data().contains("\"streamUrl\":")) { + val data = script.data().substringAfter("constant('viewerOptions', {").substringBefore("});") + val source = tryParseJson("{$data}") + val quality = Regex("\\d{3,4}p").find(source!!.nodeName)?.groupValues?.get(0) + sources.add( + ExtractorLink( + name, + name, + source.streamUrl, + referer = url, + quality = getQualityFromName(quality) + ) + ) + } + } + } + return sources + } + + + private data class ResponseSource( + @JsonProperty("streamUrl") val streamUrl: String, + @JsonProperty("nodeName") val nodeName: String + ) + +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/SpeedoStream.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/SpeedoStream.kt new file mode 100644 index 00000000..6153a7c1 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/SpeedoStream.kt @@ -0,0 +1,38 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper + +class SpeedoStream : ExtractorApi() { + override val name = "SpeedoStream" + override val mainUrl = "https://speedostream.com" + override val requiresReferer = true + + override suspend fun getUrl(url: String, referer: String?): List { + val sources = mutableListOf() + app.get(url, referer = referer).document.select("script").map { script -> + if (script.data().contains("jwplayer(\"vplayer\").setup(")) { + val data = script.data().substringAfter("sources: [") + .substringBefore("],").replace("file", "\"file\"").trim() + tryParseJson(data)?.let { + M3u8Helper.generateM3u8( + name, + it.file, + "$mainUrl/", + ).forEach { m3uData -> sources.add(m3uData) } + } + } + } + return sources + } + + private data class File( + @JsonProperty("file") val file: String, + ) + + +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamSB.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamSB.kt new file mode 100644 index 00000000..da3ef278 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamSB.kt @@ -0,0 +1,126 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.app +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 + +class Ssbstream : StreamSB() { + override var mainUrl = "https://ssbstream.net" +} + +class SBfull : StreamSB() { + override var mainUrl = "https://sbfull.com" +} + +class StreamSB1 : StreamSB() { + override var mainUrl = "https://sbplay1.com" +} + +class StreamSB2 : StreamSB() { + override var mainUrl = "https://sbplay2.com" +} + +class StreamSB3 : StreamSB() { + override var mainUrl = "https://sbplay3.com" +} + +class StreamSB4 : StreamSB() { + override var mainUrl = "https://cloudemb.com" +} + +class StreamSB5 : StreamSB() { + override var mainUrl = "https://sbplay.org" +} + +class StreamSB6 : StreamSB() { + override var mainUrl = "https://embedsb.com" +} + +class StreamSB7 : StreamSB() { + override var mainUrl = "https://pelistop.co" +} + +class StreamSB8 : StreamSB() { + override var mainUrl = "https://streamsb.net" +} + +class StreamSB9 : StreamSB() { + override var mainUrl = "https://sbplay.one" +} + +class StreamSB10 : StreamSB() { + override var mainUrl = "https://sbplay2.xyz" +} + +// This is a modified version of https://github.com/jmir1/aniyomi-extensions/blob/master/src/en/genoanime/src/eu/kanade/tachiyomi/animeextension/en/genoanime/extractors/StreamSBExtractor.kt +// The following code is under the Apache License 2.0 https://github.com/jmir1/aniyomi-extensions/blob/master/LICENSE +open class StreamSB : ExtractorApi() { + override var name = "StreamSB" + override var mainUrl = "https://watchsb.com" + override val requiresReferer = false + + private val hexArray = "0123456789ABCDEF".toCharArray() + + private fun bytesToHex(bytes: ByteArray): String { + val hexChars = CharArray(bytes.size * 2) + for (j in bytes.indices) { + val v = bytes[j].toInt() and 0xFF + + hexChars[j * 2] = hexArray[v ushr 4] + hexChars[j * 2 + 1] = hexArray[v and 0x0F] + } + return String(hexChars) + } + + data class Subs ( + @JsonProperty("file") val file: String, + @JsonProperty("label") val label: String, + ) + + data class StreamData ( + @JsonProperty("file") val file: String, + @JsonProperty("cdn_img") val cdnImg: String, + @JsonProperty("hash") val hash: String, + @JsonProperty("subs") val subs: List?, + @JsonProperty("length") val length: String, + @JsonProperty("id") val id: String, + @JsonProperty("title") val title: String, + @JsonProperty("backup") val backup: String, + ) + + data class Main ( + @JsonProperty("stream_data") val streamData: StreamData, + @JsonProperty("status_code") val statusCode: Int, + ) + + override suspend fun getUrl(url: String, referer: String?): List? { + val regexID = Regex("(embed-[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+|\\/e\\/[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") + val id = regexID.findAll(url).map { + it.value.replace(Regex("(embed-|\\/e\\/)"),"") + }.first() + val bytes = id.toByteArray() + val bytesToHex = bytesToHex(bytes) + val master = "$mainUrl/sources43/6d6144797752744a454267617c7c${bytesToHex.lowercase()}7c7c4e61755a56456f34385243727c7c73747265616d7362/6b4a33767968506e4e71374f7c7c343837323439333133333462353935333633373836643638376337633462333634663539343137373761333635313533333835333763376333393636363133393635366136323733343435323332376137633763373337343732363536313664373336327c7c504d754478413835306633797c7c73747265616d7362" + val headers = mapOf( + "watchsb" to "streamsb", + ) + val urltext = app.get(master, + headers = headers, + allowRedirects = false + ).text + val mapped = urltext.let { parseJson
(it) } + val testurl = app.get(mapped.streamData.file, headers = headers).text + // val urlmain = mapped.streamData.file.substringBefore("/hls/") + if (urltext.contains("m3u8") && testurl.contains("EXTM3U")) + return M3u8Helper.generateM3u8( + name, + mapped.streamData.file, + url, + headers = headers + ) + return null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamTape.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamTape.kt new file mode 100644 index 00000000..af436ff3 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamTape.kt @@ -0,0 +1,33 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities + +class StreamTape : ExtractorApi() { + override var name = "StreamTape" + override var mainUrl = "https://streamtape.com" + override val requiresReferer = false + + private val linkRegex = + Regex("""'robotlink'\)\.innerHTML = '(.+?)'\+ \('(.+?)'\)""") + + override suspend fun getUrl(url: String, referer: String?): List? { + with(app.get(url)) { + linkRegex.find(this.text)?.let { + val extractedUrl = "https:${it.groups[1]!!.value + it.groups[2]!!.value.substring(3,)}" + return listOf( + ExtractorLink( + name, + name, + extractedUrl, + url, + Qualities.Unknown.value, + ) + ) + } + } + return null + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Streamhub.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Streamhub.kt new file mode 100644 index 00000000..2765ae17 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Streamhub.kt @@ -0,0 +1,39 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.JsUnpacker +import com.lagradost.cloudstream3.utils.Qualities +import java.net.URI + +class Streamhub : ExtractorApi() { + override var mainUrl = "https://streamhub.to" + override var name = "Streamhub" + override val requiresReferer = false + + override fun getExtractorUrl(id: String): String { + return "$mainUrl/e/$id" + } + + override suspend fun getUrl(url: String, referer: String?): List? { + val response = app.get(url).text + Regex("eval((.|\\n)*?)").find(response)?.groupValues?.get(1)?.let { jsEval -> + JsUnpacker("eval$jsEval").unpack()?.let { unPacked -> + Regex("sources:\\[\\{src:\"(.*?)\"").find(unPacked)?.groupValues?.get(1)?.let { link -> + return listOf( + ExtractorLink( + this.name, + this.name, + link, + referer ?: "", + Qualities.Unknown.value, + URI(link).path.endsWith(".m3u8") + ) + ) + } + } + } + return null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Streamlare.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Streamlare.kt new file mode 100644 index 00000000..396327ba --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Streamlare.kt @@ -0,0 +1,60 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities +import com.lagradost.nicehttp.RequestBodyTypes +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.RequestBody.Companion.toRequestBody + + +class Streamlare : Slmaxed() { + override val mainUrl = "https://streamlare.com/" +} + +open class Slmaxed : ExtractorApi() { + override val name = "Streamlare" + override val mainUrl = "https://slmaxed.com/" + override val requiresReferer = true + + // https://slmaxed.com/e/oLvgezw3LjPzbp8E -> oLvgezw3LjPzbp8E + val embedRegex = Regex("""/e/([^/]*)""") + + + data class JsonResponse( + @JsonProperty val status: String? = null, + @JsonProperty val message: String? = null, + @JsonProperty val type: String? = null, + @JsonProperty val token: String? = null, + @JsonProperty val result: Map? = null + ) + + data class Result( + @JsonProperty val label: String? = null, + @JsonProperty val file: String? = null, + @JsonProperty val type: String? = null + ) + + override suspend fun getUrl(url: String, referer: String?): List? { + val id = embedRegex.find(url)!!.groupValues[1] + val json = app.post( + "${mainUrl}api/video/stream/get", + requestBody = """{"id":"$id"}""".toRequestBody(RequestBodyTypes.JSON.toMediaTypeOrNull()) + ).parsed() + return json.result?.mapNotNull { + it.value.let { result -> + ExtractorLink( + this.name, + this.name, + result.file ?: return@mapNotNull null, + url, + result.label?.replace("p", "", ignoreCase = true)?.trim()?.toIntOrNull() + ?: Qualities.Unknown.value, + isM3u8 = result.type?.contains("hls", ignoreCase = true) == true + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Supervideo.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Supervideo.kt new file mode 100644 index 00000000..955345aa --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Supervideo.kt @@ -0,0 +1,41 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.* +import com.lagradost.cloudstream3.utils.AppUtils.parseJson + +data class Files( + @JsonProperty("file") val id: String, + @JsonProperty("label") val label: String? = null, +) + + open class Supervideo : ExtractorApi() { + override var name = "Supervideo" + override var mainUrl = "https://supervideo.tv" + override val requiresReferer = false + override suspend fun getUrl(url: String, referer: String?): List? { + val extractedLinksList: MutableList = mutableListOf() + val response = app.get(url).text + val jstounpack = Regex("eval((.|\\n)*?)").find(response)?.groups?.get(1)?.value + val unpacjed = JsUnpacker(jstounpack).unpack() + val extractedUrl = unpacjed?.let { Regex("""sources:((.|\n)*?)image""").find(it) }?.groups?.get(1)?.value.toString().replace("file",""""file"""").replace("label",""""label"""").substringBeforeLast(",") + val parsedlinks = parseJson>(extractedUrl) + parsedlinks.forEach { data -> + if (data.label.isNullOrBlank()){ // mp4 links (with labels) are slow. Use only m3u8 link. + M3u8Helper.generateM3u8( + name, + data.id, + url, + headers = mapOf("referer" to url) + ).forEach { link -> + extractedLinksList.add(link) + } + } + } + + + return extractedLinksList + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Tantifilm.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Tantifilm.kt new file mode 100644 index 00000000..d721dea8 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Tantifilm.kt @@ -0,0 +1,42 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.ExtractorLink + +open class Tantifilm : ExtractorApi() { + override var name = "Tantifilm" + override var mainUrl = "https://cercafilm.net" + override val requiresReferer = false + + data class TantifilmJsonData ( + @JsonProperty("success") val success : Boolean, + @JsonProperty("data") val data : List, + @JsonProperty("captions")val captions : List, + @JsonProperty("is_vr") val is_vr : Boolean + ) + + data class TantifilmData ( + @JsonProperty("file") val file : String, + @JsonProperty("label") val label : String, + @JsonProperty("type") val type : String + ) + + override suspend fun getUrl(url: String, referer: String?): List? { + val link = "$mainUrl/api/source/${url.substringAfterLast("/")}" + val response = app.post(link).text.replace("""\""","") + val jsonvideodata = parseJson(response) + return jsonvideodata.data.map { + ExtractorLink( + it.file+".${it.type}", + this.name, + it.file+".${it.type}", + mainUrl, + it.label.filter{ it.isDigit() }.toInt(), + false + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Tomatomatela.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Tomatomatela.kt new file mode 100644 index 00000000..20bd69ba --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Tomatomatela.kt @@ -0,0 +1,41 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities + +class Cinestart: Tomatomatela() { + override var name = "Cinestart" + override var mainUrl = "https://cinestart.net" + override val details = "vr.php?v=" +} + +open class Tomatomatela : ExtractorApi() { + override var name = "Tomatomatela" + override var mainUrl = "https://tomatomatela.com" + override val requiresReferer = false + private data class Tomato ( + @JsonProperty("status") val status: Int, + @JsonProperty("file") val file: String + ) + open val details = "details.php?v=" + override suspend fun getUrl(url: String, referer: String?): List? { + val link = url.replace("$mainUrl/embed.html#","$mainUrl/$details") + val server = app.get(link, allowRedirects = false).text + val json = parseJson(server) + if (json.status == 200) return listOf( + ExtractorLink( + name, + name, + json.file, + "", + Qualities.Unknown.value, + isM3u8 = false + ) + ) + return null + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/UpstreamExtractor.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/UpstreamExtractor.kt new file mode 100644 index 00000000..79c657b6 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/UpstreamExtractor.kt @@ -0,0 +1,59 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities + +class UpstreamExtractor: ExtractorApi() { + override val name: String = "Upstream.to" + override val mainUrl: String = "https://upstream.to" + override val requiresReferer = true + + override suspend fun getUrl(url: String, referer: String?): List { + // WIP: m3u8 link fetched but sometimes not playing + //Log.i(this.name, "Result => (no extractor) ${url}") + val sources: MutableList = mutableListOf() + val doc = app.get(url, referer = referer).text + if (doc.isNotBlank()) { + var reg = Regex("(?<=master)(.*)(?=hls)") + val result = reg.find(doc)?.groupValues?.map { + it.trim('|') + }?.toList() + reg = Regex("(?<=\\|file\\|)(.*)(?=\\|remove\\|)") + val domainList = reg.find(doc)?.groupValues?.get(1)?.split("|") + var domain = when (!domainList.isNullOrEmpty()) { + true -> { + if (domainList.isNotEmpty()) { + var domName = "" + for (part in domainList) { + domName = "${part}.${domName}" + } + domName.trimEnd('.') + } else { "" } + } + false -> "" + } + //Log.i(this.name, "Result => (domain) ${domain}") + if (domain.isEmpty()) { + domain = "s96.upstreamcdn.co" + //Log.i(this.name, "Result => (default domain) ${domain}") + } + + result?.forEach { + val linkUrl = "https://${domain}/hls/${it}/master.m3u8" + sources.add( + ExtractorLink( + name = "Upstream m3u8", + source = this.name, + url = linkUrl, + quality = Qualities.Unknown.value, + referer = referer ?: linkUrl, + isM3u8 = true + ) + ) + } + } + return sources + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Uqload.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Uqload.kt new file mode 100644 index 00000000..e5d2875f --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Uqload.kt @@ -0,0 +1,49 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.utils.* +import com.lagradost.cloudstream3.app + +class Uqload1 : Uqload() { + override var mainUrl = "https://uqload.com" +} + +open class Uqload : ExtractorApi() { + override val name: String = "Uqload" + override val mainUrl: String = "https://www.uqload.com" + private val srcRegex = Regex("""sources:.\[(.*?)\]""") // would be possible to use the parse and find src attribute + override val requiresReferer = true + + + override suspend fun getUrl(url: String, referer: String?): List? { + val lang = url.substring(0, 2) + val flag = + if (lang == "vo") { + " \uD83C\uDDEC\uD83C\uDDE7" + } + else if (lang == "vf"){ + " \uD83C\uDDE8\uD83C\uDDF5" + } else { + "" + } + + val cleaned_url = if (lang == "ht") { // if url doesn't contain a flag and the url starts with http:// + url + } else { + url.substring(2, url.length) + } + with(app.get(cleaned_url)) { // raised error ERROR_CODE_PARSING_CONTAINER_UNSUPPORTED (3003) is due to the response: "error_nofile" + srcRegex.find(this.text)?.groupValues?.get(1)?.replace("\"", "")?.let { link -> + return listOf( + ExtractorLink( + name, + name + flag, + link, + cleaned_url, + Qualities.Unknown.value, + ) + ) + } + } + return null + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Userload.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Userload.kt new file mode 100644 index 00000000..7752b824 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Userload.kt @@ -0,0 +1,117 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.* +import org.mozilla.javascript.Context +import org.mozilla.javascript.EvaluatorException +import org.mozilla.javascript.Scriptable +import java.util.* + + +open class Userload : ExtractorApi() { + override var name = "Userload" + override var mainUrl = "https://userload.co" + override val requiresReferer = false + + private fun splitInput(input: String): List { + var counter = 0 + val array = ArrayList() + var buffer = "" + for (c in input) { + when (c) { + '(' -> counter++ + ')' -> counter-- + else -> {} + } + buffer += c + if (counter == 0) { + if (buffer.isNotBlank() && buffer != "+") + array.add(buffer) + buffer = "" + } + } + return array + } + + private fun evaluateMath(mathExpression : String): String { + val rhino = Context.enter() + rhino.initStandardObjects() + rhino.optimizationLevel = -1 + val scope: Scriptable = rhino.initStandardObjects() + return try { + rhino.evaluateString(scope, "eval($mathExpression)", "JavaScript", 1, null).toString() + } + catch (e: EvaluatorException){ + "" + } + } + + private fun decodeVideoJs(text: String): List { + text.replace("""\s+|/\*.*?\*/""".toRegex(), "") + val data = text.split("""+(゚Д゚)[゚o゚]""")[1] + val chars = data.split("""+ (゚Д゚)[゚ε゚]+""").drop(1) + val newchars = chars.map { char -> + char.replace("(o゚ー゚o)", "u") + .replace("c", "0") + .replace("(゚Д゚)['0']", "c") + .replace("゚Θ゚", "1") + .replace("!+[]", "1") + .replace("-~", "1+") + .replace("o", "3") + .replace("_", "3") + .replace("゚ー゚", "4") + .replace("(+", "(") + } + + val subchar = mutableListOf() + + newchars.dropLast(1).forEach { v -> + subchar.add(splitInput(v).map { evaluateMath(it).substringBefore(".") }.toString().filter { it.isDigit() }) + } + var txtresult = "" + subchar.forEach{ + txtresult = txtresult.plus(Char(it.toInt(8))) + } + val val1 = Regex(""""morocco="((.|\\n)*?)"&mycountry="""").find(txtresult)?.groups?.get(1)?.value.toString().drop(1).dropLast(1) + val val2 = txtresult.substringAfter("""&mycountry="+""").substringBefore(")") + + return listOf( + val1, + val2 + ) + + + } + + override suspend fun getUrl(url: String, referer: String?): List? { + + val extractedLinksList: MutableList = mutableListOf() + + val response = app.get(url).text + val jsToUnpack = Regex("ext/javascript\">eval((.|\\n)*?)").find(response)?.groups?.get(1)?.value + val unpacked = JsUnpacker(jsToUnpack).unpack() + val videoJs = app.get("$mainUrl/api/assets/userload/js/videojs.js") + val videoJsToDecode = videoJs.text + val values = decodeVideoJs(videoJsToDecode) + val morocco = unpacked!!.split(";").filter { it.contains(values[0]) }[0].split("=")[1].drop(1).dropLast(1) + val mycountry = unpacked.split(";").filter { it.contains(values[1]) }[0].split("=")[1].drop(1).dropLast(1) + val videoLinkPage = app.post("$mainUrl/api/request/", data = mapOf( + "morocco" to morocco, + "mycountry" to mycountry + )) + val videoLink = videoLinkPage.text + val nameSource = app.get(url).document.head().selectFirst("title")!!.text() + extractedLinksList.add( + ExtractorLink( + name, + name, + videoLink, + mainUrl, + getQualityFromName(nameSource), + ) + ) + + return extractedLinksList + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/VidSrcExtractor.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/VidSrcExtractor.kt new file mode 100644 index 00000000..7b087157 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/VidSrcExtractor.kt @@ -0,0 +1,68 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.apmap +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper +import com.lagradost.cloudstream3.utils.loadExtractor + +class VidSrcExtractor2 : VidSrcExtractor() { + override val mainUrl = "https://vidsrc.me/embed" + override suspend fun getUrl( + url: String, + referer: String?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val newUrl = url.lowercase().replace(mainUrl, super.mainUrl) + super.getUrl(newUrl, referer, subtitleCallback, callback) + } +} + +open class VidSrcExtractor : ExtractorApi() { + override val name = "VidSrc" + private val absoluteUrl = "https://v2.vidsrc.me" + override val mainUrl = "$absoluteUrl/embed" + override val requiresReferer = false + + override suspend fun getUrl( + url: String, + referer: String?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val iframedoc = app.get(url).document + + val serverslist = + iframedoc.select("div#sources.button_content div#content div#list div").map { + val datahash = it.attr("data-hash") + if (datahash.isNotBlank()) { + val links = try { + app.get("$absoluteUrl/src/$datahash", referer = "https://source.vidsrc.me/").url + } catch (e: Exception) { + "" + } + links + } else "" + } + + serverslist.apmap { server -> + val linkfixed = server.replace("https://vidsrc.xyz/", "https://embedsito.com/") + if (linkfixed.contains("/pro")) { + val srcresponse = app.get(server, referer = absoluteUrl).text + val m3u8Regex = Regex("((https:|http:)//.*\\.m3u8)") + val srcm3u8 = m3u8Regex.find(srcresponse)?.value ?: return@apmap + M3u8Helper.generateM3u8( + name, + srcm3u8, + absoluteUrl + ).forEach(callback) + } else { + loadExtractor(linkfixed, url, subtitleCallback, callback) + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/VideoVard.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/VideoVard.kt new file mode 100644 index 00000000..41e77967 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/VideoVard.kt @@ -0,0 +1,271 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8 +import kotlinx.coroutines.delay +import java.math.BigInteger + +class VideovardSX : WcoStream() { + override var mainUrl = "https://videovard.sx" +} + +class VideoVard : ExtractorApi() { + override var name = "Videovard" // Cause works for animekisa and wco + override var mainUrl = "https://videovard.to" + override val requiresReferer = false + + //The following code was extracted from https://github.com/saikou-app/saikou/blob/main/app/src/main/java/ani/saikou/parsers/anime/extractors/VideoVard.kt + override suspend fun getUrl(url: String, referer: String?): List { + val id = url.substringAfter("e/").substringBefore("/") + val sources = mutableListOf() + val hash = app.get("$mainUrl/api/make/download/$id").parsed() + delay(11_000) + val resm3u8 = app.post( + "$mainUrl/api/player/setup", + mapOf("Referer" to "$mainUrl/"), + data = mapOf( + "cmd" to "get_stream", + "file_code" to id, + "hash" to hash.hash!! + ) + ).parsed() + val m3u8 = decode(resm3u8.src!!, resm3u8.seed) + sources.addAll( + generateM3u8( + name, + m3u8, + mainUrl, + headers = mapOf("Referer" to mainUrl) + ) + ) + return sources + } + + companion object { + private val big0 = 0.toBigInteger() + private val big3 = 3.toBigInteger() + private val big4 = 4.toBigInteger() + private val big15 = 15.toBigInteger() + private val big16 = 16.toBigInteger() + private val big255 = 255.toBigInteger() + + private fun decode(dataFile: String, seed: String): String { + val dataSeed = replace(seed) + val newDataSeed = binaryDigest(dataSeed) + val newDataFile = bytes2blocks(ascii2bytes(dataFile)) + var list = listOf(1633837924, 1650680933).map { it.toBigInteger() } + val xorList = mutableListOf() + for (i in newDataFile.indices step 2) { + val temp = newDataFile.slice(i..i + 1) + xorList += xorBlocks(list, tearDecode(temp, newDataSeed)) + list = temp + } + + val result = replace(unPad(blocks2bytes(xorList)).map { it.toInt().toChar() }.joinToString("")) + return padLastChars(result) + } + + private fun binaryDigest(input: String): List { + val keys = listOf(1633837924, 1650680933, 1667523942, 1684366951).map { it.toBigInteger() } + var list1 = keys.slice(0..1) + var list2 = list1 + val blocks = bytes2blocks(digestPad(input)) + + for (i in blocks.indices step 4) { + list1 = tearCode(xorBlocks(blocks.slice(i..i + 1), list1), keys).toMutableList() + list2 = tearCode(xorBlocks(blocks.slice(i + 2..i + 3), list2), keys).toMutableList() + + val temp = list1[0] + list1[0] = list1[1] + list1[1] = list2[0] + list2[0] = list2[1] + list2[1] = temp + } + + return listOf(list1[0], list1[1], list2[0], list2[1]) + } + + private fun tearDecode(a90: List, a91: List): MutableList { + var (a95, a96) = a90 + + var a97 = (-957401312).toBigInteger() + for (_i in 0 until 32) { + a96 -= ((((a95 shl 4) xor rShift(a95, 5)) + a95) xor (a97 + a91[rShift(a97, 11).and(3.toBigInteger()).toInt()])) + a97 += 1640531527.toBigInteger() + a95 -= ((((a96 shl 4) xor rShift(a96, 5)) + a96) xor (a97 + a91[a97.and(3.toBigInteger()).toInt()])) + + } + + return mutableListOf(a95, a96) + } + + private fun digestPad(string: String): List { + val empList = mutableListOf() + val length = string.length + val extra = big15 - (length.toBigInteger() % big16) + empList.add(extra) + for (i in 0 until length) { + empList.add(string[i].code.toBigInteger()) + } + for (i in 0 until extra.toInt()) { + empList.add(big0) + } + + return empList + } + + private fun bytes2blocks(a22: List): List { + val empList = mutableListOf() + val length = a22.size + var listIndex = 0 + + for (i in 0 until length) { + val subIndex = i % 4 + val shiftedByte = a22[i] shl (3 - subIndex) * 8 + + if (subIndex == 0) { + empList.add(shiftedByte) + } else { + empList[listIndex] = empList[listIndex] or shiftedByte + } + + if (subIndex == 3) listIndex += 1 + } + + return empList + } + + private fun blocks2bytes(inp: List): List { + val tempList = mutableListOf() + inp.indices.forEach { i -> + tempList += (big255 and rShift(inp[i], 24)) + tempList += (big255 and rShift(inp[i], 16)) + tempList += (big255 and rShift(inp[i], 8)) + tempList += (big255 and inp[i]) + } + return tempList + } + + private fun unPad(a46: List): List { + val evenOdd = a46[0].toInt().mod(2) + return (1 until (a46.size - evenOdd)).map { + a46[it] + } + } + + private fun xorBlocks(a76: List, a77: List): List { + return listOf(a76[0] xor a77[0], a76[1] xor a77[1]) + } + + private fun rShift(input: BigInteger, by: Int): BigInteger { + return (input.mod(4294967296.toBigInteger()) shr by) + } + + private fun tearCode(list1: List, list2: List): MutableList { + var a1 = list1[0] + var a2 = list1[1] + var temp = big0 + + for (_i in 0 until 32) { + a1 += (a2 shl 4 xor rShift(a2, 5)) + a2 xor temp + list2[(temp and big3).toInt()] + temp -= 1640531527.toBigInteger() + a2 += (a1 shl 4 xor rShift(a1, 5)) + a1 xor temp + list2[(rShift(temp, 11) and big3).toInt()] + } + return mutableListOf(a1, a2) + } + + private fun ascii2bytes(input: String): List { + val abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" + val abcMap = abc.mapIndexed { i, c -> c to i.toBigInteger() }.toMap() + var index = -1 + val length = input.length + var listIndex = 0 + val bytes = mutableListOf() + + while (true) { + for (i in input) { + if (abc.contains(i)) { + index++ + break + } + } + + bytes.add((abcMap[input.getOrNull(index)?:return bytes]!! * big4)) + + while (true) { + index++ + if (abc.contains(input[index])) { + break + } + } + + var temp = abcMap[input[index]]!! + + bytes[listIndex] = bytes[listIndex] or rShift(temp, 4) + listIndex++ + temp = (big15.and(temp)) + + if ((temp == big0) && (index == (length - 1))) return bytes + + bytes.add((temp * big4 * big4)) + + while (true) { + index++ + if (index >= length) return bytes + if (abc.contains(input[index])) break + } + + temp = abcMap[input[index]]!! + bytes[listIndex] = bytes[listIndex] or rShift(temp, 2) + listIndex++ + temp = (big3 and temp) + if ((temp == big0) && (index == (length - 1))) { + return bytes + } + bytes.add((temp shl 6)) + for (i in input) { + index++ + if (abc.contains(input[index])) { + break + } + } + bytes[listIndex] = bytes[listIndex] or abcMap[input[index]]!! + listIndex++ + } + } + + private fun replace(a: String): String { + val map = mapOf( + '0' to '5', + '1' to '6', + '2' to '7', + '5' to '0', + '6' to '1', + '7' to '2' + ) + var b = "" + a.forEach { + b += if (map.containsKey(it)) map[it] else it + } + return b + } + + private fun padLastChars(input:String):String{ + return if(input.reversed()[3].isDigit()) input + else input.dropLast(4) + } + + private data class HashResponse( + val hash: String? = null, + val version:String? = null + ) + + private data class SetupResponse( + val seed: String, + val src: String?=null, + val link:String?=null + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Vidstream.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Vidstream.kt new file mode 100644 index 00000000..1d853b2d --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Vidstream.kt @@ -0,0 +1,101 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.apmap +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.argamap +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.extractorApis +import com.lagradost.cloudstream3.utils.getQualityFromName +import com.lagradost.cloudstream3.utils.loadExtractor +import org.jsoup.Jsoup + +/** + * overrideMainUrl is necessary for for other vidstream clones like vidembed.cc + * If they diverge it'd be better to make them separate. + * */ +class Vidstream(val mainUrl: String) { + val name: String = "Vidstream" + + private fun getExtractorUrl(id: String): String { + return "$mainUrl/streaming.php?id=$id" + } + + private fun getDownloadUrl(id: String): String { + return "$mainUrl/download?id=$id" + } + + private val normalApis = arrayListOf(MultiQuality()) + + // https://gogo-stream.com/streaming.php?id=MTE3NDg5 + suspend fun getUrl( + id: String, + isCasting: Boolean = false, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit, + ): Boolean { + val extractorUrl = getExtractorUrl(id) + argamap( + { + normalApis.apmap { api -> + val url = api.getExtractorUrl(id) + api.getSafeUrl( + url, + callback = callback, + subtitleCallback = subtitleCallback + ) + } + }, { + /** Stolen from GogoanimeProvider.kt extractor */ + val link = getDownloadUrl(id) + println("Generated vidstream download link: $link") + val page = app.get(link, referer = extractorUrl) + + val pageDoc = Jsoup.parse(page.text) + val qualityRegex = Regex("(\\d+)P") + + //a[download] + pageDoc.select(".dowload > a")?.apmap { element -> + val href = element.attr("href") ?: return@apmap + val qual = if (element.text() + .contains("HDP") + ) "1080" else qualityRegex.find(element.text())?.destructured?.component1() + .toString() + + if (!loadExtractor(href, link, subtitleCallback, callback)) { + callback.invoke( + ExtractorLink( + this.name, + name = this.name, + href, + page.url, + getQualityFromName(qual), + element.attr("href").contains(".m3u8") + ) + ) + } + } + }, { + with(app.get(extractorUrl)) { + val document = Jsoup.parse(this.text) + val primaryLinks = document.select("ul.list-server-items > li.linkserver") + //val extractedLinksList: MutableList = mutableListOf() + + // All vidstream links passed to extractors + primaryLinks.distinctBy { it.attr("data-video") }.forEach { element -> + val link = element.attr("data-video") + //val name = element.text() + + // Matches vidstream links with extractors + extractorApis.filter { !it.requiresReferer || !isCasting }.apmap { api -> + if (link.startsWith(api.mainUrl)) { + api.getSafeUrl(link, extractorUrl, subtitleCallback, callback) + } + } + } + } + } + ) + return true + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/VoeExtractor.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/VoeExtractor.kt new file mode 100644 index 00000000..d2f3f832 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/VoeExtractor.kt @@ -0,0 +1,51 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.getQualityFromName + +open class VoeExtractor : ExtractorApi() { + override val name: String = "Voe" + override val mainUrl: String = "https://voe.sx" + override val requiresReferer = false + + private data class ResponseLinks( + @JsonProperty("hls") val url: String?, + @JsonProperty("video_height") val label: Int? + //val type: String // Mp4 + ) + + override suspend fun getUrl(url: String, referer: String?): List { + val extractedLinksList: MutableList = mutableListOf() + val doc = app.get(url).text + if (doc.isNotBlank()) { + val start = "const sources =" + var src = doc.substring(doc.indexOf(start)) + src = src.substring(start.length, src.indexOf(";")) + .replace("0,", "0") + .trim() + //Log.i(this.name, "Result => (src) ${src}") + parseJson(src)?.let { voelink -> + //Log.i(this.name, "Result => (voelink) ${voelink}") + val linkUrl = voelink.url + val linkLabel = voelink.label?.toString() ?: "" + if (!linkUrl.isNullOrEmpty()) { + extractedLinksList.add( + ExtractorLink( + name = this.name, + source = this.name, + url = linkUrl, + quality = getQualityFromName(linkLabel), + referer = url, + isM3u8 = true + ) + ) + } + } + } + return extractedLinksList + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/WatchSB.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/WatchSB.kt new file mode 100644 index 00000000..20f0a2b5 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/WatchSB.kt @@ -0,0 +1,23 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.network.WebViewResolver +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8 + +open class WatchSB : ExtractorApi() { + override var name = "WatchSB" + override var mainUrl = "https://watchsb.com" + override val requiresReferer = false + + override suspend fun getUrl(url: String, referer: String?): List { + val response = app.get( + url, interceptor = WebViewResolver( + Regex("""master\.m3u8""") + ) + ) + + return generateM3u8(name, response.url, url, headers = response.headers.toMap()) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/WcoStream.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/WcoStream.kt new file mode 100644 index 00000000..d99485ea --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/WcoStream.kt @@ -0,0 +1,127 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.ErrorLoadingException +import com.lagradost.cloudstream3.extractors.helper.NineAnimeHelper.cipher +import com.lagradost.cloudstream3.extractors.helper.NineAnimeHelper.encrypt +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities + +class Vidstreamz : WcoStream() { + override var mainUrl = "https://vidstreamz.online" +} + +class Vizcloud : WcoStream() { + override var mainUrl = "https://vizcloud2.ru" +} + +class Vizcloud2 : WcoStream() { + override var mainUrl = "https://vizcloud2.online" +} + +class VizcloudOnline : WcoStream() { + override var mainUrl = "https://vizcloud.online" +} + +class VizcloudXyz : WcoStream() { + override var mainUrl = "https://vizcloud.xyz" +} + +class VizcloudLive : WcoStream() { + override var mainUrl = "https://vizcloud.live" +} + +class VizcloudInfo : WcoStream() { + override var mainUrl = "https://vizcloud.info" +} + +class MwvnVizcloudInfo : WcoStream() { + override var mainUrl = "https://mwvn.vizcloud.info" +} + +class VizcloudDigital : WcoStream() { + override var mainUrl = "https://vizcloud.digital" +} + +class VizcloudCloud : WcoStream() { + override var mainUrl = "https://vizcloud.cloud" +} + +class VizcloudSite : WcoStream() { + override var mainUrl = "https://vizcloud.site" +} + +open class WcoStream : ExtractorApi() { + override var name = "VidStream" // Cause works for animekisa and wco + override var mainUrl = "https://vidstream.pro" + override val requiresReferer = false + private val regex = Regex("(.+?/)e(?:mbed)?/([a-zA-Z0-9]+)") + + companion object { + // taken from https://github.com/saikou-app/saikou/blob/b35364c8c2a00364178a472fccf1ab72f09815b4/app/src/main/java/ani/saikou/parsers/anime/extractors/VizCloud.kt + // GNU General Public License v3.0 https://github.com/saikou-app/saikou/blob/main/LICENSE.md + private var lastChecked = 0L + private const val jsonLink = + "https://raw.githubusercontent.com/chenkaslowankiya/BruhFlow/main/keys.json" + private var cipherKey: VizCloudKey? = null + suspend fun getKey(): VizCloudKey { + cipherKey = + if (cipherKey != null && (lastChecked - System.currentTimeMillis()) < 1000 * 60 * 30) cipherKey!! + else { + lastChecked = System.currentTimeMillis() + app.get(jsonLink).parsed() + } + return cipherKey!! + } + + data class VizCloudKey( + @JsonProperty("cipherKey") val cipherKey: String, + @JsonProperty("mainKey") val mainKey: String, + @JsonProperty("encryptKey") val encryptKey: String, + @JsonProperty("dashTable") val dashTable: String + ) + + private const val baseTable = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+=/_" + + private fun dashify(id: String, dashTable: String): String { + val table = dashTable.split(" ") + return id.mapIndexedNotNull { i, c -> + table.getOrNull((baseTable.indexOf(c) * 16) + (i % 16)) + }.joinToString("-") + } + } + + //private val key = "LCbu3iYC7ln24K7P" // key credits @Modder4869 + override suspend fun getUrl(url: String, referer: String?): List { + val group = regex.find(url)?.groupValues!! + + val host = group[1] + val viz = getKey() + val id = encrypt( + cipher( + viz.cipherKey, + encrypt(group[2], viz.encryptKey).also { println(it) } + ).also { println(it) }, + viz.encryptKey + ).also { println(it) } + + val link = + "${host}mediainfo/${dashify(id, viz.dashTable)}?key=${viz.mainKey}" // + val response = app.get(link, referer = referer) + + data class Sources(@JsonProperty("file") val file: String) + data class Media(@JsonProperty("sources") val sources: List) + data class Data(@JsonProperty("media") val media: Media) + data class Response(@JsonProperty("data") val data: Data) + + + if (!response.text.startsWith("{")) throw ErrorLoadingException("Seems like 9Anime kiddies changed stuff again, Go touch some grass for bout an hour Or use a different Server") + return response.parsed().data.media.sources.map { + ExtractorLink(name, it.file,it.file,host,Qualities.Unknown.value,it.file.contains(".m3u8")) + } + + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/XStreamCdn.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/XStreamCdn.kt new file mode 100644 index 00000000..89f4ca67 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/XStreamCdn.kt @@ -0,0 +1,93 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.AppUtils +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.getQualityFromName + +class LayarKaca: XStreamCdn() { + override val name: String = "LayarKaca-xxi" + override val mainUrl: String = "https://layarkacaxxi.icu" +} + +class DBfilm: XStreamCdn() { + override val name: String = "DBfilm" + override val mainUrl: String = "https://dbfilm.bar" +} + +class Luxubu : XStreamCdn(){ + override val name: String = "FE" + override val mainUrl: String = "https://www.luxubu.review" +} + +class FEmbed: XStreamCdn() { + override val name: String = "FEmbed" + override val mainUrl: String = "https://www.fembed.com" +} + +class Fplayer: XStreamCdn() { + override val name: String = "Fplayer" + override val mainUrl: String = "https://fplayer.info" +} + +class FeHD: XStreamCdn() { + override val name: String = "FeHD" + override val mainUrl: String = "https://fembed-hd.com" + override var domainUrl: String = "fembed-hd.com" +} + +open class XStreamCdn : ExtractorApi() { + override val name: String = "XStreamCdn" + override val mainUrl: String = "https://embedsito.com" + override val requiresReferer = false + open var domainUrl: String = "embedsito.com" + + private data class ResponseData( + @JsonProperty("file") val file: String, + @JsonProperty("label") val label: String, + //val type: String // Mp4 + ) + + private data class ResponseJson( + @JsonProperty("success") val success: Boolean, + @JsonProperty("data") val data: List? + ) + + override fun getExtractorUrl(id: String): String { + return "$domainUrl/api/source/$id" + } + + override suspend fun getUrl(url: String, referer: String?): List { + val headers = mapOf( + "Referer" to url, + "User-Agent" to "Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0", + ) + val id = url.trimEnd('/').split("/").last() + val newUrl = "https://${domainUrl}/api/source/${id}" + val extractedLinksList: MutableList = mutableListOf() + with(app.post(newUrl, headers = headers)) { + if (this.code != 200) return listOf() + val text = this.text + if (text.isEmpty()) return listOf() + if (text == """{"success":false,"data":"Video not found or has been removed"}""") return listOf() + AppUtils.parseJson(text)?.let { + if (it.success && it.data != null) { + it.data.forEach { data -> + extractedLinksList.add( + ExtractorLink( + name, + name = name, + data.file, + url, + getQualityFromName(data.label), + ) + ) + } + } + } + } + return extractedLinksList + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/YourUpload.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/YourUpload.kt new file mode 100644 index 00000000..3c564f67 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/YourUpload.kt @@ -0,0 +1,47 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.getQualityFromName + +class YourUpload: ExtractorApi() { + override val name = "Yourupload" + override val mainUrl = "https://www.yourupload.com" + override val requiresReferer = false + + override suspend fun getUrl(url: String, referer: String?): List { + val sources = mutableListOf() + with(app.get(url).document) { + val quality = Regex("\\d{3,4}p").find(this.select("title").text())?.groupValues?.get(0) + this.select("script").map { script -> + if (script.data().contains("var jwplayerOptions = {")) { + val data = + script.data().substringAfter("var jwplayerOptions = {").substringBefore(",\n") + val link = tryParseJson( + "{${ + data.replace("file", "\"file\"").replace("'", "\"") + }}" + ) + sources.add( + ExtractorLink( + source = name, + name = name, + url = link!!.file, + referer = url, + quality = getQualityFromName(quality) + ) + ) + } + } + } + return sources + } + + private data class ResponseSource( + @JsonProperty("file") val file: String, + ) + +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/YoutubeExtractor.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/YoutubeExtractor.kt new file mode 100644 index 00000000..23704e90 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/YoutubeExtractor.kt @@ -0,0 +1,88 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.mvvm.logError +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.schemaStripRegex +import org.schabi.newpipe.extractor.ServiceList +import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor +import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory +import org.schabi.newpipe.extractor.stream.SubtitlesStream +import org.schabi.newpipe.extractor.stream.VideoStream + +class YoutubeShortLinkExtractor : YoutubeExtractor() { + override val mainUrl = "https://youtu.be" + + override fun getExtractorUrl(id: String): String { + return "$mainUrl/$id" + } +} + +class YoutubeMobileExtractor : YoutubeExtractor() { + override val mainUrl = "https://m.youtube.com" +} +class YoutubeNoCookieExtractor : YoutubeExtractor() { + override val mainUrl = "https://www.youtube-nocookie.com" +} + +open class YoutubeExtractor : ExtractorApi() { + override val mainUrl = "https://www.youtube.com" + override val requiresReferer = false + override val name = "YouTube" + + companion object { + private var ytVideos: MutableMap> = mutableMapOf() + private var ytVideosSubtitles: MutableMap> = mutableMapOf() + } + + override fun getExtractorUrl(id: String): String { + return "$mainUrl/watch?v=$id" + } + + override suspend fun getUrl( + url: String, + referer: String?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + if (ytVideos[url].isNullOrEmpty()) { + val link = + YoutubeStreamLinkHandlerFactory.getInstance().fromUrl( + url.replace( + schemaStripRegex, "" + ) + ) + + val s = object : YoutubeStreamExtractor( + ServiceList.YouTube, + link + ) { + + } + s.fetchPage() + ytVideos[url] = s.videoStreams + ytVideosSubtitles[url] = try { + s.subtitlesDefault.filterNotNull() + } catch (e: Exception) { + logError(e) + emptyList() + } + } + ytVideos[url]?.mapNotNull { + if (it.isVideoOnly || it.height <= 0) return@mapNotNull null + + ExtractorLink( + this.name, + this.name, + it.url ?: return@mapNotNull null, + "", + it.height + ) + }?.forEach(callback) + ytVideosSubtitles[url]?.mapNotNull { + SubtitleFile(it.languageTag ?: return@mapNotNull null, it.url ?: return@mapNotNull null) + }?.forEach(subtitleCallback) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Zplayer.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Zplayer.kt new file mode 100644 index 00000000..6108d2c5 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Zplayer.kt @@ -0,0 +1,58 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.apmap +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper +import com.lagradost.cloudstream3.utils.getAndUnpack + +class Zplayer: ZplayerV2() { + override var name: String = "Zplayer" + override var mainUrl: String = "https://zplayer.live" +} + +class Upstream: ZplayerV2() { + override var name: String = "Upstream" //Here 'cause works + override var mainUrl: String = "https://upstream.to" +} + +class Streamhub2: ZplayerV2() { + override var name = "Streamhub" //Here 'cause works + override var mainUrl = "https://streamhub.to" +} + +open class ZplayerV2 : ExtractorApi() { + override var name = "Zplayer V2" + override var mainUrl = "https://v2.zplayer.live" + override val requiresReferer = false + + override suspend fun getUrl(url: String, referer: String?): List { + val doc = app.get(url).document + val sources = mutableListOf() + doc.select("script").map { script -> + if (script.data().contains("eval(function(p,a,c,k,e,d)")) { + val testdata = getAndUnpack(script.data()) + val m3u8regex = Regex("((https:|http:)\\/\\/.*\\.m3u8)") + m3u8regex.findAll(testdata).map { + it.value + }.toList().apmap { urlm3u8 -> + if (urlm3u8.contains("m3u8")) { + val testurl = app.get(urlm3u8, headers = mapOf("Referer" to url)).text + if (testurl.contains("EXTM3U")) { + M3u8Helper.generateM3u8( + name, + urlm3u8, + url, + headers = mapOf("Referer" to url) + ).forEach { link -> + sources.add(link) + } + } + } + } + } + } + return sources + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/helper/AsianEmbedHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/helper/AsianEmbedHelper.kt new file mode 100644 index 00000000..e70a9474 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/helper/AsianEmbedHelper.kt @@ -0,0 +1,32 @@ +package com.lagradost.cloudstream3.extractors.helper + +import android.util.Log +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.apmap +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.loadExtractor + +class AsianEmbedHelper { + companion object { + suspend fun getUrls( + url: String, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + // Fetch links + val doc = app.get(url).document + val links = doc.select("div#list-server-more > ul > li.linkserver") + if (!links.isNullOrEmpty()) { + links.apmap { + val datavid = it.attr("data-video") ?: "" + //Log.i("AsianEmbed", "Result => (datavid) ${datavid}") + if (datavid.isNotBlank()) { + val res = loadExtractor(datavid, url, subtitleCallback, callback) + Log.i("AsianEmbed", "Result => ($res) (datavid) $datavid") + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/helper/NineAnimeHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/helper/NineAnimeHelper.kt new file mode 100644 index 00000000..be75375f --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/helper/NineAnimeHelper.kt @@ -0,0 +1,112 @@ +package com.lagradost.cloudstream3.extractors.helper + +// taken from https://github.com/saikou-app/saikou/blob/b35364c8c2a00364178a472fccf1ab72f09815b4/app/src/main/java/ani/saikou/parsers/anime/NineAnime.kt +// GNU General Public License v3.0 https://github.com/saikou-app/saikou/blob/main/LICENSE.md +object NineAnimeHelper { + private const val nineAnimeKey = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + private const val cipherKey = "kMXzgyNzT3k5dYab" + + fun encodeVrf(text: String, mainKey: String): String { + return encode( + encrypt( + cipher(mainKey, encode(text)), + nineAnimeKey + )//.replace("""=+$""".toRegex(), "") + ) + } + + fun decodeVrf(text: String, mainKey: String): String { + return decode(cipher(mainKey, decrypt(text, nineAnimeKey))) + } + + fun encrypt(input: String, key: String): String { + if (input.any { it.code > 255 }) throw Exception("illegal characters!") + var output = "" + for (i in input.indices step 3) { + val a = intArrayOf(-1, -1, -1, -1) + a[0] = input[i].code shr 2 + a[1] = (3 and input[i].code) shl 4 + if (input.length > i + 1) { + a[1] = a[1] or (input[i + 1].code shr 4) + a[2] = (15 and input[i + 1].code) shl 2 + } + if (input.length > i + 2) { + a[2] = a[2] or (input[i + 2].code shr 6) + a[3] = 63 and input[i + 2].code + } + for (n in a) { + if (n == -1) output += "=" + else { + if (n in 0..63) output += key[n] + } + } + } + return output + } + + fun cipher(key: String, text: String): String { + val arr = IntArray(256) { it } + + var u = 0 + var r: Int + arr.indices.forEach { + u = (u + arr[it] + key[it % key.length].code) % 256 + r = arr[it] + arr[it] = arr[u] + arr[u] = r + } + u = 0 + var c = 0 + + return text.indices.map { j -> + c = (c + 1) % 256 + u = (u + arr[c]) % 256 + r = arr[c] + arr[c] = arr[u] + arr[u] = r + (text[j].code xor arr[(arr[c] + arr[u]) % 256]).toChar() + }.joinToString("") + } + + @Suppress("SameParameterValue") + private fun decrypt(input: String, key: String): String { + val t = if (input.replace("""[\t\n\f\r]""".toRegex(), "").length % 4 == 0) { + input.replace("""==?$""".toRegex(), "") + } else input + if (t.length % 4 == 1 || t.contains("""[^+/0-9A-Za-z]""".toRegex())) throw Exception("bad input") + var i: Int + var r = "" + var e = 0 + var u = 0 + for (o in t.indices) { + e = e shl 6 + i = key.indexOf(t[o]) + e = e or i + u += 6 + if (24 == u) { + r += ((16711680 and e) shr 16).toChar() + r += ((65280 and e) shr 8).toChar() + r += (255 and e).toChar() + e = 0 + u = 0 + } + } + return if (12 == u) { + e = e shr 4 + r + e.toChar() + } else { + if (18 == u) { + e = e shr 2 + r += ((65280 and e) shr 8).toChar() + r += (255 and e).toChar() + } + r + } + } + + fun encode(input: String): String = + java.net.URLEncoder.encode(input, "utf-8").replace("+", "%20") + + private fun decode(input: String): String = java.net.URLDecoder.decode(input, "utf-8") +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/helper/VstreamhubHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/helper/VstreamhubHelper.kt new file mode 100644 index 00000000..5c2d6e7c --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/helper/VstreamhubHelper.kt @@ -0,0 +1,58 @@ +package com.lagradost.cloudstream3.extractors.helper + +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities +import com.lagradost.cloudstream3.utils.loadExtractor + +class VstreamhubHelper { + companion object { + private val baseUrl: String = "https://vstreamhub.com" + private val baseName: String = "Vstreamhub" + + suspend fun getUrls( + url: String, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + if (url.startsWith(baseUrl)) { + // Fetch links + val doc = app.get(url).document.select("script") + doc?.forEach { + val innerText = it?.toString() + if (!innerText.isNullOrEmpty()) { + if (innerText.contains("file:")) { + val startString = "file: " + val aa = innerText.substring(innerText.indexOf(startString)) + val linkUrl = + aa.substring(startString.length + 1, aa.indexOf("\",")).trim() + //Log.i(baseName, "Result => (linkUrl) ${linkUrl}") + val exlink = ExtractorLink( + name = "$baseName m3u8", + source = baseName, + url = linkUrl, + quality = Qualities.Unknown.value, + referer = url, + isM3u8 = true + ) + callback.invoke(exlink) + } + if (innerText.contains("playerInstance")) { + val aa = + innerText.substring(innerText.indexOf("playerInstance.addButton")) + val startString = "window.open([" + val bb = aa.substring(aa.indexOf(startString)) + val datavid = bb.substring(startString.length, bb.indexOf("]")) + .removeSurrounding("\"") + if (datavid.isNotBlank()) { + loadExtractor(datavid, url, subtitleCallback, callback) + //Log.i(baseName, "Result => (datavid) ${datavid}") + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/helper/WcoHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/helper/WcoHelper.kt new file mode 100644 index 00000000..768fa1f6 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/helper/WcoHelper.kt @@ -0,0 +1,56 @@ +package com.lagradost.cloudstream3.extractors.helper + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.AcraApplication.Companion.getKey +import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.app + +class WcoHelper { + companion object { + private const val BACKUP_KEY_DATA = "github_keys_backup" + + data class ExternalKeys( + @JsonProperty("wco_key") + val wcoKey: String? = null, + @JsonProperty("wco_cipher_key") + val wcocipher: String? = null + ) + + data class NewExternalKeys( + @JsonProperty("cipherKey") + val cipherkey: String? = null, + @JsonProperty("encryptKey") + val encryptKey: String? = null, + @JsonProperty("mainKey") + val mainKey: String? = null, + ) + + private var keys: ExternalKeys? = null + private var newKeys: NewExternalKeys? = null + private suspend fun getKeys() { + keys = keys + ?: app.get("https://raw.githubusercontent.com/reduplicated/Cloudstream/master/docs/keys.json") + .parsedSafe()?.also { setKey(BACKUP_KEY_DATA, it) } ?: getKey( + BACKUP_KEY_DATA + ) + } + + suspend fun getWcoKey(): ExternalKeys? { + getKeys() + return keys + } + + private suspend fun getNewKeys() { + newKeys = newKeys + ?: app.get("https://raw.githubusercontent.com/chekaslowakiya/BruhFlow/main/keys.json") + .parsedSafe()?.also { setKey(BACKUP_KEY_DATA, it) } ?: getKey( + BACKUP_KEY_DATA + ) + } + + suspend fun getNewWcoKey(): NewExternalKeys? { + getNewKeys() + return newKeys + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtensionManager.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtensionManager.kt deleted file mode 100644 index 497c72c1..00000000 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtensionManager.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.lagradost.cloudstream3.utils - -/* -import android.content.Context -import dalvik.system.PathClassLoader -import java.io.File -open class TestSource { - open fun doMath(): Int { - return 33 - } -} -object ExtensionManager { - fun getSourceFromDex(context: Context, pkgName: String, file: File): TestSource? { - val loader = PathClassLoader(file.absolutePath, context.classLoader) - - val obj = Class.forName(pkgName, false, loader).newInstance() - if (obj is TestSource) { - println("MATH : ${obj.doMath()}") - } - - return null - } -}*/ \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt index 16645547..de3c013a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt @@ -6,6 +6,7 @@ import com.lagradost.cloudstream3.TvType import com.lagradost.cloudstream3.USER_AGENT import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.mvvm.logError +import com.lagradost.cloudstream3.extractors.* import kotlinx.coroutines.delay import org.jsoup.Jsoup import kotlin.collections.MutableList @@ -189,7 +190,138 @@ suspend fun loadExtractor( return false } -val extractorApis: MutableList = arrayListOf() +val extractorApis: MutableList = arrayListOf( + //AllProvider(), + WcoStream(), + Vidstreamz(), + Vizcloud(), + Vizcloud2(), + VizcloudOnline(), + VizcloudXyz(), + VizcloudLive(), + VizcloudInfo(), + MwvnVizcloudInfo(), + VizcloudDigital(), + VizcloudCloud(), + VizcloudSite(), + VideoVard(), + VideovardSX(), + Mp4Upload(), + StreamTape(), + + //mixdrop extractors + MixDropBz(), + MixDropCh(), + MixDropTo(), + + MixDrop(), + + Mcloud(), + XStreamCdn(), + + StreamSB(), + StreamSB1(), + StreamSB2(), + StreamSB3(), + StreamSB4(), + StreamSB5(), + StreamSB6(), + StreamSB7(), + StreamSB8(), + StreamSB9(), + StreamSB10(), + SBfull(), + // Streamhub(), cause Streamhub2() works + Streamhub2(), + Ssbstream(), + + Fastream(), + + FEmbed(), + FeHD(), + Fplayer(), + DBfilm(), + Luxubu(), + LayarKaca(), + // WatchSB(), 'cause StreamSB.kt works + Uqload(), + Uqload1(), + Evoload(), + Evoload1(), + VoeExtractor(), + // UpstreamExtractor(), GenericM3U8.kt works + + Tomatomatela(), + Cinestart(), + OkRu(), + OkRuHttps(), + + // dood extractors + DoodCxExtractor(), + DoodPmExtractor(), + DoodToExtractor(), + DoodSoExtractor(), + DoodLaExtractor(), + DoodWsExtractor(), + DoodShExtractor(), + DoodWatchExtractor(), + + AsianLoad(), + + // GenericM3U8(), + Jawcloud(), + Zplayer(), + ZplayerV2(), + Upstream(), + + Maxstream(), + Tantifilm(), + Userload(), + Supervideo(), + GuardareStream(), + + // StreamSB.kt works + // SBPlay(), + // SBPlay1(), + // SBPlay2(), + + PlayerVoxzer(), + + BullStream(), + GMPlayer(), + + Blogger(), + Solidfiles(), + YourUpload(), + + Hxfile(), + KotakAnimeid(), + Neonime8n(), + Neonime7n(), + Yufiles(), + Aico(), + + JWPlayer(), + Meownime(), + DesuArcg(), + DesuOdchan(), + DesuOdvip(), + DesuDrive(), + + Filesim(), + Linkbox(), + Acefile(), + SpeedoStream(), + + YoutubeExtractor(), + YoutubeShortLinkExtractor(), + YoutubeMobileExtractor(), + YoutubeNoCookieExtractor(), + Streamlare(), + VidSrcExtractor(), + VidSrcExtractor2(), +) + fun getExtractorApiFromName(name: String): ExtractorApi { for (api in extractorApis) {