forked from recloudstream/cloudstream
fixed search, made stuff more parallel
This commit is contained in:
parent
b0cadda315
commit
e0d9171f3e
26 changed files with 312 additions and 221 deletions
|
@ -115,13 +115,13 @@ object APIHolder {
|
|||
}
|
||||
|
||||
fun Context.getApiSettings(): HashSet<String> {
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
//val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
|
||||
val hashSet = HashSet<String>()
|
||||
val activeLangs = getApiProviderLangSettings()
|
||||
hashSet.addAll(apis.filter { activeLangs.contains(it.lang) }.map { it.name })
|
||||
|
||||
val set = settingsManager.getStringSet(
|
||||
/*val set = settingsManager.getStringSet(
|
||||
this.getString(R.string.search_providers_list_key),
|
||||
hashSet
|
||||
)?.toHashSet() ?: hashSet
|
||||
|
@ -132,9 +132,10 @@ object APIHolder {
|
|||
if (activeLangs.contains(api.lang)) {
|
||||
list.add(name)
|
||||
}
|
||||
}
|
||||
if (list.isEmpty()) return hashSet
|
||||
return list
|
||||
}*/
|
||||
//if (list.isEmpty()) return hashSet
|
||||
//return list
|
||||
return hashSet
|
||||
}
|
||||
|
||||
fun Context.getApiDubstatusSettings(): HashSet<DubStatus> {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.lagradost.cloudstream3
|
||||
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
|
@ -43,8 +44,17 @@ fun <A, B> List<A>.apmap(f: suspend (A) -> B): List<B> = runBlocking {
|
|||
exec.awaitTermination(1, TimeUnit.DAYS)
|
||||
}*/
|
||||
|
||||
// built in try catch
|
||||
fun <R> argamap(
|
||||
vararg transforms: suspend () -> R,
|
||||
) = runBlocking {
|
||||
transforms.map { async { it.invoke() } }.map { it.await() }
|
||||
transforms.map {
|
||||
async {
|
||||
try {
|
||||
it.invoke()
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
}.map { it.await() }
|
||||
}
|
|
@ -258,7 +258,7 @@ class AllAnimeProvider : MainAPI() {
|
|||
|
||||
val sources = Regex("""sourceUrl[:=]"(.+?)"""").findAll(html).toList()
|
||||
.map { URLDecoder.decode(it.destructured.component1().sanitize(), "UTF-8") }
|
||||
sources.forEach {
|
||||
sources.apmap {
|
||||
var link = it
|
||||
if (URI(link).isAbsolute || link.startsWith("//")) {
|
||||
if (link.startsWith("//")) link = "https:$it"
|
||||
|
|
|
@ -95,9 +95,7 @@ class AnimeFlickProvider : MainAPI() {
|
|||
var alreadyAdded = false
|
||||
for (extractor in extractorApis) {
|
||||
if (link.startsWith(extractor.mainUrl)) {
|
||||
extractor.getSafeUrl(link, data)?.forEach {
|
||||
callback(it)
|
||||
}
|
||||
extractor.getSafeUrl(link, data)?.forEach(callback)
|
||||
alreadyAdded = true
|
||||
break
|
||||
}
|
||||
|
|
|
@ -52,8 +52,11 @@ class WcoProvider : MainAPI() {
|
|||
val nameHeader = filmDetail.selectFirst("> h3.film-name > a")
|
||||
val title = nameHeader.text().replace(" (Dub)", "")
|
||||
val href =
|
||||
nameHeader.attr("href").replace("/watch/", "/anime/").replace("-episode-.*".toRegex(), "/")
|
||||
val isDub = filmPoster.selectFirst("> div.film-poster-quality")?.text()?.contains("DUB") ?: false
|
||||
nameHeader.attr("href").replace("/watch/", "/anime/")
|
||||
.replace("-episode-.*".toRegex(), "/")
|
||||
val isDub =
|
||||
filmPoster.selectFirst("> div.film-poster-quality")?.text()?.contains("DUB")
|
||||
?: false
|
||||
val poster = filmPoster.selectFirst("> img").attr("data-src")
|
||||
val set: EnumSet<DubStatus> =
|
||||
EnumSet.of(if (isDub) DubStatus.Dubbed else DubStatus.Subbed)
|
||||
|
@ -84,8 +87,11 @@ class WcoProvider : MainAPI() {
|
|||
val img = fixUrl(i.selectFirst("img").attr("data-src"))
|
||||
val title = i.selectFirst("img").attr("title")
|
||||
val isDub = !i.select(".pick.film-poster-quality").isEmpty()
|
||||
val year = i.selectFirst(".film-detail.film-detail-fix > div > span:nth-child(1)").text().toIntOrNull()
|
||||
val type = i.selectFirst(".film-detail.film-detail-fix > div > span:nth-child(3)").text()
|
||||
val year =
|
||||
i.selectFirst(".film-detail.film-detail-fix > div > span:nth-child(1)").text()
|
||||
.toIntOrNull()
|
||||
val type =
|
||||
i.selectFirst(".film-detail.film-detail-fix > div > span:nth-child(3)").text()
|
||||
|
||||
returnValue.add(
|
||||
if (getType(type) == TvType.AnimeMovie) {
|
||||
|
@ -174,8 +180,9 @@ class WcoProvider : MainAPI() {
|
|||
val response = app.get(url, timeout = 120).text
|
||||
val document = Jsoup.parse(response)
|
||||
|
||||
val japaneseTitle = document.selectFirst("div.elements div.row > div:nth-child(1) > div.row-line:nth-child(1)")
|
||||
?.text()?.trim()?.replace("Other names:", "")?.trim()
|
||||
val japaneseTitle =
|
||||
document.selectFirst("div.elements div.row > div:nth-child(1) > div.row-line:nth-child(1)")
|
||||
?.text()?.trim()?.replace("Other names:", "")?.trim()
|
||||
|
||||
val canonicalTitle = document.selectFirst("meta[name=\"title\"]")
|
||||
?.attr("content")?.split("| W")?.get(0).toString()
|
||||
|
@ -187,22 +194,25 @@ class WcoProvider : MainAPI() {
|
|||
AnimeEpisode(it.attr("href"))
|
||||
} ?: ArrayList())
|
||||
|
||||
val statusElem = document.selectFirst("div.elements div.row > div:nth-child(1) > div.row-line:nth-child(2)")
|
||||
val statusElem =
|
||||
document.selectFirst("div.elements div.row > div:nth-child(1) > div.row-line:nth-child(2)")
|
||||
val status = when (statusElem?.text()?.replace("Status:", "")?.trim()) {
|
||||
"Ongoing" -> ShowStatus.Ongoing
|
||||
"Completed" -> ShowStatus.Completed
|
||||
else -> null
|
||||
}
|
||||
val yearText =
|
||||
document.selectFirst("div.elements div.row > div:nth-child(2) > div.row-line:nth-child(4)")?.text()
|
||||
document.selectFirst("div.elements div.row > div:nth-child(2) > div.row-line:nth-child(4)")
|
||||
?.text()
|
||||
val year = yearText?.replace("Date release:", "")?.trim()?.split("-")?.get(0)?.toIntOrNull()
|
||||
|
||||
val poster = document.selectFirst(".film-poster-img")?.attr("src")
|
||||
val type = document.selectFirst("span.item.mr-1 > a")?.text()?.trim()
|
||||
|
||||
val synopsis = document.selectFirst(".description > p")?.text()?.trim()
|
||||
val genre = document.select("div.elements div.row > div:nth-child(1) > div.row-line:nth-child(5) > a")
|
||||
.map { it?.text()?.trim().toString() }
|
||||
val genre =
|
||||
document.select("div.elements div.row > div:nth-child(1) > div.row-line:nth-child(5) > a")
|
||||
.map { it?.text()?.trim().toString() }
|
||||
|
||||
return newAnimeLoadResponse(canonicalTitle, url, getType(type ?: "")) {
|
||||
japName = japaneseTitle
|
||||
|
@ -231,9 +241,7 @@ class WcoProvider : MainAPI() {
|
|||
}
|
||||
|
||||
for (server in servers) {
|
||||
WcoStream().getSafeUrl(server["link"].toString(), "")?.forEach {
|
||||
callback.invoke(it)
|
||||
}
|
||||
WcoStream().getSafeUrl(server["link"].toString(), "")?.forEach(callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package com.lagradost.cloudstream3.extractors
|
|||
|
||||
import com.lagradost.cloudstream3.apmap
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
|
||||
import com.lagradost.cloudstream3.argamap
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.extractorApis
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
|
@ -27,17 +27,22 @@ class Vidstream(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 {
|
||||
try {
|
||||
normalApis.apmap { api ->
|
||||
val url = api.getExtractorUrl(id)
|
||||
val source = api.getSafeUrl(url)
|
||||
source?.forEach { callback.invoke(it) }
|
||||
}
|
||||
val extractorUrl = getExtractorUrl(id)
|
||||
|
||||
/** Stolen from GogoanimeProvider.kt extractor */
|
||||
suspendSafeApiCall {
|
||||
suspend fun getUrl(
|
||||
id: String,
|
||||
isCasting: Boolean = false,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
println("VIDSTREAM:: $id")
|
||||
val extractorUrl = getExtractorUrl(id)
|
||||
argamap(
|
||||
{
|
||||
normalApis.apmap { api ->
|
||||
val url = api.getExtractorUrl(id)
|
||||
val source = api.getSafeUrl(url)
|
||||
source?.forEach { callback.invoke(it) }
|
||||
}
|
||||
}, {
|
||||
/** Stolen from GogoanimeProvider.kt extractor */
|
||||
val link = getDownloadUrl(id)
|
||||
println("Generated vidstream download link: $link")
|
||||
val page = app.get(link, referer = extractorUrl)
|
||||
|
@ -50,7 +55,8 @@ class Vidstream(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)) {
|
||||
callback.invoke(
|
||||
|
@ -65,34 +71,32 @@ class Vidstream(val mainUrl: String) {
|
|||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
with(app.get(extractorUrl)) {
|
||||
val document = Jsoup.parse(this.text)
|
||||
val primaryLinks = document.select("ul.list-server-items > li.linkserver")
|
||||
//val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||
|
||||
with(app.get(extractorUrl)) {
|
||||
val document = Jsoup.parse(this.text)
|
||||
val primaryLinks = document.select("ul.list-server-items > li.linkserver")
|
||||
//val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||
// All vidstream links passed to extractors
|
||||
primaryLinks.distinctBy { it.attr("data-video") }.forEach { element ->
|
||||
val link = element.attr("data-video")
|
||||
//val name = element.text()
|
||||
|
||||
// All vidstream links passed to extractors
|
||||
primaryLinks.distinctBy { it.attr("data-video") }.forEach { element ->
|
||||
val link = element.attr("data-video")
|
||||
//val name = element.text()
|
||||
|
||||
// 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)
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return false
|
||||
}
|
||||
)
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -1,9 +1,8 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.mapper
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
|
@ -29,14 +28,14 @@ open class VoeExtractor : ExtractorApi() {
|
|||
.replace("0,", "0")
|
||||
.trim()
|
||||
//Log.i(this.name, "Result => (src) ${src}")
|
||||
mapper.readValue<ResponseLinks?>(src)?.let { voelink ->
|
||||
parseJson<ResponseLinks?>(src)?.let { voelink ->
|
||||
//Log.i(this.name, "Result => (voelink) ${voelink}")
|
||||
val linkUrl = voelink.url
|
||||
val linkLabel = voelink.label?.toString() ?: ""
|
||||
if (!linkUrl.isNullOrEmpty()) {
|
||||
extractedLinksList.add(
|
||||
ExtractorLink(
|
||||
name = "Voe ${linkLabel}",
|
||||
name = "Voe $linkLabel",
|
||||
source = this.name,
|
||||
url = linkUrl,
|
||||
quality = getQualityFromName(linkLabel),
|
||||
|
|
|
@ -2,8 +2,11 @@ package com.lagradost.cloudstream3.movieproviders
|
|||
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.getPostForm
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import okio.Buffer
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Document
|
||||
|
@ -211,14 +214,7 @@ class AllMoviesForYouProvider : MainAPI() {
|
|||
}
|
||||
}
|
||||
} else if (requestUrl.startsWith("https://dood")) {
|
||||
for (extractor in extractorApis) {
|
||||
if (requestUrl.startsWith(extractor.mainUrl)) {
|
||||
extractor.getSafeUrl(requestUrl)?.forEach { link ->
|
||||
callback(link)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
loadExtractor(requestUrl, null, callback)
|
||||
} else {
|
||||
callback(
|
||||
ExtractorLink(
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package com.lagradost.cloudstream3.movieproviders
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.extractorApis
|
||||
import java.util.*
|
||||
|
||||
class CinecalidadProvider:MainAPI() {
|
||||
class CinecalidadProvider : MainAPI() {
|
||||
override val mainUrl = "https://cinecalidad.lol"
|
||||
override val name = "Cinecalidad"
|
||||
override val lang = "es"
|
||||
|
@ -15,6 +16,7 @@ class CinecalidadProvider:MainAPI() {
|
|||
TvType.Movie,
|
||||
TvType.TvSeries,
|
||||
)
|
||||
|
||||
override suspend fun getMainPage(): HomePageResponse {
|
||||
val items = ArrayList<HomePageList>()
|
||||
val urls = listOf(
|
||||
|
@ -22,18 +24,22 @@ class CinecalidadProvider:MainAPI() {
|
|||
Pair("$mainUrl/genero-de-la-pelicula/peliculas-en-calidad-4k/", "4K UHD"),
|
||||
)
|
||||
|
||||
items.add(HomePageList("Series",app.get("$mainUrl/ver-serie/").document.select(".item.tvshows").map{
|
||||
val title = it.selectFirst("div.in_title").text()
|
||||
TvSeriesSearchResponse(
|
||||
title,
|
||||
it.selectFirst("a").attr("href"),
|
||||
this.name,
|
||||
TvType.TvSeries,
|
||||
it.selectFirst(".poster.custom img").attr("data-src"),
|
||||
null,
|
||||
null,
|
||||
)
|
||||
}))
|
||||
items.add(
|
||||
HomePageList(
|
||||
"Series",
|
||||
app.get("$mainUrl/ver-serie/").document.select(".item.tvshows").map {
|
||||
val title = it.selectFirst("div.in_title").text()
|
||||
TvSeriesSearchResponse(
|
||||
title,
|
||||
it.selectFirst("a").attr("href"),
|
||||
this.name,
|
||||
TvType.TvSeries,
|
||||
it.selectFirst(".poster.custom img").attr("data-src"),
|
||||
null,
|
||||
null,
|
||||
)
|
||||
})
|
||||
)
|
||||
|
||||
for (i in urls) {
|
||||
try {
|
||||
|
@ -100,7 +106,9 @@ class CinecalidadProvider:MainAPI() {
|
|||
val soup = app.get(url, timeout = 120).document
|
||||
|
||||
val title = soup.selectFirst(".single_left h1").text()
|
||||
val description = soup.selectFirst(".single_left > table:nth-child(3) > tbody:nth-child(1) > tr:nth-child(1) > td:nth-child(2) > p")?.text()?.trim()
|
||||
val description =
|
||||
soup.selectFirst(".single_left > table:nth-child(3) > tbody:nth-child(1) > tr:nth-child(1) > td:nth-child(2) > p")
|
||||
?.text()?.trim()
|
||||
val poster: String? = soup.selectFirst(".alignnone").attr("data-src")
|
||||
val episodes = soup.select("div.se-c div.se-a ul.episodios li").map { li ->
|
||||
val href = li.selectFirst("a").attr("href")
|
||||
|
@ -114,7 +122,8 @@ class CinecalidadProvider:MainAPI() {
|
|||
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,
|
||||
|
@ -157,9 +166,10 @@ class CinecalidadProvider:MainAPI() {
|
|||
val urlserver = app.get(url).text
|
||||
val serverRegex = Regex("(https:.*?\\\")")
|
||||
val videos = serverRegex.findAll(urlserver).map {
|
||||
it.value.replace("\\/", "/").replace("\"","")
|
||||
it.value.replace("\\/", "/").replace("\"", "")
|
||||
}.toList()
|
||||
val serversRegex = Regex("(https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&\\/\\/=]*))")
|
||||
val serversRegex =
|
||||
Regex("(https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&\\/\\/=]*))")
|
||||
val links = serversRegex.findAll(videos.toString()).map { it.value }.toList()
|
||||
for (link in links) {
|
||||
for (extractor in extractorApis) {
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
package com.lagradost.cloudstream3.animeproviders
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import java.util.*
|
||||
import com.lagradost.cloudstream3.extractors.FEmbed
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
|
||||
|
||||
class DoramasYTProvider:MainAPI() {
|
||||
|
||||
class DoramasYTProvider : MainAPI() {
|
||||
companion object {
|
||||
fun getType(t: String): TvType {
|
||||
return if (t.contains("OVA") || t.contains("Especial")) TvType.ONA
|
||||
|
@ -33,31 +31,44 @@ class DoramasYTProvider:MainAPI() {
|
|||
override suspend fun getMainPage(): HomePageResponse {
|
||||
val urls = listOf(
|
||||
Pair("$mainUrl/emision", "En emisión"),
|
||||
Pair("$mainUrl/doramas?categoria=pelicula&genero=false&fecha=false&letra=false", "Peliculas"),
|
||||
Pair(
|
||||
"$mainUrl/doramas?categoria=pelicula&genero=false&fecha=false&letra=false",
|
||||
"Peliculas"
|
||||
),
|
||||
Pair("$mainUrl/doramas", "Doramas"),
|
||||
Pair("$mainUrl/doramas?categoria=live-action&genero=false&fecha=false&letra=false", "Live Action"),
|
||||
Pair(
|
||||
"$mainUrl/doramas?categoria=live-action&genero=false&fecha=false&letra=false",
|
||||
"Live Action"
|
||||
),
|
||||
)
|
||||
|
||||
val items = ArrayList<HomePageList>()
|
||||
|
||||
items.add(HomePageList("Capítulos actualizados", app.get(mainUrl, timeout = 120).document.select(".col-6").map{
|
||||
val title = it.selectFirst("p").text()
|
||||
val poster = it.selectFirst(".chapter img").attr("src")
|
||||
val epRegex = Regex("episodio-(\\d+)")
|
||||
val url = it.selectFirst("a").attr("href").replace("ver/","dorama/").replace(epRegex,"sub-espanol")
|
||||
val epNum = it.selectFirst("h3").text().toIntOrNull()
|
||||
AnimeSearchResponse(
|
||||
title,
|
||||
url,
|
||||
this.name,
|
||||
TvType.Anime,
|
||||
poster,
|
||||
null,
|
||||
if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(DubStatus.Subbed),
|
||||
subEpisodes = epNum,
|
||||
dubEpisodes = epNum,
|
||||
)
|
||||
}))
|
||||
items.add(
|
||||
HomePageList(
|
||||
"Capítulos actualizados",
|
||||
app.get(mainUrl, timeout = 120).document.select(".col-6").map {
|
||||
val title = it.selectFirst("p").text()
|
||||
val poster = it.selectFirst(".chapter img").attr("src")
|
||||
val epRegex = Regex("episodio-(\\d+)")
|
||||
val url = it.selectFirst("a").attr("href").replace("ver/", "dorama/")
|
||||
.replace(epRegex, "sub-espanol")
|
||||
val epNum = it.selectFirst("h3").text().toIntOrNull()
|
||||
AnimeSearchResponse(
|
||||
title,
|
||||
url,
|
||||
this.name,
|
||||
TvType.Anime,
|
||||
poster,
|
||||
null,
|
||||
if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(
|
||||
DubStatus.Dubbed
|
||||
) else EnumSet.of(DubStatus.Subbed),
|
||||
subEpisodes = epNum,
|
||||
dubEpisodes = epNum,
|
||||
)
|
||||
})
|
||||
)
|
||||
|
||||
for (i in urls) {
|
||||
try {
|
||||
|
@ -72,7 +83,9 @@ class DoramasYTProvider:MainAPI() {
|
|||
TvType.Anime,
|
||||
poster,
|
||||
null,
|
||||
if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(DubStatus.Subbed),
|
||||
if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(
|
||||
DubStatus.Dubbed
|
||||
) else EnumSet.of(DubStatus.Subbed),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -87,28 +100,32 @@ class DoramasYTProvider:MainAPI() {
|
|||
}
|
||||
|
||||
override suspend fun search(query: String): ArrayList<SearchResponse> {
|
||||
val search = app.get("$mainUrl/buscar?q=$query", timeout = 120).document.select(".col-6").map {
|
||||
val title = it.selectFirst(".animedtls p").text()
|
||||
val href = it.selectFirst("a").attr("href")
|
||||
val image = it.selectFirst(".animes img").attr("src")
|
||||
AnimeSearchResponse(
|
||||
title,
|
||||
href,
|
||||
this.name,
|
||||
TvType.Anime,
|
||||
image,
|
||||
null,
|
||||
if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(DubStatus.Subbed),
|
||||
)
|
||||
}
|
||||
val search =
|
||||
app.get("$mainUrl/buscar?q=$query", timeout = 120).document.select(".col-6").map {
|
||||
val title = it.selectFirst(".animedtls p").text()
|
||||
val href = it.selectFirst("a").attr("href")
|
||||
val image = it.selectFirst(".animes img").attr("src")
|
||||
AnimeSearchResponse(
|
||||
title,
|
||||
href,
|
||||
this.name,
|
||||
TvType.Anime,
|
||||
image,
|
||||
null,
|
||||
if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(
|
||||
DubStatus.Dubbed
|
||||
) else EnumSet.of(DubStatus.Subbed),
|
||||
)
|
||||
}
|
||||
return ArrayList(search)
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse {
|
||||
val doc = app.get(url, timeout = 120).document
|
||||
val poster = doc.selectFirst("div.flimimg img.img1").attr("src")
|
||||
val title = doc.selectFirst("h1").text()
|
||||
val type = doc.selectFirst("h4").text()
|
||||
val description = doc.selectFirst("p.textComplete").text().replace("Ver menos","")
|
||||
val description = doc.selectFirst("p.textComplete").text().replace("Ver menos", "")
|
||||
val genres = doc.select(".nobel a").map { it.text() }
|
||||
val status = when (doc.selectFirst(".state h6")?.text()) {
|
||||
"Estreno" -> ShowStatus.Ongoing
|
||||
|
@ -129,13 +146,14 @@ class DoramasYTProvider:MainAPI() {
|
|||
tags = genres
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
app.get(data).document.select("div.playother p").forEach {
|
||||
app.get(data).document.select("div.playother p").apmap {
|
||||
val encodedurl = it.select("p").attr("data-player")
|
||||
val urlDecoded = base64Decode(encodedurl)
|
||||
val url = (urlDecoded).replace("https://doramasyt.com/reproductor?url=", "")
|
||||
|
|
|
@ -157,13 +157,10 @@ class DramaSeeProvider : MainAPI() {
|
|||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
var count = 0
|
||||
mapper.readValue<List<String>>(data).forEach { item ->
|
||||
mapper.readValue<List<String>>(data).apmap { item ->
|
||||
if (item.isNotEmpty()) {
|
||||
count++
|
||||
var url = item.trim()
|
||||
if (url.startsWith("//")) {
|
||||
url = "https:$url"
|
||||
}
|
||||
var url = fixUrl(item.trim())
|
||||
//Log.i(this.name, "Result => (url) ${url}")
|
||||
when {
|
||||
url.startsWith("https://asianembed.io") -> {
|
||||
|
|
|
@ -69,7 +69,17 @@ class FilmanProvider : MainAPI() {
|
|||
val img = i.selectFirst("> img").attr("src").replace("/thumb/", "/big/")
|
||||
val name = i.selectFirst(".title").text()
|
||||
if (type === TvType.TvSeries) {
|
||||
returnValue.add(TvSeriesSearchResponse(name, href, this.name, type, img, null, null))
|
||||
returnValue.add(
|
||||
TvSeriesSearchResponse(
|
||||
name,
|
||||
href,
|
||||
this.name,
|
||||
type,
|
||||
img,
|
||||
null,
|
||||
null
|
||||
)
|
||||
)
|
||||
} else {
|
||||
returnValue.add(MovieSearchResponse(name, href, this.name, type, img, null))
|
||||
}
|
||||
|
@ -98,15 +108,26 @@ class FilmanProvider : MainAPI() {
|
|||
val regex = Regex("""\[s(\d{1,3})e(\d{1,3})]""").find(e)
|
||||
if (regex != null) {
|
||||
val eid = regex.groups
|
||||
episodes.add(TvSeriesEpisode(
|
||||
e.split("]")[1].trim(),
|
||||
eid[1]?.value?.toInt(),
|
||||
eid[2]?.value?.toInt(),
|
||||
episode.attr("href"),
|
||||
))
|
||||
episodes.add(
|
||||
TvSeriesEpisode(
|
||||
e.split("]")[1].trim(),
|
||||
eid[1]?.value?.toInt(),
|
||||
eid[2]?.value?.toInt(),
|
||||
episode.attr("href"),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return TvSeriesLoadResponse(title, url, name, TvType.TvSeries, episodes, posterUrl, year, plot)
|
||||
return TvSeriesLoadResponse(
|
||||
title,
|
||||
url,
|
||||
name,
|
||||
TvType.TvSeries,
|
||||
episodes,
|
||||
posterUrl,
|
||||
year,
|
||||
plot
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
|
@ -115,20 +136,16 @@ class FilmanProvider : MainAPI() {
|
|||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
if(data.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
val document = if (data.startsWith("http"))
|
||||
Jsoup.parse(app.get(data).text).select("#links").first()
|
||||
else Jsoup.parse(data)
|
||||
app.get(data).document.select("#links").first()
|
||||
else Jsoup.parse(data)
|
||||
|
||||
val items = document.select(".link-to-video")
|
||||
for (i in items) {
|
||||
val decoded = base64Decode(i.select("a").attr("data-iframe"))
|
||||
document.select(".link-to-video")?.apmap { item ->
|
||||
val decoded = base64Decode(item.select("a").attr("data-iframe"))
|
||||
val link = mapper.readValue<LinkElement>(decoded).src
|
||||
loadExtractor(link, null, callback)
|
||||
}
|
||||
return true
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package com.lagradost.cloudstream3.movieproviders
|
||||
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.extractors.StreamTape
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.Jsoup
|
||||
import java.net.URLEncoder
|
||||
|
||||
|
@ -18,8 +18,23 @@ class IHaveNoTvProvider : MainAPI() {
|
|||
// Uhh, I am too lazy to scrape the "latest documentaries" and "recommended documentaries",
|
||||
// so I am just scraping 3 random categories
|
||||
val allCategories = listOf(
|
||||
"astronomy", "brain", "creativity", "design", "economics", "environment", "health", "history",
|
||||
"lifehack", "math", "music", "nature", "people", "physics", "science", "technology", "travel"
|
||||
"astronomy",
|
||||
"brain",
|
||||
"creativity",
|
||||
"design",
|
||||
"economics",
|
||||
"environment",
|
||||
"health",
|
||||
"history",
|
||||
"lifehack",
|
||||
"math",
|
||||
"music",
|
||||
"nature",
|
||||
"people",
|
||||
"physics",
|
||||
"science",
|
||||
"technology",
|
||||
"travel"
|
||||
)
|
||||
|
||||
val categories = allCategories.asSequence().shuffled().take(3)
|
||||
|
@ -82,7 +97,9 @@ class IHaveNoTvProvider : MainAPI() {
|
|||
res.selectFirst("a[href][title]")
|
||||
}
|
||||
val year =
|
||||
Regex("""•?\s+(\d{4})\s+•""").find(res.selectFirst(".episodeMeta").text())?.destructured?.component1()
|
||||
Regex("""•?\s+(\d{4})\s+•""").find(
|
||||
res.selectFirst(".episodeMeta").text()
|
||||
)?.destructured?.component1()
|
||||
?.toIntOrNull()
|
||||
|
||||
val title = aTag.attr("title")
|
||||
|
@ -138,7 +155,8 @@ class IHaveNoTvProvider : MainAPI() {
|
|||
ep.selectFirst(".episodeMeta").text()
|
||||
)?.destructured?.component1()?.toIntOrNull()
|
||||
|
||||
categories.addAll(ep.select(".episodeMeta > a[href*=\"/category/\"]").map { it.text().trim() })
|
||||
categories.addAll(
|
||||
ep.select(".episodeMeta > a[href*=\"/category/\"]").map { it.text().trim() })
|
||||
|
||||
TvSeriesEpisode(
|
||||
epTitle,
|
||||
|
@ -165,7 +183,8 @@ class IHaveNoTvProvider : MainAPI() {
|
|||
description,
|
||||
null,
|
||||
null,
|
||||
soup.selectFirst(".videoDetails").select("a[href*=\"/category/\"]").map { it.text().trim() }
|
||||
soup.selectFirst(".videoDetails").select("a[href*=\"/category/\"]")
|
||||
.map { it.text().trim() }
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -201,9 +220,7 @@ class IHaveNoTvProvider : MainAPI() {
|
|||
|
||||
val iframe = soup.selectFirst("#videoWrap iframe")
|
||||
if (iframe != null) {
|
||||
if (iframe.attr("src").startsWith("https://streamtape.com")) {
|
||||
StreamTape().getSafeUrl(iframe.attr("src"))?.forEach(callback)
|
||||
}
|
||||
loadExtractor(iframe.attr("src"), null, callback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.lagradost.cloudstream3.movieproviders
|
||||
|
||||
import android.util.Log
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.extractors.*
|
||||
|
@ -9,7 +8,6 @@ import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
|||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.Jsoup
|
||||
import kotlin.Exception
|
||||
|
||||
class KdramaHoodProvider : MainAPI() {
|
||||
override val mainUrl = "https://kdramahood.com"
|
||||
|
@ -131,13 +129,10 @@ class KdramaHoodProvider : MainAPI() {
|
|||
if (!epLinksContent.isNullOrEmpty()) {
|
||||
//Log.i(this.name, "Result => (epLinksContent) ${Jsoup.parse(epLinksContent)?.select("div")}")
|
||||
Jsoup.parse(epLinksContent)?.select("div")?.forEach { em ->
|
||||
var href = em?.html()?.trim()?.removePrefix("'") ?: return@forEach
|
||||
if (href.startsWith("//")) {
|
||||
href = "https:$href"
|
||||
}
|
||||
val href = em?.html()?.trim()?.removePrefix("'") ?: return@forEach
|
||||
//Log.i(this.name, "Result => (ep#$count link) $href")
|
||||
if (href.isNotEmpty()) {
|
||||
listOfLinks.add(href)
|
||||
listOfLinks.add(fixUrl(href))
|
||||
}
|
||||
}
|
||||
/* Doesn't get all links for some reasons
|
||||
|
@ -188,7 +183,7 @@ class KdramaHoodProvider : MainAPI() {
|
|||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
var count = 0
|
||||
mapper.readValue<List<String>>(data).forEach { item ->
|
||||
mapper.readValue<List<String>>(data).apmap { item ->
|
||||
if (item.isNotEmpty()) {
|
||||
count++
|
||||
var url = item.trim()
|
||||
|
|
|
@ -231,7 +231,7 @@ open class PelisplusProviderTemplate : MainAPI() {
|
|||
null
|
||||
}
|
||||
}
|
||||
servers.forEach {
|
||||
servers.apmap {
|
||||
// When checking strings make sure to make them lowercase and trimmed because edgecases like "beta server " wouldn't work otherwise.
|
||||
if (it.first.trim().equals("beta server", ignoreCase = true)) {
|
||||
// Group 1: link, Group 2: Label
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.lagradost.cloudstream3.movieproviders
|
||||
|
||||
import android.util.Log
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
||||
|
@ -192,7 +191,7 @@ class PinoyHDXyzProvider : MainAPI() {
|
|||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
var count = 0
|
||||
mapper.readValue<List<String>>(data).forEach { item ->
|
||||
mapper.readValue<List<String>>(data).apmap { item ->
|
||||
if (item.isNotEmpty()) {
|
||||
val url = item.trim()
|
||||
loadExtractor(url, mainUrl, callback)
|
||||
|
|
|
@ -179,7 +179,7 @@ class PinoyMoviePediaProvider : MainAPI() {
|
|||
): Boolean {
|
||||
// parse movie servers
|
||||
var count = 0
|
||||
mapper.readValue<List<String>>(data).forEach { link ->
|
||||
mapper.readValue<List<String>>(data).apmap { link ->
|
||||
count++
|
||||
if (link.contains("fembed.com")) {
|
||||
val extractor = FEmbed()
|
||||
|
|
|
@ -136,7 +136,7 @@ class PinoyMoviesEsProvider : MainAPI() {
|
|||
it?.attr("data-post") ?: return@mapNotNull null
|
||||
}?.filter { it.isNotEmpty() }?.distinct() ?: listOf()
|
||||
|
||||
postlist.forEach { datapost ->
|
||||
postlist.apmap { datapost ->
|
||||
//Log.i(this.name, "Result => (datapost) ${datapost}")
|
||||
val content = mapOf(
|
||||
Pair("action", "doo_player_ajax"),
|
||||
|
@ -163,7 +163,7 @@ class PinoyMoviesEsProvider : MainAPI() {
|
|||
): Boolean {
|
||||
// parse movie servers
|
||||
var count = 0
|
||||
mapper.readValue<List<String>>(data).forEach { link ->
|
||||
mapper.readValue<List<String>>(data).apmap { link ->
|
||||
count++
|
||||
//Log.i(this.name, "Result => (link) $link")
|
||||
if (link.startsWith("https://vstreamhub.com")) {
|
||||
|
|
|
@ -215,10 +215,9 @@ class SflixProvider(providerUrl: String, providerName: String) : MainAPI() {
|
|||
): Boolean {
|
||||
val urls = (tryParseJson<Pair<String, String>>(data)?.let { (prefix, server) ->
|
||||
val episodesUrl = "$mainUrl/ajax/v2/episode/servers/$server"
|
||||
val episodes = app.get(episodesUrl).text
|
||||
|
||||
// Supported streams, they're identical
|
||||
Jsoup.parse(episodes).select("a").mapNotNull { element ->
|
||||
app.get(episodesUrl).document.select("a").mapNotNull { element ->
|
||||
val id = element?.attr("data-id") ?: return@mapNotNull null
|
||||
if (element.select("span")?.text()?.trim()?.isValidServer() == true) {
|
||||
"$prefix.$id".replace("/tv/", "/watch-tv/")
|
||||
|
@ -250,7 +249,6 @@ class SflixProvider(providerUrl: String, providerName: String) : MainAPI() {
|
|||
mapped.sources2 to "source 3",
|
||||
mapped.sourcesBackup to "source backup"
|
||||
).forEach { (sources, sourceName) ->
|
||||
println("SOURCE:::: $sourceName $sources")
|
||||
sources?.forEach {
|
||||
it?.toExtractorLink(this, sourceName)?.forEach(callback)
|
||||
}
|
||||
|
|
|
@ -77,36 +77,40 @@ open class VidstreamProviderTemplate : MainAPI() {
|
|||
val description = soup.selectFirst(".post-entry")?.text()?.trim()
|
||||
var poster: String? = null
|
||||
|
||||
val episodes = soup.select(".listing.items.lists > .video-block").withIndex().map { (_, li) ->
|
||||
val epTitle = if (li.selectFirst(".name") != null)
|
||||
if (li.selectFirst(".name").text().contains("Episode"))
|
||||
"Episode " + li.selectFirst(".name").text().split("Episode")[1].trim()
|
||||
else
|
||||
li.selectFirst(".name").text()
|
||||
else ""
|
||||
val epThumb = li.selectFirst("img")?.attr("src")
|
||||
val epDate = li.selectFirst(".meta > .date").text()
|
||||
val episodes =
|
||||
soup.select(".listing.items.lists > .video-block").withIndex().map { (_, li) ->
|
||||
val epTitle = if (li.selectFirst(".name") != null)
|
||||
if (li.selectFirst(".name").text().contains("Episode"))
|
||||
"Episode " + li.selectFirst(".name").text().split("Episode")[1].trim()
|
||||
else
|
||||
li.selectFirst(".name").text()
|
||||
else ""
|
||||
val epThumb = li.selectFirst("img")?.attr("src")
|
||||
val epDate = li.selectFirst(".meta > .date").text()
|
||||
|
||||
if (poster == null) {
|
||||
poster = li.selectFirst("img")?.attr("onerror")?.split("=")?.get(1)?.replace(Regex("[';]"), "")
|
||||
}
|
||||
if (poster == null) {
|
||||
poster = li.selectFirst("img")?.attr("onerror")?.split("=")?.get(1)
|
||||
?.replace(Regex("[';]"), "")
|
||||
}
|
||||
|
||||
val epNum = Regex("""Episode (\d+)""").find(epTitle)?.destructured?.component1()?.toIntOrNull()
|
||||
val epNum = Regex("""Episode (\d+)""").find(epTitle)?.destructured?.component1()
|
||||
?.toIntOrNull()
|
||||
|
||||
TvSeriesEpisode(
|
||||
epTitle,
|
||||
null,
|
||||
epNum,
|
||||
fixUrl(li.selectFirst("a").attr("href")),
|
||||
epThumb,
|
||||
epDate
|
||||
)
|
||||
}.reversed()
|
||||
TvSeriesEpisode(
|
||||
epTitle,
|
||||
null,
|
||||
epNum,
|
||||
fixUrl(li.selectFirst("a").attr("href")),
|
||||
epThumb,
|
||||
epDate
|
||||
)
|
||||
}.reversed()
|
||||
|
||||
val year = episodes.first().date?.split("-")?.get(0)?.toIntOrNull()
|
||||
|
||||
// Make sure to get the type right to display the correct UI.
|
||||
val tvType = if (episodes.size == 1 && episodes[0].name == title) TvType.Movie else TvType.TvSeries
|
||||
val tvType =
|
||||
if (episodes.size == 1 && episodes[0].name == title) TvType.Movie else TvType.TvSeries
|
||||
|
||||
return when (tvType) {
|
||||
TvType.TvSeries -> {
|
||||
|
@ -157,7 +161,8 @@ open class VidstreamProviderTemplate : MainAPI() {
|
|||
val elements = inner.select(".video-block").map {
|
||||
val link = fixUrl(it.select("a").attr("href"))
|
||||
val image = it.select(".picture > img").attr("src")
|
||||
val name = it.select("div.name").text().trim().replace(Regex("""[Ee]pisode \d+"""), "")
|
||||
val name =
|
||||
it.select("div.name").text().trim().replace(Regex("""[Ee]pisode \d+"""), "")
|
||||
val isSeries = (name.contains("Season") || name.contains("Episode"))
|
||||
|
||||
if (isSeries) {
|
||||
|
@ -188,9 +193,7 @@ open class VidstreamProviderTemplate : MainAPI() {
|
|||
title, elements
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return HomePageResponse(homePageList)
|
||||
}
|
||||
|
@ -206,7 +209,8 @@ open class VidstreamProviderTemplate : MainAPI() {
|
|||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
// "?: return" is a very useful statement which returns if the iframe link isn't found.
|
||||
val iframeLink = Jsoup.parse(app.get(data).text).selectFirst("iframe")?.attr("src") ?: return false
|
||||
val iframeLink =
|
||||
Jsoup.parse(app.get(data).text).selectFirst("iframe")?.attr("src") ?: return false
|
||||
|
||||
// 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.
|
||||
|
@ -228,13 +232,15 @@ open class VidstreamProviderTemplate : MainAPI() {
|
|||
null
|
||||
}
|
||||
}
|
||||
servers.forEach {
|
||||
servers.apmap {
|
||||
// When checking strings make sure to make them lowercase and trimmed because edgecases like "beta server " wouldn't work otherwise.
|
||||
if (it.first.trim().equals( "beta server", ignoreCase = true)) {
|
||||
if (it.first.trim().equals("beta server", ignoreCase = true)) {
|
||||
// Group 1: link, Group 2: Label
|
||||
// Regex can be used to effectively parse small amounts of json without bothering with writing a json class.
|
||||
val sourceRegex = Regex("""sources:[\W\w]*?file:\s*["'](.*?)["'][\W\w]*?label:\s*["'](.*?)["']""")
|
||||
val trackRegex = Regex("""tracks:[\W\w]*?file:\s*["'](.*?)["'][\W\w]*?label:\s*["'](.*?)["']""")
|
||||
val sourceRegex =
|
||||
Regex("""sources:[\W\w]*?file:\s*["'](.*?)["'][\W\w]*?label:\s*["'](.*?)["']""")
|
||||
val trackRegex =
|
||||
Regex("""tracks:[\W\w]*?file:\s*["'](.*?)["'][\W\w]*?label:\s*["'](.*?)["']""")
|
||||
|
||||
// Having a referer is often required. It's a basic security check most providers have.
|
||||
// Try to replicate what your browser does.
|
||||
|
|
|
@ -174,12 +174,9 @@ class WatchAsianProvider : MainAPI() {
|
|||
getServerLinks(data)
|
||||
} else { data }
|
||||
var count = 0
|
||||
mapper.readValue<List<String>>(links).forEach { item ->
|
||||
mapper.readValue<List<String>>(links).apmap { item ->
|
||||
count++
|
||||
var url = item.trim()
|
||||
if (url.startsWith("//")) {
|
||||
url = "https:$url"
|
||||
}
|
||||
val url = fixUrl(item.trim())
|
||||
//Log.i(this.name, "Result => (url) $url")
|
||||
if (url.startsWith("https://asianembed.io")) {
|
||||
// Fetch links
|
||||
|
|
|
@ -9,7 +9,7 @@ import java.net.InetAddress
|
|||
* Based on https://github.com/tachiyomiorg/tachiyomi/blob/master/app/src/main/java/eu/kanade/tachiyomi/network/DohProviders.kt
|
||||
*/
|
||||
|
||||
fun OkHttpClient.Builder.addGenericDns(url: String, ips: List<String>) = dns(
|
||||
fun OkHttpClient.Builder.addGenericDns(url: String, ips: List<String>) = dns(
|
||||
DnsOverHttps
|
||||
.Builder()
|
||||
.client(build())
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.lagradost.cloudstream3.network
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.lagradost.cloudstream3.R
|
||||
|
@ -286,6 +287,7 @@ open class Requests {
|
|||
timeout: Long = 0L,
|
||||
interceptor: Interceptor? = null,
|
||||
): AppResponse {
|
||||
Log.i("GET", url)
|
||||
val client = baseClient
|
||||
.newBuilder()
|
||||
.followRedirects(allowRedirects)
|
||||
|
@ -315,6 +317,7 @@ open class Requests {
|
|||
cacheUnit: TimeUnit = DEFAULT_TIME_UNIT,
|
||||
timeout: Long = 0L,
|
||||
): AppResponse {
|
||||
Log.i("POST", url)
|
||||
val client = baseClient
|
||||
.newBuilder()
|
||||
.followRedirects(allowRedirects)
|
||||
|
@ -339,6 +342,7 @@ open class Requests {
|
|||
cacheUnit: TimeUnit = DEFAULT_TIME_UNIT,
|
||||
timeout: Long = 0L
|
||||
): AppResponse {
|
||||
Log.i("PUT", url)
|
||||
val client = baseClient
|
||||
.newBuilder()
|
||||
.followRedirects(allowRedirects)
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.google.android.material.button.MaterialButton
|
|||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
|
||||
import com.lagradost.cloudstream3.APIHolder.getApiFromName
|
||||
import com.lagradost.cloudstream3.APIHolder.getApiSettings
|
||||
import com.lagradost.cloudstream3.mvvm.Resource
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
|
@ -93,6 +94,22 @@ class SearchFragment : Fragment() {
|
|||
var selectedSearchTypes = mutableListOf<TvType>()
|
||||
var selectedApis = mutableSetOf<String>()
|
||||
|
||||
fun search(query: String?) {
|
||||
if (query == null) return
|
||||
context?.getApiSettings()?.let { settings ->
|
||||
searchViewModel.searchAndCancel(
|
||||
query = query,
|
||||
providersActive = selectedApis.filter { name ->
|
||||
settings.contains(name) && getApiFromName(name).supportedTypes.any {
|
||||
selectedSearchTypes.contains(
|
||||
it
|
||||
)
|
||||
}
|
||||
}.toSet()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
@ -274,6 +291,7 @@ class SearchFragment : Fragment() {
|
|||
|
||||
button?.isSelected = buttonContains()
|
||||
button?.setOnClickListener {
|
||||
val last = selectedSearchTypes.toSet()
|
||||
selectedSearchTypes.clear()
|
||||
selectedSearchTypes.addAll(validTypes)
|
||||
for ((otherButton, _) in pairList) {
|
||||
|
@ -281,6 +299,8 @@ class SearchFragment : Fragment() {
|
|||
}
|
||||
it?.context?.setKey(SEARCH_PREF_TAGS, selectedSearchTypes)
|
||||
it?.isSelected = true
|
||||
if (last != selectedSearchTypes.toSet()) // if you click the same button again the it does nothing
|
||||
search(main_search?.query?.toString())
|
||||
}
|
||||
|
||||
button?.setOnLongClickListener {
|
||||
|
@ -292,6 +312,7 @@ class SearchFragment : Fragment() {
|
|||
selectedSearchTypes.removeAll(validTypes)
|
||||
}
|
||||
it?.context?.setKey(SEARCH_PREF_TAGS, selectedSearchTypes)
|
||||
search(main_search?.query?.toString())
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
}
|
||||
|
@ -305,12 +326,7 @@ class SearchFragment : Fragment() {
|
|||
|
||||
main_search.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String): Boolean {
|
||||
searchViewModel.searchAndCancel(
|
||||
query = query,
|
||||
providersActive = selectedApis.filter { name ->
|
||||
getApiFromName(name).supportedTypes.any { selectedSearchTypes.contains(it) }
|
||||
}.toSet()
|
||||
)
|
||||
search(query)
|
||||
|
||||
main_search?.let {
|
||||
hideKeyboard(it)
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper
|
|||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||
|
||||
const val DOWNLOAD_HEADER_CACHE = "download_header_cache"
|
||||
|
||||
//const val WATCH_HEADER_CACHE = "watch_header_cache"
|
||||
const val DOWNLOAD_EPISODE_CACHE = "download_episode_cache"
|
||||
const val VIDEO_PLAYER_BRIGHTNESS = "video_player_alpha_key"
|
||||
|
|
|
@ -79,7 +79,7 @@ fun getAndUnpack(string: String): String {
|
|||
/**
|
||||
* Tries to load the appropriate extractor based on link, returns true if any extractor is loaded.
|
||||
* */
|
||||
suspend fun loadExtractor(url: String, referer: String?, callback: (ExtractorLink) -> Unit) : Boolean {
|
||||
suspend fun loadExtractor(url: String, referer: String? = null, callback: (ExtractorLink) -> Unit) : Boolean {
|
||||
for (extractor in extractorApis) {
|
||||
if (url.startsWith(extractor.mainUrl)) {
|
||||
extractor.getSafeUrl(url, referer)?.forEach(callback)
|
||||
|
|
Loading…
Reference in a new issue