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

541 lines
19 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.hexated
import com.hexated.SoraStream.Companion.filmxyAPI
import com.hexated.SoraStream.Companion.gdbot
import com.hexated.SoraStream.Companion.tvMoviesAPI
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.base64Decode
import com.lagradost.cloudstream3.base64Encode
import com.lagradost.cloudstream3.network.WebViewResolver
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.SubtitleHelper
import com.lagradost.cloudstream3.utils.getQualityFromName
import com.lagradost.nicehttp.RequestBodyTypes
import com.lagradost.nicehttp.requestCreator
import kotlinx.coroutines.delay
import okhttp3.FormBody
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import org.jsoup.nodes.Document
import java.net.URI
data class FilmxyCookies(
val phpsessid: String? = null,
val wLog: String? = null,
val wSec: String? = null,
)
fun String.filterIframe(seasonNum: Int?, lastSeason: Int?, year: Int?): Boolean {
return if (seasonNum != null) {
if (lastSeason == 1) {
this.contains(Regex("(?i)(S0?$seasonNum)|(Season\\s0?$seasonNum)|([0-9]{3,4}p)")) && !this.contains(
"Download",
true
)
} else {
this.contains(Regex("(?i)(S0?$seasonNum)|(Season\\s0?$seasonNum)")) && !this.contains(
"Download",
true
)
}
} else {
this.contains("$year", true) && !this.contains("Download", true)
}
}
fun String.filterMedia(title: String?, yearNum: Int?, seasonNum: Int?): Boolean {
return if (seasonNum != null) {
when {
seasonNum > 1 -> this.contains(Regex("(?i)(Season\\s0?1-0?$seasonNum)|(S0?1-S?0?$seasonNum)")) && this.contains(
"$title",
true
)
else -> this.contains(Regex("(?i)(Season\\s0?1)|(S0?1)")) && this.contains(
"$title",
true
) && this.contains("$yearNum")
}
} else {
this.contains("$title", true) && this.contains("$yearNum")
}
}
suspend fun extractMirrorUHD(url: String, ref: String): String? {
val baseDoc = app.get(fixUrl(url, ref)).document
val downLink = baseDoc.select("div.mb-4 a").randomOrNull()
?.attr("href") ?: run {
val server = baseDoc.select("div.text-center a:contains(Server 2)").attr("href")
app.get(fixUrl(server, ref)).document.selectFirst("div.mb-4 a")
?.attr("href")
}
val downPage = app.get(downLink ?: return null).document
return downPage.selectFirst("form[method=post] a.btn.btn-success")
?.attr("onclick")?.substringAfter("Openblank('")?.substringBefore("')") ?: run {
val mirror = downPage.selectFirst("form[method=post] a.btn.btn-primary")
?.attr("onclick")?.substringAfter("Openblank('")?.substringBefore("')")
app.get(
mirror ?: return null
).document.selectFirst("script:containsData(input.value =)")
?.data()?.substringAfter("input.value = '")?.substringBefore("';")
}
}
suspend fun extractBackupUHD(url: String): String? {
val resumeDoc = app.get(url)
val script = resumeDoc.document.selectFirst("script:containsData(FormData.)")?.data()
val ssid = resumeDoc.cookies["PHPSESSID"]
val baseIframe = getBaseUrl(url)
val fetchLink = script?.substringAfter("fetch('")?.substringBefore("',")?.let { fixUrl(it, baseIframe) }
val token = script?.substringAfter("'token', '")?.substringBefore("');")
val body = FormBody.Builder()
.addEncoded("token", "$token")
.build()
val cookies = mapOf("PHPSESSID" to "$ssid")
val result = app.post(
fetchLink ?: return null,
requestBody = body,
headers = mapOf(
"Accept" to "*/*",
"Origin" to baseIframe,
"Sec-Fetch-Site" to "same-origin"
),
cookies = cookies,
referer = url
).text
return tryParseJson<UHDBackupUrl>(result)?.url
}
suspend fun extractGdbot(url: String): String? {
val headers = mapOf(
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
)
val res = app.get(
"$gdbot/", headers = headers
)
val token = res.document.selectFirst("input[name=_token]")?.attr("value")
val cookiesSet = res.headers.filter { it.first == "set-cookie" }
val xsrf =
cookiesSet.find { it.second.contains("XSRF-TOKEN") }?.second?.substringAfter("XSRF-TOKEN=")
?.substringBefore(";")
val session =
cookiesSet.find { it.second.contains("gdtot_proxy_session") }?.second?.substringAfter("gdtot_proxy_session=")
?.substringBefore(";")
val cookies = mapOf(
"gdtot_proxy_session" to "$session",
"XSRF-TOKEN" to "$xsrf"
)
val requestFile = app.post(
"$gdbot/file", data = mapOf(
"link" to url,
"_token" to "$token"
), headers = headers, referer = "$gdbot/", cookies = cookies
).document
return requestFile.selectFirst("div.mt-8 a.float-right")?.attr("href")
}
suspend fun extractDirectDl(url: String): String? {
val iframe = app.get(url).document.selectFirst("li.flex.flex-col.py-6 a:contains(Direct DL)")?.attr("href")
val request = app.get(iframe ?: return null)
val driveDoc = request.document
val token = driveDoc.select("section#generate_url").attr("data-token")
val uid = driveDoc.select("section#generate_url").attr("data-uid")
val ssid = request.cookies["PHPSESSID"]
val body = """{"type":"DOWNLOAD_GENERATE","payload":{"uid":"$uid","access_token":"$token"}}""".toRequestBody(
RequestBodyTypes.JSON.toMediaTypeOrNull()
)
val json = app.post(
"https://rajbetmovies.com/action", requestBody = body, headers = mapOf(
"Accept" to "application/json, text/plain, */*",
"Cookie" to "PHPSESSID=$ssid",
"X-Requested-With" to "xmlhttprequest"
), referer = request.url
).text
return tryParseJson<DirectDl>(json)?.download_url
}
suspend fun extractDrivebot(url: String): String? {
val iframeDrivebot = app.get(url).document.selectFirst("li.flex.flex-col.py-6 a:contains(Drivebot)")
?.attr("href") ?: return null
return getDrivebotLink(iframeDrivebot)
}
suspend fun extractGdflix(url: String): String? {
val iframeGdflix = app.get(url).document.selectFirst("li.flex.flex-col.py-6 a:contains(GDFlix Direct)")
?.attr("href") ?: return null
val base = getBaseUrl(iframeGdflix)
val gdfDoc = app.get(iframeGdflix).document.selectFirst("script:containsData(replace)")?.data()?.substringAfter("replace(\"")
?.substringBefore("\")")?.let {
app.get(fixUrl(it, base)).document
}
val iframeDrivebot2 = gdfDoc?.selectFirst("a.btn.btn-outline-warning")?.attr("href")
return getDrivebotLink(iframeDrivebot2)
}
suspend fun getDrivebotLink(url: String?): String? {
val driveDoc = app.get(url ?: return null)
val ssid = driveDoc.cookies["PHPSESSID"]
val script = driveDoc.document.selectFirst("script:containsData(var formData)")?.data()
val baseUrl = getBaseUrl(url)
val token = script?.substringAfter("'token', '")?.substringBefore("');")
val link =
script?.substringAfter("fetch('")?.substringBefore("',").let { "$baseUrl$it" }
val body = FormBody.Builder()
.addEncoded("token", "$token")
.build()
val cookies = mapOf("PHPSESSID" to "$ssid")
val result = app.post(
link,
requestBody = body,
headers = mapOf(
"Accept" to "*/*",
"Origin" to baseUrl,
"Sec-Fetch-Site" to "same-origin"
),
cookies = cookies,
referer = url
).text
return tryParseJson<DriveBotLink>(result)?.url
}
suspend fun extractOiya(url: String, quality: String): String? {
val doc = app.get(url).document
return doc.selectFirst("div.wp-block-button a:matches((?i)$quality)")?.attr("href")
?: doc.selectFirst("div.wp-block-button a")?.attr("href")
}
suspend fun extractCovyn(url: String?): Pair<String?, String?>? {
val request = session.get(url ?: return null, referer = "${tvMoviesAPI}/")
val filehosting = session.baseClient.cookieJar.loadForRequest(url.toHttpUrl())
.find { it.name == "filehosting" }?.value
val headers = mapOf(
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Connection" to "keep-alive",
"Cookie" to "filehosting=$filehosting",
)
val iframe = request.document.findTvMoviesIframe()
delay(10500)
val request2 = session.get(
iframe ?: return null, referer = url, headers = headers
)
val iframe2 = request2.document.findTvMoviesIframe()
delay(10500)
val request3 = session.get(
iframe2 ?: return null, referer = iframe, headers = headers
)
val response = request3.document
val videoLink = response.selectFirst("button.btn.btn--primary")?.attr("onclick")
?.substringAfter("location = '")?.substringBefore("';")?.let {
app.get(
it, referer = iframe2, headers = headers
).url
}
val size = response.selectFirst("ul.row--list li:contains(Filesize) span:last-child")
?.text()
return Pair(videoLink, size)
}
fun getDirectGdrive(url: String): String {
return if(url.endsWith("share_link")) {
"https://drive.google.com/uc?id=${url.substringAfter("/d/").substringBefore("/")}&export=download"
} else {
url
}
}
suspend fun bypassFdAds(url: String?): String? {
val directUrl = app.get(url ?: return null, verify = false).document.select("a#link").attr("href")
.substringAfter("/go/")
.let { base64Decode(it) }
val doc = app.get(directUrl, verify = false).document
val lastDoc = app.post(
doc.select("form#landing").attr("action"),
data = mapOf("go" to doc.select("form#landing input").attr("value")),
verify = false
).document
val json = lastDoc.select("form#landing input[name=newwpsafelink]").attr("value").let { base64Decode(it) }
val finalJson = tryParseJson<FDAds>(json)?.linkr?.substringAfter("redirect=")?.let { base64Decode(it) }
return tryParseJson<Safelink>(finalJson)?.safelink
}
suspend fun bypassHrefli(url: String): String? {
val direct = url.removePrefix("https://href.li/?")
val res = app.get(direct).document
val formLink = res.select("form#landing").attr("action")
val wpHttp = res.select("input[name=_wp_http]").attr("value")
val res2 = app.post(formLink, data = mapOf("_wp_http" to wpHttp)).document
val formLink2 = res2.select("form#landing").attr("action")
val wpHttp2 = res2.select("input[name=_wp_http2]").attr("value")
val token = res2.select("input[name=token]").attr("value")
val res3 = app.post(
formLink2, data = mapOf(
"_wp_http2" to wpHttp2, "token" to token
)
).document
val script = res3.selectFirst("script:containsData(verify_button)")?.data()
val directLink = script?.substringAfter("\"href\",\"")?.substringBefore("\")")
val matchCookies =
Regex("sumitbot_\\('(\\S+?)',\n|.?'(\\S+?)',").findAll(script ?: return null).map {
it.groupValues[2]
}.toList()
val cookeName = matchCookies.firstOrNull() ?: return null
val cookeValue = matchCookies.lastOrNull() ?: return null
val cookies = mapOf(
cookeName to cookeValue
)
return app.get(
directLink ?: return null,
cookies = cookies
).document.selectFirst("meta[http-equiv=refresh]")?.attr("content")?.substringAfter("url=")
}
suspend fun getTvMoviesServer(url: String, season: Int?, episode: Int?): Pair<String, String?>? {
val req = app.get(url)
if(!req.isSuccessful) return null
val doc = req.document
return if (season == null) {
doc.select("table.wp-block-table tr:last-child td:first-child").text() to
doc.selectFirst("table.wp-block-table tr a")?.attr("href").let { link ->
app.get(link ?: return null).document.select("div#text-url a")
.mapIndexed { index, element ->
element.attr("href") to element.parent()?.textNodes()?.getOrNull(index)
?.text()
}.filter { it.second?.contains("Subtitles", true) == false }
.map { it.first }
}.lastOrNull()
} else {
doc.select("div.vc_tta-panels div#Season-$season table.wp-block-table tr:last-child td:first-child")
.text() to
doc.select("div.vc_tta-panels div#Season-$season table.wp-block-table tr a")
.mapNotNull { ele ->
app.get(ele.attr("href")).document.select("div#text-url a")
.mapIndexed { index, element ->
element.attr("href") to element.parent()?.textNodes()
?.getOrNull(index)?.text()
}.find { it.second?.contains("Episode $episode", true) == true }?.first
}.lastOrNull()
}
}
suspend fun getFilmxyCookies(imdbId: String? = null, season: Int? = null): FilmxyCookies? {
val url = if (season == null) {
"${filmxyAPI}/movie/$imdbId"
} else {
"${filmxyAPI}/tv/$imdbId"
}
val cookieUrl = "${filmxyAPI}/wp-admin/admin-ajax.php"
val res = session.get(
url,
headers = mapOf(
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"
),
)
if (!res.isSuccessful) return FilmxyCookies()
val userNonce =
res.document.select("script").find { it.data().contains("var userNonce") }?.data()?.let {
Regex("var\\suserNonce.*?\"(\\S+?)\";").find(it)?.groupValues?.get(1)
}
var phpsessid = session.baseClient.cookieJar.loadForRequest(url.toHttpUrl())
.first { it.name == "PHPSESSID" }.value
session.post(
cookieUrl,
data = mapOf(
"action" to "guest_login",
"nonce" to "$userNonce",
),
headers = mapOf(
"Cookie" to "PHPSESSID=$phpsessid; G_ENABLED_IDPS=google",
"X-Requested-With" to "XMLHttpRequest",
)
)
val cookieJar = session.baseClient.cookieJar.loadForRequest(cookieUrl.toHttpUrl())
phpsessid = cookieJar.first { it.name == "PHPSESSID" }.value
val wLog =
cookieJar.first { it.name == "wordpress_logged_in_8bf9d5433ac88cc9a3a396d6b154cd01" }.value
val wSec = cookieJar.first { it.name == "wordpress_sec_8bf9d5433ac88cc9a3a396d6b154cd01" }.value
return FilmxyCookies(phpsessid, wLog, wSec)
}
fun Document.findTvMoviesIframe(): String? {
return this.selectFirst("script:containsData(var seconds)")?.data()?.substringAfter("href='")
?.substringBefore("'>")
}
fun String?.fixTitle(): String? {
return this?.replace(Regex("[!%:']|( &)"), "")?.replace(" ", "-")?.lowercase()
?.replace("--", "-")
}
fun getLanguage(str: String): String {
return if (str.contains("(in_ID)")) "Indonesian" else str
}
fun getKisskhTitle(str: String?): String? {
return str?.replace(Regex("[^a-zA-Z0-9]"), "-")
}
fun getQuality(str: String): Int {
return when (str) {
"360p" -> Qualities.P240.value
"480p" -> Qualities.P360.value
"720p" -> Qualities.P480.value
"1080p" -> Qualities.P720.value
"1080p Ultra" -> Qualities.P1080.value
else -> getQualityFromName(str)
}
}
fun getGMoviesQuality(str: String): Int {
return when {
str.contains("480P", true) -> Qualities.P480.value
str.contains("720P", true) -> Qualities.P720.value
str.contains("1080P", true) -> Qualities.P1080.value
str.contains("4K", true) -> Qualities.P2160.value
else -> Qualities.Unknown.value
}
}
fun getSoraQuality(quality: String): Int {
return when (quality) {
"GROOT_FD" -> Qualities.P360.value
"GROOT_LD" -> Qualities.P480.value
"GROOT_SD" -> Qualities.P720.value
"GROOT_HD" -> Qualities.P1080.value
else -> Qualities.Unknown.value
}
}
fun getFDoviesQuality(str: String): String {
return when {
str.contains("1080P", true) -> "1080P"
str.contains("4K", true) -> "4K"
else -> ""
}
}
fun getVipLanguage(str: String): String {
return when (str) {
"in_ID" -> "Indonesian"
"pt" -> "Portuguese"
else -> str.split("_").first().let {
SubtitleHelper.fromTwoLettersToLanguage(it).toString()
}
}
}
fun getBaseUrl(url: String): String {
return URI(url).let {
"${it.scheme}://${it.host}"
}
}
fun decryptStreamUrl(data: String): String {
fun getTrash(arr: List<String>, item: Int): List<String> {
val trash = ArrayList<List<String>>()
for (i in 1..item) {
trash.add(arr)
}
return trash.reduce { acc, list ->
val temp = ArrayList<String>()
acc.forEach { ac ->
list.forEach { li ->
temp.add(ac.plus(li))
}
}
return@reduce temp
}
}
val trashList = listOf("@", "#", "!", "^", "$")
val trashSet = getTrash(trashList, 2) + getTrash(trashList, 3)
var trashString = data.replace("#2", "").split("//_//").joinToString("")
trashSet.forEach {
val temp = base64Encode(it.toByteArray())
trashString = trashString.replace(temp, "")
}
return base64Decode(trashString)
}
fun fixUrl(url: String, domain: String): String {
if (url.startsWith("http")) {
return url
}
if (url.isEmpty()) {
return ""
}
val startsWithNoHttp = url.startsWith("//")
if (startsWithNoHttp) {
return "https:$url"
} else {
if (url.startsWith('/')) {
return domain + url
}
return "$domain/$url"
}
}
suspend fun loadLinksWithWebView(
url: String,
callback: (ExtractorLink) -> Unit
) {
val foundVideo = WebViewResolver(
Regex("""\.m3u8|i7njdjvszykaieynzsogaysdgb0hm8u1mzubmush4maopa4wde\.com""")
).resolveUsingWebView(
requestCreator(
"GET", url, referer = "https://olgply.com/"
)
).first ?: return
callback.invoke(
ExtractorLink(
"Olgply",
"Olgply",
foundVideo.url.toString(),
"",
Qualities.P1080.value,
true
)
)
}