forked from recloudstream/cloudstream
		
	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:
		
							parent
							
								
									8aa907d1d9
								
							
						
					
					
						commit
						3b08e82787
					
				
					 12 changed files with 502 additions and 235 deletions
				
			
		|  | @ -1,11 +1,12 @@ | ||||||
| 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() { | ||||||
|     companion object { |     companion object { | ||||||
|         fun getType(t: String): TvType { |         fun getType(t: String): TvType { | ||||||
|             return if (t.contains("OVA") || t.contains("Especial")) TvType.OVA |             return if (t.contains("OVA") || t.contains("Especial")) TvType.OVA | ||||||
|  | @ -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,79 +84,93 @@ 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 | ||||||
|             AnimeSearchResponse( |             val href = "$mainUrl/anime/${searchr.slug}" | ||||||
|                 title, |             val image = "$mainUrl/uploads/animes/covers/${searchr.id}.jpg" | ||||||
|                 href, |                 AnimeSearchResponse( | ||||||
|                 this.name, |                     title, | ||||||
|                 TvType.Anime, |                     href, | ||||||
|                 fixUrl(image), |                     this.name, | ||||||
|                 null, |                     TvType.Anime, | ||||||
|                 if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of( |                     fixUrl(image), | ||||||
|                     DubStatus.Subbed |                     null, | ||||||
|                 ), |                     if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(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( |             "Finalizado" -> ShowStatus.Completed | ||||||
|                 fixUrl(href), "Episodio" + li.selectFirst("a").text().replace(title, "") |             else -> null | ||||||
|             ) |  | ||||||
|         } |         } | ||||||
|         val type = doc.selectFirst("span.Type.A").text() |         val genre = doc.select("nav.Nvgnrs a") | ||||||
|         val genre = doc.select("a.Tag") |  | ||||||
|             .map { it?.text()?.trim().toString() } |             .map { it?.text()?.trim().toString() } | ||||||
| 
 | 
 | ||||||
|         val status = |         doc.select("script").map { script -> | ||||||
|             when (doc.selectFirst("article.Anime.Single.Bglg header p strong.Anm-On")?.text()) { |             if (script.data().contains("var episodes = [")) { | ||||||
|                 "En emisión" -> ShowStatus.Ongoing |                 val data = script.data().substringAfter("var episodes = [").substringBefore("];") | ||||||
|                 "Finalizado" -> ShowStatus.Completed |                 data.split("],").forEach { | ||||||
|                 else -> null |                     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 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -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,16 +297,36 @@ class GogoanimeProvider : MainAPI() { | ||||||
|                         source: GogoSource, |                         source: GogoSource, | ||||||
|                         sourceCallback: (ExtractorLink) -> Unit |                         sourceCallback: (ExtractorLink) -> Unit | ||||||
|                     ) { |                     ) { | ||||||
|                         sourceCallback.invoke( |                         if (source.file.contains("m3u8")) { | ||||||
|                             ExtractorLink( |                             M3u8Helper().m3u8Generation( | ||||||
|                                 this.name, |                             M3u8Helper.M3u8Stream( | ||||||
|                                 "${this.name} ${source.label?.replace("0 P", "0p") ?: ""}", |  | ||||||
|                                 source.file, |                                 source.file, | ||||||
|                                 "https://gogoplay.io", |                                 headers = mapOf("Referer" to "https://gogoplay.io") | ||||||
|                                 getQualityFromName(source.label ?: ""), |                             ), true | ||||||
|                                 isM3u8 = source.type == "hls" |  | ||||||
|                             ) |  | ||||||
|                         ) |                         ) | ||||||
|  |                             .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 { |                     sources.source?.forEach { | ||||||
|  |  | ||||||
|  | @ -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" | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -20,33 +20,32 @@ 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 title = it.selectFirst("h3 a").text() | ||||||
|                 val soup = Jsoup.parse(response.text) |                 val link = fixUrl(it.selectFirst("a").attr("href")) | ||||||
|                 val home = soup.select(".filmlist div.item").map { |                 // val quality = it.selectFirst("div.quality").text() | ||||||
|                     val title = it.selectFirst("h3 a").text() |                 TvSeriesSearchResponse( | ||||||
|                     val link = fixUrl(it.selectFirst("a").attr("href")) |                     title, | ||||||
|                     TvSeriesSearchResponse( |                     link, | ||||||
|                         title, |                     this.name, | ||||||
|                         link, |                     if (link.contains("/movie/")) TvType.Movie else TvType.TvSeries, | ||||||
|                         this.name, |                     it.selectFirst("a.poster img").attr("src"), | ||||||
|                         if (link.contains("/movie/")) TvType.Movie else TvType.TvSeries, |                     null, | ||||||
|                         it.selectFirst("a.poster img").attr("src"), |                     null, | ||||||
|                         null, |                 ) | ||||||
|                         null, |  | ||||||
|                     ) |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 items.add(HomePageList(i.second, home)) |  | ||||||
|             } catch (e: Exception) { |  | ||||||
|                 e.printStackTrace() |  | ||||||
|             } |             } | ||||||
|  |             items.add(HomePageList(name, test)) | ||||||
|  |         } catch (e: Exception) { | ||||||
|  |             e.printStackTrace() | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (items.size <= 0) throw ErrorLoadingException() |         if (items.size <= 0) throw ErrorLoadingException() | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -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", | ||||||
|  |  | ||||||
|  | @ -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) { | ||||||
|  |  | ||||||
|  | @ -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,12 +97,20 @@ 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,"") | ||||||
|             TvSeriesEpisode( |             val regextest = Regex("(temporada-(\\d+)-capitulo-(\\d+)|temporada-(\\d+)-episodio-(\\d+))") | ||||||
|                 name, |             val test = regextest.find(href)?.destructured?.component1()?.replace(Regex("(temporada-|-)"),"") | ||||||
|                 null, |             val seasonid = test.let { str -> | ||||||
|                 null, |                 str?.split("episodio","capitulo")?.mapNotNull { subStr -> subStr.toIntOrNull() } | ||||||
|                 href, |             } | ||||||
|             ) |             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) { |         return when (val tvType = if (episodes.isEmpty()) TvType.Movie else TvType.TvSeries) { | ||||||
|             TvType.TvSeries -> { |             TvType.TvSeries -> { | ||||||
|  | @ -138,24 +147,15 @@ 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/") |              loadExtractor(urlc, data, callback) | ||||||
|         }.toList() |          } | ||||||
|         for (link in link1) { |  | ||||||
|             for (extractor in extractorApis) { |  | ||||||
|                 if (link.startsWith(extractor.mainUrl)) { |  | ||||||
|                     extractor.getSafeUrl(link, data)?.forEach { |  | ||||||
|                         callback(it) |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         return true |         return true | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -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,42 +15,52 @@ 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") |  | ||||||
|                     TvSeriesSearchResponse( |  | ||||||
|                         title, |  | ||||||
|                         link, |  | ||||||
|                         this.name, |  | ||||||
|                         if (link.contains("/pelicula/")) TvType.Movie else TvType.TvSeries, |  | ||||||
|                         it.selectFirst(".Posters-img").attr("src"), |  | ||||||
|                         null, |  | ||||||
|                         null, |  | ||||||
|                     ) |  | ||||||
|                 } |                 } | ||||||
| 
 |             )) | ||||||
|                 items.add(HomePageList(i.second, home)) |  | ||||||
|             } catch (e: Exception) { |  | ||||||
|                 e.printStackTrace() |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         if (items.size <= 0) throw ErrorLoadingException() |  | ||||||
|         return HomePageResponse(items) |         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> { |     override suspend fun search(query: String): List<SearchResponse> { | ||||||
|         val url = "https://pelisplushd.net/search?s=${query}" |         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 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 | ||||||
|  |  | ||||||
|  | @ -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(), | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue