package com.hexated import com.fasterxml.jackson.annotation.JsonProperty import com.hexated.SoraStream.Companion.filmxyAPI import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.network.WebViewResolver import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.nicehttp.Requests import com.lagradost.nicehttp.Session import com.lagradost.nicehttp.requestCreator import okhttp3.HttpUrl.Companion.toHttpUrl import com.google.gson.JsonParser import kotlinx.coroutines.delay import okhttp3.RequestBody.Companion.toRequestBody import java.net.URI val session = Session(Requests().baseClient) object SoraExtractor : SoraStream() { /* suspend fun invokeLocalSources( url: String, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { val doc = app.get( url, headers = mapOf("User-Agent" to RandomUserAgent.getRandomUserAgent()) ).document val script = doc.select("script").find { it.data().contains("\"sources\":[") }?.data() val sourcesData = script?.substringAfter("\"sources\":[")?.substringBefore("],") val subData = script?.substringAfter("\"subtitles\":[")?.substringBefore("],") tryParseJson>("[$sourcesData]")?.map { source -> callback.invoke( ExtractorLink( this.name, this.name, source.url ?: return@map null, "$mainServerAPI/", source.quality?.toIntOrNull() ?: Qualities.Unknown.value, isM3u8 = source.isM3U8, headers = mapOf("Origin" to mainServerAPI) ) ) } tryParseJson>("[$subData]")?.map { sub -> subtitleCallback.invoke( SubtitleFile( sub.lang.toString(), sub.url ?: return@map null ) ) } } */ suspend fun invokeTwoEmbed( id: Int? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { val url = if (season == null) { "$twoEmbedAPI/embed/tmdb/movie?id=$id" } else { "$twoEmbedAPI/embed/tmdb/tv?id=$id&s=$season&e=$episode" } val document = app.get(url).document val captchaKey = document.select("script[src*=https://www.google.com/recaptcha/api.js?render=]") .attr("src").substringAfter("render=") document.select(".dropdown-menu a[data-id]").map { it.attr("data-id") }.apmap { serverID -> val token = APIHolder.getCaptchaToken(url, captchaKey) app.get( "$twoEmbedAPI/ajax/embed/play?id=$serverID&_token=$token", referer = url ).parsedSafe()?.let { source -> val link = source.link ?: return@let if (link.contains("rabbitstream")) { val rabbitId = link.substringAfterLast("/").substringBefore("?") app.get( "https://rabbitstream.net/ajax/embed-5/getSources?id=$rabbitId", headers = mapOf("X-Requested-With" to "XMLHttpRequest") ).parsedSafe()?.tracks?.map { sub -> subtitleCallback.invoke( SubtitleFile( sub.label.toString(), sub.file ?: return@map null ) ) } } else { loadExtractor( link, twoEmbedAPI, subtitleCallback, callback ) } } } } suspend fun invokeVidSrc( id: Int? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { val url = if (season == null) { "$vidSrcAPI/embed/$id" } else { "$vidSrcAPI/embed/$id/${season}-${episode}" } loadExtractor(url, null, subtitleCallback) { link -> callback.invoke( ExtractorLink( link.name, link.name, link.url, link.referer, if (link.name == "VidSrc") Qualities.P1080.value else link.quality, link.isM3u8, link.headers, link.extractorData ) ) } } suspend fun invokeOlgply( id: Int? = null, season: Int? = null, episode: Int? = null, callback: (ExtractorLink) -> Unit ) { val url = "$olgplyAPI/${id}${season?.let { "/$it" } ?: ""}${episode?.let { "/$it" } ?: ""}" loadLinksWithWebView(url, callback) } 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() } 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 source = Regex("['|\"]file['|\"]:\\s['|\"](#\\S+?)['|\"]").find(script.toString())?.groupValues?.get( 1 ) ?: return val subtitle = Regex("['|\"]subtitle['|\"]:\\s['|\"](\\S+?)['|\"]").find(script.toString())?.groupValues?.get( 1 ) val ref = getBaseUrl(iframeDbgo) decryptStreamUrl(source).split(",").map { links -> val quality = Regex("\\[([0-9]*p.*?)]").find(links)?.groupValues?.getOrNull(1).toString().trim() 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 ) ) ) } } subtitle?.split(",")?.map { sub -> val language = Regex("\\[(.*)]").find(sub)?.groupValues?.getOrNull(1) .toString() val link = sub.replace("[$language]", "").trim() subtitleCallback.invoke( SubtitleFile( language, link ) ) } } suspend fun invoke123Movie( tmdbId: Int? = null, imdbId: String? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { val url = if (season == null) { "$movie123API/imdb.php?imdb=$imdbId&server=vcu" } else { "$movie123API/tmdb_api.php?se=$season&ep=$episode&tmdb=$tmdbId&server_name=vcu" } val iframe = app.get(url).document.selectFirst("iframe")?.attr("src") ?: return val doc = app.get( iframe, referer = url, headers = mapOf("Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8") ).document doc.select("ul.list-server-items li.linkserver").mapNotNull { server -> server.attr("data-video").let { Regex("(.*?)((\\?cap)|(\\?sub)|(#cap)|(#sub))").find(it)?.groupValues?.get(1) } }.apmap { link -> loadExtractor( link, "https://123moviesjr.cc/", subtitleCallback, callback ) } } suspend fun invokeMovieHab( imdbId: String? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { val url = if (season == null) { "$movieHabAPI/embed/movie?imdb=$imdbId" } else { "$movieHabAPI/embed/series?imdb=$imdbId&sea=$season&epi=$episode" } val doc = app.get(url, referer = "$movieHabAPI/").document val movieId = doc.selectFirst("div#embed-player")?.attr("data-movie-id") ?: return doc.select("div.dropdown-menu a").apmap { val dataId = it.attr("data-id") app.get( "$movieHabAPI/ajax/get_stream_link?id=$dataId&movie=$movieId&is_init=true&captcha=&ref=", referer = url, headers = mapOf("X-Requested-With" to "XMLHttpRequest") ).parsedSafe()?.data?.let { res -> loadExtractor( res.link ?: return@let null, movieHabAPI, subtitleCallback, callback ) } } } suspend fun invokeDatabaseGdrive( imdbId: String? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { val url = if (season == null) { "$databaseGdriveAPI/player.php?imdb=$imdbId" } else { "$databaseGdriveAPI/player.php?type=series&imdb=$imdbId&season=$season&episode=$episode" } loadExtractor(url, databaseGdriveAPI, subtitleCallback, callback) } /* suspend fun invokeSoraVIP( title: String? = null, orgTitle: String? = null, year: Int? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { val apiUrl = base64DecodeAPI("aQ==YXA=cC8=YXA=bC4=Y2U=ZXI=LnY=b2s=a2w=bG8=Ly8=czo=dHA=aHQ=") val url = if(season == null) { "$apiUrl/search/one?title=$title&orgTitle=$orgTitle&year=$year" } else { "$apiUrl/search/one?title=$title&orgTitle=$orgTitle&year=$year&season=$season" } val id = app.get(url).parsedSafe()?.data?.id val sourcesUrl = if(season == null) { "$apiUrl/movie/detail?id=$id" } else { "$apiUrl/tv/detail?id=$id&episodeId=${episode?.minus(1)}" } val json = app.get(sourcesUrl).parsedSafe() json?.sources?.map { source -> callback.invoke( ExtractorLink( "${this.name} (VIP)", "${this.name} (VIP)", source.url ?: return@map null, "$apiUrl/", source.quality ?: Qualities.Unknown.value, isM3u8 = source.url.contains(".m3u8"), ) ) } json?.subtitles?.map { sub -> subtitleCallback.invoke( SubtitleFile( getLanguage(sub.language.toString()), sub.url ?: return@map null ) ) } } */ suspend fun invokeHDMovieBox( title: String? = null, season: Int? = null, episode: Int? = null, callback: (ExtractorLink) -> Unit ) { val fixTitle = title.fixTitle() val url = "$hdMovieBoxAPI/watch/$fixTitle" // val ref = if (season == null) { // "$hdMovieBoxAPI/watch/$fixTitle" // } else { // "$hdMovieBoxAPI/watch/$fixTitle/season-$season/episode-$episode" // } val doc = app.get(url).document val id = if (season == null) { doc.selectFirst("div.player div#not-loaded")?.attr("data-whatwehave") } else { doc.select("div.season-list-column div[data-season=$season] div.list div.item")[episode?.minus( 1 ) ?: 0].selectFirst("div.ui.checkbox")?.attr("data-episode") } val iframeUrl = app.post( "$hdMovieBoxAPI/ajax/service", data = mapOf( "e_id" to "$id", "v_lang" to "en", "type" to "get_whatwehave", ), headers = mapOf("X-Requested-With" to "XMLHttpRequest") ).parsedSafe()?.apiIframe ?: return delay(1000) val iframe = app.get(iframeUrl, referer = "$hdMovieBoxAPI/").document.selectFirst("iframe") ?.attr("src") val script = app.get( iframe ?: return, referer = "$hdMovieBoxAPI/" ).document.selectFirst("script:containsData(var vhash =)")?.data() ?.substringAfter("vhash, {")?.substringBefore("}, false") tryParseJson("{$script}").let { source -> val disk = if (source?.videoDisk == null) { "" } else { base64Encode(source.videoDisk.toString().toByteArray()) } val link = getBaseUrl(iframe) + source?.videoUrl?.replace( "\\", "" ) + "?s=${source?.videoServer}&d=$disk" callback.invoke( ExtractorLink( "HDMovieBox", "HDMovieBox", link, iframe, Qualities.P1080.value, isM3u8 = true, ) ) } } suspend fun invokeSeries9( title: String? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { val fixTitle = title.fixTitle() val url = if (season == null) { "$series9API/film/$fixTitle/watching.html" } else { "$series9API/film/$fixTitle-season-$season/watching.html" } val request = app.get(url) if (!request.isSuccessful) return val res = request.document val sources: ArrayList = arrayListOf() if (season == null) { val xstreamcdn = res.selectFirst("div#list-eps div#server-29 a")?.attr("player-data")?.let { Regex("(.*?)((\\?cap)|(\\?sub)|(#cap)|(#sub))").find(it)?.groupValues?.get(1) } val streamsb = res.selectFirst("div#list-eps div#server-13 a")?.attr("player-data") val doodstream = res.selectFirst("div#list-eps div#server-14 a")?.attr("player-data") sources.addAll(listOf(xstreamcdn, streamsb, doodstream)) } else { val xstreamcdn = res.selectFirst("div#list-eps div#server-29 a[episode-data=$episode]") ?.attr("player-data")?.let { Regex("(.*?)((\\?cap)|(\\?sub)|(#cap)|(#sub))").find(it)?.groupValues?.get(1) } val streamsb = res.selectFirst("div#list-eps div#server-13 a[episode-data=$episode]") ?.attr("player-data") val doodstream = res.selectFirst("div#list-eps div#server-14 a[episode-data=$episode]") ?.attr("player-data") sources.addAll(listOf(xstreamcdn, streamsb, doodstream)) } sources.apmap { link -> loadExtractor(link ?: return@apmap null, url, subtitleCallback, callback) } } suspend fun invokeIdlix( title: String? = null, year: Int? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { val fixTitle = title.fixTitle() val url = if (season == null) { "$idlixAPI/movie/$fixTitle-$year" } else { "$idlixAPI/episode/$fixTitle-season-$season-episode-$episode" } val res = app.get(url) if (!res.isSuccessful) return val document = res.document val id = document.select("meta#dooplay-ajax-counter").attr("data-postid") val type = if (url.contains("/movie/")) "movie" else "tv" document.select("ul#playeroptionsul > li").map { it.attr("data-nume") }.apmap { nume -> val source = app.post( url = "$idlixAPI/wp-admin/admin-ajax.php", data = mapOf( "action" to "doo_player_ajax", "post" to id, "nume" to nume, "type" to type ), headers = mapOf("X-Requested-With" to "XMLHttpRequest"), referer = url ).parsed().embed_url if (!source.contains("youtube")) { loadExtractor(source, "$idlixAPI/", subtitleCallback, callback) } } } suspend fun invokeUniqueStream( title: String? = null, year: Int? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { val fixTitle = title.fixTitle() val url = if (season == null) { "$uniqueStreamAPI/movies/$fixTitle-$year" } else { "$uniqueStreamAPI/episodes/$fixTitle-season-$season-episode-$episode" } val res = app.get(url) if (!res.isSuccessful) return val document = res.document val type = if (url.contains("/movies/")) "movie" else "tv" document.select("ul#playeroptionsul > li").apmap { el -> val id = el.attr("data-post") val nume = el.attr("data-nume") val source = app.post( url = "$uniqueStreamAPI/wp-admin/admin-ajax.php", data = mapOf( "action" to "doo_player_ajax", "post" to id, "nume" to nume, "type" to type ), headers = mapOf("X-Requested-With" to "XMLHttpRequest"), referer = url ).parsed().embed_url.let { fixUrl(it) } when { source.contains("uniquestream") -> { val resDoc = app.get( source, referer = "$uniqueStreamAPI/", headers = mapOf( "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8" ) ).document val srcm3u8 = resDoc.selectFirst("script:containsData(let url =)")?.data()?.let { Regex("['|\"](.*?.m3u8)['|\"]").find(it)?.groupValues?.getOrNull(1) } ?: return@apmap null val quality = app.get( srcm3u8, referer = source, headers = mapOf( "Accept" to "*/*", ) ).text.let { quality -> if (quality.contains("RESOLUTION=1920")) Qualities.P1080.value else Qualities.P720.value } callback.invoke( ExtractorLink( "UniqueStream", "UniqueStream", srcm3u8, source, quality, true, headers = mapOf( "Accept" to "*/*", ) ) ) } !source.contains("youtube") -> loadExtractor(source, "$uniqueStreamAPI/", subtitleCallback, callback) else -> { // pass } } } } suspend fun invokeNoverse( title: String? = null, season: Int? = null, episode: Int? = null, callback: (ExtractorLink) -> Unit ) { val fixTitle = title.fixTitle() val url = if (season == null) { "$noverseAPI/movie/$fixTitle/download/" } else { "$noverseAPI/serie/$fixTitle/season-$season" } val doc = app.get(url).document val links = if (season == null) { doc.select("table.table-striped tbody tr").map { 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() } } ?: return delay(4000) links.map { (link, quality) -> val name = quality?.replace(Regex("[0-9]{3,4}p"), "Noverse")?.replace(".", " ") ?: "Noverse" callback.invoke( ExtractorLink( name, 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 ) { val url = if (season == null) { "${filmxyAPI}/movie/$imdbId" } else { "${filmxyAPI}/tv/$imdbId" } val filmxyCookies = getFilmxyCookies(imdbId, season) ?: throw ErrorLoadingException("No Cookies Found") val cookiesDoc = mapOf( "G_ENABLED_IDPS" to "google", "wordpress_logged_in_8bf9d5433ac88cc9a3a396d6b154cd01" to "${filmxyCookies.wLog}", "PHPSESSID" to "${filmxyCookies.phpsessid}" ) val request = session.get(url, cookies = cookiesDoc) if (!request.isSuccessful) return val doc = request.document val script = doc.selectFirst("script:containsData(var isSingle)")?.data().toString() val sourcesData = Regex("listSE\\s*=\\s?(.*?),[\\n|\\s]").find(script)?.groupValues?.get(1) val sourcesDetail = Regex("linkDetails\\s*=\\s?(.*?),[\\n|\\s]").find(script)?.groupValues?.get(1) //Gson is shit, but i don't care val sourcesJson = JsonParser().parse(sourcesData).asJsonObject val sourcesDetailJson = JsonParser().parse(sourcesDetail).asJsonObject val sources = if (season == null && episode == null) { sourcesJson.getAsJsonObject("movie").getAsJsonArray("movie") } else { val eps = if (episode!! < 10) "0$episode" else episode val sson = if (season!! < 10) "0$season" else season sourcesJson.getAsJsonObject("s$sson").getAsJsonArray("e$eps") }.asJsonArray val scriptUser = doc.select("script").find { it.data().contains("var userNonce") }?.data().toString() val userNonce = Regex("var\\suserNonce.*?[\"|'](\\S+?)[\"|'];").find(scriptUser)?.groupValues?.get(1) val userId = Regex("var\\suser_id.*?[\"|'](\\S+?)[\"|'];").find(scriptUser)?.groupValues?.get(1) val linkIDs = sources.joinToString("") { "&linkIDs%5B%5D=$it" }.replace("\"", "") val body = "action=get_vid_links$linkIDs&user_id=$userId&nonce=$userNonce".toRequestBody() val cookiesJson = mapOf( "G_ENABLED_IDPS" to "google", "PHPSESSID" to "${filmxyCookies.phpsessid}", "wordpress_logged_in_8bf9d5433ac88cc9a3a396d6b154cd01" to "${filmxyCookies.wLog}", "wordpress_sec_8bf9d5433ac88cc9a3a396d6b154cd01" to "${filmxyCookies.wSec}" ) val json = app.post( "$filmxyAPI/wp-admin/admin-ajax.php", requestBody = body, 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 = cookiesJson ).text.let { JsonParser().parse(it).asJsonObject } sources.map { source -> val src = source.asString val link = json.getAsJsonPrimitive(src).asString val quality = sourcesDetailJson.getAsJsonObject(src).getAsJsonPrimitive("resolution").asString val server = sourcesDetailJson.getAsJsonObject(src).getAsJsonPrimitive("server").asString val size = sourcesDetailJson.getAsJsonObject(src).getAsJsonPrimitive("size").asString callback.invoke( ExtractorLink( "Filmxy $size ($server)", "Filmxy $size ($server)", link, "$filmxyAPI/", getQualityFromName(quality) ) ) } } suspend fun invokeKimcartoon( title: String? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { val fixTitle = title.fixTitle() val url = if (season == null) { "$kimcartoonAPI/Cartoon/$fixTitle" } else { "$kimcartoonAPI/Cartoon/$fixTitle-season-$season" } val doc = app.get(url).document val iframe = if (season == null) { doc.select("table.listing tr td a").firstNotNullOf { it.attr("href") } } else { doc.select("table.listing tr td a").map { it.attr("href") }.first { it.contains("Season-$season", true) && it.contains("Episode-$episode", true) } } ?: return val source = app.get(fixUrl(iframe, kimcartoonAPI)).document.select("div#divContentVideo iframe") .attr("src") loadExtractor(source, "$kimcartoonAPI/", subtitleCallback) { link -> callback.invoke( ExtractorLink( "Luxubu", "Luxubu", link.url, link.referer, link.quality, link.isM3u8, link.headers, link.extractorData ) ) } } suspend fun invokeSoraVIP( title: String? = null, year: Int? = null, season: Int? = null, episode: Int? = null, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { val headers = mapOf( "lang" to "en", "versioncode" to "11", "clienttype" to "ios_jike_default" ) val vipAPI = base64DecodeAPI("cA==YXA=cy8=Y20=di8=LnQ=b2s=a2w=bG8=aS4=YXA=ZS0=aWw=b2I=LW0=Z2E=Ly8=czo=dHA=aHQ=") val vipUrl = base64DecodeAPI("b20=LmM=b2s=a2w=bG8=Ly8=czo=dHA=aHQ=") val doc = app.get( "$vipUrl/search?keyword=$title", ).document val scriptData = doc.select("div.search-list div.search-video-card").map { Triple( it.selectFirst("h2.title")?.text().toString(), it.selectFirst("div.desc")?.text() ?.substringBefore(".")?.toIntOrNull(), it.selectFirst("a")?.attr("href")?.split("/") ) } val script = if (scriptData.size == 1) { scriptData.first() } else { scriptData.first { if (season == null) { it.first.equals( title, true ) && it.second == year } else { it.first.contains( "$title", true ) && (it.second == year || it.first.contains("Season $season", true)) } } } val id = script.third?.last() val type = script.third?.get(2) val jsonResponse = app.get( "$vipAPI/movieDrama/get?id=${id}&category=${type}", headers = headers ) if (!jsonResponse.isSuccessful) return val json = jsonResponse.parsedSafe()?.data?.episodeVo?.first { it.seriesNo == (episode ?: 0) } json?.definitionList?.apmap { video -> delay(1000) app.get( "${vipAPI}/media/previewInfo?category=${type}&contentId=${id}&episodeId=${json.id}&definition=${video.code}", headers = headers ).parsedSafe