mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
updating vidplay encryption method
This commit is contained in:
parent
a157115cfa
commit
3e102ad07a
2 changed files with 49 additions and 58 deletions
|
@ -40,7 +40,7 @@ class VidSrcTo : ExtractorApi() {
|
||||||
val finalUrl = DecryptUrl(embedRes.result.encUrl)
|
val finalUrl = DecryptUrl(embedRes.result.encUrl)
|
||||||
if(finalUrl.equals(embedRes.result.encUrl)) return@amap
|
if(finalUrl.equals(embedRes.result.encUrl)) return@amap
|
||||||
when (source.title) {
|
when (source.title) {
|
||||||
"Vidplay" -> AnyVidplay(finalUrl.substringBefore("/e/")).getUrl(finalUrl, referer, subtitleCallback, callback)
|
"F2Cloud" -> AnyVidplay(finalUrl.substringBefore("/e/")).getUrl(finalUrl, referer, subtitleCallback, callback)
|
||||||
"Filemoon" -> FileMoon().getUrl(finalUrl, referer, subtitleCallback, callback)
|
"Filemoon" -> FileMoon().getUrl(finalUrl, referer, subtitleCallback, callback)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
package com.lagradost.cloudstream3.extractors
|
package com.lagradost.cloudstream3.extractors
|
||||||
|
|
||||||
|
import android.util.Base64
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.lagradost.cloudstream3.ErrorLoadingException
|
import com.lagradost.cloudstream3.ErrorLoadingException
|
||||||
import com.lagradost.cloudstream3.SubtitleFile
|
import com.lagradost.cloudstream3.SubtitleFile
|
||||||
import com.lagradost.cloudstream3.app
|
import com.lagradost.cloudstream3.app
|
||||||
import com.lagradost.cloudstream3.base64Encode
|
import com.lagradost.cloudstream3.base64Encode
|
||||||
|
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
|
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||||
|
import java.net.URLDecoder
|
||||||
import javax.crypto.Cipher
|
import javax.crypto.Cipher
|
||||||
import javax.crypto.spec.SecretKeySpec
|
import javax.crypto.spec.SecretKeySpec
|
||||||
import kotlin.run
|
import kotlin.run
|
||||||
|
@ -58,83 +61,71 @@ open class Vidplay : ExtractorApi() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getUrl(
|
override suspend fun getUrl(
|
||||||
url: String,
|
url: String,
|
||||||
referer: String?,
|
referer: String?,
|
||||||
subtitleCallback: (SubtitleFile) -> Unit,
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
callback: (ExtractorLink) -> Unit
|
callback: (ExtractorLink) -> Unit
|
||||||
) {
|
) {
|
||||||
|
val myKeys = getKeys()
|
||||||
|
val domain = url.substringBefore("/e/")
|
||||||
val id = url.substringBefore("?").substringAfterLast("/")
|
val id = url.substringBefore("?").substringAfterLast("/")
|
||||||
val encodeId = encodeId(id, getKeys())
|
val encodedId = encode(id, myKeys.get(0))
|
||||||
val mediaUrl = callFutoken(encodeId, url)
|
val t = url.substringAfter("t=").substringBefore("&")
|
||||||
val res = app.get(
|
val h = encode(id, myKeys.get(1))
|
||||||
"$mediaUrl", headers = mapOf(
|
val mediaUrl = "$domain/mediainfo/$encodedId?t=$t&h=$h"
|
||||||
"Accept" to "application/json, text/javascript, */*; q=0.01",
|
val encodedRes =
|
||||||
"X-Requested-With" to "XMLHttpRequest",
|
app.get("$mediaUrl").parsedSafe<Response>()?.result
|
||||||
), referer = url
|
?: throw Exception("Unable to fetch link")
|
||||||
).parsedSafe<Response>()?.result
|
val decodedRes = decode(encodedRes, myKeys.get(2))
|
||||||
|
val res = tryParseJson<Result>(decodedRes)
|
||||||
res?.sources?.map {
|
res?.sources?.map {
|
||||||
M3u8Helper.generateM3u8(
|
M3u8Helper.generateM3u8(this.name, it.file ?: return@map, "$mainUrl/")
|
||||||
this.name,
|
.forEach(callback)
|
||||||
it.file ?: return@map,
|
|
||||||
"$mainUrl/"
|
|
||||||
).forEach(callback)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res?.tracks?.filter { it.kind == "captions" }?.map {
|
res?.tracks?.filter { it.kind == "captions" }?.map {
|
||||||
subtitleCallback.invoke(
|
subtitleCallback.invoke(SubtitleFile(it.label ?: return@map, it.file ?: return@map))
|
||||||
SubtitleFile(it.label ?: return@map, it.file ?: return@map)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun callFutoken(id: String, url: String): String? {
|
private fun encode(input: String, key: String): String {
|
||||||
val script = app.get("$mainUrl/futoken", referer = url).text
|
val rc4Key = SecretKeySpec(key.toByteArray(), "RC4")
|
||||||
val k = "k='(\\S+)'".toRegex().find(script)?.groupValues?.get(1) ?: return null
|
val cipher = Cipher.getInstance("RC4")
|
||||||
val a = mutableListOf(k)
|
cipher.init(Cipher.DECRYPT_MODE, rc4Key, cipher.parameters)
|
||||||
for (i in id.indices) {
|
|
||||||
a.add((k[i % k.length].code + id[i].code).toString())
|
var vrf = cipher.doFinal(input.toByteArray())
|
||||||
}
|
vrf = Base64.encode(vrf, Base64.URL_SAFE or Base64.NO_WRAP)
|
||||||
return "$mainUrl/mediainfo/${a.joinToString(",")}?${url.substringAfter("?")}"
|
val stringVrf = java.net.URLEncoder.encode(vrf.toString(Charsets.UTF_8), "utf-8")
|
||||||
|
|
||||||
|
return stringVrf
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun encodeId(id: String, keyList: List<String>): String {
|
fun decode(input: String, key: String): String {
|
||||||
val cipher1 = Cipher.getInstance("RC4")
|
var vrf = input.toByteArray()
|
||||||
val cipher2 = Cipher.getInstance("RC4")
|
vrf = Base64.decode(vrf, Base64.URL_SAFE)
|
||||||
cipher1.init(
|
|
||||||
Cipher.DECRYPT_MODE,
|
val rc4Key = SecretKeySpec(key.toByteArray(), "RC4")
|
||||||
SecretKeySpec(keyList[0].toByteArray(), "RC4"),
|
val cipher = Cipher.getInstance("RC4")
|
||||||
cipher1.parameters
|
cipher.init(Cipher.DECRYPT_MODE, rc4Key, cipher.parameters)
|
||||||
)
|
vrf = cipher.doFinal(vrf)
|
||||||
cipher2.init(
|
|
||||||
Cipher.DECRYPT_MODE,
|
return URLDecoder.decode(vrf.toString(Charsets.UTF_8), "utf-8")
|
||||||
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 Tracks(
|
data class Tracks(
|
||||||
@JsonProperty("file") val file: String? = null,
|
@JsonProperty("file") val file: String? = null,
|
||||||
@JsonProperty("label") val label: String? = null,
|
@JsonProperty("label") val label: String? = null,
|
||||||
@JsonProperty("kind") val kind: String? = null,
|
@JsonProperty("kind") val kind: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class Sources(
|
data class Sources(
|
||||||
@JsonProperty("file") val file: String? = null,
|
@JsonProperty("file") val file: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class Result(
|
data class Result(
|
||||||
@JsonProperty("sources") val sources: ArrayList<Sources>? = arrayListOf(),
|
@JsonProperty("sources") val sources: ArrayList<Sources>? = arrayListOf(),
|
||||||
@JsonProperty("tracks") val tracks: ArrayList<Tracks>? = arrayListOf(),
|
@JsonProperty("tracks") val tracks: ArrayList<Tracks>? = arrayListOf(),
|
||||||
)
|
|
||||||
|
|
||||||
data class Response(
|
|
||||||
@JsonProperty("result") val result: Result? = null,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class Response(@JsonProperty("result") val result: String? = null)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue