forked from recloudstream/cloudstream
		
	fixed #461
This commit is contained in:
		
							parent
							
								
									fd6eee635f
								
							
						
					
					
						commit
						44c7d5ff8c
					
				
					 46 changed files with 307 additions and 253 deletions
				
			
		|  | @ -231,24 +231,24 @@ abstract class MainAPI { | |||
|     open val vpnStatus = VPNStatus.None | ||||
|     open val providerType = ProviderType.DirectProvider | ||||
| 
 | ||||
|     open fun getMainPage(): HomePageResponse? { | ||||
|     suspend open fun getMainPage(): HomePageResponse? { | ||||
|         throw NotImplementedError() | ||||
|     } | ||||
| 
 | ||||
|     open fun search(query: String): List<SearchResponse>? { | ||||
|     suspend open fun search(query: String): List<SearchResponse>? { | ||||
|         throw NotImplementedError() | ||||
|     } | ||||
| 
 | ||||
|     open fun quickSearch(query: String): List<SearchResponse>? { | ||||
|     suspend open fun quickSearch(query: String): List<SearchResponse>? { | ||||
|         throw NotImplementedError() | ||||
|     } | ||||
| 
 | ||||
|     open fun load(url: String): LoadResponse? { | ||||
|     suspend open fun load(url: String): LoadResponse? { | ||||
|         throw NotImplementedError() | ||||
|     } | ||||
| 
 | ||||
|     /**Callback is fired once a link is found, will return true if method is executed successfully*/ | ||||
|     open fun loadLinks( | ||||
|     suspend open fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -85,7 +85,7 @@ class AllAnimeProvider : MainAPI() { | |||
|         @JsonProperty("data") val data: Data | ||||
|     ) | ||||
| 
 | ||||
|     override fun search(query: String): ArrayList<SearchResponse> { | ||||
|     override suspend fun search(query: String): ArrayList<SearchResponse> { | ||||
|         val link = | ||||
|             """$mainUrl/graphql?variables=%7B%22search%22%3A%7B%22allowAdult%22%3Afalse%2C%22query%22%3A%22$query%22%7D%2C%22limit%22%3A26%2C%22page%22%3A1%2C%22translationType%22%3A%22sub%22%7D&extensions=%7B%22persistedQuery%22%3A%7B%22version%22%3A1%2C%22sha256Hash%22%3A%229343797cc3d9e3f444e2d3b7db9a84d759b816a4d84512ea72d079f85bb96e98%22%7D%7D""" | ||||
|         var res = app.get(link).text | ||||
|  | @ -123,7 +123,7 @@ class AllAnimeProvider : MainAPI() { | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse? { | ||||
|     override suspend fun load(url: String): LoadResponse? { | ||||
|         val rhino = Context.enter() | ||||
|         rhino.initStandardObjects() | ||||
|         rhino.optimizationLevel = -1 | ||||
|  | @ -238,7 +238,7 @@ class AllAnimeProvider : MainAPI() { | |||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ class AnimeFlickProvider : MainAPI() { | |||
|         TvType.ONA | ||||
|     ) | ||||
| 
 | ||||
|     override fun search(query: String): ArrayList<SearchResponse> { | ||||
|     override suspend fun search(query: String): ArrayList<SearchResponse> { | ||||
|         val link = "https://animeflick.net/search.php?search=$query" | ||||
|         val html = app.get(link).text | ||||
|         val doc = Jsoup.parse(html) | ||||
|  | @ -48,7 +48,7 @@ class AnimeFlickProvider : MainAPI() { | |||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val html = app.get(url).text | ||||
|         val doc = Jsoup.parse(html) | ||||
| 
 | ||||
|  | @ -79,7 +79,7 @@ class AnimeFlickProvider : MainAPI() { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ class AnimePaheProvider : MainAPI() { | |||
|         TvType.ONA | ||||
|     ) | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         data class Data( | ||||
|             @JsonProperty("id") val id: Int, | ||||
|             @JsonProperty("anime_id") val animeId: Int, | ||||
|  | @ -139,7 +139,7 @@ class AnimePaheProvider : MainAPI() { | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     override fun search(query: String): ArrayList<SearchResponse> { | ||||
|     override suspend fun search(query: String): ArrayList<SearchResponse> { | ||||
|         val url = "$mainUrl/api?m=search&l=8&q=$query" | ||||
|         val headers = mapOf("referer" to "$mainUrl/") | ||||
| 
 | ||||
|  | @ -242,7 +242,7 @@ class AnimePaheProvider : MainAPI() { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse? { | ||||
|     override suspend fun load(url: String): LoadResponse? { | ||||
|         return normalSafeApiCall { | ||||
| 
 | ||||
|             val regex = Regex("""a/(\d+)\?slug=(.+)""") | ||||
|  | @ -541,7 +541,7 @@ class AnimePaheProvider : MainAPI() { | |||
|         return qualities | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -92,7 +92,7 @@ class DubbedAnimeProvider : MainAPI() { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val trendingUrl = "$mainUrl/xz/trending.php?_=$unixTimeMS" | ||||
|         val lastEpisodeUrl = "$mainUrl/xz/epgrid.php?p=1&_=$unixTimeMS" | ||||
|         val recentlyAddedUrl = "$mainUrl/xz/gridgrabrecent.php?p=1&_=$unixTimeMS" | ||||
|  | @ -126,7 +126,7 @@ class DubbedAnimeProvider : MainAPI() { | |||
|         return href.replace("$mainUrl/", "") | ||||
|     } | ||||
| 
 | ||||
|     override fun quickSearch(query: String): List<SearchResponse> { | ||||
|     override suspend fun quickSearch(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/xz/searchgrid.php?p=1&limit=12&s=$query&_=$unixTime" | ||||
|         val response = app.get(url).text | ||||
|         val document = Jsoup.parse(response) | ||||
|  | @ -158,7 +158,7 @@ class DubbedAnimeProvider : MainAPI() { | |||
|         return returnValue | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/search/$query" | ||||
|         val response = app.get(url).text | ||||
|         val document = Jsoup.parse(response) | ||||
|  | @ -193,7 +193,7 @@ class DubbedAnimeProvider : MainAPI() { | |||
|         return returnValue | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  | @ -230,7 +230,7 @@ class DubbedAnimeProvider : MainAPI() { | |||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         if (getIsMovie(url)) { | ||||
|             val realSlug = url.replace("movies/", "") | ||||
|             val episode = getAnimeEpisode(realSlug, true) | ||||
|  |  | |||
|  | @ -37,7 +37,7 @@ class GogoanimeProvider : MainAPI() { | |||
|         TvType.ONA | ||||
|     ) | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val headers = mapOf( | ||||
|             "authority" to "ajax.gogo-load.com", | ||||
|             "sec-ch-ua" to "\"Google Chrome\";v=\"89\", \"Chromium\";v=\"89\", \";Not A Brand\";v=\"99\"", | ||||
|  | @ -95,7 +95,7 @@ class GogoanimeProvider : MainAPI() { | |||
|         return HomePageResponse(items) | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): ArrayList<SearchResponse> { | ||||
|     override suspend fun search(query: String): ArrayList<SearchResponse> { | ||||
|         val link = "$mainUrl/search.html?keyword=$query" | ||||
|         val html = app.get(link).text | ||||
|         val doc = Jsoup.parse(html) | ||||
|  | @ -129,7 +129,7 @@ class GogoanimeProvider : MainAPI() { | |||
|         return uri | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val link = getProperAnimeLink(url) | ||||
|         val episodeloadApi = "https://ajax.gogo-load.com/ajax/load-list-episode" | ||||
|         val html = app.get(link).text | ||||
|  | @ -232,7 +232,7 @@ class GogoanimeProvider : MainAPI() { | |||
|             } | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ class KawaiifuProvider : MainAPI() { | |||
| 
 | ||||
|     override val supportedTypes = setOf(TvType.Anime, TvType.AnimeMovie, TvType.ONA) | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val items = ArrayList<HomePageList>() | ||||
|         val resp = app.get(mainUrl).text | ||||
| 
 | ||||
|  | @ -58,7 +58,7 @@ class KawaiifuProvider : MainAPI() { | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     override fun search(query: String): ArrayList<SearchResponse> { | ||||
|     override suspend fun search(query: String): ArrayList<SearchResponse> { | ||||
|         val link = "$mainUrl/search-movie?keyword=${query}" | ||||
|         val html = app.get(link).text | ||||
|         val soup = Jsoup.parse(html) | ||||
|  | @ -80,7 +80,7 @@ class KawaiifuProvider : MainAPI() { | |||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val html = app.get(url).text | ||||
|         val soup = Jsoup.parse(html) | ||||
| 
 | ||||
|  | @ -110,7 +110,7 @@ class KawaiifuProvider : MainAPI() { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -45,7 +45,7 @@ class TenshiProvider : MainAPI() { | |||
|         } | ||||
|     }*/ | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val items = ArrayList<HomePageList>() | ||||
|         val soup = app.get(mainUrl, interceptor = ddosGuardKiller).document | ||||
|         for (section in soup.select("#content > section")) { | ||||
|  | @ -152,7 +152,7 @@ class TenshiProvider : MainAPI() { | |||
| //        @JsonProperty("cen") var cen : String | ||||
| //    ) | ||||
| 
 | ||||
| //    override fun quickSearch(query: String): ArrayList<SearchResponse>? { | ||||
| //    override suspend fun quickSearch(query: String): ArrayList<SearchResponse>? { | ||||
| //        if (!autoLoadToken()) return quickSearch(query) | ||||
| //        val url = "$mainUrl/anime/search" | ||||
| //        val response = khttp.post( | ||||
|  | @ -192,7 +192,7 @@ class TenshiProvider : MainAPI() { | |||
| //        return returnValue | ||||
| //    } | ||||
| 
 | ||||
|     override fun search(query: String): ArrayList<SearchResponse> { | ||||
|     override suspend fun search(query: String): ArrayList<SearchResponse> { | ||||
|         val url = "$mainUrl/anime" | ||||
|         var document = app.get( | ||||
|             url, | ||||
|  | @ -220,7 +220,7 @@ class TenshiProvider : MainAPI() { | |||
|         return ArrayList(returnValue) | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         var document = app.get( | ||||
|             url, | ||||
|             cookies = mapOf("loop-view" to "thumb"), | ||||
|  | @ -292,7 +292,7 @@ class TenshiProvider : MainAPI() { | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -22,7 +22,7 @@ class WatchCartoonOnlineProvider : MainAPI() { | |||
|         TvType.TvSeries | ||||
|     ) | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "https://www.wcostream.com/search" | ||||
| 
 | ||||
|         var response = | ||||
|  | @ -97,7 +97,7 @@ class WatchCartoonOnlineProvider : MainAPI() { | |||
|         return returnValue | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val isMovie = !url.contains("/anime/") | ||||
|         val response = app.get(url).text | ||||
|         val document = Jsoup.parse(response) | ||||
|  | @ -183,7 +183,7 @@ class WatchCartoonOnlineProvider : MainAPI() { | |||
|         val server: String, | ||||
|     ) | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ class WcoProvider : MainAPI() { | |||
|         TvType.ONA | ||||
|     ) | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val urls = listOf( | ||||
|             Pair("$mainUrl/ajax/list/recently_updated?type=tv", "Recently Updated Anime"), | ||||
|             Pair("$mainUrl/ajax/list/recently_updated?type=movie", "Recently Updated Movies"), | ||||
|  | @ -108,7 +108,7 @@ class WcoProvider : MainAPI() { | |||
|         return returnValue | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/search" | ||||
|         val response = | ||||
|             app.get(url, params = mapOf("keyword" to query)) | ||||
|  | @ -128,7 +128,7 @@ class WcoProvider : MainAPI() { | |||
|         return returnValue | ||||
|     } | ||||
| 
 | ||||
|     override fun quickSearch(query: String): List<SearchResponse> { | ||||
|     override suspend fun quickSearch(query: String): List<SearchResponse> { | ||||
|         val returnValue: ArrayList<SearchResponse> = ArrayList() | ||||
| 
 | ||||
|         val response = JSONObject( | ||||
|  | @ -170,7 +170,7 @@ class WcoProvider : MainAPI() { | |||
|         return returnValue | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val response = app.get(url, timeout = 120).text | ||||
|         val document = Jsoup.parse(response) | ||||
| 
 | ||||
|  | @ -216,7 +216,7 @@ class WcoProvider : MainAPI() { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -69,7 +69,7 @@ class ZoroProvider : MainAPI() { | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val html = app.get("$mainUrl/home").text | ||||
|         val document = Jsoup.parse(html) | ||||
| 
 | ||||
|  | @ -99,7 +99,7 @@ class ZoroProvider : MainAPI() { | |||
|         @JsonProperty("html") val html: String | ||||
|     ) | ||||
| 
 | ||||
| //    override fun quickSearch(query: String): List<SearchResponse> { | ||||
| //    override suspend fun quickSearch(query: String): List<SearchResponse> { | ||||
| //        val url = "$mainUrl/ajax/search/suggest?keyword=${query}" | ||||
| //        val html = mapper.readValue<Response>(khttp.get(url).text).html | ||||
| //        val document = Jsoup.parse(html) | ||||
|  | @ -126,7 +126,7 @@ class ZoroProvider : MainAPI() { | |||
| //        } | ||||
| //    } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val link = "$mainUrl/search?keyword=$query" | ||||
|         val html = app.get(link).text | ||||
|         val document = Jsoup.parse(html) | ||||
|  | @ -172,7 +172,7 @@ class ZoroProvider : MainAPI() { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val html = app.get(url).text | ||||
|         val document = Jsoup.parse(html) | ||||
| 
 | ||||
|  | @ -274,7 +274,7 @@ class ZoroProvider : MainAPI() { | |||
|         @JsonProperty("link") val link: String | ||||
|     ) | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -161,7 +161,7 @@ open class TmdbProvider : MainAPI() { | |||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
| 
 | ||||
|         // SAME AS DISCOVER IT SEEMS | ||||
| //        val popularSeries = tmdb.tvService().popular(1, "en-US").execute().body()?.results?.map { | ||||
|  | @ -220,7 +220,7 @@ open class TmdbProvider : MainAPI() { | |||
|     } | ||||
| 
 | ||||
|     // Possible to add recommendations and such here. | ||||
|     override fun load(url: String): LoadResponse? { | ||||
|     override suspend fun load(url: String): LoadResponse? { | ||||
|         // https://www.themoviedb.org/movie/7445-brothers | ||||
|         // https://www.themoviedb.org/tv/71914-the-wheel-of-time | ||||
| 
 | ||||
|  | @ -262,7 +262,7 @@ open class TmdbProvider : MainAPI() { | |||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse>? { | ||||
|     override suspend fun search(query: String): List<SearchResponse>? { | ||||
|         return tmdb.searchService().multi(query, 1, "en-Us", "US", true).execute() | ||||
|             .body()?.results?.mapNotNull { | ||||
|                 it.movie?.toSearchResponse() ?: it.tvShow?.toSearchResponse() | ||||
|  |  | |||
|  | @ -34,7 +34,7 @@ class AkwamProvider : MainAPI() { | |||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         // Title, Url | ||||
|         val moviesUrl = listOf( | ||||
|             "Movies" to "$mainUrl/movies", | ||||
|  | @ -51,7 +51,7 @@ class AkwamProvider : MainAPI() { | |||
|         return HomePageResponse(pages) | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/search?q=$query" | ||||
|         val doc = app.get(url).document | ||||
|         return doc.select("div.col-lg-auto").mapNotNull { | ||||
|  | @ -80,7 +80,7 @@ class AkwamProvider : MainAPI() { | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val doc = app.get(url).document | ||||
|         val isMovie = url.contains("/movie/") | ||||
|         val title = doc.select("h1.entry-title").text() | ||||
|  | @ -164,7 +164,7 @@ class AkwamProvider : MainAPI() { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -28,7 +28,7 @@ class AllMoviesForYouProvider : MainAPI() { | |||
|         TvType.TvSeries | ||||
|     ) | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/?s=$query" | ||||
|         val document = app.get(url).document | ||||
| 
 | ||||
|  | @ -76,7 +76,7 @@ class AllMoviesForYouProvider : MainAPI() { | |||
|         return if (list.isEmpty()) null else list | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val type = getType(url) | ||||
| 
 | ||||
|         val document = app.get(url).document | ||||
|  | @ -162,7 +162,7 @@ class AllMoviesForYouProvider : MainAPI() { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -112,7 +112,7 @@ class AsiaFlixProvider : MainAPI() { | |||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val headers = mapOf("X-Requested-By" to "asiaflix-web") | ||||
|         val response = app.get("$apiUrl/dashboard", headers = headers).text | ||||
| 
 | ||||
|  | @ -138,7 +138,7 @@ class AsiaFlixProvider : MainAPI() { | |||
|         @JsonProperty("url") val url: String?, | ||||
|     ) | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  | @ -162,14 +162,14 @@ class AsiaFlixProvider : MainAPI() { | |||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse>? { | ||||
|     override suspend fun search(query: String): List<SearchResponse>? { | ||||
|         val headers = mapOf("X-Requested-By" to "asiaflix-web") | ||||
|         val url = "$apiUrl/drama/search?q=$query" | ||||
|         val response = app.get(url, headers = headers).text | ||||
|         return mapper.readValue<List<Data>?>(response)?.map { it.toSearchResponse() } | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val headers = mapOf("X-Requested-By" to "asiaflix-web") | ||||
|         val requestUrl = "$apiUrl/drama?id=${url.split("/").lastOrNull()}" | ||||
|         val response = app.get(requestUrl, headers = headers).text | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ class DramaSeeProvider : MainAPI() { | |||
|     override val hasDownloadSupport = true | ||||
|     override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie) | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val headers = mapOf("X-Requested-By" to "dramasee.net") | ||||
|         val document = app.get(mainUrl, headers = headers).document | ||||
|         val mainbody = document.getElementsByTag("body") | ||||
|  | @ -50,7 +50,7 @@ class DramaSeeProvider : MainAPI() { | |||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/search?q=$query" | ||||
|         val html = app.get(url).document | ||||
|         val document = html.getElementsByTag("body") | ||||
|  | @ -78,7 +78,7 @@ class DramaSeeProvider : MainAPI() { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val doc = app.get(url).document | ||||
|         val body = doc.getElementsByTag("body") | ||||
|         val inner = body?.select("div.series-info") | ||||
|  | @ -149,7 +149,7 @@ class DramaSeeProvider : MainAPI() { | |||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -18,7 +18,7 @@ class FilmanProvider : MainAPI() { | |||
|         TvType.TvSeries | ||||
|     ) | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val response = app.get(mainUrl).text | ||||
|         val document = Jsoup.parse(response) | ||||
|         val lists = document.select(".item-list,.series-list") | ||||
|  | @ -54,7 +54,7 @@ class FilmanProvider : MainAPI() { | |||
|         return HomePageResponse(categories) | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/wyszukiwarka?phrase=$query" | ||||
|         val response = app.get(url).text | ||||
|         val document = Jsoup.parse(response) | ||||
|  | @ -79,7 +79,7 @@ class FilmanProvider : MainAPI() { | |||
|         return getVideos(TvType.Movie, movies) + getVideos(TvType.TvSeries, series) | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val response = app.get(url).text | ||||
|         val document = Jsoup.parse(response) | ||||
|         var title = document.select("span[itemprop=title]").text() | ||||
|  | @ -109,7 +109,7 @@ class FilmanProvider : MainAPI() { | |||
|         return TvSeriesLoadResponse(title, url, name, TvType.TvSeries, episodes, posterUrl, year, plot) | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ class HDMProvider : MainAPI() { | |||
|         TvType.Movie, | ||||
|     ) | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/search/$query" | ||||
|         val response = app.get(url).text | ||||
|         val document = Jsoup.parse(response) | ||||
|  | @ -32,7 +32,7 @@ class HDMProvider : MainAPI() { | |||
|         return returnValue | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  | @ -55,7 +55,7 @@ class HDMProvider : MainAPI() { | |||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse? { | ||||
|     override suspend fun load(url: String): LoadResponse? { | ||||
|         val response = app.get(url).text | ||||
|         val document = Jsoup.parse(response) | ||||
|         val title = document.selectFirst("h2.movieTitle")?.text() ?: throw ErrorLoadingException("No Data Found") | ||||
|  | @ -71,7 +71,7 @@ class HDMProvider : MainAPI() { | |||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val html = app.get("$mainUrl", timeout = 25).text | ||||
|         val document = Jsoup.parse(html) | ||||
|         val all = ArrayList<HomePageList>() | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ class IHaveNoTvProvider : MainAPI() { | |||
| 
 | ||||
|     override val supportedTypes = setOf(TvType.Documentary) | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         // Uhh, I am too lazy to scrape the "latest documentaries" and "recommended documentaries", | ||||
|         // so I am just scraping 3 random categories | ||||
|         val allCategories = listOf( | ||||
|  | @ -67,7 +67,7 @@ class IHaveNoTvProvider : MainAPI() { | |||
|         return HomePageResponse(items) | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): ArrayList<SearchResponse> { | ||||
|     override suspend fun search(query: String): ArrayList<SearchResponse> { | ||||
|         val url = """$mainUrl/search/${URLEncoder.encode(query, "UTF-8")}""" | ||||
|         val response = app.get(url).text | ||||
|         val soup = Jsoup.parse(response) | ||||
|  | @ -101,7 +101,7 @@ class IHaveNoTvProvider : MainAPI() { | |||
|         return ArrayList(searchResults.values) | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val isSeries = url.contains("/series/") | ||||
|         val html = app.get(url).text | ||||
|         val soup = Jsoup.parse(html) | ||||
|  | @ -190,7 +190,7 @@ class IHaveNoTvProvider : MainAPI() { | |||
|         ) else (episodes?.first() as MovieLoadResponse) | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ class KdramaHoodProvider : MainAPI() { | |||
|     override val hasDownloadSupport = true | ||||
|     override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie) | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val doc = app.get("$mainUrl/home2").document | ||||
|         val home = ArrayList<HomePageList>() | ||||
| 
 | ||||
|  | @ -59,7 +59,7 @@ class KdramaHoodProvider : MainAPI() { | |||
|         return HomePageResponse(home.filter { it.list.isNotEmpty() }) | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/?s=$query" | ||||
|         val html = app.get(url).document | ||||
|         val document = html.getElementsByTag("body") | ||||
|  | @ -87,7 +87,7 @@ class KdramaHoodProvider : MainAPI() { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val doc = app.get(url).document | ||||
|         val inner = doc.selectFirst("div.central") | ||||
| 
 | ||||
|  | @ -180,7 +180,7 @@ class KdramaHoodProvider : MainAPI() { | |||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -64,7 +64,7 @@ class LookMovieProvider : MainAPI() { | |||
|         @JsonProperty("season") var season: String, | ||||
|     ) | ||||
| 
 | ||||
|     override fun quickSearch(query: String): List<SearchResponse> { | ||||
|     override suspend fun quickSearch(query: String): List<SearchResponse> { | ||||
|         val movieUrl = "$mainUrl/api/v1/movies/search/?q=$query" | ||||
|         val movieResponse = app.get(movieUrl).text | ||||
|         val movies = mapper.readValue<LookMovieSearchResultRoot>(movieResponse).result | ||||
|  | @ -109,7 +109,7 @@ class LookMovieProvider : MainAPI() { | |||
|         return returnValue | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         fun search(query: String, isMovie: Boolean): ArrayList<SearchResponse> { | ||||
|             val url = "$mainUrl/${if (isMovie) "movies" else "shows"}/search/?q=$query" | ||||
|             val response = app.get(url).text | ||||
|  | @ -174,7 +174,7 @@ class LookMovieProvider : MainAPI() { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  | @ -198,7 +198,7 @@ class LookMovieProvider : MainAPI() { | |||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse? { | ||||
|     override suspend fun load(url: String): LoadResponse? { | ||||
|         val response = app.get(url).text | ||||
|         val document = Jsoup.parse(response) | ||||
|         val isMovie = url.contains("/movies/") | ||||
|  |  | |||
|  | @ -28,11 +28,11 @@ class MeloMovieProvider : MainAPI() { | |||
| 
 | ||||
|     data class MeloMovieLink(val name: String, val link: String) | ||||
| 
 | ||||
|     override fun quickSearch(query: String): List<SearchResponse> { | ||||
|     override suspend fun quickSearch(query: String): List<SearchResponse> { | ||||
|         return search(query) | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/movie/search/?name=$query" | ||||
|         val returnValue: ArrayList<SearchResponse> = ArrayList() | ||||
|         val response = app.get(url).text | ||||
|  | @ -98,7 +98,7 @@ class MeloMovieProvider : MainAPI() { | |||
|         return parsed.toJson() | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  | @ -111,7 +111,7 @@ class MeloMovieProvider : MainAPI() { | |||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse? { | ||||
|     override suspend fun load(url: String): LoadResponse? { | ||||
|         val response = app.get(url).text | ||||
| 
 | ||||
|         //backdrop = imgurl | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ class PelisplusHDProvider:MainAPI() { | |||
|         TvType.TvSeries, | ||||
|         TvType.Anime, | ||||
|     ) | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val items = ArrayList<HomePageList>() | ||||
|         val urls = listOf( | ||||
|             Pair("$mainUrl/peliculas", "Peliculas"), | ||||
|  | @ -55,7 +55,7 @@ class PelisplusHDProvider:MainAPI() { | |||
|         return HomePageResponse(items) | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "https://pelisplushd.net/search?s=${query}" | ||||
|         val html = app.get(url).text | ||||
|         val document = Jsoup.parse(html) | ||||
|  | @ -89,7 +89,7 @@ class PelisplusHDProvider:MainAPI() { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse? { | ||||
|     override suspend fun load(url: String): LoadResponse? { | ||||
|         val html = app.get(url).text | ||||
|         val soup = Jsoup.parse(html) | ||||
| 
 | ||||
|  | @ -146,7 +146,7 @@ class PelisplusHDProvider:MainAPI() { | |||
|             else -> null | ||||
|         } | ||||
|     } | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -35,7 +35,7 @@ open class PelisplusProviderTemplate : MainAPI() { | |||
| 
 | ||||
|     // Searching returns a SearchResponse, which can be one of the following: AnimeSearchResponse, MovieSearchResponse, TorrentSearchResponse, TvSeriesSearchResponse | ||||
|     // Each of the classes requires some different data, but always has some critical things like name, poster and url. | ||||
|     override fun search(query: String): ArrayList<SearchResponse> { | ||||
|     override suspend fun search(query: String): ArrayList<SearchResponse> { | ||||
|         // Simply looking at devtools network is enough to spot a request like: | ||||
|         // https://vidembed.cc/search.html?keyword=neverland where neverland is the query, can be written as below. | ||||
|         val link = "$mainUrl/search.html?keyword=$query" | ||||
|  | @ -68,7 +68,7 @@ open class PelisplusProviderTemplate : MainAPI() { | |||
| 
 | ||||
|     // Load, like the name suggests loads the info page, where all the episodes and data usually is. | ||||
|     // Like search you should return either of: AnimeLoadResponse, MovieLoadResponse, TorrentLoadResponse, TvSeriesLoadResponse. | ||||
|     override fun load(url: String): LoadResponse? { | ||||
|     override suspend fun load(url: String): LoadResponse? { | ||||
|         // Gets the url returned from searching. | ||||
|         val html = app.get(url).text | ||||
|         val soup = Jsoup.parse(html) | ||||
|  | @ -147,7 +147,7 @@ open class PelisplusProviderTemplate : MainAPI() { | |||
| 
 | ||||
|     // This loads the homepage, which is basically a collection of search results with labels. | ||||
|     // Optional function, but make sure to enable hasMainPage if you program this. | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val urls = homePageUrlList | ||||
|         val homePageList = ArrayList<HomePageList>() | ||||
|         // .pmap {} is used to fetch the different pages in parallel | ||||
|  | @ -201,7 +201,7 @@ open class PelisplusProviderTemplate : MainAPI() { | |||
|     // loadLinks gets the raw .mp4 or .m3u8 urls from the data parameter in the episodes class generated in load() | ||||
|     // See TvSeriesEpisode(...) in this provider. | ||||
|     // The data are usually links, but can be any other string to help aid loading the links. | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         // These callbacks are functions you should call when you get a link to a subtitle file or media file. | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ class PinoyHDXyzProvider : MainAPI() { | |||
|     override val hasQuickSearch = false | ||||
| 
 | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val all = ArrayList<HomePageList>() | ||||
|         val document = app.get(mainUrl, referer = mainUrl).document | ||||
|         val mainbody = document.getElementsByTag("body") | ||||
|  | @ -65,7 +65,7 @@ class PinoyHDXyzProvider : MainAPI() { | |||
|         return HomePageResponse(all) | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/search/?q=${query.replace(" ", "+")}" | ||||
|         val document = app.get(url).document.select("div.portfolio-thumb") | ||||
|         return document?.mapNotNull { | ||||
|  | @ -88,7 +88,7 @@ class PinoyHDXyzProvider : MainAPI() { | |||
|         }?.distinctBy { c -> c.url } ?: listOf() | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val doc = app.get(url).document | ||||
|         val body = doc.getElementsByTag("body") | ||||
|         val inner = body?.select("div.info") | ||||
|  | @ -203,7 +203,7 @@ class PinoyHDXyzProvider : MainAPI() { | |||
|         return MovieLoadResponse(title, url, this.name, tvtype, streamLinks, poster, year, descript, null, null) | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ class PinoyMoviePediaProvider : MainAPI() { | |||
|     override val hasMainPage = true | ||||
|     override val hasQuickSearch = false | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val all = ArrayList<HomePageList>() | ||||
|         val document = app.get(mainUrl).document | ||||
|         val mainbody = document.getElementsByTag("body") | ||||
|  | @ -72,7 +72,7 @@ class PinoyMoviePediaProvider : MainAPI() { | |||
|         return HomePageResponse(all.filter { a -> a.list.isNotEmpty() }) | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/?s=${query}" | ||||
|         val document = app.get(url).document.selectFirst("div.search-page") | ||||
|             ?.select("div.result-item") | ||||
|  | @ -97,7 +97,7 @@ class PinoyMoviePediaProvider : MainAPI() { | |||
|         }?.distinctBy { c -> c.url } ?: listOf() | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val doc = app.get(url).document | ||||
|         val body = doc.getElementsByTag("body") | ||||
|         val inner = body?.select("div.sheader") | ||||
|  | @ -171,7 +171,7 @@ class PinoyMoviePediaProvider : MainAPI() { | |||
|         return MovieLoadResponse(title, url, this.name, TvType.Movie, streamlinks, poster, year, descript, null, null) | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -58,7 +58,7 @@ class PinoyMoviesEsProvider : MainAPI() { | |||
|         } | ||||
|         return all | ||||
|     } | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val all = ArrayList<HomePageList>() | ||||
|         val html = app.get(mainUrl).text | ||||
|         val document = Jsoup.parse(html) | ||||
|  | @ -87,7 +87,7 @@ class PinoyMoviesEsProvider : MainAPI() { | |||
|         return HomePageResponse(all) | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/?s=${query}" | ||||
|         val html = app.get(url, interceptor = DdosGuardKiller(true)).text | ||||
|         //Log.i(this.name, "Result => (html) ${Jsoup.parse(html).getElementsByTag("body")}") | ||||
|  | @ -115,7 +115,7 @@ class PinoyMoviesEsProvider : MainAPI() { | |||
|         return listOf() | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val response = app.get(url).text | ||||
|         val doc = Jsoup.parse(response) | ||||
|         val body = doc.getElementsByTag("body") | ||||
|  | @ -185,7 +185,7 @@ class PinoyMoviesEsProvider : MainAPI() { | |||
|         return MovieLoadResponse(title, url, this.name, TvType.Movie, streamlinks, poster, year, descript, null, null) | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|             data: String, | ||||
|             isCasting: Boolean, | ||||
|             subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -1,9 +1,11 @@ | |||
| package com.lagradost.cloudstream3.movieproviders | ||||
| 
 | ||||
| import com.fasterxml.jackson.annotation.JsonProperty | ||||
| import com.fasterxml.jackson.module.kotlin.readValue | ||||
| import com.lagradost.cloudstream3.* | ||||
| import com.lagradost.cloudstream3.network.WebViewResolver | ||||
| import com.lagradost.cloudstream3.utils.AppUtils.parseJson | ||||
| import com.lagradost.cloudstream3.utils.AppUtils.toJson | ||||
| import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson | ||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | ||||
| import com.lagradost.cloudstream3.utils.M3u8Helper | ||||
| import com.lagradost.cloudstream3.utils.getQualityFromName | ||||
|  | @ -26,35 +28,7 @@ class SflixProvider(providerUrl: String, providerName: String) : MainAPI() { | |||
|     ) | ||||
|     override val vpnStatus = VPNStatus.None | ||||
| 
 | ||||
|     private fun Element.toSearchResult(): SearchResponse { | ||||
|         val img = this.select("img") | ||||
|         val title = img.attr("title") | ||||
|         val posterUrl = img.attr("data-src") | ||||
|         val href = fixUrl(this.select("a").attr("href")) | ||||
|         val isMovie = href.contains("/movie/") | ||||
|         return if (isMovie) { | ||||
|             MovieSearchResponse( | ||||
|                 title, | ||||
|                 href, | ||||
|                 this@SflixProvider.name, | ||||
|                 TvType.Movie, | ||||
|                 posterUrl, | ||||
|                 null | ||||
|             ) | ||||
|         } else { | ||||
|             TvSeriesSearchResponse( | ||||
|                 title, | ||||
|                 href, | ||||
|                 this@SflixProvider.name, | ||||
|                 TvType.Movie, | ||||
|                 posterUrl, | ||||
|                 null, | ||||
|                 null | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val html = app.get("$mainUrl/home").text | ||||
|         val document = Jsoup.parse(html) | ||||
| 
 | ||||
|  | @ -84,7 +58,7 @@ class SflixProvider(providerUrl: String, providerName: String) : MainAPI() { | |||
|         return HomePageResponse(all) | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/search/${query.replace(" ", "-")}" | ||||
|         val html = app.get(url).text | ||||
|         val document = Jsoup.parse(html) | ||||
|  | @ -119,7 +93,7 @@ class SflixProvider(providerUrl: String, providerName: String) : MainAPI() { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val document = app.get(url).document | ||||
| 
 | ||||
|         val details = document.select("div.detail_page-watch") | ||||
|  | @ -151,15 +125,16 @@ class SflixProvider(providerUrl: String, providerName: String) : MainAPI() { | |||
|             val episodes = app.get(episodesUrl).text | ||||
| 
 | ||||
|             // Supported streams, they're identical | ||||
|             val sourceId = Jsoup.parse(episodes).select("a").firstOrNull { | ||||
|                 it.select("span").text().trim().equals("RapidStream", ignoreCase = true) | ||||
|                         || it.select("span").text().trim().equals("Vidcloud", ignoreCase = true) | ||||
|             }?.attr("data-id") | ||||
|             val sourceIds = Jsoup.parse(episodes).select("a").mapNotNull { element -> | ||||
|                 val sourceId = element.attr("data-id") ?: return@mapNotNull null | ||||
|                 if(element.select("span")?.text()?.trim()?.isValidServer() == true) { | ||||
|                     "$url.$sourceId".replace("/movie/", "/watch-movie/") | ||||
|                 } else { | ||||
|                     null | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             val webViewUrl = | ||||
|                 "$url${sourceId?.let { ".$it" } ?: ""}".replace("/movie/", "/watch-movie/") | ||||
| 
 | ||||
|             return newMovieLoadResponse(title, url, TvType.Movie, webViewUrl) { | ||||
|             return newMovieLoadResponse(title, url, TvType.Movie, sourceIds.toJson()) { | ||||
|                 this.year = year | ||||
|                 this.posterUrl = posterUrl | ||||
|                 this.plot = plot | ||||
|  | @ -186,7 +161,8 @@ class SflixProvider(providerUrl: String, providerName: String) : MainAPI() { | |||
|                             episode++ | ||||
| 
 | ||||
|                             val episodeNum = | ||||
|                                 (it.select("div.episode-number")?.text() ?: episodeTitle).let { str -> | ||||
|                                 (it.select("div.episode-number")?.text() | ||||
|                                     ?: episodeTitle).let { str -> | ||||
|                                     Regex("""\d+""").find(str)?.groupValues?.firstOrNull() | ||||
|                                         ?.toIntOrNull() | ||||
|                                 } ?: episode | ||||
|  | @ -231,64 +207,102 @@ class SflixProvider(providerUrl: String, providerName: String) : MainAPI() { | |||
|         @JsonProperty("tracks") val tracks: List<Tracks?>? | ||||
|     ) | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|         callback: (ExtractorLink) -> Unit | ||||
|     ): Boolean { | ||||
| 
 | ||||
|         // To transfer url:::id | ||||
|         val split = data.split(":::") | ||||
|         // Only used for tv series | ||||
|         val url = if (split.size == 2) { | ||||
|             val episodesUrl = "$mainUrl/ajax/v2/episode/servers/${split[1]}" | ||||
|         val urls = (tryParseJson<Pair<String, String>>(data)?.let { (prefix, server) -> | ||||
|             val episodesUrl = "$mainUrl/ajax/v2/episode/servers/$server" | ||||
|             val episodes = app.get(episodesUrl).text | ||||
| 
 | ||||
|             // Supported streams, they're identical | ||||
|             val sourceId = Jsoup.parse(episodes).select("a").firstOrNull { | ||||
|                 it.select("span").text().trim().equals("RapidStream", ignoreCase = true) | ||||
|                         || it.select("span").text().trim().equals("Vidcloud", ignoreCase = true) | ||||
|             }?.attr("data-id") | ||||
|             Jsoup.parse(episodes).select("a").mapNotNull { element -> | ||||
|                 val id = element?.attr("data-id") ?: return@mapNotNull null | ||||
|                 if(element.select("span")?.text()?.trim()?.isValidServer() == true) { | ||||
|                     "$prefix.$id".replace("/tv/", "/watch-tv/") | ||||
|                 } else { | ||||
|                     null | ||||
|                 } | ||||
|             } | ||||
|         } ?: tryParseJson<List<String>>(data))?.distinct() | ||||
| 
 | ||||
|             "${split[0]}${sourceId?.let { ".$it" } ?: ""}".replace("/tv/", "/watch-tv/") | ||||
|         } else { | ||||
|             data | ||||
|         urls?.pmap { url -> | ||||
|             println("FETCHING URL $url") | ||||
|             val sources = app.get( | ||||
|                 url, | ||||
|                 interceptor = WebViewResolver( | ||||
|                     Regex("""/getSources"""), | ||||
|                 ) | ||||
|             ).text | ||||
| 
 | ||||
|             val mapped = parseJson<SourceObject>(sources) | ||||
| 
 | ||||
|             mapped.tracks?.forEach { | ||||
|                 it?.toSubtitleFile()?.let { subtitleFile -> | ||||
|                     subtitleCallback.invoke(subtitleFile) | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             listOf( | ||||
|                 mapped.sources to "", | ||||
|                 mapped.sources1 to "source 2", | ||||
|                 mapped.sources2 to "source 3", | ||||
|                 mapped.sourcesBackup to "source backup" | ||||
|             ).forEach { subList -> | ||||
|                 subList.first?.forEach { | ||||
|                     it?.toExtractorLink(this, subList.second)?.forEach(callback) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         val sources = app.get( | ||||
|             url, | ||||
|             interceptor = WebViewResolver( | ||||
|                 Regex("""/getSources""") | ||||
|         return !urls.isNullOrEmpty() | ||||
|     } | ||||
| 
 | ||||
|     private fun Element.toSearchResult(): SearchResponse { | ||||
|         val img = this.select("img") | ||||
|         val title = img.attr("title") | ||||
|         val posterUrl = img.attr("data-src") | ||||
|         val href = fixUrl(this.select("a").attr("href")) | ||||
|         val isMovie = href.contains("/movie/") | ||||
|         return if (isMovie) { | ||||
|             MovieSearchResponse( | ||||
|                 title, | ||||
|                 href, | ||||
|                 this@SflixProvider.name, | ||||
|                 TvType.Movie, | ||||
|                 posterUrl, | ||||
|                 null | ||||
|             ) | ||||
|         } else { | ||||
|             TvSeriesSearchResponse( | ||||
|                 title, | ||||
|                 href, | ||||
|                 this@SflixProvider.name, | ||||
|                 TvType.Movie, | ||||
|                 posterUrl, | ||||
|                 null, | ||||
|                 null | ||||
|             ) | ||||
|         ).text | ||||
| 
 | ||||
|         val mapped = mapper.readValue<SourceObject>(sources) | ||||
| 
 | ||||
|         mapped.tracks?.forEach { | ||||
|             it?.toSubtitleFile()?.let { subtitleFile -> | ||||
|                 subtitleCallback.invoke(subtitleFile) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         listOf( | ||||
|             mapped.sources to "source 1", | ||||
|             mapped.sources1 to "source 2", | ||||
|             mapped.sources2 to "source 3", | ||||
|             mapped.sourcesBackup to "source backup" | ||||
|         ).forEach { subList -> | ||||
|             subList.first?.forEach { | ||||
|                 it?.toExtractorLink(this, subList.second)?.forEach(callback) | ||||
|             } | ||||
|         } | ||||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     companion object { | ||||
|         // For re-use in Zoro | ||||
|         fun String?.isValidServer(): Boolean { | ||||
|             if (this.isNullOrEmpty()) return false | ||||
|             if (this.equals("UpCloud", ignoreCase = true) || this.equals( | ||||
|                     "Vidcloud", | ||||
|                     ignoreCase = true | ||||
|                 ) || this.equals("RapidStream", ignoreCase = true) | ||||
|             ) return true | ||||
|             return true | ||||
|         } | ||||
| 
 | ||||
|         // For re-use in Zoro | ||||
|         fun Sources.toExtractorLink(caller: MainAPI, name: String): List<ExtractorLink>? { | ||||
|             return this.file?.let { file -> | ||||
|                 //println("FILE::: $file") | ||||
|                 val isM3u8 = URI(this.file).path.endsWith(".m3u8") || this.type.equals( | ||||
|                     "hls", | ||||
|                     ignoreCase = true | ||||
|  | @ -296,6 +310,7 @@ class SflixProvider(providerUrl: String, providerName: String) : MainAPI() { | |||
|                 if (isM3u8) { | ||||
|                     M3u8Helper().m3u8Generation(M3u8Helper.M3u8Stream(this.file, null), true) | ||||
|                         .map { stream -> | ||||
|                             //println("stream: ${stream.quality} at ${stream.streamUrl}") | ||||
|                             val qualityString = if ((stream.quality ?: 0) == 0) label | ||||
|                                 ?: "" else "${stream.quality}p" | ||||
|                             ExtractorLink( | ||||
|  |  | |||
|  | @ -28,7 +28,7 @@ class TrailersTwoProvider : TmdbProvider() { | |||
|         TvType.Cartoon | ||||
|     ) | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -13,7 +13,7 @@ class VMoveeProvider : MainAPI() { | |||
| 
 | ||||
|     override val supportedTypes = setOf(TvType.Movie) | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/?s=$query" | ||||
|         val response = app.get(url).text | ||||
|         val document = Jsoup.parse(response) | ||||
|  | @ -60,7 +60,7 @@ class VMoveeProvider : MainAPI() { | |||
|         val data: List<ReeoovAPIData>, | ||||
|     ) | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  | @ -108,7 +108,7 @@ class VMoveeProvider : MainAPI() { | |||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val response = app.get(url).text | ||||
|         val document = Jsoup.parse(response) | ||||
| 
 | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ class VfFilmProvider : MainAPI() { | |||
| 
 | ||||
|     override val supportedTypes = setOf(TvType.Movie) | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/?s=$query" | ||||
|         val response = app.get(url).text | ||||
|         val document = Jsoup.parse(response) | ||||
|  | @ -39,7 +39,7 @@ class VfFilmProvider : MainAPI() { | |||
|         return returnValue | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  | @ -70,7 +70,7 @@ class VfFilmProvider : MainAPI() { | |||
|         return vudoUrl | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val response = app.get(url).text | ||||
|         val document = Jsoup.parse(response) | ||||
|         val title = document?.selectFirst("div.SubTitle")?.text() | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ class VfSerieProvider : MainAPI() { | |||
| 
 | ||||
|     override val supportedTypes = setOf(TvType.TvSeries) | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/?s=$query" | ||||
|         val response = app.get(url).text | ||||
|         val document = Jsoup.parse(response) | ||||
|  | @ -52,7 +52,7 @@ class VfSerieProvider : MainAPI() { | |||
|             .toString()  // direct mp4 link, https://m5.vudeo.net/2vp3xgpw2avjdohilpfbtyuxzzrqzuh4z5yxvztral5k3rjnba6f4byj3saa/v.mp4 for exemple | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  | @ -95,7 +95,7 @@ class VfSerieProvider : MainAPI() { | |||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val response = app.get(url).text | ||||
|         val document = Jsoup.parse(response) | ||||
|         val title = | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ open class VidstreamProviderTemplate : MainAPI() { | |||
| 
 | ||||
|     // Searching returns a SearchResponse, which can be one of the following: AnimeSearchResponse, MovieSearchResponse, TorrentSearchResponse, TvSeriesSearchResponse | ||||
|     // Each of the classes requires some different data, but always has some critical things like name, poster and url. | ||||
|     override fun search(query: String): ArrayList<SearchResponse> { | ||||
|     override suspend fun search(query: String): ArrayList<SearchResponse> { | ||||
|         // Simply looking at devtools network is enough to spot a request like: | ||||
|         // https://vidembed.cc/search.html?keyword=neverland where neverland is the query, can be written as below. | ||||
|         val link = "$mainUrl/search.html?keyword=$query" | ||||
|  | @ -66,7 +66,7 @@ open class VidstreamProviderTemplate : MainAPI() { | |||
| 
 | ||||
|     // Load, like the name suggests loads the info page, where all the episodes and data usually is. | ||||
|     // Like search you should return either of: AnimeLoadResponse, MovieLoadResponse, TorrentLoadResponse, TvSeriesLoadResponse. | ||||
|     override fun load(url: String): LoadResponse? { | ||||
|     override suspend fun load(url: String): LoadResponse? { | ||||
|         // Gets the url returned from searching. | ||||
|         val html = app.get(url).text | ||||
|         val soup = Jsoup.parse(html) | ||||
|  | @ -144,7 +144,7 @@ open class VidstreamProviderTemplate : MainAPI() { | |||
| 
 | ||||
|     // This loads the homepage, which is basically a collection of search results with labels. | ||||
|     // Optional function, but make sure to enable hasMainPage if you program this. | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val urls = homePageUrlList | ||||
|         val homePageList = ArrayList<HomePageList>() | ||||
|         // .pmap {} is used to fetch the different pages in parallel | ||||
|  | @ -198,7 +198,7 @@ open class VidstreamProviderTemplate : MainAPI() { | |||
|     // loadLinks gets the raw .mp4 or .m3u8 urls from the data parameter in the episodes class generated in load() | ||||
|     // See TvSeriesEpisode(...) in this provider. | ||||
|     // The data are usually links, but can be any other string to help aid loading the links. | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         // These callbacks are functions you should call when you get a link to a subtitle file or media file. | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ class WatchAsianProvider : MainAPI() { | |||
|     override val hasDownloadSupport = true | ||||
|     override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie) | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse { | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val headers = mapOf("X-Requested-By" to mainUrl) | ||||
|         val doc = app.get(mainUrl, headers = headers).document | ||||
|         val rowPair = mutableListOf<Pair<String, String>>() | ||||
|  | @ -64,7 +64,7 @@ class WatchAsianProvider : MainAPI() { | |||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/search?type=movies&keyword=$query" | ||||
|         val document = app.get(url).document.getElementsByTag("body") | ||||
|                 .select("div.block.tab-container > div > ul > li") ?: return listOf() | ||||
|  | @ -89,7 +89,7 @@ class WatchAsianProvider : MainAPI() { | |||
|         }.distinctBy { a -> a.url } | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val body = app.get(url).document | ||||
|         // Declare vars | ||||
|         val isDramaDetail = url.contains("/drama-detail/") | ||||
|  | @ -163,7 +163,7 @@ class WatchAsianProvider : MainAPI() { | |||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -13,7 +13,7 @@ class FrenchStreamProvider : MainAPI() { | |||
|     override val lang = "fr" | ||||
|     override val supportedTypes = setOf(TvType.AnimeMovie, TvType.TvSeries, TvType.Movie) | ||||
| 
 | ||||
|     override fun search(query: String): ArrayList<SearchResponse> { | ||||
|     override suspend fun search(query: String): ArrayList<SearchResponse> { | ||||
|         val link = "$mainUrl/?do=search&subaction=search&story=$query" | ||||
|         val soup = app.post(link).document | ||||
| 
 | ||||
|  | @ -49,7 +49,7 @@ class FrenchStreamProvider : MainAPI() { | |||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val soup = app.get(url).document | ||||
| 
 | ||||
|         val title = soup.selectFirst("h1#s-title").text().toString() | ||||
|  | @ -136,7 +136,7 @@ class FrenchStreamProvider : MainAPI() { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  | @ -228,7 +228,7 @@ class FrenchStreamProvider : MainAPI() { | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     override fun getMainPage(): HomePageResponse? { | ||||
|     override suspend fun getMainPage(): HomePageResponse? { | ||||
|         val document = app.get(mainUrl).document | ||||
|         val docs = document.select("div.sect") | ||||
|         val returnList = docs.mapNotNull { | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ import org.jsoup.Jsoup | |||
| import org.jsoup.nodes.Document | ||||
| import java.io.File | ||||
| import java.net.URI | ||||
| import java.util.* | ||||
| import java.util.concurrent.TimeUnit | ||||
| 
 | ||||
| 
 | ||||
|  | @ -156,13 +155,13 @@ fun getHeaders( | |||
| 
 | ||||
| fun postRequestCreator( | ||||
|     url: String, | ||||
|     headers: Map<String, String>, | ||||
|     referer: String?, | ||||
|     params: Map<String, String>, | ||||
|     cookies: Map<String, String>, | ||||
|     data: Map<String, String>, | ||||
|     cacheTime: Int, | ||||
|     cacheUnit: TimeUnit | ||||
|     headers: Map<String, String> = emptyMap(), | ||||
|     referer: String? = null, | ||||
|     params: Map<String, String> = emptyMap(), | ||||
|     cookies: Map<String, String> = emptyMap(), | ||||
|     data: Map<String, String> = emptyMap(), | ||||
|     cacheTime: Int = DEFAULT_TIME, | ||||
|     cacheUnit: TimeUnit = DEFAULT_TIME_UNIT | ||||
| ): Request { | ||||
|     return Request.Builder() | ||||
|         .url(addParamsToUrl(url, params)) | ||||
|  | @ -174,12 +173,12 @@ fun postRequestCreator( | |||
| 
 | ||||
| fun getRequestCreator( | ||||
|     url: String, | ||||
|     headers: Map<String, String>, | ||||
|     referer: String?, | ||||
|     params: Map<String, String>, | ||||
|     cookies: Map<String, String>, | ||||
|     cacheTime: Int, | ||||
|     cacheUnit: TimeUnit | ||||
|     headers: Map<String, String> = emptyMap(), | ||||
|     referer: String? = null, | ||||
|     params: Map<String, String> = emptyMap(), | ||||
|     cookies: Map<String, String> = emptyMap(), | ||||
|     cacheTime: Int = DEFAULT_TIME, | ||||
|     cacheUnit: TimeUnit = DEFAULT_TIME_UNIT | ||||
| ): Request { | ||||
|     return Request.Builder() | ||||
|         .url(addParamsToUrl(url, params)) | ||||
|  | @ -213,6 +212,8 @@ open class Requests { | |||
|         val settingsManager = PreferenceManager.getDefaultSharedPreferences(context) | ||||
|         val dns = settingsManager.getInt(context.getString(R.string.dns_pref), 0) | ||||
|         baseClient = OkHttpClient.Builder() | ||||
|             .followRedirects(true) | ||||
|             .followSslRedirects(true) | ||||
|             .cache( | ||||
|                 // Note that you need to add a ResponseInterceptor to make this 100% active. | ||||
|                 // The server response dictates if and when stuff should be cached. | ||||
|  | @ -235,10 +236,10 @@ open class Requests { | |||
| 
 | ||||
|     fun get( | ||||
|         url: String, | ||||
|         headers: Map<String, String> = mapOf(), | ||||
|         headers: Map<String, String> = emptyMap(), | ||||
|         referer: String? = null, | ||||
|         params: Map<String, String> = mapOf(), | ||||
|         cookies: Map<String, String> = mapOf(), | ||||
|         params: Map<String, String> = emptyMap(), | ||||
|         cookies: Map<String, String> = emptyMap(), | ||||
|         allowRedirects: Boolean = true, | ||||
|         cacheTime: Int = DEFAULT_TIME, | ||||
|         cacheUnit: TimeUnit = DEFAULT_TIME_UNIT, | ||||
|  | @ -258,6 +259,10 @@ open class Requests { | |||
|         return AppResponse(response) | ||||
|     } | ||||
| 
 | ||||
|     fun executeRequest(request : Request): AppResponse { | ||||
|         return AppResponse(baseClient.newCall(request).execute()) | ||||
|     } | ||||
| 
 | ||||
|     fun post( | ||||
|         url: String, | ||||
|         headers: Map<String, String> = mapOf(), | ||||
|  |  | |||
|  | @ -8,14 +8,12 @@ import com.lagradost.cloudstream3.USER_AGENT | |||
| import com.lagradost.cloudstream3.app | ||||
| import com.lagradost.cloudstream3.utils.Coroutines.main | ||||
| import kotlinx.coroutines.delay | ||||
| import kotlinx.coroutines.flow.callbackFlow | ||||
| import kotlinx.coroutines.runBlocking | ||||
| import okhttp3.Interceptor | ||||
| import okhttp3.Request | ||||
| import okhttp3.Response | ||||
| import java.net.URI | ||||
| import java.util.concurrent.TimeUnit | ||||
| import kotlin.concurrent.thread | ||||
| 
 | ||||
| /** | ||||
|  * When used as Interceptor additionalUrls cannot be returned, use WebViewResolver(...).resolveUsingWebView(...) | ||||
|  | @ -96,7 +94,34 @@ class WebViewResolver(val interceptUrl: Regex, val additionalUrls: List<Regex> = | |||
|                     // Suppress image requests as we don't display them anywhere | ||||
|                     // Less data, low chance of causing issues. | ||||
|                     // blockNetworkImage also does this job but i will keep it for the future. | ||||
|                     val blacklistedFiles = listOf(".jpg", ".png", ".webp", ".jpeg", ".webm", ".mp4") | ||||
|                     val blacklistedFiles = listOf( | ||||
|                         ".jpg", | ||||
|                         ".png", | ||||
|                         ".webp", | ||||
|                         ".mpg", | ||||
|                         ".mpeg", | ||||
|                         ".jpeg", | ||||
|                         ".webm", | ||||
|                         ".mp4", | ||||
|                         ".mp3", | ||||
|                         ".gifv", | ||||
|                         ".flv", | ||||
|                         ".asf", | ||||
|                         ".mov", | ||||
|                         ".mng", | ||||
|                         ".mkv", | ||||
|                         ".ogg", | ||||
|                         ".avi", | ||||
|                         ".wav", | ||||
|                         ".woff2", | ||||
|                         ".woff", | ||||
|                         ".ttf", | ||||
|                         ".css", | ||||
|                         ".vtt", | ||||
|                         ".srt", | ||||
|                         ".ts", | ||||
|                         ".gif", | ||||
|                     ) | ||||
| 
 | ||||
|                     /** NOTE!  request.requestHeaders is not perfect! | ||||
|                      *  They don't contain all the headers the browser actually gives. | ||||
|  | @ -105,7 +130,7 @@ class WebViewResolver(val interceptUrl: Regex, val additionalUrls: List<Regex> = | |||
|                      * **/ | ||||
|                     return try { | ||||
|                         when { | ||||
|                             blacklistedFiles.any { URI(webViewUrl).path.endsWith(it) } || webViewUrl.endsWith( | ||||
|                             blacklistedFiles.any { URI(webViewUrl).path.contains(it) } || webViewUrl.endsWith( | ||||
|                                 "/favicon.ico" | ||||
|                             ) -> WebResourceResponse( | ||||
|                                 "image/png", | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ class NyaaProvider : MainAPI() { | |||
|     override val vpnStatus = VPNStatus.Torrent | ||||
|     override val instantLinkLoading = true | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val url = "$mainUrl/?f=0&c=0_0&q=$query&s=seeders&o=desc" | ||||
|         val response = app.get(url).text | ||||
|         val document = Jsoup.parse(response) | ||||
|  | @ -35,7 +35,7 @@ class NyaaProvider : MainAPI() { | |||
|         return returnValues | ||||
|     } | ||||
| 
 | ||||
|     override fun load(url: String): LoadResponse { | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|         val response = app.get(url).text | ||||
|         val document = Jsoup.parse(response) | ||||
|         val title = document.selectFirst("h3.panel-title").text() | ||||
|  | @ -47,7 +47,7 @@ class NyaaProvider : MainAPI() { | |||
|         return TorrentLoadResponse(title, url, this.name, magnet, fixUrl(torrent), description) | ||||
|     } | ||||
| 
 | ||||
|     override fun loadLinks( | ||||
|     override suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ package com.lagradost.cloudstream3.ui | |||
| 
 | ||||
| import com.lagradost.cloudstream3.* | ||||
| import com.lagradost.cloudstream3.mvvm.Resource | ||||
| import com.lagradost.cloudstream3.mvvm.normalSafeApiCall | ||||
| import com.lagradost.cloudstream3.mvvm.logError | ||||
| import com.lagradost.cloudstream3.mvvm.safeApiCall | ||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | ||||
| 
 | ||||
|  | @ -66,15 +66,18 @@ class APIRepository(val api: MainAPI) { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun loadLinks( | ||||
|     suspend fun loadLinks( | ||||
|         data: String, | ||||
|         isCasting: Boolean, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|         callback: (ExtractorLink) -> Unit | ||||
|     ): Boolean { | ||||
|         if (isInvalidData(data)) return false // this makes providers cleaner | ||||
| 
 | ||||
|         return normalSafeApiCall { api.loadLinks(data, isCasting, subtitleCallback, callback) } | ||||
|             ?: false | ||||
|         return try { | ||||
|             api.loadLinks(data, isCasting, subtitleCallback, callback) | ||||
|         } catch (throwable: Throwable) { | ||||
|             logError(throwable) | ||||
|             return false | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -22,7 +22,8 @@ import com.google.android.gms.cast.framework.media.RemoteMediaClient | |||
| import com.google.android.gms.cast.framework.media.uicontroller.UIController | ||||
| import com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity | ||||
| import com.lagradost.cloudstream3.R | ||||
| import com.lagradost.cloudstream3.mvvm.normalSafeApiCall | ||||
| import com.lagradost.cloudstream3.mvvm.Resource | ||||
| import com.lagradost.cloudstream3.mvvm.safeApiCall | ||||
| import com.lagradost.cloudstream3.sortSubs | ||||
| import com.lagradost.cloudstream3.sortUrls | ||||
| import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator | ||||
|  | @ -31,11 +32,11 @@ import com.lagradost.cloudstream3.ui.result.ResultEpisode | |||
| import com.lagradost.cloudstream3.utils.AppUtils.toJson | ||||
| import com.lagradost.cloudstream3.utils.CastHelper.awaitLinks | ||||
| import com.lagradost.cloudstream3.utils.CastHelper.getMediaInfo | ||||
| import com.lagradost.cloudstream3.utils.Coroutines.ioSafe | ||||
| import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject | ||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | ||||
| import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe | ||||
| import org.json.JSONObject | ||||
| import kotlin.concurrent.thread | ||||
| 
 | ||||
| /*class SkipOpController(val view: ImageView) : UIController() { | ||||
|     init { | ||||
|  | @ -265,7 +266,7 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi | |||
| 
 | ||||
|                 if (itemCount != null && itemCount - currentIdIndex == 1 && !isLoadingMore) { | ||||
|                     isLoadingMore = true | ||||
|                     thread { | ||||
|                     ioSafe { | ||||
|                         val index = meta.currentEpisodeIndex + 1 | ||||
|                         val epData = meta.episodes[index] | ||||
|                         val currentLinks = mutableSetOf<ExtractorLink>() | ||||
|  | @ -273,7 +274,7 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi | |||
| 
 | ||||
|                         val generator = RepoLinkGenerator(listOf(epData)) | ||||
| 
 | ||||
|                         val isSuccessful = normalSafeApiCall { | ||||
|                         val isSuccessful = safeApiCall { | ||||
|                             generator.generateLinks(false, true, | ||||
|                                 { | ||||
|                                     it.first?.let { link -> | ||||
|  | @ -286,7 +287,7 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi | |||
| 
 | ||||
|                         val sortedLinks = sortUrls(currentLinks) | ||||
|                         val sortedSubs = sortSubs(currentSubs) | ||||
|                         if (isSuccessful == true) { | ||||
|                         if (isSuccessful == Resource.Success(true)) { | ||||
|                             if (currentLinks.isNotEmpty()) { | ||||
|                                 val jsonCopy = meta.copy( | ||||
|                                     currentLinks =  sortedLinks, | ||||
|  | @ -319,13 +320,10 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi | |||
|                                 }*/ | ||||
|                                 activity.runOnUiThread { | ||||
|                                     awaitLinks( | ||||
| 
 | ||||
|                                         remoteMediaClient?.queueAppendItem( | ||||
|                                             MediaQueueItem.Builder(mediaInfo).build(), | ||||
|                                             JSONObject() | ||||
|                                         ) | ||||
| 
 | ||||
| 
 | ||||
|                                     ) { | ||||
|                                         println("FAILED TO LOAD NEXT ITEM") | ||||
|                                         //  loadIndex(1) | ||||
|  |  | |||
|  | @ -46,7 +46,7 @@ class DownloadFileGenerator( | |||
|         return episodes[currentIndex] | ||||
|     } | ||||
| 
 | ||||
|     override fun generateLinks( | ||||
|     override suspend fun generateLinks( | ||||
|         clearCache: Boolean, | ||||
|         isCasting: Boolean, | ||||
|         callback: (Pair<ExtractorLink?, ExtractorUri?>) -> Unit, | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ interface IGenerator { | |||
|     fun getCurrent(): Any?     // this is used to get metadata about the current playing, can return null | ||||
| 
 | ||||
|     /* not safe, must use try catch */ | ||||
|     fun generateLinks( | ||||
|     suspend fun generateLinks( | ||||
|         clearCache: Boolean, | ||||
|         isCasting: Boolean, | ||||
|         callback: (Pair<ExtractorLink?, ExtractorUri?>) -> Unit, | ||||
|  |  | |||
|  | @ -51,7 +51,7 @@ class PlayerGeneratorViewModel : ViewModel() { | |||
|     } | ||||
| 
 | ||||
|     fun preLoadNextLinks() = viewModelScope.launch { | ||||
|         normalSafeApiCall { | ||||
|         safeApiCall { | ||||
|             if (generator?.hasCache == true && generator?.hasNext() == true) { | ||||
|                 generator?.next() | ||||
|                 generator?.generateLinks(clearCache = false, isCasting = false, {}, {}) | ||||
|  | @ -97,7 +97,7 @@ class PlayerGeneratorViewModel : ViewModel() { | |||
|                 _currentLinks.postValue(currentLinks) | ||||
|             }, { | ||||
|                 currentSubs.add(it) | ||||
|                // _currentSubs.postValue(currentSubs) // this causes ConcurrentModificationException, so fuck it | ||||
|                 // _currentSubs.postValue(currentSubs) // this causes ConcurrentModificationException, so fuck it | ||||
|             }) | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -57,7 +57,7 @@ class PlayerSubtitleHelper { | |||
|                 endsWith("vtt", true) -> MimeTypes.TEXT_VTT | ||||
|                 endsWith("srt", true) -> MimeTypes.APPLICATION_SUBRIP | ||||
|                 endsWith("xml", true) || endsWith("ttml", true) -> MimeTypes.APPLICATION_TTML | ||||
|                 else -> MimeTypes.APPLICATION_SUBRIP // TODO get request to see | ||||
|                 else -> MimeTypes.APPLICATION_SUBRIP | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -46,7 +46,7 @@ class RepoLinkGenerator(private val episodes: List<ResultEpisode>, private var c | |||
|     var linkCache = Array<Set<ExtractorLink>>(size = episodes.size, init = { setOf() }) | ||||
|     var subsCache = Array<Set<SubtitleData>>(size = episodes.size, init = { setOf() }) | ||||
| 
 | ||||
|     override fun generateLinks( | ||||
|     override suspend fun generateLinks( | ||||
|         clearCache: Boolean, | ||||
|         isCasting: Boolean, | ||||
|         callback: (Pair<ExtractorLink?, ExtractorUri?>) -> Unit, | ||||
|  |  | |||
|  | @ -98,6 +98,14 @@ object AppUtils { | |||
|         return mapper.readValue(value) | ||||
|     } | ||||
| 
 | ||||
|     inline fun <reified T> tryParseJson(value : String): T? { | ||||
|         return try { | ||||
|             parseJson(value) | ||||
|         } catch (_ : Exception) { | ||||
|             null | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /**| S1:E2 Hello World | ||||
|      * | Episode 2. Hello world | ||||
|      * | Hello World | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue