Fixes on multiple providers and added some extractors (#734)

* Fixes on Providers and Extractors
Co-authored-by: Osten <11805592+LagradOst@users.noreply.github.com>
This commit is contained in:
Stormunblessed 2022-03-04 12:47:36 +00:00 committed by GitHub
parent 8aa907d1d9
commit 3b08e82787
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 502 additions and 235 deletions

View file

@ -1,8 +1,9 @@
package com.lagradost.cloudstream3.animeproviders package com.lagradost.cloudstream3.animeproviders
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.loadExtractor import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import java.util.* import java.util.*
class AnimeflvnetProvider:MainAPI() { class AnimeflvnetProvider:MainAPI() {
@ -13,9 +14,8 @@ class AnimeflvnetProvider : MainAPI() {
else TvType.Anime else TvType.Anime
} }
} }
override val mainUrl = "https://www3.animeflv.net"
override val mainUrl = "https://m.animeflv.net" override val name = "Animeflv.net"
override val name = "AnimeFLV"
override val lang = "es" override val lang = "es"
override val hasMainPage = true override val hasMainPage = true
override val hasChromecastSupport = true override val hasChromecastSupport = true
@ -28,21 +28,24 @@ class AnimeflvnetProvider : MainAPI() {
override suspend fun getMainPage(): HomePageResponse { override suspend fun getMainPage(): HomePageResponse {
val urls = listOf( val urls = listOf(
Pair("$mainUrl/browse?type[]=movie&order=updated", "Peliculas actualizadas"), Pair("$mainUrl/browse?type[]=movie&order=updated", "Películas"),
Pair("$mainUrl/browse?order=updated", "Animes recientemente actualizados"), Pair("$mainUrl/browse?status[]=2&order=default", "Animes"),
Pair("$mainUrl/browse?status[]=2&order=default", "Animes finalizados"),
Pair("$mainUrl/browse?status[]=1&order=rating", "En emision"), Pair("$mainUrl/browse?status[]=1&order=rating", "En emision"),
) )
val items = ArrayList<HomePageList>() val items = ArrayList<HomePageList>()
for (i in urls) { items.add(
try { HomePageList(
val doc = app.get(i.first).document "Últimos episodios",
val home = doc.select("ul.List-Animes li.Anime").map { app.get(mainUrl).document.select("main.Main ul.ListEpisodios li").map {
val title = it.selectFirst("h2.title").text() val title = it.selectFirst("strong.Title").text()
val poster = it.selectFirst(".Image img").attr("src") val poster = it.selectFirst("span img").attr("src")
val epRegex = Regex("(-(\\d+)\$)")
val url = it.selectFirst("a").attr("href").replace(epRegex,"")
.replace("ver/","anime/")
val epNum = it.selectFirst("span.Capi").text().replace("Episodio ","").toIntOrNull()
AnimeSearchResponse( AnimeSearchResponse(
title, title,
fixUrl(it.selectFirst("a").attr("href")), fixUrl(url),
this.name, this.name,
TvType.Anime, TvType.Anime,
fixUrl(poster), fixUrl(poster),
@ -50,10 +53,29 @@ class AnimeflvnetProvider : MainAPI() {
if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of( if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(
DubStatus.Dubbed DubStatus.Dubbed
) else EnumSet.of(DubStatus.Subbed), ) else EnumSet.of(DubStatus.Subbed),
subEpisodes = epNum,
dubEpisodes = epNum,
)
})
)
for ((url, name) in urls) {
try {
val doc = app.get(url).document
val home = doc.select("ul.ListAnimes li article").map {
val title = it.selectFirst("h3.Title").text()
val poster = it.selectFirst("figure img").attr("src")
AnimeSearchResponse(
title,
fixUrl(it.selectFirst("a").attr("href")),
this.name,
TvType.Anime,
fixUrl(poster),
null,
if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(DubStatus.Subbed),
) )
} }
items.add(HomePageList(i.second, home)) items.add(HomePageList(name, home))
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
@ -62,13 +84,23 @@ class AnimeflvnetProvider : MainAPI() {
return HomePageResponse(items) return HomePageResponse(items)
} }
data class SearchObject (
@JsonProperty("id") val id: String,
@JsonProperty("title") val title: String,
@JsonProperty("type") val type: String,
@JsonProperty("last_id") val lastId: String,
@JsonProperty("slug") val slug: String
)
override suspend fun search(query: String): List<SearchResponse> { override suspend fun search(query: String): List<SearchResponse> {
val url = "${mainUrl}/browse?q=${query}" val response = app.post("https://www3.animeflv.net/api/animes/search",
val doc = app.get(url).document data = mapOf(Pair("value",query))
return doc.select("ul.List-Animes li.Anime").map { ).text
val title = it.selectFirst("h2.title").text() val json = parseJson<List<SearchObject>>(response)
val href = fixUrl(it.selectFirst("a").attr("href")) return json.map { searchr ->
val image = it.selectFirst(".Image img").attr("src") val title = searchr.title
val href = "$mainUrl/anime/${searchr.slug}"
val image = "$mainUrl/uploads/animes/covers/${searchr.id}.jpg"
AnimeSearchResponse( AnimeSearchResponse(
title, title,
href, href,
@ -76,65 +108,69 @@ class AnimeflvnetProvider : MainAPI() {
TvType.Anime, TvType.Anime,
fixUrl(image), fixUrl(image),
null, null,
if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of( if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(DubStatus.Subbed),
DubStatus.Subbed
),
) )
} }
} }
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 title = doc.selectFirst("h1.Title").text() val title = doc.selectFirst("h1.Title").text()
val description = doc.selectFirst(".Anime > header:nth-child(1) > p:nth-child(3)").text() val poster = doc.selectFirst("div.AnimeCover div.Image figure img").attr("src")
.replace("Sinopsis: ", "") val description = doc.selectFirst("div.Description p").text()
val poster = doc.selectFirst(".Image img").attr("src") val type = doc.selectFirst("span.Type").text()
val episodes = doc.select("li.Episode").map { li -> val status = when (doc.selectFirst("p.AnmStts span")?.text()) {
val href = fixUrl(li.selectFirst("a").attr("href")) "En emision" -> ShowStatus.Ongoing
AnimeEpisode(
fixUrl(href), "Episodio" + li.selectFirst("a").text().replace(title, "")
)
}
val type = doc.selectFirst("span.Type.A").text()
val genre = doc.select("a.Tag")
.map { it?.text()?.trim().toString() }
val status =
when (doc.selectFirst("article.Anime.Single.Bglg header p strong.Anm-On")?.text()) {
"En emisión" -> ShowStatus.Ongoing
"Finalizado" -> ShowStatus.Completed "Finalizado" -> ShowStatus.Completed
else -> null else -> null
} }
val genre = doc.select("nav.Nvgnrs a")
.map { it?.text()?.trim().toString() }
doc.select("script").map { script ->
if (script.data().contains("var episodes = [")) {
val data = script.data().substringAfter("var episodes = [").substringBefore("];")
data.split("],").forEach {
val epNum = it.removePrefix("[").substringBefore(",")
// val epthumbid = it.removePrefix("[").substringAfter(",").substringBefore("]")
val animeid = doc.selectFirst("div.Strs.RateIt").attr("data-id")
val epthumb = "https://cdn.animeflv.net/screenshots/$animeid/$epNum/th_3.jpg"
val link = url.replace("/anime/","/ver/")+"-$epNum"
episodes.add( AnimeEpisode(
link,
null,
posterUrl = epthumb,
episode = epNum.toIntOrNull()
)
)
}
}
}
return newAnimeLoadResponse(title, url, getType(type)) { return newAnimeLoadResponse(title, url, getType(type)) {
posterUrl = fixUrl(poster) posterUrl = fixUrl(poster)
addEpisodes(DubStatus.Subbed, episodes) addEpisodes(DubStatus.Subbed, episodes.reversed())
showStatus = status showStatus = status
plot = description plot = description
tags = genre tags = genre
} }
} }
override suspend fun loadLinks( override suspend fun loadLinks(
data: String, data: String,
isCasting: Boolean, isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
//There might be a better way to do this, but this one works app.get(data).document.select("script").apmap { script ->
val html = app.get(data).text if (script.data().contains("var videos = {") || script.data().contains("var anime_id =") || script.data().contains("server")) {
val linkRegex = Regex("""(https:.*?\.html.*)""") val videos = script.data().replace("\\/", "/")
fetchUrls(videos).map {
val videos = linkRegex.findAll(html).map { it.replace("https://embedsb.com/e/","https://watchsb.com/e/")
it.value.replace("\\/", "/") .replace("https://ok.ru","http://ok.ru")
}.toList() }.apmap {
loadExtractor(it, data, callback)
val serversRegex = }
Regex("(https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_+.~#?&/=]*))") }
serversRegex.findAll(videos.toString()).map {
it.value.replace("https://embedsb.com", "https://watchsb.com")
}.forEach { link ->
loadExtractor(link, data, callback)
} }
return true return true
} }

View file

@ -2,10 +2,7 @@ package com.lagradost.cloudstream3.animeproviders
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.AppUtils import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.getQualityFromName
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.util.* import java.util.*
import javax.crypto.Cipher import javax.crypto.Cipher
@ -300,6 +297,25 @@ class GogoanimeProvider : MainAPI() {
source: GogoSource, source: GogoSource,
sourceCallback: (ExtractorLink) -> Unit sourceCallback: (ExtractorLink) -> Unit
) { ) {
if (source.file.contains("m3u8")) {
M3u8Helper().m3u8Generation(
M3u8Helper.M3u8Stream(
source.file,
headers = mapOf("Referer" to "https://gogoplay.io")
), true
)
.map { stream ->
val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p"
sourceCallback( ExtractorLink(
name,
"$name $qualityString",
stream.streamUrl,
"https://gogoplay.io",
getQualityFromName(stream.quality.toString()),
true
))
}
} else if (source.file.contains("vidstreaming")) {
sourceCallback.invoke( sourceCallback.invoke(
ExtractorLink( ExtractorLink(
this.name, this.name,
@ -311,6 +327,7 @@ class GogoanimeProvider : MainAPI() {
) )
) )
} }
}
sources.source?.forEach { sources.source?.forEach {
invokeGogoSource(it, callback) invokeGogoSource(it, callback)

View file

@ -10,10 +10,6 @@ import com.lagradost.cloudstream3.utils.getQualityFromName
class ZplayerV2 : GenericM3U8() {
override val name = "Zplayer V2"
override val mainUrl = "https://v2.zplayer.live"
}
open class GenericM3U8 : ExtractorApi() { open class GenericM3U8 : ExtractorApi() {
override val name = "Upstream" override val name = "Upstream"

View file

@ -91,7 +91,7 @@ open class StreamSB : ExtractorApi() {
val master = "$mainUrl/sources41/566d337678566f743674494a7c7c${bytesToHex}7c7c346b6767586d6934774855537c7c73747265616d7362/6565417268755339773461447c7c346133383438333436313335376136323337373433383634376337633465366534393338373136643732373736343735373237613763376334363733353737303533366236333463353333363534366137633763373337343732363536313664373336327c7c6b586c3163614468645a47617c7c73747265616d7362" val master = "$mainUrl/sources41/566d337678566f743674494a7c7c${bytesToHex}7c7c346b6767586d6934774855537c7c73747265616d7362/6565417268755339773461447c7c346133383438333436313335376136323337373433383634376337633465366534393338373136643732373736343735373237613763376334363733353737303533366236333463353333363534366137633763373337343732363536313664373336327c7c6b586c3163614468645a47617c7c73747265616d7362"
val headers = mapOf( val headers = mapOf(
"Host" to url.substringAfter("https://").substringBefore("/"), "Host" to url.substringAfter("https://").substringBefore("/"),
"User-Agent" to USER_AGENT, "User-Agent" to "Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0",
"Accept" to "application/json, text/plain, */*", "Accept" to "application/json, text/plain, */*",
"Accept-Language" to "en-US,en;q=0.5", "Accept-Language" to "en-US,en;q=0.5",
"Referer" to url, "Referer" to url,
@ -109,7 +109,9 @@ open class StreamSB : ExtractorApi() {
allowRedirects = false allowRedirects = false
).text ).text
val mapped = urltext.let { parseJson<Main>(it) } val mapped = urltext.let { parseJson<Main>(it) }
if (urltext.contains("m3u8")) return M3u8Helper().m3u8Generation( val testurl = app.get(mapped.streamData.file, headers = headers).text
val urlmain = mapped.streamData.file.substringBefore("/hls/")
if (urltext.contains("m3u8") && testurl.contains("EXTM3U")) return M3u8Helper().m3u8Generation(
M3u8Helper.M3u8Stream( M3u8Helper.M3u8Stream(
mapped.streamData.file, mapped.streamData.file,
headers = mapOf( headers = mapOf(
@ -127,11 +129,12 @@ open class StreamSB : ExtractorApi() {
), true ), true
) )
.map { stream -> .map { stream ->
val cleanstreamurl = stream.streamUrl.replace(Regex("https://.*/hls/"), "$urlmain/hls/")
val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p" val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p"
ExtractorLink( ExtractorLink(
name, name,
"$name $qualityString", "$name $qualityString",
stream.streamUrl, cleanstreamurl,
url, url,
getQualityFromName(stream.quality.toString()), getQualityFromName(stream.quality.toString()),
true true

View file

@ -0,0 +1,59 @@
package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.apmap
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.*
class Zplayer: ZplayerV2() {
override val name: String = "Zplayer"
override val mainUrl: String = "https://zplayer.live"
}
class Upstream: ZplayerV2() {
override val name: String = "Upstream" //Here 'cause works
override val mainUrl: String = "https://upstream.to"
}
open class ZplayerV2 : ExtractorApi() {
override val name = "Zplayer V2"
override val mainUrl = "https://v2.zplayer.live"
override val requiresReferer = false
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
val doc = app.get(url).document
val sources = mutableListOf<ExtractorLink>()
doc.select("script").map { script ->
if (script.data().contains("eval(function(p,a,c,k,e,d)")) {
val testdata = getAndUnpack(script.data())
val m3u8regex = Regex("((https:|http:)\\/\\/.*\\.m3u8)")
m3u8regex.findAll(testdata).map {
it.value
}.toList().apmap { urlm3u8 ->
if (urlm3u8.contains("m3u8")) {
val testurl = app.get(urlm3u8, headers = mapOf("Referer" to url)).text
if (testurl.contains("EXTM3U")) {
M3u8Helper().m3u8Generation(
M3u8Helper.M3u8Stream(
urlm3u8,
headers = mapOf("Referer" to url)
), true
)
.map { stream ->
val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p"
sources.add( ExtractorLink(
name,
"$name $qualityString",
stream.streamUrl,
url,
getQualityFromName(stream.quality.toString()),
true
))
}
}
}
}
}
}
return sources
}
}

View file

@ -20,18 +20,19 @@ class BflixProvider(providerUrl: String, providerName: String) : MainAPI() {
override suspend fun getMainPage(): HomePageResponse { override suspend fun getMainPage(): HomePageResponse {
val items = ArrayList<HomePageList>() val items = ArrayList<HomePageList>()
val urls = listOf( val soup = app.get("$mainUrl/home").document
Pair("$mainUrl/home", "Movies"), val testa = listOf(
Pair("$mainUrl/tv-series", "Series"), Pair("Movies", "div.tab-content[data-name=movies] div.filmlist div.item"),
Pair("$mainUrl/top-imdb", "Top"), Pair("Shows", "div.tab-content[data-name=shows] div.filmlist div.item"),
Pair("Trending", "div.tab-content[data-name=trending] div.filmlist div.item"),
Pair("Latest Movies", "div.container section.bl:contains(Latest Movies) div.filmlist div.item"),
Pair("Latest TV-Series", "div.container section.bl:contains(Latest TV-Series) div.filmlist div.item"),
) )
for (i in urls) { for ((name, element) in testa) try {
try { val test = soup.select(element).map {
val response = app.get(i.first)
val soup = Jsoup.parse(response.text)
val home = soup.select(".filmlist div.item").map {
val title = it.selectFirst("h3 a").text() val title = it.selectFirst("h3 a").text()
val link = fixUrl(it.selectFirst("a").attr("href")) val link = fixUrl(it.selectFirst("a").attr("href"))
// val quality = it.selectFirst("div.quality").text()
TvSeriesSearchResponse( TvSeriesSearchResponse(
title, title,
link, link,
@ -42,12 +43,10 @@ class BflixProvider(providerUrl: String, providerName: String) : MainAPI() {
null, null,
) )
} }
items.add(HomePageList(name, test))
items.add(HomePageList(i.second, home))
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
}
if (items.size <= 0) throw ErrorLoadingException() if (items.size <= 0) throw ErrorLoadingException()
return HomePageResponse(items) return HomePageResponse(items)
@ -248,7 +247,15 @@ class BflixProvider(providerUrl: String, providerName: String) : MainAPI() {
year = null year = null
) )
} }
val rating = soup.selectFirst(".info span.imdb").text().toFloatOrNull()
?.times(1000)?.toInt()
val durationdoc = soup.selectFirst("div.info div.meta").toString()
val durationregex = Regex("((\\d+) min)")
val yearegex = Regex("<span>(\\d+)<\\/span>")
val duration = if (durationdoc.contains("na min")) null
else durationregex.find(durationdoc)?.destructured?.component1()?.replace(" min","")?.toIntOrNull()
val year = if (mainUrl == "https://bflix.ru") { yearegex.find(durationdoc)?.destructured?.component1()
?.replace(Regex("<span>|<\\/span>"),"") } else null
return when (tvType) { return when (tvType) {
TvType.TvSeries -> { TvType.TvSeries -> {
TvSeriesLoadResponse( TvSeriesLoadResponse(
@ -258,13 +265,14 @@ class BflixProvider(providerUrl: String, providerName: String) : MainAPI() {
tvType, tvType,
episodes!!, episodes!!,
poster, poster,
null, year?.toIntOrNull(),
description, description,
null, null,
null, null,
null, rating,
tags, tags,
recommendations = recommendations, recommendations = recommendations,
duration = duration,
) )
} }
TvType.Movie -> { TvType.Movie -> {
@ -275,12 +283,13 @@ class BflixProvider(providerUrl: String, providerName: String) : MainAPI() {
tvType, tvType,
url, url,
poster, poster,
null, year?.toIntOrNull(),
description, description,
null, null,
null, rating,
tags, tags,
recommendations = recommendations recommendations = recommendations,
duration = duration
) )
} }
else -> null else -> null

View file

@ -1,9 +1,9 @@
package com.lagradost.cloudstream3.movieproviders package com.lagradost.cloudstream3.movieproviders
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.Evoload import com.lagradost.cloudstream3.extractors.Cinestart
import com.lagradost.cloudstream3.extractors.FEmbed import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.extractors.StreamTape
import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.*
import java.util.* import java.util.*
@ -30,9 +30,9 @@ class CinecalidadProvider:MainAPI() {
Pair("$mainUrl/genero-de-la-pelicula/peliculas-en-calidad-4k/", "4K UHD"), Pair("$mainUrl/genero-de-la-pelicula/peliculas-en-calidad-4k/", "4K UHD"),
) )
for (i in urls) { for ((url, name) in urls) {
try { try {
val soup = app.get(i.first).document val soup = app.get(url).document
val home = soup.select(".item.movies").map { val home = soup.select(".item.movies").map {
val title = it.selectFirst("div.in_title").text() val title = it.selectFirst("div.in_title").text()
val link = it.selectFirst("a").attr("href") val link = it.selectFirst("a").attr("href")
@ -47,9 +47,9 @@ class CinecalidadProvider:MainAPI() {
) )
} }
items.add(HomePageList(i.second, home)) items.add(HomePageList(name, home))
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() logError(e)
} }
} }
@ -99,15 +99,20 @@ class CinecalidadProvider:MainAPI() {
val poster: String? = soup.selectFirst(".alignnone").attr("data-src") val poster: String? = soup.selectFirst(".alignnone").attr("data-src")
val episodes = soup.select("div.se-c div.se-a ul.episodios li").map { li -> val episodes = soup.select("div.se-c div.se-a ul.episodios li").map { li ->
val href = li.selectFirst("a").attr("href") val href = li.selectFirst("a").attr("href")
val epThumb = li.selectFirst("div.imagen img").attr("data-src") ?: li.selectFirst("div.imagen img").attr("src") val epThumb = li.selectFirst("img.lazy").attr("data-src")
val name = li.selectFirst(".episodiotitle a").text() val name = li.selectFirst(".episodiotitle a").text()
val seasonid = li.selectFirst(".numerando").text().replace(Regex("(S|E)"),"").let { str ->
str.split("-").mapNotNull { subStr -> subStr.toIntOrNull() }
}
val isValid = seasonid.size == 2
val episode = if (isValid) seasonid.getOrNull(1) else null
val season = if (isValid) seasonid.getOrNull(0) else null
TvSeriesEpisode( TvSeriesEpisode(
name, name,
null, season,
null, episode,
href, href,
epThumb if (epThumb.contains("svg")) null else epThumb
) )
} }
return when (val tvType = if (url.contains("/ver-pelicula/")) TvType.Movie else TvType.TvSeries) { return when (val tvType = if (url.contains("/ver-pelicula/")) TvType.Movie else TvType.TvSeries) {
@ -145,27 +150,108 @@ class CinecalidadProvider:MainAPI() {
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
app.get(data).document.select(".dooplay_player_option").apmap {
val datam = app.get(data)
val doc = datam.document
val datatext = datam.text
doc.select(".dooplay_player_option").apmap {
val url = it.attr("data-option") val url = it.attr("data-option")
if (url.startsWith("https://evoload.io")) { if (url.startsWith("https://cinestart.net")) {
val extractor = Evoload() val extractor = Cinestart()
extractor.getSafeUrl(url)?.forEach { link -> extractor.getSafeUrl(url)?.forEach { link ->
callback.invoke(link) callback.invoke(link)
} }
} else { } else {
loadExtractor(url, mainUrl, callback) loadExtractor(url, mainUrl, callback)
} }
if (url.startsWith("https://cinecalidad.lol")) {
val cineurlregex = Regex("(https:\\/\\/cinecalidad\\.lol\\/play\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
cineurlregex.findAll(url).map {
it.value.replace("/play/","/play/r.php")
}.toList().apmap {
app.get(it,
headers = mapOf(
"Host" to "cinecalidad.lol",
"User-Agent" to USER_AGENT,
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language" to "en-US,en;q=0.5",
"DNT" to "1",
"Connection" to "keep-alive",
"Referer" to data,
"Upgrade-Insecure-Requests" to "1",
"Sec-Fetch-Dest" to "iframe",
"Sec-Fetch-Mode" to "navigate",
"Sec-Fetch-Site" to "same-origin",
"Sec-Fetch-User" to "?1",
),
allowRedirects = false).response.headers.values("location").apmap { extractedurl ->
if (extractedurl.contains("cinestart")) {
loadExtractor(extractedurl, mainUrl, callback)
} }
if ((app.get(data).text.contains("en castellano"))) app.get("$data?ref=es").document.select(".dooplay_player_option").apmap { }
}
}
}
if (datatext.contains("en castellano")) app.get("$data?ref=es").document.select(".dooplay_player_option").apmap {
val url = it.attr("data-option") val url = it.attr("data-option")
if (url.startsWith("https://evoload.io")) { if (url.startsWith("https://cinestart.net")) {
val extractor = Evoload() val extractor = Cinestart()
extractor.getSafeUrl(url)?.forEach { link -> extractor.getSafeUrl(url)?.forEach { link ->
callback.invoke(link) callback.invoke(link)
} }
} else { } else {
loadExtractor(url, mainUrl, callback) loadExtractor(url, mainUrl, callback)
} }
if (url.startsWith("https://cinecalidad.lol")) {
val cineurlregex = Regex("(https:\\/\\/cinecalidad\\.lol\\/play\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
cineurlregex.findAll(url).map {
it.value.replace("/play/","/play/r.php")
}.toList().apmap {
app.get(it,
headers = mapOf(
"Host" to "cinecalidad.lol",
"User-Agent" to USER_AGENT,
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language" to "en-US,en;q=0.5",
"DNT" to "1",
"Connection" to "keep-alive",
"Referer" to data,
"Upgrade-Insecure-Requests" to "1",
"Sec-Fetch-Dest" to "iframe",
"Sec-Fetch-Mode" to "navigate",
"Sec-Fetch-Site" to "same-origin",
"Sec-Fetch-User" to "?1",
),
allowRedirects = false).response.headers.values("location").apmap { extractedurl ->
if (extractedurl.contains("cinestart")) {
loadExtractor(extractedurl, mainUrl, callback)
}
}
}
}
}
if (datatext.contains("Subtítulo LAT") || datatext.contains("Forzados LAT")) {
doc.select("#panel_descarga.pane a").apmap {
val link = if (data.contains("serie") || data.contains("episodio")) "${data}${it.attr("href")}"
else it.attr("href")
val docsub = app.get(link)
val linksub = docsub.document
val validsub = docsub.text
if (validsub.contains("Subtítulo") || validsub.contains("Forzados")) {
val langregex = Regex("(Subtítulo.*\$|Forzados.*\$)")
val langdoc = linksub.selectFirst("div.titulo h3").text()
val reallang = langregex.find(langdoc)?.destructured?.component1()
linksub.select("a.link").apmap {
val sublink = if (data.contains("serie") || data.contains("episodio")) "${data}${it.attr("href")}"
else it.attr("href")
subtitleCallback(
SubtitleFile(reallang!!, sublink)
)
}
}
}
} }
return true return true
} }

View file

@ -1,10 +1,11 @@
package com.lagradost.cloudstream3.movieproviders package com.lagradost.cloudstream3.movieproviders
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.utils.AppUtils.parseJson 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.*
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import java.util.* import java.util.*
class CuevanaProvider:MainAPI() { class CuevanaProvider:MainAPI() {
@ -24,9 +25,27 @@ class CuevanaProvider:MainAPI() {
Pair(mainUrl, "Recientemente actualizadas"), Pair(mainUrl, "Recientemente actualizadas"),
Pair("$mainUrl/estrenos/", "Estrenos"), Pair("$mainUrl/estrenos/", "Estrenos"),
) )
for (i in urls) { items.add(
HomePageList(
"Series",
app.get("$mainUrl/serie", timeout = 120).document.select("section.home-series li").map {
val title = it.selectFirst("h2.Title").text()
val poster = it.selectFirst("img.lazy").attr("data-src")
val url = it.selectFirst("a").attr("href")
TvSeriesSearchResponse(
title,
url,
this.name,
TvType.Anime,
poster,
null,
null,
)
})
)
for ((url, name) in urls) {
try { try {
val soup = app.get(i.first).document val soup = app.get(url).document
val home = soup.select("section li.xxx.TPostMv").map { val home = soup.select("section li.xxx.TPostMv").map {
val title = it.selectFirst("h2.Title").text() val title = it.selectFirst("h2.Title").text()
val link = it.selectFirst("a").attr("href") val link = it.selectFirst("a").attr("href")
@ -41,7 +60,7 @@ class CuevanaProvider:MainAPI() {
) )
} }
items.add(HomePageList(i.second, home)) items.add(HomePageList(name, home))
} catch (e: Exception) { } catch (e: Exception) {
logError(e) logError(e)
} }
@ -80,7 +99,7 @@ class CuevanaProvider:MainAPI() {
null null
) )
} }
}.toList() }
} }
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
@ -88,24 +107,47 @@ class CuevanaProvider:MainAPI() {
val description = soup.selectFirst(".Description p")?.text()?.trim() val description = soup.selectFirst(".Description p")?.text()?.trim()
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("(\\d+)<\\/span>") val yearRegex = Regex("<span>(\\d+)</span>")
val year = yearRegex.findAll(year1).map { val yearf = yearRegex.find(year1)?.destructured?.component1()?.replace(Regex("<span>|</span>"),"")
it.value.replace("</span>","") val year = if (yearf.isNullOrBlank()) null else yearf.toIntOrNull()
}.toList().first().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 name = li.selectFirst("h2.Title").text() val seasonid = li.selectFirst("span.Year").text().let { str ->
str.split("x").mapNotNull { subStr -> subStr.toIntOrNull() }
}
val isValid = seasonid.size == 2
val episode = if (isValid) seasonid.getOrNull(1) else null
val season = if (isValid) seasonid.getOrNull(0) else null
TvSeriesEpisode( TvSeriesEpisode(
name,
null,
null, null,
season,
episode,
href, href,
fixUrl(epThumb) fixUrl(epThumb)
) )
} }
return when (val tvType = if (episodes.isEmpty()) TvType.Movie else TvType.TvSeries) { val tags = soup.select("ul.InfoList li.AAIco-adjust:contains(Genero) a").map { it.text() }
val tvType = if (episodes.isEmpty()) TvType.Movie else TvType.TvSeries
val recelement = if (tvType == TvType.TvSeries) "main section div.series_listado.series div.xxx"
else "main section ul.MovieList li"
val recommendations =
soup.select(recelement).mapNotNull { element ->
val recTitle = element.select("h2.Title").text() ?: return@mapNotNull null
val image = element.select("figure img")?.attr("data-src")
val recUrl = fixUrl(element.select("a").attr("href"))
MovieSearchResponse(
recTitle,
recUrl,
this.name,
TvType.Movie,
image,
year = null
)
}
return when (tvType) {
TvType.TvSeries -> { TvType.TvSeries -> {
TvSeriesLoadResponse( TvSeriesLoadResponse(
title, title,
@ -116,6 +158,8 @@ class CuevanaProvider:MainAPI() {
poster, poster,
year, year,
description, description,
tags = tags,
recommendations = recommendations
) )
} }
TvType.Movie -> { TvType.Movie -> {
@ -128,6 +172,8 @@ class CuevanaProvider:MainAPI() {
poster, poster,
year, year,
description, description,
tags = tags,
recommendations = recommendations
) )
} }
else -> null else -> null
@ -199,7 +245,7 @@ class CuevanaProvider:MainAPI() {
}.toList().apmap { gotolink -> }.toList().apmap { gotolink ->
app.post("https://api.cuevana3.io/ir/redirect_ddh.php", allowRedirects = false, app.post("https://api.cuevana3.io/ir/redirect_ddh.php", allowRedirects = false,
headers = mapOf("Host" to "api.cuevana3.io", headers = mapOf("Host" to "api.cuevana3.io",
"User-Agent" to "Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0", "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",
"Content-Type" to "application/x-www-form-urlencoded", "Content-Type" to "application/x-www-form-urlencoded",

View file

@ -26,9 +26,9 @@ class EntrepeliculasyseriesProvider:MainAPI() {
Pair("$mainUrl/anime/", "Animes"), Pair("$mainUrl/anime/", "Animes"),
) )
for (i in urls) { for ((url, name) in urls) {
try { try {
val soup = app.get(i.first).document val soup = app.get(url).document
val home = soup.select("ul.list-movie li").map { val home = soup.select("ul.list-movie li").map {
val title = it.selectFirst("a.link-title h2").text() val title = it.selectFirst("a.link-title h2").text()
val link = it.selectFirst("a").attr("href") val link = it.selectFirst("a").attr("href")
@ -43,7 +43,7 @@ class EntrepeliculasyseriesProvider:MainAPI() {
) )
} }
items.add(HomePageList(i.second, home)) items.add(HomePageList(name, home))
} catch (e: Exception) { } catch (e: Exception) {
logError(e) logError(e)
} }
@ -96,13 +96,18 @@ class EntrepeliculasyseriesProvider:MainAPI() {
val episodes = soup.select(".TPostMv article").map { li -> val episodes = soup.select(".TPostMv article").map { li ->
val href = (li.select("a") ?: li.select(".C a") ?: li.select("article a")).attr("href") val href = (li.select("a") ?: li.select(".C a") ?: li.select("article a")).attr("href")
val epThumb = li.selectFirst("div.Image img").attr("data-src") val epThumb = li.selectFirst("div.Image img").attr("data-src")
val name = li.selectFirst("h2.Title").text() val seasonid = li.selectFirst("span.Year").text().let { str ->
str.split("x").mapNotNull { subStr -> subStr.toIntOrNull() }
}
val isValid = seasonid.size == 2
val episode = if (isValid) seasonid.getOrNull(1) else null
val season = if (isValid) seasonid.getOrNull(0) else null
TvSeriesEpisode( TvSeriesEpisode(
name,
null,
null, null,
season,
episode,
href, href,
epThumb fixUrl(epThumb)
) )
} }
return when (val tvType = if (url.contains("/pelicula/")) TvType.Movie else TvType.TvSeries) { return when (val tvType = if (url.contains("/pelicula/")) TvType.Movie else TvType.TvSeries) {

View file

@ -3,7 +3,8 @@ 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.extractorApis
import java.util.ArrayList import com.lagradost.cloudstream3.utils.loadExtractor
import kotlin.collections.ArrayList
class PeliSmartProvider: MainAPI() { class PeliSmartProvider: MainAPI() {
override val mainUrl = "https://pelismart.com" override val mainUrl = "https://pelismart.com"
@ -26,9 +27,9 @@ class PeliSmartProvider: MainAPI() {
Pair("$mainUrl/documentales/", "Documentales"), Pair("$mainUrl/documentales/", "Documentales"),
) )
for (i in urls) { for ((url, name) in urls) {
try { try {
val soup = app.get(i.first).document val soup = app.get(url).document
val home = soup.select(".description-off").map { val home = soup.select(".description-off").map {
val title = it.selectFirst("h3.entry-title a").text() val title = it.selectFirst("h3.entry-title a").text()
val link = it.selectFirst("a").attr("href") val link = it.selectFirst("a").attr("href")
@ -43,7 +44,7 @@ class PeliSmartProvider: MainAPI() {
) )
} }
items.add(HomePageList(i.second, home)) items.add(HomePageList(name, home))
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
@ -96,10 +97,18 @@ class PeliSmartProvider: MainAPI() {
val href = li.selectFirst("a").attr("href") val href = li.selectFirst("a").attr("href")
val preregex = Regex("(\\d+)\\. ") val preregex = Regex("(\\d+)\\. ")
val name = li.selectFirst("a").text().replace(preregex,"") val name = li.selectFirst("a").text().replace(preregex,"")
val regextest = Regex("(temporada-(\\d+)-capitulo-(\\d+)|temporada-(\\d+)-episodio-(\\d+))")
val test = regextest.find(href)?.destructured?.component1()?.replace(Regex("(temporada-|-)"),"")
val seasonid = test.let { str ->
str?.split("episodio","capitulo")?.mapNotNull { subStr -> subStr.toIntOrNull() }
}
val isValid = seasonid?.size == 2
val episode = if (isValid) seasonid?.getOrNull(1) else null
val season = if (isValid) seasonid?.getOrNull(0) else null
TvSeriesEpisode( TvSeriesEpisode(
name, name,
null, season,
null, episode,
href, href,
) )
} }
@ -138,23 +147,14 @@ class PeliSmartProvider: MainAPI() {
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
val soup = app.get(data).text val soup = app.get(data).text
val linkRegex = Regex("""(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&\/\/=]*))""") fetchUrls(soup).apmap {
val link1 = linkRegex.findAll(soup).map { val urlc = it.replace("https://pelismart.com/p/1.php?v=","https://evoload.io/e/")
it.value.replace("https://pelismart.com/p/1.php?v=","https://evoload.io/e/")
.replace("https://pelismart.com/p/2.php?v=","https://streamtape.com/e/") .replace("https://pelismart.com/p/2.php?v=","https://streamtape.com/e/")
.replace("https://pelismart.com/p/4.php?v=","https://dood.to/e/") .replace("https://pelismart.com/p/4.php?v=","https://dood.to/e/")
.replace("https://pelismarthd.com/p/1.php?v=","https://evoload.io/e/") .replace("https://pelismarthd.com/p/1.php?v=","https://evoload.io/e/")
.replace("https://pelismarthd.com/p/2.php?v=","https://streamtape.com/e/") .replace("https://pelismarthd.com/p/2.php?v=","https://streamtape.com/e/")
.replace("https://pelismarthd.com/p/4.php?v=","https://dood.to/e/") .replace("https://pelismarthd.com/p/4.php?v=","https://dood.to/e/")
}.toList() loadExtractor(urlc, data, callback)
for (link in link1) {
for (extractor in extractorApis) {
if (link.startsWith(extractor.mainUrl)) {
extractor.getSafeUrl(link, data)?.forEach {
callback(it)
}
}
}
} }
return true return true
} }

View file

@ -2,6 +2,7 @@ package com.lagradost.cloudstream3.movieproviders
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.*
import org.jsoup.nodes.Element
import java.util.* import java.util.*
class PelisplusHDProvider:MainAPI() { class PelisplusHDProvider:MainAPI() {
@ -14,41 +15,51 @@ class PelisplusHDProvider:MainAPI() {
override val supportedTypes = setOf( override val supportedTypes = setOf(
TvType.Movie, TvType.Movie,
TvType.TvSeries, TvType.TvSeries,
TvType.Anime,
) )
override suspend fun getMainPage(): HomePageResponse { override suspend fun getMainPage(): HomePageResponse {
val items = ArrayList<HomePageList>() val items = ArrayList<HomePageList>()
val urls = listOf( val document = app.get(mainUrl).document
Pair("$mainUrl/peliculas", "Peliculas"), val map = mapOf(
Pair("$mainUrl/series", "Series"), "Películas" to "#default-tab-1",
Pair("$mainUrl/generos/dorama", "Doramas"), "Series" to "#default-tab-2",
Pair("$mainUrl/animes", "Animes"), "Anime" to "#default-tab-3",
"Doramas" to "#default-tab-4",
) )
for (i in urls) { map.forEach {
try { items.add(HomePageList(
val soup = app.get(i.first).document it.key,
val home = soup.select("a.Posters-link").map { document.select(it.value).select("a.Posters-link").map { element ->
val title = it.selectFirst(".listing-content p").text() element.toSearchResult()
val link = it.selectFirst("a").attr("href") }
))
}
return HomePageResponse(items)
}
private fun Element.toSearchResult(): SearchResponse {
val title = this.select(".listing-content p").text()
val href = this.select("a").attr("href")
val posterUrl = this.select(".Posters-img").attr("src")
val isMovie = href.contains("/pelicula/")
return if (isMovie) {
MovieSearchResponse(
title,
href,
name,
TvType.Movie,
posterUrl,
null
)
} else {
TvSeriesSearchResponse( TvSeriesSearchResponse(
title, title,
link, href,
this.name, name,
if (link.contains("/pelicula/")) TvType.Movie else TvType.TvSeries, TvType.Movie,
it.selectFirst(".Posters-img").attr("src"), posterUrl,
null,
null, null,
null
) )
} }
items.add(HomePageList(i.second, home))
} catch (e: Exception) {
e.printStackTrace()
}
}
if (items.size <= 0) throw ErrorLoadingException()
return HomePageResponse(items)
} }
override suspend fun search(query: String): List<SearchResponse> { override suspend fun search(query: String): List<SearchResponse> {
@ -93,10 +104,17 @@ class PelisplusHDProvider:MainAPI() {
val episodes = soup.select("div.tab-pane .btn").map { li -> val episodes = soup.select("div.tab-pane .btn").map { li ->
val href = li.selectFirst("a").attr("href") val href = li.selectFirst("a").attr("href")
val name = li.selectFirst(".btn-primary.btn-block").text() val name = li.selectFirst(".btn-primary.btn-block").text()
val seasonid = href.replace("/capitulo/","-")
.replace(Regex("$mainUrl/.*/.*/temporada/"),"").let { str ->
str.split("-").mapNotNull { subStr -> subStr.toIntOrNull() }
}
val isValid = seasonid.size == 2
val episode = if (isValid) seasonid.getOrNull(1) else null
val season = if (isValid) seasonid.getOrNull(0) else null
TvSeriesEpisode( TvSeriesEpisode(
name, name,
null, season,
null, episode,
href, href,
) )
} }
@ -117,7 +135,7 @@ class PelisplusHDProvider:MainAPI() {
poster, poster,
year, year,
description, description,
ShowStatus.Ongoing, null,
null, null,
null, null,
tags, tags,
@ -147,20 +165,9 @@ class PelisplusHDProvider:MainAPI() {
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
val soup = app.get(data).document app.get(data).document.select("div.player > script").map { script ->
val selector = soup.selectFirst("div.player > script").toString() fetchUrls(script.data().replace("https://pelisplushd.net/fembed.php?url=","https://www.fembed.com/v/")).apmap {
val linkRegex = Regex("""(https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&\/\/=]*))""") loadExtractor(it, data, callback)
val links = linkRegex.findAll(selector).map {
it.value.replace("https://pelisplushd.net/fembed.php?url=","https://www.fembed.com/v/")
.replace("https://pelistop.co/","https://watchsb.com/")
}.toList()
for (link in links) {
for (extractor in extractorApis) {
if (link.startsWith(extractor.mainUrl)) {
extractor.getSafeUrl(link, data)?.forEach {
callback(it)
}
}
} }
} }
return true return true

View file

@ -136,9 +136,12 @@ val extractorApis: Array<ExtractorApi> = arrayOf(
AsianLoad(), AsianLoad(),
ZplayerV2(), // GenericM3U8(),
GenericM3U8(),
Jawcloud(), Jawcloud(),
Zplayer(),
ZplayerV2(),
Upstream(),
// StreamSB.kt works // StreamSB.kt works
// SBPlay(), // SBPlay(),