From 5f37e5be53fe94119593a2888ad2bb88f7c53730 Mon Sep 17 00:00:00 2001 From: hexated Date: Thu, 27 Oct 2022 15:46:19 +0700 Subject: [PATCH] added new sources into SoraExtractor --- SoraStream/build.gradle.kts | 2 +- .../main/kotlin/com/hexated/SoraExtractor.kt | 134 +++++++++++++++++- .../src/main/kotlin/com/hexated/SoraStream.kt | 37 ++++- 3 files changed, 162 insertions(+), 11 deletions(-) diff --git a/SoraStream/build.gradle.kts b/SoraStream/build.gradle.kts index 6bb83f94..5acb1295 100644 --- a/SoraStream/build.gradle.kts +++ b/SoraStream/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 11 +version = 12 cloudstream { diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt index 30eed340..03bfc652 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt @@ -1,11 +1,12 @@ package com.hexated +import com.fasterxml.jackson.annotation.JsonProperty 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.requestCreator import java.net.URI -import java.util.ArrayList object SoraExtractor : SoraStream() { @@ -22,7 +23,7 @@ object SoraExtractor : SoraStream() { val sourcesData = script?.substringAfter("\"sources\":[")?.substringBefore("],") val subData = script?.substringAfter("\"subtitles\":[")?.substringBefore("],") - AppUtils.tryParseJson>("[$sourcesData]")?.map { source -> + tryParseJson>("[$sourcesData]")?.map { source -> callback.invoke( ExtractorLink( this.name, @@ -36,7 +37,7 @@ object SoraExtractor : SoraStream() { ) } - AppUtils.tryParseJson>("[$subData]")?.map { sub -> + tryParseJson>("[$subData]")?.map { sub -> subtitleCallback.invoke( SubtitleFile( sub.lang.toString(), @@ -261,6 +262,21 @@ object SoraExtractor : SoraStream() { } } + 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( id: Int? = null, season: Int? = null, @@ -350,8 +366,110 @@ object SoraExtractor : SoraStream() { } + suspend fun invokeHDMovieBox( + title: String? = null, + season: Int? = null, + episode: Int? = null, + callback: (ExtractorLink) -> Unit + ) { + val fixTitle = title?.replace(":", "")?.replace(" ", "-")?.lowercase() + 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 + + 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 link = getBaseUrl(iframe) + source?.videoUrl?.replace( + "\\", + "" + ) + "?s=${source?.videoServer}&d=${base64Encode(source?.videoDisk?.toByteArray() ?: return)}" + 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?.replace(":", "")?.replace(" ", "-")?.lowercase() + val url = if (season == null) { + "$series9API/film/$fixTitle/watching.html" + } else { + "$series9API/film/$fixTitle-season-$season/watching.html" + } + + val res = app.get(url).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) + } + + } + } +//private fun getHdMovieBoxUrl(link: String?): String? { +// if (link == null) return null +// return if (link.startsWith("/")) "https://image.tmdb.org/t/p/w500/$link" else link +//} + private fun getQuality(str: String): Int { return when (str) { "360p" -> Qualities.P240.value @@ -424,3 +542,13 @@ suspend fun loadLinksWithWebView( ) } +data class HdMovieBoxSource( + @JsonProperty("videoUrl") val videoUrl: String? = null, + @JsonProperty("videoServer") val videoServer: String? = null, + @JsonProperty("videoDisk") val videoDisk: String? = null, +) + +data class HdMovieBoxIframe( + @JsonProperty("api_iframe") val apiIframe: String? = null, +) + diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt index ac304cf5..dc5bde33 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt @@ -3,11 +3,14 @@ package com.hexated import com.fasterxml.jackson.annotation.JsonProperty import com.hexated.RandomUserAgent.getRandomUserAgent import com.hexated.SoraExtractor.invoke123Movie +import com.hexated.SoraExtractor.invokeDatabaseGdrive import com.hexated.SoraExtractor.invokeDbgo import com.hexated.SoraExtractor.invokeGogo +import com.hexated.SoraExtractor.invokeHDMovieBox import com.hexated.SoraExtractor.invokeLocalSources import com.hexated.SoraExtractor.invokeMovieHab import com.hexated.SoraExtractor.invokeOlgply +import com.hexated.SoraExtractor.invokeSeries9 import com.hexated.SoraExtractor.invokeSoraVIP import com.hexated.SoraExtractor.invokeTwoEmbed import com.hexated.SoraExtractor.invokeVidSrc @@ -15,7 +18,6 @@ import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId import com.lagradost.cloudstream3.metaproviders.TmdbProvider -import com.lagradost.cloudstream3.mvvm.safeApiCall import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.toJson import com.lagradost.cloudstream3.utils.ExtractorLink @@ -46,6 +48,9 @@ open class SoraStream : TmdbProvider() { const val dbgoAPI = "https://dbgo.fun" const val movie123API = "https://api.123movie.cc" const val movieHabAPI = "https://moviehab.com" + const val databaseGdriveAPI = "https://databasegdriveplayer.co" + const val hdMovieBoxAPI = "https://hdmoviebox.net" + const val series9API = "https://series9.la" fun getType(t: String?): TvType { return when (t) { @@ -186,6 +191,7 @@ open class SoraStream : TmdbProvider() { .parsedSafe()?.pageProps ?: throw ErrorLoadingException("Invalid Json Response") val res = responses.result ?: return null + val title = res.title ?: res.name ?: res.originalTitle ?: res.originalName ?: return null val type = getType(data.type) val actors = responses.cast?.mapNotNull { cast -> ActorData( @@ -210,7 +216,8 @@ open class SoraStream : TmdbProvider() { responses.imdbId, data.type, eps.seasonNumber, - eps.episodeNumber + eps.episodeNumber, + title = title, ).toJson(), name = eps.name, season = eps.seasonNumber, @@ -224,7 +231,7 @@ open class SoraStream : TmdbProvider() { } } newTvSeriesLoadResponse( - res.title ?: res.name ?: res.originalTitle ?: res.originalName ?: return null, + title, url, TvType.TvSeries, episodes @@ -240,13 +247,14 @@ open class SoraStream : TmdbProvider() { } } else { newMovieLoadResponse( - res.title ?: res.name ?: res.originalTitle ?: res.originalName ?: return null, + title, url, TvType.Movie, LinkData( data.id, responses.imdbId, data.type, + title = title, ).toJson(), ) { this.posterUrl = getImageUrl(res.posterPath) @@ -341,11 +349,25 @@ open class SoraStream : TmdbProvider() { { invokeMovieHab(res.id, res.season, res.episode, subtitleCallback, callback) }, +// { +// invokeDatabaseGdrive( +// res.imdbId, +// res.season, +// res.episode, +// subtitleCallback, +// callback +// ) +// }, { if (res.aniId?.isNotEmpty() == true) invokeGogo(res.aniId, res.animeId, callback) - }) - - + }, + { + invokeHDMovieBox(res.title, res.season, res.episode, callback) + }, + { + invokeSeries9(res.title, res.season, res.episode, subtitleCallback, callback) + } + ) return true } @@ -358,6 +380,7 @@ open class SoraStream : TmdbProvider() { val episode: Int? = null, val aniId: String? = null, val animeId: String? = null, + val title: String? = null, ) data class Data(