mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
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,20 +28,21 @@ 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")
|
||||||
val title = it.selectFirst("h2.Title").text()
|
.map {
|
||||||
val poster = it.selectFirst("img.lazy").attr("data-src")
|
val title = it.selectFirst("h2.Title").text()
|
||||||
val url = it.selectFirst("a").attr("href")
|
val poster = it.selectFirst("img.lazy").attr("data-src")
|
||||||
TvSeriesSearchResponse(
|
val url = it.selectFirst("a").attr("href")
|
||||||
title,
|
TvSeriesSearchResponse(
|
||||||
url,
|
title,
|
||||||
this.name,
|
url,
|
||||||
TvType.Anime,
|
this.name,
|
||||||
poster,
|
TvType.Anime,
|
||||||
null,
|
poster,
|
||||||
null,
|
null,
|
||||||
)
|
null,
|
||||||
})
|
)
|
||||||
|
})
|
||||||
)
|
)
|
||||||
for ((url, name) in urls) {
|
for ((url, name) in urls) {
|
||||||
try {
|
try {
|
||||||
|
@ -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,30 +111,33 @@ 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 =
|
||||||
else "main section ul.MovieList li"
|
if (tvType == TvType.TvSeries) "main section div.series_listado.series div.xxx"
|
||||||
|
else "main section ul.MovieList li"
|
||||||
val recommendations =
|
val recommendations =
|
||||||
soup.select(recelement).mapNotNull { element ->
|
soup.select(recelement).mapNotNull { element ->
|
||||||
val recTitle = element.select("h2.Title").text() ?: return@mapNotNull null
|
val recTitle = element.select("h2.Title").text() ?: return@mapNotNull null
|
||||||
|
@ -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,24 +199,31 @@ 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(
|
||||||
"User-Agent" to USER_AGENT,
|
"https://api.cuevana3.me/fembed/api.php",
|
||||||
"Accept" to "application/json, text/javascript, */*; q=0.01",
|
allowRedirects = false,
|
||||||
"Accept-Language" to "en-US,en;q=0.5",
|
headers = mapOf(
|
||||||
"Content-Type" to "application/x-www-form-urlencoded; charset=UTF-8",
|
"Host" to "api.cuevana3.me",
|
||||||
"X-Requested-With" to "XMLHttpRequest",
|
"User-Agent" to USER_AGENT,
|
||||||
"Origin" to "https://api.cuevana3.me",
|
"Accept" to "application/json, text/javascript, */*; q=0.01",
|
||||||
"DNT" to "1",
|
"Accept-Language" to "en-US,en;q=0.5",
|
||||||
"Connection" to "keep-alive",
|
"Content-Type" to "application/x-www-form-urlencoded; charset=UTF-8",
|
||||||
"Sec-Fetch-Dest" to "empty",
|
"X-Requested-With" to "XMLHttpRequest",
|
||||||
"Sec-Fetch-Mode" to "cors",
|
"Origin" to "https://api.cuevana3.me",
|
||||||
"Sec-Fetch-Site" to "same-origin",),
|
"DNT" to "1",
|
||||||
data = mapOf(Pair("h",key))).text
|
"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<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,9 +111,10 @@ 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 =
|
||||||
element.toSearchResponse()
|
doc.select("div.Grid--MycimaPosts div.GridItem")?.mapNotNull { element ->
|
||||||
}
|
element.toSearchResponse()
|
||||||
|
}
|
||||||
|
|
||||||
return if (isMovie) {
|
return if (isMovie) {
|
||||||
newMovieLoadResponse(
|
newMovieLoadResponse(
|
||||||
|
@ -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 =
|
||||||
val jsonResponse = app.get(ajaxURL)
|
"$mainUrl/AjaxCenter/MoreEpisodes/${moreButton.attr("data-term")}/$it"
|
||||||
val json = parseJson<MoreEPS>(jsonResponse.text)
|
val jsonResponse = app.get(ajaxURL)
|
||||||
val document = Jsoup.parse(json.output?.replace("""\""", ""))
|
val json = parseJson<MoreEPS>(jsonResponse.text)
|
||||||
document.select("a").map { episodes.add(TvSeriesEpisode(it.text(), season, it.text().getIntFromText(), it.attr("href"), null, null)) }
|
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<MoreEPS>(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<MoreEPS>(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.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,
|
||||||
|
@ -194,18 +310,20 @@ class MyCimaProvider : MainAPI() {
|
||||||
): Boolean {
|
): Boolean {
|
||||||
app.get(data).document
|
app.get(data).document
|
||||||
.select("ul.List--Download--Mycima--Single:nth-child(2) li").map {
|
.select("ul.List--Download--Mycima--Single:nth-child(2) li").map {
|
||||||
it.select("a").map { linkElement ->
|
it.select("a").map { linkElement ->
|
||||||
callback.invoke(
|
callback.invoke(
|
||||||
ExtractorLink(
|
ExtractorLink(
|
||||||
this.name,
|
this.name,
|
||||||
this.name + " - ${linkElement.select("resolution").text().getIntFromText()}p",
|
this.name + " - ${
|
||||||
linkElement.attr("href"),
|
linkElement.select("resolution").text().getIntFromText()
|
||||||
this.mainUrl,
|
}p",
|
||||||
2
|
linkElement.attr("href"),
|
||||||
|
this.mainUrl,
|
||||||
|
2
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
}
|
}.flatten()
|
||||||
}.flatten()
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
"User-Agent" to USER_AGENT,
|
optionsUrl, headers = mapOf(
|
||||||
"Content-Type" to "application/json;charset=UTF-8",
|
"User-Agent" to USER_AGENT,
|
||||||
"Accept" to "application/json, text/plain, */*",
|
"Content-Type" to "application/json;charset=UTF-8",
|
||||||
"Origin" to url,
|
"Accept" to "application/json, text/plain, */*",
|
||||||
"Referer" to mainUrl,
|
"Origin" to url,
|
||||||
), data = data)
|
"Referer" to mainUrl,
|
||||||
|
), 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…
Reference in a new issue