mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
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 <Sofie99@gmail.com>
This commit is contained in:
parent
dfd6ce7651
commit
6f3a8c1cd2
5 changed files with 120 additions and 30 deletions
|
@ -7,7 +7,7 @@ import com.lagradost.cloudstream3.extractors.helper.AesHelper.cryptoAESHandler
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils
|
import com.lagradost.cloudstream3.utils.AppUtils
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.Qualities
|
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||||
|
|
||||||
class Moviesapi : Chillx() {
|
class Moviesapi : Chillx() {
|
||||||
override val name = "Moviesapi"
|
override val name = "Moviesapi"
|
||||||
|
@ -23,13 +23,14 @@ class Watchx : Chillx() {
|
||||||
override val name = "Watchx"
|
override val name = "Watchx"
|
||||||
override val mainUrl = "https://watchx.top"
|
override val mainUrl = "https://watchx.top"
|
||||||
}
|
}
|
||||||
|
|
||||||
open class Chillx : ExtractorApi() {
|
open class Chillx : ExtractorApi() {
|
||||||
override val name = "Chillx"
|
override val name = "Chillx"
|
||||||
override val mainUrl = "https://chillx.top"
|
override val mainUrl = "https://chillx.top"
|
||||||
override val requiresReferer = true
|
override val requiresReferer = true
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val KEY = "eN0^>\$^#M08uFv%c"
|
private const val KEY = "tSIsE8FgpRkv3QQQ"
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getUrl(
|
override suspend fun getUrl(
|
||||||
|
@ -38,10 +39,14 @@ open class Chillx : ExtractorApi() {
|
||||||
subtitleCallback: (SubtitleFile) -> Unit,
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
callback: (ExtractorLink) -> Unit
|
callback: (ExtractorLink) -> Unit
|
||||||
) {
|
) {
|
||||||
val master = Regex("MasterJS\\s*=\\s*'([^']+)").find(
|
val master = Regex("\\s*=\\s*'([^']+)").find(
|
||||||
app.get(
|
app.get(
|
||||||
url,
|
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
|
).text
|
||||||
)?.groupValues?.get(1)
|
)?.groupValues?.get(1)
|
||||||
val decrypt = cryptoAESHandler(master ?: return, KEY.toByteArray(), false)?.replace("\\", "") ?: throw ErrorLoadingException("failed to decrypt")
|
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,
|
"Origin" to mainUrl,
|
||||||
)
|
)
|
||||||
|
|
||||||
callback.invoke(
|
M3u8Helper.generateM3u8(
|
||||||
ExtractorLink(
|
name,
|
||||||
name,
|
source ?: return,
|
||||||
name,
|
"$mainUrl/",
|
||||||
source ?: return,
|
headers = headers
|
||||||
"$mainUrl/",
|
).forEach(callback)
|
||||||
Qualities.P1080.value,
|
|
||||||
headers = headers,
|
|
||||||
isM3u8 = true
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
AppUtils.tryParseJson<List<Tracks>>("[$tracks]")
|
AppUtils.tryParseJson<List<Tracks>>("[$tracks]")
|
||||||
?.filter { it.kind == "captions" }?.map { track ->
|
?.filter { it.kind == "captions" }?.map { track ->
|
||||||
|
|
|
@ -7,7 +7,6 @@ import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
|
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
|
||||||
import com.lagradost.cloudstream3.utils.Qualities
|
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
|
||||||
open class Dailymotion : ExtractorApi() {
|
open class Dailymotion : ExtractorApi() {
|
||||||
|
@ -27,21 +26,16 @@ open class Dailymotion : ExtractorApi() {
|
||||||
callback: (ExtractorLink) -> Unit
|
callback: (ExtractorLink) -> Unit
|
||||||
) {
|
) {
|
||||||
val embedUrl = getEmbedUrl(url) ?: return
|
val embedUrl = getEmbedUrl(url) ?: return
|
||||||
val doc = app.get(embedUrl).document
|
val req = app.get(embedUrl)
|
||||||
val prefix = "window.__PLAYER_CONFIG__ = "
|
val prefix = "window.__PLAYER_CONFIG__ = "
|
||||||
val configStr = doc.selectFirst("script:containsData($prefix)")?.data() ?: return
|
val configStr = req.document.selectFirst("script:containsData($prefix)")?.data() ?: return
|
||||||
val config = tryParseJson<Config>(configStr.substringAfter(prefix)) ?: return
|
val config = tryParseJson<Config>(configStr.substringAfter(prefix).substringBefore(";").trim()) ?: return
|
||||||
val id = getVideoId(embedUrl) ?: return
|
val id = getVideoId(embedUrl) ?: return
|
||||||
val dmV1st = config.dmInternalData.v1st
|
val dmV1st = config.dmInternalData.v1st
|
||||||
val dmTs = config.dmInternalData.ts
|
val dmTs = config.dmInternalData.ts
|
||||||
val metaDataUrl =
|
val embedder = config.context.embedder
|
||||||
"$mainUrl/player/metadata/video/$id?locale=en&dmV1st=$dmV1st&dmTs=$dmTs&is_native_app=0"
|
val metaDataUrl = "$mainUrl/player/metadata/video/$id?embedder=$embedder&locale=en-US&dmV1st=$dmV1st&dmTs=$dmTs&is_native_app=0"
|
||||||
val cookies = mapOf(
|
val metaData = app.get(metaDataUrl, referer = embedUrl, cookies = req.cookies)
|
||||||
"v1st" to dmV1st,
|
|
||||||
"dmvk" to config.context.dmvk,
|
|
||||||
"ts" to dmTs.toString()
|
|
||||||
)
|
|
||||||
val metaData = app.get(metaDataUrl, referer = embedUrl, cookies = cookies)
|
|
||||||
.parsedSafe<MetaData>() ?: return
|
.parsedSafe<MetaData>() ?: return
|
||||||
metaData.qualities.forEach { (_, video) ->
|
metaData.qualities.forEach { (_, video) ->
|
||||||
video.forEach {
|
video.forEach {
|
||||||
|
@ -84,13 +78,13 @@ open class Dailymotion : ExtractorApi() {
|
||||||
)
|
)
|
||||||
|
|
||||||
data class InternalData(
|
data class InternalData(
|
||||||
val ts: Int,
|
val ts: Long,
|
||||||
val v1st: String
|
val v1st: String
|
||||||
)
|
)
|
||||||
|
|
||||||
data class Context(
|
data class Context(
|
||||||
@JsonProperty("access_token") val accessToken: String?,
|
@JsonProperty("access_token") val accessToken: String?,
|
||||||
val dmvk: String,
|
val embedder: String?,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class MetaData(
|
data class MetaData(
|
||||||
|
|
|
@ -18,7 +18,8 @@ open class Linkbox : ExtractorApi() {
|
||||||
subtitleCallback: (SubtitleFile) -> Unit,
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
callback: (ExtractorLink) -> 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<Responses>()?.data?.itemId
|
||||||
app.get("$mainUrl/api/file/detail?itemId=$id", referer = url)
|
app.get("$mainUrl/api/file/detail?itemId=$id", referer = url)
|
||||||
.parsedSafe<Responses>()?.data?.itemInfo?.resolutionList?.map { link ->
|
.parsedSafe<Responses>()?.data?.itemInfo?.resolutionList?.map { link ->
|
||||||
callback.invoke(
|
callback.invoke(
|
||||||
|
@ -44,6 +45,7 @@ open class Linkbox : ExtractorApi() {
|
||||||
|
|
||||||
data class Data(
|
data class Data(
|
||||||
@JsonProperty("itemInfo") val itemInfo: ItemInfo? = null,
|
@JsonProperty("itemInfo") val itemInfo: ItemInfo? = null,
|
||||||
|
@JsonProperty("itemId") val itemId: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class Responses(
|
data class Responses(
|
||||||
|
|
|
@ -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<Response>()?.result?.sources
|
||||||
|
|
||||||
|
res?.map {
|
||||||
|
M3u8Helper.generateM3u8(
|
||||||
|
this.name,
|
||||||
|
it.file ?: return@map,
|
||||||
|
"$mainUrl/"
|
||||||
|
).forEach(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun getKeys(): List<String> {
|
||||||
|
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>): 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<Sources>? = arrayListOf(),
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Response(
|
||||||
|
@JsonProperty("result") val result: Result? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
|
@ -167,6 +167,7 @@ import com.lagradost.cloudstream3.extractors.Vidgomunimesb
|
||||||
import com.lagradost.cloudstream3.extractors.Vidmoly
|
import com.lagradost.cloudstream3.extractors.Vidmoly
|
||||||
import com.lagradost.cloudstream3.extractors.Vidmolyme
|
import com.lagradost.cloudstream3.extractors.Vidmolyme
|
||||||
import com.lagradost.cloudstream3.extractors.Vido
|
import com.lagradost.cloudstream3.extractors.Vido
|
||||||
|
import com.lagradost.cloudstream3.extractors.Vidplay
|
||||||
import com.lagradost.cloudstream3.extractors.Vidstreamz
|
import com.lagradost.cloudstream3.extractors.Vidstreamz
|
||||||
import com.lagradost.cloudstream3.extractors.Vizcloud
|
import com.lagradost.cloudstream3.extractors.Vizcloud
|
||||||
import com.lagradost.cloudstream3.extractors.Vizcloud2
|
import com.lagradost.cloudstream3.extractors.Vizcloud2
|
||||||
|
@ -793,6 +794,7 @@ val extractorApis: MutableList<ExtractorApi> = arrayListOf(
|
||||||
VidSrcExtractor2(),
|
VidSrcExtractor2(),
|
||||||
PlayLtXyz(),
|
PlayLtXyz(),
|
||||||
AStreamHub(),
|
AStreamHub(),
|
||||||
|
Vidplay(),
|
||||||
|
|
||||||
Cda(),
|
Cda(),
|
||||||
Dailymotion(),
|
Dailymotion(),
|
||||||
|
|
Loading…
Reference in a new issue