added subtitles to ExtractorApi

This commit is contained in:
LagradOst 2022-07-27 19:36:31 +02:00
parent a7e29dd8d5
commit 47f4e10078
69 changed files with 621 additions and 442 deletions

View file

@ -899,6 +899,11 @@ data class TvSeriesSearchResponse(
override var posterHeaders: Map<String, String>? = null, override var posterHeaders: Map<String, String>? = null,
) : SearchResponse ) : SearchResponse
data class TrailerData(
var mirros: List<ExtractorLink>,
var subtitles: List<SubtitleFile> = emptyList(),
)
interface LoadResponse { interface LoadResponse {
var name: String var name: String
var url: String var url: String
@ -910,7 +915,8 @@ interface LoadResponse {
var rating: Int? // 0-10000 var rating: Int? // 0-10000
var tags: List<String>? var tags: List<String>?
var duration: Int? // in minutes var duration: Int? // in minutes
var trailers: List<ExtractorLink>? var trailers: MutableList<TrailerData>
var recommendations: List<SearchResponse>? var recommendations: List<SearchResponse>?
var actors: List<ActorData>? var actors: List<ActorData>?
var comingSoon: Boolean var comingSoon: Boolean
@ -965,35 +971,25 @@ interface LoadResponse {
/**better to call addTrailer with mutible trailers directly instead of calling this multiple times*/ /**better to call addTrailer with mutible trailers directly instead of calling this multiple times*/
suspend fun LoadResponse.addTrailer(trailerUrl: String?, referer: String? = null) { suspend fun LoadResponse.addTrailer(trailerUrl: String?, referer: String? = null) {
if (!isTrailersEnabled || trailerUrl == null) return if (!isTrailersEnabled || trailerUrl == null) return
try { val links = arrayListOf<ExtractorLink>()
val newTrailers = loadExtractor(trailerUrl, referer) val subs = arrayListOf<SubtitleFile>()
addTrailer(newTrailers) loadExtractor(trailerUrl, referer, { subs.add(it) }, { links.add(it) })
} catch (e: Exception) { this.trailers.add(TrailerData(links, subs))
logError(e)
}
} }
fun LoadResponse.addTrailer(newTrailers: List<ExtractorLink>) { fun LoadResponse.addTrailer(newTrailers: List<ExtractorLink>) {
if (this.trailers == null) { trailers.addAll(newTrailers.map { TrailerData(listOf(it)) })
this.trailers = newTrailers
} else {
val update = this.trailers?.toMutableList() ?: mutableListOf()
update.addAll(newTrailers)
this.trailers = update
}
} }
suspend fun LoadResponse.addTrailer(trailerUrls: List<String>?, referer: String? = null) { suspend fun LoadResponse.addTrailer(trailerUrls: List<String>?, referer: String? = null) {
if (!isTrailersEnabled || trailerUrls == null) return if (!isTrailersEnabled || trailerUrls == null) return
val newTrailers = trailerUrls.apmap { trailerUrl -> val trailers = trailerUrls.apmap { trailerUrl ->
try { val links = arrayListOf<ExtractorLink>()
loadExtractor(trailerUrl, referer) val subs = arrayListOf<SubtitleFile>()
} catch (e: Exception) { loadExtractor(trailerUrl, referer, { subs.add(it) }, { links.add(it) })
logError(e) links to subs
emptyList() }.map { (links, subs) -> TrailerData(links, subs) }
} this.trailers.addAll(trailers)
}.flatten().distinct()
addTrailer(newTrailers)
} }
fun LoadResponse.addImdbId(id: String?) { fun LoadResponse.addImdbId(id: String?) {
@ -1087,7 +1083,7 @@ data class TorrentLoadResponse(
override var rating: Int? = null, override var rating: Int? = null,
override var tags: List<String>? = null, override var tags: List<String>? = null,
override var duration: Int? = null, override var duration: Int? = null,
override var trailers: List<ExtractorLink>? = null, override var trailers: MutableList<TrailerData> = mutableListOf(),
override var recommendations: List<SearchResponse>? = null, override var recommendations: List<SearchResponse>? = null,
override var actors: List<ActorData>? = null, override var actors: List<ActorData>? = null,
override var comingSoon: Boolean = false, override var comingSoon: Boolean = false,
@ -1115,7 +1111,7 @@ data class AnimeLoadResponse(
override var rating: Int? = null, override var rating: Int? = null,
override var duration: Int? = null, override var duration: Int? = null,
override var trailers: List<ExtractorLink>? = null, override var trailers: MutableList<TrailerData> = mutableListOf(),
override var recommendations: List<SearchResponse>? = null, override var recommendations: List<SearchResponse>? = null,
override var actors: List<ActorData>? = null, override var actors: List<ActorData>? = null,
override var comingSoon: Boolean = false, override var comingSoon: Boolean = false,
@ -1163,7 +1159,7 @@ data class LiveStreamLoadResponse(
override var rating: Int? = null, override var rating: Int? = null,
override var tags: List<String>? = null, override var tags: List<String>? = null,
override var duration: Int? = null, override var duration: Int? = null,
override var trailers: List<ExtractorLink>? = null, override var trailers: MutableList<TrailerData> = mutableListOf(),
override var recommendations: List<SearchResponse>? = null, override var recommendations: List<SearchResponse>? = null,
override var actors: List<ActorData>? = null, override var actors: List<ActorData>? = null,
override var comingSoon: Boolean = false, override var comingSoon: Boolean = false,
@ -1185,7 +1181,7 @@ data class MovieLoadResponse(
override var rating: Int? = null, override var rating: Int? = null,
override var tags: List<String>? = null, override var tags: List<String>? = null,
override var duration: Int? = null, override var duration: Int? = null,
override var trailers: List<ExtractorLink>? = null, override var trailers: MutableList<TrailerData> = mutableListOf(),
override var recommendations: List<SearchResponse>? = null, override var recommendations: List<SearchResponse>? = null,
override var actors: List<ActorData>? = null, override var actors: List<ActorData>? = null,
override var comingSoon: Boolean = false, override var comingSoon: Boolean = false,
@ -1306,7 +1302,7 @@ data class TvSeriesLoadResponse(
override var rating: Int? = null, override var rating: Int? = null,
override var tags: List<String>? = null, override var tags: List<String>? = null,
override var duration: Int? = null, override var duration: Int? = null,
override var trailers: List<ExtractorLink>? = null, override var trailers: MutableList<TrailerData> = mutableListOf(),
override var recommendations: List<SearchResponse>? = null, override var recommendations: List<SearchResponse>? = null,
override var actors: List<ActorData>? = null, override var actors: List<ActorData>? = null,
override var comingSoon: Boolean = false, override var comingSoon: Boolean = false,

View file

@ -56,8 +56,9 @@ class AnimeFlickProvider : MainAPI() {
val title = doc.selectFirst("h2.title")!!.text() val title = doc.selectFirst("h2.title")!!.text()
val yearText = doc.selectFirst(".trending-year")?.text() val yearText = doc.selectFirst(".trending-year")?.text()
val year = if (yearText != null) Regex("""(\d{4})""").find(yearText)?.destructured?.component1() val year =
?.toIntOrNull() else null if (yearText != null) Regex("""(\d{4})""").find(yearText)?.destructured?.component1()
?.toIntOrNull() else null
val description = doc.selectFirst("p")?.text() val description = doc.selectFirst("p")?.text()
val genres = doc.select("a[href*=\"genre-\"]").map { it.text() } val genres = doc.select("a[href*=\"genre-\"]").map { it.text() }
@ -95,7 +96,7 @@ class AnimeFlickProvider : MainAPI() {
var alreadyAdded = false var alreadyAdded = false
for (extractor in extractorApis) { for (extractor in extractorApis) {
if (link.startsWith(extractor.mainUrl)) { if (link.startsWith(extractor.mainUrl)) {
extractor.getSafeUrl(link, data)?.forEach(callback) extractor.getSafeUrl(link, data, subtitleCallback, callback)
alreadyAdded = true alreadyAdded = true
break break
} }

View file

@ -8,7 +8,6 @@ import com.lagradost.cloudstream3.utils.loadExtractor
import com.lagradost.nicehttp.NiceResponse import com.lagradost.nicehttp.NiceResponse
import org.jsoup.Jsoup import org.jsoup.Jsoup
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.util.ArrayList
class AnimeIndoProvider : MainAPI() { class AnimeIndoProvider : MainAPI() {
override var mainUrl = "https://animeindo.sbs" override var mainUrl = "https://animeindo.sbs"
@ -183,7 +182,7 @@ class AnimeIndoProvider : MainAPI() {
it it
} }
}.apmap { }.apmap {
loadExtractor(it, data, callback) loadExtractor(it, data, subtitleCallback, callback)
} }
return true return true

View file

@ -112,7 +112,8 @@ class AnimeSailProvider : MainAPI() {
) )
val episodes = document.select("ul.daftar > li").map { val episodes = document.select("ul.daftar > li").map {
val header = it.select("a").text().trim() val header = it.select("a").text().trim()
val name = Regex("(Episode\\s?[0-9]+)").find(header)?.groupValues?.getOrNull(0) ?: header val name =
Regex("(Episode\\s?[0-9]+)").find(header)?.groupValues?.getOrNull(0) ?: header
val link = fixUrl(it.select("a").attr("href")) val link = fixUrl(it.select("a").attr("href"))
Episode(link, name = name) Episode(link, name = name)
}.reversed() }.reversed()
@ -157,7 +158,8 @@ class AnimeSailProvider : MainAPI() {
iframe.contains("/race/") -> "Race" iframe.contains("/race/") -> "Race"
else -> this.name else -> this.name
} }
val quality = Regex("\\.([0-9]{3,4})\\.").find(link)?.groupValues?.get(1) val quality =
Regex("\\.([0-9]{3,4})\\.").find(link)?.groupValues?.get(1)
callback.invoke( callback.invoke(
ExtractorLink( ExtractorLink(
source = source, source = source,
@ -174,11 +176,11 @@ class AnimeSailProvider : MainAPI() {
iframe.startsWith("$mainUrl/utils/player/framezilla/") || iframe.startsWith("https://uservideo.xyz") -> { iframe.startsWith("$mainUrl/utils/player/framezilla/") || iframe.startsWith("https://uservideo.xyz") -> {
request(iframe, ref = data).document.select("iframe").attr("src") request(iframe, ref = data).document.select("iframe").attr("src")
.let { link -> .let { link ->
loadExtractor(fixUrl(link), mainUrl, callback) loadExtractor(fixUrl(link), mainUrl, subtitleCallback, callback)
} }
} }
else -> { else -> {
loadExtractor(iframe, mainUrl, callback) loadExtractor(iframe, mainUrl, subtitleCallback, callback)
} }
} }
} }

View file

@ -2,11 +2,12 @@ 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.*
import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.util.* import java.util.*
import kotlin.collections.ArrayList
class AnimefenixProvider:MainAPI() { class AnimefenixProvider:MainAPI() {
@ -179,7 +180,7 @@ class AnimefenixProvider:MainAPI() {
else -> "" else -> ""
} }
loadExtractor(links, data, callback) loadExtractor(links, data, subtitleCallback, callback)
argamap({ argamap({
if (links.contains("AmaNormal")) { if (links.contains("AmaNormal")) {

View file

@ -2,11 +2,13 @@ package com.lagradost.cloudstream3.movieproviders
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.*
import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8 import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.getQualityFromName
import com.lagradost.cloudstream3.utils.loadExtractor
import java.util.* import java.util.*
import kotlin.collections.ArrayList
class AnimeflvIOProvider:MainAPI() { class AnimeflvIOProvider:MainAPI() {
override var mainUrl = "https://animeflv.io" //Also scrapes from animeid.to override var mainUrl = "https://animeflv.io" //Also scrapes from animeid.to
@ -220,7 +222,7 @@ class AnimeflvIOProvider:MainAPI() {
} }
} }
} }
loadExtractor(url, data, callback) loadExtractor(url, data, subtitleCallback, callback)
} }
return true return true
} }

View file

@ -173,7 +173,7 @@ class AnimeflvnetProvider : MainAPI() {
it.replace("https://embedsb.com/e/", "https://watchsb.com/e/") it.replace("https://embedsb.com/e/", "https://watchsb.com/e/")
.replace("https://ok.ru", "http://ok.ru") .replace("https://ok.ru", "http://ok.ru")
}.apmap { }.apmap {
loadExtractor(it, data, callback) loadExtractor(it, data, subtitleCallback, callback)
} }
} }
} }

View file

@ -2,8 +2,6 @@ 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.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.mvvm.safeApiCall
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
@ -126,7 +124,7 @@ class AnimekisaProvider : MainAPI() {
): Boolean { ): Boolean {
app.get(data).document.select("#servers-list ul.nav li a").apmap { app.get(data).document.select("#servers-list ul.nav li a").apmap {
val server = it.attr("data-embed") val server = it.attr("data-embed")
loadExtractor(server, data, callback) loadExtractor(server, data, subtitleCallback, callback)
} }
return true return true
} }

View file

@ -338,7 +338,11 @@ class GogoanimeProvider : MainAPI() {
@JsonProperty("default") val default: String? = null @JsonProperty("default") val default: String? = null
) )
private suspend fun extractVideos(uri: String, callback: (ExtractorLink) -> Unit) { private suspend fun extractVideos(
uri: String,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val doc = app.get(uri).document val doc = app.get(uri).document
val iframe = fixUrlNull(doc.selectFirst("div.play-video > iframe")?.attr("src")) ?: return val iframe = fixUrlNull(doc.selectFirst("div.play-video > iframe")?.attr("src")) ?: return
@ -366,7 +370,7 @@ class GogoanimeProvider : MainAPI() {
) )
} else { } else {
val url = it.attr("href") val url = it.attr("href")
loadExtractor(url, null, callback) loadExtractor(url, null, subtitleCallback, callback)
} }
} }
}, { }, {
@ -378,7 +382,7 @@ class GogoanimeProvider : MainAPI() {
val status = element.attr("data-status") ?: return@forEach val status = element.attr("data-status") ?: return@forEach
if (status != "1") return@forEach if (status != "1") return@forEach
val data = element.attr("data-video") ?: return@forEach val data = element.attr("data-video") ?: return@forEach
loadExtractor(data, streamingResponse.url, callback) loadExtractor(data, streamingResponse.url, subtitleCallback, callback)
} }
}, { }, {
val iv = "3134003223491201" val iv = "3134003223491201"
@ -405,7 +409,7 @@ class GogoanimeProvider : MainAPI() {
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
extractVideos(data, callback) extractVideos(data, subtitleCallback, callback)
return true return true
} }
} }

View file

@ -145,7 +145,9 @@ class GomunimeProvider : MainAPI() {
document.select(".bixbox.bxcl.epcheck > script").toString().trim() document.select(".bixbox.bxcl.epcheck > script").toString().trim()
)?.groupValues?.get(1).toString().replace(Regex("""\\"""), "").trim() )?.groupValues?.get(1).toString().replace(Regex("""\\"""), "").trim()
).map { ).map {
val name = Regex("(Episode\\s?[0-9]+)").find(it.epTitle.toString())?.groupValues?.getOrNull(0) ?: it.epTitle val name =
Regex("(Episode\\s?[0-9]+)").find(it.epTitle.toString())?.groupValues?.getOrNull(0)
?: it.epTitle
val link = it.epLink val link = it.epLink
Episode(link, name) Episode(link, name)
}.reversed() }.reversed()
@ -194,7 +196,7 @@ class GomunimeProvider : MainAPI() {
safeApiCall { safeApiCall {
when { when {
it.second.contains("frame") -> { it.second.contains("frame") -> {
loadExtractor(it.first, data, callback) loadExtractor(it.first, data, subtitleCallback, callback)
} }
it.second.contains("hls") -> { it.second.contains("hls") -> {
app.post( app.post(

View file

@ -3,12 +3,12 @@ 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.*
import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8 import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
import com.lagradost.cloudstream3.utils.getQualityFromName
import com.lagradost.cloudstream3.utils.loadExtractor
import java.util.* import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.List
class JKAnimeProvider : MainAPI() { class JKAnimeProvider : MainAPI() {
@ -34,9 +34,18 @@ class JKAnimeProvider : MainAPI() {
override suspend fun getMainPage(): HomePageResponse { override suspend fun getMainPage(): HomePageResponse {
val urls = listOf( val urls = listOf(
Pair("$mainUrl/directorio/?filtro=fecha&tipo=TV&estado=1&fecha=none&temporada=none&orden=desc", "En emisión"), Pair(
Pair("$mainUrl/directorio/?filtro=fecha&tipo=none&estado=none&fecha=none&temporada=none&orden=none", "Animes"), "$mainUrl/directorio/?filtro=fecha&tipo=TV&estado=1&fecha=none&temporada=none&orden=desc",
Pair("$mainUrl/directorio/?filtro=fecha&tipo=Movie&estado=none&fecha=none&temporada=none&orden=none", "Películas"), "En emisión"
),
Pair(
"$mainUrl/directorio/?filtro=fecha&tipo=none&estado=none&fecha=none&temporada=none&orden=none",
"Animes"
),
Pair(
"$mainUrl/directorio/?filtro=fecha&tipo=Movie&estado=none&fecha=none&temporada=none&orden=none",
"Películas"
),
) )
val items = ArrayList<HomePageList>() val items = ArrayList<HomePageList>()
@ -46,12 +55,14 @@ class JKAnimeProvider : MainAPI() {
"Últimos episodios", "Últimos episodios",
app.get(mainUrl).document.select(".listadoanime-home a.bloqq").map { app.get(mainUrl).document.select(".listadoanime-home a.bloqq").map {
val title = it.selectFirst("h5")?.text() val title = it.selectFirst("h5")?.text()
val dubstat =if (title!!.contains("Latino") || title.contains("Castellano")) val dubstat = if (title!!.contains("Latino") || title.contains("Castellano"))
DubStatus.Dubbed else DubStatus.Subbed DubStatus.Dubbed else DubStatus.Subbed
val poster = it.selectFirst(".anime__sidebar__comment__item__pic img")?.attr("src") ?: "" val poster =
it.selectFirst(".anime__sidebar__comment__item__pic img")?.attr("src") ?: ""
val epRegex = Regex("/(\\d+)/|/especial/|/ova/") val epRegex = Regex("/(\\d+)/|/especial/|/ova/")
val url = it.attr("href").replace(epRegex, "") val url = it.attr("href").replace(epRegex, "")
val epNum = it.selectFirst("h6")?.text()?.replace("Episodio ", "")?.toIntOrNull() val epNum =
it.selectFirst("h6")?.text()?.replace("Episodio ", "")?.toIntOrNull()
newAnimeSearchResponse(title, url) { newAnimeSearchResponse(title, url) {
this.posterUrl = poster this.posterUrl = poster
addDubStatus(dubstat, epNum) addDubStatus(dubstat, epNum)
@ -82,12 +93,12 @@ class JKAnimeProvider : MainAPI() {
return HomePageResponse(items) return HomePageResponse(items)
} }
data class MainSearch ( data class MainSearch(
@JsonProperty("animes") val animes: List<Animes>, @JsonProperty("animes") val animes: List<Animes>,
@JsonProperty("anime_types") val animeTypes: AnimeTypes @JsonProperty("anime_types") val animeTypes: AnimeTypes
) )
data class Animes ( data class Animes(
@JsonProperty("id") val id: String, @JsonProperty("id") val id: String,
@JsonProperty("slug") val slug: String, @JsonProperty("slug") val slug: String,
@JsonProperty("title") val title: String, @JsonProperty("title") val title: String,
@ -98,7 +109,7 @@ class JKAnimeProvider : MainAPI() {
@JsonProperty("thumbnail") val thumbnail: String @JsonProperty("thumbnail") val thumbnail: String
) )
data class AnimeTypes ( data class AnimeTypes(
@JsonProperty("TV") val TV: String, @JsonProperty("TV") val TV: String,
@JsonProperty("OVA") val OVA: String, @JsonProperty("OVA") val OVA: String,
@JsonProperty("Movie") val Movie: String, @JsonProperty("Movie") val Movie: String,
@ -134,7 +145,8 @@ class JKAnimeProvider : MainAPI() {
val title = doc.selectFirst(".anime__details__title > h3")?.text() val title = doc.selectFirst(".anime__details__title > h3")?.text()
val type = doc.selectFirst(".anime__details__text")?.text() val type = doc.selectFirst(".anime__details__text")?.text()
val description = doc.selectFirst(".anime__details__text > p")?.text() val description = doc.selectFirst(".anime__details__text > p")?.text()
val genres = doc.select("div.col-lg-6:nth-child(1) > ul:nth-child(1) > li:nth-child(2) > a").map { it.text() } val genres = doc.select("div.col-lg-6:nth-child(1) > ul:nth-child(1) > li:nth-child(2) > a")
.map { it.text() }
val status = when (doc.selectFirst("span.enemision")?.text()) { val status = when (doc.selectFirst("span.enemision")?.text()) {
"En emisión" -> ShowStatus.Ongoing "En emisión" -> ShowStatus.Ongoing
"Concluido" -> ShowStatus.Completed "Concluido" -> ShowStatus.Completed
@ -143,7 +155,8 @@ class JKAnimeProvider : MainAPI() {
val animeID = doc.selectFirst("div.ml-2")?.attr("data-anime")?.toInt() val animeID = doc.selectFirst("div.ml-2")?.attr("data-anime")?.toInt()
val animeeps = "$mainUrl/ajax/last_episode/$animeID/" val animeeps = "$mainUrl/ajax/last_episode/$animeID/"
val jsoneps = app.get(animeeps).text val jsoneps = app.get(animeeps).text
val lastepnum = jsoneps.substringAfter("{\"number\":\"").substringBefore("\",\"title\"").toInt() val lastepnum =
jsoneps.substringAfter("{\"number\":\"").substringBefore("\",\"title\"").toInt()
val episodes = (1..lastepnum).map { val episodes = (1..lastepnum).map {
val link = "${url.removeSuffix("/")}/$it" val link = "${url.removeSuffix("/")}/$it"
Episode(link) Episode(link)
@ -158,7 +171,7 @@ class JKAnimeProvider : MainAPI() {
} }
} }
data class Nozomi ( data class Nozomi(
@JsonProperty("file") val file: String? @JsonProperty("file") val file: String?
) )
@ -193,16 +206,17 @@ class JKAnimeProvider : MainAPI() {
if (script.data().contains("var video = []")) { if (script.data().contains("var video = []")) {
val videos = script.data().replace("\\/", "/") val videos = script.data().replace("\\/", "/")
fetchUrls(videos).map { fetchUrls(videos).map {
it.replace("$mainUrl/jkfembed.php?u=","https://embedsito.com/v/") it.replace("$mainUrl/jkfembed.php?u=", "https://embedsito.com/v/")
.replace("$mainUrl/jkokru.php?u=","http://ok.ru/videoembed/") .replace("$mainUrl/jkokru.php?u=", "http://ok.ru/videoembed/")
.replace("$mainUrl/jkvmixdrop.php?u=","https://mixdrop.co/e/") .replace("$mainUrl/jkvmixdrop.php?u=", "https://mixdrop.co/e/")
.replace("$mainUrl/jk.php?u=","$mainUrl/") .replace("$mainUrl/jk.php?u=", "$mainUrl/")
}.apmap { link -> }.apmap { link ->
loadExtractor(link, data, callback) loadExtractor(link, data, subtitleCallback, callback)
if (link.contains("um2.php")) { if (link.contains("um2.php")) {
val doc = app.get(link, referer = data).document val doc = app.get(link, referer = data).document
val gsplaykey = doc.select("form input[value]").attr("value") val gsplaykey = doc.select("form input[value]").attr("value")
val postgsplay = app.post("$mainUrl/gsplay/redirect_post.php", app.post(
"$mainUrl/gsplay/redirect_post.php",
headers = mapOf( headers = mapOf(
"Host" to "jkanime.net", "Host" to "jkanime.net",
"User-Agent" to USER_AGENT, "User-Agent" to USER_AGENT,
@ -219,11 +233,14 @@ class JKAnimeProvider : MainAPI() {
"Sec-Fetch-Site" to "same-origin", "Sec-Fetch-Site" to "same-origin",
"TE" to "trailers", "TE" to "trailers",
"Pragma" to "no-cache", "Pragma" to "no-cache",
"Cache-Control" to "no-cache",), "Cache-Control" to "no-cache",
data = mapOf(Pair("data",gsplaykey)), ),
allowRedirects = false).okhttpResponse.headers.values("location").apmap { loc -> data = mapOf(Pair("data", gsplaykey)),
val postkey = loc.replace("/gsplay/player.html#","") allowRedirects = false
val nozomitext = app.post("$mainUrl/gsplay/api.php", ).okhttpResponse.headers.values("location").apmap { loc ->
val postkey = loc.replace("/gsplay/player.html#", "")
val nozomitext = app.post(
"$mainUrl/gsplay/api.php",
headers = mapOf( headers = mapOf(
"Host" to "jkanime.net", "Host" to "jkanime.net",
"User-Agent" to USER_AGENT, "User-Agent" to USER_AGENT,
@ -236,8 +253,9 @@ class JKAnimeProvider : MainAPI() {
"Connection" to "keep-alive", "Connection" to "keep-alive",
"Sec-Fetch-Dest" to "empty", "Sec-Fetch-Dest" to "empty",
"Sec-Fetch-Mode" to "cors", "Sec-Fetch-Mode" to "cors",
"Sec-Fetch-Site" to "same-origin",), "Sec-Fetch-Site" to "same-origin",
data = mapOf(Pair("v",postkey)), ),
data = mapOf(Pair("v", postkey)),
allowRedirects = false allowRedirects = false
).text ).text
val json = parseJson<Nozomi>(nozomitext) val json = parseJson<Nozomi>(nozomitext)
@ -245,13 +263,20 @@ class JKAnimeProvider : MainAPI() {
if (nozomiurl.isEmpty()) null else if (nozomiurl.isEmpty()) null else
nozomiurl.forEach { url -> nozomiurl.forEach { url ->
val nozominame = "Nozomi" val nozominame = "Nozomi"
streamClean(nozominame, url!!, "", null, callback, url.contains(".m3u8")) streamClean(
nozominame,
url!!,
"",
null,
callback,
url.contains(".m3u8")
)
} }
} }
} }
if (link.contains("um.php")) { if (link.contains("um.php")) {
val desutext = app.get(link, referer = data).text val desutext = app.get(link, referer = data).text
val desuRegex = Regex("((https:|http:)\\/\\/.*\\.m3u8)") val desuRegex = Regex("((https:|http:)//.*\\.m3u8)")
val file = desuRegex.find(desutext)?.value val file = desuRegex.find(desutext)?.value
val namedesu = "Desu" val namedesu = "Desu"
generateM3u8( generateM3u8(
@ -259,13 +284,31 @@ class JKAnimeProvider : MainAPI() {
file!!, file!!,
mainUrl, mainUrl,
).forEach { desurl -> ).forEach { desurl ->
streamClean(namedesu, desurl.url, mainUrl, desurl.quality.toString(), callback, true) streamClean(
namedesu,
desurl.url,
mainUrl,
desurl.quality.toString(),
callback,
true
)
} }
} }
if (link.contains("jkmedia")) { if (link.contains("jkmedia")) {
app.get(link, referer = data, allowRedirects = false).okhttpResponse.headers.values("location").apmap { xtremeurl -> app.get(
link,
referer = data,
allowRedirects = false
).okhttpResponse.headers.values("location").apmap { xtremeurl ->
val namex = "Xtreme S" val namex = "Xtreme S"
streamClean(namex, xtremeurl, "", null, callback, xtremeurl.contains(".m3u8")) streamClean(
namex,
xtremeurl,
"",
null,
callback,
xtremeurl.contains(".m3u8")
)
} }
} }
} }

View file

@ -3,7 +3,6 @@ package com.lagradost.cloudstream3.animeproviders
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.loadExtractor import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup
class KimCartoonProvider : MainAPI() { class KimCartoonProvider : MainAPI() {
@ -83,9 +82,9 @@ class KimCartoonProvider : MainAPI() {
override suspend fun quickSearch(query: String): List<SearchResponse> { override suspend fun quickSearch(query: String): List<SearchResponse> {
return app.post( return app.post(
"$mainUrl/Ajax/SearchSuggest", "$mainUrl/Ajax/SearchSuggest",
data = mapOf("keyword" to query) data = mapOf("keyword" to query)
).document.select("a").map { ).document.select("a").map {
AnimeSearchResponse( AnimeSearchResponse(
it.text(), it.text(),
it.attr("href"), it.attr("href"),
@ -143,7 +142,7 @@ class KimCartoonProvider : MainAPI() {
servers.apmap { servers.apmap {
app.get(it).document.select("#my_video_1").attr("src").let { iframe -> app.get(it).document.select("#my_video_1").attr("src").let { iframe ->
if (iframe.isNotEmpty()) { if (iframe.isNotEmpty()) {
loadExtractor(iframe, "$mainUrl/", callback) loadExtractor(iframe, "$mainUrl/", subtitleCallback, callback)
} }
//There are other servers, but they require some work to do //There are other servers, but they require some work to do
} }

View file

@ -180,7 +180,7 @@ class KuronimeProvider : MainAPI() {
safeApiCall { safeApiCall {
when { when {
it.startsWith("https://animeku.org") -> invokeKuroSource(it, callback) it.startsWith("https://animeku.org") -> invokeKuroSource(it, callback)
else -> loadExtractor(it, mainUrl, callback) else -> loadExtractor(it, mainUrl, subtitleCallback, callback)
} }
} }
} }

View file

@ -148,7 +148,7 @@ class MonoschinosProvider : MainAPI() {
callback.invoke(link) callback.invoke(link)
} }
} else { } else {
loadExtractor(url, mainUrl, callback) loadExtractor(url, mainUrl, subtitleCallback, callback)
} }
} }
return true return true

View file

@ -163,7 +163,7 @@ class MundoDonghuaProvider : MainAPI() {
}.toList().apmap { }.toList().apmap {
val unpack = getAndUnpack(it).replace("diasfem","embedsito") val unpack = getAndUnpack(it).replace("diasfem","embedsito")
fetchUrls(unpack).apmap { url -> fetchUrls(unpack).apmap { url ->
loadExtractor(url, data, callback) loadExtractor(url, data, subtitleCallback, callback)
} }
if (unpack.contains("protea_tab")) { if (unpack.contains("protea_tab")) {
val protearegex = Regex("(protea_tab.*slug.*,type)") val protearegex = Regex("(protea_tab.*slug.*,type)")

View file

@ -169,7 +169,7 @@ class NeonimeProvider : MainAPI() {
} }
source.apmap { source.apmap {
loadExtractor(it, data, callback) loadExtractor(it, data, subtitleCallback, callback)
} }
return true return true

View file

@ -339,7 +339,7 @@ class NineAnimeProvider : MainAPI() {
val encodedStreamUrl = val encodedStreamUrl =
getEpisodeLinks(it.attr("data-link-id"))?.result?.url ?: return@apmap getEpisodeLinks(it.attr("data-link-id"))?.result?.url ?: return@apmap
val url = decodeVrf(encodedStreamUrl) val url = decodeVrf(encodedStreamUrl)
if (!loadExtractor(url, callback = callback, referer = mainUrl)) { if (!loadExtractor(url, mainUrl, subtitleCallback, callback)) {
callback( callback(
ExtractorLink( ExtractorLink(
this.name, this.name,

View file

@ -3,10 +3,10 @@ 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.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup import org.jsoup.Jsoup
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.util.ArrayList
class NontonAnimeIDProvider : MainAPI() { class NontonAnimeIDProvider : MainAPI() {
override var mainUrl = "https://75.119.159.228" override var mainUrl = "https://75.119.159.228"
@ -175,13 +175,17 @@ class NontonAnimeIDProvider : MainAPI() {
) )
).parsed<EpResponse>().content ).parsed<EpResponse>().content
).select("li").map { ).select("li").map {
val name = Regex("(Episode\\s?[0-9]+)").find(it.selectFirst("a")?.text().toString())?.groupValues?.getOrNull(0) ?: it.selectFirst("a")?.text() val name = Regex("(Episode\\s?[0-9]+)").find(
it.selectFirst("a")?.text().toString()
)?.groupValues?.getOrNull(0) ?: it.selectFirst("a")?.text()
val link = fixUrl(it.selectFirst("a")!!.attr("href")) val link = fixUrl(it.selectFirst("a")!!.attr("href"))
Episode(link, name) Episode(link, name)
}.reversed() }.reversed()
} else { } else {
document.select("ul.misha_posts_wrap2 > li").map { document.select("ul.misha_posts_wrap2 > li").map {
val name = Regex("(Episode\\s?[0-9]+)").find(it.selectFirst("a")?.text().toString())?.groupValues?.getOrNull(0) ?: it.selectFirst("a")?.text() val name = Regex("(Episode\\s?[0-9]+)").find(
it.selectFirst("a")?.text().toString()
)?.groupValues?.getOrNull(0) ?: it.selectFirst("a")?.text()
val link = it.select("a").attr("href") val link = it.select("a").attr("href")
Episode(link, name) Episode(link, name)
}.reversed() }.reversed()
@ -243,7 +247,7 @@ class NontonAnimeIDProvider : MainAPI() {
} }
sources.apmap { sources.apmap {
loadExtractor(it, "$mainUrl/", callback) loadExtractor(it, "$mainUrl/", subtitleCallback, callback)
} }
return true return true

View file

@ -193,7 +193,7 @@ class OploverzProvider : MainAPI() {
} }
sources.apmap { sources.apmap {
loadExtractor(it, data, callback) loadExtractor(it, data, subtitleCallback, callback)
} }
return true return true

View file

@ -189,7 +189,7 @@ class OtakudesuProvider : MainAPI() {
} }
} }
loadExtractor(sources, data, callback) loadExtractor(sources, data, subtitleCallback, callback)
} }

View file

@ -56,7 +56,8 @@ class WcoProvider : MainAPI() {
nameHeader.attr("href").replace("/watch/", "/anime/") nameHeader.attr("href").replace("/watch/", "/anime/")
.replace(Regex("-episode-.*"), "/") .replace(Regex("-episode-.*"), "/")
val isDub = val isDub =
filmPoster!!.selectFirst("> div.film-poster-quality")?.text()?.contains("DUB") filmPoster!!.selectFirst("> div.film-poster-quality")?.text()
?.contains("DUB")
?: false ?: false
val poster = filmPoster.selectFirst("> img")!!.attr("data-src") val poster = filmPoster.selectFirst("> img")!!.attr("data-src")
val set: EnumSet<DubStatus> = val set: EnumSet<DubStatus> =
@ -231,8 +232,8 @@ class WcoProvider : MainAPI() {
} }
for (server in servers) { for (server in servers) {
WcoStream().getSafeUrl(server["link"].toString(), "")?.forEach(callback) WcoStream().getSafeUrl(server["link"].toString(), null, subtitleCallback, callback)
Mcloud().getSafeUrl(server["link"].toString(), "")?.forEach(callback) Mcloud().getSafeUrl(server["link"].toString(), null, subtitleCallback, callback)
} }
return true return true
} }

View file

@ -55,17 +55,18 @@ class ZoroProvider : MainAPI() {
private fun Element.toSearchResult(): SearchResponse? { private fun Element.toSearchResult(): SearchResponse? {
val href = fixUrl(this.select("a").attr("href")) val href = fixUrl(this.select("a").attr("href"))
val title = this.select("h3.film-name").text() val title = this.select("h3.film-name").text()
val dubSub = this.select(".film-poster > .tick.ltr").text() val dubSub = this.select(".film-poster > .tick.ltr").text()
//val episodes = this.selectFirst(".film-poster > .tick-eps")?.text()?.toIntOrNull() //val episodes = this.selectFirst(".film-poster > .tick-eps")?.text()?.toIntOrNull()
val dubExist = dubSub.contains("dub", ignoreCase = true) val dubExist = dubSub.contains("dub", ignoreCase = true)
val subExist = dubSub.contains("sub", ignoreCase = true) val subExist = dubSub.contains("sub", ignoreCase = true)
val episodes = this.selectFirst(".film-poster > .tick.rtl > .tick-eps")?.text()?.let { eps -> val episodes =
//println("REGEX:::: $eps") this.selectFirst(".film-poster > .tick.rtl > .tick-eps")?.text()?.let { eps ->
// current episode / max episode //println("REGEX:::: $eps")
//Regex("Ep (\\d+)/(\\d+)") // current episode / max episode
epRegex.find(eps)?.groupValues?.get(1)?.toIntOrNull() //Regex("Ep (\\d+)/(\\d+)")
} epRegex.find(eps)?.groupValues?.get(1)?.toIntOrNull()
}
if (href.contains("/news/") || title.trim().equals("News", ignoreCase = true)) return null if (href.contains("/news/") || title.trim().equals("News", ignoreCase = true)) return null
val posterUrl = fixUrl(this.select("img").attr("data-src")) val posterUrl = fixUrl(this.select("img").attr("data-src"))
val type = getType(this.select("div.fd-infor > span.fdi-item").text()) val type = getType(this.select("div.fd-infor > span.fdi-item").text())
@ -346,7 +347,7 @@ class ZoroProvider : MainAPI() {
link, link,
).parsed<RapidCloudResponse>().link ).parsed<RapidCloudResponse>().link
val hasLoadedExtractorLink = val hasLoadedExtractorLink =
loadExtractor(extractorLink, "https://rapid-cloud.ru/", callback) loadExtractor(extractorLink, "https://rapid-cloud.ru/", subtitleCallback, callback)
if (!hasLoadedExtractorLink) { if (!hasLoadedExtractorLink) {
extractRabbitStream( extractRabbitStream(

View file

@ -1,5 +1,6 @@
package com.lagradost.cloudstream3.extractors package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.apmap import com.lagradost.cloudstream3.apmap
import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
@ -27,12 +28,16 @@ class Pelisplus(val mainUrl: String) {
private val normalApis = arrayListOf(MultiQuality()) private val normalApis = arrayListOf(MultiQuality())
// https://gogo-stream.com/streaming.php?id=MTE3NDg5 // https://gogo-stream.com/streaming.php?id=MTE3NDg5
suspend fun getUrl(id: String, isCasting: Boolean = false, callback: (ExtractorLink) -> Unit): Boolean { suspend fun getUrl(
id: String,
isCasting: Boolean = false,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
try { try {
normalApis.apmap { api -> normalApis.apmap { api ->
val url = api.getExtractorUrl(id) val url = api.getExtractorUrl(id)
val source = api.getSafeUrl(url) api.getSafeUrl(url, subtitleCallback = subtitleCallback, callback = callback)
source?.forEach { callback.invoke(it) }
} }
val extractorUrl = getExtractorUrl(id) val extractorUrl = getExtractorUrl(id)
@ -50,9 +55,10 @@ class Pelisplus(val mainUrl: String) {
val href = element.attr("href") ?: return@apmap val href = element.attr("href") ?: return@apmap
val qual = if (element.text() val qual = if (element.text()
.contains("HDP") .contains("HDP")
) "1080" else qualityRegex.find(element.text())?.destructured?.component1().toString() ) "1080" else qualityRegex.find(element.text())?.destructured?.component1()
.toString()
if (!loadExtractor(href, link, callback)) { if (!loadExtractor(href, link, subtitleCallback, callback)) {
callback.invoke( callback.invoke(
ExtractorLink( ExtractorLink(
this.name, this.name,
@ -80,12 +86,7 @@ class Pelisplus(val mainUrl: String) {
// Matches vidstream links with extractors // Matches vidstream links with extractors
extractorApis.filter { !it.requiresReferer || !isCasting }.apmap { api -> extractorApis.filter { !it.requiresReferer || !isCasting }.apmap { api ->
if (link.startsWith(api.mainUrl)) { if (link.startsWith(api.mainUrl)) {
val extractedLinks = api.getSafeUrl(link, extractorUrl) api.getSafeUrl(link, extractorUrl, subtitleCallback, callback)
if (extractedLinks?.isNotEmpty() == true) {
extractedLinks.forEach {
callback.invoke(it)
}
}
} }
} }
} }

View file

@ -1,5 +1,6 @@
package com.lagradost.cloudstream3.extractors package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.apmap import com.lagradost.cloudstream3.apmap
import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.ExtractorApi import com.lagradost.cloudstream3.utils.ExtractorApi
@ -12,35 +13,42 @@ class VidSrcExtractor : ExtractorApi() {
override val mainUrl = "https://v2.vidsrc.me" override val mainUrl = "https://v2.vidsrc.me"
override val requiresReferer = false override val requiresReferer = false
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? { override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val iframedoc = app.get(url).document val iframedoc = app.get(url).document
val serverslist = iframedoc.select("div#sources.button_content div#content div#list div").map { val serverslist =
val datahash = it.attr("data-hash") iframedoc.select("div#sources.button_content div#content div#list div").map {
if (datahash.isNotBlank()) { val datahash = it.attr("data-hash")
val links = try { if (datahash.isNotBlank()) {
app.get("$mainUrl/src/$datahash", referer = "https://source.vidsrc.me/").url val links = try {
} catch (e: Exception) { app.get("$mainUrl/src/$datahash", referer = "https://source.vidsrc.me/").url
"" } catch (e: Exception) {
} ""
links }
} else "" links
} } else ""
}
return serverslist.apmap { server -> serverslist.apmap { server ->
val linkfixed = server.replace("https://vidsrc.xyz/","https://embedsito.com/") val linkfixed = server.replace("https://vidsrc.xyz/", "https://embedsito.com/")
if (linkfixed.contains("/pro")) { if (linkfixed.contains("/pro")) {
val srcresponse = app.get(server, referer = mainUrl).text val srcresponse = app.get(server, referer = mainUrl).text
val m3u8Regex = Regex("((https:|http:)//.*\\.m3u8)") val m3u8Regex = Regex("((https:|http:)//.*\\.m3u8)")
val srcm3u8 = m3u8Regex.find(srcresponse)?.value ?: return@apmap listOf() val srcm3u8 = m3u8Regex.find(srcresponse)?.value ?: return@apmap
M3u8Helper.generateM3u8( M3u8Helper.generateM3u8(
name, name,
srcm3u8, srcm3u8,
mainUrl mainUrl
) ).forEach(callback)
} else { } else {
loadExtractor(linkfixed, url) loadExtractor(linkfixed, url, subtitleCallback, callback)
} }
}.flatten() }
} }
} }

View file

@ -1,5 +1,6 @@
package com.lagradost.cloudstream3.extractors package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.apmap import com.lagradost.cloudstream3.apmap
import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.argamap import com.lagradost.cloudstream3.argamap
@ -30,15 +31,19 @@ class Vidstream(val mainUrl: String) {
suspend fun getUrl( suspend fun getUrl(
id: String, id: String,
isCasting: Boolean = false, isCasting: Boolean = false,
callback: (ExtractorLink) -> Unit subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit,
): Boolean { ): Boolean {
val extractorUrl = getExtractorUrl(id) val extractorUrl = getExtractorUrl(id)
argamap( argamap(
{ {
normalApis.apmap { api -> normalApis.apmap { api ->
val url = api.getExtractorUrl(id) val url = api.getExtractorUrl(id)
val source = api.getSafeUrl(url) api.getSafeUrl(
source?.forEach { callback.invoke(it) } url,
callback = callback,
subtitleCallback = subtitleCallback
)
} }
}, { }, {
/** Stolen from GogoanimeProvider.kt extractor */ /** Stolen from GogoanimeProvider.kt extractor */
@ -57,7 +62,7 @@ class Vidstream(val mainUrl: String) {
) "1080" else qualityRegex.find(element.text())?.destructured?.component1() ) "1080" else qualityRegex.find(element.text())?.destructured?.component1()
.toString() .toString()
if (!loadExtractor(href, link, callback)) { if (!loadExtractor(href, link, subtitleCallback, callback)) {
callback.invoke( callback.invoke(
ExtractorLink( ExtractorLink(
this.name, this.name,
@ -84,12 +89,7 @@ class Vidstream(val mainUrl: String) {
// Matches vidstream links with extractors // Matches vidstream links with extractors
extractorApis.filter { !it.requiresReferer || !isCasting }.apmap { api -> extractorApis.filter { !it.requiresReferer || !isCasting }.apmap { api ->
if (link.startsWith(api.mainUrl)) { if (link.startsWith(api.mainUrl)) {
val extractedLinks = api.getSafeUrl(link, extractorUrl) api.getSafeUrl(link, extractorUrl, subtitleCallback, callback)
if (extractedLinks?.isNotEmpty() == true) {
extractedLinks.forEach {
callback.invoke(it)
}
}
} }
} }
} }

View file

@ -1,14 +1,14 @@
package com.lagradost.cloudstream3.extractors package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.ErrorLoadingException import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.safeApiCall
import com.lagradost.cloudstream3.utils.ExtractorApi import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.schemaStripRegex import com.lagradost.cloudstream3.utils.schemaStripRegex
import org.schabi.newpipe.extractor.ServiceList import org.schabi.newpipe.extractor.ServiceList
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory
import org.schabi.newpipe.extractor.stream.SubtitlesStream
import org.schabi.newpipe.extractor.stream.VideoStream import org.schabi.newpipe.extractor.stream.VideoStream
class YoutubeShortLinkExtractor : YoutubeExtractor() { class YoutubeShortLinkExtractor : YoutubeExtractor() {
@ -26,56 +26,56 @@ open class YoutubeExtractor : ExtractorApi() {
companion object { companion object {
private var ytVideos: MutableMap<String, List<VideoStream>> = mutableMapOf() private var ytVideos: MutableMap<String, List<VideoStream>> = mutableMapOf()
private var ytVideosSubtitles: MutableMap<String, List<SubtitlesStream>> = mutableMapOf()
} }
override fun getExtractorUrl(id: String): String { override fun getExtractorUrl(id: String): String {
return "$mainUrl/watch?v=$id" return "$mainUrl/watch?v=$id"
} }
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? { override suspend fun getUrl(
val streams = safeApiCall { url: String,
val streams = ytVideos[url] ?: let { referer: String?,
val link = subtitleCallback: (SubtitleFile) -> Unit,
YoutubeStreamLinkHandlerFactory.getInstance().fromUrl( callback: (ExtractorLink) -> Unit
url.replace( ) {
schemaStripRegex, "" if (ytVideos[url].isNullOrEmpty()) {
) val link =
YoutubeStreamLinkHandlerFactory.getInstance().fromUrl(
url.replace(
schemaStripRegex, ""
) )
val s = object : YoutubeStreamExtractor(
ServiceList.YouTube,
link
) {
}
s.fetchPage()
val streams = s.videoStreams ?: return@let emptyList()
ytVideos[url] = streams
streams
}
if (streams.isEmpty()) {
throw ErrorLoadingException("No Youtube streams")
}
streams
//streams.sortedBy { it.height }
// .firstOrNull { !it.isVideoOnly && it.height > 0 }
// ?: throw ErrorLoadingException("No valid Youtube stream")
}
if (streams is Resource.Success) {
return streams.value.mapNotNull {
if (it.isVideoOnly || it.height <= 0) return@mapNotNull null
ExtractorLink(
this.name,
this.name,
it.url ?: return@mapNotNull null,
"",
it.height
) )
val s = object : YoutubeStreamExtractor(
ServiceList.YouTube,
link
) {
}
s.fetchPage()
ytVideos[url] = s.videoStreams
ytVideosSubtitles[url] = try {
s.subtitlesDefault.filterNotNull()
} catch (e: Exception) {
logError(e)
emptyList()
} }
} else {
return null
} }
ytVideos[url]?.mapNotNull {
if (it.isVideoOnly || it.height <= 0) return@mapNotNull null
ExtractorLink(
this.name,
this.name,
it.url ?: return@mapNotNull null,
"",
it.height
)
}?.forEach(callback)
ytVideosSubtitles[url]?.mapNotNull {
SubtitleFile(it.languageTag ?: return@mapNotNull null, it.url ?: return@mapNotNull null)
}?.forEach(subtitleCallback)
} }
} }

View file

@ -1,6 +1,7 @@
package com.lagradost.cloudstream3.extractors.helper package com.lagradost.cloudstream3.extractors.helper
import android.util.Log import android.util.Log
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.apmap import com.lagradost.cloudstream3.apmap
import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
@ -8,7 +9,11 @@ import com.lagradost.cloudstream3.utils.loadExtractor
class AsianEmbedHelper { class AsianEmbedHelper {
companion object { companion object {
suspend fun getUrls(url: String, callback: (ExtractorLink) -> Unit) { suspend fun getUrls(
url: String,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
// Fetch links // Fetch links
val doc = app.get(url).document val doc = app.get(url).document
val links = doc.select("div#list-server-more > ul > li.linkserver") val links = doc.select("div#list-server-more > ul > li.linkserver")
@ -17,7 +22,7 @@ class AsianEmbedHelper {
val datavid = it.attr("data-video") ?: "" val datavid = it.attr("data-video") ?: ""
//Log.i("AsianEmbed", "Result => (datavid) ${datavid}") //Log.i("AsianEmbed", "Result => (datavid) ${datavid}")
if (datavid.isNotBlank()) { if (datavid.isNotBlank()) {
val res = loadExtractor(datavid, url, callback) val res = loadExtractor(datavid, url, subtitleCallback, callback)
Log.i("AsianEmbed", "Result => ($res) (datavid) $datavid") Log.i("AsianEmbed", "Result => ($res) (datavid) $datavid")
} }
} }

View file

@ -1,5 +1,6 @@
package com.lagradost.cloudstream3.extractors.helper package com.lagradost.cloudstream3.extractors.helper
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities import com.lagradost.cloudstream3.utils.Qualities
@ -10,7 +11,11 @@ class VstreamhubHelper {
private val baseUrl: String = "https://vstreamhub.com" private val baseUrl: String = "https://vstreamhub.com"
private val baseName: String = "Vstreamhub" private val baseName: String = "Vstreamhub"
suspend fun getUrls(url: String, callback: (ExtractorLink) -> Unit) { suspend fun getUrls(
url: String,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
if (url.startsWith(baseUrl)) { if (url.startsWith(baseUrl)) {
// Fetch links // Fetch links
val doc = app.get(url).document.select("script") val doc = app.get(url).document.select("script")
@ -20,7 +25,8 @@ class VstreamhubHelper {
if (innerText.contains("file:")) { if (innerText.contains("file:")) {
val startString = "file: " val startString = "file: "
val aa = innerText.substring(innerText.indexOf(startString)) val aa = innerText.substring(innerText.indexOf(startString))
val linkUrl = aa.substring(startString.length + 1, aa.indexOf("\",")).trim() val linkUrl =
aa.substring(startString.length + 1, aa.indexOf("\",")).trim()
//Log.i(baseName, "Result => (linkUrl) ${linkUrl}") //Log.i(baseName, "Result => (linkUrl) ${linkUrl}")
val exlink = ExtractorLink( val exlink = ExtractorLink(
name = "$baseName m3u8", name = "$baseName m3u8",
@ -33,12 +39,14 @@ class VstreamhubHelper {
callback.invoke(exlink) callback.invoke(exlink)
} }
if (innerText.contains("playerInstance")) { if (innerText.contains("playerInstance")) {
val aa = innerText.substring(innerText.indexOf("playerInstance.addButton")) val aa =
innerText.substring(innerText.indexOf("playerInstance.addButton"))
val startString = "window.open([" val startString = "window.open(["
val bb = aa.substring(aa.indexOf(startString)) val bb = aa.substring(aa.indexOf(startString))
val datavid = bb.substring(startString.length, bb.indexOf("]")).removeSurrounding("\"") val datavid = bb.substring(startString.length, bb.indexOf("]"))
.removeSurrounding("\"")
if (datavid.isNotBlank()) { if (datavid.isNotBlank()) {
loadExtractor(datavid, url, callback) loadExtractor(datavid, url, subtitleCallback, callback)
//Log.i(baseName, "Result => (datavid) ${datavid}") //Log.i(baseName, "Result => (datavid) ${datavid}")
} }
} }

View file

@ -197,9 +197,9 @@ class AllMoviesForYouProvider : MainAPI() {
val soup = app.get(id).document val soup = app.get(id).document
soup.select("body iframe").map { soup.select("body iframe").map {
val link = fixUrl(it.attr("src").replace("streamhub.to/d/", "streamhub.to/e/")) val link = fixUrl(it.attr("src").replace("streamhub.to/d/", "streamhub.to/e/"))
loadExtractor(link, data, callback) loadExtractor(link, data, subtitleCallback, callback)
} }
} else loadExtractor(id, data, callback) } else loadExtractor(id, data, subtitleCallback, callback)
} }
return true return true
} }

View file

@ -2,10 +2,10 @@ package com.lagradost.cloudstream3.movieproviders
import androidx.core.text.parseAsHtml import androidx.core.text.parseAsHtml
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
class AltadefinizioneProvider : MainAPI() { class AltadefinizioneProvider : MainAPI() {
@ -55,16 +55,18 @@ class AltadefinizioneProvider : MainAPI() {
} }
override suspend fun search(query: String): List<SearchResponse> { override suspend fun search(query: String): List<SearchResponse> {
val doc = app.post("$mainUrl/index.php", data = mapOf( val doc = app.post(
"do" to "search", "$mainUrl/index.php", data = mapOf(
"subaction" to "search", "do" to "search",
"story" to query, "subaction" to "search",
"sortby" to "news_read" "story" to query,
)).document "sortby" to "news_read"
)
).document
return doc.select("div.box").map { return doc.select("div.box").map {
val title = it.selectFirst("img")!!.attr("alt") val title = it.selectFirst("img")!!.attr("alt")
val link = it.selectFirst("a")!!.attr("href") val link = it.selectFirst("a")!!.attr("href")
val image = mainUrl+it.selectFirst("img")!!.attr("src") val image = mainUrl + it.selectFirst("img")!!.attr("src")
val quality = getQualityFromString(it.selectFirst("span")!!.text()) val quality = getQualityFromString(it.selectFirst("span")!!.text())
MovieSearchResponse( MovieSearchResponse(
@ -83,18 +85,20 @@ class AltadefinizioneProvider : MainAPI() {
override suspend fun load(url: String): LoadResponse { override suspend fun load(url: String): LoadResponse {
val page = app.get(url) val page = app.get(url)
val document = page.document val document = page.document
val title = document.selectFirst(" h1 > a")!!.text().replace("streaming","") val title = document.selectFirst(" h1 > a")!!.text().replace("streaming", "")
val description = document.select("#sfull").toString().substringAfter("altadefinizione").substringBeforeLast("fonte trama").parseAsHtml().toString() val description = document.select("#sfull").toString().substringAfter("altadefinizione")
.substringBeforeLast("fonte trama").parseAsHtml().toString()
val rating = null val rating = null
val year = document.selectFirst("#details > li:nth-child(2)")!!.childNode(2).toString().filter { it.isDigit() }.toInt() val year = document.selectFirst("#details > li:nth-child(2)")!!.childNode(2).toString()
.filter { it.isDigit() }.toInt()
val poster = fixUrl(document.selectFirst("div.thumbphoto > img")!!.attr("src")) val poster = fixUrl(document.selectFirst("div.thumbphoto > img")!!.attr("src"))
val recomm = document.select("ul.related-list > li").map { val recomm = document.select("ul.related-list > li").map {
val href = it.selectFirst("a")!!.attr("href") val href = it.selectFirst("a")!!.attr("href")
val posterUrl = mainUrl + it.selectFirst("img")!!.attr("src") val posterUrl = mainUrl + it.selectFirst("img")!!.attr("src")
val name = it.selectFirst("img")!!.attr("alt") val name = it.selectFirst("img")!!.attr("alt")
MovieSearchResponse( MovieSearchResponse(
name, name,
href, href,
@ -110,29 +114,29 @@ class AltadefinizioneProvider : MainAPI() {
val actors: List<ActorData> = val actors: List<ActorData> =
document.select("#staring > a").map { document.select("#staring > a").map {
ActorData(actor = Actor(it.text())) ActorData(actor = Actor(it.text()))
} }
val tags: List<String> = document.select("#details > li:nth-child(1) > a").map { it.text() } val tags: List<String> = document.select("#details > li:nth-child(1) > a").map { it.text() }
val trailerurl = document.selectFirst("#showtrailer > div > div > iframe")?.attr("src") val trailerurl = document.selectFirst("#showtrailer > div > div > iframe")?.attr("src")
return newMovieLoadResponse( return newMovieLoadResponse(
title, title,
url, url,
TvType.Movie, TvType.Movie,
url url
) { ) {
posterUrl = fixUrlNull(poster) posterUrl = fixUrlNull(poster)
this.year = year this.year = year
this.plot = description this.plot = description
this.rating = rating this.rating = rating
this.recommendations = recomm this.recommendations = recomm
this.duration = null this.duration = null
this.actors = actors this.actors = actors
this.tags = tags this.tags = tags
addTrailer(trailerurl) addTrailer(trailerurl)
}
} }
}
override suspend fun loadLinks( override suspend fun loadLinks(
@ -142,23 +146,21 @@ class AltadefinizioneProvider : MainAPI() {
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
val doc = app.get(data).document val doc = app.get(data).document
if (doc.select("div.guardahd-player").isNullOrEmpty()){ if (doc.select("div.guardahd-player").isNullOrEmpty()) {
val videoUrl = doc.select("input").filter { it.hasAttr("data-mirror") }.last().attr("value") val videoUrl =
loadExtractor(videoUrl, data, callback) doc.select("input").filter { it.hasAttr("data-mirror") }.last().attr("value")
loadExtractor(videoUrl, data, subtitleCallback, callback)
doc.select("#mirrors > li > a").forEach { doc.select("#mirrors > li > a").forEach {
loadExtractor(fixUrl(it.attr("data-target")), data, callback) loadExtractor(fixUrl(it.attr("data-target")), data, subtitleCallback, callback)
} }
} } else {
else{
val pagelinks = doc.select("div.guardahd-player").select("iframe").attr("src") val pagelinks = doc.select("div.guardahd-player").select("iframe").attr("src")
val docLinks = app.get(pagelinks).document val docLinks = app.get(pagelinks).document
docLinks.select("body > div > ul > li").forEach { docLinks.select("body > div > ul > li").forEach {
loadExtractor(fixUrl(it.attr("data-link")), data, callback) loadExtractor(fixUrl(it.attr("data-link")), data, subtitleCallback, callback)
} }
} }
return true return true
} }
} }

View file

@ -27,8 +27,14 @@ open class BflixProvider : MainAPI() {
Pair("Movies", "div.tab-content[data-name=movies] div.filmlist div.item"), Pair("Movies", "div.tab-content[data-name=movies] div.filmlist div.item"),
Pair("Shows", "div.tab-content[data-name=shows] div.filmlist div.item"), Pair("Shows", "div.tab-content[data-name=shows] div.filmlist div.item"),
Pair("Trending", "div.tab-content[data-name=trending] 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(
Pair("Latest TV-Series", "div.container section.bl:contains(Latest TV-Series) div.filmlist div.item"), "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 ((name, element) in testa) try { for ((name, element) in testa) try {
val test = soup.select(element).map { val test = soup.select(element).map {
@ -57,7 +63,8 @@ open class BflixProvider : MainAPI() {
} }
//Credits to https://github.com/jmir1 //Credits to https://github.com/jmir1
private val key = "5uLKesbh0nkrpPq9VwMC6+tQBdomjJ4HNl/fWOSiREvAYagT8yIG7zx2D13UZFXc" //key credits to @Modder4869 private val key =
"5uLKesbh0nkrpPq9VwMC6+tQBdomjJ4HNl/fWOSiREvAYagT8yIG7zx2D13UZFXc" //key credits to @Modder4869
private fun getVrf(id: String): String? { private fun getVrf(id: String): String? {
val reversed = ue(encode(id) + "0000000").slice(0..5).reversed() val reversed = ue(encode(id) + "0000000").slice(0..5).reversed()
@ -216,7 +223,7 @@ open class BflixProvider : MainAPI() {
} }
val tags = soup.select("div.info .meta div:contains(Genre) a").map { it.text() } val tags = soup.select("div.info .meta div:contains(Genre) a").map { it.text() }
val episodes = Jsoup.parse( val episodes = Jsoup.parse(
app.get( app.get(
"$mainUrl/ajax/film/servers?id=$movieid&vrf=$movieidencoded" "$mainUrl/ajax/film/servers?id=$movieid&vrf=$movieidencoded"
).parsed<Response>().html ).parsed<Response>().html
@ -232,15 +239,16 @@ open class BflixProvider : MainAPI() {
val eptitle = it.selectFirst(".episode a span.name")!!.text() val eptitle = it.selectFirst(".episode a span.name")!!.text()
val secondtitle = it.selectFirst(".episode a span")!!.text() val secondtitle = it.selectFirst(".episode a span")!!.text()
.replace(Regex("(Episode (\\d+):|Episode (\\d+)-|Episode (\\d+))"),"") ?: "" .replace(Regex("(Episode (\\d+):|Episode (\\d+)-|Episode (\\d+))"), "") ?: ""
Episode( Episode(
href, href,
secondtitle+eptitle, secondtitle + eptitle,
season, season,
episode, episode,
) )
} }
val tvType = if (url.contains("/movie/") && episodes.size == 1) TvType.Movie else TvType.TvSeries val tvType =
if (url.contains("/movie/") && episodes.size == 1) TvType.Movie else TvType.TvSeries
val recommendations = val recommendations =
soup.select("div.bl-2 section.bl div.content div.filmlist div.item") soup.select("div.bl-2 section.bl div.content div.filmlist div.item")
?.mapNotNull { element -> ?.mapNotNull { element ->
@ -261,9 +269,12 @@ open class BflixProvider : MainAPI() {
val durationregex = Regex("((\\d+) min)") val durationregex = Regex("((\\d+) min)")
val yearegex = Regex("<span>(\\d+)<\\/span>") val yearegex = Regex("<span>(\\d+)<\\/span>")
val duration = if (durationdoc.contains("na min")) null val duration = if (durationdoc.contains("na min")) null
else durationregex.find(durationdoc)?.destructured?.component1()?.replace(" min","")?.toIntOrNull() else durationregex.find(durationdoc)?.destructured?.component1()?.replace(" min", "")
val year = if (mainUrl == "https://bflix.ru") { yearegex.find(durationdoc)?.destructured?.component1() ?.toIntOrNull()
?.replace(Regex("<span>|<\\/span>"),"") } else null 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(
@ -343,7 +354,8 @@ open class BflixProvider : MainAPI() {
val a = it.select("a").map { val a = it.select("a").map {
it.attr("data-kname") it.attr("data-kname")
} }
val tvType = if (data.contains("movie/") && a.size == 1) TvType.Movie else TvType.TvSeries val tvType =
if (data.contains("movie/") && a.size == 1) TvType.Movie else TvType.TvSeries
val servers = if (tvType == TvType.Movie) it.select(".episode a").attr("data-ep") val servers = if (tvType == TvType.Movie) it.select(".episode a").attr("data-ep")
else else
it.select(".episode a[href=$cleandata]").attr("data-ep") it.select(".episode a[href=$cleandata]").attr("data-ep")
@ -364,7 +376,7 @@ open class BflixProvider : MainAPI() {
?.replace("/embed/", "/e/")?.replace(Regex("(\\?sub.info.*)"), "") ?.replace("/embed/", "/e/")?.replace(Regex("(\\?sub.info.*)"), "")
}.apmap { url -> }.apmap { url ->
loadExtractor( loadExtractor(
url, data, callback url, data, subtitleCallback, callback
) )
} }
//Apparently any server works, I haven't found any diference //Apparently any server works, I haven't found any diference

View file

@ -155,7 +155,7 @@ class CineblogProvider : MainAPI() {
rating, rating,
null, null,
null, null,
null, mutableListOf(),
recomm recomm
) )
} else { } else {
@ -205,7 +205,7 @@ class CineblogProvider : MainAPI() {
val url2= Regex("""src='((.|\\n)*?)'""").find(test.text)?.groups?.get(1)?.value.toString() val url2= Regex("""src='((.|\\n)*?)'""").find(test.text)?.groups?.get(1)?.value.toString()
val trueUrl = app.get(url2, headers = mapOf("referer" to mainUrl)).url val trueUrl = app.get(url2, headers = mapOf("referer" to mainUrl)).url
loadExtractor(trueUrl, data, callback) loadExtractor(trueUrl, data, subtitleCallback, callback)
return true return true
} }

View file

@ -6,7 +6,7 @@ import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor import com.lagradost.cloudstream3.utils.loadExtractor
class CinecalidadProvider:MainAPI() { class CinecalidadProvider : MainAPI() {
override var mainUrl = "https://cinecalidad.lol" override var mainUrl = "https://cinecalidad.lol"
override var name = "Cinecalidad" override var name = "Cinecalidad"
override var lang = "es" override var lang = "es"
@ -98,9 +98,10 @@ class CinecalidadProvider:MainAPI() {
val href = li.selectFirst("a")!!.attr("href") val href = li.selectFirst("a")!!.attr("href")
val epThumb = li.selectFirst("img.lazy")!!.attr("data-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 -> val seasonid =
str.split("-").mapNotNull { subStr -> subStr.toIntOrNull() } li.selectFirst(".numerando")!!.text().replace(Regex("(S|E)"), "").let { str ->
} str.split("-").mapNotNull { subStr -> subStr.toIntOrNull() }
}
val isValid = seasonid.size == 2 val isValid = seasonid.size == 2
val episode = if (isValid) seasonid.getOrNull(1) else null val episode = if (isValid) seasonid.getOrNull(1) else null
val season = if (isValid) seasonid.getOrNull(0) else null val season = if (isValid) seasonid.getOrNull(0) else null
@ -112,7 +113,8 @@ class CinecalidadProvider:MainAPI() {
if (epThumb.contains("svg")) null else 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) {
TvType.TvSeries -> { TvType.TvSeries -> {
TvSeriesLoadResponse( TvSeriesLoadResponse(
title, title,
@ -156,18 +158,18 @@ class CinecalidadProvider:MainAPI() {
val url = it.attr("data-option") val url = it.attr("data-option")
if (url.startsWith("https://cinestart.net")) { if (url.startsWith("https://cinestart.net")) {
val extractor = Cinestart() val extractor = Cinestart()
extractor.getSafeUrl(url)?.forEach { link -> extractor.getSafeUrl(url, null, subtitleCallback, callback)
callback.invoke(link)
}
} else { } else {
loadExtractor(url, mainUrl, callback) loadExtractor(url, mainUrl, subtitleCallback, callback)
} }
if (url.startsWith("https://cinecalidad.lol")) { if (url.startsWith("https://cinecalidad.lol")) {
val cineurlregex = Regex("(https:\\/\\/cinecalidad\\.lol\\/play\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") val cineurlregex =
Regex("(https:\\/\\/cinecalidad\\.lol\\/play\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
cineurlregex.findAll(url).map { cineurlregex.findAll(url).map {
it.value.replace("/play/","/play/r.php") it.value.replace("/play/", "/play/r.php")
}.toList().apmap { }.toList().apmap {
app.get(it, app.get(
it,
headers = mapOf( headers = mapOf(
"Host" to "cinecalidad.lol", "Host" to "cinecalidad.lol",
"User-Agent" to USER_AGENT, "User-Agent" to USER_AGENT,
@ -182,57 +184,61 @@ class CinecalidadProvider:MainAPI() {
"Sec-Fetch-Site" to "same-origin", "Sec-Fetch-Site" to "same-origin",
"Sec-Fetch-User" to "?1", "Sec-Fetch-User" to "?1",
), ),
allowRedirects = false).okhttpResponse.headers.values("location").apmap { extractedurl -> allowRedirects = false
if (extractedurl.contains("cinestart")) { ).okhttpResponse.headers.values("location").apmap { extractedurl ->
loadExtractor(extractedurl, mainUrl, callback) if (extractedurl.contains("cinestart")) {
loadExtractor(extractedurl, mainUrl, subtitleCallback, callback)
} }
} }
} }
} }
} }
if (datatext.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")
val url = it.attr("data-option") .apmap {
if (url.startsWith("https://cinestart.net")) { val url = it.attr("data-option")
val extractor = Cinestart() if (url.startsWith("https://cinestart.net")) {
extractor.getSafeUrl(url)?.forEach { link -> val extractor = Cinestart()
callback.invoke(link) extractor.getSafeUrl(url, null, subtitleCallback, callback)
} else {
loadExtractor(url, mainUrl, subtitleCallback, callback)
} }
} else {
loadExtractor(url, mainUrl, callback)
}
if (url.startsWith("https://cinecalidad.lol")) { if (url.startsWith("https://cinecalidad.lol")) {
val cineurlregex = Regex("(https:\\/\\/cinecalidad\\.lol\\/play\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)") val cineurlregex =
cineurlregex.findAll(url).map { Regex("(https:\\/\\/cinecalidad\\.lol\\/play\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
it.value.replace("/play/","/play/r.php") cineurlregex.findAll(url).map {
}.toList().apmap { it.value.replace("/play/", "/play/r.php")
app.get(it, }.toList().apmap {
headers = mapOf( app.get(
"Host" to "cinecalidad.lol", it,
"User-Agent" to USER_AGENT, headers = mapOf(
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", "Host" to "cinecalidad.lol",
"Accept-Language" to "en-US,en;q=0.5", "User-Agent" to USER_AGENT,
"DNT" to "1", "Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Connection" to "keep-alive", "Accept-Language" to "en-US,en;q=0.5",
"Referer" to data, "DNT" to "1",
"Upgrade-Insecure-Requests" to "1", "Connection" to "keep-alive",
"Sec-Fetch-Dest" to "iframe", "Referer" to data,
"Sec-Fetch-Mode" to "navigate", "Upgrade-Insecure-Requests" to "1",
"Sec-Fetch-Site" to "same-origin", "Sec-Fetch-Dest" to "iframe",
"Sec-Fetch-User" to "?1", "Sec-Fetch-Mode" to "navigate",
), "Sec-Fetch-Site" to "same-origin",
allowRedirects = false).okhttpResponse.headers.values("location").apmap { extractedurl -> "Sec-Fetch-User" to "?1",
if (extractedurl.contains("cinestart")) { ),
loadExtractor(extractedurl, mainUrl, callback) allowRedirects = false
).okhttpResponse.headers.values("location").apmap { extractedurl ->
if (extractedurl.contains("cinestart")) {
loadExtractor(extractedurl, mainUrl, subtitleCallback, callback)
}
} }
} }
} }
} }
} if (datatext.contains("Subtítulo LAT") || datatext.contains("Forzados LAT")) {
if (datatext.contains("Subtítulo LAT") || datatext.contains("Forzados LAT")) {
doc.select("#panel_descarga.pane a").apmap { doc.select("#panel_descarga.pane a").apmap {
val link = if (data.contains("serie") || data.contains("episodio")) "${data}${it.attr("href")}" val link =
else it.attr("href") if (data.contains("serie") || data.contains("episodio")) "${data}${it.attr("href")}"
else it.attr("href")
val docsub = app.get(link) val docsub = app.get(link)
val linksub = docsub.document val linksub = docsub.document
val validsub = docsub.text val validsub = docsub.text
@ -241,8 +247,11 @@ class CinecalidadProvider:MainAPI() {
val langdoc = linksub.selectFirst("div.titulo h3")!!.text() val langdoc = linksub.selectFirst("div.titulo h3")!!.text()
val reallang = langregex.find(langdoc)?.destructured?.component1() val reallang = langregex.find(langdoc)?.destructured?.component1()
linksub.select("a.link").apmap { linksub.select("a.link").apmap {
val sublink = if (data.contains("serie") || data.contains("episodio")) "${data}${it.attr("href")}" val sublink =
else it.attr("href") if (data.contains("serie") || data.contains("episodio")) "${data}${
it.attr("href")
}"
else it.attr("href")
subtitleCallback( subtitleCallback(
SubtitleFile(reallang!!, sublink) SubtitleFile(reallang!!, sublink)
) )

View file

@ -227,7 +227,7 @@ class CuevanaProvider : MainAPI() {
val json = parseJson<Femcuevana>(url) val json = parseJson<Femcuevana>(url)
val link = json.url val link = json.url
if (link.contains("fembed")) { if (link.contains("fembed")) {
loadExtractor(link, data, callback) loadExtractor(link, data, subtitleCallback, callback)
} }
} }
} }
@ -281,7 +281,7 @@ class CuevanaProvider : MainAPI() {
), ),
data = mapOf(Pair("url", gotolink)) data = mapOf(Pair("url", gotolink))
).okhttpResponse.headers.values("location").apmap { golink -> ).okhttpResponse.headers.values("location").apmap { golink ->
loadExtractor(golink, data, callback) loadExtractor(golink, data, subtitleCallback, callback)
} }
} }
} }
@ -311,7 +311,7 @@ class CuevanaProvider : MainAPI() {
), ),
data = mapOf(Pair("h", inlink)) data = mapOf(Pair("h", inlink))
).okhttpResponse.headers.values("location").apmap { link -> ).okhttpResponse.headers.values("location").apmap { link ->
loadExtractor(link, data, callback) loadExtractor(link, data, subtitleCallback, callback)
} }
} }
} }

View file

@ -147,7 +147,7 @@ class DoramasYTProvider : MainAPI() {
callback.invoke(link) callback.invoke(link)
} }
} else { } else {
loadExtractor(url, mainUrl, callback) loadExtractor(url, mainUrl, subtitleCallback, callback)
} }
} }
return true return true

View file

@ -50,14 +50,15 @@ class DramaSeeProvider : MainAPI() {
override suspend fun search(query: String): List<SearchResponse> { override suspend fun search(query: String): List<SearchResponse> {
val url = "$mainUrl/search?q=$query" val url = "$mainUrl/search?q=$query"
val document = app.get(url).document val document = app.get(url).document
val posters = document.select ("div.film-poster") val posters = document.select("div.film-poster")
return posters.mapNotNull { return posters.mapNotNull {
val innerA = it.select("a") ?: return@mapNotNull null val innerA = it.select("a") ?: return@mapNotNull null
val link = fixUrlNull(innerA.attr("href")) ?: return@mapNotNull null val link = fixUrlNull(innerA.attr("href")) ?: return@mapNotNull null
val title = innerA.attr("title") ?: return@mapNotNull null val title = innerA.attr("title") ?: return@mapNotNull null
val year = Regex(""".*\((\d{4})\)""").find(title)?.groupValues?.getOrNull(1)?.toIntOrNull() val year =
Regex(""".*\((\d{4})\)""").find(title)?.groupValues?.getOrNull(1)?.toIntOrNull()
val imgSrc = it.select("img")?.attr("data-src") ?: return@mapNotNull null val imgSrc = it.select("img")?.attr("data-src") ?: return@mapNotNull null
val image = fixUrlNull(imgSrc) val image = fixUrlNull(imgSrc)
@ -193,7 +194,7 @@ class DramaSeeProvider : MainAPI() {
val status = element.attr("data-status") ?: return@forEach val status = element.attr("data-status") ?: return@forEach
if (status != "1") return@forEach if (status != "1") return@forEach
val extractorData = element.attr("data-video") ?: return@forEach val extractorData = element.attr("data-video") ?: return@forEach
loadExtractor(extractorData, iframe.url, callback) loadExtractor(extractorData, iframe.url, subtitleCallback, callback)
} }
}, { }, {
val iv = "9262859232435825" val iv = "9262859232435825"

View file

@ -206,7 +206,7 @@ class DramaidProvider : MainAPI() {
}.apmap { }.apmap {
when { when {
it.contains("motonews.club") -> invokeDriveSource(it, this.name, subtitleCallback, callback) it.contains("motonews.club") -> invokeDriveSource(it, this.name, subtitleCallback, callback)
else -> loadExtractor(it, data, callback) else -> loadExtractor(it, data, subtitleCallback, callback)
} }
} }

View file

@ -87,7 +87,7 @@ class ElifilmsProvider : MainAPI() {
val encodedurl = it.attr("data-id") val encodedurl = it.attr("data-id")
val urlDecoded = base64Decode(encodedurl) val urlDecoded = base64Decode(encodedurl)
val url = fixUrl(urlDecoded) val url = fixUrl(urlDecoded)
loadExtractor(url, data, callback) loadExtractor(url, data, subtitleCallback, callback)
} }
return true return true
} }

View file

@ -170,7 +170,7 @@ class EntrepeliculasyseriesProvider:MainAPI() {
data = mapOf(Pair("h", postkey)), data = mapOf(Pair("h", postkey)),
allowRedirects = false allowRedirects = false
).okhttpResponse.headers.values("location").apmap { ).okhttpResponse.headers.values("location").apmap {
loadExtractor(it, data, callback) loadExtractor(it, data, subtitleCallback, callback)
} }
} }
} }

View file

@ -189,7 +189,7 @@ class EstrenosDoramasProvider : MainAPI() {
val document = app.get(data).document val document = app.get(data).document
document.select("div.tab_container iframe").apmap { container -> document.select("div.tab_container iframe").apmap { container ->
val directlink = fixUrl(container.attr("src")) val directlink = fixUrl(container.attr("src"))
loadExtractor(directlink, data, callback) loadExtractor(directlink, data, subtitleCallback, callback)
if (directlink.contains("/repro/amz/")) { if (directlink.contains("/repro/amz/")) {
val amzregex = Regex("https:\\/\\/repro3\\.estrenosdoramas\\.us\\/repro\\/amz\\/examples\\/.*\\.php\\?key=.*\$") val amzregex = Regex("https:\\/\\/repro3\\.estrenosdoramas\\.us\\/repro\\/amz\\/examples\\/.*\\.php\\?key=.*\$")
@ -239,7 +239,7 @@ class EstrenosDoramasProvider : MainAPI() {
).text ).text
val extracteklink = link.substringAfter("\"urlremoto\":\"").substringBefore("\"}") val extracteklink = link.substringAfter("\"urlremoto\":\"").substringBefore("\"}")
.replace("\\/", "/").replace("//ok.ru/","http://ok.ru/") .replace("\\/", "/").replace("//ok.ru/","http://ok.ru/")
loadExtractor(extracteklink, data, callback) loadExtractor(extracteklink, data, subtitleCallback, callback)
} }
} }

View file

@ -2,8 +2,9 @@ package com.lagradost.cloudstream3.movieproviders
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.*
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup import org.jsoup.Jsoup
import org.jsoup.select.Elements import org.jsoup.select.Elements
@ -58,10 +59,11 @@ class FilmanProvider : MainAPI() {
val series = lists[3].select("#item-list > div:not(.clearfix)") val series = lists[3].select("#item-list > div:not(.clearfix)")
if (movies.isEmpty() && series.isEmpty()) return ArrayList() if (movies.isEmpty() && series.isEmpty()) return ArrayList()
fun getVideos(type: TvType, items: Elements): List<SearchResponse> { fun getVideos(type: TvType, items: Elements): List<SearchResponse> {
return items.mapNotNull { i -> return items.mapNotNull { i ->
val href = i.selectFirst(".poster > a")?.attr("href")?: return@mapNotNull null val href = i.selectFirst(".poster > a")?.attr("href") ?: return@mapNotNull null
val img = i.selectFirst(".poster > a > img")?.attr("src")?.replace("/thumb/", "/big/") val img =
val name = i.selectFirst(".film_title")?.text()?: return@mapNotNull null i.selectFirst(".poster > a > img")?.attr("src")?.replace("/thumb/", "/big/")
val name = i.selectFirst(".film_title")?.text() ?: return@mapNotNull null
val year = i.selectFirst(".film_year")?.text()?.toIntOrNull() val year = i.selectFirst(".film_year")?.text()?.toIntOrNull()
if (type === TvType.TvSeries) { if (type === TvType.TvSeries) {
TvSeriesSearchResponse( TvSeriesSearchResponse(
@ -136,7 +138,7 @@ class FilmanProvider : MainAPI() {
document?.select(".link-to-video")?.apmap { item -> document?.select(".link-to-video")?.apmap { item ->
val decoded = base64Decode(item.select("a").attr("data-iframe")) val decoded = base64Decode(item.select("a").attr("data-iframe"))
val link = tryParseJson<LinkElement>(decoded)?.src ?: return@apmap val link = tryParseJson<LinkElement>(decoded)?.src ?: return@apmap
loadExtractor(link, null, callback) loadExtractor(link, subtitleCallback, callback)
} }
return true return true
} }

View file

@ -224,15 +224,15 @@ class FilmpertuttiProvider : MainAPI() {
tryParseJson<List<String>>(data)?.apmap { id -> tryParseJson<List<String>>(data)?.apmap { id ->
if (id.contains("buckler")){ if (id.contains("buckler")){
val id2 = unshorten_linkup(id).trim().replace("/v/","/e/").replace("/f/","/e/") val id2 = unshorten_linkup(id).trim().replace("/v/","/e/").replace("/f/","/e/")
loadExtractor(id2, data, callback) loadExtractor(id2, data, subtitleCallback, callback)
} }
else if (id.contains("isecure")){ else if (id.contains("isecure")){
val doc1 = app.get(id).document val doc1 = app.get(id).document
val id2 = doc1.selectFirst("iframe")!!.attr("src") val id2 = doc1.selectFirst("iframe")!!.attr("src")
loadExtractor(id2, data, callback) loadExtractor(id2, data, subtitleCallback, callback)
} }
else{ else{
loadExtractor(id, data, callback) loadExtractor(id, data, subtitleCallback, callback)
} }
} }
return true return true

View file

@ -68,7 +68,7 @@ class FrenchStreamProvider : MainAPI() {
?.mapNotNull { // all the tags like action, thriller ...; unused variable ?.mapNotNull { // all the tags like action, thriller ...; unused variable
it?.text() it?.text()
} }
return newMovieLoadResponse(title,url,TvType.Movie,url) { return newMovieLoadResponse(title, url, TvType.Movie, url) {
this.posterUrl = poster this.posterUrl = poster
addRating(soup.select("div.fr-count > div").text()) addRating(soup.select("div.fr-count > div").text())
this.year = soup.select("ul.flist-col > li").getOrNull(2)?.text()?.toIntOrNull() this.year = soup.select("ul.flist-col > li").getOrNull(2)?.text()?.toIntOrNull()
@ -82,8 +82,7 @@ class FrenchStreamProvider : MainAPI() {
//println("listeEpisode:") //println("listeEpisode:")
val episodeList = if ("<a" !in (listEpisode[0]).toString()) { // check if VF is empty val episodeList = if ("<a" !in (listEpisode[0]).toString()) { // check if VF is empty
listEpisode[1] // no vf, return vostfr listEpisode[1] // no vf, return vostfr
} } else {
else {
listEpisode[0] // no vostfr, return vf listEpisode[0] // no vostfr, return vf
} }
@ -221,9 +220,9 @@ class FrenchStreamProvider : MainAPI() {
servers.apmap { servers.apmap {
for (extractor in extractorApis) { for (extractor in extractorApis) {
if (it.first.contains(extractor.name, ignoreCase = true)) { if (it.first.contains(extractor.name, ignoreCase = true)) {
// val name = it.first // val name = it.first
// print("true for $name") // print("true for $name")
extractor.getSafeUrl(it.second, it.second)?.forEach(callback) extractor.getSafeUrl(it.second, it.second, subtitleCallback, callback)
break break
} }
} }

View file

@ -101,7 +101,7 @@ class HDMovie5 : MainAPI() {
(doc.select("#repimdb>strong").text().toFloatOrNull()?.times(1000))?.toInt(), (doc.select("#repimdb>strong").text().toFloatOrNull()?.times(1000))?.toInt(),
info.select(".sgeneros>a").map { it.text() }, info.select(".sgeneros>a").map { it.text() },
info.select(".runtime").text().substringBefore(" Min.").toIntOrNull(), info.select(".runtime").text().substringBefore(" Min.").toIntOrNull(),
null, mutableListOf(),
doc.select("#single_relacionados>article>a").map { doc.select("#single_relacionados>article>a").map {
val img = it.select("img") val img = it.select("img")
MovieSearchResponse( MovieSearchResponse(
@ -149,7 +149,7 @@ class HDMovie5 : MainAPI() {
val html = p.parsedSafe<PlayerAjaxResponse>()?.embedURL ?: return@apmapIndexed false val html = p.parsedSafe<PlayerAjaxResponse>()?.embedURL ?: return@apmapIndexed false
val doc = Jsoup.parse(html) val doc = Jsoup.parse(html)
val link = doc.select("iframe").attr("src") val link = doc.select("iframe").attr("src")
loadExtractor(httpsify(link), "$mainUrl/", callback) loadExtractor(httpsify(link), "$mainUrl/", subtitleCallback, callback)
}.contains(true) }.contains(true)
} }
} }

View file

@ -215,7 +215,7 @@ class IHaveNoTvProvider : MainAPI() {
val iframe = soup.selectFirst("#videoWrap iframe") val iframe = soup.selectFirst("#videoWrap iframe")
if (iframe != null) { if (iframe != null) {
loadExtractor(iframe.attr("src"), null, callback) loadExtractor(iframe.attr("src"), null, subtitleCallback, callback)
} }
return true return true
} }

View file

@ -365,7 +365,7 @@ class IdlixProvider : MainAPI() {
if (source.startsWith("https://uservideo.xyz")) { if (source.startsWith("https://uservideo.xyz")) {
source = app.get(source).document.select("iframe").attr("src") source = app.get(source).document.select("iframe").attr("src")
} }
loadExtractor(source, data, callback) loadExtractor(source, data, subtitleCallback, callback)
} }
} }
} }

View file

@ -48,7 +48,9 @@ class KdramaHoodProvider : MainAPI() {
val rex = Regex("\\((\\d+)") val rex = Regex("\\((\\d+)")
//Log.i(this.name, "Result => (rex value) ${rex.find(yearText)?.value}") //Log.i(this.name, "Result => (rex value) ${rex.find(yearText)?.value}")
rex.find(yearText)?.value?.toIntOrNull() rex.find(yearText)?.value?.toIntOrNull()
} catch (e: Exception) { null } } catch (e: Exception) {
null
}
MovieSearchResponse( MovieSearchResponse(
name = title, name = title,
@ -67,7 +69,7 @@ class KdramaHoodProvider : MainAPI() {
val url = "$mainUrl/?s=$query" val url = "$mainUrl/?s=$query"
val html = app.get(url).document val html = app.get(url).document
val document = html.getElementsByTag("body") val document = html.getElementsByTag("body")
.select("div.item_1.items > div.item") ?: return listOf() .select("div.item_1.items > div.item") ?: return listOf()
return document.mapNotNull { return document.mapNotNull {
if (it == null) { if (it == null) {
@ -105,15 +107,21 @@ class KdramaHoodProvider : MainAPI() {
val startLink = "https://kdramahood.com/drama-release-year/" val startLink = "https://kdramahood.com/drama-release-year/"
var res: Int? = null var res: Int? = null
info?.select("div.metadatac")?.forEach { info?.select("div.metadatac")?.forEach {
if (res != null) { return@forEach } if (res != null) {
if (it == null) { return@forEach } return@forEach
}
if (it == null) {
return@forEach
}
val yearLink = it.select("a").attr("href") ?: return@forEach val yearLink = it.select("a").attr("href") ?: return@forEach
if (yearLink.startsWith(startLink)) { if (yearLink.startsWith(startLink)) {
res = yearLink.substring(startLink.length).replace("/", "").toIntOrNull() res = yearLink.substring(startLink.length).replace("/", "").toIntOrNull()
} }
} }
res res
} catch (e: Exception) { null } } catch (e: Exception) {
null
}
val recs = doc.select("div.sidebartv > div.tvitemrel").mapNotNull { val recs = doc.select("div.sidebartv > div.tvitemrel").mapNotNull {
val a = it?.select("a") ?: return@mapNotNull null val a = it?.select("a") ?: return@mapNotNull null
@ -161,10 +169,13 @@ class KdramaHoodProvider : MainAPI() {
} }
//Fetch default source and subtitles //Fetch default source and subtitles
epVidLinkEl.select("div.embed2")?.forEach { defsrc -> epVidLinkEl.select("div.embed2")?.forEach { defsrc ->
if (defsrc == null) { return@forEach } if (defsrc == null) {
return@forEach
}
val scriptstring = defsrc.toString() val scriptstring = defsrc.toString()
if (scriptstring.contains("sources: [{")) { if (scriptstring.contains("sources: [{")) {
"(?<=playerInstance2.setup\\()([\\s\\S]*?)(?=\\);)".toRegex().find(scriptstring)?.value?.let { itemjs -> "(?<=playerInstance2.setup\\()([\\s\\S]*?)(?=\\);)".toRegex()
.find(scriptstring)?.value?.let { itemjs ->
listOfLinks.add("$mainUrl$itemjs") listOfLinks.add("$mainUrl$itemjs")
} }
} }
@ -264,7 +275,7 @@ class KdramaHoodProvider : MainAPI() {
//Log.i(this.name, "Result => (url) $url") //Log.i(this.name, "Result => (url) $url")
when { when {
url.startsWith("https://asianembed.io") -> { url.startsWith("https://asianembed.io") -> {
AsianEmbedHelper.getUrls(url, callback) AsianEmbedHelper.getUrls(url, subtitleCallback, callback)
} }
url.startsWith("https://embedsito.com") -> { url.startsWith("https://embedsito.com") -> {
val extractor = XStreamCdn() val extractor = XStreamCdn()
@ -274,7 +285,7 @@ class KdramaHoodProvider : MainAPI() {
} }
} }
else -> { else -> {
loadExtractor(url, mainUrl, callback) loadExtractor(url, mainUrl, subtitleCallback, callback)
} }
} }
} }

View file

@ -219,7 +219,7 @@ class LayarKacaProvider : MainAPI() {
} else { } else {
it it
} }
loadExtractor(link, data, callback) loadExtractor(link, data, subtitleCallback, callback)
} }
return true return true

View file

@ -126,7 +126,7 @@ class OpenVidsProvider:TmdbProvider() {
membed.isUsingAdaptiveKeys, membed.isUsingAdaptiveKeys,
membed.isUsingAdaptiveData) membed.isUsingAdaptiveData)
} else } else
loadExtractor(links, data, callback) loadExtractor(links, data, subtitleCallback, callback)
} }
return true return true
} }

View file

@ -152,7 +152,7 @@ class PeliSmartProvider: MainAPI() {
.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) loadExtractor(urlc, data, subtitleCallback, callback)
} }
return true return true
} }

View file

@ -222,7 +222,7 @@ class PelisflixProvider : MainAPI() {
allowRedirects = false allowRedirects = false
).okhttpResponse.headers.values("location").apmap { link -> ).okhttpResponse.headers.values("location").apmap { link ->
val url1 = link.replace("#bu", "") val url1 = link.replace("#bu", "")
loadExtractor(url1, data, callback) loadExtractor(url1, data, subtitleCallback, callback)
} }
} }
} }

View file

@ -165,7 +165,7 @@ class PelisplusHDProvider:MainAPI() {
): Boolean { ): Boolean {
app.get(data).document.select("div.player > script").map { script -> app.get(data).document.select("div.player > script").map { script ->
fetchUrls(script.data().replace("https://pelisplushd.net/fembed.php?url=","https://www.fembed.com/v/")).apmap { fetchUrls(script.data().replace("https://pelisplushd.net/fembed.php?url=","https://www.fembed.com/v/")).apmap {
loadExtractor(it, data, callback) loadExtractor(it, data, subtitleCallback, callback)
} }
} }
return true return true

View file

@ -229,7 +229,7 @@ open class PelisplusProviderTemplate : MainAPI() {
if (info.contains("Latino")) { if (info.contains("Latino")) {
doc.select(".server-item-1 li").apmap { doc.select(".server-item-1 li").apmap {
val serverid = fixUrl(it.attr("data-video")).replace("streaming.php","play") val serverid = fixUrl(it.attr("data-video")).replace("streaming.php","play")
loadExtractor(serverid, data, callback) loadExtractor(serverid, data, subtitleCallback, callback)
if (serverid.contains("pelisplus.icu")) { if (serverid.contains("pelisplus.icu")) {
getPelisStream(serverid, callback) getPelisStream(serverid, callback)
} }
@ -239,7 +239,7 @@ open class PelisplusProviderTemplate : MainAPI() {
if (info.contains("Subtitulado")) { if (info.contains("Subtitulado")) {
doc.select(".server-item-0 li").apmap { doc.select(".server-item-0 li").apmap {
val serverid = fixUrl(it.attr("data-video")).replace("streaming.php","play") val serverid = fixUrl(it.attr("data-video")).replace("streaming.php","play")
loadExtractor(serverid, data, callback) loadExtractor(serverid, data, subtitleCallback, callback)
if (serverid.contains("pelisplus.icu")) { if (serverid.contains("pelisplus.icu")) {
getPelisStream(serverid, callback) getPelisStream(serverid, callback)
} }
@ -249,7 +249,7 @@ open class PelisplusProviderTemplate : MainAPI() {
if (info.contains("Castellano")) { if (info.contains("Castellano")) {
doc.select(".server-item-2 li").apmap { doc.select(".server-item-2 li").apmap {
val serverid = fixUrl(it.attr("data-video")).replace("streaming.php","play") val serverid = fixUrl(it.attr("data-video")).replace("streaming.php","play")
loadExtractor(serverid, data, callback) loadExtractor(serverid, data, subtitleCallback, callback)
if (serverid.contains("pelisplus.icu")) { if (serverid.contains("pelisplus.icu")) {
getPelisStream(serverid, callback) getPelisStream(serverid, callback)
} }

View file

@ -221,7 +221,7 @@ class PinoyHDXyzProvider : MainAPI() {
mapper.readValue<List<String>>(data).forEach { item -> mapper.readValue<List<String>>(data).forEach { item ->
val url = item.trim() val url = item.trim()
if (url.isNotBlank()) { if (url.isNotBlank()) {
if (loadExtractor(url, mainUrl, callback)) { if (loadExtractor(url, mainUrl, subtitleCallback, callback)) {
count++ count++
} }
} }

View file

@ -231,7 +231,7 @@ class PinoyMoviePediaProvider : MainAPI() {
callback.invoke(it) callback.invoke(it)
} }
} else { } else {
loadExtractor(link, mainUrl, callback) loadExtractor(link, mainUrl, subtitleCallback, callback)
} }
} }
return count > 0 return count > 0

View file

@ -1,6 +1,5 @@
package com.lagradost.cloudstream3.movieproviders package com.lagradost.cloudstream3.movieproviders
import android.util.Log
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.FEmbed import com.lagradost.cloudstream3.extractors.FEmbed
@ -26,7 +25,11 @@ class PinoyMoviesEsProvider : MainAPI() {
@JsonProperty("type") val type: String @JsonProperty("type") val type: String
) )
private fun getRowElements(mainbody: Elements, rows: List<Pair<String, String>>, sep: String): MutableList<HomePageList> { private fun getRowElements(
mainbody: Elements,
rows: List<Pair<String, String>>,
sep: String
): MutableList<HomePageList> {
val all = mutableListOf<HomePageList>() val all = mutableListOf<HomePageList>()
for (item in rows) { for (item in rows) {
val title = item.first val title = item.first
@ -36,10 +39,14 @@ class PinoyMoviesEsProvider : MainAPI() {
if (urlTitle.isNullOrEmpty()) { if (urlTitle.isNullOrEmpty()) {
urlTitle = it?.select("div.data") urlTitle = it?.select("div.data")
} }
if (urlTitle.isNullOrEmpty()) { return@mapNotNull null } if (urlTitle.isNullOrEmpty()) {
return@mapNotNull null
}
// Fetch details // Fetch details
val link = fixUrlNull(urlTitle.select("a")?.attr("href")) val link = fixUrlNull(urlTitle.select("a")?.attr("href"))
if (link.isNullOrBlank()) { return@mapNotNull null } if (link.isNullOrBlank()) {
return@mapNotNull null
}
val image = it?.select("div.poster > img")?.attr("data-src") val image = it?.select("div.poster > img")?.attr("data-src")
@ -47,7 +54,9 @@ class PinoyMoviesEsProvider : MainAPI() {
val name = urlTitle.select("h3")?.text() val name = urlTitle.select("h3")?.text()
?: urlTitle.select("h2")?.text() ?: urlTitle.select("h2")?.text()
?: urlTitle.select("h1")?.text() ?: urlTitle.select("h1")?.text()
if (name.isNullOrBlank()) { return@mapNotNull null } if (name.isNullOrBlank()) {
return@mapNotNull null
}
var year = urlTitle.select("span")?.text()?.toIntOrNull() var year = urlTitle.select("span")?.text()?.toIntOrNull()
@ -80,27 +89,32 @@ class PinoyMoviesEsProvider : MainAPI() {
} }
return all return all
} }
override suspend fun getMainPage(): HomePageResponse { override suspend fun getMainPage(): HomePageResponse {
val all = ArrayList<HomePageList>() val all = ArrayList<HomePageList>()
val document = app.get(mainUrl).document val document = app.get(mainUrl).document
val mainbody = document.getElementsByTag("body") val mainbody = document.getElementsByTag("body")
if (mainbody != null) { if (mainbody != null) {
// All rows will be hardcoded bc of the nature of the site // All rows will be hardcoded bc of the nature of the site
val homepage1 = getRowElements(mainbody, listOf( val homepage1 = getRowElements(
Pair("Suggestion", "items.featured"), mainbody, listOf(
Pair("All Movies", "items.full") Pair("Suggestion", "items.featured"),
), ".") Pair("All Movies", "items.full")
), "."
)
if (homepage1.isNotEmpty()) { if (homepage1.isNotEmpty()) {
all.addAll(homepage1) all.addAll(homepage1)
} }
//2nd rows //2nd rows
val homepage2 = getRowElements(mainbody, listOf( val homepage2 = getRowElements(
Pair("Action", "genre_action"), mainbody, listOf(
Pair("Comedy", "genre_comedy"), Pair("Action", "genre_action"),
Pair("Romance", "genre_romance"), Pair("Comedy", "genre_comedy"),
Pair("Horror", "genre_horror") Pair("Romance", "genre_romance"),
//Pair("Rated-R", "genre_rated-r") Pair("Horror", "genre_horror")
), "#") //Pair("Rated-R", "genre_rated-r")
), "#"
)
if (homepage2.isNotEmpty()) { if (homepage2.isNotEmpty()) {
all.addAll(homepage2) all.addAll(homepage2)
} }
@ -156,7 +170,9 @@ class PinoyMoviesEsProvider : MainAPI() {
val aName = a.select("img")?.attr("alt") ?: return@mapNotNull null val aName = a.select("img")?.attr("alt") ?: return@mapNotNull null
val aYear = try { val aYear = try {
aName.trim().takeLast(5).removeSuffix(")").toIntOrNull() aName.trim().takeLast(5).removeSuffix(")").toIntOrNull()
} catch (e: Exception) { null } } catch (e: Exception) {
null
}
MovieSearchResponse( MovieSearchResponse(
url = aUrl, url = aUrl,
name = aName, name = aName,
@ -181,8 +197,10 @@ class PinoyMoviesEsProvider : MainAPI() {
Pair("nume", "1"), Pair("nume", "1"),
Pair("type", "movie") Pair("type", "movie")
) )
val innerPage = app.post("https://pinoymovies.es/wp-admin/admin-ajax.php ", val innerPage = app.post(
referer = url, data = content).document.select("body")?.text()?.trim() "https://pinoymovies.es/wp-admin/admin-ajax.php ",
referer = url, data = content
).document.select("body")?.text()?.trim()
if (!innerPage.isNullOrBlank()) { if (!innerPage.isNullOrBlank()) {
tryParseJson<EmbedUrl>(innerPage)?.let { tryParseJson<EmbedUrl>(innerPage)?.let {
listOfLinks.add(it.embed_url) listOfLinks.add(it.embed_url)
@ -204,17 +222,17 @@ class PinoyMoviesEsProvider : MainAPI() {
} }
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 {
// parse movie servers // parse movie servers
var count = 0 var count = 0
tryParseJson<List<String>>(data)?.forEach { link -> tryParseJson<List<String>>(data)?.forEach { link ->
//Log.i(this.name, "Result => (link) $link") //Log.i(this.name, "Result => (link) $link")
if (link.startsWith("https://vstreamhub.com")) { if (link.startsWith("https://vstreamhub.com")) {
VstreamhubHelper.getUrls(link, callback) VstreamhubHelper.getUrls(link, subtitleCallback, callback)
count++ count++
} else if (link.contains("fembed.com")) { } else if (link.contains("fembed.com")) {
val extractor = FEmbed() val extractor = FEmbed()
@ -224,7 +242,7 @@ class PinoyMoviesEsProvider : MainAPI() {
count++ count++
} }
} else { } else {
if (loadExtractor(link, mainUrl, callback)) { if (loadExtractor(link, mainUrl, subtitleCallback, callback)) {
count++ count++
} }
} }

View file

@ -7,11 +7,12 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.safeApiCall import com.lagradost.cloudstream3.mvvm.safeApiCall
import com.lagradost.cloudstream3.network.WebViewResolver import com.lagradost.cloudstream3.network.WebViewResolver
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.getQualityFromName
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.net.URI import java.net.URI
import java.util.ArrayList
class RebahinProvider : MainAPI() { class RebahinProvider : MainAPI() {
override var mainUrl = "http://167.88.14.149" override var mainUrl = "http://167.88.14.149"
@ -263,7 +264,7 @@ class RebahinProvider : MainAPI() {
callback callback
) )
else -> { else -> {
loadExtractor(link, "$mainUrl/", callback) loadExtractor(link, "$mainUrl/", subtitleCallback, callback)
if (link.startsWith("https://sbfull.com")) { if (link.startsWith("https://sbfull.com")) {
val response = app.get( val response = app.get(
link, interceptor = WebViewResolver( link, interceptor = WebViewResolver(

View file

@ -217,7 +217,7 @@ class SeriesflixProvider : MainAPI() {
allowRedirects = false allowRedirects = false
).okhttpResponse.headers.values("location").apmap { link -> ).okhttpResponse.headers.values("location").apmap { link ->
val url1 = link.replace("#bu", "") val url1 = link.replace("#bu", "")
loadExtractor(url1, data, callback) loadExtractor(url1, data, subtitleCallback, callback)
} }
} }
} }

View file

@ -24,7 +24,6 @@ import org.jsoup.Jsoup
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.net.URI import java.net.URI
import java.util.* import java.util.*
import kotlin.collections.ArrayList
import kotlin.system.measureTimeMillis import kotlin.system.measureTimeMillis
open class SflixProvider : MainAPI() { open class SflixProvider : MainAPI() {
@ -346,7 +345,7 @@ open class SflixProvider : MainAPI() {
"https://ws11.rabbitstream.net/socket.io/?EIO=4&transport=polling" "https://ws11.rabbitstream.net/socket.io/?EIO=4&transport=polling"
if (iframeLink.contains("streamlare", ignoreCase = true)) { if (iframeLink.contains("streamlare", ignoreCase = true)) {
loadExtractor(iframeLink, null).forEach(callback) loadExtractor(iframeLink, null,subtitleCallback,callback)
} else { } else {
extractRabbitStream(iframeLink, subtitleCallback, callback, false) { it } extractRabbitStream(iframeLink, subtitleCallback, callback, false) { it }
} }

View file

@ -232,7 +232,7 @@ class TantifilmProvider : MainAPI() {
iframe.forEach { id -> iframe.forEach { id ->
val doc2 = app.get(id).document val doc2 = app.get(id).document
val id2 = app.get(doc2.selectFirst("iframe")!!.attr("src")).url val id2 = app.get(doc2.selectFirst("iframe")!!.attr("src")).url
loadExtractor(id2, data, callback) loadExtractor(id2, data, subtitleCallback, callback)
} }
return true return true
} }

View file

@ -66,7 +66,7 @@ class TwoEmbedProvider : TmdbProvider() {
if (iframeLink.contains("rabbitstream")) { if (iframeLink.contains("rabbitstream")) {
extractRabbitStream(iframeLink, subtitleCallback, callback, false) { it } extractRabbitStream(iframeLink, subtitleCallback, callback, false) { it }
} else { } else {
loadExtractor(iframeLink, embedUrl, callback) loadExtractor(iframeLink, embedUrl, subtitleCallback, callback)
} }
} }
return true return true

View file

@ -67,8 +67,10 @@ open class VidstreamProviderTemplate : MainAPI() {
open val iv: String? = null open val iv: String? = null
open val secretKey: String? = null open val secretKey: String? = null
open val secretDecryptKey: String? = null open val secretDecryptKey: String? = null
/** Generated the key from IV and ID */ /** Generated the key from IV and ID */
open val isUsingAdaptiveKeys: Boolean = false open val isUsingAdaptiveKeys: Boolean = false
/** /**
* Generate data for the encrypt-ajax automatically (only on supported sites) * Generate data for the encrypt-ajax automatically (only on supported sites)
* See $("script[data-name='episode']")[0].dataset.value * See $("script[data-name='episode']")[0].dataset.value
@ -260,7 +262,16 @@ open class VidstreamProviderTemplate : MainAPI() {
val iframeLink = val iframeLink =
Jsoup.parse(app.get(data).text).selectFirst("iframe")?.attr("src") ?: return false Jsoup.parse(app.get(data).text).selectFirst("iframe")?.attr("src") ?: return false
extractVidstream(iframeLink, this.name, callback, iv, secretKey, secretDecryptKey, isUsingAdaptiveKeys, isUsingAdaptiveData) extractVidstream(
iframeLink,
this.name,
callback,
iv,
secretKey,
secretDecryptKey,
isUsingAdaptiveKeys,
isUsingAdaptiveData
)
// In this case the video player is a vidstream clone and can be handled by the vidstream extractor. // In this case the video player is a vidstream clone and can be handled by the vidstream extractor.
// This case is a both unorthodox and you normally do not call extractors as they detect the url returned and does the rest. // This case is a both unorthodox and you normally do not call extractors as they detect the url returned and does the rest.
val vidstreamObject = Vidstream(vidstreamExtractorUrl ?: mainUrl) val vidstreamObject = Vidstream(vidstreamExtractorUrl ?: mainUrl)
@ -268,7 +279,7 @@ open class VidstreamProviderTemplate : MainAPI() {
val id = Regex("""id=([^&]*)""").find(iframeLink)?.groupValues?.get(1) val id = Regex("""id=([^&]*)""").find(iframeLink)?.groupValues?.get(1)
if (id != null) { if (id != null) {
vidstreamObject.getUrl(id, isCasting, callback) vidstreamObject.getUrl(id, isCasting, subtitleCallback, callback)
} }
val html = app.get(fixUrl(iframeLink)).text val html = app.get(fixUrl(iframeLink)).text

View file

@ -22,7 +22,7 @@ class WatchAsianProvider : MainAPI() {
val headers = mapOf("X-Requested-By" to mainUrl) val headers = mapOf("X-Requested-By" to mainUrl)
val doc = app.get(mainUrl, headers = headers).document val doc = app.get(mainUrl, headers = headers).document
val rowPair = mutableListOf<Pair<String, String>>() val rowPair = mutableListOf<Pair<String, String>>()
doc.select("div.block-tab")?.forEach { doc.select("div.block-tab").forEach {
it?.select("ul.tab > li")?.mapNotNull { row -> it?.select("ul.tab > li")?.mapNotNull { row ->
val link = row?.attr("data-tab") ?: return@mapNotNull null val link = row?.attr("data-tab") ?: return@mapNotNull null
val title = row.text() ?: return@mapNotNull null val title = row.text() ?: return@mapNotNull null
@ -77,12 +77,12 @@ class WatchAsianProvider : MainAPI() {
return document.mapNotNull { return document.mapNotNull {
val innerA = it?.selectFirst("a") ?: return@mapNotNull null val innerA = it?.selectFirst("a") ?: return@mapNotNull null
val link = fixUrlNull(innerA.attr("href")) ?: return@mapNotNull null val link = fixUrlNull(innerA.attr("href")) ?: return@mapNotNull null
val title = it.select("h3.title")?.text() ?: return@mapNotNull null val title = it.select("h3.title").text() ?: return@mapNotNull null
if (title.isEmpty()) { if (title.isEmpty()) {
return@mapNotNull null return@mapNotNull null
} }
val year = null val year = null
val imgsrc = innerA.select("img")?.attr("data-original") ?: return@mapNotNull null val imgsrc = innerA.select("img").attr("data-original") ?: return@mapNotNull null
val image = fixUrlNull(imgsrc) val image = fixUrlNull(imgsrc)
//Log.i(this.name, "Result => (img movie) $title / $link") //Log.i(this.name, "Result => (img movie) $title / $link")
MovieSearchResponse( MovieSearchResponse(
@ -100,31 +100,31 @@ class WatchAsianProvider : MainAPI() {
val body = app.get(url).document val body = app.get(url).document
// Declare vars // Declare vars
val isDramaDetail = url.contains("/drama-detail/") val isDramaDetail = url.contains("/drama-detail/")
var poster = "" var poster: String? = null
var title = "" var title = ""
var descript: String? = null var descript: String? = null
var year: Int? = null var year: Int? = null
var tags: List<String>? = null var tags: List<String>? = null
if (isDramaDetail) { if (isDramaDetail) {
val main = body.select("div.details") val main = body.select("div.details")
val inner = main?.select("div.info") val inner = main.select("div.info")
// Video details // Video details
poster = fixUrlNull(main?.select("div.img > img")?.attr("src")) ?: "" poster = fixUrlNull(main.select("div.img > img").attr("src"))
//Log.i(this.name, "Result => (imgLinkCode) ${imgLinkCode}") //Log.i(this.name, "Result => (imgLinkCode) ${imgLinkCode}")
title = inner?.select("h1")?.firstOrNull()?.text() ?: "" title = inner.select("h1").firstOrNull()?.text() ?: ""
//Log.i(this.name, "Result => (year) ${title.substring(title.length - 5)}") //Log.i(this.name, "Result => (year) ${title.substring(title.length - 5)}")
descript = inner?.text() descript = inner.text()
inner?.select("p")?.forEach { p -> inner.select("p").forEach { p ->
val caption = val caption =
p?.selectFirst("span")?.text()?.trim()?.lowercase()?.removeSuffix(":")?.trim() p?.selectFirst("span")?.text()?.trim()?.lowercase()?.removeSuffix(":")?.trim()
?: return@forEach ?: return@forEach
when (caption) { when (caption) {
"genre" -> { "genre" -> {
tags = p.select("a")?.mapNotNull { it?.text()?.trim() } tags = p.select("a").mapNotNull { it?.text()?.trim() }
} }
"released" -> { "released" -> {
year = p.select("a")?.text()?.trim()?.toIntOrNull() year = p.select("a").text().trim()?.toIntOrNull()
} }
} }
} }
@ -147,7 +147,7 @@ class WatchAsianProvider : MainAPI() {
// Episodes Links // Episodes Links
//Log.i(this.name, "Result => (all eps) ${body.select("ul.list-episode-item-2.all-episode > li")}") //Log.i(this.name, "Result => (all eps) ${body.select("ul.list-episode-item-2.all-episode > li")}")
val episodeList = body.select("ul.list-episode-item-2.all-episode > li")?.mapNotNull { ep -> val episodeList = body.select("ul.list-episode-item-2.all-episode > li").mapNotNull { ep ->
//Log.i(this.name, "Result => (epA) ${ep.select("a")}") //Log.i(this.name, "Result => (epA) ${ep.select("a")}")
val innerA = ep.select("a") ?: return@mapNotNull null val innerA = ep.select("a") ?: return@mapNotNull null
//Log.i(this.name, "Result => (innerA) ${fixUrlNull(innerA.attr("href"))}") //Log.i(this.name, "Result => (innerA) ${fixUrlNull(innerA.attr("href"))}")
@ -164,7 +164,7 @@ class WatchAsianProvider : MainAPI() {
posterUrl = poster, posterUrl = poster,
date = null date = null
) )
} ?: listOf() }
//If there's only 1 episode, consider it a movie. //If there's only 1 episode, consider it a movie.
if (episodeList.size == 1) { if (episodeList.size == 1) {
//Clean title //Clean title
@ -216,21 +216,24 @@ class WatchAsianProvider : MainAPI() {
url.startsWith("https://asianembed.io") || url.startsWith("https://asianload.io") -> { url.startsWith("https://asianembed.io") || url.startsWith("https://asianload.io") -> {
val iv = "9262859232435825" val iv = "9262859232435825"
val secretKey = "93422192433952489752342908585752" val secretKey = "93422192433952489752342908585752"
extractVidstream(url, this.name, callback, iv, secretKey, secretKey, extractVidstream(
url, this.name, callback, iv, secretKey, secretKey,
isUsingAdaptiveKeys = false, isUsingAdaptiveKeys = false,
isUsingAdaptiveData = false isUsingAdaptiveData = false
) )
AsianEmbedHelper.getUrls(url, callback) AsianEmbedHelper.getUrls(url, subtitleCallback, callback)
} }
url.startsWith("https://embedsito.com") -> { url.startsWith("https://embedsito.com") -> {
val extractor = XStreamCdn() val extractor = XStreamCdn()
extractor.domainUrl = "embedsito.com" extractor.domainUrl = "embedsito.com"
extractor.getSafeUrl(url)?.apmap { link -> extractor.getSafeUrl(
callback.invoke(link) url,
} subtitleCallback = subtitleCallback,
callback = callback,
)
} }
else -> { else -> {
loadExtractor(url, mainUrl, callback) loadExtractor(url, mainUrl, subtitleCallback, callback)
} }
} }
} }
@ -240,8 +243,8 @@ class WatchAsianProvider : MainAPI() {
private suspend fun getServerLinks(url: String): String { private suspend fun getServerLinks(url: String): String {
val moviedoc = app.get(url, referer = mainUrl).document val moviedoc = app.get(url, referer = mainUrl).document
return moviedoc.select("div.anime_muti_link > ul > li") return moviedoc.select("div.anime_muti_link > ul > li")
?.mapNotNull { .mapNotNull {
fixUrlNull(it?.attr("data-video")) ?: return@mapNotNull null fixUrlNull(it?.attr("data-video")) ?: return@mapNotNull null
}?.toJson() ?: "" }.toJson()
} }
} }

View file

@ -7,7 +7,6 @@ import com.lagradost.cloudstream3.mvvm.safeApiCall
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.util.ArrayList
class YomoviesProvider : MainAPI() { class YomoviesProvider : MainAPI() {
override var mainUrl = "https://yomovies.plus" override var mainUrl = "https://yomovies.plus"
@ -122,8 +121,15 @@ class YomoviesProvider : MainAPI() {
source, source,
referer = "$mainUrl/" referer = "$mainUrl/"
).document.select("ul.list-server-items li") ).document.select("ul.list-server-items li")
.apmap { loadExtractor(it.attr("data-video").substringBefore("=https://msubload"), "$mainUrl/", callback) } .apmap {
else -> loadExtractor(source, "$mainUrl/", callback) loadExtractor(
it.attr("data-video").substringBefore("=https://msubload"),
"$mainUrl/",
subtitleCallback,
callback
)
}
else -> loadExtractor(source, "$mainUrl/", subtitleCallback, callback)
} }
} }
} }

View file

@ -375,6 +375,7 @@ abstract class AbstractPlayerFragment(
subView = player_view?.findViewById(R.id.exo_subtitles) subView = player_view?.findViewById(R.id.exo_subtitles)
subStyle = SubtitlesFragment.getCurrentSavedStyle() subStyle = SubtitlesFragment.getCurrentSavedStyle()
player.initSubtitles(subView, subtitle_holder, subStyle) player.initSubtitles(subView, subtitle_holder, subStyle)
SubtitlesFragment.applyStyleEvent += ::onSubStyleChanged SubtitlesFragment.applyStyleEvent += ::onSubStyleChanged
try { try {

View file

@ -44,7 +44,9 @@ class LinkGenerator(
offset: Int offset: Int
): Boolean { ): Boolean {
links.apmap { link -> links.apmap { link ->
if (!extract || !loadExtractor(link, referer) { if (!extract || !loadExtractor(link, referer, {
subtitleCallback(PlayerSubtitleHelper.getSubtitleData(it))
}) {
callback(it to null) callback(it to null)
}) { }) {

View file

@ -1,5 +1,6 @@
package com.lagradost.cloudstream3.ui.player package com.lagradost.cloudstream3.ui.player
import android.util.Log
import android.util.TypedValue import android.util.TypedValue
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.FrameLayout import android.widget.FrameLayout
@ -89,6 +90,7 @@ class PlayerSubtitleHelper {
regexSubtitlesToRemoveCaptions = style.removeCaptions regexSubtitlesToRemoveCaptions = style.removeCaptions
subtitleView?.context?.let { ctx -> subtitleView?.context?.let { ctx ->
subStyle = style subStyle = style
Log.i(TAG,"SET STYLE = $style")
subtitleView?.setStyle(ctx.fromSaveToStyle(style)) subtitleView?.setStyle(ctx.fromSaveToStyle(style))
subtitleView?.translationY = -style.elevation.toPx.toFloat() subtitleView?.translationY = -style.elevation.toPx.toFloat()
val size = style.fixedTextSize val size = style.fixedTextSize

View file

@ -1901,7 +1901,7 @@ class ResultFragment : ResultTrailerPlayer() {
setRecommendations(d.recommendations, null) setRecommendations(d.recommendations, null)
setActors(d.actors) setActors(d.actors)
setNextEpisode(if (d is EpisodeResponse) d.nextAiring else null) setNextEpisode(if (d is EpisodeResponse) d.nextAiring else null)
setTrailers(d.trailers) setTrailers(d.trailers.flatMap { it.mirros }) // I dont care about subtitles yet!
if (syncModel.addSyncs(d.syncData)) { if (syncModel.addSyncs(d.syncData)) {
syncModel.updateMetaAndUser() syncModel.updateMetaAndUser()

View file

@ -1,12 +1,12 @@
package com.lagradost.cloudstream3.utils package com.lagradost.cloudstream3.utils
import android.net.Uri import android.net.Uri
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.TvType import com.lagradost.cloudstream3.TvType
import com.lagradost.cloudstream3.USER_AGENT import com.lagradost.cloudstream3.USER_AGENT
import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.extractors.* import com.lagradost.cloudstream3.extractors.*
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import org.jsoup.Jsoup import org.jsoup.Jsoup
@ -155,12 +155,26 @@ suspend fun unshortenLinkSafe(url: String): String {
} }
} }
suspend fun loadExtractor(
url: String,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
): Boolean {
return loadExtractor(
url = url,
referer = null,
subtitleCallback = subtitleCallback,
callback = callback
)
}
/** /**
* Tries to load the appropriate extractor based on link, returns true if any extractor is loaded. * Tries to load the appropriate extractor based on link, returns true if any extractor is loaded.
* */ * */
suspend fun loadExtractor( suspend fun loadExtractor(
url: String, url: String,
referer: String? = null, referer: String? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
val currentUrl = unshortenLinkSafe(url) val currentUrl = unshortenLinkSafe(url)
@ -169,7 +183,7 @@ suspend fun loadExtractor(
if (currentUrl.replace(schemaStripRegex, "") if (currentUrl.replace(schemaStripRegex, "")
.startsWith(extractor.mainUrl.replace(schemaStripRegex, "")) .startsWith(extractor.mainUrl.replace(schemaStripRegex, ""))
) { ) {
extractor.getSafeUrl(currentUrl, referer)?.forEach(callback) extractor.getSafeUrl(currentUrl, referer, subtitleCallback, callback)
return true return true
} }
} }
@ -177,20 +191,6 @@ suspend fun loadExtractor(
return false return false
} }
suspend fun loadExtractor(
url: String,
referer: String? = null,
): List<ExtractorLink> {
val currentUrl = unshortenLinkSafe(url)
for (extractor in extractorApis) {
if (currentUrl.startsWith(extractor.mainUrl)) {
return extractor.getSafeUrl(currentUrl, referer) ?: emptyList()
}
}
return emptyList()
}
val extractorApis: Array<ExtractorApi> = arrayOf( val extractorApis: Array<ExtractorApi> = arrayOf(
//AllProvider(), //AllProvider(),
WcoStream(), WcoStream(),
@ -372,14 +372,39 @@ abstract class ExtractorApi {
abstract val mainUrl: String abstract val mainUrl: String
abstract val requiresReferer: Boolean abstract val requiresReferer: Boolean
suspend fun getSafeUrl(url: String, referer: String? = null): List<ExtractorLink>? { //suspend fun getSafeUrl(url: String, referer: String? = null): List<ExtractorLink>? {
return suspendSafeApiCall { getUrl(url, referer) } // return suspendSafeApiCall { getUrl(url, referer) }
//}
// this is the new extractorapi, override to add subtitles and stuff
open suspend fun getUrl(
url: String,
referer: String? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
getUrl(url, referer)?.forEach(callback)
}
suspend fun getSafeUrl(
url: String,
referer: String? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
try {
getUrl(url, referer, subtitleCallback, callback)
} catch (e: Exception) {
logError(e)
}
} }
/** /**
* Will throw errors, use getSafeUrl if you don't want to handle the exception yourself * Will throw errors, use getSafeUrl if you don't want to handle the exception yourself
*/ */
abstract suspend fun getUrl(url: String, referer: String? = null): List<ExtractorLink>? open suspend fun getUrl(url: String, referer: String? = null): List<ExtractorLink>? {
return emptyList()
}
open fun getExtractorUrl(id: String): String { open fun getExtractorUrl(id: String): String {
return id return id