From ae137f4a3468c2c0422b20a9f0b69fc6882a6ffb Mon Sep 17 00:00:00 2001 From: Hexated <37908684+hexated@users.noreply.github.com> Date: Mon, 5 Sep 2022 06:13:17 +0700 Subject: [PATCH] added extractors (#86) --- .../cloudstream3/extractors/Embedgram.kt | 37 +++++++++ .../cloudstream3/extractors/Mvidoo.kt | 47 +++++++++++ .../cloudstream3/extractors/Streamplay.kt | 81 +++++++++++++++++++ .../extractors/UpstreamExtractor.kt | 37 ++++----- .../cloudstream3/extractors/XStreamCdn.kt | 5 ++ .../cloudstream3/utils/ExtractorApi.kt | 8 +- 6 files changed, 195 insertions(+), 20 deletions(-) create mode 100644 app/src/main/java/com/lagradost/cloudstream3/extractors/Embedgram.kt create mode 100644 app/src/main/java/com/lagradost/cloudstream3/extractors/Mvidoo.kt create mode 100644 app/src/main/java/com/lagradost/cloudstream3/extractors/Streamplay.kt diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Embedgram.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Embedgram.kt new file mode 100644 index 00000000..35569663 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Embedgram.kt @@ -0,0 +1,37 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.getQualityFromName +import com.lagradost.cloudstream3.utils.httpsify + +class Embedgram : ExtractorApi() { + override val name = "Embedgram" + override val mainUrl = "https://embedgram.com" + override val requiresReferer = true + + override suspend fun getUrl( + url: String, + referer: String?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val document = app.get(url, referer = referer).document + val link = document.select("video source:last-child").attr("src") + val quality = document.select("video source:last-child").attr("title") + callback.invoke( + ExtractorLink( + this.name, + this.name, + httpsify(link), + "$mainUrl/", + getQualityFromName(quality), + headers = mapOf( + "Range" to "bytes=0-" + ) + ) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Mvidoo.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Mvidoo.kt new file mode 100644 index 00000000..c00df942 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Mvidoo.kt @@ -0,0 +1,47 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities + +class Mvidoo : ExtractorApi() { + override val name = "Mvidoo" + override val mainUrl = "https://mvidoo.com" + override val requiresReferer = true + + private fun String.decodeHex(): String { + require(length % 2 == 0) { "Must have an even length" } + return String( + chunked(2) + .map { it.toInt(16).toByte() } + .toByteArray() + ) + } + + override suspend fun getUrl( + url: String, + referer: String?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val document = app.get(url, referer = referer).text + val data = Regex("""\{var\s*[^\s]+\s*=\s*(\[[^]]+])""").find(document)?.groupValues?.get(1) + ?.removeSurrounding("[", "]")?.replace("\"", "")?.replace("\\x", "")?.split(",")?.map { it.decodeHex() }?.reversed()?.joinToString("") ?: return + Regex("source\\s*src=\"([^\"]+)").find(data)?.groupValues?.get(1)?.let { link -> + callback.invoke( + ExtractorLink( + this.name, + this.name, + link, + "$mainUrl/", + Qualities.Unknown.value, + headers = mapOf( + "Range" to "bytes=0-" + ) + ) + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Streamplay.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Streamplay.kt new file mode 100644 index 00000000..3f5e5bd6 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Streamplay.kt @@ -0,0 +1,81 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.APIHolder.getCaptchaToken +import com.lagradost.cloudstream3.ErrorLoadingException +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.* +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson +import java.net.URI + +class Streamplay : ExtractorApi() { + override val name = "Streamplay" + override val mainUrl = "https://streamplay.to" + override val requiresReferer = true + + override suspend fun getUrl( + url: String, + referer: String?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val request = app.get(url, referer = referer) + val redirectUrl = request.url + val mainServer = URI(redirectUrl).let { + "${it.scheme}://${it.host}" + } + val key = redirectUrl.substringAfter("embed-").substringBefore(".html") + val token = + request.document.select("script").find { it.data().contains("sitekey:") }?.data() + ?.substringAfterLast("sitekey: '")?.substringBefore("',")?.let { captchaKey -> + getCaptchaToken( + redirectUrl, + captchaKey, + referer = "$mainServer/" + ) + } ?: throw ErrorLoadingException("can't bypass captcha") + app.post( + "$mainServer/player-$key-488x286.html", data = mapOf( + "op" to "embed", + "token" to token + ), + referer = redirectUrl, + headers = mapOf( + "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", + "Content-Type" to "application/x-www-form-urlencoded" + ) + ).document.select("script").find { script -> + script.data().contains("eval(function(p,a,c,k,e,d)") + }?.let { + val data = getAndUnpack(it.data()).substringAfter("sources=[").substringBefore(",desc") + .replace("file", "\"file\"") + .replace("label", "\"label\"") + tryParseJson>("[$data}]")?.map { res -> + callback.invoke( + ExtractorLink( + this.name, + this.name, + res.file ?: return@map null, + "$mainServer/", + when (res.label) { + "HD" -> Qualities.P720.value + "SD" -> Qualities.P480.value + else -> Qualities.Unknown.value + }, + headers = mapOf( + "Range" to "bytes=0-" + ) + ) + ) + } + } + + } + + data class Source( + @JsonProperty("file") val file: String? = null, + @JsonProperty("label") val label: String? = null, + ) + +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/UpstreamExtractor.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/UpstreamExtractor.kt index 79c657b6..1eb384c4 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/extractors/UpstreamExtractor.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/UpstreamExtractor.kt @@ -1,19 +1,23 @@ package com.lagradost.cloudstream3.extractors +import com.lagradost.cloudstream3.SubtitleFile 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.M3u8Helper -class UpstreamExtractor: ExtractorApi() { - override val name: String = "Upstream.to" +class UpstreamExtractor : ExtractorApi() { + override val name: String = "Upstream" 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 + override suspend fun getUrl( + url: String, + referer: String?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { //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)") @@ -30,7 +34,9 @@ class UpstreamExtractor: ExtractorApi() { domName = "${part}.${domName}" } domName.trimEnd('.') - } else { "" } + } else { + "" + } } false -> "" } @@ -42,18 +48,13 @@ class UpstreamExtractor: ExtractorApi() { 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 - ) - ) + M3u8Helper.generateM3u8( + this.name, + linkUrl, + "$mainUrl/", + headers = mapOf("Origin" to mainUrl) + ).forEach(callback) } } - return sources } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/XStreamCdn.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/XStreamCdn.kt index 75a7270b..9e3585ae 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/extractors/XStreamCdn.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/XStreamCdn.kt @@ -7,6 +7,11 @@ import com.lagradost.cloudstream3.utils.ExtractorApi import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.getQualityFromName +class FEnet: XStreamCdn() { + override val name: String = "FEnet" + override val mainUrl: String = "https://fembed.net" +} + class Rasacintaku: XStreamCdn() { override val mainUrl: String = "https://rasa-cintaku-semakin-berantai.xyz" } 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 ec7d9cc2..7a65df30 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt @@ -238,7 +238,7 @@ val extractorApis: MutableList = arrayListOf( Vidgomunime(), Fastream(), - + FEmbed(), FeHD(), Fplayer(), @@ -246,13 +246,14 @@ val extractorApis: MutableList = arrayListOf( Luxubu(), LayarKaca(), Rasacintaku(), + FEnet(), // WatchSB(), 'cause StreamSB.kt works Uqload(), Uqload1(), Evoload(), Evoload1(), VoeExtractor(), - // UpstreamExtractor(), GenericM3U8.kt works + UpstreamExtractor(), Tomatomatela(), Cinestart(), @@ -316,6 +317,9 @@ val extractorApis: MutableList = arrayListOf( Acefile(), SpeedoStream(), Zorofile(), + Embedgram(), + Mvidoo(), + Streamplay(), YoutubeExtractor(), YoutubeShortLinkExtractor(),