From 3b08e82787c369718fd0be3416656e1357a2c60b Mon Sep 17 00:00:00 2001 From: Stormunblessed <86633626+Stormunblessed@users.noreply.github.com> Date: Fri, 4 Mar 2022 12:47:36 +0000 Subject: [PATCH] Fixes on multiple providers and added some extractors (#734) * Fixes on Providers and Extractors Co-authored-by: Osten <11805592+LagradOst@users.noreply.github.com> --- .../animeproviders/AnimeflvProvider.kt | 170 +++++++++++------- .../animeproviders/GogoanimeProvider.kt | 41 +++-- .../cloudstream3/extractors/GenericM3U8.kt | 4 - .../cloudstream3/extractors/StreamSB.kt | 13 +- .../cloudstream3/extractors/Zplayer.kt | 59 ++++++ .../movieproviders/BflixProvider.kt | 71 ++++---- .../movieproviders/CinecalidadProvider.kt | 124 +++++++++++-- .../movieproviders/CuevanaProvider.kt | 74 ++++++-- .../EntrePeliculasySeriesProvider.kt | 19 +- .../movieproviders/PeliSmartProvider.kt | 56 +++--- .../movieproviders/PelisplusHDProvider.kt | 99 +++++----- .../cloudstream3/utils/ExtractorApi.kt | 7 +- 12 files changed, 502 insertions(+), 235 deletions(-) create mode 100644 app/src/main/java/com/lagradost/cloudstream3/extractors/Zplayer.kt diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeflvProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeflvProvider.kt index f40b4f9a..59cb0001 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeflvProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimeflvProvider.kt @@ -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() - 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 { - 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>(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() 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 } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/GogoanimeProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/GogoanimeProvider.kt index 2bfd28a6..3a39e957 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/GogoanimeProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/GogoanimeProvider.kt @@ -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 { diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/GenericM3U8.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/GenericM3U8.kt index c798a3fa..386d7eda 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/extractors/GenericM3U8.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/GenericM3U8.kt @@ -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" diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamSB.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamSB.kt index 034acef7..1e8d20d9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamSB.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamSB.kt @@ -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
(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 } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Zplayer.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Zplayer.kt new file mode 100644 index 00000000..5a5201ae --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Zplayer.kt @@ -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 { + val doc = app.get(url).document + val sources = mutableListOf() + 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 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/BflixProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/BflixProvider.kt index f43c7f57..2c21e053 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/BflixProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/BflixProvider.kt @@ -20,33 +20,32 @@ class BflixProvider(providerUrl: String, providerName: String) : MainAPI() { override suspend fun getMainPage(): HomePageResponse { val items = ArrayList() - 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("(\\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>"),"") } 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 diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CinecalidadProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CinecalidadProvider.kt index f5c5d970..d7654d39 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CinecalidadProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CinecalidadProvider.kt @@ -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 } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CuevanaProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CuevanaProvider.kt index 67ec00f5..f07d28d5 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CuevanaProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/CuevanaProvider.kt @@ -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("","") - }.toList().first().toIntOrNull() + val yearRegex = Regex("(\\d+)") + val yearf = yearRegex.find(year1)?.destructured?.component1()?.replace(Regex("|"),"") + val year = if (yearf.isNullOrBlank()) null else yearf.toIntOrNull() val episodes = soup.select(".all-episodes li.TPostMv article").map { li -> val href = li.select("a").attr("href") val epThumb = li.selectFirst("div.Image img").attr("data-src") ?: li.selectFirst("img.lazy").attr("data-srcc") - 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", diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/EntrePeliculasySeriesProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/EntrePeliculasySeriesProvider.kt index 5dbc40c6..8f4b7afa 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/EntrePeliculasySeriesProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/EntrePeliculasySeriesProvider.kt @@ -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) { diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PeliSmartProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PeliSmartProvider.kt index 67fdf590..36bd1622 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PeliSmartProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PeliSmartProvider.kt @@ -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 } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PelisplusHDProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PelisplusHDProvider.kt index eaa8149f..6a07d142 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PelisplusHDProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/PelisplusHDProvider.kt @@ -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() - 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 { 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 } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt index 8b50ba45..a2231862 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt @@ -136,9 +136,12 @@ val extractorApis: Array = arrayOf( AsianLoad(), - ZplayerV2(), - GenericM3U8(), + // GenericM3U8(), Jawcloud(), + Zplayer(), + ZplayerV2(), + Upstream(), + // StreamSB.kt works // SBPlay(),