mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
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,80 +84,94 @@ 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"
|
||||||
|
|
|
@ -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
|
// 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() {
|
open class StreamSB : ExtractorApi() {
|
||||||
override val name = "StreamSB"
|
override val name = "StreamSB"
|
||||||
override val mainUrl = "https://watchsb.com"
|
override val mainUrl = "https://watchsb.com"
|
||||||
|
@ -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
|
||||||
|
@ -139,4 +142,4 @@ open class StreamSB : ExtractorApi() {
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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,28 +150,109 @@ 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,22 +165,11 @@ 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…
Reference in a new issue