diff --git a/app/build.gradle b/app/build.gradle index 375b019f..67dabcfc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -36,7 +36,7 @@ android { targetSdkVersion 30 versionCode 45 - versionName "2.9.17" + versionName "2.9.18" resValue "string", "app_version", "${defaultConfig.versionName}${versionNameSuffix ?: ""}" diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt index e2ac29c0..3fa4f0c6 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt @@ -13,11 +13,14 @@ import com.fasterxml.jackson.module.kotlin.KotlinModule import com.lagradost.cloudstream3.animeproviders.* import com.lagradost.cloudstream3.metaproviders.CrossTmdbProvider 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.malApi import com.lagradost.cloudstream3.ui.player.SubtitleData +import com.lagradost.cloudstream3.utils.AppUtils.toJson import com.lagradost.cloudstream3.utils.ExtractorLink import okhttp3.Interceptor +import java.text.SimpleDateFormat import java.util.* import kotlin.math.absoluteValue @@ -800,16 +803,6 @@ fun TvType?.isEpisodeBased(): Boolean { 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( override var name: String, override var url: String, @@ -841,7 +834,7 @@ data class AnimeLoadResponse( override var posterUrl: String? = null, override var year: Int? = null, - var episodes: MutableMap> = mutableMapOf(), + var episodes: MutableMap> = mutableMapOf(), var showStatus: ShowStatus? = null, override var plot: String? = null, @@ -857,7 +850,7 @@ data class AnimeLoadResponse( override var syncData: MutableMap = mutableMapOf(), ) : LoadResponse -fun AnimeLoadResponse.addEpisodes(status: DubStatus, episodes: List?) { +fun AnimeLoadResponse.addEpisodes(status: DubStatus, episodes: List?) { if (episodes == null) return this.episodes[status] = episodes } @@ -912,6 +905,26 @@ data class MovieLoadResponse( override var syncData: MutableMap = mutableMapOf(), ) : LoadResponse +fun 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( name: String, url: String, @@ -931,23 +944,58 @@ fun MainAPI.newMovieLoadResponse( return builder } -data class TvSeriesEpisode( - val name: String? = null, - val season: Int? = null, - val episode: Int? = null, - val data: String, - val posterUrl: String? = null, - val date: String? = null, - val rating: Int? = null, - val description: String? = null, +data class Episode( + var data: String, + var name: String? = null, + var season: Int? = null, + var episode: Int? = null, + var posterUrl: String? = null, + var rating: Int? = null, + var 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 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 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( override var name: String, override var url: String, override var apiName: String, override var type: TvType, - var episodes: List, + var episodes: List, override var posterUrl: String? = null, override var year: Int? = null, @@ -968,7 +1016,7 @@ fun MainAPI.newTvSeriesLoadResponse( name: String, url: String, type: TvType, - episodes: List, + episodes: List, initializer: TvSeriesLoadResponse.() -> Unit = { } ): TvSeriesLoadResponse { val builder = TvSeriesLoadResponse( diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AllAnimeProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AllAnimeProvider.kt index fe853ca9..1c322927 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AllAnimeProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AllAnimeProvider.kt @@ -232,11 +232,11 @@ class AllAnimeProvider : MainAPI() { val episodes = showData.availableEpisodes.let { if (it == null) return@let Pair(null, null) Pair(if (it.sub != 0) ((1..it.sub).map { epNum -> - AnimeEpisode( + Episode( "$mainUrl/anime/${showData.Id}/episodes/sub/$epNum", episode = epNum ) }) else null, if (it.dub != 0) ((1..it.dub).map { epNum -> - AnimeEpisode( + Episode( "$mainUrl/anime/${showData.Id}/episodes/dub/$epNum", episode = epNum ) }) else null) diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeFlickProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeFlickProvider.kt index 3d7dc42d..65cb6193 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeFlickProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeFlickProvider.kt @@ -65,7 +65,7 @@ class AnimeFlickProvider : MainAPI() { val episodes = doc.select("#collapseOne .block-space > .row > div:nth-child(2)").map { val name = it.selectFirst("a").text() val link = mainUrl + it.selectFirst("a").attr("href") - AnimeEpisode(link, name) + Episode(link, name) }.reversed() return newAnimeLoadResponse(title, url, getType(title)) { diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimePaheProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimePaheProvider.kt index f6c357c8..5b283075 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimePaheProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimePaheProvider.kt @@ -189,7 +189,7 @@ class AnimePaheProvider : MainAPI() { ) - private suspend fun generateListOfEpisodes(link: String): ArrayList { + private suspend fun generateListOfEpisodes(link: String): ArrayList { try { val attrs = link.split('/') val id = attrs[attrs.size - 1].split("?")[0] @@ -204,7 +204,7 @@ class AnimePaheProvider : MainAPI() { val perPage = data.perPage val total = data.total var ep = 1 - val episodes = ArrayList() + val episodes = ArrayList() fun getEpisodeTitle(k: AnimeData): String { return k.title.ifEmpty { @@ -215,14 +215,11 @@ class AnimePaheProvider : MainAPI() { if (lastPage == 1 && perPage > total) { data.data.forEach { episodes.add( - AnimeEpisode( - "$mainUrl/api?m=links&id=${it.animeId}&session=${it.session}&p=kwik!!TRUE!!", - getEpisodeTitle(it), - it.snapshot.ifEmpty { - null - }, - it.createdAt - ) + newEpisode("$mainUrl/api?m=links&id=${it.animeId}&session=${it.session}&p=kwik!!TRUE!!") { + addDate(it.createdAt) + this.name = getEpisodeTitle(it) + this.posterUrl = it.snapshot + } ) } } else { @@ -230,7 +227,7 @@ class AnimePaheProvider : MainAPI() { for (i in 0 until perPage) { if (ep <= total) { episodes.add( - AnimeEpisode( + Episode( "$mainUrl/api?m=release&id=${id}&sort=episode_asc&page=${page + 1}&ep=${ep}!!FALSE!!" ) ) diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeWorldProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeWorldProvider.kt index 7a1f8f13..c3df3a67 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeWorldProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeWorldProvider.kt @@ -152,7 +152,7 @@ class AnimeWorldProvider : MainAPI() { val episodes = servers.select(".server[data-name=\"9\"] .episode").map { val id = it.select("a").attr("data-id") val number = it.select("a").attr("data-episode-num").toIntOrNull() - AnimeEpisode( + Episode( fixUrl("$mainUrl/api/episode/info?id=$id"), episode = number ) diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeflvProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeflvProvider.kt index 095bbf41..233ab127 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeflvProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeflvProvider.kt @@ -115,7 +115,7 @@ class AnimeflvnetProvider:MainAPI() { override suspend fun load(url: String): LoadResponse { val doc = app.get(url).document - val episodes = ArrayList() + val episodes = ArrayList() val title = doc.selectFirst("h1.Title").text() val poster = doc.selectFirst("div.AnimeCover div.Image figure img").attr("src") 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 epthumb = "https://cdn.animeflv.net/screenshots/$animeid/$epNum/th_3.jpg" val link = url.replace("/anime/","/ver/")+"-$epNum" - episodes.add( AnimeEpisode( + episodes.add( Episode( link, null, posterUrl = epthumb, diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimekisaProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimekisaProvider.kt index 536dd447..3a3cb0d7 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimekisaProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimekisaProvider.kt @@ -106,7 +106,7 @@ class AnimekisaProvider : MainAPI() { ) ShowStatus.Ongoing else ShowStatus.Completed val episodes = doc.select("div.tab-content ul li.nav-item").map { val link = it.selectFirst("a").attr("href") - AnimeEpisode(link) + Episode(link) } val type = if (doc.selectFirst(".dp-i-stats").toString() .contains("Movies") diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/DubbedAnimeProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/DubbedAnimeProvider.kt index f23ea6f9..6b6301e7 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/DubbedAnimeProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/DubbedAnimeProvider.kt @@ -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 = mainUrl + (if (isMovie) "/movies/jsonMovie" else "/xz/v3/jsonEpi") + ".php?slug=$slug&_=$unixTime" val response = app.get(url).text @@ -196,7 +196,7 @@ class DubbedAnimeProvider : MainAPI() { ): Boolean { val serversHTML = (if (data.startsWith(mainUrl)) { // CLASSIC EPISODE val slug = getSlug(data) - getAnimeEpisode(slug, false).serversHTML + getEpisode(slug, false).serversHTML } else data).replace("\\", "") val hls = ArrayList("hl=\"(.*?)\"".toRegex().findAll(serversHTML).map { @@ -228,7 +228,7 @@ class DubbedAnimeProvider : MainAPI() { override suspend fun load(url: String): LoadResponse { if (getIsMovie(url)) { val realSlug = url.replace("movies/", "") - val episode = getAnimeEpisode(realSlug, true) + val episode = getEpisode(realSlug, true) val poster = episode.previewImg ?: episode.wideImg return MovieLoadResponse( episode.title, @@ -253,7 +253,7 @@ class DubbedAnimeProvider : MainAPI() { val episodes = document.select("a.epibloks").map { 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")) diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/GogoanimeProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/GogoanimeProvider.kt index f7313ec6..ea50567b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/GogoanimeProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/GogoanimeProvider.kt @@ -303,7 +303,7 @@ class GogoanimeProvider : MainAPI() { 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 { - AnimeEpisode( + Episode( fixUrl(it.attr("href").trim()), "Episode " + it.selectFirst(".name").text().replace("EP", "").trim() ) diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/KawaiifuProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/KawaiifuProvider.kt index eb873dcd..ab91abed 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/KawaiifuProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/KawaiifuProvider.kt @@ -94,7 +94,7 @@ class KawaiifuProvider : MainAPI() { val episodes = Jsoup.parse( app.get(episodesLink).text ).selectFirst(".list-ep").select("li").map { - AnimeEpisode( + Episode( it.selectFirst("a").attr("href"), if (it.text().trim().toIntOrNull() != null) "Episode ${it.text().trim()}" else it.text().trim() ) diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/MonoschinosProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/MonoschinosProvider.kt index 9c35f689..0e248ea2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/MonoschinosProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/MonoschinosProvider.kt @@ -5,7 +5,6 @@ import com.lagradost.cloudstream3.extractors.FEmbed import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.loadExtractor import java.util.* -import kotlin.collections.ArrayList class MonoschinosProvider : MainAPI() { @@ -132,7 +131,7 @@ class MonoschinosProvider : MainAPI() { val name = it.selectFirst("p.animetitles").text() val link = it.selectFirst("a").attr("href") val epThumb = it.selectFirst(".animeimghv").attr("data-src") - AnimeEpisode(link, name, posterUrl = epThumb) + Episode(link, name, posterUrl = epThumb) } return newAnimeLoadResponse(title, url, getType(type)) { posterUrl = poster diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/NineAnimeProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/NineAnimeProvider.kt index bb76839e..fd687b51 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/NineAnimeProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/NineAnimeProvider.kt @@ -203,7 +203,7 @@ class NineAnimeProvider : MainAPI() { )?.select("ul.episodes li a")?.mapNotNull { val link = it?.attr("href") ?: return@mapNotNull null val name = "Episode ${it.text()}" - AnimeEpisode(link, name) + Episode(link, name) } ?: return null diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/TenshiProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/TenshiProvider.kt index 2e730794..f17e1aa9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/TenshiProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/TenshiProvider.kt @@ -125,16 +125,15 @@ class TenshiProvider : MainAPI() { } @SuppressLint("SimpleDateFormat") - private fun dateParser(dateString: String?): String? { + private fun dateParser(dateString: String?): Date? { if (dateString == null) return null try { val format = SimpleDateFormat("dd 'of' MMM',' yyyy") - val newFormat = SimpleDateFormat("dd-MM-yyyy") val data = format.parse( dateString.replace("th ", " ").replace("st ", " ").replace("nd ", " ") .replace("rd ", " ") ) ?: return null - return newFormat.format(data) + return data } catch (e: Exception) { return null } @@ -246,14 +245,12 @@ class TenshiProvider : MainAPI() { val episodes = ArrayList(episodeNodes.map { val title = it.selectFirst(".episode-title")?.text()?.trim() - AnimeEpisode( - it.attr("href"), - if(title == "No Title") null else title, - it.selectFirst("img")?.attr("src"), - dateParser(it?.selectFirst(".episode-date")?.text()?.trim()), - null, - it.attr("data-content").trim(), - ) + newEpisode(it.attr("href")) { + this.name = if (title == "No Title") null else title + this.posterUrl = it.selectFirst("img")?.attr("src") + addDate(dateParser(it?.selectFirst(".episode-date")?.text()?.trim())) + this.description = it.attr("data-content").trim() + } }) val similarAnime = document.select("ul.anime-loop > li > a")?.mapNotNull { element -> diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WatchCartoonOnlineProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WatchCartoonOnlineProvider.kt index 3d17012e..9e43ac84 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WatchCartoonOnlineProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WatchCartoonOnlineProvider.kt @@ -113,28 +113,26 @@ class WatchCartoonOnlineProvider : MainAPI() { val href = it.attr("href") if (match != null) { val last = match.groupValues[3] - return@map TvSeriesEpisode( + return@map Episode( + href, if (last.startsWith("English")) null else last, match.groupValues[1].toIntOrNull(), match.groupValues[2].toIntOrNull(), - href ) } val match2 = Regex("Episode ([0-9]*).*? (.*)").find(text) if (match2 != null) { val last = match2.groupValues[2] - return@map TvSeriesEpisode( + return@map Episode( + href, if (last.startsWith("English")) null else last, null, match2.groupValues[1].toIntOrNull(), - href ) } - return@map TvSeriesEpisode( - text, - null, - null, - href + return@map Episode( + href, + text ) } TvSeriesLoadResponse( @@ -162,7 +160,7 @@ class WatchCartoonOnlineProvider : MainAPI() { url, this.name, TvType.TvSeries, - listOf(TvSeriesEpisode(title, null, null, url)), + listOf(Episode(url,title)), null, null, description, diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WcoProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WcoProvider.kt index d7435a4e..ca4af0c6 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WcoProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WcoProvider.kt @@ -181,7 +181,7 @@ class WcoProvider : MainAPI() { val episodeNodes = document.select(".tab-content .nav-item > a") val episodes = ArrayList(episodeNodes?.map { - AnimeEpisode(it.attr("href")) + Episode(it.attr("href")) } ?: ArrayList()) val statusElem = diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ZoroProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ZoroProvider.kt index fdea9c8b..51428cea 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ZoroProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ZoroProvider.kt @@ -231,16 +231,10 @@ class ZoroProvider : MainAPI() { ).text ).html ).select(".ss-list > a[href].ssl-item.ep-item").map { - val name = it?.attr("title") - AnimeEpisode( - fixUrl(it.attr("href")), - name, - null, - null, - null, - null, - it.selectFirst(".ssli-order")?.text()?.toIntOrNull() - ) + newEpisode(it.attr("href")) { + this.name = it?.attr("title") + this.episode = it.selectFirst(".ssli-order")?.text()?.toIntOrNull() + } } val actors = document.select("div.block-actors-content > div.bac-list-wrap > div.bac-item") diff --git a/app/src/main/java/com/lagradost/cloudstream3/metaproviders/TmdbProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/metaproviders/TmdbProvider.kt index a0cbf0f6..4b7796fa 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/metaproviders/TmdbProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/metaproviders/TmdbProvider.kt @@ -94,23 +94,23 @@ open class TmdbProvider : MainAPI() { val episodes = this.seasons?.filter { !disableSeasonZero || (it.season_number ?: 0) != 0 } ?.mapNotNull { season -> season.episodes?.map { episode -> - TvSeriesEpisode( - episode.name, - episode.season_number, - episode.episode_number, + Episode( TmdbLink( episode.external_ids?.imdb_id ?: this.external_ids?.imdb_id, this.id, episode.episode_number, episode.season_number, ).toJson(), + episode.name, + episode.season_number, + episode.episode_number, getImageUrl(episode.still_path), - episode.air_date?.toString(), episode.rating, episode.overview, + episode.air_date?.time, ) } ?: (1..(season.episode_count ?: 1)).map { episodeNum -> - TvSeriesEpisode( + Episode( episode = episodeNum, data = TmdbLink( this.external_ids?.imdb_id, diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/AkwamProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/AkwamProvider.kt index 218650da..d35a88a0 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/AkwamProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/AkwamProvider.kt @@ -63,20 +63,18 @@ class AkwamProvider : MainAPI() { 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 url = a.attr("href") val title = a.text() val thumbUrl = select("picture > img").attr("src") val date = select("p.entry-date").text() - return TvSeriesEpisode( - title, - null, - title.getIntFromText(), - url, - thumbUrl, - date - ) + return newEpisode(url) { + name = title + episode = title.getIntFromText() + posterUrl = thumbUrl + addDate(date) + } } @@ -142,7 +140,7 @@ class AkwamProvider : MainAPI() { } } else { val episodes = doc.select("div.bg-primary2.p-4.col-lg-4.col-md-6.col-12").map { - it.toTvSeriesEpisode() + it.toEpisode() }.let { val isReversed = it.lastOrNull()?.episode ?: 1 < it.firstOrNull()?.episode ?: 0 if (isReversed) diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/AllMoviesForYouProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/AllMoviesForYouProvider.kt index 00e7ff5d..5b5c9e34 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/AllMoviesForYouProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/AllMoviesForYouProvider.kt @@ -130,7 +130,7 @@ class AllMoviesForYouProvider : MainAPI() { } if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found") - val episodeList = ArrayList() + val episodeList = ArrayList() for (season in list) { val seasonResponse = app.get(season.second).text @@ -144,15 +144,15 @@ class AllMoviesForYouProvider : MainAPI() { val name = aName.text() val href = aName.attr("href") val date = episode.selectFirst("> td.MvTbTtl > span")?.text() + episodeList.add( - TvSeriesEpisode( - name, - season.first, - epNum, - fixUrl(href), - fixUrlNull(poster), - date - ) + newEpisode(href) { + this.name = name + this.season = season.first + this.episode = epNum + this.posterUrl = fixUrlNull(poster) + addDate(date) + } ) } } @@ -197,7 +197,7 @@ class AllMoviesForYouProvider : MainAPI() { if (id.contains("trembed")) { val soup = app.get(id).document 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) } } else loadExtractor(id, data, callback) diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/AsiaFlixProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/AsiaFlixProvider.kt index 247c2c12..e6893c85 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/AsiaFlixProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/AsiaFlixProvider.kt @@ -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 return videoUrl?.let { - TvSeriesEpisode( - null, + Episode( + it, null, number, - it ) } } @@ -101,7 +100,7 @@ class AsiaFlixProvider : MainAPI() { "$mainUrl$dramaUrl/$_id".replace("drama-detail", "show-details"), this@AsiaFlixProvider.name, TvType.AsianDrama, - episodes.mapNotNull { it.toTvSeriesEpisode() }.sortedBy { it.episode }, + episodes.mapNotNull { it.toEpisode() }.sortedBy { it.episode }, image, releaseYear, synopsis, @@ -115,7 +114,8 @@ class AsiaFlixProvider : MainAPI() { val headers = mapOf("X-Requested-By" to "asiaflix-web") 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 val cleanedResponse = Regex(""""data":(\{.*?),\{"sectionName"""").replace(response) { """"data":null},{"sectionName"""" @@ -145,14 +145,18 @@ class AsiaFlixProvider : MainAPI() { ): Boolean { if (isCasting) return false val headers = mapOf("X-Requested-By" to "asiaflix-web") - app.get("$apiUrl/utility/get-stream-links?url=$data", headers = headers).text.toKotlinObject().url?.let { + app.get( + "$apiUrl/utility/get-stream-links?url=$data", + headers = headers + ).text.toKotlinObject().url?.let { // val fixedUrl = "https://api.asiaflix.app/api/v2/utility/cors-proxy/playlist/${URLEncoder.encode(it, StandardCharsets.UTF_8.toString())}" callback.invoke( ExtractorLink( name, name, it, - "https://asianload1.com/", /** <------ This provider should be added instead */ + "https://asianload1.com/", + /** <------ This provider should be added instead */ getQualityFromName(it), URI(it).path.endsWith(".m3u8") ) diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/BflixProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/BflixProvider.kt index 0b414955..3c2f3aac 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/BflixProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/BflixProvider.kt @@ -242,11 +242,11 @@ open class BflixProvider() : MainAPI() { val eptitle = it.selectFirst(".episode a span.name").text() val secondtitle = it.selectFirst(".episode a span").text() .replace(Regex("(Episode (\\d+):|Episode (\\d+)-|Episode (\\d+))"),"") ?: "" - TvSeriesEpisode( + Episode( + href, secondtitle+eptitle, season, episode, - href, ) } val tvType = if (url.contains("/movie/") && episodes.size == 1) TvType.Movie else TvType.TvSeries diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CinecalidadProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CinecalidadProvider.kt index 33494059..c3a98bc9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CinecalidadProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CinecalidadProvider.kt @@ -104,11 +104,11 @@ class CinecalidadProvider:MainAPI() { val isValid = seasonid.size == 2 val episode = if (isValid) seasonid.getOrNull(1) else null val season = if (isValid) seasonid.getOrNull(0) else null - TvSeriesEpisode( + Episode( + href, name, season, episode, - href, if (epThumb.contains("svg")) null else epThumb ) } diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CuevanaProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CuevanaProvider.kt index 43c568d3..dadf02df 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CuevanaProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CuevanaProvider.kt @@ -1,14 +1,13 @@ package com.lagradost.cloudstream3.movieproviders import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.module.kotlin.readValue import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.mvvm.logError -import com.lagradost.cloudstream3.utils.* 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 name = "Cuevana" override val lang = "es" @@ -19,6 +18,7 @@ class CuevanaProvider:MainAPI() { TvType.Movie, TvType.TvSeries, ) + override suspend fun getMainPage(): HomePageResponse { val items = ArrayList() val urls = listOf( @@ -28,20 +28,21 @@ class CuevanaProvider:MainAPI() { items.add( HomePageList( "Series", - app.get("$mainUrl/serie", timeout = 120).document.select("section.home-series li").map { - val title = it.selectFirst("h2.Title").text() - val poster = it.selectFirst("img.lazy").attr("data-src") - val url = it.selectFirst("a").attr("href") - TvSeriesSearchResponse( - title, - url, - this.name, - TvType.Anime, - poster, - null, - null, - ) - }) + app.get("$mainUrl/serie", timeout = 120).document.select("section.home-series li") + .map { + val title = it.selectFirst("h2.Title").text() + val poster = it.selectFirst("img.lazy").attr("data-src") + val url = it.selectFirst("a").attr("href") + TvSeriesSearchResponse( + title, + url, + this.name, + TvType.Anime, + poster, + null, + null, + ) + }) ) for ((url, name) in urls) { try { @@ -69,6 +70,7 @@ class CuevanaProvider:MainAPI() { if (items.size <= 0) throw ErrorLoadingException() return HomePageResponse(items) } + override suspend fun search(query: String): List { val url = "$mainUrl/?s=${query}" val document = app.get(url).document @@ -101,6 +103,7 @@ class CuevanaProvider:MainAPI() { } } } + override suspend fun load(url: String): LoadResponse? { val soup = app.get(url, timeout = 120).document val title = soup.selectFirst("h1.Title").text() @@ -108,30 +111,33 @@ class CuevanaProvider:MainAPI() { val poster: String? = soup.selectFirst(".movtv-info div.Image img").attr("data-src") val year1 = soup.selectFirst("footer p.meta").toString() val yearRegex = Regex("(\\d+)") - val yearf = yearRegex.find(year1)?.destructured?.component1()?.replace(Regex("|"),"") + val yearf = + yearRegex.find(year1)?.destructured?.component1()?.replace(Regex("|"), "") val year = if (yearf.isNullOrBlank()) null else yearf.toIntOrNull() val episodes = soup.select(".all-episodes li.TPostMv article").map { li -> val href = li.select("a").attr("href") 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 -> str.split("x").mapNotNull { subStr -> subStr.toIntOrNull() } } val isValid = seasonid.size == 2 val episode = if (isValid) seasonid.getOrNull(1) else null val season = if (isValid) seasonid.getOrNull(0) else null - TvSeriesEpisode( + Episode( + href, null, season, episode, - href, fixUrl(epThumb) ) } 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 recelement = if (tvType == TvType.TvSeries) "main section div.series_listado.series div.xxx" - else "main section ul.MovieList li" + val recelement = + if (tvType == TvType.TvSeries) "main section div.series_listado.series div.xxx" + else "main section ul.MovieList li" val recommendations = soup.select(recelement).mapNotNull { element -> val recTitle = element.select("h2.Title").text() ?: return@mapNotNull null @@ -183,6 +189,7 @@ class CuevanaProvider:MainAPI() { data class Femcuevana( @JsonProperty("url") val url: String, ) + override suspend fun loadLinks( data: String, isCasting: Boolean, @@ -192,24 +199,31 @@ class CuevanaProvider:MainAPI() { app.get(data).document.select("div.TPlayer.embed_div iframe").apmap { val iframe = fixUrl(it.attr("data-src")) 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 -> femreg.value }.toList().apmap { fem -> - 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", - "User-Agent" to USER_AGENT, - "Accept" to "application/json, text/javascript, */*; q=0.01", - "Accept-Language" to "en-US,en;q=0.5", - "Content-Type" to "application/x-www-form-urlencoded; charset=UTF-8", - "X-Requested-With" to "XMLHttpRequest", - "Origin" to "https://api.cuevana3.me", - "DNT" to "1", - "Connection" to "keep-alive", - "Sec-Fetch-Dest" to "empty", - "Sec-Fetch-Mode" to "cors", - "Sec-Fetch-Site" to "same-origin",), - data = mapOf(Pair("h",key))).text + 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", + "User-Agent" to USER_AGENT, + "Accept" to "application/json, text/javascript, */*; q=0.01", + "Accept-Language" to "en-US,en;q=0.5", + "Content-Type" to "application/x-www-form-urlencoded; charset=UTF-8", + "X-Requested-With" to "XMLHttpRequest", + "Origin" to "https://api.cuevana3.me", + "DNT" to "1", + "Connection" to "keep-alive", + "Sec-Fetch-Dest" to "empty", + "Sec-Fetch-Mode" to "cors", + "Sec-Fetch-Site" to "same-origin", + ), + data = mapOf(Pair("h", key)) + ).text val json = parseJson(url) val link = json.url if (link.contains("fembed")) { @@ -218,13 +232,16 @@ class CuevanaProvider:MainAPI() { } } 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 -> tomreg.value }.toList().apmap { tom -> - val tomkey = tom.replace("//apialfa.tomatomatela.com/ir/player.php?h=","") - app.post("https://apialfa.tomatomatela.com/ir/rd.php", allowRedirects = false, - headers = mapOf("Host" to "apialfa.tomatomatela.com", + val tomkey = tom.replace("//apialfa.tomatomatela.com/ir/player.php?h=", "") + app.post( + "https://apialfa.tomatomatela.com/ir/rd.php", allowRedirects = false, + headers = mapOf( + "Host" to "apialfa.tomatomatela.com", "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-Language" to "en-US,en;q=0.5", @@ -235,16 +252,21 @@ class CuevanaProvider:MainAPI() { "Upgrade-Insecure-Requests" to "1", "Sec-Fetch-Dest" to "iframe", "Sec-Fetch-Mode" to "navigate", - "Sec-Fetch-Site" to "same-origin",), - data = mapOf(Pair("url",tomkey)) + "Sec-Fetch-Site" to "same-origin", + ), + data = mapOf(Pair("url", tomkey)) ).response.headers.values("location").apmap { loc -> 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 -> - 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 -> - app.post("https://api.cuevana3.me/ir/redirect_ddh.php", allowRedirects = false, - headers = mapOf("Host" to "api.cuevana3.me", + app.post( + "https://api.cuevana3.me/ir/redirect_ddh.php", + allowRedirects = false, + headers = mapOf( + "Host" to "api.cuevana3.me", "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-Language" to "en-US,en;q=0.5", @@ -255,20 +277,24 @@ class CuevanaProvider:MainAPI() { "Upgrade-Insecure-Requests" to "1", "Sec-Fetch-Dest" to "iframe", "Sec-Fetch-Mode" to "navigate", - "Sec-Fetch-Site" to "same-origin",), - data = mapOf(Pair("url",gotolink)) + "Sec-Fetch-Site" to "same-origin", + ), + data = mapOf(Pair("url", gotolink)) ).response.headers.values("location").apmap { golink -> loadExtractor(golink, data, callback) } } } 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 -> - indreg.value.replace("//api.cuevana3.me/sc/index.php?h=","") + indreg.value.replace("//api.cuevana3.me/sc/index.php?h=", "") }.toList().apmap { inlink -> - app.post("https://api.cuevana3.me/sc/r.php", allowRedirects = false, - headers = mapOf("Host" to "api.cuevana3.me", + app.post( + "https://api.cuevana3.me/sc/r.php", allowRedirects = false, + headers = mapOf( + "Host" to "api.cuevana3.me", "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-Language" to "en-US,en;q=0.5", @@ -281,8 +307,9 @@ class CuevanaProvider:MainAPI() { "Sec-Fetch-Dest" to "iframe", "Sec-Fetch-Mode" to "navigate", "Sec-Fetch-Site" to "same-origin", - "Sec-Fetch-User" to "?1",), - data = mapOf(Pair("h",inlink)) + "Sec-Fetch-User" to "?1", + ), + data = mapOf(Pair("h", inlink)) ).response.headers.values("location").apmap { link -> loadExtractor(link, data, callback) } diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/DoramasYTProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/DoramasYTProvider.kt index 5c7abb7e..3c113a10 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/DoramasYTProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/DoramasYTProvider.kt @@ -133,7 +133,7 @@ class DoramasYTProvider : MainAPI() { val name = it.selectFirst(".dtlsflim p").text() val link = it.selectFirst("a").attr("href") 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)) { posterUrl = poster diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/DramaSeeProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/DramaSeeProvider.kt index 73c2c1e0..b37c2c92 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/DramaSeeProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/DramaSeeProvider.kt @@ -118,7 +118,7 @@ class DramaSeeProvider : MainAPI() { } // Episodes Links - val episodeList = ArrayList() + val episodeList = ArrayList() body?.select("ul.episodes > li")?.forEach { ep -> val innerA = ep.select("a") ?: return@forEach val count = innerA.select("span.episode")?.text()?.toIntOrNull() ?: 0 @@ -141,7 +141,7 @@ class DramaSeeProvider : MainAPI() { //Log.i(this.name, "Result => (listOfLinks) ${listOfLinks.toJson()}") episodeList.add( - TvSeriesEpisode( + Episode( name = null, season = null, episode = count, diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/EgyBestProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/EgyBestProvider.kt index f1c19d32..2130eaf9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/EgyBestProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/EgyBestProvider.kt @@ -1,9 +1,9 @@ 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.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.ExtractorLink import org.jsoup.nodes.Element class EgyBestProvider : MainAPI() { @@ -109,7 +109,7 @@ class EgyBestProvider : MainAPI() { this.actors = actors } } else { - val episodes = ArrayList() + val episodes = ArrayList() doc.select("#mainLoad > div:nth-child(2) > div.h_scroll > div a").map { it.attr("href") }.apmap { @@ -118,13 +118,11 @@ class EgyBestProvider : MainAPI() { 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() episodes.add( - TvSeriesEpisode( + Episode( + eit.attr("href"), eit.select("span.title").text(), season, ep, - eit.attr("href"), - null, - null ) ) } diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/EntrePeliculasySeriesProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/EntrePeliculasySeriesProvider.kt index c8a33b94..3d33d39e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/EntrePeliculasySeriesProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/EntrePeliculasySeriesProvider.kt @@ -2,8 +2,8 @@ package com.lagradost.cloudstream3.movieproviders import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.mvvm.logError -import com.lagradost.cloudstream3.utils.* -import java.util.* +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.loadExtractor class EntrepeliculasyseriesProvider:MainAPI() { override var mainUrl = "https://entrepeliculasyseries.nu" @@ -102,11 +102,11 @@ class EntrepeliculasyseriesProvider:MainAPI() { val isValid = seasonid.size == 2 val episode = if (isValid) seasonid.getOrNull(1) else null val season = if (isValid) seasonid.getOrNull(0) else null - TvSeriesEpisode( + Episode( + href, null, season, episode, - href, fixUrl(epThumb) ) } diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/FilmanProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/FilmanProvider.kt index f466cd52..62c25dbe 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/FilmanProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/FilmanProvider.kt @@ -100,11 +100,11 @@ class FilmanProvider : MainAPI() { val e = episode.text() val regex = Regex("""\[s(\d{1,3})e(\d{1,3})]""").find(e) ?: return@mapNotNull null val eid = regex.groups - TvSeriesEpisode( + Episode( + episode.attr("href"), e.split("]")[1].trim(), eid[1]?.value?.toInt(), eid[2]?.value?.toInt(), - episode.attr("href"), ) }.toMutableList() diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/IHaveNoTvProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/IHaveNoTvProvider.kt index 58fc10a6..1632a7ae 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/IHaveNoTvProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/IHaveNoTvProvider.kt @@ -139,7 +139,7 @@ class IHaveNoTvProvider : MainAPI() { val episodes = if (isSeries) { container?.select(".episode")?.map { ep -> 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 (season, epNum) = if (ep.selectFirst(".episodeMeta > strong") != null && ep.selectFirst(".episodeMeta > strong").html().contains("S") @@ -150,7 +150,7 @@ class IHaveNoTvProvider : MainAPI() { split?.get(1)?.toIntOrNull() ) } else Pair(null, null) - val epDescription = ep.selectFirst(".episodeSynopsis")?.text() + year = Regex("""•?\s+(\d{4})\s+•""").find( ep.selectFirst(".episodeMeta").text() )?.destructured?.component1()?.toIntOrNull() @@ -158,16 +158,13 @@ class IHaveNoTvProvider : MainAPI() { categories.addAll( ep.select(".episodeMeta > a[href*=\"/category/\"]").map { it.text().trim() }) - TvSeriesEpisode( - epTitle, - season, - epNum, - epLink, - thumb, - null, - null, - epDescription - ) + newEpisode(epLink) { + this.name = ep.selectFirst("a[title]").attr("title") + this.season = season + this.episode = epNum + this.posterUrl = thumb + this.description = ep.selectFirst(".episodeSynopsis")?.text() + } } } else { listOf(MovieLoadResponse( @@ -188,7 +185,7 @@ class IHaveNoTvProvider : MainAPI() { } val poster = episodes?.firstOrNull().let { - if (isSeries && it != null) (it as TvSeriesEpisode).posterUrl + if (isSeries && it != null) (it as Episode).posterUrl else null } @@ -197,7 +194,7 @@ class IHaveNoTvProvider : MainAPI() { url, this.name, TvType.TvSeries, - episodes!!.map { it as TvSeriesEpisode }, + episodes!!.map { it as Episode }, poster, year, description, diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/KdramaHoodProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/KdramaHoodProvider.kt index eb4310ff..e3bec4ae 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/KdramaHoodProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/KdramaHoodProvider.kt @@ -173,7 +173,7 @@ class KdramaHoodProvider : MainAPI() { } } } - TvSeriesEpisode( + Episode( name = null, season = null, episode = count, diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/LookMovieProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/LookMovieProvider.kt index 698fdfa4..82ce3562 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/LookMovieProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/LookMovieProvider.kt @@ -273,11 +273,11 @@ class LookMovieProvider : MainAPI() { ).toJson() - TvSeriesEpisode( + Episode( + localData, it.title, it.season.toIntOrNull(), it.episode.toIntOrNull(), - localData ) }.toList() diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MeloMovieProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MeloMovieProvider.kt index 32e8960b..18bcbb88 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MeloMovieProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MeloMovieProvider.kt @@ -5,7 +5,6 @@ import com.fasterxml.jackson.module.kotlin.readValue import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.LoadResponse.Companion.addImdbUrl 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.getQualityFromName import org.jsoup.Jsoup @@ -87,7 +86,7 @@ class MeloMovieProvider : MainAPI() { return url } - private fun serializeData(element: Element): String { + private fun serializeData(element: Element): List { val eps = element.select("> tbody > tr") val parsed = eps.map { try { @@ -99,7 +98,7 @@ class MeloMovieProvider : MainAPI() { MeloMovieLink("", "") } }.filter { it.link != "" && it.name != "" } - return parsed.toJson() + return parsed } override suspend fun loadLinks( @@ -157,7 +156,7 @@ class MeloMovieProvider : MainAPI() { addImdbUrl(imdbUrl) } } else if (type == 2) { - val episodes = ArrayList() + val episodes = ArrayList() val seasons = document.select("div.accordion__card") ?: throw ErrorLoadingException("No episodes found") for (s in seasons) { @@ -172,7 +171,10 @@ class MeloMovieProvider : MainAPI() { val links = e.selectFirst("> div.collapse > div > table.accordion__list") ?: continue val data = serializeData(links) - episodes.add(TvSeriesEpisode(null, season, episode, data)) + episodes.add(newEpisode(data) { + this.season = season + this.episode = episode + }) } } episodes.reverse() diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MyCimaProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MyCimaProvider.kt index 3e65710f..3a41706b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MyCimaProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MyCimaProvider.kt @@ -31,7 +31,7 @@ class MyCimaProvider : MainAPI() { val title = select("div.Thumb--GridItem strong").text() .replace("$year", "") .replace("مشاهدة|فيلم|مسلسل|مترجم".toRegex(), "") - .replace("( نسخة مدبلجة )"," ( نسخة مدبلجة ) ") + .replace("( نسخة مدبلجة )", " ( نسخة مدبلجة ) ") // If you need to differentiate use the url. return MovieSearchResponse( title, @@ -47,8 +47,8 @@ class MyCimaProvider : MainAPI() { override suspend fun getMainPage(): HomePageResponse { // Title, Url val moviesUrl = listOf( - "Movies" to "$mainUrl/movies/page/"+(0..25).random(), - "Series" to "$mainUrl/seriestv/new/page/"+(0..25).random() + "Movies" to "$mainUrl/movies/page/" + (0..25).random(), + "Series" to "$mainUrl/seriestv/new/page/" + (0..25).random() ) val pages = moviesUrl.apmap { val doc = app.get(it.second).document @@ -61,21 +61,23 @@ class MyCimaProvider : MainAPI() { } override suspend fun search(query: String): List { - val q = query.replace(" ","%20") + val q = query.replace(" ", "%20") val result = arrayListOf() - listOf("$mainUrl/search/$q", + listOf( + "$mainUrl/search/$q", "$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 d.select("div.Grid--MycimaPosts div.GridItem").mapNotNull { - if(it.text().contains("اعلان")) return@mapNotNull null - it.toSearchResponse()?.let { it1 -> result.add(it1) } - } + if (it.text().contains("اعلان")) return@mapNotNull null + it.toSearchResponse()?.let { it1 -> result.add(it1) } + } } return result.distinct().sortedBy { it.name } } - data class MoreEPS ( + data class MoreEPS( val output: String ) @@ -86,7 +88,8 @@ class MyCimaProvider : MainAPI() { doc.select("mycima.separated--top")?.attr("data-lazy-style")?.getImageURL() ?.ifEmpty { doc.select("meta[itemprop=\"thumbnailUrl\"]")?.attr("content") } ?.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() .replace("($year)", "") .replace("مشاهدة|فيلم|مسلسل|مترجم|انمي".toRegex(), "") @@ -96,7 +99,8 @@ class MyCimaProvider : MainAPI() { it.text().contains("المدة") }?.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() } @@ -107,9 +111,10 @@ class MyCimaProvider : MainAPI() { ?: return@mapNotNull null Actor(name, image) } - val recommendations = doc.select("div.Grid--MycimaPosts div.GridItem")?.mapNotNull { element -> - element.toSearchResponse() - } + val recommendations = + doc.select("div.Grid--MycimaPosts div.GridItem")?.mapNotNull { element -> + element.toSearchResponse() + } return if (isMovie) { newMovieLoadResponse( @@ -127,55 +132,165 @@ class MyCimaProvider : MainAPI() { addActors(actors) } } else { - val episodes = ArrayList() + val episodes = ArrayList() val seasons = doc.select("div.List--Seasons--Episodes a").not(".selected").map { it.attr("href") } 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") - .apmap { episodes.add(TvSeriesEpisode(it.text(), season, it.text().getIntFromText(), it.attr("href"), null, null))} - if(moreButton.isNotEmpty()) { + .apmap { + 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 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) + val 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 -> - if (it != null) { - if(it > totals!!) return@apmap - val ajaxURL = "$mainUrl/AjaxCenter/MoreEpisodes/${moreButton.attr("data-term")}/$it" - val jsonResponse = app.get(ajaxURL) - val json = parseJson(jsonResponse.text) - 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)) } + if (it != null) { + if (it > totals!!) return@apmap + val ajaxURL = + "$mainUrl/AjaxCenter/MoreEpisodes/${moreButton.attr("data-term")}/$it" + val jsonResponse = app.get(ajaxURL) + val json = parseJson(jsonResponse.text) + val document = Jsoup.parse(json.output?.replace("""\""", "")) + document.select("a").map { + episodes.add( + Episode( + it.attr("href"), + it.text(), + season, + it.text().getIntFromText(), + ) + ) } } - } - if(seasons.isNotEmpty()) { - seasons.apmap { surl -> - if(surl.contains("%d9%85%d8%af%d8%a8%d9%84%d8%ac")) return@apmap - val seasonsite = app.get(surl).document - val fmoreButton = seasonsite.select("div.MoreEpisodes--Button") - val fseason = seasonsite.select("div.List--Seasons--Episodes a.selected").text().getIntFromText() ?: 1 - 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))} - 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 -> - if (it != null) { - if(it > totals!!) return@apmap - val ajaxURL = "$mainUrl/AjaxCenter/MoreEpisodes/${fmoreButton.attr("data-term")}/$it" - val jsonResponse = app.get(ajaxURL) - val json = parseJson(jsonResponse.text) - 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)) } - } - } - } else return@apmap - } } - newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes.distinct().sortedBy { it.episode }) { + } + if (seasons.isNotEmpty()) { + seasons.apmap { surl -> + if (surl.contains("%d9%85%d8%af%d8%a8%d9%84%d8%ac")) return@apmap + val seasonsite = app.get(surl).document + val fmoreButton = seasonsite.select("div.MoreEpisodes--Button") + val fseason = seasonsite.select("div.List--Seasons--Episodes a.selected").text() + .getIntFromText() ?: 1 + seasonsite.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a") + .map { + episodes.add( + Episode( + it.attr("href"), + 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 -> + if (it != null) { + if (it > totals!!) return@apmap + val ajaxURL = + "$mainUrl/AjaxCenter/MoreEpisodes/${fmoreButton.attr("data-term")}/$it" + val jsonResponse = app.get(ajaxURL) + val json = parseJson(jsonResponse.text) + val document = Jsoup.parse(json.output?.replace("""\""", "")) + document.select("a").map { + episodes.add( + Episode( + it.attr("href"), + it.text(), + fseason, + it.text().getIntFromText(), + ) + ) + } + } + } + } else return@apmap + } + } + newTvSeriesLoadResponse( + title, + url, + TvType.TvSeries, + episodes.distinct().sortedBy { it.episode }) { this.duration = duration this.posterUrl = posterUrl this.tags = tags @@ -186,6 +301,7 @@ class MyCimaProvider : MainAPI() { } } } + override suspend fun loadLinks( data: String, isCasting: Boolean, @@ -194,18 +310,20 @@ class MyCimaProvider : MainAPI() { ): Boolean { app.get(data).document .select("ul.List--Download--Mycima--Single:nth-child(2) li").map { - it.select("a").map { linkElement -> - callback.invoke( - ExtractorLink( - this.name, - this.name + " - ${linkElement.select("resolution").text().getIntFromText()}p", - linkElement.attr("href"), - this.mainUrl, - 2 + it.select("a").map { linkElement -> + callback.invoke( + ExtractorLink( + this.name, + this.name + " - ${ + linkElement.select("resolution").text().getIntFromText() + }p", + linkElement.attr("href"), + this.mainUrl, + 2 + ) ) - ) - } - }.flatten() + } + }.flatten() return true } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PeliSmartProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PeliSmartProvider.kt index 36c19247..09a02c3c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PeliSmartProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PeliSmartProvider.kt @@ -2,9 +2,7 @@ package com.lagradost.cloudstream3.movieproviders import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.utils.ExtractorLink -import com.lagradost.cloudstream3.utils.extractorApis import com.lagradost.cloudstream3.utils.loadExtractor -import kotlin.collections.ArrayList class PeliSmartProvider: MainAPI() { override var mainUrl = "https://pelismart.com" @@ -105,11 +103,11 @@ class PeliSmartProvider: MainAPI() { val isValid = seasonid?.size == 2 val episode = if (isValid) seasonid?.getOrNull(1) else null val season = if (isValid) seasonid?.getOrNull(0) else null - TvSeriesEpisode( + Episode( + href, name, season, episode, - href, ) } return when (val tvType = if (episodes.isEmpty()) TvType.Movie else TvType.TvSeries) { diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PelisflixProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PelisflixProvider.kt index 257718d9..18d21afa 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PelisflixProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PelisflixProvider.kt @@ -127,7 +127,7 @@ class PelisflixProvider : MainAPI() { } if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found") - val episodeList = ArrayList() + val episodeList = ArrayList() for ((seasonInt, seasonUrl) in list) { val seasonDocument = app.get(seasonUrl).document @@ -141,14 +141,13 @@ class PelisflixProvider : MainAPI() { val href = aName.attr("href") val date = episode.selectFirst("> td.MvTbTtl > span")?.text() episodeList.add( - TvSeriesEpisode( - name, - seasonInt, - epNum, - href, - fixUrlNull(epthumb), - date - ) + newEpisode(href) { + this.name = name + this.season = seasonInt + this.episode = epNum + this.posterUrl = fixUrlNull(epthumb) + addDate(date) + } ) } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PelisplusHDProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PelisplusHDProvider.kt index 2b389980..fb14456f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PelisplusHDProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PelisplusHDProvider.kt @@ -111,11 +111,11 @@ class PelisplusHDProvider:MainAPI() { val isValid = seasonid.size == 2 val episode = if (isValid) seasonid.getOrNull(1) else null val season = if (isValid) seasonid.getOrNull(0) else null - TvSeriesEpisode( + Episode( + href, name, season, episode, - href, ) } diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PelisplusProviderTemplate.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PelisplusProviderTemplate.kt index 1ac026b5..aaf824dc 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PelisplusProviderTemplate.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PelisplusProviderTemplate.kt @@ -1,9 +1,13 @@ package com.lagradost.cloudstream3.movieproviders 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 + /** Needs to inherit from MainAPI() to * 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 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 href = fixUrl(li.selectFirst("a").attr("href")) 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 epDate = li.selectFirst(".meta > .date").text() + if(year == null) { + year = epDate?.split("-")?.get(0)?.toIntOrNull() + } - - TvSeriesEpisode( - null, - season, - episode, - fixUrl(li.selectFirst("a").attr("href")), - epThumb, - epDate - ) + newEpisode(li.selectFirst("a").attr("href")) { + this.season = season + this.episode = episode + this.posterUrl = epThumb + addDate(epDate) + } }.reversed() - val year = episodes.first().date?.split("-")?.get(0)?.toIntOrNull() - // 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 @@ -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() - // 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. override suspend fun loadLinks( data: String, diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PinoyHDXyzProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PinoyHDXyzProvider.kt index 67773d4b..1a5500ef 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PinoyHDXyzProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PinoyHDXyzProvider.kt @@ -138,7 +138,7 @@ class PinoyHDXyzProvider : MainAPI() { } // Try looking for episodes, for series - val episodeList = ArrayList() + val episodeList = ArrayList() val bodyText = body?.select("div.section-cotent1.col-md-12")?.select("section") ?.select("script")?.toString() ?: "" //Log.i(this.name, "Result => (bodyText) ${bodyText}") @@ -151,7 +151,7 @@ class PinoyHDXyzProvider : MainAPI() { val listEpStream = listOf(ep.trim()).toJson() //Log.i(this.name, "Result => (ep $count) $listEpStream") episodeList.add( - TvSeriesEpisode( + Episode( name = null, season = null, episode = count, diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PinoyMoviePediaProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PinoyMoviePediaProvider.kt index db24b553..acc22786 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PinoyMoviePediaProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PinoyMoviePediaProvider.kt @@ -159,7 +159,7 @@ class PinoyMoviePediaProvider : MainAPI() { // Parse episodes if series if (isTvSeries) { - val episodeList = ArrayList() + val episodeList = ArrayList() val epLinks = playcontainer?.select("div > div > div.source-box") //Log.i(this.name, "Result => (epList) ${epList}") body?.select("div#playeroptions > ul > li")?.forEach { ep -> @@ -175,7 +175,7 @@ class PinoyMoviePediaProvider : MainAPI() { val streamEpLink = listOf(href.trim()).toJson() //Log.i(this.name, "Result => (streamEpLink $epNum) $streamEpLink") episodeList.add( - TvSeriesEpisode( + Episode( name = null, season = null, episode = epNum, diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/SeriesflixProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/SeriesflixProvider.kt index 5f82667f..579f18f5 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/SeriesflixProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/SeriesflixProvider.kt @@ -124,7 +124,7 @@ class SeriesflixProvider : MainAPI() { } if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found") - val episodeList = ArrayList() + val episodeList = ArrayList() for (season in list) { val seasonDocument = app.get(season.second).document @@ -138,14 +138,13 @@ class SeriesflixProvider : MainAPI() { val href = aName.attr("href") val date = episode.selectFirst("> td.MvTbTtl > span")?.text() episodeList.add( - TvSeriesEpisode( - name, - season.first, - epNum, - href, - fixUrlNull(epthumb), - date - ) + newEpisode(href) { + this.name = name + this.season = season.first + this.episode = epNum + this.posterUrl = fixUrlNull(epthumb) + addDate(date) + } ) } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/SflixProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/SflixProvider.kt index 1c4cf979..9e328d7f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/SflixProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/SflixProvider.kt @@ -11,7 +11,6 @@ import com.lagradost.cloudstream3.animeproviders.ZoroProvider import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall import com.lagradost.cloudstream3.network.AppResponse 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.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.ExtractorLink @@ -214,7 +213,7 @@ open class SflixProvider : MainAPI() { val comingSoon = sourceIds.isEmpty() - return newMovieLoadResponse(title, url, TvType.Movie, sourceIds.toJson()) { + return newMovieLoadResponse(title, url, TvType.Movie, sourceIds) { this.year = year this.posterUrl = posterUrl this.plot = plot @@ -228,7 +227,7 @@ open class SflixProvider : MainAPI() { } } else { val seasonsDocument = app.get("$mainUrl/ajax/v2/tv/seasons/$id").document - val episodes = arrayListOf() + val episodes = arrayListOf() var seasonItems = seasonsDocument.select("div.dropdown-menu.dropdown-menu-model > a") if (seasonItems.isNullOrEmpty()) seasonItems = seasonsDocument.select("div.dropdown-menu > a.dropdown-item") @@ -260,13 +259,12 @@ open class SflixProvider : MainAPI() { } ?: episode episodes.add( - TvSeriesEpisode( - episodeTitle?.removePrefix("Episode $episodeNum: "), - season + 1, - episodeNum, - Pair(url, episodeData).toJson(), - fixUrlNull(episodePosterUrl) - ) + newEpisode(Pair(url, episodeData)) { + this.posterUrl = fixUrlNull(episodePosterUrl) + this.name = episodeTitle?.removePrefix("Episode $episodeNum: ") + this.season = season + 1 + this.episode = episodeNum + } ) } } @@ -370,7 +368,8 @@ open class SflixProvider : MainAPI() { val posterUrl = img.attr("data-src") ?: img.attr("src") val href = fixUrl(inner.select("a").attr("href")) 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 year: Int? = null var quality: SearchQuality? = null diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/SoaptwoDayProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/SoaptwoDayProvider.kt index 90220961..7c600cbe 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/SoaptwoDayProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/SoaptwoDayProvider.kt @@ -75,7 +75,7 @@ class SoaptwoDayProvider:MainAPI() { val episodes = soup.select("div.alert > div > div > a").mapNotNull { val link = fixUrlNull(it?.attr("href")) ?: return@mapNotNull null val name = it?.text()?.replace(Regex("(^(\\d+)\\.)"),"") - TvSeriesEpisode( + Episode( name = name, data = link ) diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TheFlixToProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TheFlixToProvider.kt index 6369b2d1..5a4c17ca 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TheFlixToProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TheFlixToProvider.kt @@ -420,13 +420,15 @@ class TheFlixToProvider : MainAPI() { ) //{"affiliateCode":"","pathname":"/movie/696806-the-adam-project"} val data = mapOf("affiliateCode" to "", "pathname" to url.removePrefix(mainUrl)) - val resp = app.post(optionsUrl, headers = mapOf( - "User-Agent" to USER_AGENT, - "Content-Type" to "application/json;charset=UTF-8", - "Accept" to "application/json, text/plain, */*", - "Origin" to url, - "Referer" to mainUrl, - ), data = data) + val resp = app.post( + optionsUrl, headers = mapOf( + "User-Agent" to USER_AGENT, + "Content-Type" to "application/json;charset=UTF-8", + "Accept" to "application/json, text/plain, */*", + "Origin" to url, + "Referer" to mainUrl, + ), data = data + ) latestCookies = resp.cookies val newData = getLoadMan(url) @@ -442,7 +444,7 @@ class TheFlixToProvider : MainAPI() { override suspend fun load(url: String): LoadResponse? { val tvtype = if (url.contains("movie")) TvType.Movie else TvType.TvSeries val json = getLoadMainRetry(url) - val episodes = ArrayList() + val episodes = ArrayList() val isMovie = tvtype == TvType.Movie val pageMain = json.props.pageProps @@ -471,11 +473,11 @@ class TheFlixToProvider : MainAPI() { val test = epi.videos val ratinginfo = (epi.voteAverage)?.times(10)?.toInt() 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, seasonum, episodenu, - "$mainUrl/tv-show/$movieId-${cleanTitle(movietitle)}/season-$seasonum/episode-$episodenu", description = epDesc!!, posterUrl = seasonPoster, rating = rating, diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/VfSerieProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/VfSerieProvider.kt index 069c75ff..f7eeee6f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/VfSerieProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/VfSerieProvider.kt @@ -28,7 +28,8 @@ class VfSerieProvider : MainAPI() { for (item in items) { 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/) continue @@ -37,7 +38,17 @@ class VfSerieProvider : MainAPI() { 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 } @@ -99,7 +110,8 @@ class VfSerieProvider : MainAPI() { val response = app.get(url).text val document = Jsoup.parse(response) 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") @@ -109,7 +121,8 @@ class VfSerieProvider : MainAPI() { //val duration = document.select("span.Time").text()?.toIntOrNull() 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() @@ -124,7 +137,7 @@ class VfSerieProvider : MainAPI() { } if (list.isEmpty()) throw ErrorLoadingException("No Seasons Found") - val episodeList = ArrayList() + val episodeList = ArrayList() for (season in list) { val episodes = document.select("table > tbody > tr") @@ -132,20 +145,20 @@ class VfSerieProvider : MainAPI() { episodes.forEach { episode -> val epNum = episode.selectFirst("> span.Num")?.text()?.toIntOrNull() 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 date = episode.selectFirst("> td.MvTbTtl > span")?.text()?.toString() val name = aName.text() val href = aName.attr("href") episodeList.add( - TvSeriesEpisode( - name, - season, - epNum, - href, - poster, - date - ) + newEpisode(href) { + this.name = name + this.season = season + this.episode = epNum + this.posterUrl = poster + addDate(date) + } ) } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/VidstreamProviderTemplate.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/VidstreamProviderTemplate.kt index e5731e25..c9dd894a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/VidstreamProviderTemplate.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/VidstreamProviderTemplate.kt @@ -85,6 +85,7 @@ open class VidstreamProviderTemplate : MainAPI() { val description = soup.selectFirst(".post-entry")?.text()?.trim() var poster: String? = null + var year : Int? = null val episodes = 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() ?.toIntOrNull() - - TvSeriesEpisode( - epTitle, - null, - epNum, - fixUrl(li.selectFirst("a").attr("href")), - epThumb, - epDate - ) + if(year == null) { + year = epDate?.split("-")?.get(0)?.toIntOrNull() + } + newEpisode(li.selectFirst("a").attr("href")) { + this.episode = epNum + this.posterUrl = epThumb + addDate(epDate) + } }.reversed() - val year = episodes.first().date?.split("-")?.get(0)?.toIntOrNull() - // 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 @@ -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() - // 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. override suspend fun loadLinks( data: String, diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/WatchAsianProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/WatchAsianProvider.kt index 2bb27f98..5e392ec9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/WatchAsianProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/WatchAsianProvider.kt @@ -156,7 +156,7 @@ class WatchAsianProvider : MainAPI() { val regex = "(?<=episode-).*?(?=.html)".toRegex() val count = regex.find(epLink, mainUrl.length)?.value?.toIntOrNull() ?: 0 //Log.i(this.name, "Result => $epLink (regexYear) ${count}") - TvSeriesEpisode( + Episode( name = null, season = null, episode = count, diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/french-stream.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/french-stream.kt index 05874ed0..1d0b8e13 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/french-stream.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/french-stream.kt @@ -112,11 +112,11 @@ class FrenchStreamProvider : MainAPI() { if (poster == null) { poster = a.selectFirst("div.fposter > img")?.attr("src") } - TvSeriesEpisode( + Episode( + fixUrl(url).plus("-episodenumber:$epNum"), epTitle, null, epNum, - fixUrl(url).plus("-episodenumber:$epNum"), null, // episode Thumbnail null // episode date ) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt index dcf43769..aef9580d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt @@ -364,8 +364,8 @@ class ResultViewModel : ViewModel() { filterName(i.name), i.posterUrl, episode, - null, // TODO FIX SEASON - i.url, + i.season, + i.data, apiName, mainId + index + 1 + idIndex * 100000, index,