From 29c78d2468f2f2ce7ceb28cd6d7f1875df30ba44 Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 3 Jan 2024 06:57:41 +0700 Subject: [PATCH] sora: added mMovies & fix oploverz --- OploverzProvider/build.gradle.kts | 2 +- .../src/main/kotlin/com/hexated/Extractors.kt | 35 + .../kotlin/com/hexated/OploverzProvider.kt | 2 +- .../com/hexated/OploverzProviderPlugin.kt | 1 + SoraStream/build.gradle.kts | 2 +- .../src/main/kotlin/com/hexated/Extractors.kt | 8 +- .../main/kotlin/com/hexated/SoraExtractor.kt | 1872 +++++------------ .../src/main/kotlin/com/hexated/SoraParser.kt | 362 ++-- .../src/main/kotlin/com/hexated/SoraStream.kt | 879 +++----- .../main/kotlin/com/hexated/SoraStreamLite.kt | 402 +--- 10 files changed, 1079 insertions(+), 2486 deletions(-) diff --git a/OploverzProvider/build.gradle.kts b/OploverzProvider/build.gradle.kts index e2ebbfc0..a8b4e717 100644 --- a/OploverzProvider/build.gradle.kts +++ b/OploverzProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 24 +version = 25 cloudstream { diff --git a/OploverzProvider/src/main/kotlin/com/hexated/Extractors.kt b/OploverzProvider/src/main/kotlin/com/hexated/Extractors.kt index c38c13b8..02a8f86d 100644 --- a/OploverzProvider/src/main/kotlin/com/hexated/Extractors.kt +++ b/OploverzProvider/src/main/kotlin/com/hexated/Extractors.kt @@ -42,4 +42,39 @@ open class Qiwi : ExtractorApi() { ?: Qualities.Unknown.value } +} + +open class Mediafire : ExtractorApi() { + override val name = "Mediafire" + override val mainUrl = "https://www.mediafire.com" + override val requiresReferer = true + + override suspend fun getUrl( + url: String, + referer: String?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val res = app.get(url, referer = referer).document + val title = res.select("div.dl-btn-label").text() + val video = res.selectFirst("a#downloadButton")?.attr("href") + + callback.invoke( + ExtractorLink( + this.name, + this.name, + video ?: return, + "", + getQuality(title), + INFER_TYPE + ) + ) + + } + + private fun getQuality(str: String?): Int { + return Regex("(\\d{3,4})[pP]").find(str ?: "")?.groupValues?.getOrNull(1)?.toIntOrNull() + ?: Qualities.Unknown.value + } + } \ No newline at end of file diff --git a/OploverzProvider/src/main/kotlin/com/hexated/OploverzProvider.kt b/OploverzProvider/src/main/kotlin/com/hexated/OploverzProvider.kt index 8ed03196..4d5dc26d 100644 --- a/OploverzProvider/src/main/kotlin/com/hexated/OploverzProvider.kt +++ b/OploverzProvider/src/main/kotlin/com/hexated/OploverzProvider.kt @@ -7,7 +7,7 @@ import com.lagradost.cloudstream3.utils.* import org.jsoup.nodes.Element class OploverzProvider : MainAPI() { - override var mainUrl = "https://oploverz.red" + override var mainUrl = "https://oploverz.life" override var name = "Oploverz" override val hasMainPage = true override var lang = "id" diff --git a/OploverzProvider/src/main/kotlin/com/hexated/OploverzProviderPlugin.kt b/OploverzProvider/src/main/kotlin/com/hexated/OploverzProviderPlugin.kt index ba7c0b85..a635a694 100644 --- a/OploverzProvider/src/main/kotlin/com/hexated/OploverzProviderPlugin.kt +++ b/OploverzProvider/src/main/kotlin/com/hexated/OploverzProviderPlugin.kt @@ -11,5 +11,6 @@ class OploverzProviderPlugin: Plugin() { // All providers should be added in this manner. Please don't edit the providers list directly. registerMainAPI(OploverzProvider()) registerExtractorAPI(Qiwi()) + registerExtractorAPI(Mediafire()) } } \ No newline at end of file diff --git a/SoraStream/build.gradle.kts b/SoraStream/build.gradle.kts index 8c2f717a..f157e229 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 = 211 +version = 212 android { defaultConfig { diff --git a/SoraStream/src/main/kotlin/com/hexated/Extractors.kt b/SoraStream/src/main/kotlin/com/hexated/Extractors.kt index 9f50b592..1674ebc2 100644 --- a/SoraStream/src/main/kotlin/com/hexated/Extractors.kt +++ b/SoraStream/src/main/kotlin/com/hexated/Extractors.kt @@ -339,13 +339,7 @@ open class Netembed : ExtractorApi() { val script = getAndUnpack(response.text) val m3u8 = Regex("((https:|http:)//.*\\.m3u8)").find(script)?.groupValues?.getOrNull(1) ?: return - if (!m3u8.startsWith("https://www.febbox.com")) { - M3u8Helper.generateM3u8( - this.name, - m3u8, - "$mainUrl/", - ).forEach(callback) - } + M3u8Helper.generateM3u8(this.name, m3u8, "$mainUrl/", ).forEach(callback) } } diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt index 1a9392d6..5e556735 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt @@ -10,6 +10,7 @@ import com.lagradost.nicehttp.Session import com.lagradost.cloudstream3.extractors.helper.AesHelper.cryptoAESHandler import com.lagradost.nicehttp.RequestBodyTypes import kotlinx.coroutines.delay +import okhttp3.Interceptor import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.RequestBody.Companion.toRequestBody import org.jsoup.Jsoup @@ -20,35 +21,20 @@ val session = Session(Requests().baseClient) object SoraExtractor : SoraStream() { - suspend fun invokeGoku( - title: String? = null, - year: Int? = null, - season: Int? = null, - lastSeason: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { - val headers = mapOf( - "X-Requested-With" to "XMLHttpRequest" - ) + suspend fun invokeGoku(title: String? = null, year: Int? = null, season: Int? = null, lastSeason: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { + val headers = mapOf("X-Requested-With" to "XMLHttpRequest") fun Document.getServers(): List> { return this.select("a").map { it.attr("data-id") to it.text() } } - val media = app.get( - "$gokuAPI/ajax/movie/search?keyword=$title", headers = headers - ).document.select("div.item").find { ele -> + val media = app.get("$gokuAPI/ajax/movie/search?keyword=$title", headers = headers).document.select("div.item").find { ele -> val url = ele.selectFirst("a.movie-link")?.attr("href") val titleMedia = ele.select("h3.movie-name").text() val titleSlug = title.createSlug() val yearMedia = ele.select("div.info-split > div:first-child").text().toIntOrNull() - val lastSeasonMedia = - ele.select("div.info-split > div:nth-child(2)").text().substringAfter("SS") - .substringBefore("/").trim().toIntOrNull() - (titleMedia.equals(title, true) || titleMedia.createSlug() - .equals(titleSlug) || url?.contains("$titleSlug-") == true) && (if (season == null) { + val lastSeasonMedia = ele.select("div.info-split > div:nth-child(2)").text().substringAfter("SS").substringBefore("/").trim().toIntOrNull() + (titleMedia.equals(title, true) || titleMedia.createSlug().equals(titleSlug) || url?.contains("$titleSlug-") == true) && (if (season == null) { yearMedia == year && url?.contains("/movie/") == true } else { lastSeasonMedia == lastSeason && url?.contains("/series/") == true @@ -56,160 +42,91 @@ object SoraExtractor : SoraStream() { } ?: return val serversId = if (season == null) { - val movieId = app.get( - fixUrl( - media.selectFirst("a")?.attr("href") ?: return, gokuAPI - ) - ).url.substringAfterLast("/") - app.get( - "$gokuAPI/ajax/movie/episode/servers/$movieId", headers = headers - ).document.getServers() + val movieId = app.get(fixUrl(media.selectFirst("a")?.attr("href") + ?: return, gokuAPI)).url.substringAfterLast("/") + app.get("$gokuAPI/ajax/movie/episode/servers/$movieId", headers = headers).document.getServers() } else { - val seasonId = app.get( - "$gokuAPI/ajax/movie/seasons/${ - media.selectFirst("a.btn-wl")?.attr("data-id") ?: return - }", headers = headers - ).document.select("a.ss-item").find { it.ownText().equals("Season $season", true) } - ?.attr("data-id") - val episodeId = app.get( - "$gokuAPI/ajax/movie/season/episodes/${seasonId ?: return}", headers = headers - ).document.select("div.item").find { + val seasonId = app.get("$gokuAPI/ajax/movie/seasons/${ + media.selectFirst("a.btn-wl")?.attr("data-id") ?: return + }", headers = headers).document.select("a.ss-item").find { it.ownText().equals("Season $season", true) }?.attr("data-id") + val episodeId = app.get("$gokuAPI/ajax/movie/season/episodes/${seasonId ?: return}", headers = headers).document.select("div.item").find { it.selectFirst("strong")?.text().equals("Eps $episode:", true) }?.selectFirst("a")?.attr("data-id") - app.get( - "$gokuAPI/ajax/movie/episode/servers/${episodeId ?: return}", headers = headers - ).document.getServers() + app.get("$gokuAPI/ajax/movie/episode/servers/${episodeId ?: return}", headers = headers).document.getServers() } serversId.apmap { (id, name) -> - val iframe = - app.get("$gokuAPI/ajax/movie/episode/server/sources/$id", headers = headers) - .parsedSafe()?.data?.link ?: return@apmap + val iframe = app.get("$gokuAPI/ajax/movie/episode/server/sources/$id", headers = headers).parsedSafe()?.data?.link + ?: return@apmap loadCustomExtractor( - name, - iframe, - "$gokuAPI/", - subtitleCallback, - callback, + name, + iframe, + "$gokuAPI/", + subtitleCallback, + callback, ) } } - suspend fun invokeVidSrc( - id: Int? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeVidSrc(id: Int? = null, season: Int? = null, episode: Int? = null, callback: (ExtractorLink) -> Unit) { val url = if (season == null) { "$vidSrcAPI/embed/movie?tmdb=$id" } else { "$vidSrcAPI/embed/tv?tmdb=$id&season=$season&episode=$episode" } - val iframedoc = - app.get(url).document.select("iframe#player_iframe").attr("src").let { httpsify(it) } + val iframedoc = app.get(url).document.select("iframe#player_iframe").attr("src").let { httpsify(it) } val doc = app.get(iframedoc, referer = url).document val index = doc.select("body").attr("data-i") val hash = doc.select("div#hidden").attr("data-h") val srcrcp = deobfstr(hash, index) - val script = app.get( - httpsify(srcrcp), - referer = iframedoc - ).document.selectFirst("script:containsData(Playerjs)")?.data() - val video = script?.substringAfter("file:\"#2")?.substringBefore("\"") - ?.replace(Regex("(//\\S+?=)"), "")?.let { base64Decode(it) } + val script = app.get(httpsify(srcrcp), referer = iframedoc).document.selectFirst("script:containsData(Playerjs)")?.data() + val video = script?.substringAfter("file:\"#2")?.substringBefore("\"")?.replace(Regex("(//\\S+?=)"), "")?.let { base64Decode(it) } - callback.invoke( - ExtractorLink( - "Vidsrc", - "Vidsrc", - video ?: return, - "https://vidsrc.stream/", - Qualities.P1080.value, - INFER_TYPE - ) - ) + callback.invoke(ExtractorLink("Vidsrc", "Vidsrc", video + ?: return, "https://vidsrc.stream/", Qualities.P1080.value, INFER_TYPE)) } - suspend fun invokeDbgo( - id: String? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeDbgo(id: String? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val iframeDbgo: String? val script = if (season == null) { val doc = app.get("$dbgoAPI/imdb.php?id=$id").document iframeDbgo = doc.select("div.myvideo iframe").attr("src") - app.get(iframeDbgo, referer = "$dbgoAPI/").document.select("script") - .find { it.data().contains("CDNplayerConfig =") }?.data() + app.get(iframeDbgo, referer = "$dbgoAPI/").document.select("script").find { it.data().contains("CDNplayerConfig =") }?.data() } else { val doc = app.get("$dbgoAPI/tv-imdb.php?id=$id&s=$season").document iframeDbgo = doc.select("div.myvideo iframe").attr("src") - val token = app.get( - iframeDbgo, referer = "$dbgoAPI/" - ).document.selectFirst("select#translator-name option")?.attr("data-token") - app.get("https://voidboost.net/serial/$token/iframe?s=$season&e=$episode&h=dbgo.fun").document.select( - "script" - ).find { it.data().contains("CDNplayerConfig =") }?.data() + val token = app.get(iframeDbgo, referer = "$dbgoAPI/").document.selectFirst("select#translator-name option")?.attr("data-token") + app.get("https://voidboost.net/serial/$token/iframe?s=$season&e=$episode&h=dbgo.fun").document.select("script").find { it.data().contains("CDNplayerConfig =") }?.data() } ?: return - val source = - Regex("['|\"]file['|\"]:\\s['|\"](#\\S+?)['|\"]").find(script)?.groupValues?.get( - 1 - ) ?: return - val subtitle = - Regex("['|\"]subtitle['|\"]:\\s['|\"](\\S+?)['|\"]").find(script)?.groupValues?.get( - 1 - ) + val source = Regex("['|\"]file['|\"]:\\s['|\"](#\\S+?)['|\"]").find(script)?.groupValues?.get(1) + ?: return + val subtitle = Regex("['|\"]subtitle['|\"]:\\s['|\"](\\S+?)['|\"]").find(script)?.groupValues?.get(1) val ref = getBaseUrl(iframeDbgo) decryptStreamUrl(source).split(",").map { links -> val quality = Regex("\\[(\\d*p.*?)]").find(links)?.groupValues?.getOrNull(1)?.trim() - ?: return@map null + ?: return@map null links.replace("[$quality]", "").split(" or ").map { it.trim() }.map { link -> val name = if (link.contains(".m3u8")) "Dbgo (Main)" else "Dbgo (Backup)" - callback.invoke( - ExtractorLink( - name, - name, - link, - "$ref/", - getQuality(quality), - isM3u8 = link.contains(".m3u8"), - headers = mapOf( - "Origin" to ref - ) - ) - ) + callback.invoke(ExtractorLink(name, name, link, "$ref/", getQuality(quality), isM3u8 = link.contains(".m3u8"), headers = mapOf("Origin" to ref))) } } subtitle?.split(",")?.map { sub -> val language = Regex("\\[(.*)]").find(sub)?.groupValues?.getOrNull(1) ?: return@map null val link = sub.replace("[$language]", "").trim() - subtitleCallback.invoke( - SubtitleFile( - getDbgoLanguage(language), link - ) - ) + subtitleCallback.invoke(SubtitleFile(getDbgoLanguage(language), link)) } } - suspend fun invokeDreamfilm( - title: String? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeDreamfilm(title: String? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val fixTitle = title.createSlug() val url = if (season == null) { "$dreamfilmAPI/$fixTitle" @@ -219,27 +136,13 @@ object SoraExtractor : SoraStream() { val doc = app.get(url).document doc.select("div#videosen a").apmap { - val iframe = app.get(it.attr("href")).document.selectFirst("div.card-video iframe") - ?.attr("data-src") - loadCustomExtractor( - null, - iframe ?: return@apmap, - "$dreamfilmAPI/", - subtitleCallback, - callback, - Qualities.P1080.value - ) + val iframe = app.get(it.attr("href")).document.selectFirst("div.card-video iframe")?.attr("data-src") + loadCustomExtractor(null, iframe + ?: return@apmap, "$dreamfilmAPI/", subtitleCallback, callback, Qualities.P1080.value) } } - suspend fun invokeMultimovies( - apiUrl: String, - title: String? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeMultimovies(apiUrl: String, title: String? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val fixTitle = title.createSlug() val url = if (season == null) { "$apiUrl/movies/$fixTitle" @@ -252,82 +155,47 @@ object SoraExtractor : SoraStream() { if (!iframe.contains("youtube")) { loadExtractor(iframe, "$directUrl/", subtitleCallback) { link -> if (link.quality == Qualities.Unknown.value) { - callback.invoke( - ExtractorLink( - link.source, - link.name, - link.url, - link.referer, - Qualities.P1080.value, - link.type, - link.headers, - link.extractorData - ) - ) + callback.invoke(ExtractorLink(link.source, link.name, link.url, link.referer, Qualities.P1080.value, link.type, link.headers, link.extractorData)) } } } } suspend fun invokeAoneroom( - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit, + title: String? = null, + year: Int? = null, + season: Int? = null, + episode: Int? = null, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit, ) { - val headers = mapOf( - "Authorization" to "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjcyODc3MjQ5OTg4MzA0NzM5NzYsInV0cCI6MSwiZXhwIjoxNzEwMzg4NzczLCJpYXQiOjE3MDI2MTI3NzN9.Myt-gVHfPfQFbFyRX3WXtiiwvRzDwBrXTEKy1l-GDRU" - ) - val subjectId = app.post( - "$aoneroomAPI/wefeed-mobile-bff/subject-api/search", data = mapOf( + val headers = mapOf("Authorization" to "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjcyODc3MjQ5OTg4MzA0NzM5NzYsInV0cCI6MSwiZXhwIjoxNzEwMzg4NzczLCJpYXQiOjE3MDI2MTI3NzN9.Myt-gVHfPfQFbFyRX3WXtiiwvRzDwBrXTEKy1l-GDRU") + val subjectId = app.post("$aoneroomAPI/wefeed-mobile-bff/subject-api/search", data = mapOf( "page" to "1", "perPage" to "10", "keyword" to "$title", "subjectType" to if (season == null) "1" else "2", - ), headers = headers - ).parsedSafe()?.data?.items?.find { + ), headers = headers).parsedSafe()?.data?.items?.find { it.title.equals(title, true) && it.releaseDate?.substringBefore("-") == "$year" }?.subjectId - val data = app.get( - "$aoneroomAPI/wefeed-mobile-bff/subject-api/resource?subjectId=${subjectId ?: return}&page=1&perPage=20&all=0&startPosition=1&endPosition=1&pagerMode=0&resolution=480", - headers = headers - ).parsedSafe()?.data?.list?.findLast { + val data = app.get("$aoneroomAPI/wefeed-mobile-bff/subject-api/resource?subjectId=${subjectId ?: return}&page=1&perPage=20&all=0&startPosition=1&endPosition=1&pagerMode=0&resolution=480", headers = headers).parsedSafe()?.data?.list?.findLast { it.se == (season ?: 0) && it.ep == (episode ?: 0) } - callback.invoke( - ExtractorLink( - "Aoneroom", - "Aoneroom", - data?.resourceLink ?: return, - "", - data.resolution ?: Qualities.Unknown.value, - INFER_TYPE - ) - ) + callback.invoke(ExtractorLink("Aoneroom", "Aoneroom", data?.resourceLink + ?: return, "", data.resolution ?: Qualities.Unknown.value, INFER_TYPE)) data.extCaptions?.map { sub -> - subtitleCallback.invoke( - SubtitleFile( + subtitleCallback.invoke(SubtitleFile( sub.lanName ?: return@map, sub.url ?: return@map, - ) - ) + )) } } - suspend fun invokeWatchCartoon( - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeWatchCartoon(title: String? = null, year: Int? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val fixTitle = title.createSlug() val url = if (season == null) { "$watchCartoonAPI/movies/$fixTitle-$year" @@ -341,39 +209,16 @@ object SoraExtractor : SoraStream() { val id = doc.select("link[rel=shortlink]").attr("href").substringAfterLast("=") doc.select("div.form-group.list-server option").apmap { - val server = app.get( - "$host/ajax-get-link-stream/?server=${it.attr("value")}&filmId=$id", - headers = mapOf( - "X-Requested-With" to "XMLHttpRequest" - ) - ).text + val server = app.get("$host/ajax-get-link-stream/?server=${it.attr("value")}&filmId=$id", headers = mapOf("X-Requested-With" to "XMLHttpRequest")).text loadExtractor(server, "$host/", subtitleCallback) { link -> if (link.quality == Qualities.Unknown.value) { - callback.invoke( - ExtractorLink( - "WatchCartoon", - "WatchCartoon", - link.url, - link.referer, - Qualities.P720.value, - link.type, - link.headers, - link.extractorData - ) - ) + callback.invoke(ExtractorLink("WatchCartoon", "WatchCartoon", link.url, link.referer, Qualities.P720.value, link.type, link.headers, link.extractorData)) } } } } - suspend fun invokeNetmovies( - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeNetmovies(title: String? = null, year: Int? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val fixTitle = title.createSlug() val url = if (season == null) { "$netmoviesAPI/movies/$fixTitle-$year" @@ -383,14 +228,7 @@ object SoraExtractor : SoraStream() { invokeWpmovies(null, url, subtitleCallback, callback) } - suspend fun invokeZshow( - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeZshow(title: String? = null, year: Int? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val fixTitle = title.createSlug() val url = if (season == null) { "$zshowAPI/movie/$fixTitle-$year" @@ -400,43 +238,45 @@ object SoraExtractor : SoraStream() { invokeWpmovies("ZShow", url, subtitleCallback, callback, encrypt = true) } + suspend fun invokeMMovies(title: String? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { + val fixTitle = title.createSlug() + val url = if (season == null) { + "$mMoviesAPI/movies/$fixTitle" + } else { + "$mMoviesAPI/episodes/$fixTitle-${season}x${episode}" + } + + invokeWpmovies(null, url, subtitleCallback, callback, true, hasCloudflare = true, interceptor = multiInterceptor) + } + private suspend fun invokeWpmovies( - name: String? = null, - url: String? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit, - fixIframe: Boolean = false, - encrypt: Boolean = false, + name: String? = null, + url: String? = null, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit, + fixIframe: Boolean = false, + encrypt: Boolean = false, + hasCloudflare: Boolean = false, + interceptor: Interceptor? = null, ) { fun String.fixBloat(): String { return this.replace("\"", "").replace("\\", "") } - val res = app.get(url ?: return) + val res = app.get(url ?: return, interceptor = if (hasCloudflare) interceptor else null) val referer = getBaseUrl(res.url) val document = res.document document.select("ul#playeroptionsul > li").map { - Triple( - it.attr("data-post"), it.attr("data-nume"), it.attr("data-type") - ) + Triple(it.attr("data-post"), it.attr("data-nume"), it.attr("data-type")) }.apmap { (id, nume, type) -> delay(1000) - val json = app.post( - url = "$referer/wp-admin/admin-ajax.php", - data = mapOf( - "action" to "doo_player_ajax", "post" to id, "nume" to nume, "type" to type - ), - headers = mapOf("Accept" to "*/*", "X-Requested-With" to "XMLHttpRequest"), - referer = url - ) + val json = app.post(url = "$referer/wp-admin/admin-ajax.php", data = mapOf("action" to "doo_player_ajax", "post" to id, "nume" to nume, "type" to type), headers = mapOf("Accept" to "*/*", "X-Requested-With" to "XMLHttpRequest"), referer = url, interceptor = if (hasCloudflare) interceptor else null) val source = tryParseJson(json.text)?.let { when { encrypt -> { val meta = tryParseJson(it.embed_url)?.meta ?: return@apmap val key = generateWpKey(it.key ?: return@apmap, meta) - cryptoAESHandler( - it.embed_url, key.toByteArray(), false - )?.fixBloat() + cryptoAESHandler(it.embed_url, key.toByteArray(), false)?.fixBloat() } fixIframe -> Jsoup.parse(it.embed_url).select("IFRAME").attr("SRC") @@ -451,38 +291,21 @@ object SoraExtractor : SoraStream() { } } - suspend fun invokeDoomovies( - title: String? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeDoomovies(title: String? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val res = app.get("$doomoviesAPI/movies/${title.createSlug()}/") val host = getBaseUrl(res.url) val document = res.document - document.select("ul#playeroptionsul > li") - .filter { element -> element.select("span.flag img").attr("src").contains("/en.") } - .map { - Triple( - it.attr("data-post"), it.attr("data-nume"), it.attr("data-type") - ) - }.apmap { (id, nume, type) -> - val source = app.get( - "$host/wp-json/dooplayer/v2/${id}/${type}/${nume}", - headers = mapOf("X-Requested-With" to "XMLHttpRequest"), - referer = "$host/" - ).parsed().embed_url - if (!source.contains("youtube")) { - loadExtractor(source, "$host/", subtitleCallback, callback) - } + document.select("ul#playeroptionsul > li").filter { element -> element.select("span.flag img").attr("src").contains("/en.") }.map { + Triple(it.attr("data-post"), it.attr("data-nume"), it.attr("data-type")) + }.apmap { (id, nume, type) -> + val source = app.get("$host/wp-json/dooplayer/v2/${id}/${type}/${nume}", headers = mapOf("X-Requested-With" to "XMLHttpRequest"), referer = "$host/").parsed().embed_url + if (!source.contains("youtube")) { + loadExtractor(source, "$host/", subtitleCallback, callback) } + } } - suspend fun invokeNoverse( - title: String? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeNoverse(title: String? = null, season: Int? = null, episode: Int? = null, callback: (ExtractorLink) -> Unit) { val fixTitle = title.createSlug() val url = if (season == null) { "$noverseAPI/movie/$fixTitle/download/" @@ -497,36 +320,27 @@ object SoraExtractor : SoraStream() { it.select("a").attr("href") to it.selectFirst("td")?.text() } } else { - doc.select("table.table-striped tbody tr") - .find { it.text().contains("Episode $episode") }?.select("td")?.map { - it.select("a").attr("href") to it.select("a").text() - } + doc.select("table.table-striped tbody tr").find { it.text().contains("Episode $episode") }?.select("td")?.map { + it.select("a").attr("href") to it.select("a").text() + } } ?: return delay(4000) links.map { (link, quality) -> - val name = - quality?.replace(Regex("\\d{3,4}p"), "Noverse")?.replace(".", " ") ?: "Noverse" - callback.invoke( - ExtractorLink( + val name = quality?.replace(Regex("\\d{3,4}p"), "Noverse")?.replace(".", " ") + ?: "Noverse" + callback.invoke(ExtractorLink( "Noverse", name, link, "", getQualityFromName("${quality?.substringBefore("p")?.trim()}p"), - ) - ) + )) } } - suspend fun invokeFilmxy( - imdbId: String? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeFilmxy(imdbId: String? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val url = if (season == null) { "${filmxyAPI}/movie/$imdbId" } else { @@ -536,18 +350,15 @@ object SoraExtractor : SoraStream() { val doc = app.get(url, cookies = filmxyCookies).document val script = doc.selectFirst("script:containsData(var isSingle)")?.data() ?: return - val sourcesData = - Regex("listSE\\s*=\\s?(.*?),[\\n|\\s]").find(script)?.groupValues?.get(1).let { - tryParseJson>>>(it) - } - val sourcesDetail = - Regex("linkDetails\\s*=\\s?(.*?),[\\n|\\s]").find(script)?.groupValues?.get(1).let { - tryParseJson>>(it) - } - val subSourcesData = - Regex("dSubtitles\\s*=\\s?(.*?),[\\n|\\s]").find(script)?.groupValues?.get(1).let { - tryParseJson>>>(it) - } + val sourcesData = Regex("listSE\\s*=\\s?(.*?),[\\n|\\s]").find(script)?.groupValues?.get(1).let { + tryParseJson>>>(it) + } + val sourcesDetail = Regex("linkDetails\\s*=\\s?(.*?),[\\n|\\s]").find(script)?.groupValues?.get(1).let { + tryParseJson>>(it) + } + val subSourcesData = Regex("dSubtitles\\s*=\\s?(.*?),[\\n|\\s]").find(script)?.groupValues?.get(1).let { + tryParseJson>>>(it) + } val (seasonSlug, episodeSlug) = getEpisodeSlug(season, episode) @@ -562,34 +373,24 @@ object SoraExtractor : SoraStream() { subSourcesData?.get("s$seasonSlug")?.get("e$episodeSlug") } - val scriptUser = - doc.select("script").find { it.data().contains("var userNonce") }?.data() ?: return - val userNonce = - Regex("var\\suserNonce.*?[\"|'](\\S+?)[\"|'];").find(scriptUser)?.groupValues?.get(1) - val userId = - Regex("var\\suser_id.*?[\"|'](\\S+?)[\"|'];").find(scriptUser)?.groupValues?.get(1) + val scriptUser = doc.select("script").find { it.data().contains("var userNonce") }?.data() + ?: return + val userNonce = Regex("var\\suserNonce.*?[\"|'](\\S+?)[\"|'];").find(scriptUser)?.groupValues?.get(1) + val userId = Regex("var\\suser_id.*?[\"|'](\\S+?)[\"|'];").find(scriptUser)?.groupValues?.get(1) - val listSources = sources.withIndex() - .groupBy { it.index / 2 } - .map { entry -> entry.value.map { it.value } } + val listSources = sources.withIndex().groupBy { it.index / 2 }.map { entry -> entry.value.map { it.value } } listSources.apmap { src -> val linkIDs = src.joinToString("") { "&linkIDs%5B%5D=$it" }.replace("\"", "") - val json = app.post( - "$filmxyAPI/wp-admin/admin-ajax.php", - requestBody = "action=get_vid_links$linkIDs&user_id=$userId&nonce=$userNonce".toRequestBody(), - referer = url, - headers = mapOf( + val json = app.post("$filmxyAPI/wp-admin/admin-ajax.php", requestBody = "action=get_vid_links$linkIDs&user_id=$userId&nonce=$userNonce".toRequestBody(), referer = url, headers = mapOf( "Accept" to "*/*", "DNT" to "1", "Content-Type" to "application/x-www-form-urlencoded; charset=UTF-8", "Origin" to filmxyAPI, "X-Requested-With" to "XMLHttpRequest", - ), - cookies = filmxyCookies - ).text.let { tryParseJson>(it) } + ), cookies = filmxyCookies).text.let { tryParseJson>(it) } src.map { source -> val link = json?.get(source) @@ -597,42 +398,22 @@ object SoraExtractor : SoraStream() { val server = sourcesDetail?.get(source)?.get("server") val size = sourcesDetail?.get(source)?.get("size") - callback.invoke( - ExtractorLink( - "Filmxy", - "Filmxy $server [$size]", - link ?: return@map, - "$filmxyAPI/", - getQualityFromName(quality) - ) - ) + callback.invoke(ExtractorLink("Filmxy", "Filmxy $server [$size]", link + ?: return@map, "$filmxyAPI/", getQualityFromName(quality))) } } subSources?.mapKeys { sub -> - subtitleCallback.invoke( - SubtitleFile( - SubtitleHelper.fromTwoLettersToLanguage(sub.key) ?: return@mapKeys, - "https://www.mysubs.org/get-subtitle/${sub.value}" - ) - ) + subtitleCallback.invoke(SubtitleFile(SubtitleHelper.fromTwoLettersToLanguage(sub.key) + ?: return@mapKeys, "https://www.mysubs.org/get-subtitle/${sub.value}")) } } - suspend fun invokeDramaday( - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { - fun String.getQuality(): String? = - Regex("""\d{3,4}[pP]""").find(this)?.groupValues?.getOrNull(0) + suspend fun invokeDramaday(title: String? = null, year: Int? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { + fun String.getQuality(): String? = Regex("""\d{3,4}[pP]""").find(this)?.groupValues?.getOrNull(0) - fun String.getTag(): String? = - Regex("""\d{3,4}[pP]\s*(.*)""").find(this)?.groupValues?.getOrNull(1) + fun String.getTag(): String? = Regex("""\d{3,4}[pP]\s*(.*)""").find(this)?.groupValues?.getOrNull(1) val slug = title.createSlug() val epsSlug = getEpisodeSlug(season, episode) @@ -646,19 +427,18 @@ object SoraExtractor : SoraStream() { val servers = if (season == null) { val player = res.select("div.tabs__pane p a[href*=https://ouo]").attr("href") val ouo = bypassOuo(player) - app.get(ouo ?: return).document.select("article p:matches(\\d{3,4}[pP]) + p:has(a)") - .flatMap { ele -> - val entry = ele.previousElementSibling()?.text() ?: "" - ele.select("a").map { - Triple(entry.getQuality(), entry.getTag(), it.attr("href")) - }.filter { - it.third.startsWith("https://pixeldrain.com") || it.third.startsWith("https://krakenfiles.com") - } + app.get(ouo + ?: return).document.select("article p:matches(\\d{3,4}[pP]) + p:has(a)").flatMap { ele -> + val entry = ele.previousElementSibling()?.text() ?: "" + ele.select("a").map { + Triple(entry.getQuality(), entry.getTag(), it.attr("href")) + }.filter { + it.third.startsWith("https://pixeldrain.com") || it.third.startsWith("https://krakenfiles.com") } + } } else { val data = res.select("tbody tr:has(td[data-order=${epsSlug.second}])") - val qualities = - data.select("td:nth-child(2)").attr("data-order").split("
").map { it } + val qualities = data.select("td:nth-child(2)").attr("data-order").split("
").map { it } val iframe = data.select("a[href*=https://ouo]").map { it.attr("href") } qualities.zip(iframe).map { Triple(it.first.getQuality(), it.first.getTag(), it.second) @@ -667,74 +447,13 @@ object SoraExtractor : SoraStream() { servers.filter { it.first == "720p" || it.first == "1080p" }.apmap { val server = if (it.third.startsWith("https://ouo")) bypassOuo(it.third) else it.third - loadCustomTagExtractor( - it.second, - server ?: return@apmap, - "$dramadayAPI/", - subtitleCallback, - callback, - getQualityFromName(it.first) - ) + loadCustomTagExtractor(it.second, server + ?: return@apmap, "$dramadayAPI/", subtitleCallback, callback, getQualityFromName(it.first)) } } - suspend fun invokeWatchflx( - tmdbId: Int? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit - ) { - val epsSlug = getEpisodeSlug(season, episode) - val cookies = getWatchflxCookies() - val url = if (season == null) { - "$watchflxAPI/browse/playmovie/$tmdbId/directplay" - } else { - "$watchflxAPI/Playseries/series/$tmdbId/directplay" - } - val res = app.get(url, cookies = cookies).document - - val showUrl = if (season == null) { - res.selectFirst("iframe.movie_player")?.attr("src") - } else { - val seasonUrl = - res.select("ul.nav.nav-tabs.tabs-left li:matches(Season $season\$) a").attr("href") - val episodeUrl = app.get( - seasonUrl, cookies = cookies - ).document.select("div.thumb-nail-list a:contains(${epsSlug.second}:)").attr("href") - app.get(episodeUrl, cookies = cookies).document.selectFirst("iframe.movie_player") - ?.attr("src") - } - val iframe = app.get( - showUrl ?: return, referer = "$watchflxAPI/" - ).document.selectFirst("div#the_frame iframe")?.attr("src") - ?.let { fixUrl(it, getBaseUrl(showUrl)) } ?: return - - val video = app.get(iframe.replace("/loc/", "/pro/"), referer = iframe).text.let { - """mp4_url\s*=\s*["'](.*)["'];""".toRegex().find(it)?.groupValues?.getOrNull(1) - } - - callback.invoke( - ExtractorLink( - "Watchflx", - "Watchflx", - video ?: return, - "$watchflxAPI/", - Qualities.P1080.value, - INFER_TYPE - ) - ) - - - } - - suspend fun invokeKimcartoon( - title: String? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeKimcartoon(title: String? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val fixTitle = title.createSlug() val doc = if (season == null || season == 1) { app.get("$kimcartoonAPI/Cartoon/$fixTitle").document @@ -750,9 +469,7 @@ object SoraExtractor : SoraStream() { it.attr("href").contains(Regex("(?i)Episode-0*$episode")) }?.attr("href") } ?: return - val servers = - app.get(fixUrl(iframe, kimcartoonAPI)).document.select("#selectServer > option") - .map { fixUrl(it.attr("value"), kimcartoonAPI) } + val servers = app.get(fixUrl(iframe, kimcartoonAPI)).document.select("#selectServer > option").map { fixUrl(it.attr("value"), kimcartoonAPI) } servers.apmap { app.get(it).document.select("#my_video_1").attr("src").let { iframe -> @@ -764,83 +481,53 @@ object SoraExtractor : SoraStream() { } suspend fun invokeDumpStream( - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit, + title: String? = null, + year: Int? = null, + season: Int? = null, + episode: Int? = null, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit, ) { val (id, type) = getDumpIdAndType(title, year, season) val json = fetchDumpEpisodes("$id", "$type", episode) ?: return json.subtitlingList?.map { sub -> - subtitleCallback.invoke( - SubtitleFile( - getVipLanguage(sub.languageAbbr ?: return@map), sub.subtitlingUrl ?: return@map - ) - ) + subtitleCallback.invoke(SubtitleFile(getVipLanguage(sub.languageAbbr + ?: return@map), sub.subtitlingUrl ?: return@map)) } } - suspend fun invokeVidsrcto( - imdbId: String?, - season: Int?, - episode: Int?, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeVidsrcto(imdbId: String?, season: Int?, episode: Int?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val url = if (season == null) { "$vidsrctoAPI/embed/movie/$imdbId" } else { "$vidsrctoAPI/embed/tv/$imdbId/$season/$episode" } - val mediaId = - app.get(url).document.selectFirst("ul.episodes li a")?.attr("data-id") ?: return + val mediaId = app.get(url).document.selectFirst("ul.episodes li a")?.attr("data-id") + ?: return - app.get("$vidsrctoAPI/ajax/embed/episode/$mediaId/sources") - .parsedSafe()?.result?.apmap { - val encUrl = app.get("$vidsrctoAPI/ajax/embed/source/${it.id}") - .parsedSafe()?.result?.url - loadExtractor( - vidsrctoDecrypt(encUrl ?: return@apmap), - "$vidsrctoAPI/", - subtitleCallback, - callback - ) - } + app.get("$vidsrctoAPI/ajax/embed/episode/$mediaId/sources").parsedSafe()?.result?.apmap { + val encUrl = app.get("$vidsrctoAPI/ajax/embed/source/${it.id}").parsedSafe()?.result?.url + loadExtractor(vidsrctoDecrypt(encUrl + ?: return@apmap), "$vidsrctoAPI/", subtitleCallback, callback) + } val subtitles = app.get("$vidsrctoAPI/ajax/embed/episode/$mediaId/subtitles").text tryParseJson>(subtitles)?.map { - subtitleCallback.invoke( - SubtitleFile( - it.label ?: "", - it.file ?: return@map - ) - ) + subtitleCallback.invoke(SubtitleFile(it.label ?: "", it.file ?: return@map)) } } - suspend fun invokeKisskh( - title: String? = null, - season: Int? = null, - episode: Int? = null, - isAnime: Boolean = false, - lastSeason: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeKisskh(title: String? = null, season: Int? = null, episode: Int? = null, isAnime: Boolean = false, lastSeason: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val slug = title.createSlug() ?: return val type = when { isAnime -> "3" season == null -> "2" else -> "1" } - val res = app.get( - "$kissKhAPI/api/DramaList/Search?q=$title&type=$type", referer = "$kissKhAPI/" - ).text.let { + val res = app.get("$kissKhAPI/api/DramaList/Search?q=$title&type=$type", referer = "$kissKhAPI/").text.let { tryParseJson>(it) } ?: return @@ -852,20 +539,15 @@ object SoraExtractor : SoraStream() { when { season == null -> slugTitle == slug lastSeason == 1 -> slugTitle.contains(slug) - else -> (slugTitle.contains(slug) && it.title?.contains( - "Season $season", - true - ) == true) + else -> (slugTitle.contains(slug) && it.title?.contains("Season $season", true) == true) } } ?: res.find { it.title.equals(title) } data?.id to data?.title } - val resDetail = app.get( - "$kissKhAPI/api/DramaList/Drama/$id?isq=false", referer = "$kissKhAPI/Drama/${ - getKisskhTitle(contentTitle) - }?id=$id" - ).parsedSafe() ?: return + val resDetail = app.get("$kissKhAPI/api/DramaList/Drama/$id?isq=false", referer = "$kissKhAPI/Drama/${ + getKisskhTitle(contentTitle) + }?id=$id").parsedSafe() ?: return val epsId = if (season == null) { resDetail.episodes?.first()?.id @@ -873,80 +555,45 @@ object SoraExtractor : SoraStream() { resDetail.episodes?.find { it.number == episode }?.id } - app.get( - "$kissKhAPI/api/DramaList/Episode/$epsId.png?err=false&ts=&time=", - referer = "$kissKhAPI/Drama/${getKisskhTitle(contentTitle)}/Episode-${episode ?: 0}?id=$id&ep=$epsId&page=0&pageSize=100" - ).parsedSafe()?.let { source -> + app.get("$kissKhAPI/api/DramaList/Episode/$epsId.png?err=false&ts=&time=", referer = "$kissKhAPI/Drama/${getKisskhTitle(contentTitle)}/Episode-${episode ?: 0}?id=$id&ep=$epsId&page=0&pageSize=100").parsedSafe()?.let { source -> listOf(source.video, source.thirdParty).apmap { link -> if (link?.contains(".m3u8") == true) { - M3u8Helper.generateM3u8( - "Kisskh", link, "$kissKhAPI/", headers = mapOf("Origin" to kissKhAPI) - ).forEach(callback) + M3u8Helper.generateM3u8("Kisskh", link, "$kissKhAPI/", headers = mapOf("Origin" to kissKhAPI)).forEach(callback) } else { - loadExtractor( - link?.substringBefore("=http") ?: return@apmap null, - "$kissKhAPI/", - subtitleCallback, - callback - ) + loadExtractor(link?.substringBefore("=http") + ?: return@apmap null, "$kissKhAPI/", subtitleCallback, callback) } } } app.get("$kissKhAPI/api/Sub/$epsId").text.let { resSub -> tryParseJson>(resSub)?.map { sub -> - subtitleCallback.invoke( - SubtitleFile( - getLanguage(sub.label ?: return@map), sub.src ?: return@map - ) - ) + subtitleCallback.invoke(SubtitleFile(getLanguage(sub.label ?: return@map), sub.src + ?: return@map)) } } } - suspend fun invokeAnimes( - title: String? = null, - epsTitle: String? = null, - date: String?, - airedDate: String?, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeAnimes(title: String? = null, epsTitle: String? = null, date: String?, airedDate: String?, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { - val (aniId, malId) = convertTmdbToAnimeId( - title, date, airedDate, if (season == null) TvType.AnimeMovie else TvType.Anime - ) + val (aniId, malId) = convertTmdbToAnimeId(title, date, airedDate, if (season == null) TvType.AnimeMovie else TvType.Anime) argamap({ invokeAnimetosho(malId, season, episode, subtitleCallback, callback) }, { invokeAniwatch(malId, episode, subtitleCallback, callback) }, { - if (season != null) invokeCrunchyroll( - aniId, malId, epsTitle, season, episode, subtitleCallback, callback - ) + if (season != null) invokeCrunchyroll(aniId, malId, epsTitle, season, episode, subtitleCallback, callback) }) } - private suspend fun invokeAnimetosho( - malId: Int? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + private suspend fun invokeAnimetosho(malId: Int? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { fun Elements.getLinks(): List> { return this.flatMap { ele -> ele.select("div.links a:matches(KrakenFiles|GoFile)").map { - Triple( - it.attr("href"), - ele.select("div.size").text(), - getIndexQuality(ele.select("div.link a").text()) - ) + Triple(it.attr("href"), ele.select("div.size").text(), getIndexQuality(ele.select("div.link a").text())) } } } @@ -954,80 +601,54 @@ object SoraExtractor : SoraStream() { val (seasonSLug, episodeSlug) = getEpisodeSlug(season, episode) val jikan = app.get("$jikanAPI/anime/$malId/full").parsedSafe()?.data val aniId = jikan?.external?.find { it.name == "AniDB" }?.url?.substringAfterLast("=") - val res = - app.get("$animetoshoAPI/series/${jikan?.title?.createSlug()}.$aniId?filter[0][t]=nyaa_class&filter[0][v]=trusted").document + val res = app.get("$animetoshoAPI/series/${jikan?.title?.createSlug()}.$aniId?filter[0][t]=nyaa_class&filter[0][v]=trusted").document val servers = if (season == null) { res.select("div.home_list_entry:has(div.links)").getLinks() } else { - res.select("div.home_list_entry:has(div.link a:matches([\\.\\s]$episodeSlug[\\.\\s]|S${seasonSLug}E$episodeSlug))") - .getLinks() + res.select("div.home_list_entry:has(div.link a:matches([\\.\\s]$episodeSlug[\\.\\s]|S${seasonSLug}E$episodeSlug))").getLinks() } servers.filter { it.third in arrayOf(Qualities.P1080.value, Qualities.P720.value) }.apmap { - loadCustomTagExtractor( - it.second, it.first, "$animetoshoAPI/", subtitleCallback, callback, it.third - ) + loadCustomTagExtractor(it.second, it.first, "$animetoshoAPI/", subtitleCallback, callback, it.third) } } - private suspend fun invokeAniwatch( - malId: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + private suspend fun invokeAniwatch(malId: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val headers = mapOf( - "X-Requested-With" to "XMLHttpRequest", + "X-Requested-With" to "XMLHttpRequest", ) - val animeId = app.get("$malsyncAPI/mal/anime/${malId ?: return}") - .parsedSafe()?.sites?.zoro?.keys?.map { it } + val animeId = app.get("$malsyncAPI/mal/anime/${malId ?: return}").parsedSafe()?.sites?.zoro?.keys?.map { it } animeId?.apmap { id -> - val episodeId = app.get( - "$aniwatchAPI/ajax/v2/episode/list/${id ?: return@apmap}", headers = headers - ).parsedSafe()?.html?.let { + val episodeId = app.get("$aniwatchAPI/ajax/v2/episode/list/${id ?: return@apmap}", headers = headers).parsedSafe()?.html?.let { Jsoup.parse(it) - }?.select("div.ss-list a")?.find { it.attr("data-number") == "${episode ?: 1}" } - ?.attr("data-id") + }?.select("div.ss-list a")?.find { it.attr("data-number") == "${episode ?: 1}" }?.attr("data-id") - val servers = app.get( - "$aniwatchAPI/ajax/v2/episode/servers?episodeId=${episodeId ?: return@apmap}", - headers = headers - ).parsedSafe()?.html?.let { Jsoup.parse(it) } - ?.select("div.item.server-item")?.map { - Triple( + val servers = app.get("$aniwatchAPI/ajax/v2/episode/servers?episodeId=${episodeId ?: return@apmap}", headers = headers).parsedSafe()?.html?.let { Jsoup.parse(it) }?.select("div.item.server-item")?.map { + Triple( it.text(), it.attr("data-id"), it.attr("data-type"), - ) - } + ) + } servers?.apmap servers@{ server -> - val iframe = app.get( - "$aniwatchAPI/ajax/v2/episode/sources?id=${server.second ?: return@servers}", - headers = headers - ).parsedSafe()?.link ?: return@servers + val iframe = app.get("$aniwatchAPI/ajax/v2/episode/sources?id=${server.second ?: return@servers}", headers = headers).parsedSafe()?.link + ?: return@servers val audio = if (server.third == "sub") "Raw" else "English Dub" loadCustomExtractor( - "${server.first} [$audio]", - iframe, - "$aniwatchAPI/", - subtitleCallback, - callback, + "${server.first} [$audio]", + iframe, + "$aniwatchAPI/", + subtitleCallback, + callback, ) } } } - suspend fun invokeLing( - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeLing(title: String? = null, year: Int? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val fixTitle = title?.replace("–", "-") val url = if (season == null) { "$lingAPI/en/videos/films/?title=$fixTitle" @@ -1037,9 +658,9 @@ object SoraExtractor : SoraStream() { val scriptData = app.get(url).document.select("div.blk.padding_b0 div.col-sm-30").map { Triple( - it.selectFirst("div.video-body h5")?.text(), - it.selectFirst("div.video-body > p")?.text(), - it.selectFirst("div.video-body a")?.attr("href"), + it.selectFirst("div.video-body h5")?.text(), + it.selectFirst("div.video-body > p")?.text(), + it.selectFirst("div.video-body a")?.attr("href"), ) } @@ -1047,9 +668,7 @@ object SoraExtractor : SoraStream() { scriptData.first() } else { scriptData.find { - it.first?.contains( - "$fixTitle", true - ) == true && it.second?.contains("$year") == true + it.first?.contains("$fixTitle", true) == true && it.second?.contains("$year") == true } } @@ -1057,36 +676,21 @@ object SoraExtractor : SoraStream() { val iframe = (if (season == null) { doc.selectFirst("a.video-js.vjs-default-skin")?.attr("data-href") } else { - doc.select("div.blk div#tab_$season li")[episode!!.minus(1)].select("h5 a") - .attr("data-href") + doc.select("div.blk div#tab_$season li")[episode!!.minus(1)].select("h5 a").attr("data-href") })?.let { fixUrl(it, lingAPI) } val source = app.get(iframe ?: return) val link = Regex("((https:|http:)//.*\\.mp4)").find(source.text)?.value ?: return - callback.invoke( - ExtractorLink( - "Ling", "Ling", "$link/index.m3u8", "$lingAPI/", Qualities.P720.value, INFER_TYPE - ) - ) + callback.invoke(ExtractorLink("Ling", "Ling", "$link/index.m3u8", "$lingAPI/", Qualities.P720.value, INFER_TYPE)) source.document.select("div#player-tracks track").map { - subtitleCallback.invoke( - SubtitleFile( - SubtitleHelper.fromTwoLettersToLanguage(it.attr("srclang")) ?: return@map null, - it.attr("src") - ) - ) + subtitleCallback.invoke(SubtitleFile(SubtitleHelper.fromTwoLettersToLanguage(it.attr("srclang")) + ?: return@map null, it.attr("src"))) } } - suspend fun invokeUhdmovies( - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeUhdmovies(title: String? = null, year: Int? = null, season: Int? = null, episode: Int? = null, callback: (ExtractorLink) -> Unit) { val fixTitle = title.createSlug() val (seasonSlug, episodeSlug) = getEpisodeSlug(season, episode) @@ -1119,12 +723,10 @@ object SoraExtractor : SoraStream() { val driveReq = app.get(driveLink) val driveRes = driveReq.document val bitLink = driveRes.select("a.btn.btn-outline-success").attr("href") - val insLink = - driveRes.select("a.btn.btn-danger:contains(Instant Download)").attr("href") + val insLink = driveRes.select("a.btn.btn-danger:contains(Instant Download)").attr("href") val downloadLink = when { insLink.isNotEmpty() -> extractInstantUHD(insLink) - driveRes.select("button.btn.btn-success").text() - .contains("Direct Download", true) -> extractDirectUHD(driveLink, driveReq) + driveRes.select("button.btn.btn-success").text().contains("Direct Download", true) -> extractDirectUHD(driveLink, driveReq) bitLink.isNullOrEmpty() -> { val backupIframe = driveRes.select("a.btn.btn-outline-warning").attr("href") @@ -1139,70 +741,20 @@ object SoraExtractor : SoraStream() { val tags = getUhdTags(quality) val qualities = getIndexQuality(quality) val size = getIndexSize(quality) - callback.invoke( - ExtractorLink( - "UHDMovies", - "UHDMovies $tags [$size]", - downloadLink ?: return@apmap, - "", - qualities - ) - ) + callback.invoke(ExtractorLink("UHDMovies", "UHDMovies $tags [$size]", downloadLink + ?: return@apmap, "", qualities)) } } - suspend fun invokeDotmovies( - title: String? = null, - year: Int? = null, - season: Int? = null, - lastSeason: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { - invokeWpredis( - title, - year, - season, - lastSeason, - episode, - subtitleCallback, - callback, - dotmoviesAPI - ) + suspend fun invokeDotmovies(title: String? = null, year: Int? = null, season: Int? = null, lastSeason: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { + invokeWpredis(title, year, season, lastSeason, episode, subtitleCallback, callback, dotmoviesAPI) } - suspend fun invokeVegamovies( - title: String? = null, - year: Int? = null, - season: Int? = null, - lastSeason: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { - invokeWpredis( - title, - year, - season, - lastSeason, - episode, - subtitleCallback, - callback, - vegaMoviesAPI - ) + suspend fun invokeVegamovies(title: String? = null, year: Int? = null, season: Int? = null, lastSeason: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { + invokeWpredis(title, year, season, lastSeason, episode, subtitleCallback, callback, vegaMoviesAPI) } - private suspend fun invokeWpredis( - title: String? = null, - year: Int? = null, - season: Int? = null, - lastSeason: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit, - api: String - ) { + private suspend fun invokeWpredis(title: String? = null, year: Int? = null, season: Int? = null, lastSeason: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit, api: String) { val (seasonSlug, episodeSlug) = getEpisodeSlug(season, episode) var res = app.get("$api/search/$title").document val match = when (season) { @@ -1210,68 +762,42 @@ object SoraExtractor : SoraStream() { 1 -> "Season 1" else -> "Season 1 – $lastSeason" } - val media = - res.selectFirst("div.blog-items article:has(h3.entry-title:matches((?i)$title.*$match)) a") - ?.attr("href") + val media = res.selectFirst("div.blog-items article:has(h3.entry-title:matches((?i)$title.*$match)) a")?.attr("href") res = app.get(media ?: return).document val hTag = if (season == null) "h5" else "h3" val aTag = if (season == null) "Download Now" else "V-Cloud" val sTag = if (season == null) "" else "(Season $season|S$seasonSlug)" - val entry = res.select("div.entry-content > $hTag:matches((?i)$sTag.*(1080p|2160p))") - .findLast { element -> !element.text().contains("Download", true) } ?: return - val tags = - """(?:1080p|2160p)(.*)""".toRegex().find(entry.text())?.groupValues?.get(1)?.trim() - val href = - entry.nextElementSibling()?.select("a:contains($aTag)")?.attr("href") - val selector = - if (season == null) "p a:contains(V-Cloud)" else "h4:matches(0?$episode) + p a:contains(V-Cloud)" - val server = app.get( - href ?: return, interceptor = wpredisInterceptor - ).document.selectFirst("div.entry-content > $selector") - ?.attr("href") ?: return + val entry = res.select("div.entry-content > $hTag:matches((?i)$sTag.*(1080p|2160p))").findLast { element -> !element.text().contains("Download", true) } + ?: return + val tags = """(?:1080p|2160p)(.*)""".toRegex().find(entry.text())?.groupValues?.get(1)?.trim() + val href = entry.nextElementSibling()?.select("a:contains($aTag)")?.attr("href") + val selector = if (season == null) "p a:contains(V-Cloud)" else "h4:matches(0?$episode) + p a:contains(V-Cloud)" + val server = app.get(href + ?: return, interceptor = wpredisInterceptor).document.selectFirst("div.entry-content > $selector")?.attr("href") + ?: return - loadCustomTagExtractor( - tags, - server, - "$api/", - subtitleCallback, - callback, - getIndexQuality(entry.text()) - ) + loadCustomTagExtractor(tags, server, "$api/", subtitleCallback, callback, getIndexQuality(entry.text())) } - suspend fun invokeHdmovies4u( - title: String? = null, - imdbId: String? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeHdmovies4u(title: String? = null, imdbId: String? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { fun String.decodeLink(): String { return base64Decode(this.substringAfterLast("/")) } val (seasonSlug, episodeSlug) = getEpisodeSlug(season, episode) - val media = - app.get("$hdmovies4uAPI/?s=${if (season == null) imdbId else title}").document.let { - val selector = - if (season == null) "a" else "a:matches((?i)$title.*Season $season)" - it.selectFirst("div.gridxw.gridxe $selector")?.attr("href") - } + val media = app.get("$hdmovies4uAPI/?s=${if (season == null) imdbId else title}").document.let { + val selector = if (season == null) "a" else "a:matches((?i)$title.*Season $season)" + it.selectFirst("div.gridxw.gridxe $selector")?.attr("href") + } val selector = if (season == null) "1080p|2160p" else "(?i)Episode.*(?:1080p|2160p)" - app.get( - media ?: return - ).document.select("section h4:matches($selector)").apmap { ele -> + app.get(media ?: return).document.select("section h4:matches($selector)").apmap { ele -> val (tags, size) = ele.select("span").map { it.text() }.let { it[it.lastIndex - 1] to it.last().substringAfter("-").trim() } val link = ele.nextElementSibling()?.select("a:contains(DriveTOT)")?.attr("href") val iframe = bypassBqrecipes(link?.decodeLink() ?: return@apmap).let { if (it?.contains("/pack/") == true) { - val href = - app.get(it).document.select("table tbody tr:contains(S${seasonSlug}E${episodeSlug}) a") - .attr("href") + val href = app.get(it).document.select("table tbody tr:contains(S${seasonSlug}E${episodeSlug}) a").attr("href") bypassBqrecipes(href.decodeLink()) } else { it @@ -1281,14 +807,7 @@ object SoraExtractor : SoraStream() { } } - suspend fun invokeGMovies( - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeGMovies(title: String? = null, year: Int? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val fixTitle = title.createSlug() val url = if (season == null || season == 1) { "$gMoviesAPI/$fixTitle-$year" @@ -1304,8 +823,7 @@ object SoraExtractor : SoraStream() { } } else { doc.select("div.is-content-justification-center").find { - it.previousElementSibling()?.text() - ?.contains(Regex("(?i)episode\\s?$episode")) == true + it.previousElementSibling()?.text()?.contains(Regex("(?i)episode\\s?$episode")) == true }?.select("div.wp-block-button")?.map { it.select("a").attr("href") to it.text() } @@ -1315,23 +833,11 @@ object SoraExtractor : SoraStream() { iframe.apmap { (iframeLink, title) -> val size = Regex("(?i)\\s(\\S+gb|mb)").find(title)?.groupValues?.getOrNull(1) - loadCustomTagExtractor( - "[$size]", - iframeLink, - "$gMoviesAPI/", - subtitleCallback, - callback, - getIndexQuality(title) - ) + loadCustomTagExtractor("[$size]", iframeLink, "$gMoviesAPI/", subtitleCallback, callback, getIndexQuality(title)) } } - suspend fun invokeFDMovies( - title: String? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeFDMovies(title: String? = null, season: Int? = null, episode: Int? = null, callback: (ExtractorLink) -> Unit) { val fixTitle = title.createSlug() val url = if (season == null) { "$fdMoviesAPI/movies/$fixTitle" @@ -1343,12 +849,7 @@ object SoraExtractor : SoraStream() { if (!request.isSuccessful) return val iframe = request.document.select("div#download tbody tr").map { - FDMovieIFrame( - it.select("a").attr("href"), - it.select("strong.quality").text(), - it.select("td:nth-child(4)").text(), - it.select("img").attr("src") - ) + FDMovieIFrame(it.select("a").attr("href"), it.select("strong.quality").text(), it.select("td:nth-child(4)").text(), it.select("img").attr("src")) }.filter { it.quality.contains(Regex("(?i)(1080p|4k)")) && it.type.contains(Regex("(gdtot|oiya|rarbgx)")) } @@ -1376,46 +877,26 @@ object SoraExtractor : SoraStream() { } } - callback.invoke( - ExtractorLink( - "FDMovies", - "FDMovies [$size]", - videoLink ?: return@apmap null, - "", - getQualityFromName(qualities) - ) - ) + callback.invoke(ExtractorLink("FDMovies", "FDMovies [$size]", videoLink + ?: return@apmap null, "", getQualityFromName(qualities))) } } - suspend fun invokeM4uhd( - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeM4uhd(title: String? = null, year: Int? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val slugTitle = title.createSlug() val (seasonSlug, episodeSlug) = getEpisodeSlug(season, episode) val req = app.get("$m4uhdAPI/search/$slugTitle.html") val referer = getBaseUrl(req.url) val scriptData = req.document.select("div.row div.item").map { ele -> - Triple( - ele.select("div.tiptitle p").text().substringBefore("(").trim().createSlug(), - ele.select("div.jtip-top div:last-child").text().filter { it.isDigit() }, - ele.selectFirst("a")?.attr("href") - ) + Triple(ele.select("div.tiptitle p").text().substringBefore("(").trim().createSlug(), ele.select("div.jtip-top div:last-child").text().filter { it.isDigit() }, ele.selectFirst("a")?.attr("href")) } val script = if (scriptData.size == 1) { scriptData.firstOrNull() } else { scriptData.find { - it.first.equals(slugTitle) && it.second == "$year" && if (season != null) it.third?.contains( - "-tvshow-" - ) == true else it.third?.contains("-movie-") == true + it.first.equals(slugTitle) && it.second == "$year" && if (season != null) it.third?.contains("-tvshow-") == true else it.third?.contains("-movie-") == true } } @@ -1429,28 +910,20 @@ object SoraExtractor : SoraStream() { val m4uData = if (season == null) { doc.select("div.le-server span").map { it.attr("data") } } else { - val idepisode = - doc.selectFirst("div.detail > p:matches((?i)S$seasonSlug-E$episodeSlug) button") - ?.attr("idepisode") + val idepisode = doc.selectFirst("div.detail > p:matches((?i)S$seasonSlug-E$episodeSlug) button")?.attr("idepisode") ?: return - val requestEmbed = app.post( - "$referer/ajaxtv", data = mapOf( - "idepisode" to idepisode, "_token" to "$token" - ), referer = link, headers = headers, cookies = cookies - ) + val requestEmbed = app.post("$referer/ajaxtv", data = mapOf("idepisode" to idepisode, "_token" to "$token"), referer = link, headers = headers, cookies = cookies) cookies = requestEmbed.cookies requestEmbed.document.select("div.le-server span").map { it.attr("data") } } m4uData.apmap { data -> val iframe = app.post( - "$referer/ajax", - data = mapOf( - "m4u" to data, "_token" to "$token" - ), - referer = link, - headers = headers, - cookies = cookies, + "$referer/ajax", + data = mapOf("m4u" to data, "_token" to "$token"), + referer = link, + headers = headers, + cookies = cookies, ).document.select("iframe").attr("src") loadExtractor(iframe, referer, subtitleCallback, callback) @@ -1458,12 +931,7 @@ object SoraExtractor : SoraStream() { } - suspend fun invokeTvMovies( - title: String? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeTvMovies(title: String? = null, season: Int? = null, episode: Int? = null, callback: (ExtractorLink) -> Unit) { val fixTitle = title.createSlug() val url = if (season == null) { "$tvMoviesAPI/show/$fixTitle" @@ -1473,43 +941,25 @@ object SoraExtractor : SoraStream() { val server = getTvMoviesServer(url, season, episode) ?: return val videoData = extractCovyn(server.second ?: return) - val quality = - Regex("(\\d{3,4})p").find(server.first)?.groupValues?.getOrNull(1)?.toIntOrNull() + val quality = Regex("(\\d{3,4})p").find(server.first)?.groupValues?.getOrNull(1)?.toIntOrNull() - callback.invoke( - ExtractorLink( - "TVMovies", - "TVMovies [${videoData?.second}]", - videoData?.first ?: return, - "", - quality ?: Qualities.Unknown.value - ) - ) + callback.invoke(ExtractorLink("TVMovies", "TVMovies [${videoData?.second}]", videoData?.first + ?: return, "", quality ?: Qualities.Unknown.value)) } - private suspend fun invokeCrunchyroll( - aniId: Int? = null, - malId: Int? = null, - epsTitle: String? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + private suspend fun invokeCrunchyroll(aniId: Int? = null, malId: Int? = null, epsTitle: String? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val id = getCrunchyrollId("${aniId ?: return}") - ?: getCrunchyrollIdFromMalSync("${malId ?: return}") + ?: getCrunchyrollIdFromMalSync("${malId ?: return}") val audioLocal = listOf( - "ja-JP", - "en-US", - "zh-CN", + "ja-JP", + "en-US", + "zh-CN", ) val token = getCrunchyrollToken() val headers = mapOf("Authorization" to "${token.tokenType} ${token.accessToken}") - val seasonIdData = app.get( - "$crunchyrollAPI/content/v2/cms/series/${id ?: return}/seasons", headers = headers - ).parsedSafe()?.data?.let { s -> + val seasonIdData = app.get("$crunchyrollAPI/content/v2/cms/series/${id ?: return}/seasons", headers = headers).parsedSafe()?.data?.let { s -> if (s.size == 1) { s.firstOrNull() } else { @@ -1522,82 +972,41 @@ object SoraExtractor : SoraStream() { } ?: s.find { it.season_number?.plus(1) == season } } } - val seasonId = seasonIdData?.versions?.filter { it.audio_locale in audioLocal } - ?.map { it.guid to it.audio_locale } ?: listOf(seasonIdData?.id to "ja-JP") + val seasonId = seasonIdData?.versions?.filter { it.audio_locale in audioLocal }?.map { it.guid to it.audio_locale } + ?: listOf(seasonIdData?.id to "ja-JP") seasonId.apmap { (sId, audioL) -> - val streamsLink = app.get( - "$crunchyrollAPI/content/v2/cms/seasons/${sId ?: return@apmap}/episodes", - headers = headers - ).parsedSafe()?.data?.find { - it.title.equals(epsTitle, true) || it.slug_title.equals( - epsTitle.createSlug(), true - ) || it.episode_number == episode + val streamsLink = app.get("$crunchyrollAPI/content/v2/cms/seasons/${sId ?: return@apmap}/episodes", headers = headers).parsedSafe()?.data?.find { + it.title.equals(epsTitle, true) || it.slug_title.equals(epsTitle.createSlug(), true) || it.episode_number == episode }?.streams_link?.substringAfter("/videos/")?.substringBefore("/streams") ?: return@apmap - val sources = app.get( - "$crunchyrollAPI/cms/v2${token.bucket}/videos/$streamsLink/streams?Policy=${token.policy}&Signature=${token.signature}&Key-Pair-Id=${token.key_pair_id}", - headers = headers - ).parsedSafe() + val sources = app.get("$crunchyrollAPI/cms/v2${token.bucket}/videos/$streamsLink/streams?Policy=${token.policy}&Signature=${token.signature}&Key-Pair-Id=${token.key_pair_id}", headers = headers).parsedSafe() - listOf( - "adaptive_hls", "vo_adaptive_hls" - ).map { hls -> + listOf("adaptive_hls", "vo_adaptive_hls").map { hls -> val name = if (hls == "adaptive_hls") "Crunchyroll" else "Vrv" val audio = if (audioL == "en-US") "English Dub" else "Raw" val source = sources?.streams?.let { if (hls == "adaptive_hls") it.adaptive_hls else it.vo_adaptive_hls } - M3u8Helper.generateM3u8( - "$name [$audio]", - source?.get("")?.get("url") ?: return@map, - "https://static.crunchyroll.com/" - ).forEach(callback) + M3u8Helper.generateM3u8("$name [$audio]", source?.get("")?.get("url") + ?: return@map, "https://static.crunchyroll.com/").forEach(callback) } sources?.subtitles?.map { sub -> - subtitleCallback.invoke( - SubtitleFile( - "${fixCrunchyrollLang(sub.key) ?: sub.key} [ass]", - sub.value["url"] ?: return@map null - ) - ) + subtitleCallback.invoke(SubtitleFile("${fixCrunchyrollLang(sub.key) ?: sub.key} [ass]", sub.value["url"] + ?: return@map null)) } } } - suspend fun invokeMoviezAdd( - apiUrl: String? = null, - api: String? = null, - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeMoviezAdd(apiUrl: String? = null, api: String? = null, title: String? = null, year: Int? = null, season: Int? = null, episode: Int? = null, callback: (ExtractorLink) -> Unit) { invokeBloginguru(apiUrl, api, title, year, season, episode, callback) } - suspend fun invokeBollyMaza( - apiUrl: String? = null, - api: String? = null, - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeBollyMaza(apiUrl: String? = null, api: String? = null, title: String? = null, year: Int? = null, season: Int? = null, episode: Int? = null, callback: (ExtractorLink) -> Unit) { invokeBloginguru(apiUrl, api, title, year, season, episode, callback) } - private suspend fun invokeBloginguru( - apiUrl: String? = null, - api: String? = null, - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit - ) { + private suspend fun invokeBloginguru(apiUrl: String? = null, api: String? = null, title: String? = null, year: Int? = null, season: Int? = null, episode: Int? = null, callback: (ExtractorLink) -> Unit) { val fixTitle = title?.createSlug()?.replace("-", " ") val doc = app.get("$apiUrl/?s=$fixTitle").document @@ -1611,97 +1020,55 @@ object SoraExtractor : SoraStream() { } } - val mediaLink = - app.get(matchMedia?.first ?: return).document.selectFirst("a#jake1")?.attr("href") + val mediaLink = app.get(matchMedia?.first + ?: return).document.selectFirst("a#jake1")?.attr("href") val detailDoc = app.get(mediaLink ?: return).document - val media = detailDoc.selectFirst("div.entry-content pre span")?.text() - ?.split("|") - ?.map { it.trim() } + val media = detailDoc.selectFirst("div.entry-content pre span")?.text()?.split("|")?.map { it.trim() } val iframe = (if (season == null) { media?.mapIndexed { index, name -> - detailDoc.select("div.entry-content > h2")[index].selectFirst("a") - ?.attr("href") to name + detailDoc.select("div.entry-content > h2")[index].selectFirst("a")?.attr("href") to name } } else { media?.mapIndexed { index, name -> - val linkMedia = - detailDoc.select("div.entry-content > h2")[index].selectFirst("a") - ?.attr("href") - app.get( - linkMedia ?: return@mapIndexed null - ).document.selectFirst("div.entry-content strong:matches((?i)S0?${season}E0?${episode}) a") - ?.attr("href") to name + val linkMedia = detailDoc.select("div.entry-content > h2")[index].selectFirst("a")?.attr("href") + app.get(linkMedia + ?: return@mapIndexed null).document.selectFirst("div.entry-content strong:matches((?i)S0?${season}E0?${episode}) a")?.attr("href") to name } })?.filter { it?.first?.startsWith("http") == true } iframe?.apmap { val iframeDoc = app.get(it?.first ?: return@apmap).document val formUrl = iframeDoc.select("form").attr("action") - val formData = - iframeDoc.select("form button").associate { v -> v.attr("name") to v.attr("value") } + val formData = iframeDoc.select("form button").associate { v -> v.attr("name") to v.attr("value") } - val videoUrl = app.post( - formUrl, - data = formData, - referer = it.first - ).document.selectFirst("div.d-flex.justify-content-center.flex-wrap a")?.attr("href") - val quality = - Regex("(\\d{3,4})p").find(it.second)?.groupValues?.getOrNull(1)?.toIntOrNull() + val videoUrl = app.post(formUrl, data = formData, referer = it.first).document.selectFirst("div.d-flex.justify-content-center.flex-wrap a")?.attr("href") + val quality = Regex("(\\d{3,4})p").find(it.second)?.groupValues?.getOrNull(1)?.toIntOrNull() val qualityName = it.second.replace("${quality}p", "").trim() - callback.invoke( - ExtractorLink( - "$api", - "$api $qualityName", - videoUrl ?: return@apmap, - "", - quality ?: Qualities.Unknown.value - ) - ) + callback.invoke(ExtractorLink("$api", "$api $qualityName", videoUrl + ?: return@apmap, "", quality ?: Qualities.Unknown.value)) } } - suspend fun invokeRStream( - id: Int? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeRStream(id: Int? = null, season: Int? = null, episode: Int? = null, callback: (ExtractorLink) -> Unit) { val url = if (season == null) { "$rStreamAPI/e/?tmdb=$id" } else { "$rStreamAPI/e/?tmdb=$id&s=$season&e=$episode" } - val res = app.get( - "$url&apikey=whXgvN4kVyoubGwqXpw26Oy3PVryl8dm", - referer = "https://watcha.movie/" - ).text + val res = app.get("$url&apikey=whXgvN4kVyoubGwqXpw26Oy3PVryl8dm", referer = "https://watcha.movie/").text val link = Regex("\"file\":\"(http.*?)\"").find(res)?.groupValues?.getOrNull(1) ?: return - callback.invoke( - ExtractorLink( - "RStream", "RStream", link, "$rStreamAPI/", Qualities.P1080.value, INFER_TYPE - ) - ) + callback.invoke(ExtractorLink("RStream", "RStream", link, "$rStreamAPI/", Qualities.P1080.value, INFER_TYPE)) } - suspend fun invokeFlixon( - tmdbId: Int? = null, - imdbId: String? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit, - onionUrl: String = "https://onionplay.se/" - ) { + suspend fun invokeFlixon(tmdbId: Int? = null, imdbId: String? = null, season: Int? = null, episode: Int? = null, callback: (ExtractorLink) -> Unit, onionUrl: String = "https://onionplay.se/") { val request = if (season == null) { val res = app.get("$flixonAPI/$imdbId", referer = onionUrl) - if (res.text.contains("BEGIN PGP SIGNED MESSAGE")) app.get( - "$flixonAPI/$imdbId-1", - referer = onionUrl - ) else res + if (res.text.contains("BEGIN PGP SIGNED MESSAGE")) app.get("$flixonAPI/$imdbId-1", referer = onionUrl) else res } else { app.get("$flixonAPI/$tmdbId-$season-$episode", referer = onionUrl) } @@ -1709,44 +1076,30 @@ object SoraExtractor : SoraStream() { val script = request.document.selectFirst("script:containsData(= \"\";)")?.data() val collection = script?.substringAfter("= [")?.substringBefore("];") val num = script?.substringAfterLast("(value) -")?.substringBefore(");")?.trim()?.toInt() - ?: return + ?: return val iframe = collection?.split(",")?.map { it.trim().toInt() }?.map { nums -> nums.minus(num).toChar() - }?.joinToString("")?.let { Jsoup.parse(it) }?.selectFirst("button.redirect") - ?.attr("onclick")?.substringAfter("('")?.substringBefore("')") + }?.joinToString("")?.let { Jsoup.parse(it) }?.selectFirst("button.redirect")?.attr("onclick")?.substringAfter("('")?.substringBefore("')") delay(1000) - val unPacker = app.get( - iframe ?: return, referer = "$flixonAPI/" - ).document.selectFirst("script:containsData(JuicyCodes.Run)")?.data() - ?.substringAfter("JuicyCodes.Run(")?.substringBefore(");")?.split("+") - ?.joinToString("") { it.replace("\"", "").trim() } - ?.let { getAndUnpack(base64Decode(it)) } + val unPacker = app.get(iframe + ?: return, referer = "$flixonAPI/").document.selectFirst("script:containsData(JuicyCodes.Run)")?.data()?.substringAfter("JuicyCodes.Run(")?.substringBefore(");")?.split("+")?.joinToString("") { it.replace("\"", "").trim() }?.let { getAndUnpack(base64Decode(it)) } - val link = Regex("[\"']file[\"']:[\"'](.+?)[\"'],").find( - unPacker ?: return - )?.groupValues?.getOrNull(1) + val link = Regex("[\"']file[\"']:[\"'](.+?)[\"'],").find(unPacker + ?: return)?.groupValues?.getOrNull(1) - callback.invoke( - ExtractorLink( - "Flixon", - "Flixon", - link ?: return, - "https://onionplay.stream/", - Qualities.P720.value, - link.contains(".m3u8") - ) - ) + callback.invoke(ExtractorLink("Flixon", "Flixon", link + ?: return, "https://onionplay.stream/", Qualities.P720.value, link.contains(".m3u8"))) } suspend fun invokeSmashyStream( - imdbId: String? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit, + imdbId: String? = null, + season: Int? = null, + episode: Int? = null, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit, ) { val url = if (season == null) { "$smashyStreamAPI/playere.php?imdb=$imdbId" @@ -1754,9 +1107,7 @@ object SoraExtractor : SoraStream() { "$smashyStreamAPI/playere.php?imdb=$imdbId&season=$season&episode=$episode" } - app.get( - url, referer = "https://smashystream.com/" - ).document.select("div#_default-servers a.server").map { + app.get(url, referer = "https://smashystream.com/").document.select("div#_default-servers a.server").map { it.attr("data-url") to it.text() }.apmap { when (it.second) { @@ -1776,21 +1127,13 @@ object SoraExtractor : SoraStream() { //TODO only subs suspend fun invokeWatchsomuch( - imdbId: String? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, + imdbId: String? = null, + season: Int? = null, + episode: Int? = null, + subtitleCallback: (SubtitleFile) -> Unit, ) { val id = imdbId?.removePrefix("tt") - val epsId = app.post( - "$watchSomuchAPI/Watch/ajMovieTorrents.aspx", data = mapOf( - "index" to "0", - "mid" to "$id", - "wsk" to "f6ea6cde-e42b-4c26-98d3-b4fe48cdd4fb", - "lid" to "", - "liu" to "" - ), headers = mapOf("X-Requested-With" to "XMLHttpRequest") - ).parsedSafe()?.movie?.torrents?.let { eps -> + val epsId = app.post("$watchSomuchAPI/Watch/ajMovieTorrents.aspx", data = mapOf("index" to "0", "mid" to "$id", "wsk" to "f6ea6cde-e42b-4c26-98d3-b4fe48cdd4fb", "lid" to "", "liu" to ""), headers = mapOf("X-Requested-With" to "XMLHttpRequest")).parsedSafe()?.movie?.torrents?.let { eps -> if (season == null) { eps.firstOrNull()?.id } else { @@ -1807,191 +1150,145 @@ object SoraExtractor : SoraStream() { } app.get(subUrl).parsedSafe()?.subtitles?.map { sub -> - subtitleCallback.invoke( - SubtitleFile( - sub.label ?: "", fixUrl(sub.url ?: return@map null, watchSomuchAPI) - ) - ) + subtitleCallback.invoke(SubtitleFile(sub.label ?: "", fixUrl(sub.url + ?: return@map null, watchSomuchAPI))) } } suspend fun invokeShinobiMovies( - apiUrl: String, - api: String, - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit, + apiUrl: String, + api: String, + title: String? = null, + year: Int? = null, + season: Int? = null, + episode: Int? = null, + callback: (ExtractorLink) -> Unit, ) { invokeIndex( - apiUrl, - api, - title, - year, - season, - episode, - callback, + apiUrl, + api, + title, + year, + season, + episode, + callback, ) } private suspend fun invokeIndex( - apiUrl: String, - api: String, - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit, - password: String = "", + apiUrl: String, + api: String, + title: String? = null, + year: Int? = null, + season: Int? = null, + episode: Int? = null, + callback: (ExtractorLink) -> Unit, + password: String = "", ) { - val passHeaders = mapOf( - "Authorization" to password - ) + val passHeaders = mapOf("Authorization" to password) val query = getIndexQuery(title, year, season, episode).let { if (api in mkvIndex) "$it mkv" else it } - val body = - """{"q":"$query","password":null,"page_token":null,"page_index":0}""".toRequestBody( - RequestBodyTypes.JSON.toMediaTypeOrNull() - ) - val data = mapOf( - "q" to query, "page_token" to "", "page_index" to "0" - ) + val body = """{"q":"$query","password":null,"page_token":null,"page_index":0}""".toRequestBody(RequestBodyTypes.JSON.toMediaTypeOrNull()) + val data = mapOf("q" to query, "page_token" to "", "page_index" to "0") val search = if (api in encodedIndex) { - decodeIndexJson( - if (api in lockedIndex) app.post( - "${apiUrl}search", - data = data, - headers = passHeaders, - referer = apiUrl, - timeout = 120L - ).text else app.post( - "${apiUrl}search", data = data, referer = apiUrl - ).text - ) + decodeIndexJson(if (api in lockedIndex) app.post("${apiUrl}search", data = data, headers = passHeaders, referer = apiUrl, timeout = 120L).text else app.post("${apiUrl}search", data = data, referer = apiUrl).text) } else { app.post("${apiUrl}search", requestBody = body, referer = apiUrl, timeout = 120L).text } - val media = if (api in untrimmedIndex) searchIndex( - title, season, episode, year, search, false - ) else searchIndex(title, season, episode, year, search) + val media = if (api in untrimmedIndex) searchIndex(title, season, episode, year, search, false) else searchIndex(title, season, episode, year, search) media?.apmap { file -> - val pathBody = """{"id":"${file.id ?: return@apmap null}"}""".toRequestBody( - RequestBodyTypes.JSON.toMediaTypeOrNull() - ) + val pathBody = """{"id":"${file.id ?: return@apmap null}"}""".toRequestBody(RequestBodyTypes.JSON.toMediaTypeOrNull()) val pathData = mapOf( - "id" to file.id, + "id" to file.id, ) val path = (if (api in encodedIndex) { if (api in lockedIndex) { - app.post( - "${apiUrl}id2path", - data = pathData, - headers = passHeaders, - referer = apiUrl, - timeout = 120L - ) + app.post("${apiUrl}id2path", data = pathData, headers = passHeaders, referer = apiUrl, timeout = 120L) } else { - app.post( - "${apiUrl}id2path", data = pathData, referer = apiUrl, timeout = 120L - ) + app.post("${apiUrl}id2path", data = pathData, referer = apiUrl, timeout = 120L) } } else { - app.post( - "${apiUrl}id2path", requestBody = pathBody, referer = apiUrl, timeout = 120L - ) + app.post("${apiUrl}id2path", requestBody = pathBody, referer = apiUrl, timeout = 120L) }).text.let { path -> if (api in ddomainIndex) { - val worker = app.get( - "${fixUrl(path, apiUrl).encodeUrl()}?a=view", - referer = if (api in needRefererIndex) apiUrl else "", - timeout = 120L - ).document.selectFirst("script:containsData(downloaddomain)")?.data() - ?.substringAfter("\"downloaddomain\":\"")?.substringBefore("\",")?.let { - "$it/0:" - } + val worker = app.get("${fixUrl(path, apiUrl).encodeUrl()}?a=view", referer = if (api in needRefererIndex) apiUrl else "", timeout = 120L).document.selectFirst("script:containsData(downloaddomain)")?.data()?.substringAfter("\"downloaddomain\":\"")?.substringBefore("\",")?.let { + "$it/0:" + } fixUrl(path, worker ?: return@apmap null) } else { fixUrl(path, apiUrl) } }.encodeUrl() - val size = - "%.2f GB".format(bytesToGigaBytes(file.size?.toDouble() ?: return@apmap null)) + val size = "%.2f GB".format(bytesToGigaBytes(file.size?.toDouble() + ?: return@apmap null)) val quality = getIndexQuality(file.name) val tags = getIndexQualityTags(file.name) - callback.invoke( - ExtractorLink( + callback.invoke(ExtractorLink( api, "$api $tags [$size]", path, if (api in needRefererIndex) apiUrl else "", quality, - ) - ) + )) } } suspend fun invokeGdbotMovies( - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit, + title: String? = null, + year: Int? = null, + season: Int? = null, + episode: Int? = null, + callback: (ExtractorLink) -> Unit, ) { val query = getIndexQuery(title, null, season, episode) val files = app.get("$gdbot/search?q=$query").document.select("ul.divide-y li").map { - Triple( - it.select("a").attr("href"), it.select("a").text(), it.select("span").text() - ) + Triple(it.select("a").attr("href"), it.select("a").text(), it.select("span").text()) }.filter { matchingIndex( - it.second, - null, - title, - year, - season, - episode, + it.second, + null, + title, + year, + season, + episode, ) }.sortedByDescending { it.third.getFileSize() } files.let { file -> - listOfNotNull(file.find { it.second.contains("2160p", true) }, - file.find { it.second.contains("1080p", true) }) + listOfNotNull(file.find { it.second.contains("2160p", true) }, file.find { it.second.contains("1080p", true) }) }.apmap { file -> val videoUrl = extractGdflix(file.first) val quality = getIndexQuality(file.second) val tags = getIndexQualityTags(file.second) val size = Regex("(\\d+\\.?\\d+\\sGB|MB)").find(file.third)?.groupValues?.get(0)?.trim() - callback.invoke( - ExtractorLink( + callback.invoke(ExtractorLink( "GdbotMovies", "GdbotMovies $tags [$size]", videoUrl ?: return@apmap null, "", quality, - ) - ) + )) } } suspend fun invokeDahmerMovies( - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit, + title: String? = null, + year: Int? = null, + season: Int? = null, + episode: Int? = null, + callback: (ExtractorLink) -> Unit, ) { val url = if (season == null) { "$dahmerMoviesAPI/movies/${title?.replace(":", "")} ($year)/" @@ -2015,35 +1312,27 @@ object SoraExtractor : SoraStream() { paths.map { val quality = getIndexQuality(it.first) val tags = getIndexQualityTags(it.first) - callback.invoke( - ExtractorLink( + callback.invoke(ExtractorLink( "DahmerMovies", "DahmerMovies $tags", (url + it.second).encodeUrl(), "", quality, - ) - ) + )) } } - suspend fun invoke2embed( - imdbId: String?, - season: Int?, - episode: Int?, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invoke2embed(imdbId: String?, season: Int?, episode: Int?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val url = if (season == null) { "$twoEmbedAPI/embed/$imdbId" } else { "$twoEmbedAPI/embedtv/$imdbId&s=$season&e=$episode" } - val framesrc = - app.get(url).document.selectFirst("iframe#iframesrc")?.attr("data-src") ?: return + val framesrc = app.get(url).document.selectFirst("iframe#iframesrc")?.attr("data-src") + ?: return val ref = getBaseUrl(framesrc) val id = framesrc.substringAfter("id=").substringBefore("&") loadExtractor("https://wishfast.top/e/$id", "$ref/", subtitleCallback, callback) @@ -2051,35 +1340,25 @@ object SoraExtractor : SoraStream() { } suspend fun invokeOmovies( - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit, + title: String? = null, + year: Int? = null, + season: Int? = null, + episode: Int? = null, + callback: (ExtractorLink) -> Unit, ) { - invokeGpress( - title, - year, - season, - episode, - callback, - BuildConfig.OMOVIES_API, - "Omovies", - base64Decode("X3NtUWFtQlFzRVRi"), - base64Decode("X3NCV2NxYlRCTWFU") - ) + invokeGpress(title, year, season, episode, callback, BuildConfig.OMOVIES_API, "Omovies", base64Decode("X3NtUWFtQlFzRVRi"), base64Decode("X3NCV2NxYlRCTWFU")) } private suspend fun invokeGpress( - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit, - api: String, - name: String, - mediaSelector: String, - episodeSelector: String, + title: String? = null, + year: Int? = null, + season: Int? = null, + episode: Int? = null, + callback: (ExtractorLink) -> Unit, + api: String, + name: String, + mediaSelector: String, + episodeSelector: String, ) { fun String.decrypt(key: String): List? { return tryParseJson>(base64Decode(this).decodePrimewireXor(key)) @@ -2092,23 +1371,19 @@ object SoraExtractor : SoraStream() { "$title Season $season" } val savedCookies = mapOf( - base64Decode("X2lkZW50aXR5Z29tb3ZpZXM3") to base64Decode("NTJmZGM3MGIwMDhjMGIxZDg4MWRhYzBmMDFjY2E4MTllZGQ1MTJkZTAxY2M4YmJjMTIyNGVkNGFhZmI3OGI1MmElM0EyJTNBJTdCaSUzQTAlM0JzJTNBMTglM0ElMjJfaWRlbnRpdHlnb21vdmllczclMjIlM0JpJTNBMSUzQnMlM0E1MiUzQSUyMiU1QjIwNTAzNjYlMkMlMjJIblZSUkFPYlRBU09KRXI0NVl5Q004d2lIb2wwVjFrbyUyMiUyQzI1OTIwMDAlNUQlMjIlM0IlN0Q="), + base64Decode("X2lkZW50aXR5Z29tb3ZpZXM3") to base64Decode("NTJmZGM3MGIwMDhjMGIxZDg4MWRhYzBmMDFjY2E4MTllZGQ1MTJkZTAxY2M4YmJjMTIyNGVkNGFhZmI3OGI1MmElM0EyJTNBJTdCaSUzQTAlM0JzJTNBMTglM0ElMjJfaWRlbnRpdHlnb21vdmllczclMjIlM0JpJTNBMSUzQnMlM0E1MiUzQSUyMiU1QjIwNTAzNjYlMkMlMjJIblZSUkFPYlRBU09KRXI0NVl5Q004d2lIb2wwVjFrbyUyMiUyQzI1OTIwMDAlNUQlMjIlM0IlN0Q="), ) val req = app.get("$api/search/$query") val doc = req.document val media = doc.select("div.$mediaSelector").map { - Triple( - it.attr("data-filmName"), it.attr("data-year"), it.select("a").attr("href") - ) + Triple(it.attr("data-filmName"), it.attr("data-year"), it.select("a").attr("href")) }.let { el -> if (el.size == 1) { el.firstOrNull() } else { el.find { if (season == null) { - (it.first.equals(title, true) || it.first.equals( - "$title ($year)", true - )) && it.second.equals("$year") + (it.first.equals(title, true) || it.first.equals("$title ($year)", true)) && it.second.equals("$year") } else { it.first.equals("$title - Season $season", true) } @@ -2119,21 +1394,14 @@ object SoraExtractor : SoraStream() { val iframe = if (season == null) { media.third } else { - val res = app.get( - fixUrl( - media.third, - api - ) - ) - res.document.selectFirst("div#$episodeSelector a:contains(Episode ${slug.second})") - ?.attr("href") + val res = app.get(fixUrl(media.third, api)) + res.document.selectFirst("div#$episodeSelector a:contains(Episode ${slug.second})")?.attr("href") } ?: return val users = if (season == null) { media.third.substringAfterLast("/") to "0" } else { - media.third.substringAfterLast("/") to iframe.substringAfterLast("/") - .substringBefore("-") + media.third.substringAfterLast("/") to iframe.substringAfterLast("/").substringBefore("-") } val res = app.get(fixUrl(iframe, api), verify = false) delay(2000) @@ -2144,33 +1412,23 @@ object SoraExtractor : SoraStream() { val url = res.document.select("meta[property=og:url]").attr("content") val headers = mapOf("X-Requested-With" to "XMLHttpRequest") val qualities = intArrayOf(2160, 1440, 1080, 720, 480, 360) - val serverRes = app.get( - "$api/user/servers/${users.first}?ep=${users.second}", - cookies = cookies, referer = url, headers = headers - ) + val serverRes = app.get("$api/user/servers/${users.first}?ep=${users.second}", cookies = cookies, referer = url, headers = headers) val unpack = getAndUnpack(serverRes.text) val key = unpack.substringAfter("(key=").substringBefore(")") val key2 = unpack.substringAfter("<\"").substringBefore("\".") serverRes.document.select("ul li").amap { el -> val server = el.attr("data-value") - val encryptedData = app.get( - "${fixUrl(serverUrl, api)}?server=$server&_=$unixTimeMS", - cookies = cookies, - referer = url, - headers = headers - ).text + val encryptedData = app.get("${fixUrl(serverUrl, api)}?server=$server&_=$unixTimeMS", cookies = cookies, referer = url, headers = headers).text val links = encryptedData.decrypt(key) ?: encryptedData.decrypt(key2) ?: return@amap links.forEach { video -> qualities.filter { it <= video.max.toInt() }.forEach { - callback( - ExtractorLink( + callback(ExtractorLink( name, name, video.src.split("360", limit = 3).joinToString(it.toString()), "$api/", it, - ) - ) + )) } } } @@ -2178,12 +1436,12 @@ object SoraExtractor : SoraStream() { } suspend fun invokeShowflix( - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit, + title: String? = null, + year: Int? = null, + season: Int? = null, + episode: Int? = null, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit, ) { val where = if (season == null) "movieName" else "seriesName" val classes = if (season == null) "movies" else "series" @@ -2204,31 +1462,24 @@ object SoraExtractor : SoraStream() { } """.trimIndent().toRequestBody(RequestBodyTypes.JSON.toMediaTypeOrNull()) - val data = - app.post("https://parse.showflix.tk/parse/classes/$classes", requestBody = body).text + val data = app.post("https://parse.showflix.tk/parse/classes/$classes", requestBody = body).text val iframes = if (season == null) { val result = tryParseJson(data)?.resultsMovies?.find { - it.movieName.equals( - "$title ($year)", - true - ) + it.movieName.equals("$title ($year)", true) } listOf( - "https://streamwish.to/e/${result?.streamwish}", - "https://filelions.to/v/${result?.filelions}.html", - "https://streamruby.com/e/${result?.streamruby}.html", + "https://streamwish.to/e/${result?.streamwish}", + "https://filelions.to/v/${result?.filelions}.html", + "https://streamruby.com/e/${result?.streamruby}.html", ) } else { val result = tryParseJson(data)?.resultsSeries?.find { - it.seriesName.equals( - title, - true - ) + it.seriesName.equals(title, true) } listOf( - result?.streamwish?.get("Season $season")?.get(episode!!), - result?.filelions?.get("Season $season")?.get(episode!!), - result?.streamruby?.get("Season $season")?.get(episode!!), + result?.streamwish?.get("Season $season")?.get(episode!!), + result?.filelions?.get("Season $season")?.get(episode!!), + result?.streamruby?.get("Season $season")?.get(episode!!), ) } @@ -2239,13 +1490,13 @@ object SoraExtractor : SoraStream() { } suspend fun invokeCinemaTv( - imdbId: String? = null, - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit, + imdbId: String? = null, + title: String? = null, + year: Int? = null, + season: Int? = null, + episode: Int? = null, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit, ) { val id = imdbId?.removePrefix("tt") val slug = title.createSlug() @@ -2255,12 +1506,11 @@ object SoraExtractor : SoraStream() { "$cinemaTvAPI/shows/play/$id-$slug-$year" } - val session = - "PHPSESSID=ngr4cudjrimdnhkth30ssohs0n; _csrf=a6ffd7bb7654083fce6df528225a238d0e85aa1fb885dc7638c1259ec1ba0d5ca%3A2%3A%7Bi%3A0%3Bs%3A5%3A%22_csrf%22%3Bi%3A1%3Bs%3A32%3A%22mTTLiDLjxohs-CpKk0bjRH3HdYMB9uBV%22%3B%7D; _ga=GA1.1.1195498587.1701871187; _ga_VZD7HJ3WK6=GS1.1.$unixTime.4.0.1.$unixTime.0.0.0" + val session = "PHPSESSID=ngr4cudjrimdnhkth30ssohs0n; _csrf=a6ffd7bb7654083fce6df528225a238d0e85aa1fb885dc7638c1259ec1ba0d5ca%3A2%3A%7Bi%3A0%3Bs%3A5%3A%22_csrf%22%3Bi%3A1%3Bs%3A32%3A%22mTTLiDLjxohs-CpKk0bjRH3HdYMB9uBV%22%3B%7D; _ga=GA1.1.1195498587.1701871187; _ga_VZD7HJ3WK6=GS1.1.$unixTime.4.0.1.$unixTime.0.0.0" val headers = mapOf( - "Cookie" to session, - "x-requested-with" to "com.wwcinematv", + "Cookie" to session, + "x-requested-with" to "com.wwcinematv", ) val doc = app.get(url, headers = headers).document @@ -2279,213 +1529,81 @@ object SoraExtractor : SoraStream() { "$cinemaTvAPI/api/v1/security/episode-access?id_episode=$episodeId&hash=$hash&expires=$expires" } - val sources = app.get( - videoUrl, - referer = url, - headers = mapOf("X-Requested-With" to "XMLHttpRequest") - ).parsedSafe() + val sources = app.get(videoUrl, referer = url, headers = mapOf("X-Requested-With" to "XMLHttpRequest")).parsedSafe() sources?.streams?.mapKeys { source -> - callback.invoke( - ExtractorLink( - "CinemaTv", - "CinemaTv", - source.value, - "$cinemaTvAPI/", - getQualityFromName(source.key), - true - ) - ) + callback.invoke(ExtractorLink("CinemaTv", "CinemaTv", source.value, "$cinemaTvAPI/", getQualityFromName(source.key), true)) } sources?.subtitles?.map { sub -> val file = sub.file.toString() - subtitleCallback.invoke( - SubtitleFile( + subtitleCallback.invoke(SubtitleFile( sub.language ?: return@map, if (file.startsWith("[")) return@map else fixUrl(file, cinemaTvAPI), - ) - ) + )) } } - suspend fun invokeFebbox( - title: String? = null, - year: Int? = null, - season: Int? = null, - lastSeason: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit, - showboxApi: String = "https://www.showbox.media" - ) { - val (seasonSlug, episodeSlug) = getEpisodeSlug(season, episode) - val res = app.get("$showboxApi/search?keyword=$title", interceptor = showboxInterceptor).document - val mediaRes = res.select("div.film_list-wrap div.flw-item").map { - ShowboxMedia( - it.select("h2.film-name a").attr("href"), - it.select("h2.film-name a").text(), - it.select("div.fd-infor > span:first-child").text(), - it.select("div.fd-infor > span:last-child").text(), - ) - } - - val filter = mediaRes.filter { - it.title.equals(title, true) && it.type == if (season == null) "Movie" else "TV" - } - - val media = if (season == null) { - filter.find { it.infor == "$year" } - } else { - filter.find { it.infor == "SS $lastSeason" } - ?: filter.find { it.infor == "SS ${lastSeason?.minus(1)}" } - ?: filter.find { it.infor == "SS 1" } - } - - val shareId = media?.url?.substringAfterLast("/") ?: return - - val shareKey = - app.get("$showboxApi/index/share_link?id=${shareId}&type=${if (season == null) "1" else "2"}", interceptor = showboxInterceptor) - .parsedSafe()?.data?.link?.substringAfterLast("/") - - val headers = mapOf("Accept-Language" to "en") - val shareRes = app.get( - "$febboxAPI/file/file_share_list?share_key=${shareKey ?: return}", - headers = headers - ) - .parsedSafe()?.data - - val fids = if (season == null) { - shareRes?.file_list - } else { - val parentId = - shareRes?.file_list?.find { it.file_name.equals("season $season", true) }?.fid - app.get( - "$febboxAPI/file/file_share_list?share_key=${shareKey}&parent_id=$parentId&page=1", - headers = headers - ) - .parsedSafe()?.data?.file_list?.filter { - it.file_name?.contains( - "s${seasonSlug}e${episodeSlug}", - true - ) == true - } - } - - fids?.mapIndexed { index, fileList -> - callback.invoke( - ExtractorLink( - "Febbox", - "Febbox [Server ${index + 1}]", - "$febboxAPI/hls/main/${fileList.oss_fid}.m3u8", - "", - getIndexQuality(fileList.file_name), - isM3u8 = true - ) - ) - } - - } - - suspend fun invokeNinetv( - tmdbId: Int? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { + suspend fun invokeNinetv(tmdbId: Int? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { val url = if (season == null) { "$nineTvAPI/movie/$tmdbId" } else { "$nineTvAPI/tv/$tmdbId-$season-$episode" } - val iframe = app.get(url, referer = "https://pressplay.top/").document.selectFirst("iframe") - ?.attr("src") + val iframe = app.get(url, referer = "https://pressplay.top/").document.selectFirst("iframe")?.attr("src") loadExtractor(iframe ?: return, "$nineTvAPI/", subtitleCallback, callback) } - suspend fun invokeNowTv( - tmdbId: Int? = null, - imdbId: String? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit, - referer: String = "https://bflix.gs/" - ) { + suspend fun invokeNowTv(tmdbId: Int? = null, imdbId: String? = null, season: Int? = null, episode: Int? = null, callback: (ExtractorLink) -> Unit, referer: String = "https://bflix.gs/") { val slug = getEpisodeSlug(season, episode) - var url = - if (season == null) "$nowTvAPI/$tmdbId.mp4" else "$nowTvAPI/tv/$tmdbId/s${season}e${slug.second}.mp4" + var url = if (season == null) "$nowTvAPI/$tmdbId.mp4" else "$nowTvAPI/tv/$tmdbId/s${season}e${slug.second}.mp4" if (!app.get(url, referer = referer).isSuccessful) { - url = - if (season == null) "$nowTvAPI/$imdbId.mp4" else "$nowTvAPI/tv/$imdbId/s${season}e${slug.second}.mp4" + url = if (season == null) "$nowTvAPI/$imdbId.mp4" else "$nowTvAPI/tv/$imdbId/s${season}e${slug.second}.mp4" if (!app.get(url, referer = referer).isSuccessful) return } - callback.invoke( - ExtractorLink( + callback.invoke(ExtractorLink( "NowTv", "NowTv", url, referer, Qualities.P1080.value, - ) - ) + )) } suspend fun invokeRidomovies( - tmdbId: Int? = null, - imdbId: String? = null, - callback: (ExtractorLink) -> Unit, + tmdbId: Int? = null, + imdbId: String? = null, + callback: (ExtractorLink) -> Unit, ) { - val slug = app.get("$ridomoviesAPI/core/api/search?q=$imdbId") - .parsedSafe()?.data?.items?.find { - it.contentable?.tmdbId == tmdbId || it.contentable?.imdbId == imdbId - }?.slug ?: return - app.get("$ridomoviesAPI/core/api/movies/$slug/videos") - .parsedSafe()?.data?.apmap { link -> - val iframe = Jsoup.parse(link.url ?: return@apmap).select("iframe").attr("data-src") - val unpacked = - getAndUnpack( - app.get( - iframe, - referer = "$ridomoviesAPI/" - ).text - ) - val video = Regex("=\"(aHR.*?)\";").find(unpacked)?.groupValues?.get(1) - callback.invoke( - ExtractorLink( - "Ridomovies", - "Ridomovies", - base64Decode(video ?: return@apmap), - "${getBaseUrl(iframe)}/", - Qualities.P1080.value, - isM3u8 = true - ) - ) - } + val slug = app.get("$ridomoviesAPI/core/api/search?q=$imdbId").parsedSafe()?.data?.items?.find { + it.contentable?.tmdbId == tmdbId || it.contentable?.imdbId == imdbId + }?.slug ?: return + app.get("$ridomoviesAPI/core/api/movies/$slug/videos").parsedSafe()?.data?.apmap { link -> + val iframe = Jsoup.parse(link.url ?: return@apmap).select("iframe").attr("data-src") + val unpacked = getAndUnpack(app.get(iframe, referer = "$ridomoviesAPI/").text) + val video = Regex("=\"(aHR.*?)\";").find(unpacked)?.groupValues?.get(1) + callback.invoke(ExtractorLink("Ridomovies", "Ridomovies", base64Decode(video + ?: return@apmap), "${getBaseUrl(iframe)}/", Qualities.P1080.value, isM3u8 = true)) + } } suspend fun invokeAllMovieland( - imdbId: String? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit, - host: String = "https://esh-bostewsom-i-273.site", + imdbId: String? = null, + season: Int? = null, + episode: Int? = null, + callback: (ExtractorLink) -> Unit, + host: String = "https://esh-bostewsom-i-273.site", ) { - val res = app.get( - "$host/play/$imdbId", referer = "$allmovielandAPI/" - ).document.selectFirst("script:containsData(player =)")?.data()?.substringAfter("{") - ?.substringBefore(";")?.substringBefore(")") + val res = app.get("$host/play/$imdbId", referer = "$allmovielandAPI/").document.selectFirst("script:containsData(player =)")?.data()?.substringAfter("{")?.substringBefore(";")?.substringBefore(")") val json = tryParseJson("{${res ?: return}") - val headers = mapOf( - "X-CSRF-TOKEN" to "${json?.key}" - ) + val headers = mapOf("X-CSRF-TOKEN" to "${json?.key}") - val serverRes = app.get( - fixUrl(json?.file ?: return, host), headers = headers, referer = "$allmovielandAPI/" - ).text.replace(Regex(""",\s*\[]"""), "") + val serverRes = app.get(fixUrl(json?.file + ?: return, host), headers = headers, referer = "$allmovielandAPI/").text.replace(Regex(""",\s*\[]"""), "") val servers = tryParseJson>(serverRes).let { server -> if (season == null) { server?.map { it.file to it.title } @@ -2497,25 +1615,19 @@ object SoraExtractor : SoraStream() { } servers?.apmap { (server, lang) -> - val path = app.post( - "${host}/playlist/${server ?: return@apmap}.txt", headers = headers, referer = "$allmovielandAPI/" - ).text - M3u8Helper.generateM3u8( - "Allmovieland [$lang]", - path, - "$allmovielandAPI/" - ).forEach(callback) + val path = app.post("${host}/playlist/${server ?: return@apmap}.txt", headers = headers, referer = "$allmovielandAPI/").text + M3u8Helper.generateM3u8("Allmovieland [$lang]", path, "$allmovielandAPI/").forEach(callback) } } suspend fun invokeEmovies( - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit, + title: String? = null, + year: Int? = null, + season: Int? = null, + episode: Int? = null, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit, ) { val slug = title.createSlug() val url = if (season == null) { @@ -2531,22 +1643,16 @@ object SoraExtractor : SoraStream() { res.selectFirst("select#selectServer option[sv=oserver]")?.attr("value") } else { res.select("div.le-server a").find { - val num = - Regex("Episode (\\d+)").find(it.text())?.groupValues?.get(1)?.toIntOrNull() + val num = Regex("Episode (\\d+)").find(it.text())?.groupValues?.get(1)?.toIntOrNull() num == episode }?.attr("href") })?.substringAfter("id=")?.substringBefore("&") - val server = app.get( - "$emoviesAPI/ajax/v4_get_sources?s=oserver&id=${id ?: return}&_=${unixTimeMS}", - headers = mapOf( - "X-Requested-With" to "XMLHttpRequest" - ) - ).parsedSafe()?.value + val server = app.get("$emoviesAPI/ajax/v4_get_sources?s=oserver&id=${id ?: return}&_=${unixTimeMS}", headers = mapOf("X-Requested-With" to "XMLHttpRequest")).parsedSafe()?.value - val script = app.get( - server ?: return, referer = "$emoviesAPI/" - ).document.selectFirst("script:containsData(sources:)")?.data() ?: return + val script = app.get(server + ?: return, referer = "$emoviesAPI/").document.selectFirst("script:containsData(sources:)")?.data() + ?: return val sources = Regex("sources:\\s*\\[(.*)],").find(script)?.groupValues?.get(1)?.let { tryParseJson>("[$it]") } @@ -2555,59 +1661,39 @@ object SoraExtractor : SoraStream() { } sources?.map { source -> - M3u8Helper.generateM3u8( - "Emovies", source.file ?: return@map, "https://embed.vodstream.xyz/" - ).forEach(callback) + M3u8Helper.generateM3u8("Emovies", source.file + ?: return@map, "https://embed.vodstream.xyz/").forEach(callback) } tracks?.map { track -> - subtitleCallback.invoke( - SubtitleFile( + subtitleCallback.invoke(SubtitleFile( track.label ?: "", track.file ?: return@map, - ) - ) + )) } } suspend fun invokeSFMovies( - tmdbId: Int? = null, - title: String? = null, - year: Int? = null, - season: Int? = null, - episode: Int? = null, - callback: (ExtractorLink) -> Unit, + tmdbId: Int? = null, + title: String? = null, + year: Int? = null, + season: Int? = null, + episode: Int? = null, + callback: (ExtractorLink) -> Unit, ) { - val headers = - mapOf("Authorization" to "Bearer 44d784c55e9a1e3dbb586f24b18b1cbcd1521673bd6178ef385890d2f989681fe22d05e291e2e0f03fce99cbc50cd520219e52cc6e30c944a559daf53a129af18349ec98f6a0e4e66b8d370a354f4f7fbd49df0ab806d533a3db71eecc7f75131a59ce8cffc5e0cc38e8af5919c23c0d904fbe31995308f065f0ff9cd1eda488") - val data = app.get( - "${BuildConfig.SFMOVIES_API}/api/mains?filters[title][\$contains]=$title", - headers = headers - ) - .parsedSafe()?.data + val headers = mapOf("Authorization" to "Bearer 44d784c55e9a1e3dbb586f24b18b1cbcd1521673bd6178ef385890d2f989681fe22d05e291e2e0f03fce99cbc50cd520219e52cc6e30c944a559daf53a129af18349ec98f6a0e4e66b8d370a354f4f7fbd49df0ab806d533a3db71eecc7f75131a59ce8cffc5e0cc38e8af5919c23c0d904fbe31995308f065f0ff9cd1eda488") + val data = app.get("${BuildConfig.SFMOVIES_API}/api/mains?filters[title][\$contains]=$title", headers = headers).parsedSafe()?.data val media = data?.find { - it.attributes?.contentId.equals("$tmdbId") || (it.attributes?.title.equals( - title, - true - ) || it.attributes?.releaseDate?.substringBefore("-").equals("$year")) + it.attributes?.contentId.equals("$tmdbId") || (it.attributes?.title.equals(title, true) || it.attributes?.releaseDate?.substringBefore("-").equals("$year")) } val video = if (season == null || episode == null) { media?.attributes?.video } else { media?.attributes?.seriess?.get(season - 1)?.get(episode - 1)?.svideos } ?: return - callback.invoke( - ExtractorLink( - "SFMovies", - "SFMovies", - fixUrl(video, getSfServer()), - "", - Qualities.P1080.value, - INFER_TYPE - ) - ) + callback.invoke(ExtractorLink("SFMovies", "SFMovies", fixUrl(video, getSfServer()), "", Qualities.P1080.value, INFER_TYPE)) } } diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt index 03eafa4c..c4378663 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt @@ -11,209 +11,185 @@ data class CrunchyrollAccessToken( val key_pair_id: String? = null, ) -data class ShowboxMedia( - val url: String, - val title: String, - val infor: String, - val type: String, -) data class FDMovieIFrame( - val link: String, - val quality: String, - val size: String, - val type: String, + val link: String, + val quality: String, + val size: String, + val type: String, ) -data class AniIds( - var id: Int? = null, - var idMal: Int? = null -) +data class AniIds(var id: Int? = null, var idMal: Int? = null) data class TmdbDate( - val today: String, - val nextWeek: String, + val today: String, + val nextWeek: String, ) -data class AniMedia( - @JsonProperty("id") var id: Int? = null, - @JsonProperty("idMal") var idMal: Int? = null -) +data class AniMedia(@JsonProperty("id") var id: Int? = null, @JsonProperty("idMal") var idMal: Int? = null) -data class AniPage( - @JsonProperty("media") var media: java.util.ArrayList = arrayListOf() -) +data class AniPage(@JsonProperty("media") var media: java.util.ArrayList = arrayListOf()) -data class AniData( - @JsonProperty("Page") var Page: AniPage? = AniPage() -) +data class AniData(@JsonProperty("Page") var Page: AniPage? = AniPage()) -data class AniSearch( - @JsonProperty("data") var data: AniData? = AniData() -) +data class AniSearch(@JsonProperty("data") var data: AniData? = AniData()) data class GpressSources( - @JsonProperty("src") val src: String, - @JsonProperty("file") val file: String? = null, - @JsonProperty("label") val label: Int? = null, - @JsonProperty("max") val max: String, + @JsonProperty("src") val src: String, + @JsonProperty("file") val file: String? = null, + @JsonProperty("label") val label: Int? = null, + @JsonProperty("max") val max: String, ) data class UHDBackupUrl( - @JsonProperty("url") val url: String? = null, + @JsonProperty("url") val url: String? = null, ) data class ResponseHash( - @JsonProperty("embed_url") val embed_url: String, - @JsonProperty("key") val key: String? = null, - @JsonProperty("type") val type: String? = null, + @JsonProperty("embed_url") val embed_url: String, + @JsonProperty("key") val key: String? = null, + @JsonProperty("type") val type: String? = null, ) data class KisskhSources( - @JsonProperty("Video") val video: String?, - @JsonProperty("ThirdParty") val thirdParty: String?, + @JsonProperty("Video") val video: String?, + @JsonProperty("ThirdParty") val thirdParty: String?, ) data class KisskhSubtitle( - @JsonProperty("src") val src: String?, - @JsonProperty("label") val label: String?, + @JsonProperty("src") val src: String?, + @JsonProperty("label") val label: String?, ) data class KisskhEpisodes( - @JsonProperty("id") val id: Int?, - @JsonProperty("number") val number: Int?, + @JsonProperty("id") val id: Int?, + @JsonProperty("number") val number: Int?, ) data class KisskhDetail( - @JsonProperty("episodes") val episodes: ArrayList? = arrayListOf(), + @JsonProperty("episodes") val episodes: ArrayList? = arrayListOf(), ) data class KisskhResults( - @JsonProperty("id") val id: Int?, - @JsonProperty("title") val title: String?, + @JsonProperty("id") val id: Int?, + @JsonProperty("title") val title: String?, ) data class DriveBotLink( - @JsonProperty("url") val url: String? = null, + @JsonProperty("url") val url: String? = null, ) data class DirectDl( - @JsonProperty("download_url") val download_url: String? = null, + @JsonProperty("download_url") val download_url: String? = null, ) data class Safelink( - @JsonProperty("safelink") val safelink: String? = null, + @JsonProperty("safelink") val safelink: String? = null, ) data class FDAds( - @JsonProperty("linkr") val linkr: String? = null, + @JsonProperty("linkr") val linkr: String? = null, ) data class ZShowEmbed( - @JsonProperty("m") val meta: String? = null, + @JsonProperty("m") val meta: String? = null, ) data class WatchsomuchTorrents( - @JsonProperty("id") val id: Int? = null, - @JsonProperty("movieId") val movieId: Int? = null, - @JsonProperty("season") val season: Int? = null, - @JsonProperty("episode") val episode: Int? = null, + @JsonProperty("id") val id: Int? = null, + @JsonProperty("movieId") val movieId: Int? = null, + @JsonProperty("season") val season: Int? = null, + @JsonProperty("episode") val episode: Int? = null, ) data class WatchsomuchMovies( - @JsonProperty("torrents") val torrents: ArrayList? = arrayListOf(), + @JsonProperty("torrents") val torrents: ArrayList? = arrayListOf(), ) data class WatchsomuchResponses( - @JsonProperty("movie") val movie: WatchsomuchMovies? = null, + @JsonProperty("movie") val movie: WatchsomuchMovies? = null, ) data class WatchsomuchSubtitles( - @JsonProperty("url") val url: String? = null, - @JsonProperty("label") val label: String? = null, + @JsonProperty("url") val url: String? = null, + @JsonProperty("label") val label: String? = null, ) data class WatchsomuchSubResponses( - @JsonProperty("subtitles") val subtitles: ArrayList? = arrayListOf(), + @JsonProperty("subtitles") val subtitles: ArrayList? = arrayListOf(), ) data class IndexMedia( - @JsonProperty("id") val id: String? = null, - @JsonProperty("driveId") val driveId: String? = null, - @JsonProperty("mimeType") val mimeType: String? = null, - @JsonProperty("size") val size: String? = null, - @JsonProperty("name") val name: String? = null, - @JsonProperty("modifiedTime") val modifiedTime: String? = null, + @JsonProperty("id") val id: String? = null, + @JsonProperty("driveId") val driveId: String? = null, + @JsonProperty("mimeType") val mimeType: String? = null, + @JsonProperty("size") val size: String? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("modifiedTime") val modifiedTime: String? = null, ) data class IndexData( - @JsonProperty("files") val files: ArrayList? = arrayListOf(), + @JsonProperty("files") val files: ArrayList? = arrayListOf(), ) data class IndexSearch( - @JsonProperty("data") val data: IndexData? = null, + @JsonProperty("data") val data: IndexData? = null, ) data class JikanExternal( - @JsonProperty("name") val name: String? = null, - @JsonProperty("url") val url: String? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("url") val url: String? = null, ) data class JikanData( - @JsonProperty("title") val title: String? = null, - @JsonProperty("external") val external: ArrayList? = arrayListOf(), + @JsonProperty("title") val title: String? = null, + @JsonProperty("external") val external: ArrayList? = arrayListOf(), ) data class JikanResponse( - @JsonProperty("data") val data: JikanData? = null, + @JsonProperty("data") val data: JikanData? = null, ) data class CinemaTvSubtitles( - @JsonProperty("language") val language: String? = null, - @JsonProperty("file") val file: Any? = null, + @JsonProperty("language") val language: String? = null, + @JsonProperty("file") val file: Any? = null, ) data class CinemaTvResponse( - @JsonProperty("streams") val streams: HashMap? = null, - @JsonProperty("subtitles") val subtitles: ArrayList? = arrayListOf(), + @JsonProperty("streams") val streams: HashMap? = null, + @JsonProperty("subtitles") val subtitles: ArrayList? = arrayListOf(), ) data class VidsrctoResult( - @JsonProperty("id") val id: String? = null, - @JsonProperty("title") val title: String? = null, - @JsonProperty("url") val url: String? = null, + @JsonProperty("id") val id: String? = null, + @JsonProperty("title") val title: String? = null, + @JsonProperty("url") val url: String? = null, ) data class VidsrctoResponse( - @JsonProperty("result") val result: VidsrctoResult? = null, + @JsonProperty("result") val result: VidsrctoResult? = null, ) data class VidsrctoSources( - @JsonProperty("result") val result: ArrayList? = arrayListOf(), + @JsonProperty("result") val result: ArrayList? = arrayListOf(), ) data class VidsrctoSubtitles( - @JsonProperty("label") val label: String? = null, - @JsonProperty("file") val file: String? = null, + @JsonProperty("label") val label: String? = null, + @JsonProperty("file") val file: String? = null, ) data class AnilistExternalLinks( - @JsonProperty("id") var id: Int? = null, - @JsonProperty("site") var site: String? = null, - @JsonProperty("url") var url: String? = null, - @JsonProperty("type") var type: String? = null, + @JsonProperty("id") var id: Int? = null, + @JsonProperty("site") var site: String? = null, + @JsonProperty("url") var url: String? = null, + @JsonProperty("type") var type: String? = null, ) -data class AnilistMedia( - @JsonProperty("externalLinks") var externalLinks: ArrayList = arrayListOf() -) +data class AnilistMedia(@JsonProperty("externalLinks") var externalLinks: ArrayList = arrayListOf()) -data class AnilistData( - @JsonProperty("Media") var Media: AnilistMedia? = AnilistMedia() -) +data class AnilistData(@JsonProperty("Media") var Media: AnilistMedia? = AnilistMedia()) -data class AnilistResponses( - @JsonProperty("data") var data: AnilistData? = AnilistData() -) +data class AnilistResponses(@JsonProperty("data") var data: AnilistData? = AnilistData()) data class CrunchyrollToken( @JsonProperty("access_token") val accessToken: String? = null, @@ -229,22 +205,22 @@ data class CrunchyrollToken( } data class CrunchyrollVersions( - @JsonProperty("audio_locale") val audio_locale: String? = null, - @JsonProperty("guid") val guid: String? = null, + @JsonProperty("audio_locale") val audio_locale: String? = null, + @JsonProperty("guid") val guid: String? = null, ) data class CrunchyrollData( - @JsonProperty("id") val id: String? = null, - @JsonProperty("title") val title: String? = null, - @JsonProperty("slug_title") val slug_title: String? = null, - @JsonProperty("season_number") val season_number: Int? = null, - @JsonProperty("episode_number") val episode_number: Int? = null, - @JsonProperty("versions") val versions: ArrayList? = null, - @JsonProperty("streams_link") val streams_link: String? = null, + @JsonProperty("id") val id: String? = null, + @JsonProperty("title") val title: String? = null, + @JsonProperty("slug_title") val slug_title: String? = null, + @JsonProperty("season_number") val season_number: Int? = null, + @JsonProperty("episode_number") val episode_number: Int? = null, + @JsonProperty("versions") val versions: ArrayList? = null, + @JsonProperty("streams_link") val streams_link: String? = null, ) data class CrunchyrollResponses( - @JsonProperty("data") val data: ArrayList? = arrayListOf(), + @JsonProperty("data") val data: ArrayList? = arrayListOf(), ) data class CrunchyrollSourcesResponses( @@ -258,34 +234,34 @@ data class CrunchyrollSourcesResponses( } data class MALSyncSites( - @JsonProperty("Zoro") val zoro: HashMap>? = hashMapOf(), + @JsonProperty("Zoro") val zoro: HashMap>? = hashMapOf(), ) data class MALSyncResponses( - @JsonProperty("Sites") val sites: MALSyncSites? = null, + @JsonProperty("Sites") val sites: MALSyncSites? = null, ) data class AniwatchResponses( - @JsonProperty("html") val html: String? = null, - @JsonProperty("link") val link: String? = null, + @JsonProperty("html") val html: String? = null, + @JsonProperty("link") val link: String? = null, ) data class MalSyncRes( - @JsonProperty("Sites") val Sites: Map>>? = null, + @JsonProperty("Sites") val Sites: Map>>? = null, ) data class GokuData( - @JsonProperty("link") val link: String? = null, + @JsonProperty("link") val link: String? = null, ) data class GokuServer( - @JsonProperty("data") val data: GokuData? = GokuData(), + @JsonProperty("data") val data: GokuData? = GokuData(), ) data class AllMovielandEpisodeFolder( - @JsonProperty("title") val title: String? = null, - @JsonProperty("id") val id: String? = null, - @JsonProperty("file") val file: String? = null, + @JsonProperty("title") val title: String? = null, + @JsonProperty("id") val id: String? = null, + @JsonProperty("file") val file: String? = null, ) data class AllMovielandSeasonFolder( @@ -302,177 +278,159 @@ data class AllMovielandServer( ) data class AllMovielandPlaylist( - @JsonProperty("file") val file: String? = null, - @JsonProperty("key") val key: String? = null, - @JsonProperty("href") val href: String? = null, + @JsonProperty("file") val file: String? = null, + @JsonProperty("key") val key: String? = null, + @JsonProperty("href") val href: String? = null, ) data class DumpMedia( - @JsonProperty("id") val id: String? = null, - @JsonProperty("domainType") val domainType: Int? = null, - @JsonProperty("name") val name: String? = null, - @JsonProperty("releaseTime") val releaseTime: String? = null, + @JsonProperty("id") val id: String? = null, + @JsonProperty("domainType") val domainType: Int? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("releaseTime") val releaseTime: String? = null, ) data class DumpQuickSearchData( - @JsonProperty("searchResults") val searchResults: ArrayList? = arrayListOf(), + @JsonProperty("searchResults") val searchResults: ArrayList? = arrayListOf(), ) data class SubtitlingList( - @JsonProperty("languageAbbr") val languageAbbr: String? = null, - @JsonProperty("language") val language: String? = null, - @JsonProperty("subtitlingUrl") val subtitlingUrl: String? = null, + @JsonProperty("languageAbbr") val languageAbbr: String? = null, + @JsonProperty("language") val language: String? = null, + @JsonProperty("subtitlingUrl") val subtitlingUrl: String? = null, ) data class DefinitionList( - @JsonProperty("code") val code: String? = null, - @JsonProperty("description") val description: String? = null, + @JsonProperty("code") val code: String? = null, + @JsonProperty("description") val description: String? = null, ) data class EpisodeVo( - @JsonProperty("id") val id: Int? = null, - @JsonProperty("seriesNo") val seriesNo: Int? = null, - @JsonProperty("definitionList") val definitionList: ArrayList? = arrayListOf(), - @JsonProperty("subtitlingList") val subtitlingList: ArrayList? = arrayListOf(), + @JsonProperty("id") val id: Int? = null, + @JsonProperty("seriesNo") val seriesNo: Int? = null, + @JsonProperty("definitionList") val definitionList: ArrayList? = arrayListOf(), + @JsonProperty("subtitlingList") val subtitlingList: ArrayList? = arrayListOf(), ) data class DumpMediaDetail( - @JsonProperty("episodeVo") val episodeVo: ArrayList? = arrayListOf(), + @JsonProperty("episodeVo") val episodeVo: ArrayList? = arrayListOf(), ) data class EMovieServer( - @JsonProperty("value") val value: String? = null, + @JsonProperty("value") val value: String? = null, ) data class EMovieSources( - @JsonProperty("file") val file: String? = null, + @JsonProperty("file") val file: String? = null, ) data class EMovieTraks( - @JsonProperty("file") val file: String? = null, - @JsonProperty("label") val label: String? = null, + @JsonProperty("file") val file: String? = null, + @JsonProperty("label") val label: String? = null, ) data class ShowflixResultsMovies( - @JsonProperty("movieName") val movieName: String? = null, - @JsonProperty("streamwish") val streamwish: String? = null, - @JsonProperty("filelions") val filelions: String? = null, - @JsonProperty("streamruby") val streamruby: String? = null, + @JsonProperty("movieName") val movieName: String? = null, + @JsonProperty("streamwish") val streamwish: String? = null, + @JsonProperty("filelions") val filelions: String? = null, + @JsonProperty("streamruby") val streamruby: String? = null, ) data class ShowflixResultsSeries( - @JsonProperty("seriesName") val seriesName: String? = null, - @JsonProperty("streamwish") val streamwish: HashMap>? = hashMapOf(), - @JsonProperty("filelions") val filelions: HashMap>? = hashMapOf(), - @JsonProperty("streamruby") val streamruby: HashMap>? = hashMapOf(), + @JsonProperty("seriesName") val seriesName: String? = null, + @JsonProperty("streamwish") val streamwish: HashMap>? = hashMapOf(), + @JsonProperty("filelions") val filelions: HashMap>? = hashMapOf(), + @JsonProperty("streamruby") val streamruby: HashMap>? = hashMapOf(), ) data class ShowflixSearchMovies( - @JsonProperty("results") val resultsMovies: ArrayList? = arrayListOf(), + @JsonProperty("results") val resultsMovies: ArrayList? = arrayListOf(), ) data class ShowflixSearchSeries( - @JsonProperty("results") val resultsSeries: ArrayList? = arrayListOf(), + @JsonProperty("results") val resultsSeries: ArrayList? = arrayListOf(), ) data class SFMoviesSeriess( - @JsonProperty("title") var title: String? = null, - @JsonProperty("svideos") var svideos: String? = null, + @JsonProperty("title") var title: String? = null, + @JsonProperty("svideos") var svideos: String? = null, ) data class SFMoviesAttributes( - @JsonProperty("title") var title: String? = null, - @JsonProperty("video") var video: String? = null, - @JsonProperty("releaseDate") var releaseDate: String? = null, - @JsonProperty("seriess") var seriess: ArrayList>? = arrayListOf(), - @JsonProperty("contentId") var contentId: String? = null, + @JsonProperty("title") var title: String? = null, + @JsonProperty("video") var video: String? = null, + @JsonProperty("releaseDate") var releaseDate: String? = null, + @JsonProperty("seriess") var seriess: ArrayList>? = arrayListOf(), + @JsonProperty("contentId") var contentId: String? = null, ) -data class SFMoviesData( - @JsonProperty("id") var id: Int? = null, - @JsonProperty("attributes") var attributes: SFMoviesAttributes? = SFMoviesAttributes() -) +data class SFMoviesData(@JsonProperty("id") var id: Int? = null, @JsonProperty("attributes") var attributes: SFMoviesAttributes? = SFMoviesAttributes()) data class SFMoviesSearch( - @JsonProperty("data") var data: ArrayList? = arrayListOf(), + @JsonProperty("data") var data: ArrayList? = arrayListOf(), ) data class RidoContentable( - @JsonProperty("imdbId") var imdbId: String? = null, - @JsonProperty("tmdbId") var tmdbId: Int? = null, + @JsonProperty("imdbId") var imdbId: String? = null, + @JsonProperty("tmdbId") var tmdbId: Int? = null, ) data class RidoItems( - @JsonProperty("slug") var slug: String? = null, - @JsonProperty("contentable") var contentable: RidoContentable? = null, + @JsonProperty("slug") var slug: String? = null, + @JsonProperty("contentable") var contentable: RidoContentable? = null, ) data class RidoData( - @JsonProperty("url") var url: String? = null, - @JsonProperty("items") var items: ArrayList? = arrayListOf(), + @JsonProperty("url") var url: String? = null, + @JsonProperty("items") var items: ArrayList? = arrayListOf(), ) data class RidoResponses( - @JsonProperty("data") var data: ArrayList? = arrayListOf(), + @JsonProperty("data") var data: ArrayList? = arrayListOf(), ) data class RidoSearch( - @JsonProperty("data") var data: RidoData? = null, + @JsonProperty("data") var data: RidoData? = null, ) data class SmashySources( - @JsonProperty("sourceUrls") var sourceUrls: ArrayList? = arrayListOf(), - @JsonProperty("subtitleUrls") var subtitleUrls: String? = null, + @JsonProperty("sourceUrls") var sourceUrls: ArrayList? = arrayListOf(), + @JsonProperty("subtitleUrls") var subtitleUrls: String? = null, ) data class SmashyDSources( - @JsonProperty("sourceUrls") var sourceUrls: ArrayList? = arrayListOf(), + @JsonProperty("sourceUrls") var sourceUrls: ArrayList? = arrayListOf(), ) data class SmashyDSourcesUrls( - @JsonProperty("file") var file: String? = null, - @JsonProperty("title") var title: String? = null, + @JsonProperty("file") var file: String? = null, + @JsonProperty("title") var title: String? = null, ) data class AoneroomResponse( - @JsonProperty("data") val data: Data? = null, + @JsonProperty("data") val data: Data? = null, ) { data class Data( - @JsonProperty("items") val items: ArrayList? = arrayListOf(), - @JsonProperty("list") val list: ArrayList? = arrayListOf(), + @JsonProperty("items") val items: ArrayList? = arrayListOf(), + @JsonProperty("list") val list: ArrayList? = arrayListOf(), ) { data class Items( - @JsonProperty("subjectId") val subjectId: String? = null, - @JsonProperty("title") val title: String? = null, - @JsonProperty("releaseDate") val releaseDate: String? = null, + @JsonProperty("subjectId") val subjectId: String? = null, + @JsonProperty("title") val title: String? = null, + @JsonProperty("releaseDate") val releaseDate: String? = null, ) data class List( - @JsonProperty("resourceLink") val resourceLink: String? = null, - @JsonProperty("extCaptions") val extCaptions: ArrayList? = arrayListOf(), - @JsonProperty("se") val se: Int? = null, - @JsonProperty("ep") val ep: Int? = null, - @JsonProperty("resolution") val resolution: Int? = null, + @JsonProperty("resourceLink") val resourceLink: String? = null, + @JsonProperty("extCaptions") val extCaptions: ArrayList? = arrayListOf(), + @JsonProperty("se") val se: Int? = null, + @JsonProperty("ep") val ep: Int? = null, + @JsonProperty("resolution") val resolution: Int? = null, ) { data class ExtCaptions( - @JsonProperty("lanName") val lanName: String? = null, - @JsonProperty("url") val url: String? = null, + @JsonProperty("lanName") val lanName: String? = null, + @JsonProperty("url") val url: String? = null, ) } } -} - -data class FebboxResponse( - @JsonProperty("data") val data: Data? = null, -) { - data class Data( - @JsonProperty("link") val link: String? = null, - @JsonProperty("file_list") val file_list: ArrayList? = arrayListOf(), - ) { - data class FileList( - @JsonProperty("fid") val fid: Long? = null, - @JsonProperty("file_name") val file_name: String? = null, - @JsonProperty("oss_fid") val oss_fid: Long? = 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 141c5839..8c6aa0ea 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt @@ -43,7 +43,7 @@ import com.hexated.SoraExtractor.invokeUhdmovies import com.hexated.SoraExtractor.invokeVegamovies import com.hexated.SoraExtractor.invokeVidsrcto import com.hexated.SoraExtractor.invokeCinemaTv -import com.hexated.SoraExtractor.invokeFebbox +import com.hexated.SoraExtractor.invokeMMovies import com.hexated.SoraExtractor.invokeOmovies import com.hexated.SoraExtractor.invokeWatchCartoon import com.hexated.SoraExtractor.invokeWatchsomuch @@ -63,13 +63,13 @@ open class SoraStream : TmdbProvider() { override val useMetaLoadResponse = true override val hasQuickSearch = true override val supportedTypes = setOf( - TvType.Movie, - TvType.TvSeries, - TvType.Anime, + TvType.Movie, + TvType.TvSeries, + TvType.Anime, ) - val showboxInterceptor by lazy { CloudflareKiller() } val wpredisInterceptor by lazy { CloudflareKiller() } + val multiInterceptor by lazy { CloudflareKiller() } /** AUTHOR : Hexated & Sora */ companion object { @@ -114,10 +114,9 @@ open class SoraStream : TmdbProvider() { const val vidsrctoAPI = "https://vidsrc.to" const val dramadayAPI = "https://dramaday.me" const val animetoshoAPI = "https://animetosho.org" - const val watchflxAPI = "https://watchflx.tv" const val showflixAPI = "https://showflix.space" const val aoneroomAPI = "https://api3.aoneroom.com" - const val febboxAPI = "https://www.febbox.com" + const val mMoviesAPI = "https://multimovies.uno" const val watchCartoonAPI = "https://www1.watchcartoononline.bz" const val fdMoviesAPI = "https://freedrivemovie.com" @@ -148,26 +147,26 @@ open class SoraStream : TmdbProvider() { } override val mainPage = mainPageOf( - "$tmdbAPI/trending/all/day?api_key=$apiKey®ion=US" to "Trending", - "$tmdbAPI/movie/popular?api_key=$apiKey®ion=US" to "Popular Movies", - "$tmdbAPI/tv/popular?api_key=$apiKey®ion=US&with_original_language=en" to "Popular TV Shows", - "$tmdbAPI/tv/airing_today?api_key=$apiKey®ion=US&with_original_language=en" to "Airing Today TV Shows", - "$tmdbAPI/discover/tv?api_key=$apiKey&with_networks=213" to "Netflix", - "$tmdbAPI/discover/tv?api_key=$apiKey&with_networks=1024" to "Amazon", - "$tmdbAPI/discover/tv?api_key=$apiKey&with_networks=2739" to "Disney+", - "$tmdbAPI/discover/tv?api_key=$apiKey&with_networks=453" to "Hulu", - "$tmdbAPI/discover/tv?api_key=$apiKey&with_networks=2552" to "Apple TV+", - "$tmdbAPI/discover/tv?api_key=$apiKey&with_networks=49" to "HBO", - "$tmdbAPI/discover/tv?api_key=$apiKey&with_networks=4330" to "Paramount+", - "$tmdbAPI/discover/tv?api_key=$apiKey&with_networks=3353" to "Peacock", - "$tmdbAPI/movie/top_rated?api_key=$apiKey®ion=US" to "Top Rated Movies", - "$tmdbAPI/tv/top_rated?api_key=$apiKey®ion=US" to "Top Rated TV Shows", - "$tmdbAPI/movie/upcoming?api_key=$apiKey®ion=US" to "Upcoming Movies", - "$tmdbAPI/discover/tv?api_key=$apiKey&with_original_language=ko" to "Korean Shows", - "$tmdbAPI/discover/tv?api_key=$apiKey&with_keywords=210024|222243&sort_by=popularity.desc&air_date.lte=${getDate().today}&air_date.gte=${getDate().today}" to "Airing Today Anime", - "$tmdbAPI/discover/tv?api_key=$apiKey&with_keywords=210024|222243&sort_by=popularity.desc&air_date.lte=${getDate().nextWeek}&air_date.gte=${getDate().today}" to "On The Air Anime", - "$tmdbAPI/discover/tv?api_key=$apiKey&with_keywords=210024|222243" to "Anime", - "$tmdbAPI/discover/movie?api_key=$apiKey&with_keywords=210024|222243" to "Anime Movies", + "$tmdbAPI/trending/all/day?api_key=$apiKey®ion=US" to "Trending", + "$tmdbAPI/movie/popular?api_key=$apiKey®ion=US" to "Popular Movies", + "$tmdbAPI/tv/popular?api_key=$apiKey®ion=US&with_original_language=en" to "Popular TV Shows", + "$tmdbAPI/tv/airing_today?api_key=$apiKey®ion=US&with_original_language=en" to "Airing Today TV Shows", + "$tmdbAPI/discover/tv?api_key=$apiKey&with_networks=213" to "Netflix", + "$tmdbAPI/discover/tv?api_key=$apiKey&with_networks=1024" to "Amazon", + "$tmdbAPI/discover/tv?api_key=$apiKey&with_networks=2739" to "Disney+", + "$tmdbAPI/discover/tv?api_key=$apiKey&with_networks=453" to "Hulu", + "$tmdbAPI/discover/tv?api_key=$apiKey&with_networks=2552" to "Apple TV+", + "$tmdbAPI/discover/tv?api_key=$apiKey&with_networks=49" to "HBO", + "$tmdbAPI/discover/tv?api_key=$apiKey&with_networks=4330" to "Paramount+", + "$tmdbAPI/discover/tv?api_key=$apiKey&with_networks=3353" to "Peacock", + "$tmdbAPI/movie/top_rated?api_key=$apiKey®ion=US" to "Top Rated Movies", + "$tmdbAPI/tv/top_rated?api_key=$apiKey®ion=US" to "Top Rated TV Shows", + "$tmdbAPI/movie/upcoming?api_key=$apiKey®ion=US" to "Upcoming Movies", + "$tmdbAPI/discover/tv?api_key=$apiKey&with_original_language=ko" to "Korean Shows", + "$tmdbAPI/discover/tv?api_key=$apiKey&with_keywords=210024|222243&sort_by=popularity.desc&air_date.lte=${getDate().today}&air_date.gte=${getDate().today}" to "Airing Today Anime", + "$tmdbAPI/discover/tv?api_key=$apiKey&with_keywords=210024|222243&sort_by=popularity.desc&air_date.lte=${getDate().nextWeek}&air_date.gte=${getDate().today}" to "On The Air Anime", + "$tmdbAPI/discover/tv?api_key=$apiKey&with_keywords=210024|222243" to "Anime", + "$tmdbAPI/discover/movie?api_key=$apiKey&with_keywords=210024|222243" to "Anime Movies", ) private fun getImageUrl(link: String?): String? { @@ -180,26 +179,20 @@ open class SoraStream : TmdbProvider() { return if (link.startsWith("/")) "https://image.tmdb.org/t/p/original/$link" else link } - override suspend fun getMainPage( - page: Int, - request: MainPageRequest - ): HomePageResponse { - val adultQuery = - if (settingsForProvider.enableAdult) "" else "&without_keywords=190370|13059|226161|195669" + override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { + val adultQuery = if (settingsForProvider.enableAdult) "" else "&without_keywords=190370|13059|226161|195669" val type = if (request.data.contains("/movie")) "movie" else "tv" - val home = app.get("${request.data}$adultQuery&page=$page") - .parsedSafe()?.results - ?.mapNotNull { media -> - media.toSearchResponse(type) - } ?: throw ErrorLoadingException("Invalid Json reponse") + val home = app.get("${request.data}$adultQuery&page=$page").parsedSafe()?.results?.mapNotNull { media -> + media.toSearchResponse(type) + } ?: throw ErrorLoadingException("Invalid Json reponse") return newHomePageResponse(request.name, home) } private fun Media.toSearchResponse(type: String? = null): SearchResponse? { return newMovieSearchResponse( - title ?: name ?: originalTitle ?: return null, - Data(id = id, type = mediaType ?: type).toJson(), - TvType.Movie, + title ?: name ?: originalTitle ?: return null, + Data(id = id, type = mediaType ?: type).toJson(), + TvType.Movie, ) { this.posterUrl = getImageUrl(posterPath) } @@ -208,9 +201,7 @@ open class SoraStream : TmdbProvider() { override suspend fun quickSearch(query: String): List? = search(query) override suspend fun search(query: String): List? { - return app.get( - "$tmdbAPI/search/multi?api_key=$apiKey&language=en-US&query=$query&page=1&include_adult=${settingsForProvider.enableAdult}" - ).parsedSafe()?.results?.mapNotNull { media -> + return app.get("$tmdbAPI/search/multi?api_key=$apiKey&language=en-US&query=$query&page=1&include_adult=${settingsForProvider.enableAdult}").parsedSafe()?.results?.mapNotNull { media -> media.toSearchResponse() } } @@ -225,7 +216,7 @@ open class SoraStream : TmdbProvider() { "$tmdbAPI/tv/${data.id}?api_key=$apiKey&append_to_response=$append" } val res = app.get(resUrl).parsedSafe() - ?: throw ErrorLoadingException("Invalid Json Response") + ?: throw ErrorLoadingException("Invalid Json Response") val title = res.title ?: res.name ?: return null val poster = getOriImageUrl(res.posterPath) @@ -241,68 +232,27 @@ open class SoraStream : TmdbProvider() { val isAsian = !isAnime && (res.original_language == "zh" || res.original_language == "ko") val isBollywood = res.production_countries?.any { it.name == "India" } ?: false - val keywords = res.keywords?.results?.mapNotNull { it.name }.orEmpty() - .ifEmpty { res.keywords?.keywords?.mapNotNull { it.name } } + val keywords = res.keywords?.results?.mapNotNull { it.name }.orEmpty().ifEmpty { res.keywords?.keywords?.mapNotNull { it.name } } val actors = res.credits?.cast?.mapNotNull { cast -> - ActorData( - Actor( - cast.name ?: cast.originalName ?: return@mapNotNull null, - getImageUrl(cast.profilePath) - ), - roleString = cast.character - ) + ActorData(Actor(cast.name ?: cast.originalName + ?: return@mapNotNull null, getImageUrl(cast.profilePath)), roleString = cast.character) } ?: return null - val recommendations = - res.recommendations?.results?.mapNotNull { media -> media.toSearchResponse() } + val recommendations = res.recommendations?.results?.mapNotNull { media -> media.toSearchResponse() } - val trailer = res.videos?.results?.map { "https://www.youtube.com/watch?v=${it.key}" } - ?.randomOrNull() + val trailer = res.videos?.results?.map { "https://www.youtube.com/watch?v=${it.key}" }?.randomOrNull() return if (type == TvType.TvSeries) { val lastSeason = res.last_episode_to_air?.season_number val episodes = res.seasons?.mapNotNull { season -> - app.get("$tmdbAPI/${data.type}/${data.id}/season/${season.seasonNumber}?api_key=$apiKey") - .parsedSafe()?.episodes?.map { eps -> - Episode( - LinkData( - data.id, - res.external_ids?.imdb_id, - res.external_ids?.tvdb_id, - data.type, - eps.seasonNumber, - eps.episodeNumber, - title = title, - year = season.airDate?.split("-")?.first()?.toIntOrNull(), - orgTitle = orgTitle, - isAnime = isAnime, - airedYear = year, - lastSeason = lastSeason, - epsTitle = eps.name, - jpTitle = res.alternative_titles?.results?.find { it.iso_3166_1 == "JP" }?.title, - date = season.airDate, - airedDate = res.releaseDate ?: res.firstAirDate, - isAsian = isAsian, - isBollywood = isBollywood, - isCartoon = isCartoon - ).toJson(), - name = eps.name + if (isUpcoming(eps.airDate)) " - [UPCOMING]" else "", - season = eps.seasonNumber, - episode = eps.episodeNumber, - posterUrl = getImageUrl(eps.stillPath), - rating = eps.voteAverage?.times(10)?.roundToInt(), - description = eps.overview - ).apply { - this.addDate(eps.airDate) - } + app.get("$tmdbAPI/${data.type}/${data.id}/season/${season.seasonNumber}?api_key=$apiKey").parsedSafe()?.episodes?.map { eps -> + Episode(LinkData(data.id, res.external_ids?.imdb_id, res.external_ids?.tvdb_id, data.type, eps.seasonNumber, eps.episodeNumber, title = title, year = season.airDate?.split("-")?.first()?.toIntOrNull(), orgTitle = orgTitle, isAnime = isAnime, airedYear = year, lastSeason = lastSeason, epsTitle = eps.name, jpTitle = res.alternative_titles?.results?.find { it.iso_3166_1 == "JP" }?.title, date = season.airDate, airedDate = res.releaseDate + ?: res.firstAirDate, isAsian = isAsian, isBollywood = isBollywood, isCartoon = isCartoon).toJson(), name = eps.name + if (isUpcoming(eps.airDate)) " - [UPCOMING]" else "", season = eps.seasonNumber, episode = eps.episodeNumber, posterUrl = getImageUrl(eps.stillPath), rating = eps.voteAverage?.times(10)?.roundToInt(), description = eps.overview).apply { + this.addDate(eps.airDate) } + } }?.flatten() ?: listOf() - newTvSeriesLoadResponse( - title, - url, - if (isAnime) TvType.Anime else TvType.TvSeries, - episodes - ) { + newTvSeriesLoadResponse(title, url, if (isAnime) TvType.Anime else TvType.TvSeries, episodes) { this.posterUrl = poster this.backgroundPosterUrl = bgPoster this.year = year @@ -319,23 +269,11 @@ open class SoraStream : TmdbProvider() { } } else { newMovieLoadResponse( - title, - url, - TvType.Movie, - LinkData( - data.id, - res.external_ids?.imdb_id, - res.external_ids?.tvdb_id, - data.type, - title = title, - year = year, - orgTitle = orgTitle, - isAnime = isAnime, - jpTitle = res.alternative_titles?.results?.find { it.iso_3166_1 == "JP" }?.title, - airedDate = res.releaseDate ?: res.firstAirDate, - isAsian = isAsian, - isBollywood = isBollywood - ).toJson(), + title, + url, + TvType.Movie, + LinkData(data.id, res.external_ids?.imdb_id, res.external_ids?.tvdb_id, data.type, title = title, year = year, orgTitle = orgTitle, isAnime = isAnime, jpTitle = res.alternative_titles?.results?.find { it.iso_3166_1 == "JP" }?.title, airedDate = res.releaseDate + ?: res.firstAirDate, isAsian = isAsian, isBollywood = isBollywood).toJson(), ) { this.posterUrl = poster this.backgroundPosterUrl = bgPoster @@ -355,556 +293,315 @@ open class SoraStream : TmdbProvider() { } } - override suspend fun loadLinks( - data: String, - isCasting: Boolean, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ): Boolean { + override suspend fun loadLinks(data: String, isCasting: Boolean, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit): Boolean { val res = parseJson(data) argamap( -// { -// invokeFebbox( -// res.title, -// res.year, -// res.season, -// res.lastSeason, -// res.episode, -// callback -// ) -// }, - { - invokeDumpStream( - res.title, - res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - invokeGoku( - res.title, - res.year, - res.season, - res.lastSeason, - res.episode, - subtitleCallback, - callback - ) - }, - { - invokeVidSrc(res.id, res.season, res.episode, callback) - }, - { - invokeDbgo(res.imdbId, res.season, res.episode, subtitleCallback, callback) - }, - { - if (!res.isAnime) invokeAoneroom( - res.title, - res.airedYear ?: res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (res.isAnime) invokeAnimes( - res.title, - res.epsTitle, - res.date, - res.airedDate, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeDreamfilm( - res.title, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, + { + invokeDumpStream(res.title, res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + invokeGoku(res.title, res.year, res.season, res.lastSeason, res.episode, subtitleCallback, callback) + }, + { + invokeVidSrc(res.id, res.season, res.episode, callback) + }, + { + invokeDbgo(res.imdbId, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeAoneroom(res.title, res.airedYear + ?: res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (res.isAnime) invokeAnimes(res.title, res.epsTitle, res.date, res.airedDate, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeDreamfilm(res.title, res.season, res.episode, subtitleCallback, callback) + }, // { // invokeNoverse(res.title, res.season, res.episode, callback) // }, - { - if (!res.isAnime) invokeFilmxy( - res.imdbId, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime && res.isCartoon) invokeKimcartoon( - res.title, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime && res.isCartoon) invokeWatchCartoon( - res.title, - res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeVidsrcto( - res.imdbId, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (res.isAsian || res.isAnime) invokeKisskh( - res.title, - res.season, - res.episode, - res.isAnime, - res.lastSeason, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeOmovies ( - res.title, - res.year, - res.season, - res.episode, - callback - ) - }, - { - if (!res.isAnime) invokeLing( - res.title, - res.airedYear ?: res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeUhdmovies( - res.title, - res.year, - res.season, - res.episode, - 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, - callback - ) - }, - { - if (!res.isAnime) invokeM4uhd( - res.title, - res.airedYear ?: res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeTvMovies(res.title, res.season, res.episode, callback) - }, - { - if (!res.isAnime) invokeMoviezAdd( - moviezAddAPI, - "MoviezAdd", - res.title, - res.year, - res.season, - res.episode, - callback - ) - }, - { - if (!res.isAnime && res.isBollywood) invokeBollyMaza( - bollyMazaAPI, - "BollyMaza", - res.title, - res.year, - res.season, - res.episode, - callback - ) - }, - { - if (!res.isAnime) invokeRStream(res.id, res.season, res.episode, callback) - }, - { - if (!res.isAnime) invokeFlixon( - res.id, - res.imdbId, - res.season, - res.episode, - callback - ) - }, - { - if (!res.isAnime) invokeSmashyStream( - res.imdbId, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeWatchsomuch( - res.imdbId, - res.season, - res.episode, - subtitleCallback - ) - }, - { - if (!res.isAnime) invokeNinetv( - res.id, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - invokeDahmerMovies( - res.title, - res.year, - res.season, - res.episode, - callback - ) - }, - { - invokeCinemaTv( - res.imdbId, - res.title, - res.airedYear ?: res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeNowTv(res.id, res.imdbId, res.season, res.episode, callback) - }, - { - if (!res.isAnime && res.season == null) invokeRidomovies( - res.id, - res.imdbId, - callback - ) - }, - { - if (!res.isAnime) invokeAllMovieland(res.imdbId, res.season, res.episode, callback) - }, - { - if (!res.isAnime) invokeEmovies( - res.title, - res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeVegamovies( - res.title, - res.year, - res.season, - res.lastSeason, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime && res.isBollywood) invokeDotmovies( - res.title, - res.year, - res.season, - res.lastSeason, - res.episode, - subtitleCallback, - callback - ) - }, - { - if(res.isBollywood) invokeMultimovies(multimoviesAPI, res.title, res.season, res.episode, subtitleCallback, callback) - }, - { - if(res.isBollywood) invokeMultimovies(multimovies2API, res.title, res.season, res.episode, subtitleCallback, callback) - }, - { - invokeNetmovies( - res.title, - res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime && res.season == null) invokeDoomovies( - res.title, - subtitleCallback, - callback - ) - }, - { - if (res.isAsian) invokeDramaday( - res.title, - res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invoke2embed(res.imdbId, res.season, res.episode, subtitleCallback, callback) - }, - { - if (!res.isAnime) invokeHdmovies4u( - res.title, - res.imdbId, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - invokeZshow( - res.title, - res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeShowflix( - res.title, - res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeSFMovies( - res.id, - res.title, - res.airedYear ?: res.year, - res.season, - res.episode, - callback - ) - } + { + if (!res.isAnime) invokeFilmxy(res.imdbId, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime && res.isCartoon) invokeKimcartoon(res.title, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime && res.isCartoon) invokeWatchCartoon(res.title, res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeVidsrcto(res.imdbId, res.season, res.episode, subtitleCallback, callback) + }, + { + if (res.isAsian || res.isAnime) invokeKisskh(res.title, res.season, res.episode, res.isAnime, res.lastSeason, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeOmovies(res.title, res.year, res.season, res.episode, callback) + }, + { + if (!res.isAnime) invokeLing(res.title, res.airedYear + ?: res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeUhdmovies(res.title, res.year, res.season, res.episode, 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, callback) + }, + { + if (!res.isAnime) invokeM4uhd(res.title, res.airedYear + ?: res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeTvMovies(res.title, res.season, res.episode, callback) + }, + { + if (!res.isAnime) invokeMoviezAdd(moviezAddAPI, "MoviezAdd", res.title, res.year, res.season, res.episode, callback) + }, + { + if (!res.isAnime && res.isBollywood) invokeBollyMaza(bollyMazaAPI, "BollyMaza", res.title, res.year, res.season, res.episode, callback) + }, + { + if (!res.isAnime) invokeRStream(res.id, res.season, res.episode, callback) + }, + { + if (!res.isAnime) invokeFlixon(res.id, res.imdbId, res.season, res.episode, callback) + }, + { + if (!res.isAnime) invokeSmashyStream(res.imdbId, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeWatchsomuch(res.imdbId, res.season, res.episode, subtitleCallback) + }, + { + if (!res.isAnime) invokeNinetv(res.id, res.season, res.episode, subtitleCallback, callback) + }, + { + invokeDahmerMovies(res.title, res.year, res.season, res.episode, callback) + }, + { + invokeCinemaTv(res.imdbId, res.title, res.airedYear + ?: res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeNowTv(res.id, res.imdbId, res.season, res.episode, callback) + }, + { + if (!res.isAnime && res.season == null) invokeRidomovies(res.id, res.imdbId, callback) + }, + { + if (!res.isAnime) invokeAllMovieland(res.imdbId, res.season, res.episode, callback) + }, + { + if (!res.isAnime) invokeEmovies(res.title, res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeVegamovies(res.title, res.year, res.season, res.lastSeason, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime && res.isBollywood) invokeDotmovies(res.title, res.year, res.season, res.lastSeason, res.episode, subtitleCallback, callback) + }, + { + if (res.isBollywood) invokeMultimovies(multimoviesAPI, res.title, res.season, res.episode, subtitleCallback, callback) + }, + { + if (res.isBollywood) invokeMultimovies(multimovies2API, res.title, res.season, res.episode, subtitleCallback, callback) + }, + { + invokeNetmovies(res.title, res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime && res.season == null) invokeDoomovies(res.title, subtitleCallback, callback) + }, + { + if (res.isAsian) invokeDramaday(res.title, res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invoke2embed(res.imdbId, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeHdmovies4u(res.title, res.imdbId, res.season, res.episode, subtitleCallback, callback) + }, + { + invokeZshow(res.title, res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeShowflix(res.title, res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeSFMovies(res.id, res.title, res.airedYear + ?: res.year, res.season, res.episode, callback) + }, + { + invokeMMovies(res.title, res.season, res.episode, subtitleCallback, callback) + }, ) return true } data class LinkData( - val id: Int? = null, - val imdbId: String? = null, - val tvdbId: Int? = null, - val type: String? = null, - val season: Int? = null, - val episode: Int? = null, - val aniId: String? = null, - val animeId: String? = null, - val title: String? = null, - val year: Int? = null, - val orgTitle: String? = null, - val isAnime: Boolean = false, - val airedYear: Int? = null, - val lastSeason: Int? = null, - val epsTitle: String? = null, - val jpTitle: String? = null, - val date: String? = null, - val airedDate: String? = null, - val isAsian: Boolean = false, - val isBollywood: Boolean = false, - val isCartoon: Boolean = false, + val id: Int? = null, + val imdbId: String? = null, + val tvdbId: Int? = null, + val type: String? = null, + val season: Int? = null, + val episode: Int? = null, + val aniId: String? = null, + val animeId: String? = null, + val title: String? = null, + val year: Int? = null, + val orgTitle: String? = null, + val isAnime: Boolean = false, + val airedYear: Int? = null, + val lastSeason: Int? = null, + val epsTitle: String? = null, + val jpTitle: String? = null, + val date: String? = null, + val airedDate: String? = null, + val isAsian: Boolean = false, + val isBollywood: Boolean = false, + val isCartoon: Boolean = false, ) data class Data( - val id: Int? = null, - val type: String? = null, - val aniId: String? = null, - val malId: Int? = null, + val id: Int? = null, + val type: String? = null, + val aniId: String? = null, + val malId: Int? = null, ) data class Results( - @JsonProperty("results") val results: ArrayList? = arrayListOf(), + @JsonProperty("results") val results: ArrayList? = arrayListOf(), ) data class Media( - @JsonProperty("id") val id: Int? = null, - @JsonProperty("name") val name: String? = null, - @JsonProperty("title") val title: String? = null, - @JsonProperty("original_title") val originalTitle: String? = null, - @JsonProperty("media_type") val mediaType: String? = null, - @JsonProperty("poster_path") val posterPath: String? = null, + @JsonProperty("id") val id: Int? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("title") val title: String? = null, + @JsonProperty("original_title") val originalTitle: String? = null, + @JsonProperty("media_type") val mediaType: String? = null, + @JsonProperty("poster_path") val posterPath: String? = null, ) data class Genres( - @JsonProperty("id") val id: Int? = null, - @JsonProperty("name") val name: String? = null, + @JsonProperty("id") val id: Int? = null, + @JsonProperty("name") val name: String? = null, ) data class Keywords( - @JsonProperty("id") val id: Int? = null, - @JsonProperty("name") val name: String? = null, + @JsonProperty("id") val id: Int? = null, + @JsonProperty("name") val name: String? = null, ) data class KeywordResults( - @JsonProperty("results") val results: ArrayList? = arrayListOf(), - @JsonProperty("keywords") val keywords: ArrayList? = arrayListOf(), + @JsonProperty("results") val results: ArrayList? = arrayListOf(), + @JsonProperty("keywords") val keywords: ArrayList? = arrayListOf(), ) data class Seasons( - @JsonProperty("id") val id: Int? = null, - @JsonProperty("name") val name: String? = null, - @JsonProperty("season_number") val seasonNumber: Int? = null, - @JsonProperty("air_date") val airDate: String? = null, + @JsonProperty("id") val id: Int? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("season_number") val seasonNumber: Int? = null, + @JsonProperty("air_date") val airDate: String? = null, ) data class Cast( - @JsonProperty("id") val id: Int? = null, - @JsonProperty("name") val name: String? = null, - @JsonProperty("original_name") val originalName: String? = null, - @JsonProperty("character") val character: String? = null, - @JsonProperty("known_for_department") val knownForDepartment: String? = null, - @JsonProperty("profile_path") val profilePath: String? = null, + @JsonProperty("id") val id: Int? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("original_name") val originalName: String? = null, + @JsonProperty("character") val character: String? = null, + @JsonProperty("known_for_department") val knownForDepartment: String? = null, + @JsonProperty("profile_path") val profilePath: String? = null, ) data class Episodes( - @JsonProperty("id") val id: Int? = null, - @JsonProperty("name") val name: String? = null, - @JsonProperty("overview") val overview: String? = null, - @JsonProperty("air_date") val airDate: String? = null, - @JsonProperty("still_path") val stillPath: String? = null, - @JsonProperty("vote_average") val voteAverage: Double? = null, - @JsonProperty("episode_number") val episodeNumber: Int? = null, - @JsonProperty("season_number") val seasonNumber: Int? = null, + @JsonProperty("id") val id: Int? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("overview") val overview: String? = null, + @JsonProperty("air_date") val airDate: String? = null, + @JsonProperty("still_path") val stillPath: String? = null, + @JsonProperty("vote_average") val voteAverage: Double? = null, + @JsonProperty("episode_number") val episodeNumber: Int? = null, + @JsonProperty("season_number") val seasonNumber: Int? = null, ) data class MediaDetailEpisodes( - @JsonProperty("episodes") val episodes: ArrayList? = arrayListOf(), + @JsonProperty("episodes") val episodes: ArrayList? = arrayListOf(), ) data class Trailers( - @JsonProperty("key") val key: String? = null, + @JsonProperty("key") val key: String? = null, ) data class ResultsTrailer( - @JsonProperty("results") val results: ArrayList? = arrayListOf(), + @JsonProperty("results") val results: ArrayList? = arrayListOf(), ) data class AltTitles( - @JsonProperty("iso_3166_1") val iso_3166_1: String? = null, - @JsonProperty("title") val title: String? = null, - @JsonProperty("type") val type: String? = null, + @JsonProperty("iso_3166_1") val iso_3166_1: String? = null, + @JsonProperty("title") val title: String? = null, + @JsonProperty("type") val type: String? = null, ) data class ResultsAltTitles( - @JsonProperty("results") val results: ArrayList? = arrayListOf(), + @JsonProperty("results") val results: ArrayList? = arrayListOf(), ) data class ExternalIds( - @JsonProperty("imdb_id") val imdb_id: String? = null, - @JsonProperty("tvdb_id") val tvdb_id: Int? = null, + @JsonProperty("imdb_id") val imdb_id: String? = null, + @JsonProperty("tvdb_id") val tvdb_id: Int? = null, ) data class Credits( - @JsonProperty("cast") val cast: ArrayList? = arrayListOf(), + @JsonProperty("cast") val cast: ArrayList? = arrayListOf(), ) data class ResultsRecommendations( - @JsonProperty("results") val results: ArrayList? = arrayListOf(), + @JsonProperty("results") val results: ArrayList? = arrayListOf(), ) data class LastEpisodeToAir( - @JsonProperty("episode_number") val episode_number: Int? = null, - @JsonProperty("season_number") val season_number: Int? = null, + @JsonProperty("episode_number") val episode_number: Int? = null, + @JsonProperty("season_number") val season_number: Int? = null, ) data class ProductionCountries( - @JsonProperty("name") val name: String? = null, + @JsonProperty("name") val name: String? = null, ) data class MediaDetail( - @JsonProperty("id") val id: Int? = null, - @JsonProperty("imdb_id") val imdbId: String? = null, - @JsonProperty("title") val title: String? = null, - @JsonProperty("name") val name: String? = null, - @JsonProperty("original_title") val originalTitle: String? = null, - @JsonProperty("original_name") val originalName: String? = null, - @JsonProperty("poster_path") val posterPath: String? = null, - @JsonProperty("backdrop_path") val backdropPath: String? = null, - @JsonProperty("release_date") val releaseDate: String? = null, - @JsonProperty("first_air_date") val firstAirDate: String? = null, - @JsonProperty("overview") val overview: String? = null, - @JsonProperty("runtime") val runtime: Int? = null, - @JsonProperty("vote_average") val vote_average: Any? = null, - @JsonProperty("original_language") val original_language: String? = null, - @JsonProperty("status") val status: String? = null, - @JsonProperty("genres") val genres: ArrayList? = arrayListOf(), - @JsonProperty("keywords") val keywords: KeywordResults? = null, - @JsonProperty("last_episode_to_air") val last_episode_to_air: LastEpisodeToAir? = null, - @JsonProperty("seasons") val seasons: ArrayList? = arrayListOf(), - @JsonProperty("videos") val videos: ResultsTrailer? = null, - @JsonProperty("external_ids") val external_ids: ExternalIds? = null, - @JsonProperty("credits") val credits: Credits? = null, - @JsonProperty("recommendations") val recommendations: ResultsRecommendations? = null, - @JsonProperty("alternative_titles") val alternative_titles: ResultsAltTitles? = null, - @JsonProperty("production_countries") val production_countries: ArrayList? = arrayListOf(), + @JsonProperty("id") val id: Int? = null, + @JsonProperty("imdb_id") val imdbId: String? = null, + @JsonProperty("title") val title: String? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("original_title") val originalTitle: String? = null, + @JsonProperty("original_name") val originalName: String? = null, + @JsonProperty("poster_path") val posterPath: String? = null, + @JsonProperty("backdrop_path") val backdropPath: String? = null, + @JsonProperty("release_date") val releaseDate: String? = null, + @JsonProperty("first_air_date") val firstAirDate: String? = null, + @JsonProperty("overview") val overview: String? = null, + @JsonProperty("runtime") val runtime: Int? = null, + @JsonProperty("vote_average") val vote_average: Any? = null, + @JsonProperty("original_language") val original_language: String? = null, + @JsonProperty("status") val status: String? = null, + @JsonProperty("genres") val genres: ArrayList? = arrayListOf(), + @JsonProperty("keywords") val keywords: KeywordResults? = null, + @JsonProperty("last_episode_to_air") val last_episode_to_air: LastEpisodeToAir? = null, + @JsonProperty("seasons") val seasons: ArrayList? = arrayListOf(), + @JsonProperty("videos") val videos: ResultsTrailer? = null, + @JsonProperty("external_ids") val external_ids: ExternalIds? = null, + @JsonProperty("credits") val credits: Credits? = null, + @JsonProperty("recommendations") val recommendations: ResultsRecommendations? = null, + @JsonProperty("alternative_titles") val alternative_titles: ResultsAltTitles? = null, + @JsonProperty("production_countries") val production_countries: ArrayList? = arrayListOf(), ) } diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt index 3b9e975f..2ea87243 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStreamLite.kt @@ -29,7 +29,7 @@ import com.hexated.SoraExtractor.invokeShowflix import com.hexated.SoraExtractor.invokeVidSrc import com.hexated.SoraExtractor.invokeVidsrcto import com.hexated.SoraExtractor.invokeCinemaTv -import com.hexated.SoraExtractor.invokeFebbox +import com.hexated.SoraExtractor.invokeMMovies import com.hexated.SoraExtractor.invokeOmovies import com.hexated.SoraExtractor.invokeWatchCartoon import com.hexated.SoraExtractor.invokeWatchsomuch @@ -42,299 +42,121 @@ import com.lagradost.cloudstream3.utils.ExtractorLink class SoraStreamLite : SoraStream() { override var name = "SoraStream-Lite" - override suspend fun loadLinks( - data: String, - isCasting: Boolean, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ): Boolean { + override suspend fun loadLinks(data: String, isCasting: Boolean, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit): Boolean { val res = AppUtils.parseJson(data) argamap( -// { -// invokeFebbox( -// res.title, -// res.year, -// res.season, -// res.lastSeason, -// res.episode, -// callback -// ) -// }, - { - if (!res.isAnime) invokeWatchsomuch( - res.imdbId, - res.season, - res.episode, - subtitleCallback - ) - }, - { - invokeDumpStream( - res.title, - res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeNinetv( - res.id, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - invokeGoku( - res.title, - res.year, - res.season, - res.lastSeason, - res.episode, - subtitleCallback, - callback - ) - }, - { - invokeVidSrc(res.id, res.season, res.episode, callback) - }, - { - invokeDbgo(res.imdbId, res.season, res.episode, subtitleCallback, callback) - }, - { - if (!res.isAnime && res.isCartoon) invokeWatchCartoon( - res.title, - res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (res.isAnime) invokeAnimes( - res.title, - res.epsTitle, - res.date, - res.airedDate, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeDreamfilm( - res.title, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeFilmxy( - res.imdbId, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeOmovies( - res.title, - res.year, - res.season, - res.episode, - callback - ) - }, - { - if (!res.isAnime && res.isCartoon) invokeKimcartoon( - res.title, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeSmashyStream( - res.imdbId, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeVidsrcto( - res.imdbId, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (res.isAsian || res.isAnime) invokeKisskh( - res.title, - res.season, - res.episode, - res.isAnime, - res.lastSeason, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeLing( - res.title, - res.airedYear ?: res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if(!res.isAnime) invokeM4uhd( - res.title, - res.airedYear ?: res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeRStream(res.id, res.season, res.episode, callback) - }, - { - if (!res.isAnime) invokeFlixon(res.id, res.imdbId, res.season, res.episode, callback) - }, - { - invokeCinemaTv( - res.imdbId, - res.title, - res.airedYear ?: res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeNowTv(res.id, res.imdbId, res.season, res.episode, callback) - }, - { - if (!res.isAnime) invokeAoneroom( - res.title, - res.airedYear ?: res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime && res.season == null) invokeRidomovies( - res.id, - res.imdbId, - callback - ) - }, - { - if (!res.isAnime) invokeEmovies( - res.title, - res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if(res.isBollywood) invokeMultimovies(multimoviesAPI, res.title, res.season, res.episode, subtitleCallback, callback) - }, - { - if(res.isBollywood) invokeMultimovies(multimovies2API, res.title, res.season, res.episode, subtitleCallback, callback) - }, - { - invokeNetmovies( - res.title, - res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeAllMovieland(res.imdbId, res.season, res.episode, callback) - }, - { - if (!res.isAnime && res.season == null) invokeDoomovies( - res.title, - subtitleCallback, - callback - ) - }, - { - if(res.isAsian) invokeDramaday( - res.title, - res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if(!res.isAnime) invoke2embed( - res.imdbId, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - invokeZshow( - res.title, - res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if (!res.isAnime) invokeShowflix( - res.title, - res.year, - res.season, - res.episode, - subtitleCallback, - callback - ) - }, - { - if(!res.isAnime) invokeSFMovies( - res.id, - res.title, - res.airedYear ?: res.year, - res.season, - res.episode, - callback - ) - } + { + if (!res.isAnime) invokeWatchsomuch(res.imdbId, res.season, res.episode, subtitleCallback) + }, + { + invokeDumpStream(res.title, res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeNinetv(res.id, res.season, res.episode, subtitleCallback, callback) + }, + { + invokeGoku(res.title, res.year, res.season, res.lastSeason, res.episode, subtitleCallback, callback) + }, + { + invokeVidSrc(res.id, res.season, res.episode, callback) + }, + { + invokeDbgo(res.imdbId, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime && res.isCartoon) invokeWatchCartoon(res.title, res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (res.isAnime) invokeAnimes(res.title, res.epsTitle, res.date, res.airedDate, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeDreamfilm(res.title, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeFilmxy(res.imdbId, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeOmovies(res.title, res.year, res.season, res.episode, callback) + }, + { + if (!res.isAnime && res.isCartoon) invokeKimcartoon(res.title, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeSmashyStream(res.imdbId, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeVidsrcto(res.imdbId, res.season, res.episode, subtitleCallback, callback) + }, + { + if (res.isAsian || res.isAnime) invokeKisskh(res.title, res.season, res.episode, res.isAnime, res.lastSeason, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeLing(res.title, res.airedYear + ?: res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeM4uhd(res.title, res.airedYear + ?: res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeRStream(res.id, res.season, res.episode, callback) + }, + { + if (!res.isAnime) invokeFlixon(res.id, res.imdbId, res.season, res.episode, callback) + }, + { + invokeCinemaTv(res.imdbId, res.title, res.airedYear + ?: res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeNowTv(res.id, res.imdbId, res.season, res.episode, callback) + }, + { + if (!res.isAnime) invokeAoneroom(res.title, res.airedYear + ?: res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime && res.season == null) invokeRidomovies(res.id, res.imdbId, callback) + }, + { + if (!res.isAnime) invokeEmovies(res.title, res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (res.isBollywood) invokeMultimovies(multimoviesAPI, res.title, res.season, res.episode, subtitleCallback, callback) + }, + { + if (res.isBollywood) invokeMultimovies(multimovies2API, res.title, res.season, res.episode, subtitleCallback, callback) + }, + { + invokeNetmovies(res.title, res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeAllMovieland(res.imdbId, res.season, res.episode, callback) + }, + { + if (!res.isAnime && res.season == null) invokeDoomovies(res.title, subtitleCallback, callback) + }, + { + if (res.isAsian) invokeDramaday(res.title, res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invoke2embed(res.imdbId, res.season, res.episode, subtitleCallback, callback) + }, + { + invokeZshow(res.title, res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeShowflix(res.title, res.year, res.season, res.episode, subtitleCallback, callback) + }, + { + if (!res.isAnime) invokeSFMovies(res.id, res.title, res.airedYear + ?: res.year, res.season, res.episode, callback) + }, + { + invokeMMovies(res.title, res.season, res.episode, subtitleCallback, callback) + }, ) return true