From 01899b2b8c8471601fdfc1a098b84ee816818a27 Mon Sep 17 00:00:00 2001 From: hexated Date: Tue, 19 Sep 2023 09:48:36 +0700 Subject: [PATCH] solve #283 --- SoraStream/build.gradle.kts | 2 +- .../src/main/kotlin/com/hexated/Extractors.kt | 49 ++++++ .../main/kotlin/com/hexated/SoraExtractor.kt | 156 +----------------- .../src/main/kotlin/com/hexated/SoraParser.kt | 8 - .../src/main/kotlin/com/hexated/SoraStream.kt | 40 +---- .../main/kotlin/com/hexated/SoraStreamLite.kt | 14 -- .../kotlin/com/hexated/SoraStreamPlugin.kt | 1 + 7 files changed, 62 insertions(+), 208 deletions(-) diff --git a/SoraStream/build.gradle.kts b/SoraStream/build.gradle.kts index 00f5658e..71382c79 100644 --- a/SoraStream/build.gradle.kts +++ b/SoraStream/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.konan.properties.Properties // use an integer for version numbers -version = 171 +version = 172 android { defaultConfig { diff --git a/SoraStream/src/main/kotlin/com/hexated/Extractors.kt b/SoraStream/src/main/kotlin/com/hexated/Extractors.kt index 065b7c1b..4f846a8c 100644 --- a/SoraStream/src/main/kotlin/com/hexated/Extractors.kt +++ b/SoraStream/src/main/kotlin/com/hexated/Extractors.kt @@ -135,6 +135,55 @@ open class Playm4u : ExtractorApi() { } +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(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, + ) + +} + open class VCloud : ExtractorApi() { override val name: String = "V-Cloud" override val mainUrl: String = "https://v-cloud.bio" diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt index afd1127f..6d913ac5 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt @@ -200,36 +200,6 @@ object SoraExtractor : SoraStream() { } - suspend fun invokeMovieHab( - imdbId: String? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { - val url = if (season == null) { - "$movieHabAPI/embed/movie?imdb=$imdbId" - } else { - "$movieHabAPI/embed/series?imdb=$imdbId&sea=$season&epi=$episode" - } - - val doc = app.get(url, referer = "$movieHabAPI/").document - val movieId = doc.selectFirst("div#embed-player")?.attr("data-movie-id") ?: return - - doc.select("div.dropdown-menu a").apmap { - val dataId = it.attr("data-id") - app.get( - "$movieHabAPI/ajax/get_stream_link?id=$dataId&movie=$movieId&is_init=true&captcha=&ref=", - referer = url, - headers = mapOf("X-Requested-With" to "XMLHttpRequest") - ).parsedSafe()?.data?.let { res -> - loadExtractor( - res.link ?: return@let null, movieHabAPI, subtitleCallback, callback - ) - } - } - } - suspend fun invokeDreamfilm( title: String? = null, season: Int? = null, @@ -1457,11 +1427,10 @@ object SoraExtractor : SoraStream() { val (seasonSlug, episodeSlug) = getEpisodeSlug(season, episode) val req = app.get("$m4uhdAPI/search/${title.createSlug()}.html") val referer = getBaseUrl(req.url) - val res = req.document - val scriptData = res.select("div.row div.item").map { ele -> + val scriptData = req.document.select("div.row div.item").map { ele -> Triple( ele.select("div.tiptitle p").text(), - ele.select("div.jtip-top div:last-child").text().filter { it.isDigit() }, + ele.select("div.jtip-top div:last-child").text().substringBefore("–").filter { it.isDigit() }, ele.selectFirst("a")?.attr("href") ) } @@ -1478,13 +1447,8 @@ object SoraExtractor : SoraStream() { val link = fixUrl(script?.third ?: return, referer) 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(";") + var cookies = request.cookies + val headers = mapOf("Accept" to "*/*", "X-Requested-With" to "XMLHttpRequest",) val doc = request.document val token = doc.selectFirst("meta[name=csrf-token]")?.attr("content") @@ -1498,22 +1462,9 @@ object SoraExtractor : SoraStream() { val requestEmbed = app.post( "$referer/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", - ) + ), referer = link, headers = headers, cookies = cookies ) - 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(";") + cookies = requestEmbed.cookies requestEmbed.document.select("div.le-server span").map { it.attr("data") } } @@ -1524,14 +1475,8 @@ object SoraExtractor : SoraStream() { "m4u" to data, "_token" to "$token" ), referer = link, - headers = mapOf( - "Accept" to "*/*", - "X-Requested-With" to "XMLHttpRequest", - ), - cookies = mapOf( - "laravel_session" to "$session", - "XSRF-TOKEN" to "$xsrf", - ), + headers = headers, + cookies = cookies, ).document.select("iframe").attr("src") loadExtractor(iframe, referer, subtitleCallback, callback) @@ -1651,43 +1596,6 @@ object SoraExtractor : SoraStream() { } } - suspend fun invokeMoviesbay( - title: String? = null, - year: Int? = null, - callback: (ExtractorLink) -> Unit - ) { - val url = - "https://sheets.googleapis.com/v4/spreadsheets/12RD3HX3NkSiCyqQJxemyS8W0R9B7J4VBl35uLBa5W0E/values/main?alt=json&key=AIzaSyA_ZY8GYxyUZYlcKGkDIHuku_gmE4z-AHQ" - val json = app.get(url, referer = "$moviesbayAPI/") - .parsedSafe()?.values - - val media = json?.find { it.first() == "${title.createSlug()}-$year" } - - media?.filter { it.startsWith("https://drive.google.com") || it.startsWith("https://cdn.moviesbay.live") } - ?.apmap { - val index = media.indexOf(it) - val size = media[index.minus(1)] - val quality = media[index.minus(2)] - val qualityName = media[index.minus(3)] - val link = if (it.startsWith("https://drive.google.com")) { - getDirectGdrive(it) - } else { - it.removeSuffix("?a=view") - } - - callback.invoke( - ExtractorLink( - "Moviesbay", - "Moviesbay $qualityName [$size]", - link, - "", - getQualityFromName(quality) - ) - ) - - } - } - suspend fun invokeMoviezAdd( apiUrl: String? = null, api: String? = null, @@ -2651,54 +2559,6 @@ object SoraExtractor : SoraStream() { } - suspend fun invokeFourCartoon( - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit - ) { - val fixTitle = title.createSlug() - val headers = mapOf( - "X-Requested-With" to "XMLHttpRequest" - ) - val url = if (season == null) { - "$fourCartoonAPI/movies/$fixTitle-$year" - } else { - "$fourCartoonAPI/episode/$fixTitle-season-$season-episode-$episode" - } - - val document = app.get(url).document - val id = document.selectFirst("input[name=idpost]")?.attr("value") - val server = app.get( - "$fourCartoonAPI/ajax-get-link-stream/?server=streamango&filmId=${id ?: return}", - headers = headers - ).text - val hash = - getAndUnpack(app.get(server, referer = fourCartoonAPI).text).substringAfter("(\"") - .substringBefore("\",") - val iframeUrl = getBaseUrl(server) - val source = app.post( - "$iframeUrl/player/index.php?data=$hash&do=getVideo", data = mapOf( - "hast" to hash, - "r" to "$fourCartoonAPI/", - ), - headers = headers - ).parsedSafe()?.videoSource - - callback.invoke( - ExtractorLink( - "4Cartoon", - "4Cartoon", - source ?: return, - "$iframeUrl/", - Qualities.P720.value, - true, - ) - ) - - } - suspend fun invokeSusflix( tmdbId: Int? = null, season: Int? = null, diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt index 0496a55d..b85cf61d 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt @@ -42,10 +42,6 @@ data class UHDBackupUrl( @JsonProperty("url") val url: String? = null, ) -data class MoviesbayValues( - @JsonProperty("values") val values: List>? = arrayListOf(), -) - data class ResponseHash( @JsonProperty("embed_url") val embed_url: String, @JsonProperty("key") val key: String? = null, @@ -391,10 +387,6 @@ data class EMovieTraks( @JsonProperty("label") val label: String? = null, ) -data class FourCartoonSources( - @JsonProperty("videoSource") val videoSource: String? = null, -) - data class WatchhubStream( @JsonProperty("name") val name: String? = null, @JsonProperty("externalUrl") val externalUrl: String? = null, diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt index 6b927c90..25f6dea4 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt @@ -8,7 +8,6 @@ import com.hexated.SoraExtractor.invokeCryMovies import com.hexated.SoraExtractor.invokeDbgo import com.hexated.SoraExtractor.invokeFilmxy import com.hexated.SoraExtractor.invokeKimcartoon -import com.hexated.SoraExtractor.invokeMovieHab import com.hexated.SoraExtractor.invokeVidSrc import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer @@ -25,7 +24,6 @@ import com.hexated.SoraExtractor.invokeGoku import com.hexated.SoraExtractor.invokeKisskh import com.hexated.SoraExtractor.invokeLing import com.hexated.SoraExtractor.invokeM4uhd -import com.hexated.SoraExtractor.invokeMoviesbay import com.hexated.SoraExtractor.invokeMoviezAdd import com.hexated.SoraExtractor.invokeNavy import com.hexated.SoraExtractor.invokeNinetv @@ -36,7 +34,6 @@ import com.hexated.SoraExtractor.invokeShinobiMovies import com.hexated.SoraExtractor.invokeSmashyStream import com.hexated.SoraExtractor.invokeDumpStream import com.hexated.SoraExtractor.invokeEmovies -import com.hexated.SoraExtractor.invokeFourCartoon import com.hexated.SoraExtractor.invokeHdmovies4u import com.hexated.SoraExtractor.invokeJump1 import com.hexated.SoraExtractor.invokeMoment @@ -90,7 +87,6 @@ open class SoraStream : TmdbProvider() { const val twoEmbedAPI = "https://www.2embed.cc" const val vidSrcAPI = "https://v2.vidsrc.me" const val dbgoAPI = "https://dbgo.fun" - const val movieHabAPI = "https://moviehab.com" const val dreamfilmAPI = "https://dreamfilmsw.net" const val noverseAPI = "https://www.nollyverse.com" const val filmxyAPI = "https://www.filmxy.vip" @@ -99,15 +95,14 @@ open class SoraStream : TmdbProvider() { const val crunchyrollAPI = "https://beta-api.crunchyroll.com" const val kissKhAPI = "https://kisskh.co" const val lingAPI = "https://ling-online.net" - const val uhdmoviesAPI = "https://uhdmovies.wiki" + const val uhdmoviesAPI = "https://uhdmovies.store" const val fwatayakoAPI = "https://5100.svetacdn.in" const val gMoviesAPI = "https://gdrivemovies.xyz" const val fdMoviesAPI = "https://freedrivemovie.lol" const val m4uhdAPI = "https://ww2.m4ufree.com" const val tvMoviesAPI = "https://www.tvseriesnmovies.com" - const val moviezAddAPI = "https://ww2.moviezaddiction.click" - const val bollyMazaAPI = "https://m.bollymaza.click" - const val moviesbayAPI = "https://moviesbay.live" + const val moviezAddAPI = "https://ww3.moviezaddiction.click" + const val bollyMazaAPI = "https://ww3.bollymaza.click" const val rStreamAPI = "https://remotestre.am" const val flixonAPI = "https://flixon.lol" const val smashyStreamAPI = "https://embed.smashystream.com" @@ -120,7 +115,6 @@ open class SoraStream : TmdbProvider() { const val navyAPI = "https://navy-issue-i-239.site" const val emoviesAPI = "https://emovies.si" const val pobmoviesAPI = "https://pobmovies.cam" - const val fourCartoonAPI = "https://4cartoon.net" const val multimoviesAPI = "https://multi-movies.xyz" const val netmoviesAPI = "https://web.netmovies.to" const val momentAPI = "https://moment-explanation-i-244.site" @@ -404,9 +398,6 @@ open class SoraStream : TmdbProvider() { { invokeDbgo(res.imdbId, res.season, res.episode, subtitleCallback, callback) }, - { - invokeMovieHab(res.imdbId, res.season, res.episode, subtitleCallback, callback) - }, { if (res.isAnime) invokeAnimes( res.title, @@ -522,13 +513,6 @@ open class SoraStream : TmdbProvider() { { invokeTvMovies(res.title, res.season, res.episode, callback) }, - { - if (res.season == null) invokeMoviesbay( - res.title, - res.year, - callback - ) - }, { if (!res.isAnime) invokeMoviezAdd( moviezAddAPI, @@ -676,15 +660,6 @@ open class SoraStream : TmdbProvider() { callback ) }, - { - if (!res.isAnime) invokeFourCartoon( - res.title, - res.year, - res.season, - res.episode, - callback - ) - }, { invokeMultimovies(res.title, res.season, res.episode, subtitleCallback, callback) }, @@ -919,13 +894,4 @@ open class SoraStream : TmdbProvider() { @JsonProperty("alternative_titles") val alternative_titles: ResultsAltTitles? = null, ) - data class MovieHabData( - @JsonProperty("link") val link: String? = null, - @JsonProperty("token") val token: String? = null, - ) - - data class MovieHabRes( - @JsonProperty("data") val data: MovieHabData? = null, - ) - } diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt index e2a59297..79053efc 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt @@ -14,7 +14,6 @@ import com.hexated.SoraExtractor.invokeKimcartoon import com.hexated.SoraExtractor.invokeKisskh import com.hexated.SoraExtractor.invokeLing import com.hexated.SoraExtractor.invokeM4uhd -import com.hexated.SoraExtractor.invokeMovieHab import com.hexated.SoraExtractor.invokeNavy import com.hexated.SoraExtractor.invokeNinetv import com.hexated.SoraExtractor.invokeNowTv @@ -23,7 +22,6 @@ import com.hexated.SoraExtractor.invokeRidomovies import com.hexated.SoraExtractor.invokeSmashyStream import com.hexated.SoraExtractor.invokeDumpStream import com.hexated.SoraExtractor.invokeEmovies -import com.hexated.SoraExtractor.invokeFourCartoon import com.hexated.SoraExtractor.invokeJump1 import com.hexated.SoraExtractor.invokeMoment import com.hexated.SoraExtractor.invokeMultimovies @@ -110,9 +108,6 @@ class SoraStreamLite : SoraStream() { { invokeDbgo(res.imdbId, res.season, res.episode, subtitleCallback, callback) }, - { - invokeMovieHab(res.imdbId, res.season, res.episode, subtitleCallback, callback) - }, { if (res.isAnime) invokeAnimes( res.title, @@ -269,15 +264,6 @@ class SoraStreamLite : SoraStream() { callback ) }, - { - if (!res.isAnime) invokeFourCartoon( - res.title, - res.year, - res.season, - res.episode, - callback - ) - }, { invokeMultimovies(res.title, res.season, res.episode, subtitleCallback, callback) }, diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStreamPlugin.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStreamPlugin.kt index 758ba3f5..224dcc9b 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStreamPlugin.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStreamPlugin.kt @@ -21,5 +21,6 @@ class SoraStreamPlugin: Plugin() { registerExtractorAPI(VCloud()) registerExtractorAPI(Pixeldra()) registerExtractorAPI(Hubcloud()) + registerExtractorAPI(M4ufree()) } } \ No newline at end of file