forked from recloudstream/cloudstream
		
	api refactor, breaking change for forks
This commit is contained in:
		
							parent
							
								
									99fa40eaeb
								
							
						
					
					
						commit
						750b1878cb
					
				
					 49 changed files with 564 additions and 376 deletions
				
			
		|  | @ -36,7 +36,7 @@ android { | ||||||
|         targetSdkVersion 30 |         targetSdkVersion 30 | ||||||
| 
 | 
 | ||||||
|         versionCode 45 |         versionCode 45 | ||||||
|         versionName "2.9.17" |         versionName "2.9.18" | ||||||
| 
 | 
 | ||||||
|         resValue "string", "app_version", |         resValue "string", "app_version", | ||||||
|                 "${defaultConfig.versionName}${versionNameSuffix ?: ""}" |                 "${defaultConfig.versionName}${versionNameSuffix ?: ""}" | ||||||
|  |  | ||||||
|  | @ -13,11 +13,14 @@ import com.fasterxml.jackson.module.kotlin.KotlinModule | ||||||
| import com.lagradost.cloudstream3.animeproviders.* | import com.lagradost.cloudstream3.animeproviders.* | ||||||
| import com.lagradost.cloudstream3.metaproviders.CrossTmdbProvider | import com.lagradost.cloudstream3.metaproviders.CrossTmdbProvider | ||||||
| import com.lagradost.cloudstream3.movieproviders.* | import com.lagradost.cloudstream3.movieproviders.* | ||||||
|  | import com.lagradost.cloudstream3.mvvm.logError | ||||||
| import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.aniListApi | import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.aniListApi | ||||||
| import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.malApi | import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.malApi | ||||||
| import com.lagradost.cloudstream3.ui.player.SubtitleData | import com.lagradost.cloudstream3.ui.player.SubtitleData | ||||||
|  | import com.lagradost.cloudstream3.utils.AppUtils.toJson | ||||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
| import okhttp3.Interceptor | import okhttp3.Interceptor | ||||||
|  | import java.text.SimpleDateFormat | ||||||
| import java.util.* | import java.util.* | ||||||
| import kotlin.math.absoluteValue | import kotlin.math.absoluteValue | ||||||
| 
 | 
 | ||||||
|  | @ -800,16 +803,6 @@ fun TvType?.isEpisodeBased(): Boolean { | ||||||
|     return (this == TvType.TvSeries || this == TvType.Anime) |     return (this == TvType.TvSeries || this == TvType.Anime) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| data class AnimeEpisode( |  | ||||||
|     val url: String, |  | ||||||
|     var name: String? = null, |  | ||||||
|     var posterUrl: String? = null, |  | ||||||
|     var date: String? = null, |  | ||||||
|     var rating: Int? = null, |  | ||||||
|     var description: String? = null, |  | ||||||
|     var episode: Int? = null, |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| data class TorrentLoadResponse( | data class TorrentLoadResponse( | ||||||
|     override var name: String, |     override var name: String, | ||||||
|     override var url: String, |     override var url: String, | ||||||
|  | @ -841,7 +834,7 @@ data class AnimeLoadResponse( | ||||||
|     override var posterUrl: String? = null, |     override var posterUrl: String? = null, | ||||||
|     override var year: Int? = null, |     override var year: Int? = null, | ||||||
| 
 | 
 | ||||||
|     var episodes: MutableMap<DubStatus, List<AnimeEpisode>> = mutableMapOf(), |     var episodes: MutableMap<DubStatus, List<Episode>> = mutableMapOf(), | ||||||
|     var showStatus: ShowStatus? = null, |     var showStatus: ShowStatus? = null, | ||||||
| 
 | 
 | ||||||
|     override var plot: String? = null, |     override var plot: String? = null, | ||||||
|  | @ -857,7 +850,7 @@ data class AnimeLoadResponse( | ||||||
|     override var syncData: MutableMap<String, String> = mutableMapOf(), |     override var syncData: MutableMap<String, String> = mutableMapOf(), | ||||||
| ) : LoadResponse | ) : LoadResponse | ||||||
| 
 | 
 | ||||||
| fun AnimeLoadResponse.addEpisodes(status: DubStatus, episodes: List<AnimeEpisode>?) { | fun AnimeLoadResponse.addEpisodes(status: DubStatus, episodes: List<Episode>?) { | ||||||
|     if (episodes == null) return |     if (episodes == null) return | ||||||
|     this.episodes[status] = episodes |     this.episodes[status] = episodes | ||||||
| } | } | ||||||
|  | @ -912,6 +905,26 @@ data class MovieLoadResponse( | ||||||
|     override var syncData: MutableMap<String, String> = mutableMapOf(), |     override var syncData: MutableMap<String, String> = mutableMapOf(), | ||||||
| ) : LoadResponse | ) : LoadResponse | ||||||
| 
 | 
 | ||||||
|  | fun <T> MainAPI.newMovieLoadResponse( | ||||||
|  |     name: String, | ||||||
|  |     url: String, | ||||||
|  |     type: TvType, | ||||||
|  |     data: T?, | ||||||
|  |     initializer: MovieLoadResponse.() -> Unit = { } | ||||||
|  | ): MovieLoadResponse { | ||||||
|  |     val dataUrl = data?.toJson() ?: "" | ||||||
|  |     val builder = MovieLoadResponse( | ||||||
|  |         name = name, | ||||||
|  |         url = url, | ||||||
|  |         apiName = this.name, | ||||||
|  |         type = type, | ||||||
|  |         dataUrl = dataUrl, | ||||||
|  |         comingSoon = dataUrl.isBlank() | ||||||
|  |     ) | ||||||
|  |     builder.initializer() | ||||||
|  |     return builder | ||||||
|  | } | ||||||
|  | 
 | ||||||
| fun MainAPI.newMovieLoadResponse( | fun MainAPI.newMovieLoadResponse( | ||||||
|     name: String, |     name: String, | ||||||
|     url: String, |     url: String, | ||||||
|  | @ -931,23 +944,58 @@ fun MainAPI.newMovieLoadResponse( | ||||||
|     return builder |     return builder | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| data class TvSeriesEpisode( | data class Episode( | ||||||
|     val name: String? = null, |     var data: String, | ||||||
|     val season: Int? = null, |     var name: String? = null, | ||||||
|     val episode: Int? = null, |     var season: Int? = null, | ||||||
|     val data: String, |     var episode: Int? = null, | ||||||
|     val posterUrl: String? = null, |     var posterUrl: String? = null, | ||||||
|     val date: String? = null, |     var rating: Int? = null, | ||||||
|     val rating: Int? = null, |     var description: String? = null, | ||||||
|     val description: String? = null, |     var date: Long? = null, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | fun Episode.addDate(date: String?, fomat: String = "yyyy-MM-dd") { | ||||||
|  |     try { | ||||||
|  |         this.date = SimpleDateFormat(fomat)?.parse(date ?: return)?.time | ||||||
|  |     } catch (e: Exception) { | ||||||
|  |         logError(e) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fun Episode.addDate(date: Date?) { | ||||||
|  |     this.date = date?.time | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fun <T> MainAPI.newEpisode( | ||||||
|  |     url: String, | ||||||
|  |     initializer: Episode.() -> Unit = { }, | ||||||
|  |     fix: Boolean = true, | ||||||
|  | ): Episode { | ||||||
|  |     val builder = Episode( | ||||||
|  |         data = if (fix) fixUrl(url) else url | ||||||
|  |     ) | ||||||
|  |     builder.initializer() | ||||||
|  |     return builder | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fun <T> MainAPI.newEpisode( | ||||||
|  |     data: T, | ||||||
|  |     initializer: Episode.() -> Unit = { } | ||||||
|  | ): Episode { | ||||||
|  |     val builder = Episode( | ||||||
|  |         data = data?.toJson() ?: throw ErrorLoadingException("invalid newEpisode") | ||||||
|  |     ) | ||||||
|  |     builder.initializer() | ||||||
|  |     return builder | ||||||
|  | } | ||||||
|  | 
 | ||||||
| data class TvSeriesLoadResponse( | data class TvSeriesLoadResponse( | ||||||
|     override var name: String, |     override var name: String, | ||||||
|     override var url: String, |     override var url: String, | ||||||
|     override var apiName: String, |     override var apiName: String, | ||||||
|     override var type: TvType, |     override var type: TvType, | ||||||
|     var episodes: List<TvSeriesEpisode>, |     var episodes: List<Episode>, | ||||||
| 
 | 
 | ||||||
|     override var posterUrl: String? = null, |     override var posterUrl: String? = null, | ||||||
|     override var year: Int? = null, |     override var year: Int? = null, | ||||||
|  | @ -968,7 +1016,7 @@ fun MainAPI.newTvSeriesLoadResponse( | ||||||
|     name: String, |     name: String, | ||||||
|     url: String, |     url: String, | ||||||
|     type: TvType, |     type: TvType, | ||||||
|     episodes: List<TvSeriesEpisode>, |     episodes: List<Episode>, | ||||||
|     initializer: TvSeriesLoadResponse.() -> Unit = { } |     initializer: TvSeriesLoadResponse.() -> Unit = { } | ||||||
| ): TvSeriesLoadResponse { | ): TvSeriesLoadResponse { | ||||||
|     val builder = TvSeriesLoadResponse( |     val builder = TvSeriesLoadResponse( | ||||||
|  |  | ||||||
|  | @ -232,11 +232,11 @@ class AllAnimeProvider : MainAPI() { | ||||||
|         val episodes = showData.availableEpisodes.let { |         val episodes = showData.availableEpisodes.let { | ||||||
|             if (it == null) return@let Pair(null, null) |             if (it == null) return@let Pair(null, null) | ||||||
|             Pair(if (it.sub != 0) ((1..it.sub).map { epNum -> |             Pair(if (it.sub != 0) ((1..it.sub).map { epNum -> | ||||||
|                 AnimeEpisode( |                 Episode( | ||||||
|                     "$mainUrl/anime/${showData.Id}/episodes/sub/$epNum", episode = epNum |                     "$mainUrl/anime/${showData.Id}/episodes/sub/$epNum", episode = epNum | ||||||
|                 ) |                 ) | ||||||
|             }) else null, if (it.dub != 0) ((1..it.dub).map { epNum -> |             }) else null, if (it.dub != 0) ((1..it.dub).map { epNum -> | ||||||
|                 AnimeEpisode( |                 Episode( | ||||||
|                     "$mainUrl/anime/${showData.Id}/episodes/dub/$epNum", episode = epNum |                     "$mainUrl/anime/${showData.Id}/episodes/dub/$epNum", episode = epNum | ||||||
|                 ) |                 ) | ||||||
|             }) else null) |             }) else null) | ||||||
|  |  | ||||||
|  | @ -65,7 +65,7 @@ class AnimeFlickProvider : MainAPI() { | ||||||
|         val episodes = doc.select("#collapseOne .block-space > .row > div:nth-child(2)").map { |         val episodes = doc.select("#collapseOne .block-space > .row > div:nth-child(2)").map { | ||||||
|             val name = it.selectFirst("a").text() |             val name = it.selectFirst("a").text() | ||||||
|             val link = mainUrl + it.selectFirst("a").attr("href") |             val link = mainUrl + it.selectFirst("a").attr("href") | ||||||
|             AnimeEpisode(link, name) |             Episode(link, name) | ||||||
|         }.reversed() |         }.reversed() | ||||||
| 
 | 
 | ||||||
|         return newAnimeLoadResponse(title, url, getType(title)) { |         return newAnimeLoadResponse(title, url, getType(title)) { | ||||||
|  |  | ||||||
|  | @ -189,7 +189,7 @@ class AnimePaheProvider : MainAPI() { | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     private suspend fun generateListOfEpisodes(link: String): ArrayList<AnimeEpisode> { |     private suspend fun generateListOfEpisodes(link: String): ArrayList<Episode> { | ||||||
|         try { |         try { | ||||||
|             val attrs = link.split('/') |             val attrs = link.split('/') | ||||||
|             val id = attrs[attrs.size - 1].split("?")[0] |             val id = attrs[attrs.size - 1].split("?")[0] | ||||||
|  | @ -204,7 +204,7 @@ class AnimePaheProvider : MainAPI() { | ||||||
|             val perPage = data.perPage |             val perPage = data.perPage | ||||||
|             val total = data.total |             val total = data.total | ||||||
|             var ep = 1 |             var ep = 1 | ||||||
|             val episodes = ArrayList<AnimeEpisode>() |             val episodes = ArrayList<Episode>() | ||||||
| 
 | 
 | ||||||
|             fun getEpisodeTitle(k: AnimeData): String { |             fun getEpisodeTitle(k: AnimeData): String { | ||||||
|                 return k.title.ifEmpty { |                 return k.title.ifEmpty { | ||||||
|  | @ -215,14 +215,11 @@ class AnimePaheProvider : MainAPI() { | ||||||
|             if (lastPage == 1 && perPage > total) { |             if (lastPage == 1 && perPage > total) { | ||||||
|                 data.data.forEach { |                 data.data.forEach { | ||||||
|                     episodes.add( |                     episodes.add( | ||||||
|                         AnimeEpisode( |                         newEpisode("$mainUrl/api?m=links&id=${it.animeId}&session=${it.session}&p=kwik!!TRUE!!") { | ||||||
|                             "$mainUrl/api?m=links&id=${it.animeId}&session=${it.session}&p=kwik!!TRUE!!", |                             addDate(it.createdAt) | ||||||
|                             getEpisodeTitle(it), |                             this.name = getEpisodeTitle(it) | ||||||
|                             it.snapshot.ifEmpty { |                             this.posterUrl = it.snapshot | ||||||
|                                 null |                         } | ||||||
|                             }, |  | ||||||
|                             it.createdAt |  | ||||||
|                         ) |  | ||||||
|                     ) |                     ) | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|  | @ -230,7 +227,7 @@ class AnimePaheProvider : MainAPI() { | ||||||
|                     for (i in 0 until perPage) { |                     for (i in 0 until perPage) { | ||||||
|                         if (ep <= total) { |                         if (ep <= total) { | ||||||
|                             episodes.add( |                             episodes.add( | ||||||
|                                 AnimeEpisode( |                                 Episode( | ||||||
|                                     "$mainUrl/api?m=release&id=${id}&sort=episode_asc&page=${page + 1}&ep=${ep}!!FALSE!!" |                                     "$mainUrl/api?m=release&id=${id}&sort=episode_asc&page=${page + 1}&ep=${ep}!!FALSE!!" | ||||||
|                                 ) |                                 ) | ||||||
|                             ) |                             ) | ||||||
|  |  | ||||||
|  | @ -152,7 +152,7 @@ class AnimeWorldProvider : MainAPI() { | ||||||
|         val episodes = servers.select(".server[data-name=\"9\"] .episode").map { |         val episodes = servers.select(".server[data-name=\"9\"] .episode").map { | ||||||
|             val id = it.select("a").attr("data-id") |             val id = it.select("a").attr("data-id") | ||||||
|             val number = it.select("a").attr("data-episode-num").toIntOrNull() |             val number = it.select("a").attr("data-episode-num").toIntOrNull() | ||||||
|             AnimeEpisode( |             Episode( | ||||||
|                 fixUrl("$mainUrl/api/episode/info?id=$id"), |                 fixUrl("$mainUrl/api/episode/info?id=$id"), | ||||||
|                 episode = number |                 episode = number | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|  | @ -115,7 +115,7 @@ class AnimeflvnetProvider:MainAPI() { | ||||||
| 
 | 
 | ||||||
|     override suspend fun load(url: String): LoadResponse { |     override suspend fun load(url: String): LoadResponse { | ||||||
|         val doc = app.get(url).document |         val doc = app.get(url).document | ||||||
|         val episodes = ArrayList<AnimeEpisode>() |         val episodes = ArrayList<Episode>() | ||||||
|         val title = doc.selectFirst("h1.Title").text() |         val title = doc.selectFirst("h1.Title").text() | ||||||
|         val poster = doc.selectFirst("div.AnimeCover div.Image figure img").attr("src") |         val poster = doc.selectFirst("div.AnimeCover div.Image figure img").attr("src") | ||||||
|         val description = doc.selectFirst("div.Description p").text() |         val description = doc.selectFirst("div.Description p").text() | ||||||
|  | @ -137,7 +137,7 @@ class AnimeflvnetProvider:MainAPI() { | ||||||
|                     val animeid = doc.selectFirst("div.Strs.RateIt").attr("data-id") |                     val animeid = doc.selectFirst("div.Strs.RateIt").attr("data-id") | ||||||
|                     val epthumb = "https://cdn.animeflv.net/screenshots/$animeid/$epNum/th_3.jpg" |                     val epthumb = "https://cdn.animeflv.net/screenshots/$animeid/$epNum/th_3.jpg" | ||||||
|                     val link = url.replace("/anime/","/ver/")+"-$epNum" |                     val link = url.replace("/anime/","/ver/")+"-$epNum" | ||||||
|                     episodes.add( AnimeEpisode( |                     episodes.add( Episode( | ||||||
|                         link, |                         link, | ||||||
|                         null, |                         null, | ||||||
|                         posterUrl = epthumb, |                         posterUrl = epthumb, | ||||||
|  |  | ||||||
|  | @ -106,7 +106,7 @@ class AnimekisaProvider : MainAPI() { | ||||||
|         ) ShowStatus.Ongoing else ShowStatus.Completed |         ) ShowStatus.Ongoing else ShowStatus.Completed | ||||||
|         val episodes = doc.select("div.tab-content ul li.nav-item").map { |         val episodes = doc.select("div.tab-content ul li.nav-item").map { | ||||||
|             val link = it.selectFirst("a").attr("href") |             val link = it.selectFirst("a").attr("href") | ||||||
|             AnimeEpisode(link) |             Episode(link) | ||||||
|         } |         } | ||||||
|         val type = if (doc.selectFirst(".dp-i-stats").toString() |         val type = if (doc.selectFirst(".dp-i-stats").toString() | ||||||
|                 .contains("Movies") |                 .contains("Movies") | ||||||
|  |  | ||||||
|  | @ -112,7 +112,7 @@ class DubbedAnimeProvider : MainAPI() { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     private suspend fun getAnimeEpisode(slug: String, isMovie: Boolean): EpisodeInfo { |     private suspend fun getEpisode(slug: String, isMovie: Boolean): EpisodeInfo { | ||||||
|         val url = |         val url = | ||||||
|             mainUrl + (if (isMovie) "/movies/jsonMovie" else "/xz/v3/jsonEpi") + ".php?slug=$slug&_=$unixTime" |             mainUrl + (if (isMovie) "/movies/jsonMovie" else "/xz/v3/jsonEpi") + ".php?slug=$slug&_=$unixTime" | ||||||
|         val response = app.get(url).text |         val response = app.get(url).text | ||||||
|  | @ -196,7 +196,7 @@ class DubbedAnimeProvider : MainAPI() { | ||||||
|     ): Boolean { |     ): Boolean { | ||||||
|         val serversHTML = (if (data.startsWith(mainUrl)) { // CLASSIC EPISODE |         val serversHTML = (if (data.startsWith(mainUrl)) { // CLASSIC EPISODE | ||||||
|             val slug = getSlug(data) |             val slug = getSlug(data) | ||||||
|             getAnimeEpisode(slug, false).serversHTML |             getEpisode(slug, false).serversHTML | ||||||
|         } else data).replace("\\", "") |         } else data).replace("\\", "") | ||||||
| 
 | 
 | ||||||
|         val hls = ArrayList("hl=\"(.*?)\"".toRegex().findAll(serversHTML).map { |         val hls = ArrayList("hl=\"(.*?)\"".toRegex().findAll(serversHTML).map { | ||||||
|  | @ -228,7 +228,7 @@ class DubbedAnimeProvider : MainAPI() { | ||||||
|     override suspend fun load(url: String): LoadResponse { |     override suspend fun load(url: String): LoadResponse { | ||||||
|         if (getIsMovie(url)) { |         if (getIsMovie(url)) { | ||||||
|             val realSlug = url.replace("movies/", "") |             val realSlug = url.replace("movies/", "") | ||||||
|             val episode = getAnimeEpisode(realSlug, true) |             val episode = getEpisode(realSlug, true) | ||||||
|             val poster = episode.previewImg ?: episode.wideImg |             val poster = episode.previewImg ?: episode.wideImg | ||||||
|             return MovieLoadResponse( |             return MovieLoadResponse( | ||||||
|                 episode.title, |                 episode.title, | ||||||
|  | @ -253,7 +253,7 @@ class DubbedAnimeProvider : MainAPI() { | ||||||
| 
 | 
 | ||||||
|             val episodes = document.select("a.epibloks").map { |             val episodes = document.select("a.epibloks").map { | ||||||
|                 val epTitle = it.selectFirst("> div.inwel > span.isgrxx")?.text() |                 val epTitle = it.selectFirst("> div.inwel > span.isgrxx")?.text() | ||||||
|                 AnimeEpisode(fixUrl(it.attr("href")), epTitle) |                 Episode(fixUrl(it.attr("href")), epTitle) | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             val img = fixUrl(document.select("div.fkimgs > img").attr("src")) |             val img = fixUrl(document.select("div.fkimgs > img").attr("src")) | ||||||
|  |  | ||||||
|  | @ -303,7 +303,7 @@ class GogoanimeProvider : MainAPI() { | ||||||
|         val params = mapOf("ep_start" to "0", "ep_end" to "2000", "id" to animeId) |         val params = mapOf("ep_start" to "0", "ep_end" to "2000", "id" to animeId) | ||||||
| 
 | 
 | ||||||
|         val episodes = app.get(episodeloadApi, params = params).document.select("a").map { |         val episodes = app.get(episodeloadApi, params = params).document.select("a").map { | ||||||
|             AnimeEpisode( |             Episode( | ||||||
|                 fixUrl(it.attr("href").trim()), |                 fixUrl(it.attr("href").trim()), | ||||||
|                 "Episode " + it.selectFirst(".name").text().replace("EP", "").trim() |                 "Episode " + it.selectFirst(".name").text().replace("EP", "").trim() | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|  | @ -94,7 +94,7 @@ class KawaiifuProvider : MainAPI() { | ||||||
|         val episodes = Jsoup.parse( |         val episodes = Jsoup.parse( | ||||||
|             app.get(episodesLink).text |             app.get(episodesLink).text | ||||||
|         ).selectFirst(".list-ep").select("li").map { |         ).selectFirst(".list-ep").select("li").map { | ||||||
|             AnimeEpisode( |             Episode( | ||||||
|                 it.selectFirst("a").attr("href"), |                 it.selectFirst("a").attr("href"), | ||||||
|                 if (it.text().trim().toIntOrNull() != null) "Episode ${it.text().trim()}" else it.text().trim() |                 if (it.text().trim().toIntOrNull() != null) "Episode ${it.text().trim()}" else it.text().trim() | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|  | @ -5,7 +5,6 @@ import com.lagradost.cloudstream3.extractors.FEmbed | ||||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
| import com.lagradost.cloudstream3.utils.loadExtractor | import com.lagradost.cloudstream3.utils.loadExtractor | ||||||
| import java.util.* | import java.util.* | ||||||
| import kotlin.collections.ArrayList |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class MonoschinosProvider : MainAPI() { | class MonoschinosProvider : MainAPI() { | ||||||
|  | @ -132,7 +131,7 @@ class MonoschinosProvider : MainAPI() { | ||||||
|             val name = it.selectFirst("p.animetitles").text() |             val name = it.selectFirst("p.animetitles").text() | ||||||
|             val link = it.selectFirst("a").attr("href") |             val link = it.selectFirst("a").attr("href") | ||||||
|             val epThumb = it.selectFirst(".animeimghv").attr("data-src") |             val epThumb = it.selectFirst(".animeimghv").attr("data-src") | ||||||
|             AnimeEpisode(link, name, posterUrl = epThumb) |             Episode(link, name, posterUrl = epThumb) | ||||||
|         } |         } | ||||||
|         return newAnimeLoadResponse(title, url, getType(type)) { |         return newAnimeLoadResponse(title, url, getType(type)) { | ||||||
|             posterUrl = poster |             posterUrl = poster | ||||||
|  |  | ||||||
|  | @ -203,7 +203,7 @@ class NineAnimeProvider : MainAPI() { | ||||||
|         )?.select("ul.episodes li a")?.mapNotNull { |         )?.select("ul.episodes li a")?.mapNotNull { | ||||||
|             val link = it?.attr("href") ?: return@mapNotNull null |             val link = it?.attr("href") ?: return@mapNotNull null | ||||||
|             val name = "Episode ${it.text()}" |             val name = "Episode ${it.text()}" | ||||||
|             AnimeEpisode(link, name) |             Episode(link, name) | ||||||
|         } ?: return null |         } ?: return null | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -125,16 +125,15 @@ class TenshiProvider : MainAPI() { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @SuppressLint("SimpleDateFormat") |     @SuppressLint("SimpleDateFormat") | ||||||
|     private fun dateParser(dateString: String?): String? { |     private fun dateParser(dateString: String?): Date? { | ||||||
|         if (dateString == null) return null |         if (dateString == null) return null | ||||||
|         try { |         try { | ||||||
|             val format = SimpleDateFormat("dd 'of' MMM',' yyyy") |             val format = SimpleDateFormat("dd 'of' MMM',' yyyy") | ||||||
|             val newFormat = SimpleDateFormat("dd-MM-yyyy") |  | ||||||
|             val data = format.parse( |             val data = format.parse( | ||||||
|                 dateString.replace("th ", " ").replace("st ", " ").replace("nd ", " ") |                 dateString.replace("th ", " ").replace("st ", " ").replace("nd ", " ") | ||||||
|                     .replace("rd ", " ") |                     .replace("rd ", " ") | ||||||
|             ) ?: return null |             ) ?: return null | ||||||
|             return newFormat.format(data) |             return data | ||||||
|         } catch (e: Exception) { |         } catch (e: Exception) { | ||||||
|             return null |             return null | ||||||
|         } |         } | ||||||
|  | @ -246,14 +245,12 @@ class TenshiProvider : MainAPI() { | ||||||
| 
 | 
 | ||||||
|         val episodes = ArrayList(episodeNodes.map { |         val episodes = ArrayList(episodeNodes.map { | ||||||
|             val title = it.selectFirst(".episode-title")?.text()?.trim() |             val title = it.selectFirst(".episode-title")?.text()?.trim() | ||||||
|             AnimeEpisode( |             newEpisode(it.attr("href")) { | ||||||
|                 it.attr("href"), |                 this.name = if (title == "No Title") null else title | ||||||
|                 if(title == "No Title") null else title, |                 this.posterUrl = it.selectFirst("img")?.attr("src") | ||||||
|                 it.selectFirst("img")?.attr("src"), |                 addDate(dateParser(it?.selectFirst(".episode-date")?.text()?.trim())) | ||||||
|                 dateParser(it?.selectFirst(".episode-date")?.text()?.trim()), |                 this.description = it.attr("data-content").trim() | ||||||
|                 null, |             } | ||||||
|                 it.attr("data-content").trim(), |  | ||||||
|             ) |  | ||||||
|         }) |         }) | ||||||
| 
 | 
 | ||||||
|         val similarAnime = document.select("ul.anime-loop > li > a")?.mapNotNull { element -> |         val similarAnime = document.select("ul.anime-loop > li > a")?.mapNotNull { element -> | ||||||
|  |  | ||||||
|  | @ -113,28 +113,26 @@ class WatchCartoonOnlineProvider : MainAPI() { | ||||||
|                 val href = it.attr("href") |                 val href = it.attr("href") | ||||||
|                 if (match != null) { |                 if (match != null) { | ||||||
|                     val last = match.groupValues[3] |                     val last = match.groupValues[3] | ||||||
|                     return@map TvSeriesEpisode( |                     return@map Episode( | ||||||
|  |                         href, | ||||||
|                         if (last.startsWith("English")) null else last, |                         if (last.startsWith("English")) null else last, | ||||||
|                         match.groupValues[1].toIntOrNull(), |                         match.groupValues[1].toIntOrNull(), | ||||||
|                         match.groupValues[2].toIntOrNull(), |                         match.groupValues[2].toIntOrNull(), | ||||||
|                         href |  | ||||||
|                     ) |                     ) | ||||||
|                 } |                 } | ||||||
|                 val match2 = Regex("Episode ([0-9]*).*? (.*)").find(text) |                 val match2 = Regex("Episode ([0-9]*).*? (.*)").find(text) | ||||||
|                 if (match2 != null) { |                 if (match2 != null) { | ||||||
|                     val last = match2.groupValues[2] |                     val last = match2.groupValues[2] | ||||||
|                     return@map TvSeriesEpisode( |                     return@map Episode( | ||||||
|  |                         href, | ||||||
|                         if (last.startsWith("English")) null else last, |                         if (last.startsWith("English")) null else last, | ||||||
|                         null, |                         null, | ||||||
|                         match2.groupValues[1].toIntOrNull(), |                         match2.groupValues[1].toIntOrNull(), | ||||||
|                         href |  | ||||||
|                     ) |                     ) | ||||||
|                 } |                 } | ||||||
|                 return@map TvSeriesEpisode( |                 return@map Episode( | ||||||
|                     text, |                     href, | ||||||
|                     null, |                     text | ||||||
|                     null, |  | ||||||
|                     href |  | ||||||
|                 ) |                 ) | ||||||
|             } |             } | ||||||
|             TvSeriesLoadResponse( |             TvSeriesLoadResponse( | ||||||
|  | @ -162,7 +160,7 @@ class WatchCartoonOnlineProvider : MainAPI() { | ||||||
|                 url, |                 url, | ||||||
|                 this.name, |                 this.name, | ||||||
|                 TvType.TvSeries, |                 TvType.TvSeries, | ||||||
|                 listOf(TvSeriesEpisode(title, null, null, url)), |                 listOf(Episode(url,title)), | ||||||
|                 null, |                 null, | ||||||
|                 null, |                 null, | ||||||
|                 description, |                 description, | ||||||
|  |  | ||||||
|  | @ -181,7 +181,7 @@ class WcoProvider : MainAPI() { | ||||||
|         val episodeNodes = document.select(".tab-content .nav-item > a") |         val episodeNodes = document.select(".tab-content .nav-item > a") | ||||||
| 
 | 
 | ||||||
|         val episodes = ArrayList(episodeNodes?.map { |         val episodes = ArrayList(episodeNodes?.map { | ||||||
|             AnimeEpisode(it.attr("href")) |             Episode(it.attr("href")) | ||||||
|         } ?: ArrayList()) |         } ?: ArrayList()) | ||||||
| 
 | 
 | ||||||
|         val statusElem = |         val statusElem = | ||||||
|  |  | ||||||
|  | @ -231,16 +231,10 @@ class ZoroProvider : MainAPI() { | ||||||
|                 ).text |                 ).text | ||||||
|             ).html |             ).html | ||||||
|         ).select(".ss-list > a[href].ssl-item.ep-item").map { |         ).select(".ss-list > a[href].ssl-item.ep-item").map { | ||||||
|             val name = it?.attr("title") |             newEpisode(it.attr("href")) { | ||||||
|             AnimeEpisode( |                 this.name = it?.attr("title") | ||||||
|                 fixUrl(it.attr("href")), |                 this.episode = it.selectFirst(".ssli-order")?.text()?.toIntOrNull() | ||||||
|                 name, |             } | ||||||
|                 null, |  | ||||||
|                 null, |  | ||||||
|                 null, |  | ||||||
|                 null, |  | ||||||
|                 it.selectFirst(".ssli-order")?.text()?.toIntOrNull() |  | ||||||
|             ) |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         val actors = document.select("div.block-actors-content > div.bac-list-wrap > div.bac-item") |         val actors = document.select("div.block-actors-content > div.bac-list-wrap > div.bac-item") | ||||||
|  |  | ||||||
|  | @ -94,23 +94,23 @@ open class TmdbProvider : MainAPI() { | ||||||
|         val episodes = this.seasons?.filter { !disableSeasonZero || (it.season_number ?: 0) != 0 } |         val episodes = this.seasons?.filter { !disableSeasonZero || (it.season_number ?: 0) != 0 } | ||||||
|             ?.mapNotNull { season -> |             ?.mapNotNull { season -> | ||||||
|                 season.episodes?.map { episode -> |                 season.episodes?.map { episode -> | ||||||
|                     TvSeriesEpisode( |                     Episode( | ||||||
|                         episode.name, |  | ||||||
|                         episode.season_number, |  | ||||||
|                         episode.episode_number, |  | ||||||
|                         TmdbLink( |                         TmdbLink( | ||||||
|                             episode.external_ids?.imdb_id ?: this.external_ids?.imdb_id, |                             episode.external_ids?.imdb_id ?: this.external_ids?.imdb_id, | ||||||
|                             this.id, |                             this.id, | ||||||
|                             episode.episode_number, |                             episode.episode_number, | ||||||
|                             episode.season_number, |                             episode.season_number, | ||||||
|                         ).toJson(), |                         ).toJson(), | ||||||
|  |                         episode.name, | ||||||
|  |                         episode.season_number, | ||||||
|  |                         episode.episode_number, | ||||||
|                         getImageUrl(episode.still_path), |                         getImageUrl(episode.still_path), | ||||||
|                         episode.air_date?.toString(), |  | ||||||
|                         episode.rating, |                         episode.rating, | ||||||
|                         episode.overview, |                         episode.overview, | ||||||
|  |                         episode.air_date?.time, | ||||||
|                     ) |                     ) | ||||||
|                 } ?: (1..(season.episode_count ?: 1)).map { episodeNum -> |                 } ?: (1..(season.episode_count ?: 1)).map { episodeNum -> | ||||||
|                     TvSeriesEpisode( |                     Episode( | ||||||
|                         episode = episodeNum, |                         episode = episodeNum, | ||||||
|                         data = TmdbLink( |                         data = TmdbLink( | ||||||
|                             this.external_ids?.imdb_id, |                             this.external_ids?.imdb_id, | ||||||
|  |  | ||||||
|  | @ -63,20 +63,18 @@ class AkwamProvider : MainAPI() { | ||||||
|         return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull() |         return Regex("""\d+""").find(this)?.groupValues?.firstOrNull()?.toIntOrNull() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private fun Element.toTvSeriesEpisode(): TvSeriesEpisode { |     private fun Element.toEpisode(): Episode { | ||||||
|         val a = select("a.text-white") |         val a = select("a.text-white") | ||||||
|         val url = a.attr("href") |         val url = a.attr("href") | ||||||
|         val title = a.text() |         val title = a.text() | ||||||
|         val thumbUrl = select("picture > img").attr("src") |         val thumbUrl = select("picture > img").attr("src") | ||||||
|         val date = select("p.entry-date").text() |         val date = select("p.entry-date").text() | ||||||
|         return TvSeriesEpisode( |         return newEpisode(url) { | ||||||
|             title, |             name = title | ||||||
|             null, |             episode = title.getIntFromText() | ||||||
|             title.getIntFromText(), |             posterUrl = thumbUrl | ||||||
|             url, |             addDate(date) | ||||||
|             thumbUrl, |         } | ||||||
|             date |  | ||||||
|         ) |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -142,7 +140,7 @@ class AkwamProvider : MainAPI() { | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             val episodes = doc.select("div.bg-primary2.p-4.col-lg-4.col-md-6.col-12").map { |             val episodes = doc.select("div.bg-primary2.p-4.col-lg-4.col-md-6.col-12").map { | ||||||
|                 it.toTvSeriesEpisode() |                 it.toEpisode() | ||||||
|             }.let { |             }.let { | ||||||
|                 val isReversed = it.lastOrNull()?.episode ?: 1 < it.firstOrNull()?.episode ?: 0 |                 val isReversed = it.lastOrNull()?.episode ?: 1 < it.firstOrNull()?.episode ?: 0 | ||||||
|                 if (isReversed) |                 if (isReversed) | ||||||
|  |  | ||||||
|  | @ -130,7 +130,7 @@ class AllMoviesForYouProvider : MainAPI() { | ||||||
|             } |             } | ||||||
|             if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found") |             if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found") | ||||||
| 
 | 
 | ||||||
|             val episodeList = ArrayList<TvSeriesEpisode>() |             val episodeList = ArrayList<Episode>() | ||||||
| 
 | 
 | ||||||
|             for (season in list) { |             for (season in list) { | ||||||
|                 val seasonResponse = app.get(season.second).text |                 val seasonResponse = app.get(season.second).text | ||||||
|  | @ -144,15 +144,15 @@ class AllMoviesForYouProvider : MainAPI() { | ||||||
|                         val name = aName.text() |                         val name = aName.text() | ||||||
|                         val href = aName.attr("href") |                         val href = aName.attr("href") | ||||||
|                         val date = episode.selectFirst("> td.MvTbTtl > span")?.text() |                         val date = episode.selectFirst("> td.MvTbTtl > span")?.text() | ||||||
|  | 
 | ||||||
|                         episodeList.add( |                         episodeList.add( | ||||||
|                             TvSeriesEpisode( |                             newEpisode(href) { | ||||||
|                                 name, |                                 this.name = name | ||||||
|                                 season.first, |                                 this.season = season.first | ||||||
|                                 epNum, |                                 this.episode = epNum | ||||||
|                                 fixUrl(href), |                                 this.posterUrl = fixUrlNull(poster) | ||||||
|                                 fixUrlNull(poster), |                                 addDate(date) | ||||||
|                                 date |                             } | ||||||
|                             ) |  | ||||||
|                         ) |                         ) | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  | @ -197,7 +197,7 @@ class AllMoviesForYouProvider : MainAPI() { | ||||||
|             if (id.contains("trembed")) { |             if (id.contains("trembed")) { | ||||||
|                 val soup = app.get(id).document |                 val soup = app.get(id).document | ||||||
|                 soup.select("body iframe").map { |                 soup.select("body iframe").map { | ||||||
|                     val link = fixUrl(it.attr("src").replace("streamhub.to/d/","streamhub.to/e/")) |                     val link = fixUrl(it.attr("src").replace("streamhub.to/d/", "streamhub.to/e/")) | ||||||
|                     loadExtractor(link, data, callback) |                     loadExtractor(link, data, callback) | ||||||
|                 } |                 } | ||||||
|             } else loadExtractor(id, data, callback) |             } else loadExtractor(id, data, callback) | ||||||
|  |  | ||||||
|  | @ -83,14 +83,13 @@ class AsiaFlixProvider : MainAPI() { | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private fun Episodes.toTvSeriesEpisode(): TvSeriesEpisode? { |     private fun Episodes.toEpisode(): Episode? { | ||||||
|         if (videoUrl != null && videoUrl.contains("watch/null") || number == null) return null |         if (videoUrl != null && videoUrl.contains("watch/null") || number == null) return null | ||||||
|         return videoUrl?.let { |         return videoUrl?.let { | ||||||
|             TvSeriesEpisode( |             Episode( | ||||||
|                 null, |                 it, | ||||||
|                 null, |                 null, | ||||||
|                 number, |                 number, | ||||||
|                 it |  | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -101,7 +100,7 @@ class AsiaFlixProvider : MainAPI() { | ||||||
|             "$mainUrl$dramaUrl/$_id".replace("drama-detail", "show-details"), |             "$mainUrl$dramaUrl/$_id".replace("drama-detail", "show-details"), | ||||||
|             this@AsiaFlixProvider.name, |             this@AsiaFlixProvider.name, | ||||||
|             TvType.AsianDrama, |             TvType.AsianDrama, | ||||||
|             episodes.mapNotNull { it.toTvSeriesEpisode() }.sortedBy { it.episode }, |             episodes.mapNotNull { it.toEpisode() }.sortedBy { it.episode }, | ||||||
|             image, |             image, | ||||||
|             releaseYear, |             releaseYear, | ||||||
|             synopsis, |             synopsis, | ||||||
|  | @ -115,7 +114,8 @@ class AsiaFlixProvider : MainAPI() { | ||||||
|         val headers = mapOf("X-Requested-By" to "asiaflix-web") |         val headers = mapOf("X-Requested-By" to "asiaflix-web") | ||||||
|         val response = app.get("$apiUrl/dashboard", headers = headers).text |         val response = app.get("$apiUrl/dashboard", headers = headers).text | ||||||
| 
 | 
 | ||||||
|         val customMapper = mapper.copy().configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true) |         val customMapper = | ||||||
|  |             mapper.copy().configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true) | ||||||
|         // Hack, because it can either be object or a list |         // Hack, because it can either be object or a list | ||||||
|         val cleanedResponse = Regex(""""data":(\{.*?),\{"sectionName"""").replace(response) { |         val cleanedResponse = Regex(""""data":(\{.*?),\{"sectionName"""").replace(response) { | ||||||
|             """"data":null},{"sectionName"""" |             """"data":null},{"sectionName"""" | ||||||
|  | @ -145,14 +145,18 @@ class AsiaFlixProvider : MainAPI() { | ||||||
|     ): Boolean { |     ): Boolean { | ||||||
|         if (isCasting) return false |         if (isCasting) return false | ||||||
|         val headers = mapOf("X-Requested-By" to "asiaflix-web") |         val headers = mapOf("X-Requested-By" to "asiaflix-web") | ||||||
|         app.get("$apiUrl/utility/get-stream-links?url=$data", headers = headers).text.toKotlinObject<Link>().url?.let { |         app.get( | ||||||
|  |             "$apiUrl/utility/get-stream-links?url=$data", | ||||||
|  |             headers = headers | ||||||
|  |         ).text.toKotlinObject<Link>().url?.let { | ||||||
| //            val fixedUrl = "https://api.asiaflix.app/api/v2/utility/cors-proxy/playlist/${URLEncoder.encode(it, StandardCharsets.UTF_8.toString())}" | //            val fixedUrl = "https://api.asiaflix.app/api/v2/utility/cors-proxy/playlist/${URLEncoder.encode(it, StandardCharsets.UTF_8.toString())}" | ||||||
|             callback.invoke( |             callback.invoke( | ||||||
|                 ExtractorLink( |                 ExtractorLink( | ||||||
|                     name, |                     name, | ||||||
|                     name, |                     name, | ||||||
|                     it, |                     it, | ||||||
|                     "https://asianload1.com/", /** <------ This provider should be added instead */ |                     "https://asianload1.com/", | ||||||
|  |                     /** <------ This provider should be added instead */ | ||||||
|                     getQualityFromName(it), |                     getQualityFromName(it), | ||||||
|                     URI(it).path.endsWith(".m3u8") |                     URI(it).path.endsWith(".m3u8") | ||||||
|                 ) |                 ) | ||||||
|  |  | ||||||
|  | @ -242,11 +242,11 @@ open class BflixProvider() : MainAPI() { | ||||||
|             val eptitle = it.selectFirst(".episode a span.name").text() |             val eptitle = it.selectFirst(".episode a span.name").text() | ||||||
|             val secondtitle = it.selectFirst(".episode a span").text() |             val secondtitle = it.selectFirst(".episode a span").text() | ||||||
|                 .replace(Regex("(Episode (\\d+):|Episode (\\d+)-|Episode (\\d+))"),"") ?: "" |                 .replace(Regex("(Episode (\\d+):|Episode (\\d+)-|Episode (\\d+))"),"") ?: "" | ||||||
|             TvSeriesEpisode( |             Episode( | ||||||
|  |                 href, | ||||||
|                 secondtitle+eptitle, |                 secondtitle+eptitle, | ||||||
|                 season, |                 season, | ||||||
|                 episode, |                 episode, | ||||||
|                 href, |  | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
|         val tvType = if (url.contains("/movie/") && episodes.size == 1) TvType.Movie else TvType.TvSeries |         val tvType = if (url.contains("/movie/") && episodes.size == 1) TvType.Movie else TvType.TvSeries | ||||||
|  |  | ||||||
|  | @ -104,11 +104,11 @@ class CinecalidadProvider:MainAPI() { | ||||||
|             val isValid = seasonid.size == 2 |             val isValid = seasonid.size == 2 | ||||||
|             val episode = if (isValid) seasonid.getOrNull(1) else null |             val episode = if (isValid) seasonid.getOrNull(1) else null | ||||||
|             val season = if (isValid) seasonid.getOrNull(0) else null |             val season = if (isValid) seasonid.getOrNull(0) else null | ||||||
|             TvSeriesEpisode( |             Episode( | ||||||
|  |                 href, | ||||||
|                 name, |                 name, | ||||||
|                 season, |                 season, | ||||||
|                 episode, |                 episode, | ||||||
|                 href, |  | ||||||
|                 if (epThumb.contains("svg")) null else epThumb |                 if (epThumb.contains("svg")) null else epThumb | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -1,14 +1,13 @@ | ||||||
| package com.lagradost.cloudstream3.movieproviders | package com.lagradost.cloudstream3.movieproviders | ||||||
| 
 | 
 | ||||||
| import com.fasterxml.jackson.annotation.JsonProperty | import com.fasterxml.jackson.annotation.JsonProperty | ||||||
| import com.fasterxml.jackson.module.kotlin.readValue |  | ||||||
| import com.lagradost.cloudstream3.* | import com.lagradost.cloudstream3.* | ||||||
| import com.lagradost.cloudstream3.mvvm.logError | import com.lagradost.cloudstream3.mvvm.logError | ||||||
| import com.lagradost.cloudstream3.utils.* |  | ||||||
| import com.lagradost.cloudstream3.utils.AppUtils.parseJson | import com.lagradost.cloudstream3.utils.AppUtils.parseJson | ||||||
| import java.util.* | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
|  | import com.lagradost.cloudstream3.utils.loadExtractor | ||||||
| 
 | 
 | ||||||
| class CuevanaProvider:MainAPI() { | class CuevanaProvider : MainAPI() { | ||||||
|     override var mainUrl = "https://cuevana3.me" |     override var mainUrl = "https://cuevana3.me" | ||||||
|     override var name = "Cuevana" |     override var name = "Cuevana" | ||||||
|     override val lang = "es" |     override val lang = "es" | ||||||
|  | @ -19,6 +18,7 @@ class CuevanaProvider:MainAPI() { | ||||||
|         TvType.Movie, |         TvType.Movie, | ||||||
|         TvType.TvSeries, |         TvType.TvSeries, | ||||||
|     ) |     ) | ||||||
|  | 
 | ||||||
|     override suspend fun getMainPage(): HomePageResponse { |     override suspend fun getMainPage(): HomePageResponse { | ||||||
|         val items = ArrayList<HomePageList>() |         val items = ArrayList<HomePageList>() | ||||||
|         val urls = listOf( |         val urls = listOf( | ||||||
|  | @ -28,7 +28,8 @@ class CuevanaProvider:MainAPI() { | ||||||
|         items.add( |         items.add( | ||||||
|             HomePageList( |             HomePageList( | ||||||
|                 "Series", |                 "Series", | ||||||
|                 app.get("$mainUrl/serie", timeout = 120).document.select("section.home-series li").map { |                 app.get("$mainUrl/serie", timeout = 120).document.select("section.home-series li") | ||||||
|  |                     .map { | ||||||
|                         val title = it.selectFirst("h2.Title").text() |                         val title = it.selectFirst("h2.Title").text() | ||||||
|                         val poster = it.selectFirst("img.lazy").attr("data-src") |                         val poster = it.selectFirst("img.lazy").attr("data-src") | ||||||
|                         val url = it.selectFirst("a").attr("href") |                         val url = it.selectFirst("a").attr("href") | ||||||
|  | @ -69,6 +70,7 @@ class CuevanaProvider:MainAPI() { | ||||||
|         if (items.size <= 0) throw ErrorLoadingException() |         if (items.size <= 0) throw ErrorLoadingException() | ||||||
|         return HomePageResponse(items) |         return HomePageResponse(items) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     override suspend fun search(query: String): List<SearchResponse> { |     override suspend fun search(query: String): List<SearchResponse> { | ||||||
|         val url = "$mainUrl/?s=${query}" |         val url = "$mainUrl/?s=${query}" | ||||||
|         val document = app.get(url).document |         val document = app.get(url).document | ||||||
|  | @ -101,6 +103,7 @@ class CuevanaProvider:MainAPI() { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     override suspend fun load(url: String): LoadResponse? { |     override suspend fun load(url: String): LoadResponse? { | ||||||
|         val soup = app.get(url, timeout = 120).document |         val soup = app.get(url, timeout = 120).document | ||||||
|         val title = soup.selectFirst("h1.Title").text() |         val title = soup.selectFirst("h1.Title").text() | ||||||
|  | @ -108,29 +111,32 @@ class CuevanaProvider:MainAPI() { | ||||||
|         val poster: String? = soup.selectFirst(".movtv-info div.Image img").attr("data-src") |         val poster: String? = soup.selectFirst(".movtv-info div.Image img").attr("data-src") | ||||||
|         val year1 = soup.selectFirst("footer p.meta").toString() |         val year1 = soup.selectFirst("footer p.meta").toString() | ||||||
|         val yearRegex = Regex("<span>(\\d+)</span>") |         val yearRegex = Regex("<span>(\\d+)</span>") | ||||||
|         val yearf =  yearRegex.find(year1)?.destructured?.component1()?.replace(Regex("<span>|</span>"),"") |         val yearf = | ||||||
|  |             yearRegex.find(year1)?.destructured?.component1()?.replace(Regex("<span>|</span>"), "") | ||||||
|         val year = if (yearf.isNullOrBlank()) null else yearf.toIntOrNull() |         val year = if (yearf.isNullOrBlank()) null else yearf.toIntOrNull() | ||||||
|         val episodes = soup.select(".all-episodes li.TPostMv article").map { li -> |         val episodes = soup.select(".all-episodes li.TPostMv article").map { li -> | ||||||
|             val href = li.select("a").attr("href") |             val href = li.select("a").attr("href") | ||||||
|             val epThumb = |             val epThumb = | ||||||
|                 li.selectFirst("div.Image img").attr("data-src") ?: li.selectFirst("img.lazy").attr("data-srcc") |                 li.selectFirst("div.Image img").attr("data-src") ?: li.selectFirst("img.lazy") | ||||||
|  |                     .attr("data-srcc") | ||||||
|             val seasonid = li.selectFirst("span.Year").text().let { str -> |             val seasonid = li.selectFirst("span.Year").text().let { str -> | ||||||
|                 str.split("x").mapNotNull { subStr -> subStr.toIntOrNull() } |                 str.split("x").mapNotNull { subStr -> subStr.toIntOrNull() } | ||||||
|             } |             } | ||||||
|             val isValid = seasonid.size == 2 |             val isValid = seasonid.size == 2 | ||||||
|             val episode = if (isValid) seasonid.getOrNull(1) else null |             val episode = if (isValid) seasonid.getOrNull(1) else null | ||||||
|             val season = if (isValid) seasonid.getOrNull(0) else null |             val season = if (isValid) seasonid.getOrNull(0) else null | ||||||
|             TvSeriesEpisode( |             Episode( | ||||||
|  |                 href, | ||||||
|                 null, |                 null, | ||||||
|                 season, |                 season, | ||||||
|                 episode, |                 episode, | ||||||
|                 href, |  | ||||||
|                 fixUrl(epThumb) |                 fixUrl(epThumb) | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
|         val tags = soup.select("ul.InfoList li.AAIco-adjust:contains(Genero) a").map { it.text() } |         val tags = soup.select("ul.InfoList li.AAIco-adjust:contains(Genero) a").map { it.text() } | ||||||
|         val tvType = if (episodes.isEmpty()) TvType.Movie else TvType.TvSeries |         val tvType = if (episodes.isEmpty()) TvType.Movie else TvType.TvSeries | ||||||
|         val recelement = if (tvType == TvType.TvSeries) "main section div.series_listado.series div.xxx" |         val recelement = | ||||||
|  |             if (tvType == TvType.TvSeries) "main section div.series_listado.series div.xxx" | ||||||
|             else "main section ul.MovieList li" |             else "main section ul.MovieList li" | ||||||
|         val recommendations = |         val recommendations = | ||||||
|             soup.select(recelement).mapNotNull { element -> |             soup.select(recelement).mapNotNull { element -> | ||||||
|  | @ -183,6 +189,7 @@ class CuevanaProvider:MainAPI() { | ||||||
|     data class Femcuevana( |     data class Femcuevana( | ||||||
|         @JsonProperty("url") val url: String, |         @JsonProperty("url") val url: String, | ||||||
|     ) |     ) | ||||||
|  | 
 | ||||||
|     override suspend fun loadLinks( |     override suspend fun loadLinks( | ||||||
|         data: String, |         data: String, | ||||||
|         isCasting: Boolean, |         isCasting: Boolean, | ||||||
|  | @ -192,12 +199,17 @@ class CuevanaProvider:MainAPI() { | ||||||
|         app.get(data).document.select("div.TPlayer.embed_div iframe").apmap { |         app.get(data).document.select("div.TPlayer.embed_div iframe").apmap { | ||||||
|             val iframe = fixUrl(it.attr("data-src")) |             val iframe = fixUrl(it.attr("data-src")) | ||||||
|             if (iframe.contains("api.cuevana3.me/fembed/")) { |             if (iframe.contains("api.cuevana3.me/fembed/")) { | ||||||
|                 val femregex = Regex("(https.\\/\\/api\\.cuevana3\\.me\\/fembed\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") |                 val femregex = | ||||||
|  |                     Regex("(https.\\/\\/api\\.cuevana3\\.me\\/fembed\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") | ||||||
|                 femregex.findAll(iframe).map { femreg -> |                 femregex.findAll(iframe).map { femreg -> | ||||||
|                     femreg.value |                     femreg.value | ||||||
|                 }.toList().apmap { fem -> |                 }.toList().apmap { fem -> | ||||||
|                     val key = fem.replace("https://api.cuevana3.me/fembed/?h=","") |                     val key = fem.replace("https://api.cuevana3.me/fembed/?h=", "") | ||||||
|                     val url = app.post("https://api.cuevana3.me/fembed/api.php", allowRedirects = false, headers = mapOf("Host" to "api.cuevana3.me", |                     val url = app.post( | ||||||
|  |                         "https://api.cuevana3.me/fembed/api.php", | ||||||
|  |                         allowRedirects = false, | ||||||
|  |                         headers = mapOf( | ||||||
|  |                             "Host" to "api.cuevana3.me", | ||||||
|                             "User-Agent" to USER_AGENT, |                             "User-Agent" to USER_AGENT, | ||||||
|                             "Accept" to "application/json, text/javascript, */*; q=0.01", |                             "Accept" to "application/json, text/javascript, */*; q=0.01", | ||||||
|                             "Accept-Language" to "en-US,en;q=0.5", |                             "Accept-Language" to "en-US,en;q=0.5", | ||||||
|  | @ -208,8 +220,10 @@ class CuevanaProvider:MainAPI() { | ||||||
|                             "Connection" to "keep-alive", |                             "Connection" to "keep-alive", | ||||||
|                             "Sec-Fetch-Dest" to "empty", |                             "Sec-Fetch-Dest" to "empty", | ||||||
|                             "Sec-Fetch-Mode" to "cors", |                             "Sec-Fetch-Mode" to "cors", | ||||||
|                         "Sec-Fetch-Site" to "same-origin",), |                             "Sec-Fetch-Site" to "same-origin", | ||||||
|                         data = mapOf(Pair("h",key))).text |                         ), | ||||||
|  |                         data = mapOf(Pair("h", key)) | ||||||
|  |                     ).text | ||||||
|                     val json = parseJson<Femcuevana>(url) |                     val json = parseJson<Femcuevana>(url) | ||||||
|                     val link = json.url |                     val link = json.url | ||||||
|                     if (link.contains("fembed")) { |                     if (link.contains("fembed")) { | ||||||
|  | @ -218,13 +232,16 @@ class CuevanaProvider:MainAPI() { | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             if (iframe.contains("tomatomatela")) { |             if (iframe.contains("tomatomatela")) { | ||||||
|                 val tomatoRegex = Regex("(\\/\\/apialfa.tomatomatela.com\\/ir\\/player.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") |                 val tomatoRegex = | ||||||
|  |                     Regex("(\\/\\/apialfa.tomatomatela.com\\/ir\\/player.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") | ||||||
|                 tomatoRegex.findAll(iframe).map { tomreg -> |                 tomatoRegex.findAll(iframe).map { tomreg -> | ||||||
|                     tomreg.value |                     tomreg.value | ||||||
|                 }.toList().apmap { tom -> |                 }.toList().apmap { tom -> | ||||||
|                     val tomkey = tom.replace("//apialfa.tomatomatela.com/ir/player.php?h=","") |                     val tomkey = tom.replace("//apialfa.tomatomatela.com/ir/player.php?h=", "") | ||||||
|                     app.post("https://apialfa.tomatomatela.com/ir/rd.php", allowRedirects = false, |                     app.post( | ||||||
|                         headers = mapOf("Host" to "apialfa.tomatomatela.com", |                         "https://apialfa.tomatomatela.com/ir/rd.php", allowRedirects = false, | ||||||
|  |                         headers = mapOf( | ||||||
|  |                             "Host" to "apialfa.tomatomatela.com", | ||||||
|                             "User-Agent" to USER_AGENT, |                             "User-Agent" to USER_AGENT, | ||||||
|                             "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", |                             "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", | ||||||
|                             "Accept-Language" to "en-US,en;q=0.5", |                             "Accept-Language" to "en-US,en;q=0.5", | ||||||
|  | @ -235,16 +252,21 @@ class CuevanaProvider:MainAPI() { | ||||||
|                             "Upgrade-Insecure-Requests" to "1", |                             "Upgrade-Insecure-Requests" to "1", | ||||||
|                             "Sec-Fetch-Dest" to "iframe", |                             "Sec-Fetch-Dest" to "iframe", | ||||||
|                             "Sec-Fetch-Mode" to "navigate", |                             "Sec-Fetch-Mode" to "navigate", | ||||||
|                             "Sec-Fetch-Site" to "same-origin",), |                             "Sec-Fetch-Site" to "same-origin", | ||||||
|                         data = mapOf(Pair("url",tomkey)) |                         ), | ||||||
|  |                         data = mapOf(Pair("url", tomkey)) | ||||||
|                     ).response.headers.values("location").apmap { loc -> |                     ).response.headers.values("location").apmap { loc -> | ||||||
|                         if (loc.contains("goto_ddh.php")) { |                         if (loc.contains("goto_ddh.php")) { | ||||||
|                             val gotoregex = Regex("(\\/\\/api.cuevana3.me\\/ir\\/goto_ddh.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") |                             val gotoregex = | ||||||
|  |                                 Regex("(\\/\\/api.cuevana3.me\\/ir\\/goto_ddh.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") | ||||||
|                             gotoregex.findAll(loc).map { goreg -> |                             gotoregex.findAll(loc).map { goreg -> | ||||||
|                                 goreg.value.replace("//api.cuevana3.me/ir/goto_ddh.php?h=","") |                                 goreg.value.replace("//api.cuevana3.me/ir/goto_ddh.php?h=", "") | ||||||
|                             }.toList().apmap { gotolink -> |                             }.toList().apmap { gotolink -> | ||||||
|                                 app.post("https://api.cuevana3.me/ir/redirect_ddh.php", allowRedirects = false, |                                 app.post( | ||||||
|                                     headers = mapOf("Host" to "api.cuevana3.me", |                                     "https://api.cuevana3.me/ir/redirect_ddh.php", | ||||||
|  |                                     allowRedirects = false, | ||||||
|  |                                     headers = mapOf( | ||||||
|  |                                         "Host" to "api.cuevana3.me", | ||||||
|                                         "User-Agent" to USER_AGENT, |                                         "User-Agent" to USER_AGENT, | ||||||
|                                         "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", |                                         "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", | ||||||
|                                         "Accept-Language" to "en-US,en;q=0.5", |                                         "Accept-Language" to "en-US,en;q=0.5", | ||||||
|  | @ -255,20 +277,24 @@ class CuevanaProvider:MainAPI() { | ||||||
|                                         "Upgrade-Insecure-Requests" to "1", |                                         "Upgrade-Insecure-Requests" to "1", | ||||||
|                                         "Sec-Fetch-Dest" to "iframe", |                                         "Sec-Fetch-Dest" to "iframe", | ||||||
|                                         "Sec-Fetch-Mode" to "navigate", |                                         "Sec-Fetch-Mode" to "navigate", | ||||||
|                                         "Sec-Fetch-Site" to "same-origin",), |                                         "Sec-Fetch-Site" to "same-origin", | ||||||
|                                     data = mapOf(Pair("url",gotolink)) |                                     ), | ||||||
|  |                                     data = mapOf(Pair("url", gotolink)) | ||||||
|                                 ).response.headers.values("location").apmap { golink -> |                                 ).response.headers.values("location").apmap { golink -> | ||||||
|                                     loadExtractor(golink, data, callback) |                                     loadExtractor(golink, data, callback) | ||||||
|                                 } |                                 } | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                         if (loc.contains("index.php?h=")) { |                         if (loc.contains("index.php?h=")) { | ||||||
|                             val indexRegex = Regex("(\\/\\/api.cuevana3.me\\/sc\\/index.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") |                             val indexRegex = | ||||||
|  |                                 Regex("(\\/\\/api.cuevana3.me\\/sc\\/index.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") | ||||||
|                             indexRegex.findAll(loc).map { indreg -> |                             indexRegex.findAll(loc).map { indreg -> | ||||||
|                                 indreg.value.replace("//api.cuevana3.me/sc/index.php?h=","") |                                 indreg.value.replace("//api.cuevana3.me/sc/index.php?h=", "") | ||||||
|                             }.toList().apmap { inlink -> |                             }.toList().apmap { inlink -> | ||||||
|                                 app.post("https://api.cuevana3.me/sc/r.php", allowRedirects = false, |                                 app.post( | ||||||
|                                     headers = mapOf("Host" to "api.cuevana3.me", |                                     "https://api.cuevana3.me/sc/r.php", allowRedirects = false, | ||||||
|  |                                     headers = mapOf( | ||||||
|  |                                         "Host" to "api.cuevana3.me", | ||||||
|                                         "User-Agent" to USER_AGENT, |                                         "User-Agent" to USER_AGENT, | ||||||
|                                         "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", |                                         "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", | ||||||
|                                         "Accept-Language" to "en-US,en;q=0.5", |                                         "Accept-Language" to "en-US,en;q=0.5", | ||||||
|  | @ -281,8 +307,9 @@ class CuevanaProvider:MainAPI() { | ||||||
|                                         "Sec-Fetch-Dest" to "iframe", |                                         "Sec-Fetch-Dest" to "iframe", | ||||||
|                                         "Sec-Fetch-Mode" to "navigate", |                                         "Sec-Fetch-Mode" to "navigate", | ||||||
|                                         "Sec-Fetch-Site" to "same-origin", |                                         "Sec-Fetch-Site" to "same-origin", | ||||||
|                                         "Sec-Fetch-User" to "?1",), |                                         "Sec-Fetch-User" to "?1", | ||||||
|                                     data = mapOf(Pair("h",inlink)) |                                     ), | ||||||
|  |                                     data = mapOf(Pair("h", inlink)) | ||||||
|                                 ).response.headers.values("location").apmap { link -> |                                 ).response.headers.values("location").apmap { link -> | ||||||
|                                     loadExtractor(link, data, callback) |                                     loadExtractor(link, data, callback) | ||||||
|                                 } |                                 } | ||||||
|  |  | ||||||
|  | @ -133,7 +133,7 @@ class DoramasYTProvider : MainAPI() { | ||||||
|             val name = it.selectFirst(".dtlsflim p").text() |             val name = it.selectFirst(".dtlsflim p").text() | ||||||
|             val link = it.selectFirst("a").attr("href") |             val link = it.selectFirst("a").attr("href") | ||||||
|             val epThumb = it.selectFirst(".flimimg img.img1").attr("src") |             val epThumb = it.selectFirst(".flimimg img.img1").attr("src") | ||||||
|             AnimeEpisode(link, name, posterUrl = epThumb) |             Episode(link, name, posterUrl = epThumb) | ||||||
|         } |         } | ||||||
|         return newAnimeLoadResponse(title, url, getType(type)) { |         return newAnimeLoadResponse(title, url, getType(type)) { | ||||||
|             posterUrl = poster |             posterUrl = poster | ||||||
|  |  | ||||||
|  | @ -118,7 +118,7 @@ class DramaSeeProvider : MainAPI() { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Episodes Links |         // Episodes Links | ||||||
|         val episodeList = ArrayList<TvSeriesEpisode>() |         val episodeList = ArrayList<Episode>() | ||||||
|         body?.select("ul.episodes > li")?.forEach { ep -> |         body?.select("ul.episodes > li")?.forEach { ep -> | ||||||
|             val innerA = ep.select("a") ?: return@forEach |             val innerA = ep.select("a") ?: return@forEach | ||||||
|             val count = innerA.select("span.episode")?.text()?.toIntOrNull() ?: 0 |             val count = innerA.select("span.episode")?.text()?.toIntOrNull() ?: 0 | ||||||
|  | @ -141,7 +141,7 @@ class DramaSeeProvider : MainAPI() { | ||||||
| 
 | 
 | ||||||
|                     //Log.i(this.name, "Result => (listOfLinks) ${listOfLinks.toJson()}") |                     //Log.i(this.name, "Result => (listOfLinks) ${listOfLinks.toJson()}") | ||||||
|                     episodeList.add( |                     episodeList.add( | ||||||
|                         TvSeriesEpisode( |                         Episode( | ||||||
|                             name = null, |                             name = null, | ||||||
|                             season = null, |                             season = null, | ||||||
|                             episode = count, |                             episode = count, | ||||||
|  |  | ||||||
|  | @ -1,9 +1,9 @@ | ||||||
| package com.lagradost.cloudstream3.movieproviders | package com.lagradost.cloudstream3.movieproviders | ||||||
| 
 | 
 | ||||||
| import com.lagradost.cloudstream3.* |  | ||||||
| import com.lagradost.cloudstream3.utils.ExtractorLink |  | ||||||
| import com.lagradost.cloudstream3.utils.AppUtils.parseJson |  | ||||||
| import com.fasterxml.jackson.annotation.JsonProperty | import com.fasterxml.jackson.annotation.JsonProperty | ||||||
|  | import com.lagradost.cloudstream3.* | ||||||
|  | import com.lagradost.cloudstream3.utils.AppUtils.parseJson | ||||||
|  | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
| import org.jsoup.nodes.Element | import org.jsoup.nodes.Element | ||||||
| 
 | 
 | ||||||
| class EgyBestProvider : MainAPI() { | class EgyBestProvider : MainAPI() { | ||||||
|  | @ -109,7 +109,7 @@ class EgyBestProvider : MainAPI() { | ||||||
|                 this.actors = actors |                 this.actors = actors | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             val episodes = ArrayList<TvSeriesEpisode>() |             val episodes = ArrayList<Episode>() | ||||||
|             doc.select("#mainLoad > div:nth-child(2) > div.h_scroll > div a").map { |             doc.select("#mainLoad > div:nth-child(2) > div.h_scroll > div a").map { | ||||||
|                 it.attr("href") |                 it.attr("href") | ||||||
|             }.apmap { |             }.apmap { | ||||||
|  | @ -118,13 +118,11 @@ class EgyBestProvider : MainAPI() { | ||||||
|                 d.select("#mainLoad > div:nth-child(3) > div.movies_small a").map { eit -> |                 d.select("#mainLoad > div:nth-child(3) > div.movies_small a").map { eit -> | ||||||
|                     val ep = Regex("ep-(.....)").find(eit.attr("href"))?.groupValues?.getOrNull(1)?.getIntFromText() |                     val ep = Regex("ep-(.....)").find(eit.attr("href"))?.groupValues?.getOrNull(1)?.getIntFromText() | ||||||
|                     episodes.add( |                     episodes.add( | ||||||
|                         TvSeriesEpisode( |                         Episode( | ||||||
|  |                             eit.attr("href"), | ||||||
|                             eit.select("span.title").text(), |                             eit.select("span.title").text(), | ||||||
|                             season, |                             season, | ||||||
|                             ep, |                             ep, | ||||||
|                             eit.attr("href"), |  | ||||||
|                             null, |  | ||||||
|                             null |  | ||||||
|                         ) |                         ) | ||||||
|                     ) |                     ) | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  | @ -2,8 +2,8 @@ package com.lagradost.cloudstream3.movieproviders | ||||||
| 
 | 
 | ||||||
| import com.lagradost.cloudstream3.* | import com.lagradost.cloudstream3.* | ||||||
| import com.lagradost.cloudstream3.mvvm.logError | import com.lagradost.cloudstream3.mvvm.logError | ||||||
| import com.lagradost.cloudstream3.utils.* | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
| import java.util.* | import com.lagradost.cloudstream3.utils.loadExtractor | ||||||
| 
 | 
 | ||||||
| class EntrepeliculasyseriesProvider:MainAPI() { | class EntrepeliculasyseriesProvider:MainAPI() { | ||||||
|     override var mainUrl = "https://entrepeliculasyseries.nu" |     override var mainUrl = "https://entrepeliculasyseries.nu" | ||||||
|  | @ -102,11 +102,11 @@ class EntrepeliculasyseriesProvider:MainAPI() { | ||||||
|             val isValid = seasonid.size == 2 |             val isValid = seasonid.size == 2 | ||||||
|             val episode = if (isValid) seasonid.getOrNull(1) else null |             val episode = if (isValid) seasonid.getOrNull(1) else null | ||||||
|             val season = if (isValid) seasonid.getOrNull(0) else null |             val season = if (isValid) seasonid.getOrNull(0) else null | ||||||
|             TvSeriesEpisode( |             Episode( | ||||||
|  |                 href, | ||||||
|                 null, |                 null, | ||||||
|                 season, |                 season, | ||||||
|                 episode, |                 episode, | ||||||
|                 href, |  | ||||||
|                 fixUrl(epThumb) |                 fixUrl(epThumb) | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -100,11 +100,11 @@ class FilmanProvider : MainAPI() { | ||||||
|             val e = episode.text() |             val e = episode.text() | ||||||
|             val regex = Regex("""\[s(\d{1,3})e(\d{1,3})]""").find(e) ?: return@mapNotNull null |             val regex = Regex("""\[s(\d{1,3})e(\d{1,3})]""").find(e) ?: return@mapNotNull null | ||||||
|             val eid = regex.groups |             val eid = regex.groups | ||||||
|             TvSeriesEpisode( |             Episode( | ||||||
|  |                 episode.attr("href"), | ||||||
|                 e.split("]")[1].trim(), |                 e.split("]")[1].trim(), | ||||||
|                 eid[1]?.value?.toInt(), |                 eid[1]?.value?.toInt(), | ||||||
|                 eid[2]?.value?.toInt(), |                 eid[2]?.value?.toInt(), | ||||||
|                 episode.attr("href"), |  | ||||||
|             ) |             ) | ||||||
|         }.toMutableList() |         }.toMutableList() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -139,7 +139,7 @@ class IHaveNoTvProvider : MainAPI() { | ||||||
|         val episodes = if (isSeries) { |         val episodes = if (isSeries) { | ||||||
|             container?.select(".episode")?.map { ep -> |             container?.select(".episode")?.map { ep -> | ||||||
|                 val thumb = ep.selectFirst("img").attr("src") |                 val thumb = ep.selectFirst("img").attr("src") | ||||||
|                 val epTitle = ep.selectFirst("a[title]").attr("title") | 
 | ||||||
|                 val epLink = fixUrl(ep.selectFirst("a[title]").attr("href")) |                 val epLink = fixUrl(ep.selectFirst("a[title]").attr("href")) | ||||||
|                 val (season, epNum) = if (ep.selectFirst(".episodeMeta > strong") != null && |                 val (season, epNum) = if (ep.selectFirst(".episodeMeta > strong") != null && | ||||||
|                     ep.selectFirst(".episodeMeta > strong").html().contains("S") |                     ep.selectFirst(".episodeMeta > strong").html().contains("S") | ||||||
|  | @ -150,7 +150,7 @@ class IHaveNoTvProvider : MainAPI() { | ||||||
|                         split?.get(1)?.toIntOrNull() |                         split?.get(1)?.toIntOrNull() | ||||||
|                     ) |                     ) | ||||||
|                 } else Pair<Int?, Int?>(null, null) |                 } else Pair<Int?, Int?>(null, null) | ||||||
|                 val epDescription = ep.selectFirst(".episodeSynopsis")?.text() | 
 | ||||||
|                 year = Regex("""•?\s+(\d{4})\s+•""").find( |                 year = Regex("""•?\s+(\d{4})\s+•""").find( | ||||||
|                     ep.selectFirst(".episodeMeta").text() |                     ep.selectFirst(".episodeMeta").text() | ||||||
|                 )?.destructured?.component1()?.toIntOrNull() |                 )?.destructured?.component1()?.toIntOrNull() | ||||||
|  | @ -158,16 +158,13 @@ class IHaveNoTvProvider : MainAPI() { | ||||||
|                 categories.addAll( |                 categories.addAll( | ||||||
|                     ep.select(".episodeMeta > a[href*=\"/category/\"]").map { it.text().trim() }) |                     ep.select(".episodeMeta > a[href*=\"/category/\"]").map { it.text().trim() }) | ||||||
| 
 | 
 | ||||||
|                 TvSeriesEpisode( |                 newEpisode(epLink) { | ||||||
|                     epTitle, |                     this.name = ep.selectFirst("a[title]").attr("title") | ||||||
|                     season, |                     this.season = season | ||||||
|                     epNum, |                     this.episode = epNum | ||||||
|                     epLink, |                     this.posterUrl = thumb | ||||||
|                     thumb, |                     this.description = ep.selectFirst(".episodeSynopsis")?.text() | ||||||
|                     null, |                 } | ||||||
|                     null, |  | ||||||
|                     epDescription |  | ||||||
|                 ) |  | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             listOf(MovieLoadResponse( |             listOf(MovieLoadResponse( | ||||||
|  | @ -188,7 +185,7 @@ class IHaveNoTvProvider : MainAPI() { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         val poster = episodes?.firstOrNull().let { |         val poster = episodes?.firstOrNull().let { | ||||||
|             if (isSeries && it != null) (it as TvSeriesEpisode).posterUrl |             if (isSeries && it != null) (it as Episode).posterUrl | ||||||
|             else null |             else null | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -197,7 +194,7 @@ class IHaveNoTvProvider : MainAPI() { | ||||||
|             url, |             url, | ||||||
|             this.name, |             this.name, | ||||||
|             TvType.TvSeries, |             TvType.TvSeries, | ||||||
|             episodes!!.map { it as TvSeriesEpisode }, |             episodes!!.map { it as Episode }, | ||||||
|             poster, |             poster, | ||||||
|             year, |             year, | ||||||
|             description, |             description, | ||||||
|  |  | ||||||
|  | @ -173,7 +173,7 @@ class KdramaHoodProvider : MainAPI() { | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             TvSeriesEpisode( |             Episode( | ||||||
|                 name = null, |                 name = null, | ||||||
|                 season = null, |                 season = null, | ||||||
|                 episode = count, |                 episode = count, | ||||||
|  |  | ||||||
|  | @ -273,11 +273,11 @@ class LookMovieProvider : MainAPI() { | ||||||
|                     ).toJson() |                     ).toJson() | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|                 TvSeriesEpisode( |                 Episode( | ||||||
|  |                     localData, | ||||||
|                     it.title, |                     it.title, | ||||||
|                     it.season.toIntOrNull(), |                     it.season.toIntOrNull(), | ||||||
|                     it.episode.toIntOrNull(), |                     it.episode.toIntOrNull(), | ||||||
|                     localData |  | ||||||
|                 ) |                 ) | ||||||
|             }.toList() |             }.toList() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -5,7 +5,6 @@ import com.fasterxml.jackson.module.kotlin.readValue | ||||||
| import com.lagradost.cloudstream3.* | import com.lagradost.cloudstream3.* | ||||||
| import com.lagradost.cloudstream3.LoadResponse.Companion.addImdbUrl | import com.lagradost.cloudstream3.LoadResponse.Companion.addImdbUrl | ||||||
| import com.lagradost.cloudstream3.utils.AppUtils.parseJson | import com.lagradost.cloudstream3.utils.AppUtils.parseJson | ||||||
| import com.lagradost.cloudstream3.utils.AppUtils.toJson |  | ||||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
| import com.lagradost.cloudstream3.utils.getQualityFromName | import com.lagradost.cloudstream3.utils.getQualityFromName | ||||||
| import org.jsoup.Jsoup | import org.jsoup.Jsoup | ||||||
|  | @ -87,7 +86,7 @@ class MeloMovieProvider : MainAPI() { | ||||||
|         return url |         return url | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private fun serializeData(element: Element): String { |     private fun serializeData(element: Element): List<MeloMovieProvider.MeloMovieLink> { | ||||||
|         val eps = element.select("> tbody > tr") |         val eps = element.select("> tbody > tr") | ||||||
|         val parsed = eps.map { |         val parsed = eps.map { | ||||||
|             try { |             try { | ||||||
|  | @ -99,7 +98,7 @@ class MeloMovieProvider : MainAPI() { | ||||||
|                 MeloMovieLink("", "") |                 MeloMovieLink("", "") | ||||||
|             } |             } | ||||||
|         }.filter { it.link != "" && it.name != "" } |         }.filter { it.link != "" && it.name != "" } | ||||||
|         return parsed.toJson() |         return parsed | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override suspend fun loadLinks( |     override suspend fun loadLinks( | ||||||
|  | @ -157,7 +156,7 @@ class MeloMovieProvider : MainAPI() { | ||||||
|                 addImdbUrl(imdbUrl) |                 addImdbUrl(imdbUrl) | ||||||
|             } |             } | ||||||
|         } else if (type == 2) { |         } else if (type == 2) { | ||||||
|             val episodes = ArrayList<TvSeriesEpisode>() |             val episodes = ArrayList<Episode>() | ||||||
|             val seasons = document.select("div.accordion__card") |             val seasons = document.select("div.accordion__card") | ||||||
|                 ?: throw ErrorLoadingException("No episodes found") |                 ?: throw ErrorLoadingException("No episodes found") | ||||||
|             for (s in seasons) { |             for (s in seasons) { | ||||||
|  | @ -172,7 +171,10 @@ class MeloMovieProvider : MainAPI() { | ||||||
|                     val links = |                     val links = | ||||||
|                         e.selectFirst("> div.collapse > div > table.accordion__list") ?: continue |                         e.selectFirst("> div.collapse > div > table.accordion__list") ?: continue | ||||||
|                     val data = serializeData(links) |                     val data = serializeData(links) | ||||||
|                     episodes.add(TvSeriesEpisode(null, season, episode, data)) |                     episodes.add(newEpisode(data) { | ||||||
|  |                         this.season = season | ||||||
|  |                         this.episode = episode | ||||||
|  |                     }) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             episodes.reverse() |             episodes.reverse() | ||||||
|  |  | ||||||
|  | @ -31,7 +31,7 @@ class MyCimaProvider : MainAPI() { | ||||||
|         val title = select("div.Thumb--GridItem strong").text() |         val title = select("div.Thumb--GridItem strong").text() | ||||||
|             .replace("$year", "") |             .replace("$year", "") | ||||||
|             .replace("مشاهدة|فيلم|مسلسل|مترجم".toRegex(), "") |             .replace("مشاهدة|فيلم|مسلسل|مترجم".toRegex(), "") | ||||||
|             .replace("( نسخة مدبلجة )"," ( نسخة مدبلجة ) ") |             .replace("( نسخة مدبلجة )", " ( نسخة مدبلجة ) ") | ||||||
|         // If you need to differentiate use the url. |         // If you need to differentiate use the url. | ||||||
|         return MovieSearchResponse( |         return MovieSearchResponse( | ||||||
|             title, |             title, | ||||||
|  | @ -47,8 +47,8 @@ class MyCimaProvider : MainAPI() { | ||||||
|     override suspend fun getMainPage(): HomePageResponse { |     override suspend fun getMainPage(): HomePageResponse { | ||||||
|         // Title, Url |         // Title, Url | ||||||
|         val moviesUrl = listOf( |         val moviesUrl = listOf( | ||||||
|             "Movies" to "$mainUrl/movies/page/"+(0..25).random(), |             "Movies" to "$mainUrl/movies/page/" + (0..25).random(), | ||||||
|             "Series" to "$mainUrl/seriestv/new/page/"+(0..25).random() |             "Series" to "$mainUrl/seriestv/new/page/" + (0..25).random() | ||||||
|         ) |         ) | ||||||
|         val pages = moviesUrl.apmap { |         val pages = moviesUrl.apmap { | ||||||
|             val doc = app.get(it.second).document |             val doc = app.get(it.second).document | ||||||
|  | @ -61,21 +61,23 @@ class MyCimaProvider : MainAPI() { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override suspend fun search(query: String): List<SearchResponse> { |     override suspend fun search(query: String): List<SearchResponse> { | ||||||
|         val q = query.replace(" ","%20") |         val q = query.replace(" ", "%20") | ||||||
|         val result = arrayListOf<SearchResponse>() |         val result = arrayListOf<SearchResponse>() | ||||||
|         listOf("$mainUrl/search/$q", |         listOf( | ||||||
|  |             "$mainUrl/search/$q", | ||||||
|             "$mainUrl/search/$q/list/series/", |             "$mainUrl/search/$q/list/series/", | ||||||
|             "$mainUrl/search/$q/list/anime/").apmap { url -> |             "$mainUrl/search/$q/list/anime/" | ||||||
|  |         ).apmap { url -> | ||||||
|             val d = app.get(url).document |             val d = app.get(url).document | ||||||
|             d.select("div.Grid--MycimaPosts div.GridItem").mapNotNull { |             d.select("div.Grid--MycimaPosts div.GridItem").mapNotNull { | ||||||
|                 if(it.text().contains("اعلان")) return@mapNotNull null |                 if (it.text().contains("اعلان")) return@mapNotNull null | ||||||
|                 it.toSearchResponse()?.let { it1 -> result.add(it1) } |                 it.toSearchResponse()?.let { it1 -> result.add(it1) } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         return result.distinct().sortedBy { it.name } |         return result.distinct().sortedBy { it.name } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     data class MoreEPS ( |     data class MoreEPS( | ||||||
|         val output: String |         val output: String | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|  | @ -86,7 +88,8 @@ class MyCimaProvider : MainAPI() { | ||||||
|             doc.select("mycima.separated--top")?.attr("data-lazy-style")?.getImageURL() |             doc.select("mycima.separated--top")?.attr("data-lazy-style")?.getImageURL() | ||||||
|                 ?.ifEmpty { doc.select("meta[itemprop=\"thumbnailUrl\"]")?.attr("content") } |                 ?.ifEmpty { doc.select("meta[itemprop=\"thumbnailUrl\"]")?.attr("content") } | ||||||
|                 ?.ifEmpty { doc.select("mycima.separated--top")?.attr("style")?.getImageURL() } |                 ?.ifEmpty { doc.select("mycima.separated--top")?.attr("style")?.getImageURL() } | ||||||
|         val year = doc.select("div.Title--Content--Single-begin h1 a.unline")?.text()?.getIntFromText() |         val year = | ||||||
|  |             doc.select("div.Title--Content--Single-begin h1 a.unline")?.text()?.getIntFromText() | ||||||
|         val title = doc.select("div.Title--Content--Single-begin h1").text() |         val title = doc.select("div.Title--Content--Single-begin h1").text() | ||||||
|             .replace("($year)", "") |             .replace("($year)", "") | ||||||
|             .replace("مشاهدة|فيلم|مسلسل|مترجم|انمي".toRegex(), "") |             .replace("مشاهدة|فيلم|مسلسل|مترجم|انمي".toRegex(), "") | ||||||
|  | @ -96,7 +99,8 @@ class MyCimaProvider : MainAPI() { | ||||||
|                 it.text().contains("المدة") |                 it.text().contains("المدة") | ||||||
|             }?.text()?.getIntFromText() |             }?.text()?.getIntFromText() | ||||||
| 
 | 
 | ||||||
|         val synopsis = doc.select("div.StoryMovieContent").text().ifEmpty { doc.select("div.PostItemContent").text() } |         val synopsis = doc.select("div.StoryMovieContent").text() | ||||||
|  |             .ifEmpty { doc.select("div.PostItemContent").text() } | ||||||
| 
 | 
 | ||||||
|         val tags = doc.select("li:nth-child(3) > p > a").map { it.text() } |         val tags = doc.select("li:nth-child(3) > p > a").map { it.text() } | ||||||
| 
 | 
 | ||||||
|  | @ -107,7 +111,8 @@ class MyCimaProvider : MainAPI() { | ||||||
|                 ?: return@mapNotNull null |                 ?: return@mapNotNull null | ||||||
|             Actor(name, image) |             Actor(name, image) | ||||||
|         } |         } | ||||||
|         val recommendations = doc.select("div.Grid--MycimaPosts div.GridItem")?.mapNotNull { element -> |         val recommendations = | ||||||
|  |             doc.select("div.Grid--MycimaPosts div.GridItem")?.mapNotNull { element -> | ||||||
|                 element.toSearchResponse() |                 element.toSearchResponse() | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  | @ -127,55 +132,165 @@ class MyCimaProvider : MainAPI() { | ||||||
|                 addActors(actors) |                 addActors(actors) | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             val episodes = ArrayList<TvSeriesEpisode>() |             val episodes = ArrayList<Episode>() | ||||||
|             val seasons = doc.select("div.List--Seasons--Episodes a").not(".selected").map { |             val seasons = doc.select("div.List--Seasons--Episodes a").not(".selected").map { | ||||||
|                 it.attr("href") |                 it.attr("href") | ||||||
|             } |             } | ||||||
|             val moreButton = doc.select("div.MoreEpisodes--Button") |             val moreButton = doc.select("div.MoreEpisodes--Button") | ||||||
|             val season = doc.select("div.List--Seasons--Episodes a.selected").text().getIntFromText() |             val season = | ||||||
|  |                 doc.select("div.List--Seasons--Episodes a.selected").text().getIntFromText() | ||||||
|             doc.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a") |             doc.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a") | ||||||
|                 .apmap { episodes.add(TvSeriesEpisode(it.text(), season, it.text().getIntFromText(), it.attr("href"), null, null))} |                 .apmap { | ||||||
|             if(moreButton.isNotEmpty()) { |                     episodes.add( | ||||||
|  |                         Episode( | ||||||
|  |                             it.attr("href"), | ||||||
|  |                             it.text(), | ||||||
|  |                             season, | ||||||
|  |                             it.text().getIntFromText(), | ||||||
|  |                         ) | ||||||
|  |                     ) | ||||||
|  |                 } | ||||||
|  |             if (moreButton.isNotEmpty()) { | ||||||
|                 val n = doc.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a").size |                 val n = doc.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a").size | ||||||
|                 val totals = doc.select("div.Episodes--Seasons--Episodes a").first().text().getIntFromText() |                 val totals = | ||||||
|                 val mEPS = arrayListOf(n, n+40, n+80, n+120, n+160, n+200, n+240, n+280, n+320, n+360, n+400, n+440, n+480, n+520, n+660, n+700, n+740, n+780, n+820, n+860, n+900, n+940, n+980, n+1020, n+1060, n+1100, n+1140, n+1180, n+1220, totals) |                     doc.select("div.Episodes--Seasons--Episodes a").first().text().getIntFromText() | ||||||
|  |                 val mEPS = arrayListOf( | ||||||
|  |                     n, | ||||||
|  |                     n + 40, | ||||||
|  |                     n + 80, | ||||||
|  |                     n + 120, | ||||||
|  |                     n + 160, | ||||||
|  |                     n + 200, | ||||||
|  |                     n + 240, | ||||||
|  |                     n + 280, | ||||||
|  |                     n + 320, | ||||||
|  |                     n + 360, | ||||||
|  |                     n + 400, | ||||||
|  |                     n + 440, | ||||||
|  |                     n + 480, | ||||||
|  |                     n + 520, | ||||||
|  |                     n + 660, | ||||||
|  |                     n + 700, | ||||||
|  |                     n + 740, | ||||||
|  |                     n + 780, | ||||||
|  |                     n + 820, | ||||||
|  |                     n + 860, | ||||||
|  |                     n + 900, | ||||||
|  |                     n + 940, | ||||||
|  |                     n + 980, | ||||||
|  |                     n + 1020, | ||||||
|  |                     n + 1060, | ||||||
|  |                     n + 1100, | ||||||
|  |                     n + 1140, | ||||||
|  |                     n + 1180, | ||||||
|  |                     n + 1220, | ||||||
|  |                     totals | ||||||
|  |                 ) | ||||||
|                 mEPS.apmap { it -> |                 mEPS.apmap { it -> | ||||||
|                     if (it != null) { |                     if (it != null) { | ||||||
|                             if(it > totals!!) return@apmap |                         if (it > totals!!) return@apmap | ||||||
|                             val ajaxURL = "$mainUrl/AjaxCenter/MoreEpisodes/${moreButton.attr("data-term")}/$it" |                         val ajaxURL = | ||||||
|  |                             "$mainUrl/AjaxCenter/MoreEpisodes/${moreButton.attr("data-term")}/$it" | ||||||
|                         val jsonResponse = app.get(ajaxURL) |                         val jsonResponse = app.get(ajaxURL) | ||||||
|                         val json = parseJson<MoreEPS>(jsonResponse.text) |                         val json = parseJson<MoreEPS>(jsonResponse.text) | ||||||
|                         val document = Jsoup.parse(json.output?.replace("""\""", "")) |                         val document = Jsoup.parse(json.output?.replace("""\""", "")) | ||||||
|                             document.select("a").map { episodes.add(TvSeriesEpisode(it.text(), season, it.text().getIntFromText(), it.attr("href"), null, null)) } |                         document.select("a").map { | ||||||
|  |                             episodes.add( | ||||||
|  |                                 Episode( | ||||||
|  |                                     it.attr("href"), | ||||||
|  |                                     it.text(), | ||||||
|  |                                     season, | ||||||
|  |                                     it.text().getIntFromText(), | ||||||
|  |                                 ) | ||||||
|  |                             ) | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             if(seasons.isNotEmpty()) { |             } | ||||||
|  |             if (seasons.isNotEmpty()) { | ||||||
|                 seasons.apmap { surl -> |                 seasons.apmap { surl -> | ||||||
|                         if(surl.contains("%d9%85%d8%af%d8%a8%d9%84%d8%ac")) return@apmap |                     if (surl.contains("%d9%85%d8%af%d8%a8%d9%84%d8%ac")) return@apmap | ||||||
|                     val seasonsite = app.get(surl).document |                     val seasonsite = app.get(surl).document | ||||||
|                     val fmoreButton = seasonsite.select("div.MoreEpisodes--Button") |                     val fmoreButton = seasonsite.select("div.MoreEpisodes--Button") | ||||||
|                             val fseason = seasonsite.select("div.List--Seasons--Episodes a.selected").text().getIntFromText() ?: 1 |                     val fseason = seasonsite.select("div.List--Seasons--Episodes a.selected").text() | ||||||
|  |                         .getIntFromText() ?: 1 | ||||||
|                     seasonsite.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a") |                     seasonsite.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a") | ||||||
|                                         .apmap { episodes.add(TvSeriesEpisode(it.text(), fseason, it.text().getIntFromText(), it.attr("href"), null, null))} |                         .map { | ||||||
|                             if(fmoreButton.isNotEmpty()) { |                             episodes.add( | ||||||
|                                 val n = seasonsite.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a").size |                                 Episode( | ||||||
|                                 val totals = seasonsite.select("div.Episodes--Seasons--Episodes a").first().text().getIntFromText() |                                     it.attr("href"), | ||||||
|                                 val mEPS = arrayListOf(n, n+40, n+80, n+120, n+160, n+200, n+240, n+280, n+320, n+360, n+400, n+440, n+480, n+520, n+660, n+700, n+740, n+780, n+820, n+860, n+900, n+940, n+980, n+1020, n+1060, n+1100, n+1140, n+1180, n+1220, totals) |                                     it.text(), | ||||||
|  |                                     fseason, | ||||||
|  |                                     it.text().getIntFromText(), | ||||||
|  |                                 ) | ||||||
|  |                             ) | ||||||
|  |                         } | ||||||
|  |                     if (fmoreButton.isNotEmpty()) { | ||||||
|  |                         val n = | ||||||
|  |                             seasonsite.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a").size | ||||||
|  |                         val totals = | ||||||
|  |                             seasonsite.select("div.Episodes--Seasons--Episodes a").first().text() | ||||||
|  |                                 .getIntFromText() | ||||||
|  |                         val mEPS = arrayListOf( | ||||||
|  |                             n, | ||||||
|  |                             n + 40, | ||||||
|  |                             n + 80, | ||||||
|  |                             n + 120, | ||||||
|  |                             n + 160, | ||||||
|  |                             n + 200, | ||||||
|  |                             n + 240, | ||||||
|  |                             n + 280, | ||||||
|  |                             n + 320, | ||||||
|  |                             n + 360, | ||||||
|  |                             n + 400, | ||||||
|  |                             n + 440, | ||||||
|  |                             n + 480, | ||||||
|  |                             n + 520, | ||||||
|  |                             n + 660, | ||||||
|  |                             n + 700, | ||||||
|  |                             n + 740, | ||||||
|  |                             n + 780, | ||||||
|  |                             n + 820, | ||||||
|  |                             n + 860, | ||||||
|  |                             n + 900, | ||||||
|  |                             n + 940, | ||||||
|  |                             n + 980, | ||||||
|  |                             n + 1020, | ||||||
|  |                             n + 1060, | ||||||
|  |                             n + 1100, | ||||||
|  |                             n + 1140, | ||||||
|  |                             n + 1180, | ||||||
|  |                             n + 1220, | ||||||
|  |                             totals | ||||||
|  |                         ) | ||||||
|                         mEPS.apmap { it -> |                         mEPS.apmap { it -> | ||||||
|                             if (it != null) { |                             if (it != null) { | ||||||
|                                             if(it > totals!!) return@apmap |                                 if (it > totals!!) return@apmap | ||||||
|                                             val ajaxURL = "$mainUrl/AjaxCenter/MoreEpisodes/${fmoreButton.attr("data-term")}/$it" |                                 val ajaxURL = | ||||||
|  |                                     "$mainUrl/AjaxCenter/MoreEpisodes/${fmoreButton.attr("data-term")}/$it" | ||||||
|                                 val jsonResponse = app.get(ajaxURL) |                                 val jsonResponse = app.get(ajaxURL) | ||||||
|                                 val json = parseJson<MoreEPS>(jsonResponse.text) |                                 val json = parseJson<MoreEPS>(jsonResponse.text) | ||||||
|                                 val document = Jsoup.parse(json.output?.replace("""\""", "")) |                                 val document = Jsoup.parse(json.output?.replace("""\""", "")) | ||||||
|                                             document.select("a").map { episodes.add(TvSeriesEpisode(it.text(), fseason, it.text().getIntFromText(), it.attr("href"), null, null)) } |                                 document.select("a").map { | ||||||
|  |                                     episodes.add( | ||||||
|  |                                         Episode( | ||||||
|  |                                             it.attr("href"), | ||||||
|  |                                             it.text(), | ||||||
|  |                                             fseason, | ||||||
|  |                                             it.text().getIntFromText(), | ||||||
|  |                                         ) | ||||||
|  |                                     ) | ||||||
|  |                                 } | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                     } else return@apmap |                     } else return@apmap | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes.distinct().sortedBy { it.episode }) { |             newTvSeriesLoadResponse( | ||||||
|  |                 title, | ||||||
|  |                 url, | ||||||
|  |                 TvType.TvSeries, | ||||||
|  |                 episodes.distinct().sortedBy { it.episode }) { | ||||||
|                 this.duration = duration |                 this.duration = duration | ||||||
|                 this.posterUrl = posterUrl |                 this.posterUrl = posterUrl | ||||||
|                 this.tags = tags |                 this.tags = tags | ||||||
|  | @ -186,6 +301,7 @@ class MyCimaProvider : MainAPI() { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     override suspend fun loadLinks( |     override suspend fun loadLinks( | ||||||
|         data: String, |         data: String, | ||||||
|         isCasting: Boolean, |         isCasting: Boolean, | ||||||
|  | @ -198,7 +314,9 @@ class MyCimaProvider : MainAPI() { | ||||||
|                     callback.invoke( |                     callback.invoke( | ||||||
|                         ExtractorLink( |                         ExtractorLink( | ||||||
|                             this.name, |                             this.name, | ||||||
|                         this.name + " - ${linkElement.select("resolution").text().getIntFromText()}p", |                             this.name + " - ${ | ||||||
|  |                                 linkElement.select("resolution").text().getIntFromText() | ||||||
|  |                             }p", | ||||||
|                             linkElement.attr("href"), |                             linkElement.attr("href"), | ||||||
|                             this.mainUrl, |                             this.mainUrl, | ||||||
|                             2 |                             2 | ||||||
|  |  | ||||||
|  | @ -2,9 +2,7 @@ package com.lagradost.cloudstream3.movieproviders | ||||||
| 
 | 
 | ||||||
| import com.lagradost.cloudstream3.* | import com.lagradost.cloudstream3.* | ||||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
| import com.lagradost.cloudstream3.utils.extractorApis |  | ||||||
| import com.lagradost.cloudstream3.utils.loadExtractor | import com.lagradost.cloudstream3.utils.loadExtractor | ||||||
| import kotlin.collections.ArrayList |  | ||||||
| 
 | 
 | ||||||
| class PeliSmartProvider: MainAPI() { | class PeliSmartProvider: MainAPI() { | ||||||
|     override var mainUrl = "https://pelismart.com" |     override var mainUrl = "https://pelismart.com" | ||||||
|  | @ -105,11 +103,11 @@ class PeliSmartProvider: MainAPI() { | ||||||
|             val isValid = seasonid?.size == 2 |             val isValid = seasonid?.size == 2 | ||||||
|             val episode = if (isValid) seasonid?.getOrNull(1) else null |             val episode = if (isValid) seasonid?.getOrNull(1) else null | ||||||
|             val season = if (isValid) seasonid?.getOrNull(0) else null |             val season = if (isValid) seasonid?.getOrNull(0) else null | ||||||
|                 TvSeriesEpisode( |                 Episode( | ||||||
|  |                     href, | ||||||
|                     name, |                     name, | ||||||
|                     season, |                     season, | ||||||
|                     episode, |                     episode, | ||||||
|                     href, |  | ||||||
|                 ) |                 ) | ||||||
|         } |         } | ||||||
|         return when (val tvType = if (episodes.isEmpty()) TvType.Movie else TvType.TvSeries) { |         return when (val tvType = if (episodes.isEmpty()) TvType.Movie else TvType.TvSeries) { | ||||||
|  |  | ||||||
|  | @ -127,7 +127,7 @@ class PelisflixProvider : MainAPI() { | ||||||
|             } |             } | ||||||
|             if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found") |             if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found") | ||||||
| 
 | 
 | ||||||
|             val episodeList = ArrayList<TvSeriesEpisode>() |             val episodeList = ArrayList<Episode>() | ||||||
| 
 | 
 | ||||||
|             for ((seasonInt, seasonUrl) in list) { |             for ((seasonInt, seasonUrl) in list) { | ||||||
|                 val seasonDocument = app.get(seasonUrl).document |                 val seasonDocument = app.get(seasonUrl).document | ||||||
|  | @ -141,14 +141,13 @@ class PelisflixProvider : MainAPI() { | ||||||
|                         val href = aName.attr("href") |                         val href = aName.attr("href") | ||||||
|                         val date = episode.selectFirst("> td.MvTbTtl > span")?.text() |                         val date = episode.selectFirst("> td.MvTbTtl > span")?.text() | ||||||
|                         episodeList.add( |                         episodeList.add( | ||||||
|                             TvSeriesEpisode( |                             newEpisode(href) { | ||||||
|                                 name, |                                 this.name = name | ||||||
|                                 seasonInt, |                                 this.season = seasonInt | ||||||
|                                 epNum, |                                 this.episode =  epNum | ||||||
|                                 href, |                                 this.posterUrl = fixUrlNull(epthumb) | ||||||
|                                 fixUrlNull(epthumb), |                                 addDate(date) | ||||||
|                                 date |                             } | ||||||
|                             ) |  | ||||||
|                         ) |                         ) | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  | @ -111,11 +111,11 @@ class PelisplusHDProvider:MainAPI() { | ||||||
|             val isValid = seasonid.size == 2 |             val isValid = seasonid.size == 2 | ||||||
|             val episode = if (isValid) seasonid.getOrNull(1) else null |             val episode = if (isValid) seasonid.getOrNull(1) else null | ||||||
|             val season = if (isValid) seasonid.getOrNull(0) else null |             val season = if (isValid) seasonid.getOrNull(0) else null | ||||||
|             TvSeriesEpisode( |             Episode( | ||||||
|  |                 href, | ||||||
|                 name, |                 name, | ||||||
|                 season, |                 season, | ||||||
|                 episode, |                 episode, | ||||||
|                 href, |  | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,9 +1,13 @@ | ||||||
| package com.lagradost.cloudstream3.movieproviders | package com.lagradost.cloudstream3.movieproviders | ||||||
| 
 | 
 | ||||||
| import com.lagradost.cloudstream3.* | import com.lagradost.cloudstream3.* | ||||||
| import com.lagradost.cloudstream3.utils.* | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
|  | import com.lagradost.cloudstream3.utils.M3u8Helper | ||||||
|  | import com.lagradost.cloudstream3.utils.getQualityFromName | ||||||
|  | import com.lagradost.cloudstream3.utils.loadExtractor | ||||||
| import org.jsoup.Jsoup | import org.jsoup.Jsoup | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| /** Needs to inherit from MainAPI() to | /** Needs to inherit from MainAPI() to | ||||||
|  * make the app know what functions to call |  * make the app know what functions to call | ||||||
|  */ |  */ | ||||||
|  | @ -74,6 +78,7 @@ open class PelisplusProviderTemplate : MainAPI() { | ||||||
|         val description = soup.selectFirst(".post-entry")?.text()?.trim() |         val description = soup.selectFirst(".post-entry")?.text()?.trim() | ||||||
|         val poster = soup.selectFirst("head meta[property=og:image]").attr("content") |         val poster = soup.selectFirst("head meta[property=og:image]").attr("content") | ||||||
| 
 | 
 | ||||||
|  |         var year : Int? = null | ||||||
|         val episodes = soup.select(".listing.items.lists > .video-block").map { li -> |         val episodes = soup.select(".listing.items.lists > .video-block").map { li -> | ||||||
|             val href = fixUrl(li.selectFirst("a").attr("href")) |             val href = fixUrl(li.selectFirst("a").attr("href")) | ||||||
|             val regexseason = Regex("(-[Tt]emporada-(\\d+)-[Cc]apitulo-(\\d+))") |             val regexseason = Regex("(-[Tt]emporada-(\\d+)-[Cc]apitulo-(\\d+))") | ||||||
|  | @ -87,20 +92,18 @@ open class PelisplusProviderTemplate : MainAPI() { | ||||||
|             val epThumb = fixUrl(li.selectFirst("img").attr("src")) |             val epThumb = fixUrl(li.selectFirst("img").attr("src")) | ||||||
|             val epDate = li.selectFirst(".meta > .date").text() |             val epDate = li.selectFirst(".meta > .date").text() | ||||||
| 
 | 
 | ||||||
|  |             if(year == null) { | ||||||
|  |                 year = epDate?.split("-")?.get(0)?.toIntOrNull() | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
| 
 |             newEpisode(li.selectFirst("a").attr("href")) { | ||||||
|             TvSeriesEpisode( |                 this.season = season | ||||||
|                 null, |                 this.episode = episode | ||||||
|                 season, |                 this.posterUrl = epThumb | ||||||
|                 episode, |                 addDate(epDate) | ||||||
|                 fixUrl(li.selectFirst("a").attr("href")), |             } | ||||||
|                 epThumb, |  | ||||||
|                 epDate |  | ||||||
|             ) |  | ||||||
|         }.reversed() |         }.reversed() | ||||||
| 
 | 
 | ||||||
|         val year = episodes.first().date?.split("-")?.get(0)?.toIntOrNull() |  | ||||||
| 
 |  | ||||||
|         // Make sure to get the type right to display the correct UI. |         // Make sure to get the type right to display the correct UI. | ||||||
|         val tvType = if (episodes.size == 1 && episodes[0].name == title) TvType.Movie else TvType.TvSeries |         val tvType = if (episodes.size == 1 && episodes[0].name == title) TvType.Movie else TvType.TvSeries | ||||||
| 
 | 
 | ||||||
|  | @ -224,7 +227,7 @@ open class PelisplusProviderTemplate : MainAPI() { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // loadLinks gets the raw .mp4 or .m3u8 urls from the data parameter in the episodes class generated in load() |     // loadLinks gets the raw .mp4 or .m3u8 urls from the data parameter in the episodes class generated in load() | ||||||
|     // See TvSeriesEpisode(...) in this provider. |     // See Episode(...) in this provider. | ||||||
|     // The data are usually links, but can be any other string to help aid loading the links. |     // The data are usually links, but can be any other string to help aid loading the links. | ||||||
|     override suspend fun loadLinks( |     override suspend fun loadLinks( | ||||||
|         data: String, |         data: String, | ||||||
|  |  | ||||||
|  | @ -138,7 +138,7 @@ class PinoyHDXyzProvider : MainAPI() { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Try looking for episodes, for series |         // Try looking for episodes, for series | ||||||
|         val episodeList = ArrayList<TvSeriesEpisode>() |         val episodeList = ArrayList<Episode>() | ||||||
|         val bodyText = body?.select("div.section-cotent1.col-md-12")?.select("section") |         val bodyText = body?.select("div.section-cotent1.col-md-12")?.select("section") | ||||||
|             ?.select("script")?.toString() ?: "" |             ?.select("script")?.toString() ?: "" | ||||||
|         //Log.i(this.name, "Result => (bodyText) ${bodyText}") |         //Log.i(this.name, "Result => (bodyText) ${bodyText}") | ||||||
|  | @ -151,7 +151,7 @@ class PinoyHDXyzProvider : MainAPI() { | ||||||
|                     val listEpStream = listOf(ep.trim()).toJson() |                     val listEpStream = listOf(ep.trim()).toJson() | ||||||
|                     //Log.i(this.name, "Result => (ep $count) $listEpStream") |                     //Log.i(this.name, "Result => (ep $count) $listEpStream") | ||||||
|                     episodeList.add( |                     episodeList.add( | ||||||
|                         TvSeriesEpisode( |                         Episode( | ||||||
|                             name = null, |                             name = null, | ||||||
|                             season = null, |                             season = null, | ||||||
|                             episode = count, |                             episode = count, | ||||||
|  |  | ||||||
|  | @ -159,7 +159,7 @@ class PinoyMoviePediaProvider : MainAPI() { | ||||||
| 
 | 
 | ||||||
|         // Parse episodes if series |         // Parse episodes if series | ||||||
|         if (isTvSeries) { |         if (isTvSeries) { | ||||||
|             val episodeList = ArrayList<TvSeriesEpisode>() |             val episodeList = ArrayList<Episode>() | ||||||
|             val epLinks = playcontainer?.select("div > div > div.source-box") |             val epLinks = playcontainer?.select("div > div > div.source-box") | ||||||
|             //Log.i(this.name, "Result => (epList) ${epList}") |             //Log.i(this.name, "Result => (epList) ${epList}") | ||||||
|             body?.select("div#playeroptions > ul > li")?.forEach { ep -> |             body?.select("div#playeroptions > ul > li")?.forEach { ep -> | ||||||
|  | @ -175,7 +175,7 @@ class PinoyMoviePediaProvider : MainAPI() { | ||||||
|                     val streamEpLink = listOf(href.trim()).toJson() |                     val streamEpLink = listOf(href.trim()).toJson() | ||||||
|                     //Log.i(this.name, "Result => (streamEpLink $epNum) $streamEpLink") |                     //Log.i(this.name, "Result => (streamEpLink $epNum) $streamEpLink") | ||||||
|                     episodeList.add( |                     episodeList.add( | ||||||
|                         TvSeriesEpisode( |                         Episode( | ||||||
|                             name = null, |                             name = null, | ||||||
|                             season = null, |                             season = null, | ||||||
|                             episode = epNum, |                             episode = epNum, | ||||||
|  |  | ||||||
|  | @ -124,7 +124,7 @@ class SeriesflixProvider : MainAPI() { | ||||||
|             } |             } | ||||||
|             if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found") |             if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found") | ||||||
| 
 | 
 | ||||||
|             val episodeList = ArrayList<TvSeriesEpisode>() |             val episodeList = ArrayList<Episode>() | ||||||
| 
 | 
 | ||||||
|             for (season in list) { |             for (season in list) { | ||||||
|                 val seasonDocument = app.get(season.second).document |                 val seasonDocument = app.get(season.second).document | ||||||
|  | @ -138,14 +138,13 @@ class SeriesflixProvider : MainAPI() { | ||||||
|                         val href = aName.attr("href") |                         val href = aName.attr("href") | ||||||
|                         val date = episode.selectFirst("> td.MvTbTtl > span")?.text() |                         val date = episode.selectFirst("> td.MvTbTtl > span")?.text() | ||||||
|                         episodeList.add( |                         episodeList.add( | ||||||
|                             TvSeriesEpisode( |                             newEpisode(href) { | ||||||
|                                 name, |                                 this.name = name | ||||||
|                                 season.first, |                                 this.season = season.first | ||||||
|                                 epNum, |                                 this.episode = epNum | ||||||
|                                 href, |                                 this.posterUrl = fixUrlNull(epthumb) | ||||||
|                                 fixUrlNull(epthumb), |                                 addDate(date) | ||||||
|                                 date |                             } | ||||||
|                             ) |  | ||||||
|                         ) |                         ) | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  | @ -11,7 +11,6 @@ import com.lagradost.cloudstream3.animeproviders.ZoroProvider | ||||||
| import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall | import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall | ||||||
| import com.lagradost.cloudstream3.network.AppResponse | import com.lagradost.cloudstream3.network.AppResponse | ||||||
| import com.lagradost.cloudstream3.utils.AppUtils.parseJson | 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.AppUtils.tryParseJson | ||||||
| import com.lagradost.cloudstream3.utils.Coroutines.ioSafe | import com.lagradost.cloudstream3.utils.Coroutines.ioSafe | ||||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
|  | @ -214,7 +213,7 @@ open class SflixProvider : MainAPI() { | ||||||
| 
 | 
 | ||||||
|             val comingSoon = sourceIds.isEmpty() |             val comingSoon = sourceIds.isEmpty() | ||||||
| 
 | 
 | ||||||
|             return newMovieLoadResponse(title, url, TvType.Movie, sourceIds.toJson()) { |             return newMovieLoadResponse(title, url, TvType.Movie, sourceIds) { | ||||||
|                 this.year = year |                 this.year = year | ||||||
|                 this.posterUrl = posterUrl |                 this.posterUrl = posterUrl | ||||||
|                 this.plot = plot |                 this.plot = plot | ||||||
|  | @ -228,7 +227,7 @@ open class SflixProvider : MainAPI() { | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             val seasonsDocument = app.get("$mainUrl/ajax/v2/tv/seasons/$id").document |             val seasonsDocument = app.get("$mainUrl/ajax/v2/tv/seasons/$id").document | ||||||
|             val episodes = arrayListOf<TvSeriesEpisode>() |             val episodes = arrayListOf<Episode>() | ||||||
|             var seasonItems = seasonsDocument.select("div.dropdown-menu.dropdown-menu-model > a") |             var seasonItems = seasonsDocument.select("div.dropdown-menu.dropdown-menu-model > a") | ||||||
|             if (seasonItems.isNullOrEmpty()) |             if (seasonItems.isNullOrEmpty()) | ||||||
|                 seasonItems = seasonsDocument.select("div.dropdown-menu > a.dropdown-item") |                 seasonItems = seasonsDocument.select("div.dropdown-menu > a.dropdown-item") | ||||||
|  | @ -260,13 +259,12 @@ open class SflixProvider : MainAPI() { | ||||||
|                         } ?: episode |                         } ?: episode | ||||||
| 
 | 
 | ||||||
|                     episodes.add( |                     episodes.add( | ||||||
|                         TvSeriesEpisode( |                         newEpisode(Pair(url, episodeData)) { | ||||||
|                             episodeTitle?.removePrefix("Episode $episodeNum: "), |                             this.posterUrl = fixUrlNull(episodePosterUrl) | ||||||
|                             season + 1, |                             this.name = episodeTitle?.removePrefix("Episode $episodeNum: ") | ||||||
|                             episodeNum, |                             this.season = season + 1 | ||||||
|                             Pair(url, episodeData).toJson(), |                             this.episode = episodeNum | ||||||
|                             fixUrlNull(episodePosterUrl) |                         } | ||||||
|                         ) |  | ||||||
|                     ) |                     ) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | @ -370,7 +368,8 @@ open class SflixProvider : MainAPI() { | ||||||
|         val posterUrl = img.attr("data-src") ?: img.attr("src") |         val posterUrl = img.attr("data-src") ?: img.attr("src") | ||||||
|         val href = fixUrl(inner.select("a").attr("href")) |         val href = fixUrl(inner.select("a").attr("href")) | ||||||
|         val isMovie = href.contains("/movie/") |         val isMovie = href.contains("/movie/") | ||||||
|         val otherInfo = this.selectFirst("div.film-detail > div.fd-infor")?.select("span")?.toList() ?: listOf() |         val otherInfo = | ||||||
|  |             this.selectFirst("div.film-detail > div.fd-infor")?.select("span")?.toList() ?: listOf() | ||||||
|         //var rating: Int? = null |         //var rating: Int? = null | ||||||
|         var year: Int? = null |         var year: Int? = null | ||||||
|         var quality: SearchQuality? = null |         var quality: SearchQuality? = null | ||||||
|  |  | ||||||
|  | @ -75,7 +75,7 @@ class SoaptwoDayProvider:MainAPI() { | ||||||
|         val episodes = soup.select("div.alert > div > div > a").mapNotNull { |         val episodes = soup.select("div.alert > div > div > a").mapNotNull { | ||||||
|             val link = fixUrlNull(it?.attr("href")) ?: return@mapNotNull null |             val link = fixUrlNull(it?.attr("href")) ?: return@mapNotNull null | ||||||
|             val name = it?.text()?.replace(Regex("(^(\\d+)\\.)"),"") |             val name = it?.text()?.replace(Regex("(^(\\d+)\\.)"),"") | ||||||
|             TvSeriesEpisode( |             Episode( | ||||||
|                 name = name, |                 name = name, | ||||||
|                 data = link |                 data = link | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|  | @ -420,13 +420,15 @@ class TheFlixToProvider : MainAPI() { | ||||||
|                 ) |                 ) | ||||||
|                 //{"affiliateCode":"","pathname":"/movie/696806-the-adam-project"} |                 //{"affiliateCode":"","pathname":"/movie/696806-the-adam-project"} | ||||||
|                 val data = mapOf("affiliateCode" to "", "pathname" to url.removePrefix(mainUrl)) |                 val data = mapOf("affiliateCode" to "", "pathname" to url.removePrefix(mainUrl)) | ||||||
|                 val resp = app.post(optionsUrl, headers = mapOf( |                 val resp = app.post( | ||||||
|  |                     optionsUrl, headers = mapOf( | ||||||
|                         "User-Agent" to USER_AGENT, |                         "User-Agent" to USER_AGENT, | ||||||
|                         "Content-Type" to "application/json;charset=UTF-8", |                         "Content-Type" to "application/json;charset=UTF-8", | ||||||
|                         "Accept" to "application/json, text/plain, */*", |                         "Accept" to "application/json, text/plain, */*", | ||||||
|                         "Origin" to url, |                         "Origin" to url, | ||||||
|                         "Referer" to mainUrl, |                         "Referer" to mainUrl, | ||||||
|                 ), data = data) |                     ), data = data | ||||||
|  |                 ) | ||||||
| 
 | 
 | ||||||
|                 latestCookies = resp.cookies |                 latestCookies = resp.cookies | ||||||
|                 val newData = getLoadMan(url) |                 val newData = getLoadMan(url) | ||||||
|  | @ -442,7 +444,7 @@ class TheFlixToProvider : MainAPI() { | ||||||
|     override suspend fun load(url: String): LoadResponse? { |     override suspend fun load(url: String): LoadResponse? { | ||||||
|         val tvtype = if (url.contains("movie")) TvType.Movie else TvType.TvSeries |         val tvtype = if (url.contains("movie")) TvType.Movie else TvType.TvSeries | ||||||
|         val json = getLoadMainRetry(url) |         val json = getLoadMainRetry(url) | ||||||
|         val episodes = ArrayList<TvSeriesEpisode>() |         val episodes = ArrayList<Episode>() | ||||||
|         val isMovie = tvtype == TvType.Movie |         val isMovie = tvtype == TvType.Movie | ||||||
|         val pageMain = json.props.pageProps |         val pageMain = json.props.pageProps | ||||||
| 
 | 
 | ||||||
|  | @ -471,11 +473,11 @@ class TheFlixToProvider : MainAPI() { | ||||||
|                     val test = epi.videos |                     val test = epi.videos | ||||||
|                     val ratinginfo = (epi.voteAverage)?.times(10)?.toInt() |                     val ratinginfo = (epi.voteAverage)?.times(10)?.toInt() | ||||||
|                     val rating = if (ratinginfo?.equals(0) == true) null else ratinginfo |                     val rating = if (ratinginfo?.equals(0) == true) null else ratinginfo | ||||||
|                     val eps = TvSeriesEpisode( |                     val eps = Episode( | ||||||
|  |                         "$mainUrl/tv-show/$movieId-${cleanTitle(movietitle)}/season-$seasonum/episode-$episodenu", | ||||||
|                         title, |                         title, | ||||||
|                         seasonum, |                         seasonum, | ||||||
|                         episodenu, |                         episodenu, | ||||||
|                         "$mainUrl/tv-show/$movieId-${cleanTitle(movietitle)}/season-$seasonum/episode-$episodenu", |  | ||||||
|                         description = epDesc!!, |                         description = epDesc!!, | ||||||
|                         posterUrl = seasonPoster, |                         posterUrl = seasonPoster, | ||||||
|                         rating = rating, |                         rating = rating, | ||||||
|  |  | ||||||
|  | @ -28,7 +28,8 @@ class VfSerieProvider : MainAPI() { | ||||||
|         for (item in items) { |         for (item in items) { | ||||||
|             val href = item.attr("href") |             val href = item.attr("href") | ||||||
| 
 | 
 | ||||||
|             val poster = item.selectFirst("> div.Image > figure > img").attr("src").replace("//image", "https://image") |             val poster = item.selectFirst("> div.Image > figure > img").attr("src") | ||||||
|  |                 .replace("//image", "https://image") | ||||||
| 
 | 
 | ||||||
|             if (poster == "$mainUrl/wp-content/themes/toroplay/img/cnt/noimg-thumbnail.png") {  // if the poster is missing (the item is just a redirect to something like https://vf-serie.org/series-tv/) |             if (poster == "$mainUrl/wp-content/themes/toroplay/img/cnt/noimg-thumbnail.png") {  // if the poster is missing (the item is just a redirect to something like https://vf-serie.org/series-tv/) | ||||||
|                 continue |                 continue | ||||||
|  | @ -37,7 +38,17 @@ class VfSerieProvider : MainAPI() { | ||||||
| 
 | 
 | ||||||
|             val year = item.selectFirst("> span.Year").text()?.toIntOrNull() |             val year = item.selectFirst("> span.Year").text()?.toIntOrNull() | ||||||
| 
 | 
 | ||||||
|             returnValue.add(TvSeriesSearchResponse(name, href, this.name, TvType.TvSeries, poster, year, null)) |             returnValue.add( | ||||||
|  |                 TvSeriesSearchResponse( | ||||||
|  |                     name, | ||||||
|  |                     href, | ||||||
|  |                     this.name, | ||||||
|  |                     TvType.TvSeries, | ||||||
|  |                     poster, | ||||||
|  |                     year, | ||||||
|  |                     null | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|         } |         } | ||||||
|         return returnValue |         return returnValue | ||||||
|     } |     } | ||||||
|  | @ -99,7 +110,8 @@ class VfSerieProvider : MainAPI() { | ||||||
|         val response = app.get(url).text |         val response = app.get(url).text | ||||||
|         val document = Jsoup.parse(response) |         val document = Jsoup.parse(response) | ||||||
|         val title = |         val title = | ||||||
|             document?.selectFirst(".Title")?.text()?.replace("Regarder Serie ", "")?.replace(" En Streaming", "") |             document?.selectFirst(".Title")?.text()?.replace("Regarder Serie ", "") | ||||||
|  |                 ?.replace(" En Streaming", "") | ||||||
|                 ?: throw ErrorLoadingException("Service might be unavailable") |                 ?: throw ErrorLoadingException("Service might be unavailable") | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -109,7 +121,8 @@ class VfSerieProvider : MainAPI() { | ||||||
|         //val duration = document.select("span.Time").text()?.toIntOrNull() |         //val duration = document.select("span.Time").text()?.toIntOrNull() | ||||||
| 
 | 
 | ||||||
|         val backgroundPoster = |         val backgroundPoster = | ||||||
|             document.selectFirst("div.Image > figure > img").attr("src").replace("//image", "https://image") |             document.selectFirst("div.Image > figure > img").attr("src") | ||||||
|  |                 .replace("//image", "https://image") | ||||||
| 
 | 
 | ||||||
|         val descript = document.selectFirst("div.Description > p").text() |         val descript = document.selectFirst("div.Description > p").text() | ||||||
| 
 | 
 | ||||||
|  | @ -124,7 +137,7 @@ class VfSerieProvider : MainAPI() { | ||||||
|         } |         } | ||||||
|         if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found") |         if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found") | ||||||
| 
 | 
 | ||||||
|         val episodeList = ArrayList<TvSeriesEpisode>() |         val episodeList = ArrayList<Episode>() | ||||||
| 
 | 
 | ||||||
|         for (season in list) { |         for (season in list) { | ||||||
|             val episodes = document.select("table > tbody > tr") |             val episodes = document.select("table > tbody > tr") | ||||||
|  | @ -132,20 +145,20 @@ class VfSerieProvider : MainAPI() { | ||||||
|                 episodes.forEach { episode -> |                 episodes.forEach { episode -> | ||||||
|                     val epNum = episode.selectFirst("> span.Num")?.text()?.toIntOrNull() |                     val epNum = episode.selectFirst("> span.Num")?.text()?.toIntOrNull() | ||||||
|                     val poster = |                     val poster = | ||||||
|                         episode.selectFirst("> td.MvTbImg > a > img")?.attr("src")?.replace("//image", "https://image") |                         episode.selectFirst("> td.MvTbImg > a > img")?.attr("src") | ||||||
|  |                             ?.replace("//image", "https://image") | ||||||
|                     val aName = episode.selectFirst("> td.MvTbTtl > a") |                     val aName = episode.selectFirst("> td.MvTbTtl > a") | ||||||
|                     val date = episode.selectFirst("> td.MvTbTtl > span")?.text()?.toString() |                     val date = episode.selectFirst("> td.MvTbTtl > span")?.text()?.toString() | ||||||
|                     val name = aName.text() |                     val name = aName.text() | ||||||
|                     val href = aName.attr("href") |                     val href = aName.attr("href") | ||||||
|                     episodeList.add( |                     episodeList.add( | ||||||
|                         TvSeriesEpisode( |                         newEpisode(href) { | ||||||
|                             name, |                             this.name = name | ||||||
|                             season, |                             this.season = season | ||||||
|                             epNum, |                             this.episode = epNum | ||||||
|                             href, |                             this.posterUrl = poster | ||||||
|                             poster, |                             addDate(date) | ||||||
|                             date |                         } | ||||||
|                         ) |  | ||||||
|                     ) |                     ) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  | @ -85,6 +85,7 @@ open class VidstreamProviderTemplate : MainAPI() { | ||||||
| 
 | 
 | ||||||
|         val description = soup.selectFirst(".post-entry")?.text()?.trim() |         val description = soup.selectFirst(".post-entry")?.text()?.trim() | ||||||
|         var poster: String? = null |         var poster: String? = null | ||||||
|  |         var year : Int? = null | ||||||
| 
 | 
 | ||||||
|         val episodes = |         val episodes = | ||||||
|             soup.select(".listing.items.lists > .video-block").withIndex().map { (_, li) -> |             soup.select(".listing.items.lists > .video-block").withIndex().map { (_, li) -> | ||||||
|  | @ -104,19 +105,16 @@ open class VidstreamProviderTemplate : MainAPI() { | ||||||
| 
 | 
 | ||||||
|                 val epNum = Regex("""Episode (\d+)""").find(epTitle)?.destructured?.component1() |                 val epNum = Regex("""Episode (\d+)""").find(epTitle)?.destructured?.component1() | ||||||
|                     ?.toIntOrNull() |                     ?.toIntOrNull() | ||||||
| 
 |                 if(year == null) { | ||||||
|                 TvSeriesEpisode( |                     year = epDate?.split("-")?.get(0)?.toIntOrNull() | ||||||
|                     epTitle, |                 } | ||||||
|                     null, |                 newEpisode(li.selectFirst("a").attr("href")) { | ||||||
|                     epNum, |                     this.episode = epNum | ||||||
|                     fixUrl(li.selectFirst("a").attr("href")), |                     this.posterUrl = epThumb | ||||||
|                     epThumb, |                     addDate(epDate) | ||||||
|                     epDate |                 } | ||||||
|                 ) |  | ||||||
|             }.reversed() |             }.reversed() | ||||||
| 
 | 
 | ||||||
|         val year = episodes.first().date?.split("-")?.get(0)?.toIntOrNull() |  | ||||||
| 
 |  | ||||||
|         // Make sure to get the type right to display the correct UI. |         // Make sure to get the type right to display the correct UI. | ||||||
|         val tvType = |         val tvType = | ||||||
|             if (episodes.size == 1 && episodes[0].name == title) TvType.Movie else TvType.TvSeries |             if (episodes.size == 1 && episodes[0].name == title) TvType.Movie else TvType.TvSeries | ||||||
|  | @ -208,7 +206,7 @@ open class VidstreamProviderTemplate : MainAPI() { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // loadLinks gets the raw .mp4 or .m3u8 urls from the data parameter in the episodes class generated in load() |     // loadLinks gets the raw .mp4 or .m3u8 urls from the data parameter in the episodes class generated in load() | ||||||
|     // See TvSeriesEpisode(...) in this provider. |     // See Episode(...) in this provider. | ||||||
|     // The data are usually links, but can be any other string to help aid loading the links. |     // The data are usually links, but can be any other string to help aid loading the links. | ||||||
|     override suspend fun loadLinks( |     override suspend fun loadLinks( | ||||||
|         data: String, |         data: String, | ||||||
|  |  | ||||||
|  | @ -156,7 +156,7 @@ class WatchAsianProvider : MainAPI() { | ||||||
|             val regex = "(?<=episode-).*?(?=.html)".toRegex() |             val regex = "(?<=episode-).*?(?=.html)".toRegex() | ||||||
|             val count = regex.find(epLink, mainUrl.length)?.value?.toIntOrNull() ?: 0 |             val count = regex.find(epLink, mainUrl.length)?.value?.toIntOrNull() ?: 0 | ||||||
|             //Log.i(this.name, "Result => $epLink (regexYear) ${count}") |             //Log.i(this.name, "Result => $epLink (regexYear) ${count}") | ||||||
|             TvSeriesEpisode( |             Episode( | ||||||
|                 name = null, |                 name = null, | ||||||
|                 season = null, |                 season = null, | ||||||
|                 episode = count, |                 episode = count, | ||||||
|  |  | ||||||
|  | @ -112,11 +112,11 @@ class FrenchStreamProvider : MainAPI() { | ||||||
|                 if (poster == null) { |                 if (poster == null) { | ||||||
|                     poster = a.selectFirst("div.fposter > img")?.attr("src") |                     poster = a.selectFirst("div.fposter > img")?.attr("src") | ||||||
|                 } |                 } | ||||||
|                 TvSeriesEpisode( |                 Episode( | ||||||
|  |                     fixUrl(url).plus("-episodenumber:$epNum"), | ||||||
|                     epTitle, |                     epTitle, | ||||||
|                     null, |                     null, | ||||||
|                     epNum, |                     epNum, | ||||||
|                     fixUrl(url).plus("-episodenumber:$epNum"), |  | ||||||
|                     null,  // episode Thumbnail |                     null,  // episode Thumbnail | ||||||
|                     null // episode date |                     null // episode date | ||||||
|                 ) |                 ) | ||||||
|  |  | ||||||
|  | @ -364,8 +364,8 @@ class ResultViewModel : ViewModel() { | ||||||
|                                     filterName(i.name), |                                     filterName(i.name), | ||||||
|                                     i.posterUrl, |                                     i.posterUrl, | ||||||
|                                     episode, |                                     episode, | ||||||
|                                     null, // TODO FIX SEASON |                                     i.season, | ||||||
|                                     i.url, |                                     i.data, | ||||||
|                                     apiName, |                                     apiName, | ||||||
|                                     mainId + index + 1 + idIndex * 100000, |                                     mainId + index + 1 + idIndex * 100000, | ||||||
|                                     index, |                                     index, | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue