From cc7bf8534ca9e0ea7a494e0f944a1bb8cf83c24b Mon Sep 17 00:00:00 2001 From: Stormunblessed <86633626+Stormunblessed@users.noreply.github.com> Date: Tue, 12 Jul 2022 20:29:51 +0000 Subject: [PATCH] fixes and new provider (#1262) * fixes * fixes --- .../com/lagradost/cloudstream3/MainAPI.kt | 1 + .../animeproviders/MonoschinosProvider.kt | 4 +- .../movieproviders/TheFlixToProvider.kt | 391 ++++++++++-------- .../movieproviders/VidSrcProvider.kt | 73 ++++ docs/providers.json | 2 +- 5 files changed, 288 insertions(+), 183 deletions(-) create mode 100644 app/src/main/java/com/lagradost/cloudstream3/movieproviders/VidSrcProvider.kt diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt index 37cf64de..4feef790 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt @@ -100,6 +100,7 @@ object APIHolder { OpenVidsProvider(), IdlixProvider(), MultiplexProvider(), + VidSrcProvider(), // Metadata providers //TmdbProvider(), diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/MonoschinosProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/MonoschinosProvider.kt index e06d2e66..2548bb8b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/MonoschinosProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/MonoschinosProvider.kt @@ -50,12 +50,12 @@ class MonoschinosProvider : MainAPI() { HomePageList( "CapĂ­tulos actualizados", app.get(mainUrl, timeout = 120).document.select(".col-6").map { - val title = it.selectFirst("p.animetitles")!!.text() + val title = it.selectFirst("p.animetitles")?.text() ?: it.selectFirst(".animetitles")?.text() ?: "" val poster = it.selectFirst(".animeimghv")!!.attr("data-src") val epRegex = Regex("episodio-(\\d+)") val url = it.selectFirst("a")?.attr("href")!!.replace("ver/", "anime/") .replace(epRegex, "sub-espanol") - val epNum = it.selectFirst(".positioning h5")?.text()?.toIntOrNull() + val epNum = (it.selectFirst(".positioning h5")?.text() ?: it.selectFirst("div.positioning p")?.text())?.toIntOrNull() newAnimeSearchResponse(title, url) { this.posterUrl = fixUrl(poster) addDubStatus(getDubStatus(title), epNum) diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TheFlixToProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TheFlixToProvider.kt index 81bd5757..38f08ec9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TheFlixToProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TheFlixToProvider.kt @@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.movieproviders import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.LoadResponse.Companion.addActors +import com.lagradost.cloudstream3.network.cookies import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.getQualityFromName @@ -22,6 +23,8 @@ class TheFlixToProvider : MainAPI() { TvType.TvSeries, ) + + data class HomeJson( @JsonProperty("props") val props: HomeProps = HomeProps(), ) @@ -92,9 +95,54 @@ class TheFlixToProvider : MainAPI() { @JsonProperty("conversionDate") val conversionDate: String? = null, @JsonProperty("id") val id: Int? = null, @JsonProperty("available") val available: Boolean? = null, + @JsonProperty("videos" ) val videos : ArrayList? = arrayListOf(), ) + private suspend fun getCookies(): Map { + // val cookieResponse = app.post( + // "https://theflix.to:5679/authorization/session/continue?contentUsageType=Viewing", + // headers = mapOf( + // "Host" to "theflix.to:5679", + // "User-Agent" to "Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0", + // "Accept" to "application/json, text/plain," + // "Accept-Language" to "en-US,en;q=0.5", + // "Content-Type" to "application/json;charset=utf-8", + // "Content-Length" to "35", + // "Origin" to "https://theflix.to", + // "DNT" to "1", + // "Connection" to "keep-alive", + // "Referer" to "https://theflix.to/", + // "Sec-Fetch-Dest" to "empty", + // "Sec-Fetch-Mode" to "cors", + // "Sec-Fetch-Site" to "same-site",)).okhttpResponse.headers.values("Set-Cookie") + + val cookies = app.post( + "$mainUrl:5679/authorization/session/continue?contentUsageType=Viewing", + headers = mapOf( + "Host" to "theflix.to:5679", + "User-Agent" to USER_AGENT, + "Accept" to "application/json, text/plain, */*", + "Accept-Language" to "en-US,en;q=0.5", + "Content-Type" to "application/json;charset=utf-8", + "Content-Length" to "35", + "Origin" to mainUrl, + "DNT" to "1", + "Connection" to "keep-alive", + "Referer" to mainUrl, + "Sec-Fetch-Dest" to "empty", + "Sec-Fetch-Mode" to "cors", + "Sec-Fetch-Site" to "same-site",) + ).cookies + /* val cookieRegex = Regex("(theflix\\..*?id\\=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") + val findcookie = cookieRegex.findAll(cookieResponse.toString()).map { it.value }.toList() + val cookiesstring = findcookie.toString().replace(", ","; ").replace("[","").replace("]","") + val cookiesmap = mapOf("Cookie" to cookiesstring) */ + latestCookies = cookies + return latestCookies + } + + override suspend fun getMainPage(): HomePageResponse { val items = ArrayList() val doc = app.get(mainUrl).document @@ -131,7 +179,7 @@ class TheFlixToProvider : MainAPI() { if (type?.contains("TV") == true) TvType.TvSeries else TvType.Movie val link = if (typeinfo == TvType.Movie) "$mainUrl/movie/${info.id}-${cleanTitle(title)}" - else "$mainUrl/tv-show/${info.id}-${cleanTitle(title)}/season-1/episode-1" + else "$mainUrl/tv-show/${info.id}-${cleanTitle(title).replace("?","")}/season-1/episode-1" TvSeriesSearchResponse( title, link, @@ -226,67 +274,53 @@ class TheFlixToProvider : MainAPI() { } return search } - - - data class LoadMain( - @JsonProperty("props") val props: LoadProps = LoadProps(), - @JsonProperty("page") var page: String? = null, - //@JsonProperty("query") val query: Query? = Query(), - @JsonProperty("buildId") val buildId: String? = null, - @JsonProperty("runtimeConfig") val runtimeConfig: RuntimeConfig? = RuntimeConfig(), - @JsonProperty("isFallback") val isFallback: Boolean? = null, - @JsonProperty("customServer") val customServer: Boolean? = null, - @JsonProperty("appGip") val appGip: Boolean? = null + data class LoadMain ( + @JsonProperty("props" ) val props : LoadProps? = LoadProps(), + @JsonProperty("page" ) val page : String? = null, + @JsonProperty("buildId" ) val buildId : String? = null, + @JsonProperty("runtimeConfig" ) val runtimeConfig : RuntimeConfig? = RuntimeConfig(), + @JsonProperty("isFallback" ) val isFallback : Boolean? = null, + @JsonProperty("gssp" ) val gssp : Boolean? = null, + @JsonProperty("customServer" ) val customServer : Boolean? = null, + @JsonProperty("appGip" ) val appGip : Boolean? = null ) - data class RuntimeConfig( - @JsonProperty("AddThisService") val AddThisService: AddThisService? = AddThisService(), - //@JsonProperty("Application") val Application: Application? = Application(), - //@JsonProperty("Content") val Content: Content? = Content(), - //@JsonProperty("GtmService") val GtmService: GtmService? = GtmService(), - //@JsonProperty("IptvChannels") val IptvChannels: IptvChannels? = IptvChannels(), - //@JsonProperty("Notifications") val Notifications: Notifications? = Notifications(), - //@JsonProperty("Payments") val Payments: Payments? = Payments(), - //@JsonProperty("Redux") val Redux: Redux? = Redux(), - //@JsonProperty("Search") val Search: Search? = Search(), - @JsonProperty("Services") val Services: Services? = Services(), - //@JsonProperty("Sitemap") val Sitemap: Sitemap? = Sitemap(), - //@JsonProperty("Support") val Support: Support? = Support(), - @JsonProperty("Videos") val Videos: Videos? = Videos() + data class LoadProps ( + @JsonProperty("pageProps" ) val pageProps : LoadPageProps? = LoadPageProps(), + @JsonProperty("__N_SSP" ) val _NSSP : Boolean? = null ) - - data class Server( - @JsonProperty("Url") var Url: String? = null - ) - - data class Services( - - @JsonProperty("Server") val Server: Server? = Server(), - @JsonProperty("TmdbServer") val TmdbServer: Server? = Server() - - ) - - data class AddThisService( - @JsonProperty("PublicId") val PublicId: String? = null - ) - - data class LoadProps( - @JsonProperty("pageProps") val pageProps: LoadPageProps = LoadPageProps(), - ) - - data class LoadPageProps( - @JsonProperty("selectedTv") val selectedTv: TheFlixMetadata? = TheFlixMetadata(), + data class LoadPageProps ( + @JsonProperty("selectedTv" ) val selectedTv : TheFlixMetadata? = TheFlixMetadata(), @JsonProperty("movie") val movie: TheFlixMetadata? = TheFlixMetadata(), - @JsonProperty("videoUrl") val videoUrl: String? = null, - @JsonProperty("recommendationsList") val recommendationsList: RecommendationsList? = RecommendationsList(), + @JsonProperty("recommendationsList" ) val recommendationsList : RecommendationsList? = RecommendationsList(), + @JsonProperty("basePageSegments" ) val basePageSegments : ArrayList? = arrayListOf() ) - data class Genres( - @JsonProperty("name") val name: String, - @JsonProperty("id") val id: Int? = null + data class TheFlixMetadata ( + @JsonProperty("episodeRuntime" ) val episodeRuntime : Int? = null, + @JsonProperty("name" ) val name : String? = null, + @JsonProperty("numberOfSeasons" ) val numberOfSeasons : Int? = null, + @JsonProperty("numberOfEpisodes" ) val numberOfEpisodes : Int? = null, + @JsonProperty("originalLanguage" ) val originalLanguage : String? = null, + @JsonProperty("popularity" ) val popularity : Double? = null, + @JsonProperty("status" ) val status : String? = null, + @JsonProperty("voteAverage" ) val voteAverage : Double? = null, + @JsonProperty("voteCount" ) val voteCount : Int? = null, + @JsonProperty("cast" ) val cast : String? = null, + @JsonProperty("director" ) val director : String? = null, + @JsonProperty("overview" ) val overview : String? = null, + @JsonProperty("posterUrl" ) val posterUrl : String? = null, + @JsonProperty("releaseDate" ) val releaseDate : String? = null, + @JsonProperty("createdAt" ) val createdAt : String? = null, + @JsonProperty("updatedAt" ) val updatedAt : String? = null, + @JsonProperty("id" ) val id : Int? = null, + @JsonProperty("available" ) val available : Boolean? = null, + @JsonProperty("genres" ) val genres : ArrayList? = arrayListOf(), + @JsonProperty("seasons" ) val seasons : ArrayList? = arrayListOf(), + @JsonProperty("videos" ) val videos : ArrayList? = arrayListOf(), + @JsonProperty("runtime" ) val runtime : Int? = null, ) - data class Seasons( @JsonProperty("name") val name: String? = null, @JsonProperty("numberOfEpisodes") val numberOfEpisodes: Int? = null, @@ -297,7 +331,7 @@ class TheFlixToProvider : MainAPI() { @JsonProperty("createdAt") val createdAt: String? = null, @JsonProperty("updatedAt") val updatedAt: String? = null, @JsonProperty("id") val id: Int? = null, - @JsonProperty("episodes") val episodes: ArrayList = arrayListOf() + @JsonProperty("episodes") val episodes: ArrayList? = arrayListOf() ) data class Episodes( @@ -311,68 +345,55 @@ class TheFlixToProvider : MainAPI() { @JsonProperty("createdAt") val createdAt: String? = null, @JsonProperty("updatedAt") val updatedAt: String? = null, @JsonProperty("id") val id: Int? = null, - @JsonProperty("videos") val videos: ArrayList = arrayListOf() - ) - - data class Videos( - @JsonProperty("language") val language: String? = null, - @JsonProperty("name") val name: String? = null, - @JsonProperty("id") val id: Int? = null - ) - - data class RecommendationsList( - @JsonProperty("docs") val docs: ArrayList = arrayListOf(), - @JsonProperty("total") val total: Int? = null, - @JsonProperty("page") val page: Int? = null, - @JsonProperty("limit") val limit: Int? = null, - @JsonProperty("pages") val pages: Int? = null, - @JsonProperty("type") val type: String? = null, - ) - - data class LoadDocs( - @JsonProperty("name") val name: String = String(), - @JsonProperty("originalLanguage") val originalLanguage: String? = null, - @JsonProperty("popularity") val popularity: Double? = null, - @JsonProperty("runtime") val runtime: Int? = null, - @JsonProperty("status") val status: String? = null, - @JsonProperty("voteAverage") val voteAverage: Double? = null, - @JsonProperty("voteCount") val voteCount: Int? = null, - @JsonProperty("cast") val cast: String? = null, - @JsonProperty("director") val director: String? = null, - @JsonProperty("overview") val overview: String? = null, - @JsonProperty("posterUrl") val posterUrl: String? = null, - @JsonProperty("releaseDate") val releaseDate: String? = null, - @JsonProperty("createdAt") val createdAt: String? = null, - @JsonProperty("updatedAt") val updatedAt: String? = null, - @JsonProperty("id") val id: Int? = null, - @JsonProperty("available") val available: Boolean? = null, + @JsonProperty("videos") val videos: ArrayList? = arrayListOf() ) - data class TheFlixMetadata( - @JsonProperty("episodeRuntime") val episodeRuntime: Int? = null, - @JsonProperty("name") val name: String = String(), - @JsonProperty("originalLanguage") val originalLanguage: String? = null, - @JsonProperty("popularity") val popularity: Double? = null, - @JsonProperty("runtime") val runtime: Int? = null, - @JsonProperty("numberOfSeasons") val numberOfSeasons: Int? = null, - @JsonProperty("numberOfEpisodes") val numberOfEpisodes: Int? = null, - @JsonProperty("status") val status: String? = null, - @JsonProperty("voteAverage") val voteAverage: Double? = null, - @JsonProperty("voteCount") val voteCount: Int? = null, - @JsonProperty("cast") val cast: String? = null, - @JsonProperty("director") val director: String? = null, - @JsonProperty("overview") val overview: String? = null, - @JsonProperty("posterUrl") val posterUrl: String? = null, - @JsonProperty("releaseDate") val releaseDate: String? = null, - @JsonProperty("conversionDate") val conversionDate: String? = null, - @JsonProperty("createdAt") val createdAt: String? = null, - @JsonProperty("updatedAt") val updatedAt: String? = null, - @JsonProperty("id") val id: Int? = null, - @JsonProperty("available") val available: Boolean? = null, - @JsonProperty("genres") val genres: ArrayList = arrayListOf(), - @JsonProperty("videos") val videos: ArrayList = arrayListOf(), - @JsonProperty("seasons") val seasons: ArrayList = arrayListOf() + data class Genres ( + @JsonProperty("name" ) val name : String? = null, + @JsonProperty("id" ) val id : Int? = null + ) + + data class RuntimeConfig ( + @JsonProperty("AddThisService" ) val AddThisService : RuntimeConfigData? = RuntimeConfigData(), + @JsonProperty("Application" ) val Application : RuntimeConfigData? = RuntimeConfigData(), + @JsonProperty("GtmService" ) val GtmService : RuntimeConfigData? = RuntimeConfigData(), + @JsonProperty("Services" ) val Services : RuntimeConfigData? = RuntimeConfigData(), + ) + + data class RuntimeConfigData( + @JsonProperty("PublicId" ) val PublicId : String? = null, + @JsonProperty("ContentUsageType" ) val ContentUsageType : String? = null, + @JsonProperty("IsDevelopmentMode" ) val IsDevelopmentMode : Boolean? = null, + @JsonProperty("IsDevelopmentOrProductionMode" ) val IsDevelopmentOrProductionMode : Boolean? = null, + @JsonProperty("IsProductionMode" ) val IsProductionMode : Boolean? = null, + @JsonProperty("IsStagingMode" ) val IsStagingMode : Boolean? = null, + @JsonProperty("IsTestMode" ) val IsTestMode : Boolean? = null, + @JsonProperty("Mode" ) val Mode : String? = null, + @JsonProperty("Name" ) val Name : String? = null, + @JsonProperty("Url" ) val Url : String? = null, + @JsonProperty("UseFilterInfoInUrl" ) val UseFilterInfoInUrl : Boolean? = null, + @JsonProperty("TrackingId" ) val TrackingId : String? = null, + @JsonProperty("Server" ) val Server : Server? = Server(), + @JsonProperty("TmdbServer" ) val TmdbServer : TmdbServer? = TmdbServer(), + ) + + data class TmdbServer ( + @JsonProperty("Url" ) val Url : String? = null + ) + + + data class Server ( + @JsonProperty("Url" ) val Url : String? = null + ) + + data class RecommendationsList ( + @JsonProperty("docs" ) val docs : ArrayList = arrayListOf(), + @JsonProperty("total" ) val total : Int? = null, + @JsonProperty("page" ) val page : Int? = null, + @JsonProperty("limit" ) val limit : Int? = null, + @JsonProperty("pages" ) val pages : Int? = null, + @JsonProperty("type" ) val type : String? = null, ) private fun cleanTitle(title: String): String { @@ -395,60 +416,21 @@ class TheFlixToProvider : MainAPI() { } private suspend fun getLoadMan(url: String): LoadMain { - val og = app.get(url, cookies = latestCookies) + getCookies() + val og = app.get(url, headers = latestCookies) val soup = og.document val script = soup.selectFirst("script[type=application/json]")!!.data() return parseJson(script) } - // I legit cant figure this out - private suspend fun getLoadMainRetry(url: String): LoadMain { - val first = getLoadMan(url) - val notFound = "/404" - if (first.page == notFound) { - first.runtimeConfig?.Services?.TmdbServer?.Url?.let { authUrl -> - val optionsUrl = "$authUrl/authorization/session/continue?contentUsageType=Viewing" - val options = app.options( - optionsUrl, - headers = mapOf( - "User-Agent" to USER_AGENT, - "Access-Control-Request-Method" to "POST", - "Access-Control-Request-Headers" to "content-type", - "Origin" to url, - "Referer" to mainUrl, - ) - ) - //{"affiliateCode":"","pathname":"/movie/696806-the-adam-project"} - val data = mapOf("affiliateCode" to "", "pathname" to url.removePrefix(mainUrl)) - val resp = app.post( - optionsUrl, headers = mapOf( - "User-Agent" to USER_AGENT, - "Content-Type" to "application/json;charset=UTF-8", - "Accept" to "application/json, text/plain, */*", - "Origin" to url, - "Referer" to mainUrl, - ), data = data - ) - - latestCookies = resp.cookies - val newData = getLoadMan(url) - if (newData.page == notFound) { - throw ErrorLoadingException("404 Not found") - } - return newData - } - } - return first - } - override suspend fun load(url: String): LoadResponse? { val tvtype = if (url.contains("movie")) TvType.Movie else TvType.TvSeries - val json = getLoadMainRetry(url) + val json = getLoadMan(url) val episodes = ArrayList() val isMovie = tvtype == TvType.Movie - val pageMain = json.props.pageProps + val pageMain = json.props?.pageProps - val metadata: TheFlixMetadata? = if (isMovie) pageMain.movie else pageMain.selectedTv + val metadata: TheFlixMetadata? = if (isMovie) pageMain?.movie else pageMain?.selectedTv val available = metadata?.available @@ -463,9 +445,9 @@ class TheFlixToProvider : MainAPI() { val description = metadata.overview if (!isMovie) { - metadata.seasons.map { seasons -> + metadata.seasons?.map { seasons -> val seasonPoster = seasons.posterUrl ?: metadata.posterUrl - seasons.episodes.forEach { epi -> + seasons.episodes?.forEach { epi -> val episodenu = epi.episodeNumber val seasonum = epi.seasonNumber val title = epi.name @@ -474,7 +456,7 @@ class TheFlixToProvider : MainAPI() { val ratinginfo = (epi.voteAverage)?.times(10)?.toInt() val rating = if (ratinginfo?.equals(0) == true) null else ratinginfo val eps = Episode( - "$mainUrl/tv-show/$movieId-${cleanTitle(movietitle)}/season-$seasonum/episode-$episodenu", + "$mainUrl/tv-show/$movieId-${cleanTitle(movietitle!!)}/season-$seasonum/episode-$episodenu", title, seasonum, episodenu, @@ -482,7 +464,7 @@ class TheFlixToProvider : MainAPI() { posterUrl = seasonPoster, rating = rating, ) - if (test.isNotEmpty()) { + if (test!!.isNotEmpty()) { episodes.add(eps) } else { //Nothing, will prevent seasons/episodes with no videos to be added @@ -492,9 +474,9 @@ class TheFlixToProvider : MainAPI() { } val rating = metadata.voteAverage?.toFloat()?.times(1000)?.toInt() - val tags = metadata.genres.map { it.name } + val tags = metadata.genres?.mapNotNull { it.name } - val recommendationsitem = pageMain.recommendationsList?.docs?.map { loadDocs -> + val recommendationsitem = pageMain?.recommendationsList?.docs?.map { loadDocs -> val title = loadDocs.name val posterrec = loadDocs.posterUrl val link = if (isMovie) "$mainUrl/movie/${loadDocs.id}-${cleanTitle(title)}" @@ -516,7 +498,7 @@ class TheFlixToProvider : MainAPI() { return when (tvtype) { TvType.TvSeries -> { - return newTvSeriesLoadResponse(movietitle, url, TvType.TvSeries, episodes) { + return newTvSeriesLoadResponse(movietitle!!, url, TvType.TvSeries, episodes) { this.posterUrl = poster this.year = year?.toIntOrNull() this.plot = description @@ -529,7 +511,7 @@ class TheFlixToProvider : MainAPI() { } } TvType.Movie -> { - newMovieLoadResponse(movietitle, url, TvType.Movie, url) { + newMovieLoadResponse(movietitle!!, url, TvType.Movie, url) { this.year = year?.toIntOrNull() this.posterUrl = poster this.plot = description @@ -546,27 +528,76 @@ class TheFlixToProvider : MainAPI() { } + data class VideoData ( + @JsonProperty("url" ) val url : String? = null, + @JsonProperty("id" ) val id : String? = null, + @JsonProperty("type" ) val type : String? = null, + ) + + override suspend fun loadLinks( data: String, isCasting: Boolean, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ): Boolean { - val json = getLoadMainRetry(data) - val extractedLink = json.props.pageProps.videoUrl + val json = getLoadMan(data) + val authhost = json.runtimeConfig?.Services?.Server?.Url + val isMovie = data.contains("/movie/") val qualityReg = Regex("(\\d+p)") - if (extractedLink != null) { - val quality = qualityReg.find(extractedLink)?.value ?: "" - callback( - ExtractorLink( - name, - "$name $quality", - extractedLink, - "", - getQualityFromName(quality), - false - ) - ) + if (isMovie){ + json.props?.pageProps?.movie?.videos?.apmap { id -> + val jsonmovie = app.get("$authhost/movies/videos/$id/request-access?contentUsageType=Viewing", + headers = latestCookies).parsedSafe() ?: return@apmap false + val extractedlink = jsonmovie.url + if (!extractedlink.isNullOrEmpty()) { + val quality = qualityReg.find(extractedlink)?.value ?: "" + callback( + ExtractorLink( + name, + name, + extractedlink, + "", + getQualityFromName(quality), + false + ) + ) + } else null + } + } + else + { + val dataRegex = Regex("(season-(\\d+)\\/episode-(\\d+))") + val cleandatainfo = dataRegex.find(data)?.value?.replace(Regex("(season-|episode-)"),"")?.replace("/","x") + val tesatt = cleandatainfo.let { str -> + str?.split("x")?.mapNotNull { subStr -> subStr.toIntOrNull() } + } + val epID = tesatt?.getOrNull(1) + val seasonid = tesatt?.getOrNull(0) + json.props?.pageProps?.selectedTv?.seasons?.map { + it.episodes?.map { + val epsInfo = Triple(it.seasonNumber, it.episodeNumber, it.videos) + if (epsInfo.first == seasonid && epsInfo.second == epID) { + epsInfo.third?.apmap { id -> + val jsonserie = app.get("$authhost/tv/videos/$id/request-access?contentUsageType=Viewing", headers = latestCookies).parsedSafe() ?: return@apmap false + val extractedlink = jsonserie.url + if (!extractedlink.isNullOrEmpty()) { + val quality = qualityReg.find(extractedlink)?.value ?: "" + callback( + ExtractorLink( + name, + name, + extractedlink, + "", + getQualityFromName(quality), + false + ) + ) + } else null + } + } + } + } } return true } diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/VidSrcProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/VidSrcProvider.kt new file mode 100644 index 00000000..84036abb --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/VidSrcProvider.kt @@ -0,0 +1,73 @@ +package com.lagradost.cloudstream3.movieproviders + +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.metaproviders.TmdbLink +import com.lagradost.cloudstream3.metaproviders.TmdbProvider +import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8 +import com.lagradost.cloudstream3.utils.loadExtractor + +class VidSrcProvider : TmdbProvider() { + override val apiName = "VidSrc" + override var name = "VidSrc" + override var mainUrl = "https://v2.vidsrc.me" + override val useMetaLoadResponse = true + override val instantLinkLoading = false + override val supportedTypes = setOf( + TvType.Movie, + TvType.TvSeries, + ) + + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + val mappedData = parseJson(data) + val (id, site) = if (mappedData.imdbID != null) listOf( + mappedData.imdbID, + "imdb" + ) else listOf(mappedData.tmdbID.toString(), "tmdb") + val isMovie = mappedData.episode == null && mappedData.season == null + val embedUrl = if (isMovie) { + if(site == "imdb") "$mainUrl/embed/$id" else + "$mainUrl/embed/$id" + } else { + val suffix = "$id/${mappedData.season ?: 1}-${mappedData.episode ?: 1}" + if (site == "imdb") "$mainUrl/embed/$suffix" else + "$mainUrl/embed/$suffix" + } + val iframedoc = app.get(embedUrl).document + + val serverslist = iframedoc.select("div#sources.button_content div#content div#list div").map { + val datahash = it.attr("data-hash") + if (datahash.isNotBlank()) { + val links = try { + app.get("$mainUrl/src/$datahash", referer = "https://source.vidsrc.me/").url + } catch (e: Exception) { + "" + } + links + } else "" + } + + serverslist.apmap { server -> + val linkfixed = server.replace("https://vidsrc.xyz/","https://embedsito.com/") + if (linkfixed.contains("/pro")) { + val srcresponse = app.get(server, referer = mainUrl).text + val m3u8Regex = Regex("((https:|http:)\\/\\/.*\\.m3u8)") + val srcm3u8 = m3u8Regex.find(srcresponse)?.value ?: return@apmap false + generateM3u8( + name, + srcm3u8, + mainUrl + ).forEach(callback) + } else + loadExtractor(linkfixed, embedUrl, callback) + } + + return true + } +} \ No newline at end of file diff --git a/docs/providers.json b/docs/providers.json index d06b9fbb..bee41c07 100644 --- a/docs/providers.json +++ b/docs/providers.json @@ -472,7 +472,7 @@ "TheFlixToProvider": { "language": "en", "name": "TheFlix.to", - "status": 0, + "status": 1, "url": "https://theflix.to" }, "TrailersTwoProvider": {