2023-12-08 16:28:16 +00:00
|
|
|
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
|
|
|
|
|
2024-01-17 21:30:20 +00:00
|
|
|
// Code found in https://github.com/KillerDogeEmpire/vidplay-keys
|
|
|
|
// special credits to @KillerDogeEmpire for providing key
|
2024-01-03 09:24:12 +00:00
|
|
|
|
2024-04-16 04:05:50 +00:00
|
|
|
class AnyVidplay(hostUrl: String) : Vidplay() {
|
|
|
|
override val mainUrl = hostUrl
|
|
|
|
}
|
|
|
|
|
2024-01-03 09:24:12 +00:00
|
|
|
class MyCloud : Vidplay() {
|
|
|
|
override val name = "MyCloud"
|
|
|
|
override val mainUrl = "https://mcloud.bz"
|
|
|
|
}
|
|
|
|
|
|
|
|
class VidplayOnline : Vidplay() {
|
|
|
|
override val mainUrl = "https://vidplay.online"
|
|
|
|
}
|
|
|
|
|
2023-12-08 16:28:16 +00:00
|
|
|
open class Vidplay : ExtractorApi() {
|
|
|
|
override val name = "Vidplay"
|
|
|
|
override val mainUrl = "https://vidplay.site"
|
|
|
|
override val requiresReferer = true
|
2024-01-03 09:24:12 +00:00
|
|
|
open val key =
|
2024-01-17 21:30:20 +00:00
|
|
|
"https://raw.githubusercontent.com/KillerDogeEmpire/vidplay-keys/keys/keys.json"
|
2023-12-08 16:28:16 +00:00
|
|
|
|
|
|
|
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
|
2024-01-05 16:08:48 +00:00
|
|
|
).parsedSafe<Response>()?.result
|
2023-12-08 16:28:16 +00:00
|
|
|
|
2024-01-05 16:08:48 +00:00
|
|
|
res?.sources?.map {
|
2023-12-08 16:28:16 +00:00
|
|
|
M3u8Helper.generateM3u8(
|
|
|
|
this.name,
|
|
|
|
it.file ?: return@map,
|
|
|
|
"$mainUrl/"
|
|
|
|
).forEach(callback)
|
|
|
|
}
|
|
|
|
|
2024-01-05 16:08:48 +00:00
|
|
|
res?.tracks?.filter { it.kind == "captions" }?.map {
|
|
|
|
subtitleCallback.invoke(
|
|
|
|
SubtitleFile(it.label ?: return@map, it.file ?: return@map)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-12-08 16:28:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private suspend fun getKeys(): List<String> {
|
2023-12-23 22:55:02 +00:00
|
|
|
return app.get(key).parsed()
|
2023-12-08 16:28:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private suspend fun callFutoken(id: String, url: String): String? {
|
2024-04-12 08:53:30 +00:00
|
|
|
val script = app.get("$mainUrl/futoken", referer = url).text
|
2023-12-08 16:28:16 +00:00
|
|
|
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("/", "_")
|
|
|
|
}
|
|
|
|
|
2024-01-05 16:08:48 +00:00
|
|
|
data class Tracks(
|
|
|
|
@JsonProperty("file") val file: String? = null,
|
|
|
|
@JsonProperty("label") val label: String? = null,
|
|
|
|
@JsonProperty("kind") val kind: String? = null,
|
|
|
|
)
|
|
|
|
|
2023-12-08 16:28:16 +00:00
|
|
|
data class Sources(
|
|
|
|
@JsonProperty("file") val file: String? = null,
|
|
|
|
)
|
|
|
|
|
|
|
|
data class Result(
|
|
|
|
@JsonProperty("sources") val sources: ArrayList<Sources>? = arrayListOf(),
|
2024-01-05 16:08:48 +00:00
|
|
|
@JsonProperty("tracks") val tracks: ArrayList<Tracks>? = arrayListOf(),
|
2023-12-08 16:28:16 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
data class Response(
|
|
|
|
@JsonProperty("result") val result: Result? = null,
|
|
|
|
)
|
|
|
|
|
2023-12-20 00:18:32 +00:00
|
|
|
}
|