mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
added subtitles to ExtractorApi
This commit is contained in:
parent
a7e29dd8d5
commit
47f4e10078
69 changed files with 621 additions and 442 deletions
|
@ -899,6 +899,11 @@ data class TvSeriesSearchResponse(
|
|||
override var posterHeaders: Map<String, String>? = null,
|
||||
) : SearchResponse
|
||||
|
||||
data class TrailerData(
|
||||
var mirros: List<ExtractorLink>,
|
||||
var subtitles: List<SubtitleFile> = emptyList(),
|
||||
)
|
||||
|
||||
interface LoadResponse {
|
||||
var name: String
|
||||
var url: String
|
||||
|
@ -910,7 +915,8 @@ interface LoadResponse {
|
|||
var rating: Int? // 0-10000
|
||||
var tags: List<String>?
|
||||
var duration: Int? // in minutes
|
||||
var trailers: List<ExtractorLink>?
|
||||
var trailers: MutableList<TrailerData>
|
||||
|
||||
var recommendations: List<SearchResponse>?
|
||||
var actors: List<ActorData>?
|
||||
var comingSoon: Boolean
|
||||
|
@ -965,35 +971,25 @@ interface LoadResponse {
|
|||
/**better to call addTrailer with mutible trailers directly instead of calling this multiple times*/
|
||||
suspend fun LoadResponse.addTrailer(trailerUrl: String?, referer: String? = null) {
|
||||
if (!isTrailersEnabled || trailerUrl == null) return
|
||||
try {
|
||||
val newTrailers = loadExtractor(trailerUrl, referer)
|
||||
addTrailer(newTrailers)
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
val links = arrayListOf<ExtractorLink>()
|
||||
val subs = arrayListOf<SubtitleFile>()
|
||||
loadExtractor(trailerUrl, referer, { subs.add(it) }, { links.add(it) })
|
||||
this.trailers.add(TrailerData(links, subs))
|
||||
}
|
||||
|
||||
fun LoadResponse.addTrailer(newTrailers: List<ExtractorLink>) {
|
||||
if (this.trailers == null) {
|
||||
this.trailers = newTrailers
|
||||
} else {
|
||||
val update = this.trailers?.toMutableList() ?: mutableListOf()
|
||||
update.addAll(newTrailers)
|
||||
this.trailers = update
|
||||
}
|
||||
trailers.addAll(newTrailers.map { TrailerData(listOf(it)) })
|
||||
}
|
||||
|
||||
suspend fun LoadResponse.addTrailer(trailerUrls: List<String>?, referer: String? = null) {
|
||||
if (!isTrailersEnabled || trailerUrls == null) return
|
||||
val newTrailers = trailerUrls.apmap { trailerUrl ->
|
||||
try {
|
||||
loadExtractor(trailerUrl, referer)
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
emptyList()
|
||||
}
|
||||
}.flatten().distinct()
|
||||
addTrailer(newTrailers)
|
||||
val trailers = trailerUrls.apmap { trailerUrl ->
|
||||
val links = arrayListOf<ExtractorLink>()
|
||||
val subs = arrayListOf<SubtitleFile>()
|
||||
loadExtractor(trailerUrl, referer, { subs.add(it) }, { links.add(it) })
|
||||
links to subs
|
||||
}.map { (links, subs) -> TrailerData(links, subs) }
|
||||
this.trailers.addAll(trailers)
|
||||
}
|
||||
|
||||
fun LoadResponse.addImdbId(id: String?) {
|
||||
|
@ -1087,7 +1083,7 @@ data class TorrentLoadResponse(
|
|||
override var rating: Int? = null,
|
||||
override var tags: List<String>? = 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 actors: List<ActorData>? = null,
|
||||
override var comingSoon: Boolean = false,
|
||||
|
@ -1115,7 +1111,7 @@ data class AnimeLoadResponse(
|
|||
|
||||
override var rating: 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 actors: List<ActorData>? = null,
|
||||
override var comingSoon: Boolean = false,
|
||||
|
@ -1163,7 +1159,7 @@ data class LiveStreamLoadResponse(
|
|||
override var rating: Int? = null,
|
||||
override var tags: List<String>? = 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 actors: List<ActorData>? = null,
|
||||
override var comingSoon: Boolean = false,
|
||||
|
@ -1185,7 +1181,7 @@ data class MovieLoadResponse(
|
|||
override var rating: Int? = null,
|
||||
override var tags: List<String>? = 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 actors: List<ActorData>? = null,
|
||||
override var comingSoon: Boolean = false,
|
||||
|
@ -1306,7 +1302,7 @@ data class TvSeriesLoadResponse(
|
|||
override var rating: Int? = null,
|
||||
override var tags: List<String>? = 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 actors: List<ActorData>? = null,
|
||||
override var comingSoon: Boolean = false,
|
||||
|
|
|
@ -56,7 +56,8 @@ class AnimeFlickProvider : MainAPI() {
|
|||
val title = doc.selectFirst("h2.title")!!.text()
|
||||
|
||||
val yearText = doc.selectFirst(".trending-year")?.text()
|
||||
val year = if (yearText != null) Regex("""(\d{4})""").find(yearText)?.destructured?.component1()
|
||||
val year =
|
||||
if (yearText != null) Regex("""(\d{4})""").find(yearText)?.destructured?.component1()
|
||||
?.toIntOrNull() else null
|
||||
val description = doc.selectFirst("p")?.text()
|
||||
|
||||
|
@ -95,7 +96,7 @@ class AnimeFlickProvider : MainAPI() {
|
|||
var alreadyAdded = false
|
||||
for (extractor in extractorApis) {
|
||||
if (link.startsWith(extractor.mainUrl)) {
|
||||
extractor.getSafeUrl(link, data)?.forEach(callback)
|
||||
extractor.getSafeUrl(link, data, subtitleCallback, callback)
|
||||
alreadyAdded = true
|
||||
break
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import com.lagradost.cloudstream3.utils.loadExtractor
|
|||
import com.lagradost.nicehttp.NiceResponse
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Element
|
||||
import java.util.ArrayList
|
||||
|
||||
class AnimeIndoProvider : MainAPI() {
|
||||
override var mainUrl = "https://animeindo.sbs"
|
||||
|
@ -183,7 +182,7 @@ class AnimeIndoProvider : MainAPI() {
|
|||
it
|
||||
}
|
||||
}.apmap {
|
||||
loadExtractor(it, data, callback)
|
||||
loadExtractor(it, data, subtitleCallback, callback)
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
|
@ -112,7 +112,8 @@ class AnimeSailProvider : MainAPI() {
|
|||
)
|
||||
val episodes = document.select("ul.daftar > li").map {
|
||||
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"))
|
||||
Episode(link, name = name)
|
||||
}.reversed()
|
||||
|
@ -157,7 +158,8 @@ class AnimeSailProvider : MainAPI() {
|
|||
iframe.contains("/race/") -> "Race"
|
||||
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(
|
||||
ExtractorLink(
|
||||
source = source,
|
||||
|
@ -174,11 +176,11 @@ class AnimeSailProvider : MainAPI() {
|
|||
iframe.startsWith("$mainUrl/utils/player/framezilla/") || iframe.startsWith("https://uservideo.xyz") -> {
|
||||
request(iframe, ref = data).document.select("iframe").attr("src")
|
||||
.let { link ->
|
||||
loadExtractor(fixUrl(link), mainUrl, callback)
|
||||
loadExtractor(fixUrl(link), mainUrl, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
loadExtractor(iframe, mainUrl, callback)
|
||||
loadExtractor(iframe, mainUrl, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,12 @@ package com.lagradost.cloudstream3.animeproviders
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
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 java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
|
||||
class AnimefenixProvider:MainAPI() {
|
||||
|
@ -179,7 +180,7 @@ class AnimefenixProvider:MainAPI() {
|
|||
|
||||
else -> ""
|
||||
}
|
||||
loadExtractor(links, data, callback)
|
||||
loadExtractor(links, data, subtitleCallback, callback)
|
||||
|
||||
argamap({
|
||||
if (links.contains("AmaNormal")) {
|
||||
|
|
|
@ -2,11 +2,13 @@ package com.lagradost.cloudstream3.movieproviders
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
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.Qualities
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class AnimeflvIOProvider:MainAPI() {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -173,7 +173,7 @@ class AnimeflvnetProvider : MainAPI() {
|
|||
it.replace("https://embedsb.com/e/", "https://watchsb.com/e/")
|
||||
.replace("https://ok.ru", "http://ok.ru")
|
||||
}.apmap {
|
||||
loadExtractor(it, data, callback)
|
||||
loadExtractor(it, data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@ package com.lagradost.cloudstream3.animeproviders
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
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.utils.AppUtils.parseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
|
@ -126,7 +124,7 @@ class AnimekisaProvider : MainAPI() {
|
|||
): Boolean {
|
||||
app.get(data).document.select("#servers-list ul.nav li a").apmap {
|
||||
val server = it.attr("data-embed")
|
||||
loadExtractor(server, data, callback)
|
||||
loadExtractor(server, data, subtitleCallback, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -338,7 +338,11 @@ class GogoanimeProvider : MainAPI() {
|
|||
@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 iframe = fixUrlNull(doc.selectFirst("div.play-video > iframe")?.attr("src")) ?: return
|
||||
|
@ -366,7 +370,7 @@ class GogoanimeProvider : MainAPI() {
|
|||
)
|
||||
} else {
|
||||
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
|
||||
if (status != "1") return@forEach
|
||||
val data = element.attr("data-video") ?: return@forEach
|
||||
loadExtractor(data, streamingResponse.url, callback)
|
||||
loadExtractor(data, streamingResponse.url, subtitleCallback, callback)
|
||||
}
|
||||
}, {
|
||||
val iv = "3134003223491201"
|
||||
|
@ -405,7 +409,7 @@ class GogoanimeProvider : MainAPI() {
|
|||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
extractVideos(data, callback)
|
||||
extractVideos(data, subtitleCallback, callback)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,9 @@ class GomunimeProvider : MainAPI() {
|
|||
document.select(".bixbox.bxcl.epcheck > script").toString().trim()
|
||||
)?.groupValues?.get(1).toString().replace(Regex("""\\"""), "").trim()
|
||||
).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
|
||||
Episode(link, name)
|
||||
}.reversed()
|
||||
|
@ -194,7 +196,7 @@ class GomunimeProvider : MainAPI() {
|
|||
safeApiCall {
|
||||
when {
|
||||
it.second.contains("frame") -> {
|
||||
loadExtractor(it.first, data, callback)
|
||||
loadExtractor(it.first, data, subtitleCallback, callback)
|
||||
}
|
||||
it.second.contains("hls") -> {
|
||||
app.post(
|
||||
|
|
|
@ -3,12 +3,12 @@ package com.lagradost.cloudstream3.animeproviders
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
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.getQualityFromName
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.List
|
||||
|
||||
|
||||
class JKAnimeProvider : MainAPI() {
|
||||
|
@ -34,9 +34,18 @@ class JKAnimeProvider : MainAPI() {
|
|||
|
||||
override suspend fun getMainPage(): HomePageResponse {
|
||||
val urls = listOf(
|
||||
Pair("$mainUrl/directorio/?filtro=fecha&tipo=TV&estado=1&fecha=none&temporada=none&orden=desc", "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"),
|
||||
Pair(
|
||||
"$mainUrl/directorio/?filtro=fecha&tipo=TV&estado=1&fecha=none&temporada=none&orden=desc",
|
||||
"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>()
|
||||
|
@ -46,12 +55,14 @@ class JKAnimeProvider : MainAPI() {
|
|||
"Últimos episodios",
|
||||
app.get(mainUrl).document.select(".listadoanime-home a.bloqq").map {
|
||||
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
|
||||
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 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) {
|
||||
this.posterUrl = poster
|
||||
addDubStatus(dubstat, epNum)
|
||||
|
@ -82,12 +93,12 @@ class JKAnimeProvider : MainAPI() {
|
|||
return HomePageResponse(items)
|
||||
}
|
||||
|
||||
data class MainSearch (
|
||||
data class MainSearch(
|
||||
@JsonProperty("animes") val animes: List<Animes>,
|
||||
@JsonProperty("anime_types") val animeTypes: AnimeTypes
|
||||
)
|
||||
|
||||
data class Animes (
|
||||
data class Animes(
|
||||
@JsonProperty("id") val id: String,
|
||||
@JsonProperty("slug") val slug: String,
|
||||
@JsonProperty("title") val title: String,
|
||||
|
@ -98,7 +109,7 @@ class JKAnimeProvider : MainAPI() {
|
|||
@JsonProperty("thumbnail") val thumbnail: String
|
||||
)
|
||||
|
||||
data class AnimeTypes (
|
||||
data class AnimeTypes(
|
||||
@JsonProperty("TV") val TV: String,
|
||||
@JsonProperty("OVA") val OVA: String,
|
||||
@JsonProperty("Movie") val Movie: String,
|
||||
|
@ -134,7 +145,8 @@ class JKAnimeProvider : MainAPI() {
|
|||
val title = doc.selectFirst(".anime__details__title > h3")?.text()
|
||||
val type = doc.selectFirst(".anime__details__text")?.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()) {
|
||||
"En emisión" -> ShowStatus.Ongoing
|
||||
"Concluido" -> ShowStatus.Completed
|
||||
|
@ -143,7 +155,8 @@ class JKAnimeProvider : MainAPI() {
|
|||
val animeID = doc.selectFirst("div.ml-2")?.attr("data-anime")?.toInt()
|
||||
val animeeps = "$mainUrl/ajax/last_episode/$animeID/"
|
||||
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 link = "${url.removeSuffix("/")}/$it"
|
||||
Episode(link)
|
||||
|
@ -158,7 +171,7 @@ class JKAnimeProvider : MainAPI() {
|
|||
}
|
||||
}
|
||||
|
||||
data class Nozomi (
|
||||
data class Nozomi(
|
||||
@JsonProperty("file") val file: String?
|
||||
)
|
||||
|
||||
|
@ -193,16 +206,17 @@ class JKAnimeProvider : MainAPI() {
|
|||
if (script.data().contains("var video = []")) {
|
||||
val videos = script.data().replace("\\/", "/")
|
||||
fetchUrls(videos).map {
|
||||
it.replace("$mainUrl/jkfembed.php?u=","https://embedsito.com/v/")
|
||||
.replace("$mainUrl/jkokru.php?u=","http://ok.ru/videoembed/")
|
||||
.replace("$mainUrl/jkvmixdrop.php?u=","https://mixdrop.co/e/")
|
||||
.replace("$mainUrl/jk.php?u=","$mainUrl/")
|
||||
it.replace("$mainUrl/jkfembed.php?u=", "https://embedsito.com/v/")
|
||||
.replace("$mainUrl/jkokru.php?u=", "http://ok.ru/videoembed/")
|
||||
.replace("$mainUrl/jkvmixdrop.php?u=", "https://mixdrop.co/e/")
|
||||
.replace("$mainUrl/jk.php?u=", "$mainUrl/")
|
||||
}.apmap { link ->
|
||||
loadExtractor(link, data, callback)
|
||||
loadExtractor(link, data, subtitleCallback, callback)
|
||||
if (link.contains("um2.php")) {
|
||||
val doc = app.get(link, referer = data).document
|
||||
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(
|
||||
"Host" to "jkanime.net",
|
||||
"User-Agent" to USER_AGENT,
|
||||
|
@ -219,11 +233,14 @@ class JKAnimeProvider : MainAPI() {
|
|||
"Sec-Fetch-Site" to "same-origin",
|
||||
"TE" to "trailers",
|
||||
"Pragma" to "no-cache",
|
||||
"Cache-Control" to "no-cache",),
|
||||
data = mapOf(Pair("data",gsplaykey)),
|
||||
allowRedirects = false).okhttpResponse.headers.values("location").apmap { loc ->
|
||||
val postkey = loc.replace("/gsplay/player.html#","")
|
||||
val nozomitext = app.post("$mainUrl/gsplay/api.php",
|
||||
"Cache-Control" to "no-cache",
|
||||
),
|
||||
data = mapOf(Pair("data", gsplaykey)),
|
||||
allowRedirects = false
|
||||
).okhttpResponse.headers.values("location").apmap { loc ->
|
||||
val postkey = loc.replace("/gsplay/player.html#", "")
|
||||
val nozomitext = app.post(
|
||||
"$mainUrl/gsplay/api.php",
|
||||
headers = mapOf(
|
||||
"Host" to "jkanime.net",
|
||||
"User-Agent" to USER_AGENT,
|
||||
|
@ -236,8 +253,9 @@ class JKAnimeProvider : MainAPI() {
|
|||
"Connection" to "keep-alive",
|
||||
"Sec-Fetch-Dest" to "empty",
|
||||
"Sec-Fetch-Mode" to "cors",
|
||||
"Sec-Fetch-Site" to "same-origin",),
|
||||
data = mapOf(Pair("v",postkey)),
|
||||
"Sec-Fetch-Site" to "same-origin",
|
||||
),
|
||||
data = mapOf(Pair("v", postkey)),
|
||||
allowRedirects = false
|
||||
).text
|
||||
val json = parseJson<Nozomi>(nozomitext)
|
||||
|
@ -245,13 +263,20 @@ class JKAnimeProvider : MainAPI() {
|
|||
if (nozomiurl.isEmpty()) null else
|
||||
nozomiurl.forEach { url ->
|
||||
val nozominame = "Nozomi"
|
||||
streamClean(nozominame, url!!, "", null, callback, url.contains(".m3u8"))
|
||||
streamClean(
|
||||
nozominame,
|
||||
url!!,
|
||||
"",
|
||||
null,
|
||||
callback,
|
||||
url.contains(".m3u8")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (link.contains("um.php")) {
|
||||
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 namedesu = "Desu"
|
||||
generateM3u8(
|
||||
|
@ -259,13 +284,31 @@ class JKAnimeProvider : MainAPI() {
|
|||
file!!,
|
||||
mainUrl,
|
||||
).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")) {
|
||||
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"
|
||||
streamClean(namex, xtremeurl, "", null, callback, xtremeurl.contains(".m3u8"))
|
||||
streamClean(
|
||||
namex,
|
||||
xtremeurl,
|
||||
"",
|
||||
null,
|
||||
callback,
|
||||
xtremeurl.contains(".m3u8")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package com.lagradost.cloudstream3.animeproviders
|
|||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.Jsoup
|
||||
|
||||
class KimCartoonProvider : MainAPI() {
|
||||
|
||||
|
@ -143,7 +142,7 @@ class KimCartoonProvider : MainAPI() {
|
|||
servers.apmap {
|
||||
app.get(it).document.select("#my_video_1").attr("src").let { iframe ->
|
||||
if (iframe.isNotEmpty()) {
|
||||
loadExtractor(iframe, "$mainUrl/", callback)
|
||||
loadExtractor(iframe, "$mainUrl/", subtitleCallback, callback)
|
||||
}
|
||||
//There are other servers, but they require some work to do
|
||||
}
|
||||
|
|
|
@ -180,7 +180,7 @@ class KuronimeProvider : MainAPI() {
|
|||
safeApiCall {
|
||||
when {
|
||||
it.startsWith("https://animeku.org") -> invokeKuroSource(it, callback)
|
||||
else -> loadExtractor(it, mainUrl, callback)
|
||||
else -> loadExtractor(it, mainUrl, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ class MonoschinosProvider : MainAPI() {
|
|||
callback.invoke(link)
|
||||
}
|
||||
} else {
|
||||
loadExtractor(url, mainUrl, callback)
|
||||
loadExtractor(url, mainUrl, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
|
|
@ -163,7 +163,7 @@ class MundoDonghuaProvider : MainAPI() {
|
|||
}.toList().apmap {
|
||||
val unpack = getAndUnpack(it).replace("diasfem","embedsito")
|
||||
fetchUrls(unpack).apmap { url ->
|
||||
loadExtractor(url, data, callback)
|
||||
loadExtractor(url, data, subtitleCallback, callback)
|
||||
}
|
||||
if (unpack.contains("protea_tab")) {
|
||||
val protearegex = Regex("(protea_tab.*slug.*,type)")
|
||||
|
|
|
@ -169,7 +169,7 @@ class NeonimeProvider : MainAPI() {
|
|||
}
|
||||
|
||||
source.apmap {
|
||||
loadExtractor(it, data, callback)
|
||||
loadExtractor(it, data, subtitleCallback, callback)
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
|
@ -339,7 +339,7 @@ class NineAnimeProvider : MainAPI() {
|
|||
val encodedStreamUrl =
|
||||
getEpisodeLinks(it.attr("data-link-id"))?.result?.url ?: return@apmap
|
||||
val url = decodeVrf(encodedStreamUrl)
|
||||
if (!loadExtractor(url, callback = callback, referer = mainUrl)) {
|
||||
if (!loadExtractor(url, mainUrl, subtitleCallback, callback)) {
|
||||
callback(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
|
|
|
@ -3,10 +3,10 @@ package com.lagradost.cloudstream3.animeproviders
|
|||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
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.nodes.Element
|
||||
import java.util.ArrayList
|
||||
|
||||
class NontonAnimeIDProvider : MainAPI() {
|
||||
override var mainUrl = "https://75.119.159.228"
|
||||
|
@ -175,13 +175,17 @@ class NontonAnimeIDProvider : MainAPI() {
|
|||
)
|
||||
).parsed<EpResponse>().content
|
||||
).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"))
|
||||
Episode(link, name)
|
||||
}.reversed()
|
||||
} else {
|
||||
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")
|
||||
Episode(link, name)
|
||||
}.reversed()
|
||||
|
@ -243,7 +247,7 @@ class NontonAnimeIDProvider : MainAPI() {
|
|||
}
|
||||
|
||||
sources.apmap {
|
||||
loadExtractor(it, "$mainUrl/", callback)
|
||||
loadExtractor(it, "$mainUrl/", subtitleCallback, callback)
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
|
@ -193,7 +193,7 @@ class OploverzProvider : MainAPI() {
|
|||
}
|
||||
|
||||
sources.apmap {
|
||||
loadExtractor(it, data, callback)
|
||||
loadExtractor(it, data, subtitleCallback, callback)
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
|
@ -189,7 +189,7 @@ class OtakudesuProvider : MainAPI() {
|
|||
}
|
||||
}
|
||||
|
||||
loadExtractor(sources, data, callback)
|
||||
loadExtractor(sources, data, subtitleCallback, callback)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,8 @@ class WcoProvider : MainAPI() {
|
|||
nameHeader.attr("href").replace("/watch/", "/anime/")
|
||||
.replace(Regex("-episode-.*"), "/")
|
||||
val isDub =
|
||||
filmPoster!!.selectFirst("> div.film-poster-quality")?.text()?.contains("DUB")
|
||||
filmPoster!!.selectFirst("> div.film-poster-quality")?.text()
|
||||
?.contains("DUB")
|
||||
?: false
|
||||
val poster = filmPoster.selectFirst("> img")!!.attr("data-src")
|
||||
val set: EnumSet<DubStatus> =
|
||||
|
@ -231,8 +232,8 @@ class WcoProvider : MainAPI() {
|
|||
}
|
||||
|
||||
for (server in servers) {
|
||||
WcoStream().getSafeUrl(server["link"].toString(), "")?.forEach(callback)
|
||||
Mcloud().getSafeUrl(server["link"].toString(), "")?.forEach(callback)
|
||||
WcoStream().getSafeUrl(server["link"].toString(), null, subtitleCallback, callback)
|
||||
Mcloud().getSafeUrl(server["link"].toString(), null, subtitleCallback, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -60,7 +60,8 @@ class ZoroProvider : MainAPI() {
|
|||
|
||||
val dubExist = dubSub.contains("dub", ignoreCase = true)
|
||||
val subExist = dubSub.contains("sub", ignoreCase = true)
|
||||
val episodes = this.selectFirst(".film-poster > .tick.rtl > .tick-eps")?.text()?.let { eps ->
|
||||
val episodes =
|
||||
this.selectFirst(".film-poster > .tick.rtl > .tick-eps")?.text()?.let { eps ->
|
||||
//println("REGEX:::: $eps")
|
||||
// current episode / max episode
|
||||
//Regex("Ep (\\d+)/(\\d+)")
|
||||
|
@ -346,7 +347,7 @@ class ZoroProvider : MainAPI() {
|
|||
link,
|
||||
).parsed<RapidCloudResponse>().link
|
||||
val hasLoadedExtractorLink =
|
||||
loadExtractor(extractorLink, "https://rapid-cloud.ru/", callback)
|
||||
loadExtractor(extractorLink, "https://rapid-cloud.ru/", subtitleCallback, callback)
|
||||
|
||||
if (!hasLoadedExtractorLink) {
|
||||
extractRabbitStream(
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.apmap
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
|
||||
|
@ -27,12 +28,16 @@ class Pelisplus(val mainUrl: String) {
|
|||
private val normalApis = arrayListOf(MultiQuality())
|
||||
|
||||
// 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 {
|
||||
normalApis.apmap { api ->
|
||||
val url = api.getExtractorUrl(id)
|
||||
val source = api.getSafeUrl(url)
|
||||
source?.forEach { callback.invoke(it) }
|
||||
api.getSafeUrl(url, subtitleCallback = subtitleCallback, callback = callback)
|
||||
}
|
||||
val extractorUrl = getExtractorUrl(id)
|
||||
|
||||
|
@ -50,9 +55,10 @@ class Pelisplus(val mainUrl: String) {
|
|||
val href = element.attr("href") ?: return@apmap
|
||||
val qual = if (element.text()
|
||||
.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(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
|
@ -80,12 +86,7 @@ class Pelisplus(val mainUrl: String) {
|
|||
// Matches vidstream links with extractors
|
||||
extractorApis.filter { !it.requiresReferer || !isCasting }.apmap { api ->
|
||||
if (link.startsWith(api.mainUrl)) {
|
||||
val extractedLinks = api.getSafeUrl(link, extractorUrl)
|
||||
if (extractedLinks?.isNotEmpty() == true) {
|
||||
extractedLinks.forEach {
|
||||
callback.invoke(it)
|
||||
}
|
||||
}
|
||||
api.getSafeUrl(link, extractorUrl, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.apmap
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
|
@ -12,10 +13,16 @@ class VidSrcExtractor : ExtractorApi() {
|
|||
override val mainUrl = "https://v2.vidsrc.me"
|
||||
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 serverslist = iframedoc.select("div#sources.button_content div#content div#list div").map {
|
||||
val serverslist =
|
||||
iframedoc.select("div#sources.button_content div#content div#list div").map {
|
||||
val datahash = it.attr("data-hash")
|
||||
if (datahash.isNotBlank()) {
|
||||
val links = try {
|
||||
|
@ -27,20 +34,21 @@ class VidSrcExtractor : ExtractorApi() {
|
|||
} else ""
|
||||
}
|
||||
|
||||
return serverslist.apmap { server ->
|
||||
val linkfixed = server.replace("https://vidsrc.xyz/","https://embedsito.com/")
|
||||
serverslist.apmap { server ->
|
||||
val linkfixed = server.replace("https://vidsrc.xyz/", "https://embedsito.com/")
|
||||
if (linkfixed.contains("/pro")) {
|
||||
val srcresponse = app.get(server, referer = mainUrl).text
|
||||
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(
|
||||
name,
|
||||
srcm3u8,
|
||||
mainUrl
|
||||
)
|
||||
).forEach(callback)
|
||||
} else {
|
||||
loadExtractor(linkfixed, url)
|
||||
loadExtractor(linkfixed, url, subtitleCallback, callback)
|
||||
}
|
||||
}.flatten()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.apmap
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.argamap
|
||||
|
@ -30,15 +31,19 @@ class Vidstream(val mainUrl: String) {
|
|||
suspend fun getUrl(
|
||||
id: String,
|
||||
isCasting: Boolean = false,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit,
|
||||
): Boolean {
|
||||
val extractorUrl = getExtractorUrl(id)
|
||||
argamap(
|
||||
{
|
||||
normalApis.apmap { api ->
|
||||
val url = api.getExtractorUrl(id)
|
||||
val source = api.getSafeUrl(url)
|
||||
source?.forEach { callback.invoke(it) }
|
||||
api.getSafeUrl(
|
||||
url,
|
||||
callback = callback,
|
||||
subtitleCallback = subtitleCallback
|
||||
)
|
||||
}
|
||||
}, {
|
||||
/** Stolen from GogoanimeProvider.kt extractor */
|
||||
|
@ -57,7 +62,7 @@ class Vidstream(val mainUrl: String) {
|
|||
) "1080" else qualityRegex.find(element.text())?.destructured?.component1()
|
||||
.toString()
|
||||
|
||||
if (!loadExtractor(href, link, callback)) {
|
||||
if (!loadExtractor(href, link, subtitleCallback, callback)) {
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
|
@ -84,12 +89,7 @@ class Vidstream(val mainUrl: String) {
|
|||
// Matches vidstream links with extractors
|
||||
extractorApis.filter { !it.requiresReferer || !isCasting }.apmap { api ->
|
||||
if (link.startsWith(api.mainUrl)) {
|
||||
val extractedLinks = api.getSafeUrl(link, extractorUrl)
|
||||
if (extractedLinks?.isNotEmpty() == true) {
|
||||
extractedLinks.forEach {
|
||||
callback.invoke(it)
|
||||
}
|
||||
}
|
||||
api.getSafeUrl(link, extractorUrl, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.ErrorLoadingException
|
||||
import com.lagradost.cloudstream3.mvvm.Resource
|
||||
import com.lagradost.cloudstream3.mvvm.safeApiCall
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.schemaStripRegex
|
||||
import org.schabi.newpipe.extractor.ServiceList
|
||||
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor
|
||||
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory
|
||||
import org.schabi.newpipe.extractor.stream.SubtitlesStream
|
||||
import org.schabi.newpipe.extractor.stream.VideoStream
|
||||
|
||||
class YoutubeShortLinkExtractor : YoutubeExtractor() {
|
||||
|
@ -26,15 +26,20 @@ open class YoutubeExtractor : ExtractorApi() {
|
|||
|
||||
companion object {
|
||||
private var ytVideos: MutableMap<String, List<VideoStream>> = mutableMapOf()
|
||||
private var ytVideosSubtitles: MutableMap<String, List<SubtitlesStream>> = mutableMapOf()
|
||||
}
|
||||
|
||||
override fun getExtractorUrl(id: String): String {
|
||||
return "$mainUrl/watch?v=$id"
|
||||
}
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val streams = safeApiCall {
|
||||
val streams = ytVideos[url] ?: let {
|
||||
override suspend fun getUrl(
|
||||
url: String,
|
||||
referer: String?,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
if (ytVideos[url].isNullOrEmpty()) {
|
||||
val link =
|
||||
YoutubeStreamLinkHandlerFactory.getInstance().fromUrl(
|
||||
url.replace(
|
||||
|
@ -49,21 +54,15 @@ open class YoutubeExtractor : ExtractorApi() {
|
|||
|
||||
}
|
||||
s.fetchPage()
|
||||
val streams = s.videoStreams ?: return@let emptyList()
|
||||
ytVideos[url] = streams
|
||||
streams
|
||||
ytVideos[url] = s.videoStreams
|
||||
ytVideosSubtitles[url] = try {
|
||||
s.subtitlesDefault.filterNotNull()
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
emptyList()
|
||||
}
|
||||
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 {
|
||||
ytVideos[url]?.mapNotNull {
|
||||
if (it.isVideoOnly || it.height <= 0) return@mapNotNull null
|
||||
|
||||
ExtractorLink(
|
||||
|
@ -73,9 +72,10 @@ open class YoutubeExtractor : ExtractorApi() {
|
|||
"",
|
||||
it.height
|
||||
)
|
||||
}?.forEach(callback)
|
||||
ytVideosSubtitles[url]?.mapNotNull {
|
||||
SubtitleFile(it.languageTag ?: return@mapNotNull null, it.url ?: return@mapNotNull null)
|
||||
}?.forEach(subtitleCallback)
|
||||
}
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package com.lagradost.cloudstream3.extractors.helper
|
||||
|
||||
import android.util.Log
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.apmap
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
|
@ -8,7 +9,11 @@ import com.lagradost.cloudstream3.utils.loadExtractor
|
|||
|
||||
class AsianEmbedHelper {
|
||||
companion object {
|
||||
suspend fun getUrls(url: String, callback: (ExtractorLink) -> Unit) {
|
||||
suspend fun getUrls(
|
||||
url: String,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
// Fetch links
|
||||
val doc = app.get(url).document
|
||||
val links = doc.select("div#list-server-more > ul > li.linkserver")
|
||||
|
@ -17,7 +22,7 @@ class AsianEmbedHelper {
|
|||
val datavid = it.attr("data-video") ?: ""
|
||||
//Log.i("AsianEmbed", "Result => (datavid) ${datavid}")
|
||||
if (datavid.isNotBlank()) {
|
||||
val res = loadExtractor(datavid, url, callback)
|
||||
val res = loadExtractor(datavid, url, subtitleCallback, callback)
|
||||
Log.i("AsianEmbed", "Result => ($res) (datavid) $datavid")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.lagradost.cloudstream3.extractors.helper
|
||||
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
|
@ -10,7 +11,11 @@ class VstreamhubHelper {
|
|||
private val baseUrl: String = "https://vstreamhub.com"
|
||||
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)) {
|
||||
// Fetch links
|
||||
val doc = app.get(url).document.select("script")
|
||||
|
@ -20,7 +25,8 @@ class VstreamhubHelper {
|
|||
if (innerText.contains("file:")) {
|
||||
val startString = "file: "
|
||||
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}")
|
||||
val exlink = ExtractorLink(
|
||||
name = "$baseName m3u8",
|
||||
|
@ -33,12 +39,14 @@ class VstreamhubHelper {
|
|||
callback.invoke(exlink)
|
||||
}
|
||||
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 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()) {
|
||||
loadExtractor(datavid, url, callback)
|
||||
loadExtractor(datavid, url, subtitleCallback, callback)
|
||||
//Log.i(baseName, "Result => (datavid) ${datavid}")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -197,9 +197,9 @@ class AllMoviesForYouProvider : MainAPI() {
|
|||
val soup = app.get(id).document
|
||||
soup.select("body iframe").map {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@ package com.lagradost.cloudstream3.movieproviders
|
|||
|
||||
import androidx.core.text.parseAsHtml
|
||||
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.mvvm.logError
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
|
||||
|
||||
class AltadefinizioneProvider : MainAPI() {
|
||||
|
@ -55,16 +55,18 @@ class AltadefinizioneProvider : MainAPI() {
|
|||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val doc = app.post("$mainUrl/index.php", data = mapOf(
|
||||
val doc = app.post(
|
||||
"$mainUrl/index.php", data = mapOf(
|
||||
"do" to "search",
|
||||
"subaction" to "search",
|
||||
"story" to query,
|
||||
"sortby" to "news_read"
|
||||
)).document
|
||||
)
|
||||
).document
|
||||
return doc.select("div.box").map {
|
||||
val title = it.selectFirst("img")!!.attr("alt")
|
||||
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())
|
||||
|
||||
MovieSearchResponse(
|
||||
|
@ -83,11 +85,13 @@ class AltadefinizioneProvider : MainAPI() {
|
|||
override suspend fun load(url: String): LoadResponse {
|
||||
val page = app.get(url)
|
||||
val document = page.document
|
||||
val title = document.selectFirst(" h1 > a")!!.text().replace("streaming","")
|
||||
val description = document.select("#sfull").toString().substringAfter("altadefinizione").substringBeforeLast("fonte trama").parseAsHtml().toString()
|
||||
val title = document.selectFirst(" h1 > a")!!.text().replace("streaming", "")
|
||||
val description = document.select("#sfull").toString().substringAfter("altadefinizione")
|
||||
.substringBeforeLast("fonte trama").parseAsHtml().toString()
|
||||
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"))
|
||||
|
||||
|
@ -142,23 +146,21 @@ class AltadefinizioneProvider : MainAPI() {
|
|||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val doc = app.get(data).document
|
||||
if (doc.select("div.guardahd-player").isNullOrEmpty()){
|
||||
val videoUrl = doc.select("input").filter { it.hasAttr("data-mirror") }.last().attr("value")
|
||||
loadExtractor(videoUrl, data, callback)
|
||||
if (doc.select("div.guardahd-player").isNullOrEmpty()) {
|
||||
val videoUrl =
|
||||
doc.select("input").filter { it.hasAttr("data-mirror") }.last().attr("value")
|
||||
loadExtractor(videoUrl, data, subtitleCallback, callback)
|
||||
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 docLinks = app.get(pagelinks).document
|
||||
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
|
||||
}
|
||||
}
|
|
@ -27,8 +27,14 @@ open class BflixProvider : MainAPI() {
|
|||
Pair("Movies", "div.tab-content[data-name=movies] div.filmlist div.item"),
|
||||
Pair("Shows", "div.tab-content[data-name=shows] div.filmlist div.item"),
|
||||
Pair("Trending", "div.tab-content[data-name=trending] div.filmlist div.item"),
|
||||
Pair("Latest Movies", "div.container section.bl:contains(Latest Movies) div.filmlist div.item"),
|
||||
Pair("Latest TV-Series", "div.container section.bl:contains(Latest TV-Series) div.filmlist div.item"),
|
||||
Pair(
|
||||
"Latest Movies",
|
||||
"div.container section.bl:contains(Latest Movies) div.filmlist div.item"
|
||||
),
|
||||
Pair(
|
||||
"Latest TV-Series",
|
||||
"div.container section.bl:contains(Latest TV-Series) div.filmlist div.item"
|
||||
),
|
||||
)
|
||||
for ((name, element) in testa) try {
|
||||
val test = soup.select(element).map {
|
||||
|
@ -57,7 +63,8 @@ open class BflixProvider : MainAPI() {
|
|||
}
|
||||
|
||||
//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? {
|
||||
val reversed = ue(encode(id) + "0000000").slice(0..5).reversed()
|
||||
|
@ -232,15 +239,16 @@ open class BflixProvider : MainAPI() {
|
|||
|
||||
val eptitle = it.selectFirst(".episode a span.name")!!.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(
|
||||
href,
|
||||
secondtitle+eptitle,
|
||||
secondtitle + eptitle,
|
||||
season,
|
||||
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 =
|
||||
soup.select("div.bl-2 section.bl div.content div.filmlist div.item")
|
||||
?.mapNotNull { element ->
|
||||
|
@ -261,9 +269,12 @@ open class BflixProvider : MainAPI() {
|
|||
val durationregex = Regex("((\\d+) min)")
|
||||
val yearegex = Regex("<span>(\\d+)<\\/span>")
|
||||
val duration = if (durationdoc.contains("na min")) null
|
||||
else durationregex.find(durationdoc)?.destructured?.component1()?.replace(" min","")?.toIntOrNull()
|
||||
val year = if (mainUrl == "https://bflix.ru") { yearegex.find(durationdoc)?.destructured?.component1()
|
||||
?.replace(Regex("<span>|<\\/span>"),"") } else null
|
||||
else durationregex.find(durationdoc)?.destructured?.component1()?.replace(" min", "")
|
||||
?.toIntOrNull()
|
||||
val year = if (mainUrl == "https://bflix.ru") {
|
||||
yearegex.find(durationdoc)?.destructured?.component1()
|
||||
?.replace(Regex("<span>|<\\/span>"), "")
|
||||
} else null
|
||||
return when (tvType) {
|
||||
TvType.TvSeries -> {
|
||||
TvSeriesLoadResponse(
|
||||
|
@ -343,7 +354,8 @@ open class BflixProvider : MainAPI() {
|
|||
val a = it.select("a").map {
|
||||
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")
|
||||
else
|
||||
it.select(".episode a[href=$cleandata]").attr("data-ep")
|
||||
|
@ -364,7 +376,7 @@ open class BflixProvider : MainAPI() {
|
|||
?.replace("/embed/", "/e/")?.replace(Regex("(\\?sub.info.*)"), "")
|
||||
}.apmap { url ->
|
||||
loadExtractor(
|
||||
url, data, callback
|
||||
url, data, subtitleCallback, callback
|
||||
)
|
||||
}
|
||||
//Apparently any server works, I haven't found any diference
|
||||
|
|
|
@ -155,7 +155,7 @@ class CineblogProvider : MainAPI() {
|
|||
rating,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
mutableListOf(),
|
||||
recomm
|
||||
)
|
||||
} else {
|
||||
|
@ -205,7 +205,7 @@ class CineblogProvider : MainAPI() {
|
|||
|
||||
val url2= Regex("""src='((.|\\n)*?)'""").find(test.text)?.groups?.get(1)?.value.toString()
|
||||
val trueUrl = app.get(url2, headers = mapOf("referer" to mainUrl)).url
|
||||
loadExtractor(trueUrl, data, callback)
|
||||
loadExtractor(trueUrl, data, subtitleCallback, callback)
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import com.lagradost.cloudstream3.mvvm.logError
|
|||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
|
||||
class CinecalidadProvider:MainAPI() {
|
||||
class CinecalidadProvider : MainAPI() {
|
||||
override var mainUrl = "https://cinecalidad.lol"
|
||||
override var name = "Cinecalidad"
|
||||
override var lang = "es"
|
||||
|
@ -98,7 +98,8 @@ class CinecalidadProvider:MainAPI() {
|
|||
val href = li.selectFirst("a")!!.attr("href")
|
||||
val epThumb = li.selectFirst("img.lazy")!!.attr("data-src")
|
||||
val name = li.selectFirst(".episodiotitle a")!!.text()
|
||||
val seasonid = li.selectFirst(".numerando")!!.text().replace(Regex("(S|E)"),"").let { str ->
|
||||
val seasonid =
|
||||
li.selectFirst(".numerando")!!.text().replace(Regex("(S|E)"), "").let { str ->
|
||||
str.split("-").mapNotNull { subStr -> subStr.toIntOrNull() }
|
||||
}
|
||||
val isValid = seasonid.size == 2
|
||||
|
@ -112,7 +113,8 @@ class CinecalidadProvider:MainAPI() {
|
|||
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 -> {
|
||||
TvSeriesLoadResponse(
|
||||
title,
|
||||
|
@ -156,18 +158,18 @@ class CinecalidadProvider:MainAPI() {
|
|||
val url = it.attr("data-option")
|
||||
if (url.startsWith("https://cinestart.net")) {
|
||||
val extractor = Cinestart()
|
||||
extractor.getSafeUrl(url)?.forEach { link ->
|
||||
callback.invoke(link)
|
||||
}
|
||||
extractor.getSafeUrl(url, null, subtitleCallback, callback)
|
||||
} else {
|
||||
loadExtractor(url, mainUrl, callback)
|
||||
loadExtractor(url, mainUrl, subtitleCallback, callback)
|
||||
}
|
||||
if (url.startsWith("https://cinecalidad.lol")) {
|
||||
val cineurlregex = Regex("(https:\\/\\/cinecalidad\\.lol\\/play\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
|
||||
val cineurlregex =
|
||||
Regex("(https:\\/\\/cinecalidad\\.lol\\/play\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
|
||||
cineurlregex.findAll(url).map {
|
||||
it.value.replace("/play/","/play/r.php")
|
||||
it.value.replace("/play/", "/play/r.php")
|
||||
}.toList().apmap {
|
||||
app.get(it,
|
||||
app.get(
|
||||
it,
|
||||
headers = mapOf(
|
||||
"Host" to "cinecalidad.lol",
|
||||
"User-Agent" to USER_AGENT,
|
||||
|
@ -182,31 +184,33 @@ class CinecalidadProvider:MainAPI() {
|
|||
"Sec-Fetch-Site" to "same-origin",
|
||||
"Sec-Fetch-User" to "?1",
|
||||
),
|
||||
allowRedirects = false).okhttpResponse.headers.values("location").apmap { extractedurl ->
|
||||
allowRedirects = false
|
||||
).okhttpResponse.headers.values("location").apmap { extractedurl ->
|
||||
if (extractedurl.contains("cinestart")) {
|
||||
loadExtractor(extractedurl, mainUrl, callback)
|
||||
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")
|
||||
.apmap {
|
||||
val url = it.attr("data-option")
|
||||
if (url.startsWith("https://cinestart.net")) {
|
||||
val extractor = Cinestart()
|
||||
extractor.getSafeUrl(url)?.forEach { link ->
|
||||
callback.invoke(link)
|
||||
}
|
||||
extractor.getSafeUrl(url, null, subtitleCallback, callback)
|
||||
} else {
|
||||
loadExtractor(url, mainUrl, callback)
|
||||
loadExtractor(url, mainUrl, subtitleCallback, callback)
|
||||
}
|
||||
|
||||
if (url.startsWith("https://cinecalidad.lol")) {
|
||||
val cineurlregex = Regex("(https:\\/\\/cinecalidad\\.lol\\/play\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
|
||||
val cineurlregex =
|
||||
Regex("(https:\\/\\/cinecalidad\\.lol\\/play\\/\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
|
||||
cineurlregex.findAll(url).map {
|
||||
it.value.replace("/play/","/play/r.php")
|
||||
it.value.replace("/play/", "/play/r.php")
|
||||
}.toList().apmap {
|
||||
app.get(it,
|
||||
app.get(
|
||||
it,
|
||||
headers = mapOf(
|
||||
"Host" to "cinecalidad.lol",
|
||||
"User-Agent" to USER_AGENT,
|
||||
|
@ -221,9 +225,10 @@ class CinecalidadProvider:MainAPI() {
|
|||
"Sec-Fetch-Site" to "same-origin",
|
||||
"Sec-Fetch-User" to "?1",
|
||||
),
|
||||
allowRedirects = false).okhttpResponse.headers.values("location").apmap { extractedurl ->
|
||||
allowRedirects = false
|
||||
).okhttpResponse.headers.values("location").apmap { extractedurl ->
|
||||
if (extractedurl.contains("cinestart")) {
|
||||
loadExtractor(extractedurl, mainUrl, callback)
|
||||
loadExtractor(extractedurl, mainUrl, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -231,7 +236,8 @@ class CinecalidadProvider:MainAPI() {
|
|||
}
|
||||
if (datatext.contains("Subtítulo LAT") || datatext.contains("Forzados LAT")) {
|
||||
doc.select("#panel_descarga.pane a").apmap {
|
||||
val link = if (data.contains("serie") || data.contains("episodio")) "${data}${it.attr("href")}"
|
||||
val link =
|
||||
if (data.contains("serie") || data.contains("episodio")) "${data}${it.attr("href")}"
|
||||
else it.attr("href")
|
||||
val docsub = app.get(link)
|
||||
val linksub = docsub.document
|
||||
|
@ -241,7 +247,10 @@ class CinecalidadProvider:MainAPI() {
|
|||
val langdoc = linksub.selectFirst("div.titulo h3")!!.text()
|
||||
val reallang = langregex.find(langdoc)?.destructured?.component1()
|
||||
linksub.select("a.link").apmap {
|
||||
val sublink = if (data.contains("serie") || data.contains("episodio")) "${data}${it.attr("href")}"
|
||||
val sublink =
|
||||
if (data.contains("serie") || data.contains("episodio")) "${data}${
|
||||
it.attr("href")
|
||||
}"
|
||||
else it.attr("href")
|
||||
subtitleCallback(
|
||||
SubtitleFile(reallang!!, sublink)
|
||||
|
|
|
@ -227,7 +227,7 @@ class CuevanaProvider : MainAPI() {
|
|||
val json = parseJson<Femcuevana>(url)
|
||||
val link = json.url
|
||||
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))
|
||||
).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))
|
||||
).okhttpResponse.headers.values("location").apmap { link ->
|
||||
loadExtractor(link, data, callback)
|
||||
loadExtractor(link, data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ class DoramasYTProvider : MainAPI() {
|
|||
callback.invoke(link)
|
||||
}
|
||||
} else {
|
||||
loadExtractor(url, mainUrl, callback)
|
||||
loadExtractor(url, mainUrl, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
|
|
@ -50,14 +50,15 @@ class DramaSeeProvider : MainAPI() {
|
|||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val url = "$mainUrl/search?q=$query"
|
||||
val document = app.get(url).document
|
||||
val posters = document.select ("div.film-poster")
|
||||
val posters = document.select("div.film-poster")
|
||||
|
||||
|
||||
return posters.mapNotNull {
|
||||
val innerA = it.select("a") ?: return@mapNotNull null
|
||||
val link = fixUrlNull(innerA.attr("href")) ?: 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 image = fixUrlNull(imgSrc)
|
||||
|
||||
|
@ -193,7 +194,7 @@ class DramaSeeProvider : MainAPI() {
|
|||
val status = element.attr("data-status") ?: return@forEach
|
||||
if (status != "1") return@forEach
|
||||
val extractorData = element.attr("data-video") ?: return@forEach
|
||||
loadExtractor(extractorData, iframe.url, callback)
|
||||
loadExtractor(extractorData, iframe.url, subtitleCallback, callback)
|
||||
}
|
||||
}, {
|
||||
val iv = "9262859232435825"
|
||||
|
|
|
@ -206,7 +206,7 @@ class DramaidProvider : MainAPI() {
|
|||
}.apmap {
|
||||
when {
|
||||
it.contains("motonews.club") -> invokeDriveSource(it, this.name, subtitleCallback, callback)
|
||||
else -> loadExtractor(it, data, callback)
|
||||
else -> loadExtractor(it, data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ class ElifilmsProvider : MainAPI() {
|
|||
val encodedurl = it.attr("data-id")
|
||||
val urlDecoded = base64Decode(encodedurl)
|
||||
val url = fixUrl(urlDecoded)
|
||||
loadExtractor(url, data, callback)
|
||||
loadExtractor(url, data, subtitleCallback, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ class EntrepeliculasyseriesProvider:MainAPI() {
|
|||
data = mapOf(Pair("h", postkey)),
|
||||
allowRedirects = false
|
||||
).okhttpResponse.headers.values("location").apmap {
|
||||
loadExtractor(it, data, callback)
|
||||
loadExtractor(it, data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -189,7 +189,7 @@ class EstrenosDoramasProvider : MainAPI() {
|
|||
val document = app.get(data).document
|
||||
document.select("div.tab_container iframe").apmap { container ->
|
||||
val directlink = fixUrl(container.attr("src"))
|
||||
loadExtractor(directlink, data, callback)
|
||||
loadExtractor(directlink, data, subtitleCallback, callback)
|
||||
|
||||
if (directlink.contains("/repro/amz/")) {
|
||||
val amzregex = Regex("https:\\/\\/repro3\\.estrenosdoramas\\.us\\/repro\\/amz\\/examples\\/.*\\.php\\?key=.*\$")
|
||||
|
@ -239,7 +239,7 @@ class EstrenosDoramasProvider : MainAPI() {
|
|||
).text
|
||||
val extracteklink = link.substringAfter("\"urlremoto\":\"").substringBefore("\"}")
|
||||
.replace("\\/", "/").replace("//ok.ru/","http://ok.ru/")
|
||||
loadExtractor(extracteklink, data, callback)
|
||||
loadExtractor(extracteklink, data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,9 @@ package com.lagradost.cloudstream3.movieproviders
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
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.select.Elements
|
||||
|
||||
|
@ -59,9 +60,10 @@ class FilmanProvider : MainAPI() {
|
|||
if (movies.isEmpty() && series.isEmpty()) return ArrayList()
|
||||
fun getVideos(type: TvType, items: Elements): List<SearchResponse> {
|
||||
return items.mapNotNull { i ->
|
||||
val href = i.selectFirst(".poster > a")?.attr("href")?: return@mapNotNull null
|
||||
val img = i.selectFirst(".poster > a > img")?.attr("src")?.replace("/thumb/", "/big/")
|
||||
val name = i.selectFirst(".film_title")?.text()?: 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 name = i.selectFirst(".film_title")?.text() ?: return@mapNotNull null
|
||||
val year = i.selectFirst(".film_year")?.text()?.toIntOrNull()
|
||||
if (type === TvType.TvSeries) {
|
||||
TvSeriesSearchResponse(
|
||||
|
@ -136,7 +138,7 @@ class FilmanProvider : MainAPI() {
|
|||
document?.select(".link-to-video")?.apmap { item ->
|
||||
val decoded = base64Decode(item.select("a").attr("data-iframe"))
|
||||
val link = tryParseJson<LinkElement>(decoded)?.src ?: return@apmap
|
||||
loadExtractor(link, null, callback)
|
||||
loadExtractor(link, subtitleCallback, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -224,15 +224,15 @@ class FilmpertuttiProvider : MainAPI() {
|
|||
tryParseJson<List<String>>(data)?.apmap { id ->
|
||||
if (id.contains("buckler")){
|
||||
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")){
|
||||
val doc1 = app.get(id).document
|
||||
val id2 = doc1.selectFirst("iframe")!!.attr("src")
|
||||
loadExtractor(id2, data, callback)
|
||||
loadExtractor(id2, data, subtitleCallback, callback)
|
||||
}
|
||||
else{
|
||||
loadExtractor(id, data, callback)
|
||||
loadExtractor(id, data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
|
|
@ -68,7 +68,7 @@ class FrenchStreamProvider : MainAPI() {
|
|||
?.mapNotNull { // all the tags like action, thriller ...; unused variable
|
||||
it?.text()
|
||||
}
|
||||
return newMovieLoadResponse(title,url,TvType.Movie,url) {
|
||||
return newMovieLoadResponse(title, url, TvType.Movie, url) {
|
||||
this.posterUrl = poster
|
||||
addRating(soup.select("div.fr-count > div").text())
|
||||
this.year = soup.select("ul.flist-col > li").getOrNull(2)?.text()?.toIntOrNull()
|
||||
|
@ -82,8 +82,7 @@ class FrenchStreamProvider : MainAPI() {
|
|||
//println("listeEpisode:")
|
||||
val episodeList = if ("<a" !in (listEpisode[0]).toString()) { // check if VF is empty
|
||||
listEpisode[1] // no vf, return vostfr
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
listEpisode[0] // no vostfr, return vf
|
||||
}
|
||||
|
||||
|
@ -223,7 +222,7 @@ class FrenchStreamProvider : MainAPI() {
|
|||
if (it.first.contains(extractor.name, ignoreCase = true)) {
|
||||
// val name = it.first
|
||||
// print("true for $name")
|
||||
extractor.getSafeUrl(it.second, it.second)?.forEach(callback)
|
||||
extractor.getSafeUrl(it.second, it.second, subtitleCallback, callback)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ class HDMovie5 : MainAPI() {
|
|||
(doc.select("#repimdb>strong").text().toFloatOrNull()?.times(1000))?.toInt(),
|
||||
info.select(".sgeneros>a").map { it.text() },
|
||||
info.select(".runtime").text().substringBefore(" Min.").toIntOrNull(),
|
||||
null,
|
||||
mutableListOf(),
|
||||
doc.select("#single_relacionados>article>a").map {
|
||||
val img = it.select("img")
|
||||
MovieSearchResponse(
|
||||
|
@ -149,7 +149,7 @@ class HDMovie5 : MainAPI() {
|
|||
val html = p.parsedSafe<PlayerAjaxResponse>()?.embedURL ?: return@apmapIndexed false
|
||||
val doc = Jsoup.parse(html)
|
||||
val link = doc.select("iframe").attr("src")
|
||||
loadExtractor(httpsify(link), "$mainUrl/", callback)
|
||||
loadExtractor(httpsify(link), "$mainUrl/", subtitleCallback, callback)
|
||||
}.contains(true)
|
||||
}
|
||||
}
|
|
@ -215,7 +215,7 @@ class IHaveNoTvProvider : MainAPI() {
|
|||
|
||||
val iframe = soup.selectFirst("#videoWrap iframe")
|
||||
if (iframe != null) {
|
||||
loadExtractor(iframe.attr("src"), null, callback)
|
||||
loadExtractor(iframe.attr("src"), null, subtitleCallback, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -365,7 +365,7 @@ class IdlixProvider : MainAPI() {
|
|||
if (source.startsWith("https://uservideo.xyz")) {
|
||||
source = app.get(source).document.select("iframe").attr("src")
|
||||
}
|
||||
loadExtractor(source, data, callback)
|
||||
loadExtractor(source, data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,9 @@ class KdramaHoodProvider : MainAPI() {
|
|||
val rex = Regex("\\((\\d+)")
|
||||
//Log.i(this.name, "Result => (rex value) ${rex.find(yearText)?.value}")
|
||||
rex.find(yearText)?.value?.toIntOrNull()
|
||||
} catch (e: Exception) { null }
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
MovieSearchResponse(
|
||||
name = title,
|
||||
|
@ -105,15 +107,21 @@ class KdramaHoodProvider : MainAPI() {
|
|||
val startLink = "https://kdramahood.com/drama-release-year/"
|
||||
var res: Int? = null
|
||||
info?.select("div.metadatac")?.forEach {
|
||||
if (res != null) { return@forEach }
|
||||
if (it == null) { return@forEach }
|
||||
if (res != null) {
|
||||
return@forEach
|
||||
}
|
||||
if (it == null) {
|
||||
return@forEach
|
||||
}
|
||||
val yearLink = it.select("a").attr("href") ?: return@forEach
|
||||
if (yearLink.startsWith(startLink)) {
|
||||
res = yearLink.substring(startLink.length).replace("/", "").toIntOrNull()
|
||||
}
|
||||
}
|
||||
res
|
||||
} catch (e: Exception) { null }
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
val recs = doc.select("div.sidebartv > div.tvitemrel").mapNotNull {
|
||||
val a = it?.select("a") ?: return@mapNotNull null
|
||||
|
@ -161,10 +169,13 @@ class KdramaHoodProvider : MainAPI() {
|
|||
}
|
||||
//Fetch default source and subtitles
|
||||
epVidLinkEl.select("div.embed2")?.forEach { defsrc ->
|
||||
if (defsrc == null) { return@forEach }
|
||||
if (defsrc == null) {
|
||||
return@forEach
|
||||
}
|
||||
val scriptstring = defsrc.toString()
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
@ -264,7 +275,7 @@ class KdramaHoodProvider : MainAPI() {
|
|||
//Log.i(this.name, "Result => (url) $url")
|
||||
when {
|
||||
url.startsWith("https://asianembed.io") -> {
|
||||
AsianEmbedHelper.getUrls(url, callback)
|
||||
AsianEmbedHelper.getUrls(url, subtitleCallback, callback)
|
||||
}
|
||||
url.startsWith("https://embedsito.com") -> {
|
||||
val extractor = XStreamCdn()
|
||||
|
@ -274,7 +285,7 @@ class KdramaHoodProvider : MainAPI() {
|
|||
}
|
||||
}
|
||||
else -> {
|
||||
loadExtractor(url, mainUrl, callback)
|
||||
loadExtractor(url, mainUrl, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -219,7 +219,7 @@ class LayarKacaProvider : MainAPI() {
|
|||
} else {
|
||||
it
|
||||
}
|
||||
loadExtractor(link, data, callback)
|
||||
loadExtractor(link, data, subtitleCallback, callback)
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
|
@ -126,7 +126,7 @@ class OpenVidsProvider:TmdbProvider() {
|
|||
membed.isUsingAdaptiveKeys,
|
||||
membed.isUsingAdaptiveData)
|
||||
} else
|
||||
loadExtractor(links, data, callback)
|
||||
loadExtractor(links, data, subtitleCallback, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -152,7 +152,7 @@ class PeliSmartProvider: MainAPI() {
|
|||
.replace("https://pelismarthd.com/p/1.php?v=","https://evoload.io/e/")
|
||||
.replace("https://pelismarthd.com/p/2.php?v=","https://streamtape.com/e/")
|
||||
.replace("https://pelismarthd.com/p/4.php?v=","https://dood.to/e/")
|
||||
loadExtractor(urlc, data, callback)
|
||||
loadExtractor(urlc, data, subtitleCallback, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -222,7 +222,7 @@ class PelisflixProvider : MainAPI() {
|
|||
allowRedirects = false
|
||||
).okhttpResponse.headers.values("location").apmap { link ->
|
||||
val url1 = link.replace("#bu", "")
|
||||
loadExtractor(url1, data, callback)
|
||||
loadExtractor(url1, data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -165,7 +165,7 @@ class PelisplusHDProvider:MainAPI() {
|
|||
): Boolean {
|
||||
app.get(data).document.select("div.player > script").map { script ->
|
||||
fetchUrls(script.data().replace("https://pelisplushd.net/fembed.php?url=","https://www.fembed.com/v/")).apmap {
|
||||
loadExtractor(it, data, callback)
|
||||
loadExtractor(it, data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
|
|
@ -229,7 +229,7 @@ open class PelisplusProviderTemplate : MainAPI() {
|
|||
if (info.contains("Latino")) {
|
||||
doc.select(".server-item-1 li").apmap {
|
||||
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")) {
|
||||
getPelisStream(serverid, callback)
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ open class PelisplusProviderTemplate : MainAPI() {
|
|||
if (info.contains("Subtitulado")) {
|
||||
doc.select(".server-item-0 li").apmap {
|
||||
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")) {
|
||||
getPelisStream(serverid, callback)
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ open class PelisplusProviderTemplate : MainAPI() {
|
|||
if (info.contains("Castellano")) {
|
||||
doc.select(".server-item-2 li").apmap {
|
||||
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")) {
|
||||
getPelisStream(serverid, callback)
|
||||
}
|
||||
|
|
|
@ -221,7 +221,7 @@ class PinoyHDXyzProvider : MainAPI() {
|
|||
mapper.readValue<List<String>>(data).forEach { item ->
|
||||
val url = item.trim()
|
||||
if (url.isNotBlank()) {
|
||||
if (loadExtractor(url, mainUrl, callback)) {
|
||||
if (loadExtractor(url, mainUrl, subtitleCallback, callback)) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
|
|
@ -231,7 +231,7 @@ class PinoyMoviePediaProvider : MainAPI() {
|
|||
callback.invoke(it)
|
||||
}
|
||||
} else {
|
||||
loadExtractor(link, mainUrl, callback)
|
||||
loadExtractor(link, mainUrl, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
return count > 0
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.lagradost.cloudstream3.movieproviders
|
||||
|
||||
import android.util.Log
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.extractors.FEmbed
|
||||
|
@ -26,7 +25,11 @@ class PinoyMoviesEsProvider : MainAPI() {
|
|||
@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>()
|
||||
for (item in rows) {
|
||||
val title = item.first
|
||||
|
@ -36,10 +39,14 @@ class PinoyMoviesEsProvider : MainAPI() {
|
|||
if (urlTitle.isNullOrEmpty()) {
|
||||
urlTitle = it?.select("div.data")
|
||||
}
|
||||
if (urlTitle.isNullOrEmpty()) { return@mapNotNull null }
|
||||
if (urlTitle.isNullOrEmpty()) {
|
||||
return@mapNotNull null
|
||||
}
|
||||
// Fetch details
|
||||
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")
|
||||
|
||||
|
@ -47,7 +54,9 @@ class PinoyMoviesEsProvider : MainAPI() {
|
|||
val name = urlTitle.select("h3")?.text()
|
||||
?: urlTitle.select("h2")?.text()
|
||||
?: urlTitle.select("h1")?.text()
|
||||
if (name.isNullOrBlank()) { return@mapNotNull null }
|
||||
if (name.isNullOrBlank()) {
|
||||
return@mapNotNull null
|
||||
}
|
||||
|
||||
var year = urlTitle.select("span")?.text()?.toIntOrNull()
|
||||
|
||||
|
@ -80,27 +89,32 @@ class PinoyMoviesEsProvider : MainAPI() {
|
|||
}
|
||||
return all
|
||||
}
|
||||
|
||||
override suspend fun getMainPage(): HomePageResponse {
|
||||
val all = ArrayList<HomePageList>()
|
||||
val document = app.get(mainUrl).document
|
||||
val mainbody = document.getElementsByTag("body")
|
||||
if (mainbody != null) {
|
||||
// All rows will be hardcoded bc of the nature of the site
|
||||
val homepage1 = getRowElements(mainbody, listOf(
|
||||
val homepage1 = getRowElements(
|
||||
mainbody, listOf(
|
||||
Pair("Suggestion", "items.featured"),
|
||||
Pair("All Movies", "items.full")
|
||||
), ".")
|
||||
), "."
|
||||
)
|
||||
if (homepage1.isNotEmpty()) {
|
||||
all.addAll(homepage1)
|
||||
}
|
||||
//2nd rows
|
||||
val homepage2 = getRowElements(mainbody, listOf(
|
||||
val homepage2 = getRowElements(
|
||||
mainbody, listOf(
|
||||
Pair("Action", "genre_action"),
|
||||
Pair("Comedy", "genre_comedy"),
|
||||
Pair("Romance", "genre_romance"),
|
||||
Pair("Horror", "genre_horror")
|
||||
//Pair("Rated-R", "genre_rated-r")
|
||||
), "#")
|
||||
), "#"
|
||||
)
|
||||
if (homepage2.isNotEmpty()) {
|
||||
all.addAll(homepage2)
|
||||
}
|
||||
|
@ -156,7 +170,9 @@ class PinoyMoviesEsProvider : MainAPI() {
|
|||
val aName = a.select("img")?.attr("alt") ?: return@mapNotNull null
|
||||
val aYear = try {
|
||||
aName.trim().takeLast(5).removeSuffix(")").toIntOrNull()
|
||||
} catch (e: Exception) { null }
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
MovieSearchResponse(
|
||||
url = aUrl,
|
||||
name = aName,
|
||||
|
@ -181,8 +197,10 @@ class PinoyMoviesEsProvider : MainAPI() {
|
|||
Pair("nume", "1"),
|
||||
Pair("type", "movie")
|
||||
)
|
||||
val innerPage = app.post("https://pinoymovies.es/wp-admin/admin-ajax.php ",
|
||||
referer = url, data = content).document.select("body")?.text()?.trim()
|
||||
val innerPage = app.post(
|
||||
"https://pinoymovies.es/wp-admin/admin-ajax.php ",
|
||||
referer = url, data = content
|
||||
).document.select("body")?.text()?.trim()
|
||||
if (!innerPage.isNullOrBlank()) {
|
||||
tryParseJson<EmbedUrl>(innerPage)?.let {
|
||||
listOfLinks.add(it.embed_url)
|
||||
|
@ -214,7 +232,7 @@ class PinoyMoviesEsProvider : MainAPI() {
|
|||
tryParseJson<List<String>>(data)?.forEach { link ->
|
||||
//Log.i(this.name, "Result => (link) $link")
|
||||
if (link.startsWith("https://vstreamhub.com")) {
|
||||
VstreamhubHelper.getUrls(link, callback)
|
||||
VstreamhubHelper.getUrls(link, subtitleCallback, callback)
|
||||
count++
|
||||
} else if (link.contains("fembed.com")) {
|
||||
val extractor = FEmbed()
|
||||
|
@ -224,7 +242,7 @@ class PinoyMoviesEsProvider : MainAPI() {
|
|||
count++
|
||||
}
|
||||
} else {
|
||||
if (loadExtractor(link, mainUrl, callback)) {
|
||||
if (loadExtractor(link, mainUrl, subtitleCallback, callback)) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,12 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
|||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.mvvm.safeApiCall
|
||||
import com.lagradost.cloudstream3.network.WebViewResolver
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
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 java.net.URI
|
||||
import java.util.ArrayList
|
||||
|
||||
class RebahinProvider : MainAPI() {
|
||||
override var mainUrl = "http://167.88.14.149"
|
||||
|
@ -263,7 +264,7 @@ class RebahinProvider : MainAPI() {
|
|||
callback
|
||||
)
|
||||
else -> {
|
||||
loadExtractor(link, "$mainUrl/", callback)
|
||||
loadExtractor(link, "$mainUrl/", subtitleCallback, callback)
|
||||
if (link.startsWith("https://sbfull.com")) {
|
||||
val response = app.get(
|
||||
link, interceptor = WebViewResolver(
|
||||
|
|
|
@ -217,7 +217,7 @@ class SeriesflixProvider : MainAPI() {
|
|||
allowRedirects = false
|
||||
).okhttpResponse.headers.values("location").apmap { link ->
|
||||
val url1 = link.replace("#bu", "")
|
||||
loadExtractor(url1, data, callback)
|
||||
loadExtractor(url1, data, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import org.jsoup.Jsoup
|
|||
import org.jsoup.nodes.Element
|
||||
import java.net.URI
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
open class SflixProvider : MainAPI() {
|
||||
|
@ -346,7 +345,7 @@ open class SflixProvider : MainAPI() {
|
|||
"https://ws11.rabbitstream.net/socket.io/?EIO=4&transport=polling"
|
||||
|
||||
if (iframeLink.contains("streamlare", ignoreCase = true)) {
|
||||
loadExtractor(iframeLink, null).forEach(callback)
|
||||
loadExtractor(iframeLink, null,subtitleCallback,callback)
|
||||
} else {
|
||||
extractRabbitStream(iframeLink, subtitleCallback, callback, false) { it }
|
||||
}
|
||||
|
|
|
@ -232,7 +232,7 @@ class TantifilmProvider : MainAPI() {
|
|||
iframe.forEach { id ->
|
||||
val doc2 = app.get(id).document
|
||||
val id2 = app.get(doc2.selectFirst("iframe")!!.attr("src")).url
|
||||
loadExtractor(id2, data, callback)
|
||||
loadExtractor(id2, data, subtitleCallback, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ class TwoEmbedProvider : TmdbProvider() {
|
|||
if (iframeLink.contains("rabbitstream")) {
|
||||
extractRabbitStream(iframeLink, subtitleCallback, callback, false) { it }
|
||||
} else {
|
||||
loadExtractor(iframeLink, embedUrl, callback)
|
||||
loadExtractor(iframeLink, embedUrl, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
|
|
@ -67,8 +67,10 @@ open class VidstreamProviderTemplate : MainAPI() {
|
|||
open val iv: String? = null
|
||||
open val secretKey: String? = null
|
||||
open val secretDecryptKey: String? = null
|
||||
|
||||
/** Generated the key from IV and ID */
|
||||
open val isUsingAdaptiveKeys: Boolean = false
|
||||
|
||||
/**
|
||||
* Generate data for the encrypt-ajax automatically (only on supported sites)
|
||||
* See $("script[data-name='episode']")[0].dataset.value
|
||||
|
@ -260,7 +262,16 @@ open class VidstreamProviderTemplate : MainAPI() {
|
|||
val iframeLink =
|
||||
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.
|
||||
// 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)
|
||||
|
@ -268,7 +279,7 @@ open class VidstreamProviderTemplate : MainAPI() {
|
|||
val id = Regex("""id=([^&]*)""").find(iframeLink)?.groupValues?.get(1)
|
||||
|
||||
if (id != null) {
|
||||
vidstreamObject.getUrl(id, isCasting, callback)
|
||||
vidstreamObject.getUrl(id, isCasting, subtitleCallback, callback)
|
||||
}
|
||||
|
||||
val html = app.get(fixUrl(iframeLink)).text
|
||||
|
|
|
@ -22,7 +22,7 @@ class WatchAsianProvider : MainAPI() {
|
|||
val headers = mapOf("X-Requested-By" to mainUrl)
|
||||
val doc = app.get(mainUrl, headers = headers).document
|
||||
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 ->
|
||||
val link = row?.attr("data-tab") ?: return@mapNotNull null
|
||||
val title = row.text() ?: return@mapNotNull null
|
||||
|
@ -77,12 +77,12 @@ class WatchAsianProvider : MainAPI() {
|
|||
return document.mapNotNull {
|
||||
val innerA = it?.selectFirst("a") ?: 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()) {
|
||||
return@mapNotNull 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)
|
||||
//Log.i(this.name, "Result => (img movie) $title / $link")
|
||||
MovieSearchResponse(
|
||||
|
@ -100,31 +100,31 @@ class WatchAsianProvider : MainAPI() {
|
|||
val body = app.get(url).document
|
||||
// Declare vars
|
||||
val isDramaDetail = url.contains("/drama-detail/")
|
||||
var poster = ""
|
||||
var poster: String? = null
|
||||
var title = ""
|
||||
var descript: String? = null
|
||||
var year: Int? = null
|
||||
var tags: List<String>? = null
|
||||
if (isDramaDetail) {
|
||||
val main = body.select("div.details")
|
||||
val inner = main?.select("div.info")
|
||||
val inner = main.select("div.info")
|
||||
// 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}")
|
||||
title = inner?.select("h1")?.firstOrNull()?.text() ?: ""
|
||||
title = inner.select("h1").firstOrNull()?.text() ?: ""
|
||||
//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 =
|
||||
p?.selectFirst("span")?.text()?.trim()?.lowercase()?.removeSuffix(":")?.trim()
|
||||
?: return@forEach
|
||||
when (caption) {
|
||||
"genre" -> {
|
||||
tags = p.select("a")?.mapNotNull { it?.text()?.trim() }
|
||||
tags = p.select("a").mapNotNull { it?.text()?.trim() }
|
||||
}
|
||||
"released" -> {
|
||||
year = p.select("a")?.text()?.trim()?.toIntOrNull()
|
||||
year = p.select("a").text().trim()?.toIntOrNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ class WatchAsianProvider : MainAPI() {
|
|||
|
||||
// Episodes Links
|
||||
//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")}")
|
||||
val innerA = ep.select("a") ?: return@mapNotNull null
|
||||
//Log.i(this.name, "Result => (innerA) ${fixUrlNull(innerA.attr("href"))}")
|
||||
|
@ -164,7 +164,7 @@ class WatchAsianProvider : MainAPI() {
|
|||
posterUrl = poster,
|
||||
date = null
|
||||
)
|
||||
} ?: listOf()
|
||||
}
|
||||
//If there's only 1 episode, consider it a movie.
|
||||
if (episodeList.size == 1) {
|
||||
//Clean title
|
||||
|
@ -216,21 +216,24 @@ class WatchAsianProvider : MainAPI() {
|
|||
url.startsWith("https://asianembed.io") || url.startsWith("https://asianload.io") -> {
|
||||
val iv = "9262859232435825"
|
||||
val secretKey = "93422192433952489752342908585752"
|
||||
extractVidstream(url, this.name, callback, iv, secretKey, secretKey,
|
||||
extractVidstream(
|
||||
url, this.name, callback, iv, secretKey, secretKey,
|
||||
isUsingAdaptiveKeys = false,
|
||||
isUsingAdaptiveData = false
|
||||
)
|
||||
AsianEmbedHelper.getUrls(url, callback)
|
||||
AsianEmbedHelper.getUrls(url, subtitleCallback, callback)
|
||||
}
|
||||
url.startsWith("https://embedsito.com") -> {
|
||||
val extractor = XStreamCdn()
|
||||
extractor.domainUrl = "embedsito.com"
|
||||
extractor.getSafeUrl(url)?.apmap { link ->
|
||||
callback.invoke(link)
|
||||
}
|
||||
extractor.getSafeUrl(
|
||||
url,
|
||||
subtitleCallback = subtitleCallback,
|
||||
callback = callback,
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
loadExtractor(url, mainUrl, callback)
|
||||
loadExtractor(url, mainUrl, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -240,8 +243,8 @@ class WatchAsianProvider : MainAPI() {
|
|||
private suspend fun getServerLinks(url: String): String {
|
||||
val moviedoc = app.get(url, referer = mainUrl).document
|
||||
return moviedoc.select("div.anime_muti_link > ul > li")
|
||||
?.mapNotNull {
|
||||
.mapNotNull {
|
||||
fixUrlNull(it?.attr("data-video")) ?: return@mapNotNull null
|
||||
}?.toJson() ?: ""
|
||||
}.toJson()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import com.lagradost.cloudstream3.mvvm.safeApiCall
|
|||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.nodes.Element
|
||||
import java.util.ArrayList
|
||||
|
||||
class YomoviesProvider : MainAPI() {
|
||||
override var mainUrl = "https://yomovies.plus"
|
||||
|
@ -122,8 +121,15 @@ class YomoviesProvider : MainAPI() {
|
|||
source,
|
||||
referer = "$mainUrl/"
|
||||
).document.select("ul.list-server-items li")
|
||||
.apmap { loadExtractor(it.attr("data-video").substringBefore("=https://msubload"), "$mainUrl/", callback) }
|
||||
else -> loadExtractor(source, "$mainUrl/", callback)
|
||||
.apmap {
|
||||
loadExtractor(
|
||||
it.attr("data-video").substringBefore("=https://msubload"),
|
||||
"$mainUrl/",
|
||||
subtitleCallback,
|
||||
callback
|
||||
)
|
||||
}
|
||||
else -> loadExtractor(source, "$mainUrl/", subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -375,6 +375,7 @@ abstract class AbstractPlayerFragment(
|
|||
subView = player_view?.findViewById(R.id.exo_subtitles)
|
||||
subStyle = SubtitlesFragment.getCurrentSavedStyle()
|
||||
player.initSubtitles(subView, subtitle_holder, subStyle)
|
||||
|
||||
SubtitlesFragment.applyStyleEvent += ::onSubStyleChanged
|
||||
|
||||
try {
|
||||
|
|
|
@ -44,7 +44,9 @@ class LinkGenerator(
|
|||
offset: Int
|
||||
): Boolean {
|
||||
links.apmap { link ->
|
||||
if (!extract || !loadExtractor(link, referer) {
|
||||
if (!extract || !loadExtractor(link, referer, {
|
||||
subtitleCallback(PlayerSubtitleHelper.getSubtitleData(it))
|
||||
}) {
|
||||
callback(it to null)
|
||||
}) {
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.lagradost.cloudstream3.ui.player
|
||||
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
|
@ -89,6 +90,7 @@ class PlayerSubtitleHelper {
|
|||
regexSubtitlesToRemoveCaptions = style.removeCaptions
|
||||
subtitleView?.context?.let { ctx ->
|
||||
subStyle = style
|
||||
Log.i(TAG,"SET STYLE = $style")
|
||||
subtitleView?.setStyle(ctx.fromSaveToStyle(style))
|
||||
subtitleView?.translationY = -style.elevation.toPx.toFloat()
|
||||
val size = style.fixedTextSize
|
||||
|
|
|
@ -1901,7 +1901,7 @@ class ResultFragment : ResultTrailerPlayer() {
|
|||
setRecommendations(d.recommendations, null)
|
||||
setActors(d.actors)
|
||||
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)) {
|
||||
syncModel.updateMetaAndUser()
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package com.lagradost.cloudstream3.utils
|
||||
|
||||
import android.net.Uri
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.TvType
|
||||
import com.lagradost.cloudstream3.USER_AGENT
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.extractors.*
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
|
||||
import kotlinx.coroutines.delay
|
||||
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.
|
||||
* */
|
||||
suspend fun loadExtractor(
|
||||
url: String,
|
||||
referer: String? = null,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val currentUrl = unshortenLinkSafe(url)
|
||||
|
@ -169,7 +183,7 @@ suspend fun loadExtractor(
|
|||
if (currentUrl.replace(schemaStripRegex, "")
|
||||
.startsWith(extractor.mainUrl.replace(schemaStripRegex, ""))
|
||||
) {
|
||||
extractor.getSafeUrl(currentUrl, referer)?.forEach(callback)
|
||||
extractor.getSafeUrl(currentUrl, referer, subtitleCallback, callback)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -177,20 +191,6 @@ suspend fun loadExtractor(
|
|||
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(
|
||||
//AllProvider(),
|
||||
WcoStream(),
|
||||
|
@ -372,14 +372,39 @@ abstract class ExtractorApi {
|
|||
abstract val mainUrl: String
|
||||
abstract val requiresReferer: Boolean
|
||||
|
||||
suspend fun getSafeUrl(url: String, referer: String? = null): List<ExtractorLink>? {
|
||||
return suspendSafeApiCall { getUrl(url, referer) }
|
||||
//suspend fun getSafeUrl(url: String, referer: String? = null): List<ExtractorLink>? {
|
||||
// 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
|
||||
*/
|
||||
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 {
|
||||
return id
|
||||
|
|
Loading…
Reference in a new issue