From e9d716663cf458dced348a87cd9dc6b3be2d24c5 Mon Sep 17 00:00:00 2001 From: hexated Date: Fri, 9 Dec 2022 15:44:01 +0700 Subject: [PATCH] [Sora] fixed Gdbot - enabled GMovies & FDMovies - added M4uhd --- SoraStream/build.gradle.kts | 2 +- .../main/kotlin/com/hexated/SoraExtractor.kt | 103 +++++++++++++++++- .../src/main/kotlin/com/hexated/SoraStream.kt | 19 ++-- .../kotlin/com/hexated/SoraStreamPlugin.kt | 1 + .../src/main/kotlin/com/hexated/SoraUtils.kt | 25 +++++ 5 files changed, 139 insertions(+), 11 deletions(-) diff --git a/SoraStream/build.gradle.kts b/SoraStream/build.gradle.kts index 91bf35ff..00119a4f 100644 --- a/SoraStream/build.gradle.kts +++ b/SoraStream/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 48 +version = 49 cloudstream { diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt index feb62c4d..29a04897 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt @@ -8,9 +8,9 @@ import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.nicehttp.Requests import com.lagradost.nicehttp.Session import com.google.gson.JsonParser +import com.lagradost.cloudstream3.extractors.XStreamCdn import com.lagradost.cloudstream3.network.CloudflareKiller import kotlinx.coroutines.delay -import okhttp3.FormBody import okhttp3.RequestBody.Companion.toRequestBody val session = Session(Requests().baseClient) @@ -1343,7 +1343,7 @@ object SoraExtractor : SoraStream() { iframe.apmap { (iframeLink, title) -> val size = Regex("(?i)\\s(\\S+gb|mb)").find(title)?.groupValues?.getOrNull(1) val gdBotLink = extractGdbot(iframeLink) - val videoLink = extractDrivebot(gdBotLink ?: return@apmap null) + val videoLink = extractDirectDl(gdBotLink ?: return@apmap null) callback.invoke( ExtractorLink( @@ -1386,7 +1386,7 @@ object SoraExtractor : SoraStream() { iframe.apmap { (link, quality, size) -> val fdLink = bypassFdAds(link) val gdBotLink = extractGdbot(fdLink ?: return@apmap null) - val videoLink = extractDrivebot(gdBotLink ?: return@apmap null) + val videoLink = extractDirectDl(gdBotLink ?: return@apmap null) callback.invoke( ExtractorLink( @@ -1401,7 +1401,100 @@ object SoraExtractor : SoraStream() { } + suspend fun invokeM4uhd( + title: String? = null, + year: Int? = null, + season: Int? = null, + episode: Int? = null, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val res = app.get("$m4uhdAPI/search/${title.fixTitle()}.html").document + val scriptData = res.select("div.row div.item").map { + Triple( + it.selectFirst("img.imagecover")?.attr("title"), + it.selectFirst("div.jtip-top div:last-child")?.text(), + it.selectFirst("a")?.attr("href") + ) + } + val script = if (scriptData.size == 1) { + scriptData.firstOrNull() + } else { + scriptData.find { + it.first?.contains( + "Watch Free ${title?.replace(":", "")}", + true + ) == true && (it.first?.contains("$year") == true || it.second?.contains( + "$year" + ) == true) + } + } + + val link = fixUrl(script?.third ?: return, m4uhdAPI) + val request = app.get(link) + var cookiesSet = request.headers.filter { it.first == "set-cookie" } + var xsrf = cookiesSet.find { it.second.contains("XSRF-TOKEN") }?.second?.substringAfter("XSRF-TOKEN=") + ?.substringBefore(";") + var session = cookiesSet.find { it.second.contains("laravel_session") }?.second?.substringAfter("laravel_session=") + ?.substringBefore(";") + + val doc = request.document + val token = doc.selectFirst("meta[name=csrf-token]")?.attr("content") + val m4uData = if (season == null) { + doc.select("div.le-server span#fem").attr("data") + } else { + val episodeData = doc.selectFirst("div.col-lg-9.col-xl-9 p:matches((?i)S0?$season-E0?$episode$)") ?: return + val idepisode = episodeData.select("button").attr("idepisode") ?: return + val requestEmbed = app.post( + "$m4uhdAPI/ajaxtv", + data = mapOf( + "idepisode" to idepisode, + "_token" to "$token" + ), + referer = link, + headers = mapOf( + "X-Requested-With" to "XMLHttpRequest", + ), + cookies = mapOf( + "laravel_session" to "$session", + "XSRF-TOKEN" to "$xsrf", + ) + ) + cookiesSet = requestEmbed.headers.filter { it.first == "set-cookie" } + xsrf = cookiesSet.find { it.second.contains("XSRF-TOKEN") }?.second?.substringAfter("XSRF-TOKEN=") + ?.substringBefore(";") + session = cookiesSet.find { it.second.contains("laravel_session") }?.second?.substringAfter("laravel_session=") + ?.substringBefore(";") + requestEmbed.document.select("span#fem").attr("data") + } + + val iframe = app.post( + "$m4uhdAPI/ajax", + data = mapOf( + "m4u" to m4uData, + "_token" to "$token" + ), + referer = link, + headers = mapOf( + "Accept" to "*/*", + "X-Requested-With" to "XMLHttpRequest", + ), + cookies = mapOf( + "laravel_session" to "$session", + "XSRF-TOKEN" to "$xsrf", + ), + ).document.select("iframe").attr("src") + + loadExtractor(iframe, m4uhdAPI, subtitleCallback, callback) + + } + +} + +class StreamM4u: XStreamCdn() { + override val name: String = "StreamM4u" + override val mainUrl: String = "https://streamm4u.club" } data class UHDBackupUrl( @@ -1556,4 +1649,8 @@ data class SourcesFwatayako( data class DriveBotLink( @JsonProperty("url") val url: String? = null, +) + +data class DirectDl( + @JsonProperty("download_url") val download_url: String? = null, ) \ No newline at end of file diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt index db3337ee..abf4ab9a 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt @@ -25,6 +25,7 @@ import com.hexated.SoraExtractor.invokeFDMovies import com.hexated.SoraExtractor.invokeFwatayako import com.hexated.SoraExtractor.invokeGMovies import com.hexated.SoraExtractor.invokeLing +import com.hexated.SoraExtractor.invokeM4uhd import com.hexated.SoraExtractor.invokeUhdmovies import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.toJson @@ -67,7 +68,7 @@ open class SoraStream : TmdbProvider() { const val uniqueStreamAPI = "https://uniquestream.net" const val filmxyAPI = "https://www.filmxy.vip" const val kimcartoonAPI = "https://kimcartoon.li" - const val xMovieAPI = "https://xemovies.net" + const val xMovieAPI = "https://xemovies.to" const val consumetFlixhqAPI = "https://api.consumet.org/movies/flixhq" const val consumetZoroAPI = "https://api.consumet.org/anime/zoro" const val kissKhAPI = "https://kisskh.me" @@ -76,6 +77,7 @@ open class SoraStream : TmdbProvider() { const val fwatayakoAPI = "https://5100.svetacdn.in" const val gMoviesAPI = "https://gdrivemovies.xyz" const val fdMoviesAPI = "https://freedrivemovie.com" + const val m4uhdAPI = "https://m4uhd.tv" fun getType(t: String?): TvType { return when (t) { @@ -420,12 +422,15 @@ open class SoraStream : TmdbProvider() { { invokeFwatayako(res.imdbId, res.season, res.episode, subtitleCallback, callback) }, -// { -// if(!res.isAnime) invokeGMovies(res.title, res.year, res.season, res.episode, subtitleCallback, callback) -// }, -// { -// if(!res.isAnime) invokeFDMovies(res.title, res.season, res.episode, subtitleCallback, callback) -// }, + { + if(!res.isAnime) invokeGMovies(res.title, res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if(!res.isAnime) invokeFDMovies(res.title, res.season, res.episode, subtitleCallback, callback) + }, + { + invokeM4uhd(res.title, res.year, res.season, res.episode, subtitleCallback, callback) + } ) return true diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStreamPlugin.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStreamPlugin.kt index bdf4216e..131c2895 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStreamPlugin.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStreamPlugin.kt @@ -10,5 +10,6 @@ class SoraStreamPlugin: Plugin() { override fun load(context: Context) { // All providers should be added in this manner. Please don't edit the providers list directly. registerMainAPI(SoraStream()) + registerExtractorAPI(StreamM4u()) } } \ No newline at end of file diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt index 87d0f41e..307649ab 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt @@ -11,9 +11,12 @@ import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.Qualities import com.lagradost.cloudstream3.utils.getQualityFromName +import com.lagradost.nicehttp.RequestBodyTypes import com.lagradost.nicehttp.requestCreator import okhttp3.FormBody import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.RequestBody.Companion.toRequestBody import java.net.URI data class FilmxyCookies( @@ -136,6 +139,28 @@ suspend fun extractGdbot(url: String): String? { 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(json)?.download_url +} + suspend fun extractDrivebot(url: String): String? { val iframeGdbot = app.get(url).document.selectFirst("li.flex.flex-col.py-6 a:contains(Drivebot)")