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> {
|
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> {
|
||||||
|
|
|
@ -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() }
|
||||||
}
|
}
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -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),
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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=", "")
|
||||||
|
|
|
@ -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") -> {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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")) {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue