diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt index fafbd3fc..c2c0514a 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt @@ -1,20 +1,15 @@ package com.hexated import com.fasterxml.jackson.annotation.JsonProperty -import com.hexated.SoraStream.Companion.filmxyAPI import com.lagradost.cloudstream3.* -import com.lagradost.cloudstream3.network.WebViewResolver import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.nicehttp.Requests import com.lagradost.nicehttp.Session -import com.lagradost.nicehttp.requestCreator -import okhttp3.HttpUrl.Companion.toHttpUrl import com.google.gson.JsonParser import com.lagradost.cloudstream3.network.CloudflareKiller import kotlinx.coroutines.delay import okhttp3.RequestBody.Companion.toRequestBody -import java.net.URI val session = Session(Requests().baseClient) @@ -1341,198 +1336,6 @@ object SoraExtractor : SoraStream() { } -data class FilmxyCookies( - val phpsessid: String? = null, - val wLog: String? = null, - val wSec: String? = null, -) - -fun String.filterIframe(seasonNum: Int?, year: Int?): Boolean { - return if (seasonNum != null) { - if (seasonNum == 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 - ) && this.contains("$yearNum") - 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 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) -} - -private 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 -} - -private fun getKisskhTitle(str: String?): String? { - return str?.replace(Regex("[^a-zA-Z0-9]"), "-") -} - -private 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) - } -} - -private fun getBaseUrl(url: String): String { - return URI(url).let { - "${it.scheme}://${it.host}" - } -} - -private fun decryptStreamUrl(data: String): String { - - fun getTrash(arr: List, item: Int): List { - val trash = ArrayList>() - for (i in 1..item) { - trash.add(arr) - } - return trash.reduce { acc, list -> - val temp = ArrayList() - 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) - -} - -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 - ) - ) -} - -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" - } -} - data class HdMovieBoxSource( @JsonProperty("videoUrl") val videoUrl: String? = null, @JsonProperty("videoServer") val videoServer: String? = null, diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt new file mode 100644 index 00000000..160185bd --- /dev/null +++ b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt @@ -0,0 +1,203 @@ +package com.hexated + +import com.lagradost.cloudstream3.base64Decode +import com.lagradost.cloudstream3.base64Encode +import com.lagradost.cloudstream3.network.WebViewResolver +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities +import com.lagradost.cloudstream3.utils.getQualityFromName +import com.lagradost.nicehttp.requestCreator +import okhttp3.HttpUrl.Companion.toHttpUrl +import java.net.URI + +data class FilmxyCookies( + val phpsessid: String? = null, + val wLog: String? = null, + val wSec: String? = null, +) + +fun String.filterIframe(seasonNum: Int?, year: Int?): Boolean { + return if (seasonNum != null) { + if (seasonNum == 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 + ) && this.contains("$yearNum") + 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 getFilmxyCookies(imdbId: String? = null, season: Int? = null): FilmxyCookies? { + + val url = if (season == null) { + "${SoraStream.filmxyAPI}/movie/$imdbId" + } else { + "${SoraStream.filmxyAPI}/tv/$imdbId" + } + val cookieUrl = "${SoraStream.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 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 getBaseUrl(url: String): String { + return URI(url).let { + "${it.scheme}://${it.host}" + } +} + +fun decryptStreamUrl(data: String): String { + + fun getTrash(arr: List, item: Int): List { + val trash = ArrayList>() + for (i in 1..item) { + trash.add(arr) + } + return trash.reduce { acc, list -> + val temp = ArrayList() + 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 + ) + ) +} \ No newline at end of file diff --git a/YomoviesProvider/build.gradle.kts b/YomoviesProvider/build.gradle.kts index c8f09aa1..ae70b277 100644 --- a/YomoviesProvider/build.gradle.kts +++ b/YomoviesProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 10 +version = 11 cloudstream { diff --git a/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProvider.kt b/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProvider.kt index 56742adc..cfa8201e 100644 --- a/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProvider.kt +++ b/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProvider.kt @@ -10,7 +10,8 @@ import org.jsoup.nodes.Element import java.net.URI class YomoviesProvider : MainAPI() { - override var mainUrl = "https://yomovies.icu" + override var mainUrl = "https://yomovies.run" + private var directUrl = mainUrl override var name = "Yomovies" override val hasMainPage = true override var lang = "hi" @@ -64,8 +65,9 @@ class YomoviesProvider : MainAPI() { } override suspend fun load(url: String): LoadResponse? { - val document = app.get(url).document - + val request = app.get(url) + directUrl = getBaseUrl(request.url) + val document = request.document val title = document.selectFirst("div.mvic-desc h3")?.text()?.trim() ?: return null val poster = fixUrlNull(document.selectFirst("div.thumb.mvic-thumb img")?.attr("src")) val tags = document.select("div.mvici-left p:nth-child(1) a").map { it.text() } @@ -140,31 +142,30 @@ class YomoviesProvider : MainAPI() { callback: (ExtractorLink) -> Unit ): Boolean { - if (data.startsWith(mainUrl)) { - val req = app.get(data) - val ref = getBaseUrl(req.url) - req.document.select("div.movieplay iframe").map { fixUrl(it.attr("src")) } + if (data.contains("yomovies")) { + val doc = app.get(data).document + doc.select("div.movieplay iframe").map { fixUrl(it.attr("src")) } .apmap { source -> safeApiCall { when { source.startsWith("https://membed.net") -> app.get( source, - referer = "$ref/" + referer = "$directUrl/" ).document.select("ul.list-server-items li") .apmap { loadExtractor( it.attr("data-video").substringBefore("=https://msubload"), - "$ref/", + "$directUrl/", subtitleCallback, callback ) } - else -> loadExtractor(source, "$ref/", subtitleCallback, callback) + else -> loadExtractor(source, "$directUrl/", subtitleCallback, callback) } } } } else { - loadExtractor(data, "$mainUrl/", subtitleCallback, callback) + loadExtractor(data, "$directUrl/", subtitleCallback, callback) } return true