diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt index c3341e1b..134d2777 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt @@ -1,5 +1,6 @@ package com.hexated +import android.util.Log import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.metaproviders.TmdbProvider @@ -7,6 +8,7 @@ import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.toJson import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.Qualities +import com.lagradost.cloudstream3.utils.loadExtractor import kotlin.math.roundToInt class SoraStream : TmdbProvider() { @@ -27,6 +29,7 @@ class SoraStream : TmdbProvider() { private const val apiKey = "b030404650f279792a8d3287232358e3" // PLEASE DON'T STEAL private var mainAPI = base64Decode("aHR0cHM6Ly94cHdhdGNoLnZlcmNlbC5hcHA=") private var mainServerAPI = base64Decode("aHR0cHM6Ly9zb3JhLW1vdmllLnZlcmNlbC5hcHA=") + private const val twoEmbedAPI = "https://www.2embed.to" fun getType(t: String?): TvType { return when (t) { @@ -180,6 +183,40 @@ class SoraStream : TmdbProvider() { } } + private 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 -> + Log.i("hexated", "${source.link}") + loadExtractor( + source.link ?: return@let null, + twoEmbedAPI, + subtitleCallback, + callback + ) + } + } + } + override suspend fun loadLinks( data: String, isCasting: Boolean, @@ -204,27 +241,31 @@ class SoraStream : TmdbProvider() { referer = referer ).parsedSafe() - json?.sources?.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) + if (json?.sources.isNullOrEmpty()) { + invokeTwoEmbed(res.id, res.season, res.episode, subtitleCallback, callback) + } else { + json?.sources?.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) + ) ) - ) - } + } - json?.subtitles?.map { sub -> - subtitleCallback.invoke( - SubtitleFile( - sub.lang.toString(), - sub.url ?: return@map null + json?.subtitles?.map { sub -> + subtitleCallback.invoke( + SubtitleFile( + sub.lang.toString(), + sub.url ?: return@map null + ) ) - ) + } } return true @@ -335,4 +376,11 @@ class SoraStream : TmdbProvider() { @JsonProperty("pageProps") val pageProps: PageProps? = null, ) + data class EmbedJson( + @JsonProperty("type") val type: String? = null, + @JsonProperty("link") val link: String? = null, + @JsonProperty("sources") val sources: List = arrayListOf(), + @JsonProperty("tracks") val tracks: List? = null, + ) + }