From 69773a66e4f371406e2da3ec6907a44398c63c2e Mon Sep 17 00:00:00 2001 From: sarlay Date: Sat, 27 Aug 2022 23:46:47 +0200 Subject: [PATCH] added sflix and meta providers --- OlgplyProvider/build.gradle.kts | 26 + .../src/main/AndroidManifest.xml | 0 .../kotlin/com/lagradost/OlgplyProvider.kt | 115 ++++ .../com/lagradost/OlgplyProviderPlugin.kt | 4 +- .../kotlin/com/lagradost/TheFlixToProvider.kt | 621 ------------------ TrailersTwoProvider/build.gradle.kts | 30 + .../src/main/AndroidManifest.xml | 2 + .../com/lagradost/TrailersTwoProvider.kt | 319 +++++++++ .../lagradost/TrailersTwoProviderPlugin.kt | 14 + .../build.gradle.kts | 3 +- VidSrcProvider/src/main/AndroidManifest.xml | 2 + .../kotlin/com/lagradost/VidSrcProvider.kt | 53 ++ .../com/lagradost/VidSrcProviderPlugin.kt | 14 + 13 files changed, 578 insertions(+), 625 deletions(-) create mode 100644 OlgplyProvider/build.gradle.kts rename {TheFlixToProvider => OlgplyProvider}/src/main/AndroidManifest.xml (100%) create mode 100644 OlgplyProvider/src/main/kotlin/com/lagradost/OlgplyProvider.kt rename TheFlixToProvider/src/main/kotlin/com/lagradost/TheFlixToProviderPlugin.kt => OlgplyProvider/src/main/kotlin/com/lagradost/OlgplyProviderPlugin.kt (79%) delete mode 100644 TheFlixToProvider/src/main/kotlin/com/lagradost/TheFlixToProvider.kt create mode 100644 TrailersTwoProvider/build.gradle.kts create mode 100644 TrailersTwoProvider/src/main/AndroidManifest.xml create mode 100644 TrailersTwoProvider/src/main/kotlin/com/lagradost/TrailersTwoProvider.kt create mode 100644 TrailersTwoProvider/src/main/kotlin/com/lagradost/TrailersTwoProviderPlugin.kt rename {TheFlixToProvider => VidSrcProvider}/build.gradle.kts (85%) create mode 100644 VidSrcProvider/src/main/AndroidManifest.xml create mode 100644 VidSrcProvider/src/main/kotlin/com/lagradost/VidSrcProvider.kt create mode 100644 VidSrcProvider/src/main/kotlin/com/lagradost/VidSrcProviderPlugin.kt diff --git a/OlgplyProvider/build.gradle.kts b/OlgplyProvider/build.gradle.kts new file mode 100644 index 0000000..9099795 --- /dev/null +++ b/OlgplyProvider/build.gradle.kts @@ -0,0 +1,26 @@ +// use an integer for version numbers +version = 3 + + +cloudstream { + language = "en" + // All of these properties are optional, you can safely remove them + + description = "Uses TMDB" + authors = listOf("Blatzar") + + /** + * 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=olgply.com&sz=%size%" +} \ No newline at end of file diff --git a/TheFlixToProvider/src/main/AndroidManifest.xml b/OlgplyProvider/src/main/AndroidManifest.xml similarity index 100% rename from TheFlixToProvider/src/main/AndroidManifest.xml rename to OlgplyProvider/src/main/AndroidManifest.xml diff --git a/OlgplyProvider/src/main/kotlin/com/lagradost/OlgplyProvider.kt b/OlgplyProvider/src/main/kotlin/com/lagradost/OlgplyProvider.kt new file mode 100644 index 0000000..c2a0636 --- /dev/null +++ b/OlgplyProvider/src/main/kotlin/com/lagradost/OlgplyProvider.kt @@ -0,0 +1,115 @@ +package com.lagradost + +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.TvType +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.metaproviders.TmdbLink +import com.lagradost.cloudstream3.metaproviders.TmdbProvider +import com.lagradost.cloudstream3.network.WebViewResolver +import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities +import com.lagradost.nicehttp.requestCreator +import org.mozilla.javascript.Context +import org.mozilla.javascript.Scriptable +import org.mozilla.javascript.ScriptableObject + +class OlgplyProvider : TmdbProvider() { + override var mainUrl = "https://olgply.com" + override val apiName = "Olgply" + override var name = "Olgply" + override val instantLinkLoading = true + override val useMetaLoadResponse = true + override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie) + + private suspend fun loadLinksWithWebView( + url: String, +// subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val foundVideo = WebViewResolver( + Regex("""\.m3u8|i7njdjvszykaieynzsogaysdgb0hm8u1mzubmush4maopa4wde\.com""") + ).resolveUsingWebView( + requestCreator( + "GET", url, referer = "https://olgply.xyz/" + ) + ) + .first ?: return + + callback.invoke( + ExtractorLink( + this.name, + "Movies4Discord", + foundVideo.url.toString(), + "", + Qualities.Unknown.value, + true + ) + ) + } + + + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + val mappedData = parseJson(data) + val tmdbId = mappedData.tmdbID ?: return false + val jsRegex = Regex("""eval\(.*\);""") + + val apiUrl = + "https://olgply.xyz/${tmdbId}${mappedData.season?.let { "/$it" } ?: ""}${mappedData.episode?.let { "/$it" } ?: ""}" +// val html = +// app.get(apiUrl, referer = "https://olgply.xyz/").text +// val rhino = Context.enter() +// rhino.optimizationLevel = -1 +// val scope: Scriptable = rhino.initSafeStandardObjects() +// val documentJs = """ +// Plyr = function(){}; +// +// hlsPrototype = { +// loadSource(url) { +// this.url = url; +// } +// }; +// +// function Hls() {}; +// Hls.isSupported = function(){return true}; +// +// Hls.prototype = hlsPrototype; +// Hls.prototype.constructor = Hls; +// +// document = { +// "querySelector" : function() {} +// }; +// """.trimIndent() +// +// val foundJs = jsRegex.find(html)?.groupValues?.getOrNull(0) ?: return false +// try { +// rhino.evaluateString(scope, documentJs + foundJs, "JavaScript", 1, null) +// } catch (e: Exception) { +// } +// +// val hls = scope.get("hls", scope) as? ScriptableObject +// +// if (hls != null) { +// callback.invoke( +// ExtractorLink( +// this.name, +// this.name, +// hls["url"].toString(), +// this.mainUrl + "/", +// Qualities.Unknown.value, +// headers = mapOf("range" to "bytes=0-"), +// isM3u8 = true +// ) +// ) +// } else { + // Disgraceful fallback, but the js for Movies4Discord refuses to work correctly :( + loadLinksWithWebView(apiUrl, callback) +// } + return true + } +} \ No newline at end of file diff --git a/TheFlixToProvider/src/main/kotlin/com/lagradost/TheFlixToProviderPlugin.kt b/OlgplyProvider/src/main/kotlin/com/lagradost/OlgplyProviderPlugin.kt similarity index 79% rename from TheFlixToProvider/src/main/kotlin/com/lagradost/TheFlixToProviderPlugin.kt rename to OlgplyProvider/src/main/kotlin/com/lagradost/OlgplyProviderPlugin.kt index 6eb5cfa..6ec160a 100644 --- a/TheFlixToProvider/src/main/kotlin/com/lagradost/TheFlixToProviderPlugin.kt +++ b/OlgplyProvider/src/main/kotlin/com/lagradost/OlgplyProviderPlugin.kt @@ -6,9 +6,9 @@ import com.lagradost.cloudstream3.plugins.Plugin import android.content.Context @CloudstreamPlugin -class TheFlixToProviderPlugin: Plugin() { +class OlgplyProviderPlugin: Plugin() { override fun load(context: Context) { // All providers should be added in this manner. Please don't edit the providers list directly. - registerMainAPI(TheFlixToProvider()) + registerMainAPI(OlgplyProvider()) } } \ 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 deleted file mode 100644 index 430fa85..0000000 --- a/TheFlixToProvider/src/main/kotlin/com/lagradost/TheFlixToProvider.kt +++ /dev/null @@ -1,621 +0,0 @@ -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.AppUtils.tryParseJson -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 { - println("query: $query") - val parsedFilter = tryParseJson(query) - val searchTitle = 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=$searchTitle", // TODO add genre filter - "$mainUrl/tv-shows/trending${yearFilter}?search=$searchTitle" - ) - 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/TrailersTwoProvider/build.gradle.kts b/TrailersTwoProvider/build.gradle.kts new file mode 100644 index 0000000..98ca853 --- /dev/null +++ b/TrailersTwoProvider/build.gradle.kts @@ -0,0 +1,30 @@ +// 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( + "Cartoon", + "Anime", + "Movie", + "AnimeMovie", + "TvSeries", + ) + + + iconUrl = "https://www.google.com/s2/favicons?domain=trailers.to&sz=%size%" +} \ No newline at end of file diff --git a/TrailersTwoProvider/src/main/AndroidManifest.xml b/TrailersTwoProvider/src/main/AndroidManifest.xml new file mode 100644 index 0000000..29aec9d --- /dev/null +++ b/TrailersTwoProvider/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/TrailersTwoProvider/src/main/kotlin/com/lagradost/TrailersTwoProvider.kt b/TrailersTwoProvider/src/main/kotlin/com/lagradost/TrailersTwoProvider.kt new file mode 100644 index 0000000..d7d5212 --- /dev/null +++ b/TrailersTwoProvider/src/main/kotlin/com/lagradost/TrailersTwoProvider.kt @@ -0,0 +1,319 @@ +package com.lagradost + +import com.fasterxml.jackson.annotation.JsonProperty +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.Qualities +import com.lagradost.cloudstream3.utils.SubtitleHelper + +class TrailersTwoProvider : TmdbProvider() { + val user = "cloudstream" + override val apiName = "Trailers.to" + override var name = "Trailers.to" + override var mainUrl = "https://trailers.to" + override val useMetaLoadResponse = true + override val instantLinkLoading = true + + data class TrailersEpisode( + // val tvShowItemID: Long?, + //val tvShow: String, + //val tvShowIMDB: String?, + //val tvShowTMDB: Long?, + @JsonProperty("ItemID") + val itemID: Int, + //val title: String, + //@JsonProperty("IMDb") + @JsonProperty("IMDb") + val imdb: String?, + //@JsonProperty("TMDb") + @JsonProperty("TMDb") + val tmdb: Int?, + //val releaseDate: String, + //val entryDate: String + ) + + data class TrailersMovie( + @JsonProperty("ItemID") + val itemID: Int, + @JsonProperty("IMDb") + val imdb: String?, + @JsonProperty("TMDb") + val tmdb: Int?, + //@JsonProperty("Title") + //val title: String?, + ) + + /*companion object { + private var tmdbToIdMovies: HashMap = hashMapOf() + private var imdbToIdMovies: HashMap = hashMapOf() + private var tmdbToIdTvSeries: HashMap = hashMapOf() + private var imdbToIdTvSeries: HashMap = hashMapOf() + + private const val startDate = 1900 + private const val endDate = 9999 + + fun getEpisode(tmdb: Int?, imdb: String?): Int? { + var currentId: Int? = null + if (tmdb != null) { + currentId = tmdbToIdTvSeries[tmdb] + } + if (imdb != null && currentId == null) { + currentId = imdbToIdTvSeries[imdb] + } + return currentId + } + + fun getMovie(tmdb: Int?, imdb: String?): Int? { + var currentId: Int? = null + if (tmdb != null) { + currentId = tmdbToIdMovies[tmdb] + } + if (imdb != null && currentId == null) { + currentId = imdbToIdMovies[imdb] + } + return currentId + } + + suspend fun fillData(isMovie: Boolean) { + if (isMovie) { + if (tmdbToIdMovies.isNotEmpty() || imdbToIdMovies.isNotEmpty()) { + return + } + parseJson>( + app.get( + "https://trailers.to/movies?from=$startDate-01-01&to=$endDate", + timeout = 30 + ).text + ).forEach { movie -> + movie.imdb?.let { + imdbToIdTvSeries[it] = movie.itemID + } + movie.tmdb?.let { + tmdbToIdTvSeries[it] = movie.itemID + } + } + } else { + if (tmdbToIdTvSeries.isNotEmpty() || imdbToIdTvSeries.isNotEmpty()) { + return + } + parseJson>( + app.get( + "https://trailers.to/episodes?from=$startDate-01-01&to=$endDate", + timeout = 30 + ).text + ).forEach { episode -> + episode.imdb?.let { + imdbToIdTvSeries[it] = episode.itemID + } + episode.tmdb?.let { + tmdbToIdTvSeries[it] = episode.itemID + } + } + } + } + }*/ + + override val supportedTypes = setOf( + TvType.Movie, + TvType.TvSeries, + //TvType.AnimeMovie, + //TvType.Anime, + //TvType.Cartoon + ) + + 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 (videoUrl, subtitleUrl) = if (isMovie) { + val suffix = "$user/$site/$id" + Pair( + "https://trailers.to/video/$suffix", + "https://trailers.to/subtitles/$suffix" + ) + } else { + val suffix = "$user/$site/$id/S${mappedData.season ?: 1}E${mappedData.episode ?: 1}" + Pair( + "https://trailers.to/video/$suffix", + "https://trailers.to/subtitles/$suffix" + ) + } + + callback.invoke( + ExtractorLink( + this.name, + this.name, + videoUrl, + "https://trailers.to", + Qualities.Unknown.value, + false, + ) + ) + + argamap( + { + val subtitles = + app.get(subtitleUrl).text + val subtitlesMapped = parseJson>(subtitles) + subtitlesMapped.forEach { + subtitleCallback.invoke( + SubtitleFile( + SubtitleHelper.fromTwoLettersToLanguage(it.LanguageCode ?: "en") + ?: "English", + "https://trailers.to/subtitles/${it.ContentHash ?: return@forEach}/${it.LanguageCode ?: return@forEach}.vtt" // ${it.MetaInfo?.SubFormat ?: "srt"}" + ) + ) + } + }, { + //https://trailers.to/en/quick-search?q=iron man + val name = mappedData.movieName + if (name != null && isMovie) { + app.get("https://trailers.to/en/quick-search?q=${name}").document.select("a.post-minimal") + .mapNotNull { + it?.attr("href") + }.map { Regex("""/movie/(\d+)/""").find(it)?.groupValues?.getOrNull(1) } + .firstOrNull()?.let { movieId -> + val correctUrl = app.get(videoUrl).url + callback.invoke( + ExtractorLink( + this.name, + "${this.name} Backup", + correctUrl.replace("/$user/0/", "/$user/$movieId/"), + "https://trailers.to", + Qualities.Unknown.value, + false, + ) + ) + } + } + } + ) + + /* + // the problem with this code is that it tages ages and the json file is 50mb or so for movies + fillData(isMovie) + val movieId = if (isMovie) { + getMovie(mappedData.tmdbID, mappedData.imdbID) + } else { + getEpisode(mappedData.tmdbID, mappedData.imdbID) + } ?: return@argamap + val request = app.get(data) + val endUrl = request.url + callback.invoke( + ExtractorLink( + this.name, + "${this.name} Backup", + endUrl.replace("/cloudstream/0/", "/cloudstream/$movieId/"), + "https://trailers.to", + Qualities.Unknown.value, + false, + ) + ) + */ + + return true + } +} + +// Auto generated +data class TrailersSubtitleFile( + @JsonProperty("SubtitleID") val SubtitleID: Int?, + @JsonProperty("ItemID") val ItemID: Int?, + @JsonProperty("ContentText") val ContentText: String?, + @JsonProperty("ContentHash") val ContentHash: String?, + @JsonProperty("LanguageCode") val LanguageCode: String?, + @JsonProperty("MetaInfo") val MetaInfo: MetaInfo?, + @JsonProperty("EntryDate") val EntryDate: String?, + @JsonProperty("ItemSubtitleAdaptations") val ItemSubtitleAdaptations: List?, + @JsonProperty("ReleaseNames") val ReleaseNames: List?, + @JsonProperty("SubFileNames") val SubFileNames: List?, + @JsonProperty("Framerates") val Framerates: List?, + @JsonProperty("IsRelevant") val IsRelevant: Boolean? +) + +data class QueryParameters( + @JsonProperty("imdbid") val imdbid: String? +) + +data class MetaInfo( + @JsonProperty("MatchedBy") val MatchedBy: String?, + @JsonProperty("IDSubMovieFile") val IDSubMovieFile: String?, + @JsonProperty("MovieHash") val MovieHash: String?, + @JsonProperty("MovieByteSize") val MovieByteSize: String?, + @JsonProperty("MovieTimeMS") val MovieTimeMS: String?, + @JsonProperty("IDSubtitleFile") val IDSubtitleFile: String?, + @JsonProperty("SubFileName") val SubFileName: String?, + @JsonProperty("SubActualCD") val SubActualCD: String?, + @JsonProperty("SubSize") val SubSize: String?, + @JsonProperty("SubHash") val SubHash: String?, + @JsonProperty("SubLastTS") val SubLastTS: String?, + @JsonProperty("SubTSGroup") val SubTSGroup: String?, + @JsonProperty("InfoReleaseGroup") val InfoReleaseGroup: String?, + @JsonProperty("InfoFormat") val InfoFormat: String?, + @JsonProperty("InfoOther") val InfoOther: String?, + @JsonProperty("IDSubtitle") val IDSubtitle: String?, + @JsonProperty("UserID") val UserID: String?, + @JsonProperty("SubLanguageID") val SubLanguageID: String?, + @JsonProperty("SubFormat") val SubFormat: String?, + @JsonProperty("SubSumCD") val SubSumCD: String?, + @JsonProperty("SubAuthorComment") val SubAuthorComment: String?, + @JsonProperty("SubAddDate") val SubAddDate: String?, + @JsonProperty("SubBad") val SubBad: String?, + @JsonProperty("SubRating") val SubRating: String?, + @JsonProperty("SubSumVotes") val SubSumVotes: String?, + @JsonProperty("SubDownloadsCnt") val SubDownloadsCnt: String?, + @JsonProperty("MovieReleaseName") val MovieReleaseName: String?, + @JsonProperty("MovieFPS") val MovieFPS: String?, + @JsonProperty("IDMovie") val IDMovie: String?, + @JsonProperty("IDMovieImdb") val IDMovieImdb: String?, + @JsonProperty("MovieName") val MovieName: String?, + @JsonProperty("MovieNameEng") val MovieNameEng: String?, + @JsonProperty("MovieYear") val MovieYear: String?, + @JsonProperty("MovieImdbRating") val MovieImdbRating: String?, + @JsonProperty("SubFeatured") val SubFeatured: String?, + @JsonProperty("UserNickName") val UserNickName: String?, + @JsonProperty("SubTranslator") val SubTranslator: String?, + @JsonProperty("ISO639") val ISO639: String?, + @JsonProperty("LanguageName") val LanguageName: String?, + @JsonProperty("SubComments") val SubComments: String?, + @JsonProperty("SubHearingImpaired") val SubHearingImpaired: String?, + @JsonProperty("UserRank") val UserRank: String?, + @JsonProperty("SeriesSeason") val SeriesSeason: String?, + @JsonProperty("SeriesEpisode") val SeriesEpisode: String?, + @JsonProperty("MovieKind") val MovieKind: String?, + @JsonProperty("SubHD") val SubHD: String?, + @JsonProperty("SeriesIMDBParent") val SeriesIMDBParent: String?, + @JsonProperty("SubEncoding") val SubEncoding: String?, + @JsonProperty("SubAutoTranslation") val SubAutoTranslation: String?, + @JsonProperty("SubForeignPartsOnly") val SubForeignPartsOnly: String?, + @JsonProperty("SubFromTrusted") val SubFromTrusted: String?, + @JsonProperty("QueryCached") val QueryCached: Int?, + @JsonProperty("SubTSGroupHash") val SubTSGroupHash: String?, + @JsonProperty("SubDownloadLink") val SubDownloadLink: String?, + @JsonProperty("ZipDownloadLink") val ZipDownloadLink: String?, + @JsonProperty("SubtitlesLink") val SubtitlesLink: String?, + @JsonProperty("QueryNumber") val QueryNumber: String?, + @JsonProperty("QueryParameters") val QueryParameters: QueryParameters?, + @JsonProperty("Score") val Score: Double? +) + +data class ItemSubtitleAdaptations( + @JsonProperty("ContentHash") val ContentHash: String?, + @JsonProperty("OffsetMs") val OffsetMs: Int?, + @JsonProperty("Framerate") val Framerate: Int?, + @JsonProperty("Views") val Views: Int?, + @JsonProperty("EntryDate") val EntryDate: String?, + @JsonProperty("Subtitle") val Subtitle: String? +) \ No newline at end of file diff --git a/TrailersTwoProvider/src/main/kotlin/com/lagradost/TrailersTwoProviderPlugin.kt b/TrailersTwoProvider/src/main/kotlin/com/lagradost/TrailersTwoProviderPlugin.kt new file mode 100644 index 0000000..459713d --- /dev/null +++ b/TrailersTwoProvider/src/main/kotlin/com/lagradost/TrailersTwoProviderPlugin.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 TrailersTwoProviderPlugin: Plugin() { + override fun load(context: Context) { + // All providers should be added in this manner. Please don't edit the providers list directly. + registerMainAPI(TrailersTwoProvider()) + } +} \ No newline at end of file diff --git a/TheFlixToProvider/build.gradle.kts b/VidSrcProvider/build.gradle.kts similarity index 85% rename from TheFlixToProvider/build.gradle.kts rename to VidSrcProvider/build.gradle.kts index 0526dcb..f8d7a8e 100644 --- a/TheFlixToProvider/build.gradle.kts +++ b/VidSrcProvider/build.gradle.kts @@ -22,5 +22,4 @@ cloudstream { "Movie", ) - iconUrl = "https://www.google.com/s2/favicons?domain=theflix.to&sz=%size%" -} \ No newline at end of file + } \ No newline at end of file diff --git a/VidSrcProvider/src/main/AndroidManifest.xml b/VidSrcProvider/src/main/AndroidManifest.xml new file mode 100644 index 0000000..29aec9d --- /dev/null +++ b/VidSrcProvider/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/VidSrcProvider/src/main/kotlin/com/lagradost/VidSrcProvider.kt b/VidSrcProvider/src/main/kotlin/com/lagradost/VidSrcProvider.kt new file mode 100644 index 0000000..012cae9 --- /dev/null +++ b/VidSrcProvider/src/main/kotlin/com/lagradost/VidSrcProvider.kt @@ -0,0 +1,53 @@ +package com.lagradost + +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.TvType +//import com.lagradost.cloudstream3.extractors.VidSrcExtractor +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.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, + ) + +// companion object { +// val extractor = VidSrcExtractor() +// } + + 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" + } + + loadExtractor(embedUrl, null, subtitleCallback, callback) +// extractor.getSafeUrl(embedUrl, null, subtitleCallback, callback) + + return true + } +} \ No newline at end of file diff --git a/VidSrcProvider/src/main/kotlin/com/lagradost/VidSrcProviderPlugin.kt b/VidSrcProvider/src/main/kotlin/com/lagradost/VidSrcProviderPlugin.kt new file mode 100644 index 0000000..6dd1352 --- /dev/null +++ b/VidSrcProvider/src/main/kotlin/com/lagradost/VidSrcProviderPlugin.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 VidSrcProviderPlugin: Plugin() { + override fun load(context: Context) { + // All providers should be added in this manner. Please don't edit the providers list directly. + registerMainAPI(VidSrcProvider()) + } +} \ No newline at end of file