cloudstream-extensions-hexated/SoraStream/src/main/kotlin/com/hexated/Extractors.kt

450 lines
15 KiB
Kotlin
Raw Normal View History

2023-09-09 12:16:04 +00:00
package com.hexated
import com.lagradost.cloudstream3.extractors.Filesim
import com.lagradost.cloudstream3.extractors.GMPlayer
import com.lagradost.cloudstream3.extractors.StreamSB
import com.lagradost.cloudstream3.extractors.Voe
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
2023-09-26 05:45:33 +00:00
import com.lagradost.cloudstream3.ErrorLoadingException
2023-09-09 12:16:04 +00:00
import com.lagradost.cloudstream3.SubtitleFile
2023-09-13 07:58:52 +00:00
import com.lagradost.cloudstream3.apmap
2023-09-09 12:16:04 +00:00
import com.lagradost.cloudstream3.app
2023-09-13 07:58:52 +00:00
import com.lagradost.cloudstream3.base64Decode
import com.lagradost.cloudstream3.extractors.Pixeldrain
2023-09-26 05:45:33 +00:00
import com.lagradost.cloudstream3.extractors.helper.AesHelper
2023-09-09 12:16:04 +00:00
import com.lagradost.cloudstream3.utils.*
2023-09-30 16:31:50 +00:00
import org.jsoup.nodes.Document
import org.mozilla.javascript.Context
import org.mozilla.javascript.Scriptable
2023-09-09 12:16:04 +00:00
import java.math.BigInteger
import java.security.MessageDigest
open class Playm4u : ExtractorApi() {
override val name = "Playm4u"
override val mainUrl = "https://play9str.playm4u.xyz"
override val requiresReferer = true
private val password = "plhq@@@22"
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val document = app.get(url, referer = referer).document
val script = document.selectFirst("script:containsData(idfile =)")?.data() ?: return
val passScript = document.selectFirst("script:containsData(domain_ref =)")?.data() ?: return
val pass = passScript.substringAfter("CryptoJS.MD5('").substringBefore("')")
val amount = passScript.substringAfter(".toString()), ").substringBefore("));").toInt()
2023-09-10 06:12:57 +00:00
val idFile = "idfile".findIn(script)
val idUser = "idUser".findIn(script)
val domainApi = "DOMAIN_API".findIn(script)
val nameKeyV3 = "NameKeyV3".findIn(script)
2023-09-09 12:16:04 +00:00
val dataEnc = caesarShift(
mahoa(
"Win32|$idUser|$idFile|$referer",
md5(pass)
), amount
).toHex()
val captchaKey =
document.select("script[src*=https://www.google.com/recaptcha/api.js?render=]")
.attr("src").substringAfter("render=")
val token = getCaptchaToken(
url,
captchaKey,
referer = referer
)
val source = app.post(
domainApi, data = mapOf(
"namekey" to nameKeyV3,
"token" to "$token",
"referrer" to "$referer",
"data" to "$dataEnc|${md5(dataEnc + password)}",
), referer = "$mainUrl/"
).parsedSafe<Source>()
callback.invoke(
ExtractorLink(
this.name,
this.name,
source?.data ?: return,
"$mainUrl/",
Qualities.P1080.value,
INFER_TYPE
)
)
subtitleCallback.invoke(
SubtitleFile(
source.sub?.substringBefore("|")?.toLanguage() ?: return,
source.sub.substringAfter("|"),
)
)
}
private fun caesarShift(str: String, amount: Int): String {
var output = ""
val adjustedAmount = if (amount < 0) amount + 26 else amount
for (element in str) {
var c = element
if (c.isLetter()) {
val code = c.code
c = when (code) {
in 65..90 -> ((code - 65 + adjustedAmount) % 26 + 65).toChar()
in 97..122 -> ((code - 97 + adjustedAmount) % 26 + 97).toChar()
else -> c
}
}
output += c
}
return output
}
private fun mahoa(input: String, key: String): String {
val a = CryptoJS.encrypt(key, input)
return a.replace("U2FsdGVkX1", "")
.replace("/", "|a")
.replace("+", "|b")
.replace("=", "|c")
.replace("|", "-z")
}
private fun md5(input: String): String {
val md = MessageDigest.getInstance("MD5")
return BigInteger(1, md.digest(input.toByteArray())).toString(16).padStart(32, '0')
}
private fun String.toHex(): String {
return this.toByteArray().joinToString("") { "%02x".format(it) }
}
private fun String.findIn(data: String): String {
2023-09-10 06:12:57 +00:00
return "$this\\s*=\\s*[\"'](\\S+)[\"'];".toRegex().find(data)?.groupValues?.get(1) ?: ""
2023-09-09 12:16:04 +00:00
}
private fun String.toLanguage() : String {
return if(this == "EN") "English" else this
}
data class Source(
@JsonProperty("data") val data: String? = null,
@JsonProperty("sub") val sub: String? = null,
)
}
2023-09-19 02:48:36 +00:00
open class M4ufree : ExtractorApi() {
override val name = "M4ufree"
override val mainUrl = "https://play.playm4u.xyz"
override val requiresReferer = true
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val document = session.get(url, referer = referer).document
val script = document.selectFirst("script:containsData(idfile =)")?.data() ?: return
val idFile = "idfile".findIn(script)
val idUser = "idUser".findIn(script)
val video = session.post(
"https://api-plhq.playm4u.xyz/apidatard/$idUser/$idFile",
data = mapOf("referrer" to "$referer"),
headers = mapOf(
"Accept" to "*/*",
"X-Requested-With" to "XMLHttpRequest",
)
).text.let { AppUtils.tryParseJson<Source>(it) }?.data
callback.invoke(
ExtractorLink(
this.name,
this.name,
video ?: return,
referer ?: "",
Qualities.P720.value,
INFER_TYPE
)
)
}
private fun String.findIn(data: String): String? {
return "$this\\s*=\\s*[\"'](\\S+)[\"'];".toRegex().find(data)?.groupValues?.get(1)
}
data class Source(
@JsonProperty("data") val data: String? = null,
)
}
2023-09-13 07:58:52 +00:00
open class VCloud : ExtractorApi() {
override val name: String = "V-Cloud"
override val mainUrl: String = "https://v-cloud.bio"
override val requiresReferer = true
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val res = app.get(url)
val doc = res.document
val changedLink = doc.selectFirst("script:containsData(url =)")?.data()?.let {
"""url\s*=\s*['"](.*)['"];""".toRegex().find(it)?.groupValues?.get(1)
?.substringAfter("r=")
2023-09-14 18:39:07 +00:00
} ?: doc.selectFirst("div.div.vd.d-none a")?.attr("href")
2023-09-13 07:58:52 +00:00
val header = doc.selectFirst("div.card-header")?.text()
app.get(
base64Decode(changedLink ?: return), cookies = res.cookies, headers = mapOf(
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"
)
).document.select("p.text-success ~ a").apmap {
val link = it.attr("href")
2023-09-21 07:43:38 +00:00
if (link.contains("workers.dev")) {
2023-09-13 07:58:52 +00:00
callback.invoke(
ExtractorLink(
this.name,
this.name,
link,
"",
getIndexQuality(header),
INFER_TYPE
)
)
} else {
val direct = if(link.contains("gofile.io")) app.get(link).url else link
loadExtractor(direct, referer, subtitleCallback, callback)
}
}
}
private fun getIndexQuality(str: String?): Int {
return Regex("(\\d{3,4})[pP]").find(str ?: "")?.groupValues?.getOrNull(1)?.toIntOrNull()
?: Qualities.Unknown.value
}
}
2023-09-30 16:31:50 +00:00
object NineTv {
2023-09-26 05:45:33 +00:00
suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val mainUrl = getBaseUrl(url)
2023-11-08 21:34:56 +00:00
val res = app.get(url, 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",
"Referer" to (referer ?: ""),
))
2023-10-31 20:00:38 +00:00
val master = Regex("\\s*=\\s*'([^']+)").find(res.text)?.groupValues?.get(1)
2023-11-21 14:46:11 +00:00
val key = "tSIsE8FgpRkv3QQQ"
2023-09-26 05:45:33 +00:00
val decrypt = AesHelper.cryptoAESHandler(master ?: return, key.toByteArray(), false)
2023-09-30 16:31:50 +00:00
?.replace("\\", "")
?: throw ErrorLoadingException("failed to decrypt")
2023-09-26 05:45:33 +00:00
val source = Regex(""""?file"?:\s*"([^"]+)""").find(decrypt)?.groupValues?.get(1)
val tracks = Regex("""tracks:\s*\[(.+)]""").find(decrypt)?.groupValues?.get(1)
2023-10-01 08:34:30 +00:00
val name = url.getHost()
2023-09-26 05:45:33 +00:00
M3u8Helper.generateM3u8(
2023-10-01 08:34:30 +00:00
name,
source ?: return,
2023-09-26 05:45:33 +00:00
"$mainUrl/",
headers = mapOf(
"Accept" to "*/*",
"Connection" to "keep-alive",
"Sec-Fetch-Dest" to "empty",
"Sec-Fetch-Mode" to "cors",
"Sec-Fetch-Site" to "cross-site",
"Origin" to mainUrl,
)
).forEach(callback)
AppUtils.tryParseJson<List<Tracks>>("[$tracks]")
?.filter { it.kind == "captions" }?.map { track ->
subtitleCallback.invoke(
SubtitleFile(
track.label ?: "",
track.file ?: return@map null
)
)
}
}
2023-09-30 16:31:50 +00:00
private fun Document.getKeys(): String? {
val script = (this.selectFirst("script:containsData(eval\\()")?.data()
?.replace("eval(", "var result=")?.removeSuffix(");") + ";").trimIndent()
val run = script.runJS("result")
return """,\s*'([^']+)""".toRegex().find(run)?.groupValues?.getOrNull(1)
}
private fun String.runJS(variable: String): String {
val rhino = Context.enter()
rhino.optimizationLevel = -1
val scope: Scriptable = rhino.initSafeStandardObjects()
val result: String
try {
rhino.evaluateString(scope, this, "JavaScript", 1, null)
result = Context.toString(scope.get(variable, scope))
} finally {
Context.exit()
}
return result
2023-09-26 05:45:33 +00:00
}
data class Tracks(
@JsonProperty("file") val file: String? = null,
@JsonProperty("label") val label: String? = null,
@JsonProperty("kind") val kind: String? = null,
)
}
2023-10-08 01:37:12 +00:00
open class Streamruby : ExtractorApi() {
override val name = "Streamruby"
override val mainUrl = "https://streamruby.com"
override val requiresReferer = true
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val id = "/e/(\\w+)".toRegex().find(url)?.groupValues?.get(1) ?: return
val response = app.post("$mainUrl/dl", data = mapOf(
"op" to "embed",
"file_code" to id,
"auto" to "1",
"referer" to "",
), referer = referer)
val script = if (!getPacked(response.text).isNullOrEmpty()) {
getAndUnpack(response.text)
} else {
response.document.selectFirst("script:containsData(sources:)")?.data()
}
val m3u8 =
Regex("file:\\s*\"(.*?m3u8.*?)\"").find(script ?: return)?.groupValues?.getOrNull(1)
M3u8Helper.generateM3u8(
name,
m3u8 ?: return,
mainUrl
).forEach(callback)
}
}
2023-11-21 19:33:27 +00:00
open class Uploadever : ExtractorApi() {
override val name = "Uploadever"
override val mainUrl = "https://uploadever.in"
override val requiresReferer = true
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
var res = app.get(url, referer = referer).document
val formUrl = res.select("form").attr("action")
var formData = res.select("form input").associate { it.attr("name") to it.attr("value") }.filterKeys { it != "go" }
.toMutableMap()
val formReq = app.post(formUrl, data = formData)
res = formReq.document
val captchaKey = res.select("script[src*=https://www.google.com/recaptcha/api.js?render=]").attr("src").substringAfter("render=")
val token = getCaptchaToken(url, captchaKey, referer = "$mainUrl/")
formData = res.select("form#down input").associate { it.attr("name") to it.attr("value") }.toMutableMap()
formData["adblock_detected"] = "0"
formData["referer"] = url
res = app.post(formReq.url, data = formData + mapOf("g-recaptcha-response" to "$token"), cookies = formReq.cookies).document
val video = res.select("div.download-button a.btn.btn-dow.recaptchav2").attr("href")
callback.invoke(
ExtractorLink(
this.name,
this.name,
video,
"",
Qualities.Unknown.value,
INFER_TYPE
)
)
}
}
2023-10-08 01:37:12 +00:00
class Streamwish : Filesim() {
override val name = "Streamwish"
override var mainUrl = "https://streamwish.to"
}
2023-11-16 11:05:39 +00:00
class Wishfast : Filesim() {
override val name = "Wishfast"
override var mainUrl = "https://wishfast.top"
}
2023-10-08 01:37:12 +00:00
class FilelionsTo : Filesim() {
override val name = "Filelions"
override var mainUrl = "https://filelions.to"
}
2023-09-14 18:39:07 +00:00
class Hubcloud : VCloud() {
override val name = "Hubcloud"
override val mainUrl = "https://hubcloud.in"
}
2023-09-13 07:58:52 +00:00
class Pixeldra : Pixeldrain() {
override val mainUrl = "https://pixeldra.in"
}
2023-09-09 12:16:04 +00:00
class TravelR : GMPlayer() {
override val name = "TravelR"
override val mainUrl = "https://travel-russia.xyz"
}
class Mwish : Filesim() {
override val name = "Mwish"
override var mainUrl = "https://mwish.pro"
}
class Animefever : Filesim() {
override val name = "Animefever"
override var mainUrl = "https://animefever.fun"
}
class Multimovies : Filesim() {
override val name = "Multimovies"
override var mainUrl = "https://multimovies.cloud"
}
class MultimoviesSB : StreamSB() {
override var name = "Multimovies"
override var mainUrl = "https://multimovies.website"
}
class Yipsu : Voe() {
override val name = "Yipsu"
override var mainUrl = "https://yip.su"
2023-10-22 09:52:23 +00:00
}
class Embedwish : Filesim() {
override val name = "Embedwish"
override var mainUrl = "https://embedwish.com"
2023-09-30 16:31:50 +00:00
}