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

599 lines
20 KiB
Kotlin
Raw Normal View History

2022-12-02 13:00:44 +00:00
package com.hexated
2022-12-07 19:17:24 +00:00
import com.hexated.SoraStream.Companion.filmxyAPI
2022-12-02 16:50:56 +00:00
import com.hexated.SoraStream.Companion.gdbot
2022-12-15 17:30:38 +00:00
import com.hexated.SoraStream.Companion.tvMoviesAPI
2023-01-11 01:28:46 +00:00
import com.lagradost.cloudstream3.APIHolder
2023-01-11 12:42:59 +00:00
import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
2022-12-02 16:50:56 +00:00
import com.lagradost.cloudstream3.app
2022-12-02 13:00:44 +00:00
import com.lagradost.cloudstream3.base64Decode
import com.lagradost.cloudstream3.base64Encode
import com.lagradost.cloudstream3.network.WebViewResolver
2022-12-07 19:17:24 +00:00
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
2022-12-02 13:00:44 +00:00
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
2023-01-03 23:01:24 +00:00
import com.lagradost.cloudstream3.utils.SubtitleHelper
2022-12-02 13:00:44 +00:00
import com.lagradost.cloudstream3.utils.getQualityFromName
2023-01-11 01:28:46 +00:00
import com.lagradost.nicehttp.NiceResponse
import com.lagradost.nicehttp.RequestBodyTypes
2022-12-02 13:00:44 +00:00
import com.lagradost.nicehttp.requestCreator
2022-12-15 17:30:38 +00:00
import kotlinx.coroutines.delay
2022-12-07 15:06:48 +00:00
import okhttp3.FormBody
2022-12-02 13:00:44 +00:00
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
2022-12-10 12:25:28 +00:00
import org.jsoup.nodes.Document
2022-12-02 13:00:44 +00:00
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 {
2022-12-02 13:00:44 +00:00
return if (seasonNum != null) {
if (lastSeason == 1) {
2022-12-02 13:00:44 +00:00
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
2022-12-17 12:53:12 +00:00
)
2022-12-02 13:00:44 +00:00
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")
}
}
2022-12-07 19:17:24 +00:00
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
}
2022-12-02 16:50:56 +00:00
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" }
2022-12-07 15:06:48 +00:00
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(";")
2022-12-02 16:50:56 +00:00
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
}
2022-12-07 15:06:48 +00:00
suspend fun extractDrivebot(url: String): String? {
2022-12-20 15:24:47 +00:00
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(\"")
2022-12-20 15:24:47 +00:00
?.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)
2022-12-07 15:06:48 +00:00
val ssid = driveDoc.cookies["PHPSESSID"]
val script = driveDoc.document.selectFirst("script:containsData(var formData)")?.data()
2022-12-20 15:24:47 +00:00
val baseUrl = getBaseUrl(url)
2022-12-07 15:06:48 +00:00
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,
2022-12-20 15:24:47 +00:00
referer = url
2022-12-07 15:06:48 +00:00
).text
2022-12-07 19:17:24 +00:00
return tryParseJson<DriveBotLink>(result)?.url
2022-12-07 15:06:48 +00:00
}
2022-12-12 13:24:46 +00:00
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")
}
2022-12-15 17:30:38 +00:00
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)
}
2022-12-29 13:19:16 +00:00
fun getDirectGdrive(url: String): String {
2023-01-11 01:28:46 +00:00
return if (url.contains("&export=download")) {
2022-12-29 13:19:16 +00:00
url
2023-01-11 01:28:46 +00:00
} else {
"https://drive.google.com/uc?id=${
url.substringAfter("/d/").substringBefore("/")
}&export=download"
2022-12-29 13:19:16 +00:00
}
}
2023-01-11 01:28:46 +00:00
suspend fun bypassOuo(url: String?) : String? {
var res = session.get(url ?: return null)
2023-01-11 12:42:59 +00:00
run lit@{
(1..2).forEach { _ ->
if (res.headers["location"] != null) return@lit
val document = res.document
val nextUrl = document.select("form").attr("action")
val data = document.select("form input").mapNotNull {
it.attr("name") to it.attr("value")
}.toMap().toMutableMap()
val captchaKey =
document.select("script[src*=https://www.google.com/recaptcha/api.js?render=]")
.attr("src").substringAfter("render=")
val token = getCaptchaToken(url, captchaKey)
data["x-token"] = token ?: ""
res = session.post(
nextUrl,
data = data,
headers = mapOf("content-type" to "application/x-www-form-urlencoded"),
allowRedirects = false
)
}
2023-01-11 01:28:46 +00:00
}
return res.headers["location"]
}
suspend fun fetchingKaizoku(
domain: String,
postId: String,
data: List<String>,
ref: String
): NiceResponse {
return app.post(
"$domain/wp-admin/admin-ajax.php",
data = mapOf(
"action" to "DDL",
"post_id" to postId,
"div_id" to data.first(),
"tab_id" to data[1],
"num" to data[2],
"folder" to data.last()
),
headers = mapOf("X-Requested-With" to "XMLHttpRequest"),
referer = ref
)
}
fun String.splitData(): List<String> {
return this.substringAfterLast("DDL(").substringBefore(")").split(",")
.map { it.replace("'", "").trim() }
}
2023-01-02 17:15:40 +00:00
suspend fun bypassFdAds(url: String?): String? {
2023-01-03 16:42:50 +00:00
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")),
2022-12-07 15:06:48 +00:00
verify = false
).document
2023-01-03 16:42:50 +00:00
val json = lastDoc.select("form#landing input[name=newwpsafelink]").attr("value").let { base64Decode(it) }
2023-01-03 23:01:24 +00:00
val finalJson = tryParseJson<FDAds>(json)?.linkr?.substringAfter("redirect=")?.let { base64Decode(it) }
return tryParseJson<Safelink>(finalJson)?.safelink
2022-12-07 15:06:48 +00:00
}
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 {
2022-12-16 22:29:01 +00:00
it.groupValues[2]
}.toList()
2022-12-16 22:29:01 +00:00
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=")
}
2022-12-10 12:25:28 +00:00
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()
}
}
2022-12-02 13:00:44 +00:00
suspend fun getFilmxyCookies(imdbId: String? = null, season: Int? = null): FilmxyCookies? {
val url = if (season == null) {
2022-12-07 19:17:24 +00:00
"${filmxyAPI}/movie/$imdbId"
2022-12-02 13:00:44 +00:00
} else {
2022-12-07 19:17:24 +00:00
"${filmxyAPI}/tv/$imdbId"
2022-12-02 13:00:44 +00:00
}
2022-12-07 19:17:24 +00:00
val cookieUrl = "${filmxyAPI}/wp-admin/admin-ajax.php"
2022-12-02 13:00:44 +00:00
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)
}
2022-12-10 12:25:28 +00:00
fun Document.findTvMoviesIframe(): String? {
return this.selectFirst("script:containsData(var seconds)")?.data()?.substringAfter("href='")
?.substringBefore("'>")
}
2022-12-02 13:00:44 +00:00
fun String?.fixTitle(): String? {
2023-01-11 01:28:46 +00:00
return this?.replace(Regex("[!%:'?]|( &)"), "")?.replace(" ", "-")?.lowercase()
2022-12-02 13:00:44 +00:00
?.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)
}
}
2022-12-02 16:50:56 +00:00
fun getGMoviesQuality(str: String): Int {
return when {
str.contains("480P", true) -> Qualities.P480.value
str.contains("720P", true) -> Qualities.P720.value
2022-12-12 13:24:46 +00:00
str.contains("1080P", true) -> Qualities.P1080.value
2022-12-02 16:50:56 +00:00
str.contains("4K", true) -> Qualities.P2160.value
else -> Qualities.Unknown.value
}
}
2022-12-09 20:54:40 +00:00
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
}
}
2022-12-12 13:24:46 +00:00
fun getFDoviesQuality(str: String): String {
return when {
str.contains("1080P", true) -> "1080P"
str.contains("4K", true) -> "4K"
else -> ""
}
}
2023-01-03 23:01:24 +00:00
fun getVipLanguage(str: String): String {
return when (str) {
"in_ID" -> "Indonesian"
"pt" -> "Portuguese"
else -> str.split("_").first().let {
SubtitleHelper.fromTwoLettersToLanguage(it).toString()
}
}
}
2022-12-02 13:00:44 +00:00
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
)
)
}