fixed search, made stuff more parallel

This commit is contained in:
LagradOst 2022-01-30 02:50:49 +01:00
parent b0cadda315
commit e0d9171f3e
26 changed files with 312 additions and 221 deletions

View file

@ -115,13 +115,13 @@ object APIHolder {
} }
fun Context.getApiSettings(): HashSet<String> { fun Context.getApiSettings(): HashSet<String> {
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) //val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
val hashSet = HashSet<String>() val hashSet = HashSet<String>()
val activeLangs = getApiProviderLangSettings() val activeLangs = getApiProviderLangSettings()
hashSet.addAll(apis.filter { activeLangs.contains(it.lang) }.map { it.name }) 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), this.getString(R.string.search_providers_list_key),
hashSet hashSet
)?.toHashSet() ?: hashSet )?.toHashSet() ?: hashSet
@ -132,9 +132,10 @@ object APIHolder {
if (activeLangs.contains(api.lang)) { if (activeLangs.contains(api.lang)) {
list.add(name) list.add(name)
} }
} }*/
if (list.isEmpty()) return hashSet //if (list.isEmpty()) return hashSet
return list //return list
return hashSet
} }
fun Context.getApiDubstatusSettings(): HashSet<DubStatus> { fun Context.getApiDubstatusSettings(): HashSet<DubStatus> {

View file

@ -1,5 +1,6 @@
package com.lagradost.cloudstream3 package com.lagradost.cloudstream3
import com.lagradost.cloudstream3.mvvm.logError
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking 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) exec.awaitTermination(1, TimeUnit.DAYS)
}*/ }*/
// built in try catch
fun <R> argamap( fun <R> argamap(
vararg transforms: suspend () -> R, vararg transforms: suspend () -> R,
) = runBlocking { ) = runBlocking {
transforms.map { async { it.invoke() } }.map { it.await() } transforms.map {
async {
try {
it.invoke()
} catch (e: Exception) {
logError(e)
}
}
}.map { it.await() }
} }

View file

@ -258,7 +258,7 @@ class AllAnimeProvider : MainAPI() {
val sources = Regex("""sourceUrl[:=]"(.+?)"""").findAll(html).toList() val sources = Regex("""sourceUrl[:=]"(.+?)"""").findAll(html).toList()
.map { URLDecoder.decode(it.destructured.component1().sanitize(), "UTF-8") } .map { URLDecoder.decode(it.destructured.component1().sanitize(), "UTF-8") }
sources.forEach { sources.apmap {
var link = it var link = it
if (URI(link).isAbsolute || link.startsWith("//")) { if (URI(link).isAbsolute || link.startsWith("//")) {
if (link.startsWith("//")) link = "https:$it" if (link.startsWith("//")) link = "https:$it"

View file

@ -95,9 +95,7 @@ class AnimeFlickProvider : MainAPI() {
var alreadyAdded = false var alreadyAdded = false
for (extractor in extractorApis) { for (extractor in extractorApis) {
if (link.startsWith(extractor.mainUrl)) { if (link.startsWith(extractor.mainUrl)) {
extractor.getSafeUrl(link, data)?.forEach { extractor.getSafeUrl(link, data)?.forEach(callback)
callback(it)
}
alreadyAdded = true alreadyAdded = true
break break
} }

View file

@ -52,8 +52,11 @@ class WcoProvider : MainAPI() {
val nameHeader = filmDetail.selectFirst("> h3.film-name > a") val nameHeader = filmDetail.selectFirst("> h3.film-name > a")
val title = nameHeader.text().replace(" (Dub)", "") val title = nameHeader.text().replace(" (Dub)", "")
val href = val href =
nameHeader.attr("href").replace("/watch/", "/anime/").replace("-episode-.*".toRegex(), "/") nameHeader.attr("href").replace("/watch/", "/anime/")
val isDub = filmPoster.selectFirst("> div.film-poster-quality")?.text()?.contains("DUB") ?: false .replace("-episode-.*".toRegex(), "/")
val isDub =
filmPoster.selectFirst("> div.film-poster-quality")?.text()?.contains("DUB")
?: false
val poster = filmPoster.selectFirst("> img").attr("data-src") val poster = filmPoster.selectFirst("> img").attr("data-src")
val set: EnumSet<DubStatus> = val set: EnumSet<DubStatus> =
EnumSet.of(if (isDub) DubStatus.Dubbed else DubStatus.Subbed) 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 img = fixUrl(i.selectFirst("img").attr("data-src"))
val title = i.selectFirst("img").attr("title") val title = i.selectFirst("img").attr("title")
val isDub = !i.select(".pick.film-poster-quality").isEmpty() 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 year =
val type = i.selectFirst(".film-detail.film-detail-fix > div > span:nth-child(3)").text() 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( returnValue.add(
if (getType(type) == TvType.AnimeMovie) { if (getType(type) == TvType.AnimeMovie) {
@ -174,7 +180,8 @@ class WcoProvider : MainAPI() {
val response = app.get(url, timeout = 120).text val response = app.get(url, timeout = 120).text
val document = Jsoup.parse(response) val document = Jsoup.parse(response)
val japaneseTitle = document.selectFirst("div.elements div.row > div:nth-child(1) > div.row-line:nth-child(1)") val japaneseTitle =
document.selectFirst("div.elements div.row > div:nth-child(1) > div.row-line:nth-child(1)")
?.text()?.trim()?.replace("Other names:", "")?.trim() ?.text()?.trim()?.replace("Other names:", "")?.trim()
val canonicalTitle = document.selectFirst("meta[name=\"title\"]") val canonicalTitle = document.selectFirst("meta[name=\"title\"]")
@ -187,21 +194,24 @@ class WcoProvider : MainAPI() {
AnimeEpisode(it.attr("href")) AnimeEpisode(it.attr("href"))
} ?: ArrayList()) } ?: 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()) { val status = when (statusElem?.text()?.replace("Status:", "")?.trim()) {
"Ongoing" -> ShowStatus.Ongoing "Ongoing" -> ShowStatus.Ongoing
"Completed" -> ShowStatus.Completed "Completed" -> ShowStatus.Completed
else -> null else -> null
} }
val yearText = 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 year = yearText?.replace("Date release:", "")?.trim()?.split("-")?.get(0)?.toIntOrNull()
val poster = document.selectFirst(".film-poster-img")?.attr("src") val poster = document.selectFirst(".film-poster-img")?.attr("src")
val type = document.selectFirst("span.item.mr-1 > a")?.text()?.trim() val type = document.selectFirst("span.item.mr-1 > a")?.text()?.trim()
val synopsis = document.selectFirst(".description > p")?.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") val genre =
document.select("div.elements div.row > div:nth-child(1) > div.row-line:nth-child(5) > a")
.map { it?.text()?.trim().toString() } .map { it?.text()?.trim().toString() }
return newAnimeLoadResponse(canonicalTitle, url, getType(type ?: "")) { return newAnimeLoadResponse(canonicalTitle, url, getType(type ?: "")) {
@ -231,9 +241,7 @@ class WcoProvider : MainAPI() {
} }
for (server in servers) { for (server in servers) {
WcoStream().getSafeUrl(server["link"].toString(), "")?.forEach { WcoStream().getSafeUrl(server["link"].toString(), "")?.forEach(callback)
callback.invoke(it)
}
} }
return true return true
} }

View file

@ -2,7 +2,7 @@ package com.lagradost.cloudstream3.extractors
import com.lagradost.cloudstream3.apmap import com.lagradost.cloudstream3.apmap
import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall import com.lagradost.cloudstream3.argamap
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.extractorApis import com.lagradost.cloudstream3.utils.extractorApis
import com.lagradost.cloudstream3.utils.getQualityFromName import com.lagradost.cloudstream3.utils.getQualityFromName
@ -27,17 +27,22 @@ class Vidstream(val mainUrl: String) {
private val normalApis = arrayListOf(MultiQuality()) private val normalApis = arrayListOf(MultiQuality())
// https://gogo-stream.com/streaming.php?id=MTE3NDg5 // https://gogo-stream.com/streaming.php?id=MTE3NDg5
suspend fun getUrl(id: String, isCasting: Boolean = false, callback: (ExtractorLink) -> Unit): Boolean { suspend fun getUrl(
try { id: String,
isCasting: Boolean = false,
callback: (ExtractorLink) -> Unit
): Boolean {
println("VIDSTREAM:: $id")
val extractorUrl = getExtractorUrl(id)
argamap(
{
normalApis.apmap { api -> normalApis.apmap { api ->
val url = api.getExtractorUrl(id) val url = api.getExtractorUrl(id)
val source = api.getSafeUrl(url) val source = api.getSafeUrl(url)
source?.forEach { callback.invoke(it) } source?.forEach { callback.invoke(it) }
} }
val extractorUrl = getExtractorUrl(id) }, {
/** Stolen from GogoanimeProvider.kt extractor */ /** Stolen from GogoanimeProvider.kt extractor */
suspendSafeApiCall {
val link = getDownloadUrl(id) val link = getDownloadUrl(id)
println("Generated vidstream download link: $link") println("Generated vidstream download link: $link")
val page = app.get(link, referer = extractorUrl) val page = app.get(link, referer = extractorUrl)
@ -50,7 +55,8 @@ class Vidstream(val mainUrl: String) {
val href = element.attr("href") ?: return@apmap val href = element.attr("href") ?: return@apmap
val qual = if (element.text() val qual = if (element.text()
.contains("HDP") .contains("HDP")
) "1080" else qualityRegex.find(element.text())?.destructured?.component1().toString() ) "1080" else qualityRegex.find(element.text())?.destructured?.component1()
.toString()
if (!loadExtractor(href, link, callback)) { if (!loadExtractor(href, link, callback)) {
callback.invoke( callback.invoke(
@ -65,8 +71,7 @@ class Vidstream(val mainUrl: String) {
) )
} }
} }
} }, {
with(app.get(extractorUrl)) { with(app.get(extractorUrl)) {
val document = Jsoup.parse(this.text) val document = Jsoup.parse(this.text)
val primaryLinks = document.select("ul.list-server-items > li.linkserver") val primaryLinks = document.select("ul.list-server-items > li.linkserver")
@ -89,10 +94,9 @@ class Vidstream(val mainUrl: String) {
} }
} }
} }
}
}
)
return true return true
} }
} catch (e: Exception) {
return false
}
}
} }

View file

@ -1,9 +1,8 @@
package com.lagradost.cloudstream3.extractors package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.module.kotlin.readValue
import com.lagradost.cloudstream3.app 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.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.getQualityFromName import com.lagradost.cloudstream3.utils.getQualityFromName
@ -29,14 +28,14 @@ open class VoeExtractor : ExtractorApi() {
.replace("0,", "0") .replace("0,", "0")
.trim() .trim()
//Log.i(this.name, "Result => (src) ${src}") //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}") //Log.i(this.name, "Result => (voelink) ${voelink}")
val linkUrl = voelink.url val linkUrl = voelink.url
val linkLabel = voelink.label?.toString() ?: "" val linkLabel = voelink.label?.toString() ?: ""
if (!linkUrl.isNullOrEmpty()) { if (!linkUrl.isNullOrEmpty()) {
extractedLinksList.add( extractedLinksList.add(
ExtractorLink( ExtractorLink(
name = "Voe ${linkLabel}", name = "Voe $linkLabel",
source = this.name, source = this.name,
url = linkUrl, url = linkUrl,
quality = getQualityFromName(linkLabel), quality = getQualityFromName(linkLabel),

View file

@ -2,8 +2,11 @@ package com.lagradost.cloudstream3.movieproviders
import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.readValue
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.toJson 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 okio.Buffer
import org.jsoup.Jsoup import org.jsoup.Jsoup
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
@ -211,14 +214,7 @@ class AllMoviesForYouProvider : MainAPI() {
} }
} }
} else if (requestUrl.startsWith("https://dood")) { } else if (requestUrl.startsWith("https://dood")) {
for (extractor in extractorApis) { loadExtractor(requestUrl, null, callback)
if (requestUrl.startsWith(extractor.mainUrl)) {
extractor.getSafeUrl(requestUrl)?.forEach { link ->
callback(link)
}
break
}
}
} else { } else {
callback( callback(
ExtractorLink( ExtractorLink(

View file

@ -1,7 +1,8 @@
package com.lagradost.cloudstream3.movieproviders package com.lagradost.cloudstream3.movieproviders
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.extractorApis
import java.util.* import java.util.*
class CinecalidadProvider : MainAPI() { class CinecalidadProvider : MainAPI() {
@ -15,6 +16,7 @@ class CinecalidadProvider:MainAPI() {
TvType.Movie, TvType.Movie,
TvType.TvSeries, TvType.TvSeries,
) )
override suspend fun getMainPage(): HomePageResponse { override suspend fun getMainPage(): HomePageResponse {
val items = ArrayList<HomePageList>() val items = ArrayList<HomePageList>()
val urls = listOf( val urls = listOf(
@ -22,7 +24,10 @@ class CinecalidadProvider:MainAPI() {
Pair("$mainUrl/genero-de-la-pelicula/peliculas-en-calidad-4k/", "4K UHD"), Pair("$mainUrl/genero-de-la-pelicula/peliculas-en-calidad-4k/", "4K UHD"),
) )
items.add(HomePageList("Series",app.get("$mainUrl/ver-serie/").document.select(".item.tvshows").map{ items.add(
HomePageList(
"Series",
app.get("$mainUrl/ver-serie/").document.select(".item.tvshows").map {
val title = it.selectFirst("div.in_title").text() val title = it.selectFirst("div.in_title").text()
TvSeriesSearchResponse( TvSeriesSearchResponse(
title, title,
@ -33,7 +38,8 @@ class CinecalidadProvider:MainAPI() {
null, null,
null, null,
) )
})) })
)
for (i in urls) { for (i in urls) {
try { try {
@ -100,7 +106,9 @@ class CinecalidadProvider:MainAPI() {
val soup = app.get(url, timeout = 120).document val soup = app.get(url, timeout = 120).document
val title = soup.selectFirst(".single_left h1").text() 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 poster: String? = soup.selectFirst(".alignnone").attr("data-src")
val episodes = soup.select("div.se-c div.se-a ul.episodios li").map { li -> val episodes = soup.select("div.se-c div.se-a ul.episodios li").map { li ->
val href = li.selectFirst("a").attr("href") val href = li.selectFirst("a").attr("href")
@ -114,7 +122,8 @@ class CinecalidadProvider:MainAPI() {
epThumb epThumb
) )
} }
return when (val tvType = if (url.contains("/ver-pelicula/")) TvType.Movie else TvType.TvSeries) { return when (val tvType =
if (url.contains("/ver-pelicula/")) TvType.Movie else TvType.TvSeries) {
TvType.TvSeries -> { TvType.TvSeries -> {
TvSeriesLoadResponse( TvSeriesLoadResponse(
title, title,
@ -159,7 +168,8 @@ class CinecalidadProvider:MainAPI() {
val videos = serverRegex.findAll(urlserver).map { val videos = serverRegex.findAll(urlserver).map {
it.value.replace("\\/", "/").replace("\"", "") it.value.replace("\\/", "/").replace("\"", "")
}.toList() }.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() val links = serversRegex.findAll(videos.toString()).map { it.value }.toList()
for (link in links) { for (link in links) {
for (extractor in extractorApis) { for (extractor in extractorApis) {

View file

@ -1,16 +1,14 @@
package com.lagradost.cloudstream3.animeproviders package com.lagradost.cloudstream3.animeproviders
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import java.util.*
import com.lagradost.cloudstream3.extractors.FEmbed import com.lagradost.cloudstream3.extractors.FEmbed
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor import com.lagradost.cloudstream3.utils.loadExtractor
import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
class DoramasYTProvider : MainAPI() { class DoramasYTProvider : MainAPI() {
companion object { companion object {
fun getType(t: String): TvType { fun getType(t: String): TvType {
return if (t.contains("OVA") || t.contains("Especial")) TvType.ONA return if (t.contains("OVA") || t.contains("Especial")) TvType.ONA
@ -33,18 +31,28 @@ class DoramasYTProvider:MainAPI() {
override suspend fun getMainPage(): HomePageResponse { override suspend fun getMainPage(): HomePageResponse {
val urls = listOf( val urls = listOf(
Pair("$mainUrl/emision", "En emisión"), 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", "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>() val items = ArrayList<HomePageList>()
items.add(HomePageList("Capítulos actualizados", app.get(mainUrl, timeout = 120).document.select(".col-6").map{ items.add(
HomePageList(
"Capítulos actualizados",
app.get(mainUrl, timeout = 120).document.select(".col-6").map {
val title = it.selectFirst("p").text() val title = it.selectFirst("p").text()
val poster = it.selectFirst(".chapter img").attr("src") val poster = it.selectFirst(".chapter img").attr("src")
val epRegex = Regex("episodio-(\\d+)") val epRegex = Regex("episodio-(\\d+)")
val url = it.selectFirst("a").attr("href").replace("ver/","dorama/").replace(epRegex,"sub-espanol") val url = it.selectFirst("a").attr("href").replace("ver/", "dorama/")
.replace(epRegex, "sub-espanol")
val epNum = it.selectFirst("h3").text().toIntOrNull() val epNum = it.selectFirst("h3").text().toIntOrNull()
AnimeSearchResponse( AnimeSearchResponse(
title, title,
@ -53,11 +61,14 @@ class DoramasYTProvider:MainAPI() {
TvType.Anime, TvType.Anime,
poster, poster,
null, 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),
subEpisodes = epNum, subEpisodes = epNum,
dubEpisodes = epNum, dubEpisodes = epNum,
) )
})) })
)
for (i in urls) { for (i in urls) {
try { try {
@ -72,7 +83,9 @@ class DoramasYTProvider:MainAPI() {
TvType.Anime, TvType.Anime,
poster, poster,
null, 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,7 +100,8 @@ class DoramasYTProvider:MainAPI() {
} }
override suspend fun search(query: String): ArrayList<SearchResponse> { override suspend fun search(query: String): ArrayList<SearchResponse> {
val search = app.get("$mainUrl/buscar?q=$query", timeout = 120).document.select(".col-6").map { val search =
app.get("$mainUrl/buscar?q=$query", timeout = 120).document.select(".col-6").map {
val title = it.selectFirst(".animedtls p").text() val title = it.selectFirst(".animedtls p").text()
val href = it.selectFirst("a").attr("href") val href = it.selectFirst("a").attr("href")
val image = it.selectFirst(".animes img").attr("src") val image = it.selectFirst(".animes img").attr("src")
@ -98,11 +112,14 @@ class DoramasYTProvider:MainAPI() {
TvType.Anime, TvType.Anime,
image, image,
null, 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),
) )
} }
return ArrayList(search) return ArrayList(search)
} }
override suspend fun load(url: String): LoadResponse { override suspend fun load(url: String): LoadResponse {
val doc = app.get(url, timeout = 120).document val doc = app.get(url, timeout = 120).document
val poster = doc.selectFirst("div.flimimg img.img1").attr("src") val poster = doc.selectFirst("div.flimimg img.img1").attr("src")
@ -129,13 +146,14 @@ class DoramasYTProvider:MainAPI() {
tags = genres tags = genres
} }
} }
override suspend fun loadLinks( override suspend fun loadLinks(
data: String, data: String,
isCasting: Boolean, isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
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 encodedurl = it.select("p").attr("data-player")
val urlDecoded = base64Decode(encodedurl) val urlDecoded = base64Decode(encodedurl)
val url = (urlDecoded).replace("https://doramasyt.com/reproductor?url=", "") val url = (urlDecoded).replace("https://doramasyt.com/reproductor?url=", "")

View file

@ -157,13 +157,10 @@ class DramaSeeProvider : MainAPI() {
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
var count = 0 var count = 0
mapper.readValue<List<String>>(data).forEach { item -> mapper.readValue<List<String>>(data).apmap { item ->
if (item.isNotEmpty()) { if (item.isNotEmpty()) {
count++ count++
var url = item.trim() var url = fixUrl(item.trim())
if (url.startsWith("//")) {
url = "https:$url"
}
//Log.i(this.name, "Result => (url) ${url}") //Log.i(this.name, "Result => (url) ${url}")
when { when {
url.startsWith("https://asianembed.io") -> { url.startsWith("https://asianembed.io") -> {

View file

@ -69,7 +69,17 @@ class FilmanProvider : MainAPI() {
val img = i.selectFirst("> img").attr("src").replace("/thumb/", "/big/") val img = i.selectFirst("> img").attr("src").replace("/thumb/", "/big/")
val name = i.selectFirst(".title").text() val name = i.selectFirst(".title").text()
if (type === TvType.TvSeries) { 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 { } else {
returnValue.add(MovieSearchResponse(name, href, this.name, type, img, null)) 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) val regex = Regex("""\[s(\d{1,3})e(\d{1,3})]""").find(e)
if (regex != null) { if (regex != null) {
val eid = regex.groups val eid = regex.groups
episodes.add(TvSeriesEpisode( episodes.add(
TvSeriesEpisode(
e.split("]")[1].trim(), e.split("]")[1].trim(),
eid[1]?.value?.toInt(), eid[1]?.value?.toInt(),
eid[2]?.value?.toInt(), eid[2]?.value?.toInt(),
episode.attr("href"), 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( override suspend fun loadLinks(
@ -115,16 +136,12 @@ class FilmanProvider : MainAPI() {
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
if(data.isEmpty()) {
return false
}
val document = if (data.startsWith("http")) val document = if (data.startsWith("http"))
Jsoup.parse(app.get(data).text).select("#links").first() app.get(data).document.select("#links").first()
else Jsoup.parse(data) else Jsoup.parse(data)
val items = document.select(".link-to-video") document.select(".link-to-video")?.apmap { item ->
for (i in items) { val decoded = base64Decode(item.select("a").attr("data-iframe"))
val decoded = base64Decode(i.select("a").attr("data-iframe"))
val link = mapper.readValue<LinkElement>(decoded).src val link = mapper.readValue<LinkElement>(decoded).src
loadExtractor(link, null, callback) loadExtractor(link, null, callback)
} }

View file

@ -1,8 +1,8 @@
package com.lagradost.cloudstream3.movieproviders package com.lagradost.cloudstream3.movieproviders
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.StreamTape
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.net.URLEncoder import java.net.URLEncoder
@ -18,8 +18,23 @@ class IHaveNoTvProvider : MainAPI() {
// Uhh, I am too lazy to scrape the "latest documentaries" and "recommended documentaries", // Uhh, I am too lazy to scrape the "latest documentaries" and "recommended documentaries",
// so I am just scraping 3 random categories // so I am just scraping 3 random categories
val allCategories = listOf( val allCategories = listOf(
"astronomy", "brain", "creativity", "design", "economics", "environment", "health", "history", "astronomy",
"lifehack", "math", "music", "nature", "people", "physics", "science", "technology", "travel" "brain",
"creativity",
"design",
"economics",
"environment",
"health",
"history",
"lifehack",
"math",
"music",
"nature",
"people",
"physics",
"science",
"technology",
"travel"
) )
val categories = allCategories.asSequence().shuffled().take(3) val categories = allCategories.asSequence().shuffled().take(3)
@ -82,7 +97,9 @@ class IHaveNoTvProvider : MainAPI() {
res.selectFirst("a[href][title]") res.selectFirst("a[href][title]")
} }
val year = 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() ?.toIntOrNull()
val title = aTag.attr("title") val title = aTag.attr("title")
@ -138,7 +155,8 @@ class IHaveNoTvProvider : MainAPI() {
ep.selectFirst(".episodeMeta").text() ep.selectFirst(".episodeMeta").text()
)?.destructured?.component1()?.toIntOrNull() )?.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( TvSeriesEpisode(
epTitle, epTitle,
@ -165,7 +183,8 @@ class IHaveNoTvProvider : MainAPI() {
description, description,
null, null,
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") val iframe = soup.selectFirst("#videoWrap iframe")
if (iframe != null) { if (iframe != null) {
if (iframe.attr("src").startsWith("https://streamtape.com")) { loadExtractor(iframe.attr("src"), null, callback)
StreamTape().getSafeUrl(iframe.attr("src"))?.forEach(callback)
}
} }
return true return true
} }

View file

@ -1,6 +1,5 @@
package com.lagradost.cloudstream3.movieproviders package com.lagradost.cloudstream3.movieproviders
import android.util.Log
import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.readValue
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.* 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.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup import org.jsoup.Jsoup
import kotlin.Exception
class KdramaHoodProvider : MainAPI() { class KdramaHoodProvider : MainAPI() {
override val mainUrl = "https://kdramahood.com" override val mainUrl = "https://kdramahood.com"
@ -131,13 +129,10 @@ class KdramaHoodProvider : MainAPI() {
if (!epLinksContent.isNullOrEmpty()) { if (!epLinksContent.isNullOrEmpty()) {
//Log.i(this.name, "Result => (epLinksContent) ${Jsoup.parse(epLinksContent)?.select("div")}") //Log.i(this.name, "Result => (epLinksContent) ${Jsoup.parse(epLinksContent)?.select("div")}")
Jsoup.parse(epLinksContent)?.select("div")?.forEach { em -> Jsoup.parse(epLinksContent)?.select("div")?.forEach { em ->
var href = em?.html()?.trim()?.removePrefix("'") ?: return@forEach val href = em?.html()?.trim()?.removePrefix("'") ?: return@forEach
if (href.startsWith("//")) {
href = "https:$href"
}
//Log.i(this.name, "Result => (ep#$count link) $href") //Log.i(this.name, "Result => (ep#$count link) $href")
if (href.isNotEmpty()) { if (href.isNotEmpty()) {
listOfLinks.add(href) listOfLinks.add(fixUrl(href))
} }
} }
/* Doesn't get all links for some reasons /* Doesn't get all links for some reasons
@ -188,7 +183,7 @@ class KdramaHoodProvider : MainAPI() {
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
var count = 0 var count = 0
mapper.readValue<List<String>>(data).forEach { item -> mapper.readValue<List<String>>(data).apmap { item ->
if (item.isNotEmpty()) { if (item.isNotEmpty()) {
count++ count++
var url = item.trim() var url = item.trim()

View file

@ -231,7 +231,7 @@ open class PelisplusProviderTemplate : MainAPI() {
null 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. // 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 // Group 1: link, Group 2: Label

View file

@ -1,6 +1,5 @@
package com.lagradost.cloudstream3.movieproviders package com.lagradost.cloudstream3.movieproviders
import android.util.Log
import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.readValue
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.utils.AppUtils.toJson import com.lagradost.cloudstream3.utils.AppUtils.toJson
@ -192,7 +191,7 @@ class PinoyHDXyzProvider : MainAPI() {
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
var count = 0 var count = 0
mapper.readValue<List<String>>(data).forEach { item -> mapper.readValue<List<String>>(data).apmap { item ->
if (item.isNotEmpty()) { if (item.isNotEmpty()) {
val url = item.trim() val url = item.trim()
loadExtractor(url, mainUrl, callback) loadExtractor(url, mainUrl, callback)

View file

@ -179,7 +179,7 @@ class PinoyMoviePediaProvider : MainAPI() {
): Boolean { ): Boolean {
// parse movie servers // parse movie servers
var count = 0 var count = 0
mapper.readValue<List<String>>(data).forEach { link -> mapper.readValue<List<String>>(data).apmap { link ->
count++ count++
if (link.contains("fembed.com")) { if (link.contains("fembed.com")) {
val extractor = FEmbed() val extractor = FEmbed()

View file

@ -136,7 +136,7 @@ class PinoyMoviesEsProvider : MainAPI() {
it?.attr("data-post") ?: return@mapNotNull null it?.attr("data-post") ?: return@mapNotNull null
}?.filter { it.isNotEmpty() }?.distinct() ?: listOf() }?.filter { it.isNotEmpty() }?.distinct() ?: listOf()
postlist.forEach { datapost -> postlist.apmap { datapost ->
//Log.i(this.name, "Result => (datapost) ${datapost}") //Log.i(this.name, "Result => (datapost) ${datapost}")
val content = mapOf( val content = mapOf(
Pair("action", "doo_player_ajax"), Pair("action", "doo_player_ajax"),
@ -163,7 +163,7 @@ class PinoyMoviesEsProvider : MainAPI() {
): Boolean { ): Boolean {
// parse movie servers // parse movie servers
var count = 0 var count = 0
mapper.readValue<List<String>>(data).forEach { link -> mapper.readValue<List<String>>(data).apmap { link ->
count++ count++
//Log.i(this.name, "Result => (link) $link") //Log.i(this.name, "Result => (link) $link")
if (link.startsWith("https://vstreamhub.com")) { if (link.startsWith("https://vstreamhub.com")) {

View file

@ -215,10 +215,9 @@ class SflixProvider(providerUrl: String, providerName: String) : MainAPI() {
): Boolean { ): Boolean {
val urls = (tryParseJson<Pair<String, String>>(data)?.let { (prefix, server) -> val urls = (tryParseJson<Pair<String, String>>(data)?.let { (prefix, server) ->
val episodesUrl = "$mainUrl/ajax/v2/episode/servers/$server" val episodesUrl = "$mainUrl/ajax/v2/episode/servers/$server"
val episodes = app.get(episodesUrl).text
// Supported streams, they're identical // 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 val id = element?.attr("data-id") ?: return@mapNotNull null
if (element.select("span")?.text()?.trim()?.isValidServer() == true) { if (element.select("span")?.text()?.trim()?.isValidServer() == true) {
"$prefix.$id".replace("/tv/", "/watch-tv/") "$prefix.$id".replace("/tv/", "/watch-tv/")
@ -250,7 +249,6 @@ class SflixProvider(providerUrl: String, providerName: String) : MainAPI() {
mapped.sources2 to "source 3", mapped.sources2 to "source 3",
mapped.sourcesBackup to "source backup" mapped.sourcesBackup to "source backup"
).forEach { (sources, sourceName) -> ).forEach { (sources, sourceName) ->
println("SOURCE:::: $sourceName $sources")
sources?.forEach { sources?.forEach {
it?.toExtractorLink(this, sourceName)?.forEach(callback) it?.toExtractorLink(this, sourceName)?.forEach(callback)
} }

View file

@ -77,7 +77,8 @@ open class VidstreamProviderTemplate : MainAPI() {
val description = soup.selectFirst(".post-entry")?.text()?.trim() val description = soup.selectFirst(".post-entry")?.text()?.trim()
var poster: String? = null var poster: String? = null
val episodes = soup.select(".listing.items.lists > .video-block").withIndex().map { (_, li) -> val episodes =
soup.select(".listing.items.lists > .video-block").withIndex().map { (_, li) ->
val epTitle = if (li.selectFirst(".name") != null) val epTitle = if (li.selectFirst(".name") != null)
if (li.selectFirst(".name").text().contains("Episode")) if (li.selectFirst(".name").text().contains("Episode"))
"Episode " + li.selectFirst(".name").text().split("Episode")[1].trim() "Episode " + li.selectFirst(".name").text().split("Episode")[1].trim()
@ -88,10 +89,12 @@ open class VidstreamProviderTemplate : MainAPI() {
val epDate = li.selectFirst(".meta > .date").text() val epDate = li.selectFirst(".meta > .date").text()
if (poster == null) { if (poster == null) {
poster = li.selectFirst("img")?.attr("onerror")?.split("=")?.get(1)?.replace(Regex("[';]"), "") 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( TvSeriesEpisode(
epTitle, epTitle,
@ -106,7 +109,8 @@ open class VidstreamProviderTemplate : MainAPI() {
val year = episodes.first().date?.split("-")?.get(0)?.toIntOrNull() val year = episodes.first().date?.split("-")?.get(0)?.toIntOrNull()
// Make sure to get the type right to display the correct UI. // 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) { return when (tvType) {
TvType.TvSeries -> { TvType.TvSeries -> {
@ -157,7 +161,8 @@ open class VidstreamProviderTemplate : MainAPI() {
val elements = inner.select(".video-block").map { val elements = inner.select(".video-block").map {
val link = fixUrl(it.select("a").attr("href")) val link = fixUrl(it.select("a").attr("href"))
val image = it.select(".picture > img").attr("src") 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")) val isSeries = (name.contains("Season") || name.contains("Episode"))
if (isSeries) { if (isSeries) {
@ -188,9 +193,7 @@ open class VidstreamProviderTemplate : MainAPI() {
title, elements title, elements
) )
) )
} }
} }
return HomePageResponse(homePageList) return HomePageResponse(homePageList)
} }
@ -206,7 +209,8 @@ open class VidstreamProviderTemplate : MainAPI() {
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
// "?: return" is a very useful statement which returns if the iframe link isn't found. // "?: 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. // In this case the video player is a vidstream clone and can be handled by the vidstream extractor.
// This case is a both unorthodox and you normally do not call extractors as they detect the url returned and does the rest. // This case is a both unorthodox and you normally do not call extractors as they detect the url returned and does the rest.
@ -228,13 +232,15 @@ open class VidstreamProviderTemplate : MainAPI() {
null 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. // 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 // Group 1: link, Group 2: Label
// Regex can be used to effectively parse small amounts of json without bothering with writing a json class. // 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 sourceRegex =
val trackRegex = Regex("""tracks:[\W\w]*?file:\s*["'](.*?)["'][\W\w]*?label:\s*["'](.*?)["']""") 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. // Having a referer is often required. It's a basic security check most providers have.
// Try to replicate what your browser does. // Try to replicate what your browser does.

View file

@ -174,12 +174,9 @@ class WatchAsianProvider : MainAPI() {
getServerLinks(data) getServerLinks(data)
} else { data } } else { data }
var count = 0 var count = 0
mapper.readValue<List<String>>(links).forEach { item -> mapper.readValue<List<String>>(links).apmap { item ->
count++ count++
var url = item.trim() val url = fixUrl(item.trim())
if (url.startsWith("//")) {
url = "https:$url"
}
//Log.i(this.name, "Result => (url) $url") //Log.i(this.name, "Result => (url) $url")
if (url.startsWith("https://asianembed.io")) { if (url.startsWith("https://asianembed.io")) {
// Fetch links // Fetch links

View file

@ -1,6 +1,7 @@
package com.lagradost.cloudstream3.network package com.lagradost.cloudstream3.network
import android.content.Context import android.content.Context
import android.util.Log
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.readValue
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
@ -286,6 +287,7 @@ open class Requests {
timeout: Long = 0L, timeout: Long = 0L,
interceptor: Interceptor? = null, interceptor: Interceptor? = null,
): AppResponse { ): AppResponse {
Log.i("GET", url)
val client = baseClient val client = baseClient
.newBuilder() .newBuilder()
.followRedirects(allowRedirects) .followRedirects(allowRedirects)
@ -315,6 +317,7 @@ open class Requests {
cacheUnit: TimeUnit = DEFAULT_TIME_UNIT, cacheUnit: TimeUnit = DEFAULT_TIME_UNIT,
timeout: Long = 0L, timeout: Long = 0L,
): AppResponse { ): AppResponse {
Log.i("POST", url)
val client = baseClient val client = baseClient
.newBuilder() .newBuilder()
.followRedirects(allowRedirects) .followRedirects(allowRedirects)
@ -339,6 +342,7 @@ open class Requests {
cacheUnit: TimeUnit = DEFAULT_TIME_UNIT, cacheUnit: TimeUnit = DEFAULT_TIME_UNIT,
timeout: Long = 0L timeout: Long = 0L
): AppResponse { ): AppResponse {
Log.i("PUT", url)
val client = baseClient val client = baseClient
.newBuilder() .newBuilder()
.followRedirects(allowRedirects) .followRedirects(allowRedirects)

View file

@ -22,6 +22,7 @@ import com.google.android.material.button.MaterialButton
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
import com.lagradost.cloudstream3.APIHolder.getApiFromName import com.lagradost.cloudstream3.APIHolder.getApiFromName
import com.lagradost.cloudstream3.APIHolder.getApiSettings
import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.observe import com.lagradost.cloudstream3.mvvm.observe
@ -93,6 +94,22 @@ class SearchFragment : Fragment() {
var selectedSearchTypes = mutableListOf<TvType>() var selectedSearchTypes = mutableListOf<TvType>()
var selectedApis = mutableSetOf<String>() 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?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
@ -274,6 +291,7 @@ class SearchFragment : Fragment() {
button?.isSelected = buttonContains() button?.isSelected = buttonContains()
button?.setOnClickListener { button?.setOnClickListener {
val last = selectedSearchTypes.toSet()
selectedSearchTypes.clear() selectedSearchTypes.clear()
selectedSearchTypes.addAll(validTypes) selectedSearchTypes.addAll(validTypes)
for ((otherButton, _) in pairList) { for ((otherButton, _) in pairList) {
@ -281,6 +299,8 @@ class SearchFragment : Fragment() {
} }
it?.context?.setKey(SEARCH_PREF_TAGS, selectedSearchTypes) it?.context?.setKey(SEARCH_PREF_TAGS, selectedSearchTypes)
it?.isSelected = true 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 { button?.setOnLongClickListener {
@ -292,6 +312,7 @@ class SearchFragment : Fragment() {
selectedSearchTypes.removeAll(validTypes) selectedSearchTypes.removeAll(validTypes)
} }
it?.context?.setKey(SEARCH_PREF_TAGS, selectedSearchTypes) it?.context?.setKey(SEARCH_PREF_TAGS, selectedSearchTypes)
search(main_search?.query?.toString())
return@setOnLongClickListener true return@setOnLongClickListener true
} }
} }
@ -305,12 +326,7 @@ class SearchFragment : Fragment() {
main_search.setOnQueryTextListener(object : SearchView.OnQueryTextListener { main_search.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean { override fun onQueryTextSubmit(query: String): Boolean {
searchViewModel.searchAndCancel( search(query)
query = query,
providersActive = selectedApis.filter { name ->
getApiFromName(name).supportedTypes.any { selectedSearchTypes.contains(it) }
}.toSet()
)
main_search?.let { main_search?.let {
hideKeyboard(it) hideKeyboard(it)

View file

@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule import com.fasterxml.jackson.module.kotlin.KotlinModule
const val DOWNLOAD_HEADER_CACHE = "download_header_cache" const val DOWNLOAD_HEADER_CACHE = "download_header_cache"
//const val WATCH_HEADER_CACHE = "watch_header_cache" //const val WATCH_HEADER_CACHE = "watch_header_cache"
const val DOWNLOAD_EPISODE_CACHE = "download_episode_cache" const val DOWNLOAD_EPISODE_CACHE = "download_episode_cache"
const val VIDEO_PLAYER_BRIGHTNESS = "video_player_alpha_key" const val VIDEO_PLAYER_BRIGHTNESS = "video_player_alpha_key"

View file

@ -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. * 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) { for (extractor in extractorApis) {
if (url.startsWith(extractor.mainUrl)) { if (url.startsWith(extractor.mainUrl)) {
extractor.getSafeUrl(url, referer)?.forEach(callback) extractor.getSafeUrl(url, referer)?.forEach(callback)