diff --git a/NginxProvider/src/main/kotlin/com/lagradost/NginxProvider.kt b/NginxProvider/src/main/kotlin/com/lagradost/NginxProvider.kt index c1f54b5..44ce5d7 100644 --- a/NginxProvider/src/main/kotlin/com/lagradost/NginxProvider.kt +++ b/NginxProvider/src/main/kotlin/com/lagradost/NginxProvider.kt @@ -20,6 +20,7 @@ class NginxProvider : MainAPI() { override val hasMainPage = true override val hasQuickSearch = false override val supportedTypes = setOf(TvType.AnimeMovie, TvType.TvSeries, TvType.Movie) + // override val hasSearch = false companion object { var companionName = "Nginx" diff --git a/SuperStream/src/main/kotlin/com/lagradost/SuperStream.kt b/SuperStream/src/main/kotlin/com/lagradost/SuperStream.kt index 3f737ab..a393949 100644 --- a/SuperStream/src/main/kotlin/com/lagradost/SuperStream.kt +++ b/SuperStream/src/main/kotlin/com/lagradost/SuperStream.kt @@ -27,7 +27,7 @@ const val TYPE_MOVIES = 1 class SuperStream : MainAPI() { override var name = "SuperStream" - override val hasMainPage = true + override val hasMainPage = false override val hasChromecastSupport = true override val supportedTypes = setOf( TvType.Movie, diff --git a/TheFlixToProvider/build.gradle.kts b/TheFlixToProvider/build.gradle.kts new file mode 100644 index 0000000..0526dcb --- /dev/null +++ b/TheFlixToProvider/build.gradle.kts @@ -0,0 +1,26 @@ +// use an integer for version numbers +version = 1 + + +cloudstream { + language = "en" + // All of these properties are optional, you can safely remove them + + // description = "Lorem Ipsum" + // authors = listOf("Cloudburst") + + /** + * Status int as the following: + * 0: Down + * 1: Ok + * 2: Slow + * 3: Beta only + * */ + status = 1 // will be 3 if unspecified + tvTypes = listOf( + "TvSeries", + "Movie", + ) + + iconUrl = "https://www.google.com/s2/favicons?domain=theflix.to&sz=%size%" +} \ No newline at end of file diff --git a/TheFlixToProvider/src/main/AndroidManifest.xml b/TheFlixToProvider/src/main/AndroidManifest.xml new file mode 100644 index 0000000..29aec9d --- /dev/null +++ b/TheFlixToProvider/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/TheFlixToProvider/src/main/kotlin/com/lagradost/TheFlixToProvider.kt b/TheFlixToProvider/src/main/kotlin/com/lagradost/TheFlixToProvider.kt new file mode 100644 index 0000000..b96543f --- /dev/null +++ b/TheFlixToProvider/src/main/kotlin/com/lagradost/TheFlixToProvider.kt @@ -0,0 +1,619 @@ +package com.lagradost + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.LoadResponse.Companion.addActors +import com.lagradost.cloudstream3.utils.AppUtils +import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.getQualityFromName + +class TheFlixToProvider : MainAPI() { + companion object { + var latestCookies: Map = emptyMap() + } + + override var name = "TheFlix.to" + override var mainUrl = "https://theflix.to" + override val instantLinkLoading = false + override val hasMainPage = false + override val supportedTypes = setOf( + TvType.Movie, + TvType.TvSeries, + ) + + + + data class HomeJson( + @JsonProperty("props") val props: HomeProps = HomeProps(), + ) + + data class HomeProps( + @JsonProperty("pageProps") val pageProps: PageProps = PageProps(), + ) + + data class PageProps( + @JsonProperty("moviesListTrending") val moviesListTrending: MoviesListTrending = MoviesListTrending(), + @JsonProperty("moviesListNewArrivals") val moviesListNewArrivals: MoviesListNewArrivals = MoviesListNewArrivals(), + @JsonProperty("tvsListTrending") val tvsListTrending: TvsListTrending = TvsListTrending(), + @JsonProperty("tvsListNewEpisodes") val tvsListNewEpisodes: TvsListNewEpisodes = TvsListNewEpisodes(), + ) + + + data class MoviesListTrending( + @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 MoviesListNewArrivals( + @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 TvsListTrending( + @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 TvsListNewEpisodes( + @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 Docs( + @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("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(page: Int, request : MainPageRequest): HomePageResponse { + val items = ArrayList() + val doc = app.get(mainUrl).document + val scriptText = doc.selectFirst("script[type=application/json]")!!.data() + if (scriptText.contains("moviesListTrending")) { + val json = parseJson(scriptText) + val homePageProps = json.props.pageProps + listOf( + Triple( + homePageProps.moviesListNewArrivals.docs, + homePageProps.moviesListNewArrivals.type, + "New Movie arrivals" + ), + Triple( + homePageProps.moviesListTrending.docs, + homePageProps.moviesListTrending.type, + "Trending Movies" + ), + Triple( + homePageProps.tvsListTrending.docs, + homePageProps.tvsListTrending.type, + "Trending TV Series" + ), + Triple( + homePageProps.tvsListNewEpisodes.docs, + homePageProps.tvsListNewEpisodes.type, + "New Episodes" + ) + ).map { (docs, type, homename) -> + val home = docs.map { info -> + val title = info.name + val poster = info.posterUrl + val typeinfo = + 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).replace("?","")}/season-1/episode-1" + TvSeriesSearchResponse( + title, + link, + this.name, + typeinfo, + poster, + null, + null, + ) + } + items.add(HomePageList(homename, home)) + } + + } + + if (items.size <= 0) throw ErrorLoadingException() + return HomePageResponse(items) + } + + data class SearchJson( + @JsonProperty("props") val props: SearchProps = SearchProps(), + ) + + data class SearchProps( + @JsonProperty("pageProps") val pageProps: SearchPageProps = SearchPageProps(), + ) + + data class SearchPageProps( + @JsonProperty("mainList") val mainList: SearchMainList = SearchMainList(), + ) + + data class SearchMainList( + @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 data class TmdbProviderSearchFilter( + @JsonProperty("title") val title: String, + @JsonProperty("tmdbYear") val tmdbYear: Int?, + @JsonProperty("tmdbPlot") val tmdbPlot: String?, + @JsonProperty("duration") val duration: Int?, + @JsonProperty("type") val type: TvType?, + ) + + override suspend fun search(query: String): List { + + val parsedFilter = AppUtils.tryParseJson(query) + val query = parsedFilter?.title ?: throw ErrorLoadingException() + + val yearFilter = if(parsedFilter.tmdbYear != null) { + "/year-${parsedFilter.tmdbYear}" + } else { + "" + } + val search = ArrayList() + val urls = listOf( + "$mainUrl/movies/trending${yearFilter}?search=$query", // TODO add genre filter + "$mainUrl/tv-shows/trending${yearFilter}?search=$query" + ) + urls.apmap { url -> + val doc = app.get(url).document + val scriptText = doc.selectFirst("script[type=application/json]")!!.data() + if (scriptText.contains("pageProps")) { + val json = parseJson(scriptText) + val searchPageProps = json.props.pageProps.mainList + val pair = listOf(Pair(searchPageProps.docs, searchPageProps.type)) + pair.map { (docs, type) -> + docs.map { info -> + val title = info.name + val poster = info.posterUrl + val typeinfo = + 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" + if (typeinfo == TvType.Movie) { + search.add( + MovieSearchResponse( + title, + link, + this.name, + TvType.Movie, + poster, + null + ) + ) + } else { + search.add( + TvSeriesSearchResponse( + title, + link, + this.name, + TvType.TvSeries, + poster, + null, + null + ) + ) + } + } + } + } + } + return search + } + 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 LoadProps ( + @JsonProperty("pageProps" ) val pageProps : LoadPageProps? = LoadPageProps(), + @JsonProperty("__N_SSP" ) val _NSSP : Boolean? = null + ) + + data class LoadPageProps ( + @JsonProperty("selectedTv" ) val selectedTv : TheFlixMetadata? = TheFlixMetadata(), + @JsonProperty("movie") val movie: TheFlixMetadata? = TheFlixMetadata(), + @JsonProperty("recommendationsList" ) val recommendationsList : RecommendationsList? = RecommendationsList(), + @JsonProperty("basePageSegments" ) val basePageSegments : ArrayList? = arrayListOf() + ) + + 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, + @JsonProperty("seasonNumber") val seasonNumber: Int? = 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("episodes") val episodes: ArrayList? = arrayListOf() + ) + + data class Episodes( + @JsonProperty("episodeNumber") val episodeNumber: Int? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("seasonNumber") val seasonNumber: Int? = null, + @JsonProperty("voteAverage") val voteAverage: Double? = null, + @JsonProperty("voteCount") val voteCount: Int? = null, + @JsonProperty("overview") val overview: 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("videos") val videos: 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 { + val dotTitle = title.substringBefore("/season") + if (dotTitle.contains(Regex("\\..\\."))) { //For titles containing more than two dots (S.W.A.T.) + return (dotTitle.removeSuffix(".") + .replace(" - ", "-") + .replace(".", "-").replace(" ", "-") + .replace("-&", "") + .replace(Regex("(:|-&)"), "") + .replace("'", "-")).lowercase() + } + return (title + .replace(" - ", "-") + .replace(" ", "-") + .replace("-&", "") + .replace("/", "-") + .replace(Regex("(:|-&|\\.)"), "") + .replace("'", "-")).lowercase() + } + + private suspend fun getLoadMan(url: String): LoadMain { + getCookies() + val og = app.get(url, headers = latestCookies) + val soup = og.document + val script = soup.selectFirst("script[type=application/json]")!!.data() + return parseJson(script) + } + + override suspend fun load(url: String): LoadResponse? { + val tvtype = if (url.contains("movie")) TvType.Movie else TvType.TvSeries + val json = getLoadMan(url) + val episodes = ArrayList() + val isMovie = tvtype == TvType.Movie + val pageMain = json.props?.pageProps + + val metadata: TheFlixMetadata? = if (isMovie) pageMain?.movie else pageMain?.selectedTv + + val available = metadata?.available + + val comingsoon = !available!! + + val movieId = metadata.id + + val movietitle = metadata.name + + val poster = metadata.posterUrl + + val description = metadata.overview + + if (!isMovie) { + metadata.seasons?.map { seasons -> + val seasonPoster = seasons.posterUrl ?: metadata.posterUrl + seasons.episodes?.forEach { epi -> + val episodenu = epi.episodeNumber + val seasonum = epi.seasonNumber + val title = epi.name + val epDesc = epi.overview + val test = epi.videos + 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", + title, + seasonum, + episodenu, + description = epDesc!!, + posterUrl = seasonPoster, + rating = rating, + ) + if (test!!.isNotEmpty()) { + episodes.add(eps) + } else { + //Nothing, will prevent seasons/episodes with no videos to be added + } + } + } + } + val rating = metadata.voteAverage?.toFloat()?.times(1000)?.toInt() + + val tags = metadata.genres?.mapNotNull { it.name } + + 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)}" + else "$mainUrl/tv-show/${loadDocs.id}-${cleanTitle(title)}/season-1/episode-1" + MovieSearchResponse( + title, + link, + this.name, + tvtype, + posterrec, + year = null + ) + } + + val year = metadata.releaseDate?.substringBefore("-") + + val runtime = metadata.runtime?.div(60) ?: metadata.episodeRuntime?.div(60) + val cast = metadata.cast?.split(",") + + return when (tvtype) { + TvType.TvSeries -> { + return newTvSeriesLoadResponse(movietitle!!, url, TvType.TvSeries, episodes) { + this.posterUrl = poster + this.year = year?.toIntOrNull() + this.plot = description + this.duration = runtime + addActors(cast) + this.tags = tags + this.recommendations = recommendationsitem + this.comingSoon = comingsoon + this.rating = rating + } + } + TvType.Movie -> { + newMovieLoadResponse(movietitle!!, url, TvType.Movie, url) { + this.year = year?.toIntOrNull() + this.posterUrl = poster + this.plot = description + this.duration = runtime + addActors(cast) + this.tags = tags + this.recommendations = recommendationsitem + this.comingSoon = comingsoon + this.rating = rating + } + } + else -> null + } + } + + + 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 = getLoadMan(data) + val authhost = json.runtimeConfig?.Services?.Server?.Url + val isMovie = data.contains("/movie/") + val qualityReg = Regex("(\\d+p)") + 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/TheFlixToProvider/src/main/kotlin/com/lagradost/TheFlixToProviderPlugin.kt b/TheFlixToProvider/src/main/kotlin/com/lagradost/TheFlixToProviderPlugin.kt new file mode 100644 index 0000000..6eb5cfa --- /dev/null +++ b/TheFlixToProvider/src/main/kotlin/com/lagradost/TheFlixToProviderPlugin.kt @@ -0,0 +1,14 @@ + +package com.lagradost + +import com.lagradost.cloudstream3.plugins.CloudstreamPlugin +import com.lagradost.cloudstream3.plugins.Plugin +import android.content.Context + +@CloudstreamPlugin +class TheFlixToProviderPlugin: Plugin() { + override fun load(context: Context) { + // All providers should be added in this manner. Please don't edit the providers list directly. + registerMainAPI(TheFlixToProvider()) + } +} \ No newline at end of file