From 6f3a8c1cd22e7e964ffa9206773d76fc26956372 Mon Sep 17 00:00:00 2001 From: Sofie <117321707+Sofie99@users.noreply.github.com> Date: Fri, 8 Dec 2023 23:28:16 +0700 Subject: [PATCH] extractor: added vidplay and fix few extractors (#795) * extractor: added Vidplay * fix id * fix Chillx * fix Linkbox * update m3u8helper in chillx * fix Dailymotion --------- Co-authored-by: Sofie99 --- .../cloudstream3/extractors/Chillx.kt | 30 +++--- .../cloudstream3/extractors/Dailymotion.kt | 22 ++--- .../cloudstream3/extractors/Linkbox.kt | 4 +- .../cloudstream3/extractors/Vidplay.kt | 92 +++++++++++++++++++ .../cloudstream3/utils/ExtractorApi.kt | 2 + 5 files changed, 120 insertions(+), 30 deletions(-) create mode 100644 app/src/main/java/com/lagradost/cloudstream3/extractors/Vidplay.kt diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Chillx.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Chillx.kt index a9fafc39..cb234c5c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/extractors/Chillx.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Chillx.kt @@ -7,7 +7,7 @@ import com.lagradost.cloudstream3.extractors.helper.AesHelper.cryptoAESHandler import com.lagradost.cloudstream3.utils.AppUtils 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 Moviesapi : Chillx() { override val name = "Moviesapi" @@ -23,13 +23,14 @@ class Watchx : Chillx() { override val name = "Watchx" override val mainUrl = "https://watchx.top" } + open class Chillx : ExtractorApi() { override val name = "Chillx" override val mainUrl = "https://chillx.top" override val requiresReferer = true companion object { - private const val KEY = "eN0^>\$^#M08uFv%c" + private const val KEY = "tSIsE8FgpRkv3QQQ" } override suspend fun getUrl( @@ -38,10 +39,14 @@ open class Chillx : ExtractorApi() { subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { - val master = Regex("MasterJS\\s*=\\s*'([^']+)").find( + val master = Regex("\\s*=\\s*'([^']+)").find( app.get( url, - referer = referer + referer = referer ?: "", + headers = mapOf( + "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", + "Accept-Language" to "en-US,en;q=0.5", + ) ).text )?.groupValues?.get(1) val decrypt = cryptoAESHandler(master ?: return, KEY.toByteArray(), false)?.replace("\\", "") ?: throw ErrorLoadingException("failed to decrypt") @@ -59,17 +64,12 @@ open class Chillx : ExtractorApi() { "Origin" to mainUrl, ) - callback.invoke( - ExtractorLink( - name, - name, - source ?: return, - "$mainUrl/", - Qualities.P1080.value, - headers = headers, - isM3u8 = true - ) - ) + M3u8Helper.generateM3u8( + name, + source ?: return, + "$mainUrl/", + headers = headers + ).forEach(callback) AppUtils.tryParseJson>("[$tracks]") ?.filter { it.kind == "captions" }?.map { track -> diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Dailymotion.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Dailymotion.kt index 4b7cb19f..0df93dc5 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/extractors/Dailymotion.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Dailymotion.kt @@ -7,7 +7,6 @@ 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.Companion.generateM3u8 -import com.lagradost.cloudstream3.utils.Qualities import java.net.URL open class Dailymotion : ExtractorApi() { @@ -27,21 +26,16 @@ open class Dailymotion : ExtractorApi() { callback: (ExtractorLink) -> Unit ) { val embedUrl = getEmbedUrl(url) ?: return - val doc = app.get(embedUrl).document + val req = app.get(embedUrl) val prefix = "window.__PLAYER_CONFIG__ = " - val configStr = doc.selectFirst("script:containsData($prefix)")?.data() ?: return - val config = tryParseJson(configStr.substringAfter(prefix)) ?: return + val configStr = req.document.selectFirst("script:containsData($prefix)")?.data() ?: return + val config = tryParseJson(configStr.substringAfter(prefix).substringBefore(";").trim()) ?: return val id = getVideoId(embedUrl) ?: return val dmV1st = config.dmInternalData.v1st val dmTs = config.dmInternalData.ts - val metaDataUrl = - "$mainUrl/player/metadata/video/$id?locale=en&dmV1st=$dmV1st&dmTs=$dmTs&is_native_app=0" - val cookies = mapOf( - "v1st" to dmV1st, - "dmvk" to config.context.dmvk, - "ts" to dmTs.toString() - ) - val metaData = app.get(metaDataUrl, referer = embedUrl, cookies = cookies) + val embedder = config.context.embedder + val metaDataUrl = "$mainUrl/player/metadata/video/$id?embedder=$embedder&locale=en-US&dmV1st=$dmV1st&dmTs=$dmTs&is_native_app=0" + val metaData = app.get(metaDataUrl, referer = embedUrl, cookies = req.cookies) .parsedSafe() ?: return metaData.qualities.forEach { (_, video) -> video.forEach { @@ -84,13 +78,13 @@ open class Dailymotion : ExtractorApi() { ) data class InternalData( - val ts: Int, + val ts: Long, val v1st: String ) data class Context( @JsonProperty("access_token") val accessToken: String?, - val dmvk: String, + val embedder: String?, ) data class MetaData( diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Linkbox.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Linkbox.kt index 6a4945bb..04a9a6ac 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/extractors/Linkbox.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Linkbox.kt @@ -18,7 +18,8 @@ open class Linkbox : ExtractorApi() { subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { - val id = Regex("""(?:/f/|/file/|\?id=)(\w+)""").find(url)?.groupValues?.get(1) + val token = Regex("""(?:/f/|/file/|\?id=)(\w+)""").find(url)?.groupValues?.get(1) + val id = app.get("$mainUrl/api/file/share_out_list/?sortField=utime&sortAsc=0&pageNo=1&pageSize=50&shareToken=$token").parsedSafe()?.data?.itemId app.get("$mainUrl/api/file/detail?itemId=$id", referer = url) .parsedSafe()?.data?.itemInfo?.resolutionList?.map { link -> callback.invoke( @@ -44,6 +45,7 @@ open class Linkbox : ExtractorApi() { data class Data( @JsonProperty("itemInfo") val itemInfo: ItemInfo? = null, + @JsonProperty("itemId") val itemId: String? = null, ) data class Responses( diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Vidplay.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Vidplay.kt new file mode 100644 index 00000000..6e3e16a2 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Vidplay.kt @@ -0,0 +1,92 @@ +package com.lagradost.cloudstream3.extractors + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.base64Encode +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper +import javax.crypto.Cipher +import javax.crypto.spec.SecretKeySpec + +// Code found in https://github.com/Claudemirovsky/worstsource-keys +// special credits to @Claudemirovsky for providing key +open class Vidplay : ExtractorApi() { + override val name = "Vidplay" + override val mainUrl = "https://vidplay.site" + override val requiresReferer = true + + override suspend fun getUrl( + url: String, + referer: String?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val id = url.substringBefore("?").substringAfterLast("/") + val encodeId = encodeId(id, getKeys()) + val mediaUrl = callFutoken(encodeId, url) + val res = app.get( + "$mediaUrl", headers = mapOf( + "Accept" to "application/json, text/javascript, */*; q=0.01", + "X-Requested-With" to "XMLHttpRequest", + ), referer = url + ).parsedSafe()?.result?.sources + + res?.map { + M3u8Helper.generateM3u8( + this.name, + it.file ?: return@map, + "$mainUrl/" + ).forEach(callback) + } + + } + + private suspend fun getKeys(): List { + return app.get("https://raw.githubusercontent.com/Claudemirovsky/worstsource-keys/keys/keys.json") + .parsed() + } + + private suspend fun callFutoken(id: String, url: String): String? { + val script = app.get("$mainUrl/futoken").text + val k = "k='(\\S+)'".toRegex().find(script)?.groupValues?.get(1) ?: return null + val a = mutableListOf(k) + for (i in id.indices) { + a.add((k[i % k.length].code + id[i].code).toString()) + } + return "$mainUrl/mediainfo/${a.joinToString(",")}?${url.substringAfter("?")}" + } + + private fun encodeId(id: String, keyList: List): String { + val cipher1 = Cipher.getInstance("RC4") + val cipher2 = Cipher.getInstance("RC4") + cipher1.init( + Cipher.DECRYPT_MODE, + SecretKeySpec(keyList[0].toByteArray(), "RC4"), + cipher1.parameters + ) + cipher2.init( + Cipher.DECRYPT_MODE, + SecretKeySpec(keyList[1].toByteArray(), "RC4"), + cipher2.parameters + ) + var input = id.toByteArray() + input = cipher1.doFinal(input) + input = cipher2.doFinal(input) + return base64Encode(input).replace("/", "_") + } + + data class Sources( + @JsonProperty("file") val file: String? = null, + ) + + data class Result( + @JsonProperty("sources") val sources: ArrayList? = arrayListOf(), + ) + + data class Response( + @JsonProperty("result") val result: Result? = 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 923c3531..2e9dd691 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt @@ -167,6 +167,7 @@ import com.lagradost.cloudstream3.extractors.Vidgomunimesb import com.lagradost.cloudstream3.extractors.Vidmoly import com.lagradost.cloudstream3.extractors.Vidmolyme import com.lagradost.cloudstream3.extractors.Vido +import com.lagradost.cloudstream3.extractors.Vidplay import com.lagradost.cloudstream3.extractors.Vidstreamz import com.lagradost.cloudstream3.extractors.Vizcloud import com.lagradost.cloudstream3.extractors.Vizcloud2 @@ -793,6 +794,7 @@ val extractorApis: MutableList = arrayListOf( VidSrcExtractor2(), PlayLtXyz(), AStreamHub(), + Vidplay(), Cda(), Dailymotion(),