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,11 +1,12 @@
package com.lagradost.cloudstream3.animeproviders
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import java.util.*
class AnimeflvnetProvider : MainAPI() {
class AnimeflvnetProvider:MainAPI() {
companion object {
fun getType(t: String): TvType {
return if (t.contains("OVA") || t.contains("Especial")) TvType.OVA
@ -13,9 +14,8 @@ class AnimeflvnetProvider : MainAPI() {
else TvType.Anime
}
}
override val mainUrl = "https://m.animeflv.net"
override val name = "AnimeFLV"
override val mainUrl = "https://www3.animeflv.net"
override val name = "Animeflv.net"
override val lang = "es"
override val hasMainPage = true
override val hasChromecastSupport = true
@ -28,21 +28,24 @@ class AnimeflvnetProvider : MainAPI() {
override suspend fun getMainPage(): HomePageResponse {
val urls = listOf(
Pair("$mainUrl/browse?type[]=movie&order=updated", "Peliculas actualizadas"),
Pair("$mainUrl/browse?order=updated", "Animes recientemente actualizados"),
Pair("$mainUrl/browse?status[]=2&order=default", "Animes finalizados"),
Pair("$mainUrl/browse?type[]=movie&order=updated", "Películas"),
Pair("$mainUrl/browse?status[]=2&order=default", "Animes"),
Pair("$mainUrl/browse?status[]=1&order=rating", "En emision"),
)
val items = ArrayList<HomePageList>()
for (i in urls) {
try {
val doc = app.get(i.first).document
val home = doc.select("ul.List-Animes li.Anime").map {
val title = it.selectFirst("h2.title").text()
val poster = it.selectFirst(".Image img").attr("src")
items.add(
HomePageList(
"Últimos episodios",
app.get(mainUrl).document.select("main.Main ul.ListEpisodios li").map {
val title = it.selectFirst("strong.Title").text()
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(
title,
fixUrl(it.selectFirst("a").attr("href")),
fixUrl(url),
this.name,
TvType.Anime,
fixUrl(poster),
@ -50,10 +53,29 @@ class AnimeflvnetProvider : MainAPI() {
if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(
DubStatus.Dubbed
) 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) {
e.printStackTrace()
}
@ -62,80 +84,94 @@ class AnimeflvnetProvider : MainAPI() {
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> {
val url = "${mainUrl}/browse?q=${query}"
val doc = app.get(url).document
return doc.select("ul.List-Animes li.Anime").map {
val title = it.selectFirst("h2.title").text()
val href = fixUrl(it.selectFirst("a").attr("href"))
val image = it.selectFirst(".Image img").attr("src")
AnimeSearchResponse(
title,
href,
this.name,
TvType.Anime,
fixUrl(image),
null,
if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(
DubStatus.Subbed
),
)
val response = app.post("https://www3.animeflv.net/api/animes/search",
data = mapOf(Pair("value",query))
).text
val json = parseJson<List<SearchObject>>(response)
return json.map { searchr ->
val title = searchr.title
val href = "$mainUrl/anime/${searchr.slug}"
val image = "$mainUrl/uploads/animes/covers/${searchr.id}.jpg"
AnimeSearchResponse(
title,
href,
this.name,
TvType.Anime,
fixUrl(image),
null,
if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(DubStatus.Subbed),
)
}
}
override suspend fun load(url: String): LoadResponse {
val doc = app.get(url).document
val episodes = ArrayList<AnimeEpisode>()
val title = doc.selectFirst("h1.Title").text()
val description = doc.selectFirst(".Anime > header:nth-child(1) > p:nth-child(3)").text()
.replace("Sinopsis: ", "")
val poster = doc.selectFirst(".Image img").attr("src")
val episodes = doc.select("li.Episode").map { li ->
val href = fixUrl(li.selectFirst("a").attr("href"))
AnimeEpisode(
fixUrl(href), "Episodio" + li.selectFirst("a").text().replace(title, "")
)
val poster = doc.selectFirst("div.AnimeCover div.Image figure img").attr("src")
val description = doc.selectFirst("div.Description p").text()
val type = doc.selectFirst("span.Type").text()
val status = when (doc.selectFirst("p.AnmStts span")?.text()) {
"En emision" -> ShowStatus.Ongoing
"Finalizado" -> ShowStatus.Completed
else -> null
}
val type = doc.selectFirst("span.Type.A").text()
val genre = doc.select("a.Tag")
val genre = doc.select("nav.Nvgnrs a")
.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
else -> null
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)) {
posterUrl = fixUrl(poster)
addEpisodes(DubStatus.Subbed, episodes)
addEpisodes(DubStatus.Subbed, episodes.reversed())
showStatus = status
plot = description
tags = genre
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
//There might be a better way to do this, but this one works
val html = app.get(data).text
val linkRegex = Regex("""(https:.*?\.html.*)""")
val videos = linkRegex.findAll(html).map {
it.value.replace("\\/", "/")
}.toList()
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)
app.get(data).document.select("script").apmap { script ->
if (script.data().contains("var videos = {") || script.data().contains("var anime_id =") || script.data().contains("server")) {
val videos = script.data().replace("\\/", "/")
fetchUrls(videos).map {
it.replace("https://embedsb.com/e/","https://watchsb.com/e/")
.replace("https://ok.ru","http://ok.ru")
}.apmap {
loadExtractor(it, data, callback)
}
}
}
return true
}
}
}

View File

@ -2,10 +2,7 @@ package com.lagradost.cloudstream3.animeproviders
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.AppUtils
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.getQualityFromName
import com.lagradost.cloudstream3.utils.loadExtractor
import com.lagradost.cloudstream3.utils.*
import org.jsoup.Jsoup
import java.util.*
import javax.crypto.Cipher
@ -300,16 +297,36 @@ class GogoanimeProvider : MainAPI() {
source: GogoSource,
sourceCallback: (ExtractorLink) -> Unit
) {
sourceCallback.invoke(
ExtractorLink(
this.name,
"${this.name} ${source.label?.replace("0 P", "0p") ?: ""}",
if (source.file.contains("m3u8")) {
M3u8Helper().m3u8Generation(
M3u8Helper.M3u8Stream(
source.file,
"https://gogoplay.io",
getQualityFromName(source.label ?: ""),
isM3u8 = source.type == "hls"
)
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(
ExtractorLink(
this.name,
"${this.name} ${source.label?.replace("0 P", "0p") ?: ""}",
source.file,
"https://gogoplay.io",
getQualityFromName(source.label ?: ""),
isM3u8 = source.type == "hls"
)
)
}
}
sources.source?.forEach {

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() {
override val name = "Upstream"

View File

@ -45,7 +45,7 @@ class StreamSB9 : StreamSB() {
}
// This is a modified version of https://github.com/jmir1/aniyomi-extensions/blob/master/src/en/genoanime/src/eu/kanade/tachiyomi/animeextension/en/genoanime/extractors/StreamSBExtractor.kt
// The following code is under the Apache License 2.0 https://github.com/jmir1/aniyomi-extensions/blob/master/LICENSE
// The following code is under the Apache License 2.0 https://github.com/jmir1/aniyomi-extensions/blob/master/LICENSE
open class StreamSB : ExtractorApi() {
override val name = "StreamSB"
override val mainUrl = "https://watchsb.com"
@ -91,7 +91,7 @@ open class StreamSB : ExtractorApi() {
val master = "$mainUrl/sources41/566d337678566f743674494a7c7c${bytesToHex}7c7c346b6767586d6934774855537c7c73747265616d7362/6565417268755339773461447c7c346133383438333436313335376136323337373433383634376337633465366534393338373136643732373736343735373237613763376334363733353737303533366236333463353333363534366137633763373337343732363536313664373336327c7c6b586c3163614468645a47617c7c73747265616d7362"
val headers = mapOf(
"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-Language" to "en-US,en;q=0.5",
"Referer" to url,
@ -109,7 +109,9 @@ open class StreamSB : ExtractorApi() {
allowRedirects = false
).text
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(
mapped.streamData.file,
headers = mapOf(
@ -127,11 +129,12 @@ open class StreamSB : ExtractorApi() {
), true
)
.map { stream ->
val cleanstreamurl = stream.streamUrl.replace(Regex("https://.*/hls/"), "$urlmain/hls/")
val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p"
ExtractorLink(
name,
"$name $qualityString",
stream.streamUrl,
cleanstreamurl,
url,
getQualityFromName(stream.quality.toString()),
true
@ -139,4 +142,4 @@ open class StreamSB : ExtractorApi() {
}
return null
}
}
}

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,33 +20,32 @@ class BflixProvider(providerUrl: String, providerName: String) : MainAPI() {
override suspend fun getMainPage(): HomePageResponse {
val items = ArrayList<HomePageList>()
val urls = listOf(
Pair("$mainUrl/home", "Movies"),
Pair("$mainUrl/tv-series", "Series"),
Pair("$mainUrl/top-imdb", "Top"),
val soup = app.get("$mainUrl/home").document
val testa = listOf(
Pair("Movies", "div.tab-content[data-name=movies] div.filmlist div.item"),
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) {
try {
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 link = fixUrl(it.selectFirst("a").attr("href"))
TvSeriesSearchResponse(
title,
link,
this.name,
if (link.contains("/movie/")) TvType.Movie else TvType.TvSeries,
it.selectFirst("a.poster img").attr("src"),
null,
null,
)
}
items.add(HomePageList(i.second, home))
} catch (e: Exception) {
e.printStackTrace()
for ((name, element) in testa) try {
val test = soup.select(element).map {
val title = it.selectFirst("h3 a").text()
val link = fixUrl(it.selectFirst("a").attr("href"))
// val quality = it.selectFirst("div.quality").text()
TvSeriesSearchResponse(
title,
link,
this.name,
if (link.contains("/movie/")) TvType.Movie else TvType.TvSeries,
it.selectFirst("a.poster img").attr("src"),
null,
null,
)
}
items.add(HomePageList(name, test))
} catch (e: Exception) {
e.printStackTrace()
}
if (items.size <= 0) throw ErrorLoadingException()
@ -248,7 +247,15 @@ class BflixProvider(providerUrl: String, providerName: String) : MainAPI() {
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) {
TvType.TvSeries -> {
TvSeriesLoadResponse(
@ -258,13 +265,14 @@ class BflixProvider(providerUrl: String, providerName: String) : MainAPI() {
tvType,
episodes!!,
poster,
null,
year?.toIntOrNull(),
description,
null,
null,
null,
rating,
tags,
recommendations = recommendations,
duration = duration,
)
}
TvType.Movie -> {
@ -275,12 +283,13 @@ class BflixProvider(providerUrl: String, providerName: String) : MainAPI() {
tvType,
url,
poster,
null,
year?.toIntOrNull(),
description,
null,
null,
rating,
tags,
recommendations = recommendations
recommendations = recommendations,
duration = duration
)
}
else -> null

View File

@ -1,9 +1,9 @@
package com.lagradost.cloudstream3.movieproviders
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.Evoload
import com.lagradost.cloudstream3.extractors.FEmbed
import com.lagradost.cloudstream3.extractors.StreamTape
import com.lagradost.cloudstream3.extractors.Cinestart
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.utils.*
import java.util.*
@ -30,9 +30,9 @@ class CinecalidadProvider:MainAPI() {
Pair("$mainUrl/genero-de-la-pelicula/peliculas-en-calidad-4k/", "4K UHD"),
)
for (i in urls) {
for ((url, name) in urls) {
try {
val soup = app.get(i.first).document
val soup = app.get(url).document
val home = soup.select(".item.movies").map {
val title = it.selectFirst("div.in_title").text()
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) {
e.printStackTrace()
logError(e)
}
}
@ -99,15 +99,20 @@ class CinecalidadProvider:MainAPI() {
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 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 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(
name,
null,
null,
season,
episode,
href,
epThumb
if (epThumb.contains("svg")) null else epThumb
)
}
return when (val tvType = if (url.contains("/ver-pelicula/")) TvType.Movie else TvType.TvSeries) {
@ -145,28 +150,109 @@ class CinecalidadProvider:MainAPI() {
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): 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")
if (url.startsWith("https://evoload.io")) {
val extractor = Evoload()
if (url.startsWith("https://cinestart.net")) {
val extractor = Cinestart()
extractor.getSafeUrl(url)?.forEach { link ->
callback.invoke(link)
}
} else {
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")
if (url.startsWith("https://evoload.io")) {
val extractor = Evoload()
if (url.startsWith("https://cinestart.net")) {
val extractor = Cinestart()
extractor.getSafeUrl(url)?.forEach { link ->
callback.invoke(link)
}
} else {
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
}
}
}

View File

@ -1,10 +1,11 @@
package com.lagradost.cloudstream3.movieproviders
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.mvvm.logError
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import java.util.*
class CuevanaProvider:MainAPI() {
@ -24,9 +25,27 @@ class CuevanaProvider:MainAPI() {
Pair(mainUrl, "Recientemente actualizadas"),
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 {
val soup = app.get(i.first).document
val soup = app.get(url).document
val home = soup.select("section li.xxx.TPostMv").map {
val title = it.selectFirst("h2.Title").text()
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) {
logError(e)
}
@ -80,7 +99,7 @@ class CuevanaProvider:MainAPI() {
null
)
}
}.toList()
}
}
override suspend fun load(url: String): LoadResponse? {
val soup = app.get(url, timeout = 120).document
@ -88,24 +107,47 @@ class CuevanaProvider:MainAPI() {
val description = soup.selectFirst(".Description p")?.text()?.trim()
val poster: String? = soup.selectFirst(".movtv-info div.Image img").attr("data-src")
val year1 = soup.selectFirst("footer p.meta").toString()
val yearRegex = Regex("(\\d+)<\\/span>")
val year = yearRegex.findAll(year1).map {
it.value.replace("</span>","")
}.toList().first().toIntOrNull()
val yearRegex = Regex("<span>(\\d+)</span>")
val yearf = yearRegex.find(year1)?.destructured?.component1()?.replace(Regex("<span>|</span>"),"")
val year = if (yearf.isNullOrBlank()) null else yearf.toIntOrNull()
val episodes = soup.select(".all-episodes li.TPostMv article").map { li ->
val href = li.select("a").attr("href")
val epThumb =
li.selectFirst("div.Image img").attr("data-src") ?: li.selectFirst("img.lazy").attr("data-srcc")
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(
name,
null,
null,
season,
episode,
href,
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 -> {
TvSeriesLoadResponse(
title,
@ -116,6 +158,8 @@ class CuevanaProvider:MainAPI() {
poster,
year,
description,
tags = tags,
recommendations = recommendations
)
}
TvType.Movie -> {
@ -128,6 +172,8 @@ class CuevanaProvider:MainAPI() {
poster,
year,
description,
tags = tags,
recommendations = recommendations
)
}
else -> null
@ -199,7 +245,7 @@ class CuevanaProvider:MainAPI() {
}.toList().apmap { gotolink ->
app.post("https://api.cuevana3.io/ir/redirect_ddh.php", allowRedirects = false,
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-Language" to "en-US,en;q=0.5",
"Content-Type" to "application/x-www-form-urlencoded",

View File

@ -26,9 +26,9 @@ class EntrepeliculasyseriesProvider:MainAPI() {
Pair("$mainUrl/anime/", "Animes"),
)
for (i in urls) {
for ((url, name) in urls) {
try {
val soup = app.get(i.first).document
val soup = app.get(url).document
val home = soup.select("ul.list-movie li").map {
val title = it.selectFirst("a.link-title h2").text()
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) {
logError(e)
}
@ -96,13 +96,18 @@ class EntrepeliculasyseriesProvider:MainAPI() {
val episodes = soup.select(".TPostMv article").map { li ->
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 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(
name,
null,
null,
season,
episode,
href,
epThumb
fixUrl(epThumb)
)
}
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.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.extractorApis
import java.util.ArrayList
import com.lagradost.cloudstream3.utils.loadExtractor
import kotlin.collections.ArrayList
class PeliSmartProvider: MainAPI() {
override val mainUrl = "https://pelismart.com"
@ -26,9 +27,9 @@ class PeliSmartProvider: MainAPI() {
Pair("$mainUrl/documentales/", "Documentales"),
)
for (i in urls) {
for ((url, name) in urls) {
try {
val soup = app.get(i.first).document
val soup = app.get(url).document
val home = soup.select(".description-off").map {
val title = it.selectFirst("h3.entry-title a").text()
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) {
e.printStackTrace()
}
@ -96,12 +97,20 @@ class PeliSmartProvider: MainAPI() {
val href = li.selectFirst("a").attr("href")
val preregex = Regex("(\\d+)\\. ")
val name = li.selectFirst("a").text().replace(preregex,"")
TvSeriesEpisode(
name,
null,
null,
href,
)
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(
name,
season,
episode,
href,
)
}
return when (val tvType = if (episodes.isEmpty()) TvType.Movie else TvType.TvSeries) {
TvType.TvSeries -> {
@ -138,24 +147,15 @@ class PeliSmartProvider: MainAPI() {
callback: (ExtractorLink) -> Unit
): Boolean {
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()@:%_\+.~#?&\/\/=]*))""")
val link1 = linkRegex.findAll(soup).map {
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/4.php?v=","https://dood.to/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/4.php?v=","https://dood.to/e/")
}.toList()
for (link in link1) {
for (extractor in extractorApis) {
if (link.startsWith(extractor.mainUrl)) {
extractor.getSafeUrl(link, data)?.forEach {
callback(it)
}
}
}
}
fetchUrls(soup).apmap {
val urlc = it.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/4.php?v=","https://dood.to/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/4.php?v=","https://dood.to/e/")
loadExtractor(urlc, data, callback)
}
return true
}
}

View File

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

View File

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