Switched to NiceHttp

Used !! as it was easier (with 10000 providers)
+ visible errors
This commit is contained in:
Blatzar 2022-05-02 18:58:27 +02:00
parent e64a875543
commit 109e1b9f17
56 changed files with 728 additions and 1094 deletions

View file

@ -105,16 +105,16 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
//implementation "io.karn:khttp-android:0.1.2" //okhttp instead
implementation 'org.jsoup:jsoup:1.13.1'
implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.12.3"
// implementation 'org.jsoup:jsoup:1.13.1'
// implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.12.3"
implementation "com.google.android.material:material:1.5.0"
implementation "androidx.preference:preference-ktx:1.2.0"
implementation 'com.github.bumptech.glide:glide:4.13.0'
kapt 'com.github.bumptech.glide:compiler:4.13.0'
implementation 'com.github.bumptech.glide:okhttp3-integration:4.12.0'
implementation 'com.github.bumptech.glide:glide:4.13.1'
kapt 'com.github.bumptech.glide:compiler:4.13.1'
implementation 'com.github.bumptech.glide:okhttp3-integration:4.13.0'
implementation 'jp.wasabeef:glide-transformations:4.3.0'
@ -154,8 +154,9 @@ dependencies {
implementation "androidx.work:work-runtime-ktx:2.7.1"
// Networking
implementation "com.squareup.okhttp3:okhttp:4.9.2"
implementation "com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.1"
// implementation "com.squareup.okhttp3:okhttp:4.9.2"
// implementation "com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.1"
implementation 'com.github.Blatzar:NiceHttp:0.1.8'
// Util to skip the URI file fuckery 🙏
implementation "com.github.tachiyomiorg:unifile:17bec43"

View file

@ -36,7 +36,7 @@ import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.CommonActivity.updateLocale
import com.lagradost.cloudstream3.movieproviders.NginxProvider
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.network.Requests
import com.lagradost.cloudstream3.network.initClient
import com.lagradost.cloudstream3.receivers.VideoDownloadRestartReceiver
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.OAuth2Apis
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.OAuth2accountApis
@ -65,6 +65,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.getResourceColor
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
import com.lagradost.cloudstream3.utils.UIHelper.navigate
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
import com.lagradost.nicehttp.Requests
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.fragment_result_swipe.*
import kotlinx.coroutines.Dispatchers

View file

@ -32,10 +32,10 @@ class AnimeFlickProvider : MainAPI() {
val html = app.get(link).text
val doc = Jsoup.parse(html)
return doc.select(".row.mt-2").map {
val href = mainUrl + it.selectFirst("a").attr("href")
val title = it.selectFirst("h5 > a").text()
val poster = mainUrl + it.selectFirst("img").attr("src").replace("70x110", "225x320")
return doc.select(".row.mt-2").mapNotNull {
val href = mainUrl + it.selectFirst("a")?.attr("href")
val title = it.selectFirst("h5 > a")?.text() ?: return@mapNotNull null
val poster = mainUrl + it.selectFirst("img")?.attr("src")?.replace("70x110", "225x320")
AnimeSearchResponse(
title,
href,
@ -52,19 +52,19 @@ class AnimeFlickProvider : MainAPI() {
val html = app.get(url).text
val doc = Jsoup.parse(html)
val poster = mainUrl + doc.selectFirst("img.rounded").attr("src")
val title = doc.selectFirst("h2.title").text()
val poster = mainUrl + doc.selectFirst("img.rounded")?.attr("src")
val title = doc.selectFirst("h2.title")!!.text()
val yearText = doc.selectFirst(".trending-year")?.text()
val year = if (yearText != null) Regex("""(\d{4})""").find(yearText)?.destructured?.component1()
?.toIntOrNull() else null
val description = doc.selectFirst("p").text()
val description = doc.selectFirst("p")?.text()
val genres = doc.select("a[href*=\"genre-\"]").map { it.text() }
val episodes = doc.select("#collapseOne .block-space > .row > div:nth-child(2)").map {
val name = it.selectFirst("a").text()
val link = mainUrl + it.selectFirst("a").attr("href")
val name = it.selectFirst("a")?.text()
val link = mainUrl + it.selectFirst("a")?.attr("href")
Episode(link, name)
}.reversed()

View file

@ -7,10 +7,10 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
import com.lagradost.cloudstream3.network.AppResponse
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.JsUnpacker
import com.lagradost.cloudstream3.utils.getQualityFromName
import com.lagradost.nicehttp.NiceResponse
import org.jsoup.Jsoup
import kotlin.math.pow
@ -242,7 +242,7 @@ class AnimePaheProvider : MainAPI() {
val doc = Jsoup.parse(html)
val japTitle = doc.selectFirst("h2.japanese")?.text()
val poster = doc.selectFirst(".anime-poster a").attr("href")
val poster = doc.selectFirst(".anime-poster a")?.attr("href")
val tvType = doc.selectFirst("""a[href*="/anime/type/"]""")?.text()
@ -263,7 +263,7 @@ class AnimePaheProvider : MainAPI() {
"completed" -> ShowStatus.Completed
else -> null
}
val synopsis = doc.selectFirst(".anime-synopsis").text()
val synopsis = doc.selectFirst(".anime-synopsis")?.text()
var anilistId: Int? = null
var malId: Int? = null
@ -431,7 +431,7 @@ class AnimePaheProvider : MainAPI() {
}
var responseCode = 302
var adflyContent: AppResponse? = null
var adflyContent: NiceResponse? = null
var tries = 0
while (responseCode != 200 && tries < 20) {
@ -481,7 +481,7 @@ class AnimePaheProvider : MainAPI() {
val decrypted = decrypt(fullString, key, v1.toInt(), v2.toInt())
val uri = KWIK_D_URL.find(decrypted)!!.destructured.component1()
val tok = KWIK_D_TOKEN.find(decrypted)!!.destructured.component1()
var content: AppResponse? = null
var content: NiceResponse? = null
var code = 419
var tries = 0

View file

@ -6,10 +6,10 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
import com.lagradost.cloudstream3.LoadResponse.Companion.addRating
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.network.AppResponse
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.nicehttp.NiceResponse
import org.jsoup.nodes.Element
class AnimeWorldProvider : MainAPI() {
@ -29,7 +29,7 @@ class AnimeWorldProvider : MainAPI() {
private val cookieRegex = Regex("$cookieName=(.+?)(\\s?);")
private val cookies = mutableMapOf(cookieName to "")
private suspend fun request(url: String): AppResponse {
private suspend fun request(url: String): NiceResponse {
val response = app.get(url, cookies = cookies)
return cookieRegex.find(response.text)?.let {
val verify = it.groups[1]?.value ?: throw ErrorLoadingException("Can't bypass protection")

View file

@ -7,19 +7,21 @@ import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import java.util.*
class AnimeflvnetProvider:MainAPI() {
class AnimeflvnetProvider : MainAPI() {
companion object {
fun getType(t: String): TvType {
return if (t.contains("OVA") || t.contains("Especial")) TvType.OVA
else if (t.contains("Película")) TvType.AnimeMovie
else TvType.Anime
}
fun getDubStatus(title: String): DubStatus {
return if (title.contains("Latino") || title.contains("Castellano"))
DubStatus.Dubbed
else DubStatus.Subbed
}
}
override var mainUrl = "https://www3.animeflv.net"
override var name = "Animeflv.net"
override val lang = "es"
@ -42,13 +44,14 @@ class AnimeflvnetProvider:MainAPI() {
items.add(
HomePageList(
"Últimos episodios",
app.get(mainUrl).document.select("main.Main ul.ListEpisodios li").map {
val title = it.selectFirst("strong.Title").text()
val poster = it.selectFirst("span img").attr("src")
app.get(mainUrl).document.select("main.Main ul.ListEpisodios li").mapNotNull {
val title = it.selectFirst("strong.Title")?.text() ?: return@mapNotNull null
val poster = it.selectFirst("span img")?.attr("src") ?: return@mapNotNull null
val epRegex = Regex("(-(\\d+)\$)")
val url = it.selectFirst("a").attr("href").replace(epRegex,"")
.replace("ver/","anime/")
val epNum = it.selectFirst("span.Capi").text().replace("Episodio ","").toIntOrNull()
val url = it.selectFirst("a")?.attr("href")?.replace(epRegex, "")
?.replace("ver/", "anime/") ?: return@mapNotNull null
val epNum =
it.selectFirst("span.Capi")?.text()?.replace("Episodio ", "")?.toIntOrNull()
newAnimeSearchResponse(title, url) {
this.posterUrl = fixUrl(poster)
addDubStatus(getDubStatus(title), epNum)
@ -58,10 +61,13 @@ class AnimeflvnetProvider:MainAPI() {
for ((url, name) in urls) {
try {
val doc = app.get(url).document
val home = doc.select("ul.ListAnimes li article").map {
val title = it.selectFirst("h3.Title").text()
val poster = it.selectFirst("figure img").attr("src")
newAnimeSearchResponse(title, fixUrl(it.selectFirst("a").attr("href"))) {
val home = doc.select("ul.ListAnimes li article").mapNotNull {
val title = it.selectFirst("h3.Title")?.text() ?: return@mapNotNull null
val poster = it.selectFirst("figure img")?.attr("src") ?: return@mapNotNull null
newAnimeSearchResponse(
title,
fixUrl(it.selectFirst("a")?.attr("href") ?: return@mapNotNull null)
) {
this.posterUrl = fixUrl(poster)
addDubStatus(MonoschinosProvider.getDubStatus(title))
}
@ -76,7 +82,7 @@ class AnimeflvnetProvider:MainAPI() {
return HomePageResponse(items)
}
data class SearchObject (
data class SearchObject(
@JsonProperty("id") val id: String,
@JsonProperty("title") val title: String,
@JsonProperty("type") val type: String,
@ -85,33 +91,36 @@ class AnimeflvnetProvider:MainAPI() {
)
override suspend fun search(query: String): List<SearchResponse> {
val response = app.post("https://www3.animeflv.net/api/animes/search",
data = mapOf(Pair("value",query))
val response = app.post(
"https://www3.animeflv.net/api/animes/search",
data = mapOf(Pair("value", query))
).text
val json = parseJson<List<SearchObject>>(response)
return json.map { searchr ->
return json.map { searchr ->
val title = searchr.title
val href = "$mainUrl/anime/${searchr.slug}"
val image = "$mainUrl/uploads/animes/covers/${searchr.id}.jpg"
AnimeSearchResponse(
title,
href,
this.name,
TvType.Anime,
fixUrl(image),
null,
if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(DubStatus.Subbed),
)
AnimeSearchResponse(
title,
href,
this.name,
TvType.Anime,
fixUrl(image),
null,
if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(
DubStatus.Subbed
),
)
}
}
override suspend fun load(url: String): LoadResponse {
val doc = app.get(url).document
val episodes = ArrayList<Episode>()
val title = doc.selectFirst("h1.Title").text()
val poster = doc.selectFirst("div.AnimeCover div.Image figure img").attr("src")
val description = doc.selectFirst("div.Description p").text()
val type = doc.selectFirst("span.Type").text()
val title = doc.selectFirst("h1.Title")!!.text()
val poster = doc.selectFirst("div.AnimeCover div.Image figure img")?.attr("src")!!
val description = doc.selectFirst("div.Description p")?.text()
val type = doc.selectFirst("span.Type")?.text() ?: ""
val status = when (doc.selectFirst("p.AnmStts span")?.text()) {
"En emision" -> ShowStatus.Ongoing
"Finalizado" -> ShowStatus.Completed
@ -126,15 +135,16 @@ class AnimeflvnetProvider:MainAPI() {
data.split("],").forEach {
val epNum = it.removePrefix("[").substringBefore(",")
// val epthumbid = it.removePrefix("[").substringAfter(",").substringBefore("]")
val animeid = doc.selectFirst("div.Strs.RateIt").attr("data-id")
val animeid = doc.selectFirst("div.Strs.RateIt")?.attr("data-id")
val epthumb = "https://cdn.animeflv.net/screenshots/$animeid/$epNum/th_3.jpg"
val link = url.replace("/anime/","/ver/")+"-$epNum"
episodes.add( Episode(
link,
null,
posterUrl = epthumb,
episode = epNum.toIntOrNull()
)
val link = url.replace("/anime/", "/ver/") + "-$epNum"
episodes.add(
Episode(
link,
null,
posterUrl = epthumb,
episode = epNum.toIntOrNull()
)
)
}
}
@ -147,6 +157,7 @@ class AnimeflvnetProvider:MainAPI() {
tags = genre
}
}
override suspend fun loadLinks(
data: String,
isCasting: Boolean,
@ -154,11 +165,13 @@ class AnimeflvnetProvider:MainAPI() {
callback: (ExtractorLink) -> Unit
): Boolean {
app.get(data).document.select("script").apmap { script ->
if (script.data().contains("var videos = {") || script.data().contains("var anime_id =") || script.data().contains("server")) {
if (script.data().contains("var videos = {") || script.data()
.contains("var anime_id =") || script.data().contains("server")
) {
val videos = script.data().replace("\\/", "/")
fetchUrls(videos).map {
it.replace("https://embedsb.com/e/","https://watchsb.com/e/")
.replace("https://ok.ru","http://ok.ru")
it.replace("https://embedsb.com/e/", "https://watchsb.com/e/")
.replace("https://ok.ru", "http://ok.ru")
}.apmap {
loadExtractor(it, data, callback)
}

View file

@ -2,6 +2,9 @@ package com.lagradost.cloudstream3.animeproviders
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.mvvm.safeApiCall
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
@ -31,23 +34,20 @@ class AnimekisaProvider : MainAPI() {
Pair("$mainUrl/ajax/list/views?type=day", "Trending now"),
Pair("$mainUrl/ajax/list/views?type=week", "Trending by week"),
Pair("$mainUrl/ajax/list/views?type=month", "Trending by month"),
)
)
val items = ArrayList<HomePageList>()
for ((url, name) in urls) {
try {
val items = urls.mapNotNull {
suspendSafeApiCall {
val home = Jsoup.parse(
parseJson<Response>(
app.get(
url
it.first
).text
).html
).select("div.flw-item").map {
val title = it.selectFirst("h3.title a").text()
val link = it.selectFirst("a").attr("href")
val poster = it.selectFirst("img.lazyload").attr("data-src")
).select("div.flw-item").mapNotNull secondMap@ {
val title = it.selectFirst("h3.title a")?.text() ?: return@secondMap null
val link = it.selectFirst("a")?.attr("href") ?: return@secondMap null
val poster = it.selectFirst("img.lazyload")?.attr("data-src")
AnimeSearchResponse(
title,
link,
@ -60,52 +60,50 @@ class AnimekisaProvider : MainAPI() {
) else EnumSet.of(DubStatus.Subbed),
)
}
items.add(HomePageList(name, home))
} catch (e: Exception) {
e.printStackTrace()
HomePageList(name, home)
}
}
if (items.size <= 0) throw ErrorLoadingException()
if (items.isEmpty()) throw ErrorLoadingException()
return HomePageResponse(items)
}
override suspend fun search(query: String): List<SearchResponse> {
return app.get("$mainUrl/search/?keyword=$query").document.select("div.flw-item").map {
val title = it.selectFirst("h3 a").text()
val url = it.selectFirst("a.film-poster-ahref").attr("href")
.replace("watch/", "anime/").replace(
Regex("(-episode-(\\d+)\\/\$|-episode-(\\d+)\$|-episode-full|-episode-.*-.(\\/|))"),
""
return app.get("$mainUrl/search/?keyword=$query").document.select("div.flw-item")
.mapNotNull {
val title = it.selectFirst("h3 a")?.text() ?: ""
val url = it.selectFirst("a.film-poster-ahref")?.attr("href")
?.replace("watch/", "anime/")?.replace(
Regex("(-episode-(\\d+)\\/\$|-episode-(\\d+)\$|-episode-full|-episode-.*-.(\\/|))"),
""
) ?: return@mapNotNull null
val poster = it.selectFirst(".film-poster img")?.attr("data-src")
AnimeSearchResponse(
title,
url,
this.name,
TvType.Anime,
poster,
null,
if (title.contains("(DUB)") || title.contains("(Dub)")) EnumSet.of(
DubStatus.Dubbed
) else EnumSet.of(DubStatus.Subbed),
)
val poster = it.selectFirst(".film-poster img").attr("data-src")
AnimeSearchResponse(
title,
url,
this.name,
TvType.Anime,
poster,
null,
if (title.contains("(DUB)") || title.contains("(Dub)")) EnumSet.of(
DubStatus.Dubbed
) else EnumSet.of(DubStatus.Subbed),
)
}.toList()
}.toList()
}
override suspend fun load(url: String): LoadResponse {
val doc = app.get(url, timeout = 120).document
val poster = doc.selectFirst(".mb-2 img").attr("src")
?: doc.selectFirst("head meta[property=og:image]").attr("content")
val title = doc.selectFirst("h1.heading-name a").text()
val description = doc.selectFirst("div.description p").text().trim()
val poster = doc.selectFirst(".mb-2 img")?.attr("src")
?: doc.selectFirst("head meta[property=og:image]")?.attr("content")
val title = doc.selectFirst("h1.heading-name a")!!.text()
val description = doc.selectFirst("div.description p")?.text()?.trim()
val genres = doc.select("div.row-line a").map { it.text() }
val test = if (doc.selectFirst("div.dp-i-c-right").toString()
.contains("Airing")
) ShowStatus.Ongoing else ShowStatus.Completed
val episodes = doc.select("div.tab-content ul li.nav-item").map {
val link = it.selectFirst("a").attr("href")
val episodes = doc.select("div.tab-content ul li.nav-item").mapNotNull {
val link = it.selectFirst("a")?.attr("href") ?: return@mapNotNull null
Episode(link)
}
val type = if (doc.selectFirst(".dp-i-stats").toString()

View file

@ -57,9 +57,9 @@ class DubbedAnimeProvider : MainAPI() {
private suspend fun parseDocumentTrending(url: String): List<SearchResponse> {
val response = app.get(url).text
val document = Jsoup.parse(response)
return document.select("li > a").map {
return document.select("li > a").mapNotNull {
val href = fixUrl(it.attr("href"))
val title = it.selectFirst("> div > div.cittx").text()
val title = it.selectFirst("> div > div.cittx")?.text() ?: return@mapNotNull null
val poster = fixUrlNull(it.selectFirst("> div > div.imghddde > img")?.attr("src"))
AnimeSearchResponse(
title,
@ -79,10 +79,11 @@ class DubbedAnimeProvider : MainAPI() {
): List<SearchResponse> {
val response = app.get(url).text
val document = Jsoup.parse(response)
return document.select("a.grid__link").map {
return document.select("a.grid__link").mapNotNull {
val href = fixUrl(it.attr("href"))
val title = it.selectFirst("> div.gridtitlek").text()
val poster = fixUrl(it.selectFirst("> img.grid__img").attr("src"))
val title = it.selectFirst("> div.gridtitlek")?.text() ?: return@mapNotNull null
val poster =
fixUrl(it.selectFirst("> img.grid__img")?.attr("src") ?: return@mapNotNull null)
AnimeSearchResponse(
title,
if (trimEpisode) href.removeRange(href.lastIndexOf('/'), href.length) else href,
@ -135,9 +136,9 @@ class DubbedAnimeProvider : MainAPI() {
val document = Jsoup.parse(response)
val items = document.select("div.grid__item > a")
if (items.isEmpty()) return emptyList()
return items.map { i ->
return items.mapNotNull { i ->
val href = fixUrl(i.attr("href"))
val title = i.selectFirst("div.gridtitlek").text()
val title = i.selectFirst("div.gridtitlek")?.text() ?: return@mapNotNull null
val img = fixUrlNull(i.selectFirst("img.grid__img")?.attr("src"))
if (getIsMovie(href)) {
@ -164,11 +165,11 @@ class DubbedAnimeProvider : MainAPI() {
val document = Jsoup.parse(response)
val items = document.select("div.resultinner > a.resulta")
if (items.isEmpty()) return ArrayList()
return items.map { i ->
return items.mapNotNull { i ->
val innerDiv = i.selectFirst("> div.result")
val href = fixUrl(i.attr("href"))
val img = fixUrl(innerDiv.selectFirst("> div.imgkz > img").attr("src"))
val title = innerDiv.selectFirst("> div.titleresults").text()
val img = fixUrl(innerDiv?.selectFirst("> div.imgkz > img")?.attr("src") ?: return@mapNotNull null)
val title = innerDiv.selectFirst("> div.titleresults")?.text() ?: return@mapNotNull null
if (getIsMovie(href)) {
MovieSearchResponse(
@ -244,12 +245,13 @@ class DubbedAnimeProvider : MainAPI() {
} else {
val response = app.get(url).text
val document = Jsoup.parse(response)
val title = document.selectFirst("h4").text()
val title = document.selectFirst("h4")!!.text()
val descriptHeader = document.selectFirst("div.animeDescript")
val descript = descriptHeader.selectFirst("> p").text()
val year = descriptHeader.selectFirst("> div.distatsx > div.sroverd").text()
.replace("Released: ", "")
.toIntOrNull()
val descript = descriptHeader?.selectFirst("> p")?.text()
val year = descriptHeader?.selectFirst("> div.distatsx > div.sroverd")
?.text()
?.replace("Released: ", "")
?.toIntOrNull()
val episodes = document.select("a.epibloks").map {
val epTitle = it.selectFirst("> div.inwel > span.isgrxx")?.text()

View file

@ -116,7 +116,8 @@ class GogoanimeProvider : MainAPI() {
val encryptRequestData = if (isUsingAdaptiveData) {
// Only fetch the document if necessary
val realDocument = document ?: app.get(iframeUrl).document
val dataEncrypted = realDocument.select("script[data-name='episode']").attr("data-value")
val dataEncrypted =
realDocument.select("script[data-name='episode']").attr("data-value")
val headers = cryptoHandler(dataEncrypted, foundIv, foundKey, false)
"id=$encryptedId&alias=$id&" + headers.substringAfter("&")
} else {
@ -246,17 +247,17 @@ class GogoanimeProvider : MainAPI() {
val html = app.get(link).text
val doc = Jsoup.parse(html)
val episodes = doc.select(""".last_episodes li""").map {
val episodes = doc.select(""".last_episodes li""").mapNotNull {
AnimeSearchResponse(
it.selectFirst(".name").text().replace(" (Dub)", ""),
fixUrl(it.selectFirst(".name > a").attr("href")),
it.selectFirst(".name")?.text()?.replace(" (Dub)", "") ?: return@mapNotNull null,
fixUrl(it.selectFirst(".name > a")?.attr("href") ?: return@mapNotNull null),
this.name,
TvType.Anime,
it.selectFirst("img").attr("src"),
it.selectFirst("img")?.attr("src"),
it.selectFirst(".released")?.text()?.split(":")?.getOrNull(1)?.trim()
?.toIntOrNull(),
if (it.selectFirst(".name").text()
.contains("Dub")
if (it.selectFirst(".name")?.text()
?.contains("Dub") == true
) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(
DubStatus.Subbed
),
@ -282,8 +283,8 @@ class GogoanimeProvider : MainAPI() {
val doc = Jsoup.parse(html)
val animeBody = doc.selectFirst(".anime_info_body_bg")
val title = animeBody.selectFirst("h1").text()
val poster = animeBody.selectFirst("img").attr("src")
val title = animeBody?.selectFirst("h1")!!.text()
val poster = animeBody.selectFirst("img")?.attr("src")
var description: String? = null
val genre = ArrayList<String>()
var year: Int? = null
@ -292,7 +293,7 @@ class GogoanimeProvider : MainAPI() {
var type: String? = null
animeBody.select("p.type").forEach { pType ->
when (pType.selectFirst("span").text().trim()) {
when (pType.selectFirst("span")?.text()?.trim()) {
"Plot Summary:" -> {
description = pType.text().replace("Plot Summary:", "").trim()
}
@ -316,13 +317,13 @@ class GogoanimeProvider : MainAPI() {
}
}
val animeId = doc.selectFirst("#movie_id").attr("value")
val animeId = doc.selectFirst("#movie_id")!!.attr("value")
val params = mapOf("ep_start" to "0", "ep_end" to "2000", "id" to animeId)
val episodes = app.get(episodeloadApi, params = params).document.select("a").map {
Episode(
fixUrl(it.attr("href").trim()),
"Episode " + it.selectFirst(".name").text().replace("EP", "").trim()
"Episode " + it.selectFirst(".name")?.text()?.replace("EP", "")?.trim()
)
}.reversed()
@ -357,7 +358,7 @@ class GogoanimeProvider : MainAPI() {
private suspend fun extractVideos(uri: String, callback: (ExtractorLink) -> Unit) {
val doc = app.get(uri).document
val iframe = fixUrlNull(doc.selectFirst("div.play-video > iframe").attr("src")) ?: return
val iframe = fixUrlNull(doc.selectFirst("div.play-video > iframe")?.attr("src")) ?: return
argamap(
{

View file

@ -20,31 +20,35 @@ class KawaiifuProvider : MainAPI() {
val soup = Jsoup.parse(resp)
items.add(HomePageList("Latest Updates", soup.select(".today-update .item").map {
val title = it.selectFirst("img").attr("alt")
items.add(HomePageList("Latest Updates", soup.select(".today-update .item").mapNotNull {
val title = it.selectFirst("img")?.attr("alt")
AnimeSearchResponse(
title,
it.selectFirst("a").attr("href"),
title ?: return@mapNotNull null,
it.selectFirst("a")?.attr("href") ?: return@mapNotNull null,
this.name,
TvType.Anime,
it.selectFirst("img").attr("src"),
it.selectFirst("h4 > a").attr("href").split("-").last().toIntOrNull(),
if (title.contains("(DUB)")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(DubStatus.Subbed),
it.selectFirst("img")?.attr("src"),
it.selectFirst("h4 > a")?.attr("href")?.split("-")?.last()?.toIntOrNull(),
if (title.contains("(DUB)")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(
DubStatus.Subbed
),
)
}))
for (section in soup.select(".section")) {
try {
val title = section.selectFirst(".title").text()
val anime = section.select(".list-film > .item").map { ani ->
val animTitle = ani.selectFirst("img").attr("alt")
val title = section.selectFirst(".title")!!.text()
val anime = section.select(".list-film > .item").mapNotNull { ani ->
val animTitle = ani.selectFirst("img")?.attr("alt")
AnimeSearchResponse(
animTitle,
ani.selectFirst("a").attr("href"),
animTitle ?: return@mapNotNull null,
ani.selectFirst("a")?.attr("href") ?: return@mapNotNull null,
this.name,
TvType.Anime,
ani.selectFirst("img").attr("src"),
ani.selectFirst(".vl-chil-date").text().toIntOrNull(),
if (animTitle.contains("(DUB)")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(DubStatus.Subbed),
ani.selectFirst("img")?.attr("src"),
ani.selectFirst(".vl-chil-date")?.text()?.toIntOrNull(),
if (animTitle.contains("(DUB)")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(
DubStatus.Subbed
),
)
}
items.add(HomePageList(title, anime))
@ -63,11 +67,11 @@ class KawaiifuProvider : MainAPI() {
val html = app.get(link).text
val soup = Jsoup.parse(html)
return ArrayList(soup.select(".item").map {
val year = it.selectFirst("h4 > a").attr("href").split("-").last().toIntOrNull()
val title = it.selectFirst("img").attr("alt")
val poster = it.selectFirst("img").attr("src")
val uri = it.selectFirst("a").attr("href")
return ArrayList(soup.select(".item").mapNotNull {
val year = it.selectFirst("h4 > a")?.attr("href")?.split("-")?.last()?.toIntOrNull()
val title = it.selectFirst("img")?.attr("alt") ?: return@mapNotNull null
val poster = it.selectFirst("img")?.attr("src")
val uri = it.selectFirst("a")?.attr("href") ?: return@mapNotNull null
AnimeSearchResponse(
title,
uri,
@ -84,22 +88,26 @@ class KawaiifuProvider : MainAPI() {
val html = app.get(url).text
val soup = Jsoup.parse(html)
val title = soup.selectFirst(".title").text()
val title = soup.selectFirst(".title")!!.text()
val tags = soup.select(".table a[href*=\"/tag/\"]").map { tag -> tag.text() }
val description = soup.select(".sub-desc p")
.filter { it.select("strong").isEmpty() && it.select("iframe").isEmpty() }.joinToString("\n") { it.text() }
.filter { it.select("strong").isEmpty() && it.select("iframe").isEmpty() }
.joinToString("\n") { it.text() }
val year = url.split("/").filter { it.contains("-") }[0].split("-")[1].toIntOrNull()
val episodesLink = soup.selectFirst("a[href*=\".html-episode\"]").attr("href") ?: throw ErrorLoadingException("Error getting episode list")
val episodesLink = soup.selectFirst("a[href*=\".html-episode\"]")?.attr("href")
?: throw ErrorLoadingException("Error getting episode list")
val episodes = Jsoup.parse(
app.get(episodesLink).text
).selectFirst(".list-ep").select("li").map {
).selectFirst(".list-ep")?.select("li")?.map {
Episode(
it.selectFirst("a").attr("href"),
if (it.text().trim().toIntOrNull() != null) "Episode ${it.text().trim()}" else it.text().trim()
it.selectFirst("a")!!.attr("href"),
if (it.text().trim().toIntOrNull() != null) "Episode ${
it.text().trim()
}" else it.text().trim()
)
}
val poster = soup.selectFirst("a.thumb > img").attr("src")
val poster = soup.selectFirst("a.thumb > img")?.attr("src")
return newAnimeLoadResponse(title, url, TvType.Anime) {
this.year = year
@ -119,11 +127,13 @@ class KawaiifuProvider : MainAPI() {
val htmlSource = app.get(data).text
val soupa = Jsoup.parse(htmlSource)
val episodeNum = if (data.contains("ep=")) data.split("ep=")[1].split("&")[0].toIntOrNull() else null
val episodeNum =
if (data.contains("ep=")) data.split("ep=")[1].split("&")[0].toIntOrNull() else null
val servers = soupa.select(".list-server").map {
val serverName = it.selectFirst(".server-name").text()
val episodes = it.select(".list-ep > li > a").map { episode -> Pair(episode.attr("href"), episode.text()) }
val serverName = it.selectFirst(".server-name")!!.text()
val episodes = it.select(".list-ep > li > a")
.map { episode -> Pair(episode.attr("href"), episode.text()) }
val episode = if (episodeNum == null) episodes[0] else episodes.mapNotNull { ep ->
if ((if (ep.first.contains("ep=")) ep.first.split("ep=")[1].split("&")[0].toIntOrNull() else null) == episodeNum) {
ep

View file

@ -50,12 +50,12 @@ class MonoschinosProvider : MainAPI() {
HomePageList(
"Capítulos actualizados",
app.get(mainUrl, timeout = 120).document.select(".col-6").map {
val title = it.selectFirst("p.animetitles").text()
val poster = it.selectFirst(".animeimghv").attr("data-src")
val title = it.selectFirst("p.animetitles")!!.text()
val poster = it.selectFirst(".animeimghv")!!.attr("data-src")
val epRegex = Regex("episodio-(\\d+)")
val url = it.selectFirst("a").attr("href").replace("ver/", "anime/")
val url = it.selectFirst("a")?.attr("href")!!.replace("ver/", "anime/")
.replace(epRegex, "sub-espanol")
val epNum = it.selectFirst(".positioning h5").text().toIntOrNull()
val epNum = it.selectFirst(".positioning h5")?.text()?.toIntOrNull()
newAnimeSearchResponse(title, url) {
this.posterUrl = fixUrl(poster)
addDubStatus(getDubStatus(title), epNum)
@ -66,9 +66,9 @@ class MonoschinosProvider : MainAPI() {
for (i in urls) {
try {
val home = app.get(i.first, timeout = 120).document.select(".col-6").map {
val title = it.selectFirst(".seristitles").text()
val poster = it.selectFirst("img.animemainimg").attr("src")
newAnimeSearchResponse(title, fixUrl(it.selectFirst("a").attr("href"))) {
val title = it.selectFirst(".seristitles")!!.text()
val poster = it.selectFirst("img.animemainimg")!!.attr("src")
newAnimeSearchResponse(title, fixUrl(it.selectFirst("a")!!.attr("href"))) {
this.posterUrl = fixUrl(poster)
addDubStatus(getDubStatus(title))
}
@ -87,9 +87,9 @@ class MonoschinosProvider : MainAPI() {
override suspend fun search(query: String): ArrayList<SearchResponse> {
val search =
app.get("$mainUrl/buscar?q=$query", timeout = 120).document.select(".col-6").map {
val title = it.selectFirst(".seristitles").text()
val href = fixUrl(it.selectFirst("a").attr("href"))
val image = it.selectFirst("img.animemainimg").attr("src")
val title = it.selectFirst(".seristitles")!!.text()
val href = fixUrl(it.selectFirst("a")!!.attr("href"))
val image = it.selectFirst("img.animemainimg")!!.attr("src")
AnimeSearchResponse(
title,
href,
@ -107,10 +107,10 @@ class MonoschinosProvider : MainAPI() {
override suspend fun load(url: String): LoadResponse {
val doc = app.get(url, timeout = 120).document
val poster = doc.selectFirst(".chapterpic img").attr("src")
val title = doc.selectFirst(".chapterdetails h1").text()
val type = doc.selectFirst("div.chapterdetls2").text()
val description = doc.selectFirst("p.textComplete").text().replace("Ver menos", "")
val poster = doc.selectFirst(".chapterpic img")!!.attr("src")
val title = doc.selectFirst(".chapterdetails h1")!!.text()
val type = doc.selectFirst("div.chapterdetls2")!!.text()
val description = doc.selectFirst("p.textComplete")!!.text().replace("Ver menos", "")
val genres = doc.select(".breadcrumb-item a").map { it.text() }
val status = when (doc.selectFirst("button.btn1")?.text()) {
"Estreno" -> ShowStatus.Ongoing
@ -118,9 +118,9 @@ class MonoschinosProvider : MainAPI() {
else -> null
}
val episodes = doc.select("div.col-item").map {
val name = it.selectFirst("p.animetitles").text()
val link = it.selectFirst("a").attr("href")
val epThumb = it.selectFirst(".animeimghv").attr("data-src")
val name = it.selectFirst("p.animetitles")!!.text()
val link = it.selectFirst("a")!!.attr("href")
val epThumb = it.selectFirst(".animeimghv")!!.attr("data-src")
Episode(link, name, posterUrl = epThumb)
}
return newAnimeLoadResponse(title, url, getType(type)) {

View file

@ -45,11 +45,11 @@ class NineAnimeProvider : MainAPI() {
val home = Jsoup.parse(
app.get(
url
).mapped<Response>().html
).parsed<Response>().html
).select("ul.anime-list li").map {
val title = it.selectFirst("a.name").text()
val link = it.selectFirst("a").attr("href")
val poster = it.selectFirst("a.poster img").attr("src")
val title = it.selectFirst("a.name")!!.text()
val link = it.selectFirst("a")!!.attr("href")
val poster = it.selectFirst("a.poster img")!!.attr("src")
newAnimeSearchResponse(title, link) {
this.posterUrl = poster
@ -173,11 +173,11 @@ class NineAnimeProvider : MainAPI() {
val url = "$mainUrl/filter?sort=title%3Aasc&keyword=$query"
return app.get(url).document.select("ul.anime-list li").mapNotNull {
val title = it.selectFirst("a.name").text()
val title = it.selectFirst("a.name")!!.text()
val href =
fixUrlNull(it.selectFirst("a").attr("href"))?.replace(Regex("(\\?ep=(\\d+)\$)"), "")
fixUrlNull(it.selectFirst("a")!!.attr("href"))?.replace(Regex("(\\?ep=(\\d+)\$)"), "")
?: return@mapNotNull null
val image = it.selectFirst("a.poster img").attr("src")
val image = it.selectFirst("a.poster img")!!.attr("src")
AnimeSearchResponse(
title,
href,
@ -199,26 +199,26 @@ class NineAnimeProvider : MainAPI() {
override suspend fun load(url: String): LoadResponse? {
val validUrl = url.replace("https://9anime.to", mainUrl)
val doc = app.get(validUrl).document
val animeid = doc.selectFirst("div.player-wrapper.watchpage").attr("data-id") ?: return null
val animeid = doc.selectFirst("div.player-wrapper.watchpage")!!.attr("data-id") ?: return null
val animeidencoded = encode(getVrf(animeid) ?: return null)
val poster = doc.selectFirst("aside.main div.thumb div img").attr("src")
val title = doc.selectFirst(".info .title").text()
val description = doc.selectFirst("div.info p").text().replace("Ver menos", "").trim()
val poster = doc.selectFirst("aside.main div.thumb div img")!!.attr("src")
val title = doc.selectFirst(".info .title")!!.text()
val description = doc.selectFirst("div.info p")!!.text().replace("Ver menos", "").trim()
val episodes = Jsoup.parse(
app.get(
"$mainUrl/ajax/anime/servers?ep=1&id=${animeid}&vrf=$animeidencoded&ep=8&episode=&token="
).mapped<Response>().html
)?.select("ul.episodes li a")?.mapNotNull {
).parsed<Response>().html
).select("ul.episodes li a").mapNotNull {
val link = it?.attr("href") ?: return@mapNotNull null
val name = "Episode ${it.text()}"
Episode(link, name)
} ?: return null
}
val recommendations =
doc.select("div.container aside.main section div.body ul.anime-list li")
?.mapNotNull { element ->
val recTitle = element.select("a.name")?.text() ?: return@mapNotNull null
val image = element.select("a.poster img")?.attr("src")
.mapNotNull { element ->
val recTitle = element.select("a.name").text() ?: return@mapNotNull null
val image = element.select("a.poster img").attr("src")
val recUrl = fixUrl(element.select("a").attr("href"))
newAnimeSearchResponse(recTitle, recUrl) {
this.posterUrl = image
@ -226,7 +226,7 @@ class NineAnimeProvider : MainAPI() {
}
}
val infodoc = doc.selectFirst("div.info .meta .col1").text()
val infodoc = doc.selectFirst("div.info .meta .col1")!!.text()
val tvType = if (infodoc.contains("Movie")) TvType.AnimeMovie else TvType.Anime
val status =
if (infodoc.contains("Completed")) ShowStatus.Completed
@ -264,13 +264,13 @@ class NineAnimeProvider : MainAPI() {
): Boolean {
val document = app.get(data).document
val animeid =
document.selectFirst("div.player-wrapper.watchpage").attr("data-id") ?: return false
document.selectFirst("div.player-wrapper.watchpage")!!.attr("data-id") ?: return false
val animeidencoded = encode(getVrf(animeid) ?: return false)
Jsoup.parse(
app.get(
"$mainUrl/ajax/anime/servers?&id=${animeid}&vrf=$animeidencoded&episode=&token="
).mapped<Response>().html
).parsed<Response>().html
).select("div.body").map { element ->
val jsonregex = Regex("(\\{.+\\}.*$data)")
val servers = jsonregex.find(element.toString())?.value?.replace(

View file

@ -47,6 +47,7 @@ class TenshiProvider : MainAPI() {
override suspend fun getMainPage(): HomePageResponse {
val items = ArrayList<HomePageList>()
val soup = app.get(mainUrl, interceptor = ddosGuardKiller).document
println(soup)
for (section in soup.select("#content > section")) {
try {
if (section.attr("id") == "toplist-tabs") {
@ -58,11 +59,11 @@ class TenshiProvider : MainAPI() {
}
val anime = top.select("li > a").map {
AnimeSearchResponse(
it.selectFirst(".thumb-title").text(),
it.selectFirst(".thumb-title")!!.text(),
fixUrl(it.attr("href")),
this.name,
TvType.Anime,
it.selectFirst("img").attr("src"),
it.selectFirst("img")!!.attr("src"),
null,
EnumSet.of(DubStatus.Subbed),
)
@ -70,14 +71,14 @@ class TenshiProvider : MainAPI() {
items.add(HomePageList(title, anime))
}
} else {
val title = section.selectFirst("h2").text()
val title = section.selectFirst("h2")!!.text()
val anime = section.select("li > a").map {
AnimeSearchResponse(
it.selectFirst(".thumb-title")?.text() ?: "",
fixUrl(it.attr("href")),
this.name,
TvType.Anime,
it.selectFirst("img").attr("src"),
it.selectFirst("img")!!.attr("src"),
null,
EnumSet.of(DubStatus.Subbed),
)
@ -104,7 +105,7 @@ class TenshiProvider : MainAPI() {
val items = soup.select("ul.thumb > li > a")
return items.map {
val href = fixUrl(it.attr("href"))
val img = fixUrl(it.selectFirst("img").attr("src"))
val img = fixUrl(it.selectFirst("img")!!.attr("src"))
val title = it.attr("title")
if (getIsMovie(href, true)) {
MovieSearchResponse(
@ -225,10 +226,10 @@ class TenshiProvider : MainAPI() {
interceptor = ddosGuardKiller
).document
val canonicalTitle = document.selectFirst("header.entry-header > h1.mb-3").text().trim()
val canonicalTitle = document.selectFirst("header.entry-header > h1.mb-3")!!.text().trim()
val episodeNodes = document.select("li[class*=\"episode\"] > a").toMutableList()
val totalEpisodePages = if (document.select(".pagination").size > 0)
document.select(".pagination .page-item a.page-link:not([rel])").last().text()
document.select(".pagination .page-item a.page-link:not([rel])").last()!!.text()
.toIntOrNull()
else 1
@ -283,7 +284,7 @@ class TenshiProvider : MainAPI() {
?.trim()
val pattern = Regex("(\\d{4})")
val yearText = document.selectFirst("li.release-date .value").text()
val yearText = document.selectFirst("li.release-date .value")!!.text()
year = pattern.find(yearText)?.groupValues?.get(1)?.toIntOrNull()
addEpisodes(DubStatus.Subbed, episodes)
@ -310,7 +311,6 @@ class TenshiProvider : MainAPI() {
@JsonProperty("size") val size: Int
)
val sources = ArrayList<ExtractorLink>()
for (source in soup.select("""[aria-labelledby="mirror-dropdown"] > li > a.dropdown-item""")) {
val release = source.text().replace("/", "").trim()
val sourceHTML = app.get(
@ -330,24 +330,24 @@ class TenshiProvider : MainAPI() {
.replace(",}", "}")
.replace(",]", "]")
)
sources.addAll(qualities.map {
ExtractorLink(
this.name,
"${this.name} $release",
fixUrl(it.src),
this.mainUrl,
getQualityFromName("${it.size}"),
headers = getHeaders(
mapOf(),
null,
ddosGuardKiller.savedCookiesMap.get(URI(this.mainUrl).host) ?: mapOf()
).toMap()
qualities.forEach {
callback.invoke(
ExtractorLink(
this.name,
"${this.name} $release",
fixUrl(it.src),
this.mainUrl,
getQualityFromName("${it.size}"),
headers = getHeaders(emptyMap(),
ddosGuardKiller.savedCookiesMap[URI(this.mainUrl).host]
?: emptyMap()
).toMap()
)
)
})
}
}
}
sources.forEach(callback)
return true
}
}

View file

@ -38,11 +38,11 @@ class WatchCartoonOnlineProvider : MainAPI() {
for (item in items) {
val header = item.selectFirst("> div.iccerceve")
val titleHeader = header.selectFirst("> div.aramadabaslik > a")
val title = titleHeader.text()
val titleHeader = header!!.selectFirst("> div.aramadabaslik > a")
val title = titleHeader!!.text()
val href = fixUrl(titleHeader.attr("href"))
val poster = fixUrl(header.selectFirst("> a > img").attr("src"))
val genreText = item.selectFirst("div.cerceve-tur-ve-genre").ownText()
val poster = fixUrl(header.selectFirst("> a > img")!!.attr("src"))
val genreText = item.selectFirst("div.cerceve-tur-ve-genre")!!.ownText()
if (genreText.contains("cartoon")) {
returnValue.add(TvSeriesSearchResponse(title, href, this.name, TvType.Cartoon, poster, null, null))
} else {
@ -76,7 +76,7 @@ class WatchCartoonOnlineProvider : MainAPI() {
for (item in items) {
val titleHeader = item.selectFirst("a")
val title = titleHeader.text()
val title = titleHeader!!.text()
val href = fixUrl(titleHeader.attr("href"))
//val isDubbed = title.contains("dubbed")
//val set: EnumSet<DubStatus> =
@ -103,9 +103,9 @@ class WatchCartoonOnlineProvider : MainAPI() {
val document = Jsoup.parse(response)
return if (!isMovie) {
val title = document.selectFirst("td.vsbaslik > h2").text()
val title = document.selectFirst("td.vsbaslik > h2")!!.text()
val poster = fixUrlNull(document.selectFirst("div#cat-img-desc > div > img")?.attr("src"))
val plot = document.selectFirst("div.iltext").text()
val plot = document.selectFirst("div.iltext")!!.text()
val genres = document.select("div#cat-genre > div.wcobtn > a").map { it.text() }
val episodes = document.select("div#catlist-listview > ul > li > a").reversed().map {
val text = it.text()
@ -152,7 +152,7 @@ class WatchCartoonOnlineProvider : MainAPI() {
val title = document.selectFirst(".iltext .Apple-style-span")?.text().toString()
val b = document.select(".iltext b")
val description = if (b.isNotEmpty()) {
b.last().html().split("<br>")[0]
b.last()!!.html().split("<br>")[0]
} else null
TvSeriesLoadResponse(

View file

@ -50,15 +50,15 @@ class WcoProvider : MainAPI() {
val results = document.select("div.flw-item").map {
val filmPoster = it.selectFirst("> div.film-poster")
val filmDetail = it.selectFirst("> div.film-detail")
val nameHeader = filmDetail.selectFirst("> h3.film-name > a")
val title = nameHeader.text().replace(" (Dub)", "")
val nameHeader = filmDetail!!.selectFirst("> h3.film-name > a")
val title = nameHeader!!.text().replace(" (Dub)", "")
val href =
nameHeader.attr("href").replace("/watch/", "/anime/")
.replace(Regex("-episode-.*"), "/")
val isDub =
filmPoster.selectFirst("> div.film-poster-quality")?.text()?.contains("DUB")
filmPoster!!.selectFirst("> div.film-poster-quality")?.text()?.contains("DUB")
?: false
val poster = filmPoster.selectFirst("> img").attr("data-src")
val poster = filmPoster.selectFirst("> img")!!.attr("data-src")
val set: EnumSet<DubStatus> =
EnumSet.of(if (isDub) DubStatus.Dubbed else DubStatus.Subbed)
AnimeSearchResponse(title, href, this.name, TvType.Anime, poster, null, set)
@ -83,15 +83,15 @@ class WcoProvider : MainAPI() {
val items = soup.select(".film_list-wrap > .flw-item")
if (items.isEmpty()) return ArrayList()
return items.map { i ->
val href = fixAnimeLink(i.selectFirst("a").attr("href"))
val img = fixUrl(i.selectFirst("img").attr("data-src"))
val title = i.selectFirst("img").attr("title")
val href = fixAnimeLink(i.selectFirst("a")!!.attr("href"))
val img = fixUrl(i.selectFirst("img")!!.attr("data-src"))
val title = i.selectFirst("img")!!.attr("title")
val isDub = !i.select(".pick.film-poster-quality").isEmpty()
val year =
i.selectFirst(".film-detail.film-detail-fix > div > span:nth-child(1)").text()
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()
i.selectFirst(".film-detail.film-detail-fix > div > span:nth-child(3)")!!.text()
if (getType(type) == TvType.AnimeMovie) {
MovieSearchResponse(

View file

@ -8,11 +8,11 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
import com.lagradost.cloudstream3.movieproviders.SflixProvider.Companion.extractRabbitStream
import com.lagradost.cloudstream3.movieproviders.SflixProvider.Companion.runSflixExtractorVerifierJob
import com.lagradost.cloudstream3.network.Requests.Companion.await
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import com.lagradost.nicehttp.Requests.Companion.await
import okhttp3.Interceptor
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
@ -141,7 +141,7 @@ class ZoroProvider : MainAPI() {
return document.select(".flw-item").map {
val title = it.selectFirst(".film-detail > .film-name > a")?.attr("title").toString()
val filmPoster = it.selectFirst(".film-poster")
val poster = filmPoster.selectFirst("img")?.attr("data-src")
val poster = filmPoster!!.selectFirst("img")?.attr("data-src")
val episodes = filmPoster.selectFirst("div.rtl > div.tick-eps")?.text()?.let { eps ->
// current episode / max episode
@ -154,7 +154,7 @@ class ZoroProvider : MainAPI() {
val tvType =
getType(it.selectFirst(".film-detail > .fd-infor > .fdi-item")?.text().toString())
val href = fixUrl(it.selectFirst(".film-name a").attr("href"))
val href = fixUrl(it.selectFirst(".film-name a")!!.attr("href"))
newAnimeSearchResponse(title, href, tvType) {
this.posterUrl = poster
@ -327,11 +327,11 @@ class ZoroProvider : MainAPI() {
val servers: List<Pair<DubStatus, String>> = Jsoup.parse(
app.get("$mainUrl/ajax/v2/episode/servers?episodeId=" + data.split("=")[1])
.mapped<Response>().html
.parsed<Response>().html
).select(".server-item[data-type][data-id]").map {
Pair(
if (it.attr("data-type") == "sub") DubStatus.Subbed else DubStatus.Dubbed,
it.attr("data-id")!!
it.attr("data-id")
)
}
@ -344,7 +344,7 @@ class ZoroProvider : MainAPI() {
"$mainUrl/ajax/v2/episode/sources?id=${it.second}"
val extractorLink = app.get(
link,
).mapped<RapidCloudResponse>().link
).parsed<RapidCloudResponse>().link
val hasLoadedExtractorLink =
loadExtractor(extractorLink, "https://rapid-cloud.ru/", callback)

View file

@ -77,7 +77,7 @@ open class WcoStream : ExtractorApi() {
@JsonProperty("media") val media: Media
)
val mapped = app.get(apiLink, headers = mapOf("Referer" to referrer)).mapped<WcoResponse>()
val mapped = app.get(apiLink, headers = mapOf("Referer" to referrer)).parsed<WcoResponse>()
val sources = mutableListOf<ExtractorLink>()
if (mapped.success) {

View file

@ -37,14 +37,14 @@ class AllMoviesForYouProvider : MainAPI() {
for ((name, element) in urls) {
try {
val home = soup.select(element).map {
val title = it.selectFirst("h2.title").text()
val link = it.selectFirst("a").attr("href")
val title = it.selectFirst("h2.title")!!.text()
val link = it.selectFirst("a")!!.attr("href")
TvSeriesSearchResponse(
title,
link,
this.name,
TvType.Movie,
fixUrl(it.selectFirst("figure img").attr("data-src")),
fixUrl(it.selectFirst("figure img")!!.attr("data-src")),
null,
null,
)
@ -66,8 +66,8 @@ class AllMoviesForYouProvider : MainAPI() {
val items = document.select("ul.MovieList > li > article > a")
return items.map { item ->
val href = item.attr("href")
val title = item.selectFirst("> h2.Title").text()
val img = fixUrl(item.selectFirst("> div.Image > figure > img").attr("data-src"))
val title = item.selectFirst("> h2.Title")!!.text()
val img = fixUrl(item.selectFirst("> div.Image > figure > img")!!.attr("data-src"))
val type = getType(href)
if (type == TvType.Movie) {
MovieSearchResponse(title, href, this.name, type, img, null)
@ -108,12 +108,12 @@ class AllMoviesForYouProvider : MainAPI() {
val document = app.get(url).document
val title = document.selectFirst("h1.Title").text()
val descipt = document.selectFirst("div.Description > p").text()
val title = document.selectFirst("h1.Title")!!.text()
val descipt = document.selectFirst("div.Description > p")!!.text()
val rating =
document.selectFirst("div.Vote > div.post-ratings > span")?.text()?.toRatingInt()
val year = document.selectFirst("span.Date")?.text()
val duration = document.selectFirst("span.Time").text()
val duration = document.selectFirst("span.Time")!!.text()
val backgroundPoster =
fixUrlNull(document.selectFirst("div.Image > figure > img")?.attr("data-src"))
@ -140,7 +140,7 @@ class AllMoviesForYouProvider : MainAPI() {
val epNum = episode.selectFirst("> td > span.Num")?.text()?.toIntOrNull()
val poster = episode.selectFirst("> td.MvTbImg > a > img")?.attr("data-src")
val aName = episode.selectFirst("> td.MvTbTtl > a")
val name = aName.text()
val name = aName!!.text()
val href = aName.attr("href")
val date = episode.selectFirst("> td.MvTbTtl > span")?.text()

View file

@ -32,16 +32,16 @@ open class BflixProvider : MainAPI() {
)
for ((name, element) in testa) try {
val test = soup.select(element).map {
val title = it.selectFirst("h3 a").text()
val link = fixUrl(it.selectFirst("a").attr("href"))
val qualityInfo = it.selectFirst("div.quality").text()
val title = it.selectFirst("h3 a")!!.text()
val link = fixUrl(it.selectFirst("a")!!.attr("href"))
val qualityInfo = it.selectFirst("div.quality")!!.text()
val quality = getQualityFromString(qualityInfo)
TvSeriesSearchResponse(
title,
link,
this.name,
if (link.contains("/movie/")) TvType.Movie else TvType.TvSeries,
it.selectFirst("a.poster img").attr("src"),
it.selectFirst("a.poster img")!!.attr("src"),
null,
null,
quality = quality
@ -167,11 +167,11 @@ open class BflixProvider : MainAPI() {
val document = Jsoup.parse(html)
return document.select(".filmlist div.item").map {
val title = it.selectFirst("h3 a").text()
val href = fixUrl(it.selectFirst("a").attr("href"))
val image = it.selectFirst("a.poster img").attr("src")
val title = it.selectFirst("h3 a")!!.text()
val href = fixUrl(it.selectFirst("a")!!.attr("href"))
val image = it.selectFirst("a.poster img")!!.attr("src")
val isMovie = href.contains("/movie/")
val qualityInfo = it.selectFirst("div.quality").text()
val qualityInfo = it.selectFirst("div.quality")!!.text()
val quality = getQualityFromString(qualityInfo)
if (isMovie) {
@ -205,33 +205,33 @@ open class BflixProvider : MainAPI() {
override suspend fun load(url: String): LoadResponse? {
val soup = app.get(url).document
val movieid = soup.selectFirst("div#watch").attr("data-id")
val movieid = soup.selectFirst("div#watch")!!.attr("data-id")
val movieidencoded = encode(getVrf(movieid) ?: return null)
val title = soup.selectFirst("div.info h1").text()
val title = soup.selectFirst("div.info h1")!!.text()
val description = soup.selectFirst(".info .desc")?.text()?.trim()
val poster: String? = try {
soup.selectFirst("img.poster").attr("src")
soup.selectFirst("img.poster")!!.attr("src")
} catch (e: Exception) {
soup.selectFirst(".info .poster img").attr("src")
soup.selectFirst(".info .poster img")!!.attr("src")
}
val tags = soup.select("div.info .meta div:contains(Genre) a").map { it.text() }
val episodes = Jsoup.parse(
app.get(
"$mainUrl/ajax/film/servers?id=$movieid&vrf=$movieidencoded"
).mapped<Response>().html
).parsed<Response>().html
).select("div.episode").map {
val a = it.selectFirst("a")
val href = fixUrl(a.attr("href"))
val extraData = a.attr("data-kname")?.let { str ->
val href = fixUrl(a!!.attr("href"))
val extraData = a.attr("data-kname").let { str ->
str.split("-").mapNotNull { subStr -> subStr.toIntOrNull() }
}
val isValid = extraData?.size == 2
val episode = if (isValid) extraData?.getOrNull(1) else null
val season = if (isValid) extraData?.getOrNull(0) else null
val isValid = extraData.size == 2
val episode = if (isValid) extraData.getOrNull(1) else null
val season = if (isValid) extraData.getOrNull(0) else null
val eptitle = it.selectFirst(".episode a span.name").text()
val secondtitle = it.selectFirst(".episode a span").text()
val eptitle = it.selectFirst(".episode a span.name")!!.text()
val secondtitle = it.selectFirst(".episode a span")!!.text()
.replace(Regex("(Episode (\\d+):|Episode (\\d+)-|Episode (\\d+))"),"") ?: ""
Episode(
href,
@ -329,7 +329,7 @@ open class BflixProvider : MainAPI() {
): Boolean {
val soup = app.get(data).document
val movieid = encode(soup.selectFirst("div#watch").attr("data-id") ?: return false)
val movieid = encode(soup.selectFirst("div#watch")?.attr("data-id") ?: return false)
val movieidencoded = encode(getVrf(movieid!!) ?: return false)
Jsoup.parse(
parseJson<Response>(

View file

@ -31,14 +31,14 @@ class CinecalidadProvider:MainAPI() {
try {
val soup = app.get(url).document
val home = soup.select(".item.movies").map {
val title = it.selectFirst("div.in_title").text()
val link = it.selectFirst("a").attr("href")
val title = it.selectFirst("div.in_title")!!.text()
val link = it.selectFirst("a")!!.attr("href")
TvSeriesSearchResponse(
title,
link,
this.name,
if (link.contains("/ver-pelicula/")) TvType.Movie else TvType.TvSeries,
it.selectFirst(".poster.custom img").attr("data-src"),
it.selectFirst(".poster.custom img")!!.attr("data-src"),
null,
null,
)
@ -59,9 +59,9 @@ class CinecalidadProvider:MainAPI() {
val document = app.get(url).document
return document.select("article").map {
val title = it.selectFirst("div.in_title").text()
val href = it.selectFirst("a").attr("href")
val image = it.selectFirst(".poster.custom img").attr("data-src")
val title = it.selectFirst("div.in_title")!!.text()
val href = it.selectFirst("a")!!.attr("href")
val image = it.selectFirst(".poster.custom img")!!.attr("data-src")
val isMovie = href.contains("/ver-pelicula/")
if (isMovie) {
@ -91,14 +91,14 @@ class CinecalidadProvider:MainAPI() {
override suspend fun load(url: String): LoadResponse? {
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("div.single_left table tbody tr td 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 href = li.selectFirst("a").attr("href")
val epThumb = li.selectFirst("img.lazy").attr("data-src")
val name = li.selectFirst(".episodiotitle a").text()
val seasonid = li.selectFirst(".numerando").text().replace(Regex("(S|E)"),"").let { str ->
val href = li.selectFirst("a")!!.attr("href")
val epThumb = li.selectFirst("img.lazy")!!.attr("data-src")
val name = li.selectFirst(".episodiotitle a")!!.text()
val seasonid = li.selectFirst(".numerando")!!.text().replace(Regex("(S|E)"),"").let { str ->
str.split("-").mapNotNull { subStr -> subStr.toIntOrNull() }
}
val isValid = seasonid.size == 2
@ -182,7 +182,7 @@ class CinecalidadProvider:MainAPI() {
"Sec-Fetch-Site" to "same-origin",
"Sec-Fetch-User" to "?1",
),
allowRedirects = false).response.headers.values("location").apmap { extractedurl ->
allowRedirects = false).okhttpResponse.headers.values("location").apmap { extractedurl ->
if (extractedurl.contains("cinestart")) {
loadExtractor(extractedurl, mainUrl, callback)
}
@ -221,7 +221,7 @@ class CinecalidadProvider:MainAPI() {
"Sec-Fetch-Site" to "same-origin",
"Sec-Fetch-User" to "?1",
),
allowRedirects = false).response.headers.values("location").apmap { extractedurl ->
allowRedirects = false).okhttpResponse.headers.values("location").apmap { extractedurl ->
if (extractedurl.contains("cinestart")) {
loadExtractor(extractedurl, mainUrl, callback)
}
@ -238,7 +238,7 @@ class CinecalidadProvider:MainAPI() {
val validsub = docsub.text
if (validsub.contains("Subtítulo") || validsub.contains("Forzados")) {
val langregex = Regex("(Subtítulo.*\$|Forzados.*\$)")
val langdoc = linksub.selectFirst("div.titulo h3").text()
val langdoc = linksub.selectFirst("div.titulo h3")!!.text()
val reallang = langregex.find(langdoc)?.destructured?.component1()
linksub.select("a.link").apmap {
val sublink = if (data.contains("serie") || data.contains("episodio")) "${data}${it.attr("href")}"

View file

@ -30,9 +30,9 @@ class CuevanaProvider : MainAPI() {
"Series",
app.get("$mainUrl/serie", timeout = 120).document.select("section.home-series li")
.map {
val title = it.selectFirst("h2.Title").text()
val poster = it.selectFirst("img.lazy").attr("data-src")
val url = it.selectFirst("a").attr("href")
val title = it.selectFirst("h2.Title")!!.text()
val poster = it.selectFirst("img.lazy")!!.attr("data-src")
val url = it.selectFirst("a")!!.attr("href")
TvSeriesSearchResponse(
title,
url,
@ -48,14 +48,14 @@ class CuevanaProvider : MainAPI() {
try {
val soup = app.get(url).document
val home = soup.select("section li.xxx.TPostMv").map {
val title = it.selectFirst("h2.Title").text()
val link = it.selectFirst("a").attr("href")
val title = it.selectFirst("h2.Title")!!.text()
val link = it.selectFirst("a")!!.attr("href")
TvSeriesSearchResponse(
title,
link,
this.name,
if (link.contains("/pelicula/")) TvType.Movie else TvType.TvSeries,
it.selectFirst("img.lazy").attr("data-src"),
it.selectFirst("img.lazy")!!.attr("data-src"),
null,
null,
)
@ -76,9 +76,9 @@ class CuevanaProvider : MainAPI() {
val document = app.get(url).document
return document.select("li.xxx.TPostMv").map {
val title = it.selectFirst("h2.Title").text()
val href = it.selectFirst("a").attr("href")
val image = it.selectFirst("img.lazy").attr("data-src")
val title = it.selectFirst("h2.Title")!!.text()
val href = it.selectFirst("a")!!.attr("href")
val image = it.selectFirst("img.lazy")!!.attr("data-src")
val isSerie = href.contains("/serie/")
if (isSerie) {
@ -106,9 +106,9 @@ class CuevanaProvider : MainAPI() {
override suspend fun load(url: String): LoadResponse? {
val soup = app.get(url, timeout = 120).document
val title = soup.selectFirst("h1.Title").text()
val title = soup.selectFirst("h1.Title")!!.text()
val description = soup.selectFirst(".Description p")?.text()?.trim()
val poster: String? = soup.selectFirst(".movtv-info div.Image img").attr("data-src")
val poster: String? = soup.selectFirst(".movtv-info div.Image img")!!.attr("data-src")
val year1 = soup.selectFirst("footer p.meta").toString()
val yearRegex = Regex("<span>(\\d+)</span>")
val yearf =
@ -117,9 +117,9 @@ class CuevanaProvider : MainAPI() {
val episodes = soup.select(".all-episodes li.TPostMv article").map { li ->
val href = li.select("a").attr("href")
val epThumb =
li.selectFirst("div.Image img").attr("data-src") ?: li.selectFirst("img.lazy")
li.selectFirst("div.Image img")?.attr("data-src") ?: li.selectFirst("img.lazy")!!
.attr("data-srcc")
val seasonid = li.selectFirst("span.Year").text().let { str ->
val seasonid = li.selectFirst("span.Year")!!.text().let { str ->
str.split("x").mapNotNull { subStr -> subStr.toIntOrNull() }
}
val isValid = seasonid.size == 2
@ -255,7 +255,7 @@ class CuevanaProvider : MainAPI() {
"Sec-Fetch-Site" to "same-origin",
),
data = mapOf(Pair("url", tomkey))
).response.headers.values("location").apmap { loc ->
).okhttpResponse.headers.values("location").apmap { loc ->
if (loc.contains("goto_ddh.php")) {
val gotoregex =
Regex("(\\/\\/api.cuevana3.me\\/ir\\/goto_ddh.php\\?h=[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
@ -280,7 +280,7 @@ class CuevanaProvider : MainAPI() {
"Sec-Fetch-Site" to "same-origin",
),
data = mapOf(Pair("url", gotolink))
).response.headers.values("location").apmap { golink ->
).okhttpResponse.headers.values("location").apmap { golink ->
loadExtractor(golink, data, callback)
}
}
@ -310,7 +310,7 @@ class CuevanaProvider : MainAPI() {
"Sec-Fetch-User" to "?1",
),
data = mapOf(Pair("h", inlink))
).response.headers.values("location").apmap { link ->
).okhttpResponse.headers.values("location").apmap { link ->
loadExtractor(link, data, callback)
}
}

View file

@ -52,12 +52,12 @@ class DoramasYTProvider : MainAPI() {
HomePageList(
"Capítulos actualizados",
app.get(mainUrl, timeout = 120).document.select(".col-6").map {
val title = it.selectFirst("p").text()
val poster = it.selectFirst(".chapter img").attr("src")
val title = it.selectFirst("p")!!.text()
val poster = it.selectFirst(".chapter img")!!.attr("src")
val epRegex = Regex("episodio-(\\d+)")
val url = it.selectFirst("a").attr("href").replace("ver/", "dorama/")
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()
newAnimeSearchResponse(title,url) {
this.posterUrl = fixUrl(poster)
addDubStatus(getDubStatus(title), epNum)
@ -68,9 +68,9 @@ class DoramasYTProvider : MainAPI() {
for (i in urls) {
try {
val home = app.get(i.first, timeout = 120).document.select(".col-6").map {
val title = it.selectFirst(".animedtls p").text()
val poster = it.selectFirst(".anithumb img").attr("src")
newAnimeSearchResponse(title, fixUrl(it.selectFirst("a").attr("href"))) {
val title = it.selectFirst(".animedtls p")!!.text()
val poster = it.selectFirst(".anithumb img")!!.attr("src")
newAnimeSearchResponse(title, fixUrl(it.selectFirst("a")!!.attr("href"))) {
this.posterUrl = fixUrl(poster)
addDubStatus(getDubStatus(title))
}
@ -88,9 +88,9 @@ class DoramasYTProvider : MainAPI() {
override suspend fun search(query: String): List<SearchResponse> {
return app.get("$mainUrl/buscar?q=$query", timeout = 120).document.select(".col-6").map {
val title = it.selectFirst(".animedtls p").text()
val href = it.selectFirst("a").attr("href")
val image = it.selectFirst(".animes img").attr("src")
val title = it.selectFirst(".animedtls p")!!.text()
val href = it.selectFirst("a")!!.attr("href")
val image = it.selectFirst(".animes img")!!.attr("src")
AnimeSearchResponse(
title,
href,
@ -107,10 +107,10 @@ class DoramasYTProvider : MainAPI() {
override suspend fun load(url: String): LoadResponse {
val doc = app.get(url, timeout = 120).document
val poster = doc.selectFirst("div.flimimg img.img1").attr("src")
val title = doc.selectFirst("h1").text()
val type = doc.selectFirst("h4").text()
val description = doc.selectFirst("p.textComplete").text().replace("Ver menos", "")
val poster = doc.selectFirst("div.flimimg img.img1")!!.attr("src")
val title = doc.selectFirst("h1")!!.text()
val type = doc.selectFirst("h4")!!.text()
val description = doc.selectFirst("p.textComplete")!!.text().replace("Ver menos", "")
val genres = doc.select(".nobel a").map { it.text() }
val status = when (doc.selectFirst(".state h6")?.text()) {
"Estreno" -> ShowStatus.Ongoing
@ -118,9 +118,9 @@ class DoramasYTProvider : MainAPI() {
else -> null
}
val episodes = doc.select(".heromain .col-item").map {
val name = it.selectFirst(".dtlsflim p").text()
val link = it.selectFirst("a").attr("href")
val epThumb = it.selectFirst(".flimimg img.img1").attr("src")
val name = it.selectFirst(".dtlsflim p")!!.text()
val link = it.selectFirst("a")!!.attr("href")
val epThumb = it.selectFirst(".flimimg img.img1")!!.attr("src")
Episode(link, name, posterUrl = epThumb)
}
return newAnimeLoadResponse(title, url, getType(type)) {

View file

@ -46,7 +46,7 @@ class EgyBestProvider : MainAPI() {
val pages = arrayListOf<HomePageList>()
doc.select("#mainLoad div.mbox").apmap {
val name = it.select(".bdb.pda > strong").text()
if (it.select(".movie").first().attr("href").contains("season-(.....)|ep-(.....)".toRegex())) return@apmap
if (it.select(".movie").first()?.attr("href")?.contains("season-(.....)|ep-(.....)".toRegex()) == true) return@apmap
val list = arrayListOf<SearchResponse>()
it.select(".movie").map { element ->
list.add(element.toSearchResponse()!!)
@ -87,16 +87,16 @@ class EgyBestProvider : MainAPI() {
it.text().contains("النوع")
}?.select("a")?.map { it.text() }
val actors = doc.select("div.cast_list .cast_item")?.mapNotNull {
val actors = doc.select("div.cast_list .cast_item").mapNotNull {
val name = it.selectFirst("div > a > img")?.attr("alt") ?: return@mapNotNull null
val image = it.selectFirst("div > a > img")?.attr("src") ?: return@mapNotNull null
val roleString = it.selectFirst("div > span").text()
val roleString = it.selectFirst("div > span")!!.text()
val mainActor = Actor(name, image)
ActorData(actor = mainActor, roleString = roleString)
}
return if (isMovie) {
val recommendations = doc.select(".movies_small .movie")?.mapNotNull { element ->
val recommendations = doc.select(".movies_small .movie").mapNotNull { element ->
element.toSearchResponse()
}

View file

@ -30,14 +30,14 @@ class EntrepeliculasyseriesProvider:MainAPI() {
try {
val soup = app.get(url).document
val home = soup.select("ul.list-movie li").map {
val title = it.selectFirst("a.link-title h2").text()
val link = it.selectFirst("a").attr("href")
val title = it.selectFirst("a.link-title h2")!!.text()
val link = it.selectFirst("a")!!.attr("href")
TvSeriesSearchResponse(
title,
link,
this.name,
if (link.contains("/pelicula/")) TvType.Movie else TvType.TvSeries,
it.selectFirst("a.poster img").attr("src"),
it.selectFirst("a.poster img")!!.attr("src"),
null,
null,
)
@ -58,9 +58,9 @@ class EntrepeliculasyseriesProvider:MainAPI() {
val document = app.get(url).document
return document.select("li.xxx.TPostMv").map {
val title = it.selectFirst("h2.Title").text()
val href = it.selectFirst("a").attr("href")
val image = it.selectFirst("img.lazy").attr("data-src")
val title = it.selectFirst("h2.Title")!!.text()
val href = it.selectFirst("a")!!.attr("href")
val image = it.selectFirst("img.lazy")!!.attr("data-src")
val isMovie = href.contains("/pelicula/")
if (isMovie) {
@ -90,13 +90,13 @@ class EntrepeliculasyseriesProvider:MainAPI() {
override suspend fun load(url: String): LoadResponse? {
val soup = app.get(url, timeout = 120).document
val title = soup.selectFirst("h1.title-post").text()
val title = soup.selectFirst("h1.title-post")!!.text()
val description = soup.selectFirst("p.text-content:nth-child(3)")?.text()?.trim()
val poster: String? = soup.selectFirst("article.TPost img.lazy").attr("data-src")
val poster: String? = soup.selectFirst("article.TPost img.lazy")!!.attr("data-src")
val episodes = soup.select(".TPostMv article").map { li ->
val href = (li.select("a") ?: li.select(".C a") ?: li.select("article a")).attr("href")
val epThumb = li.selectFirst("div.Image img").attr("data-src")
val seasonid = li.selectFirst("span.Year").text().let { str ->
val epThumb = li.selectFirst("div.Image img")!!.attr("data-src")
val seasonid = li.selectFirst("span.Year")!!.text().let { str ->
str.split("x").mapNotNull { subStr -> subStr.toIntOrNull() }
}
val isValid = seasonid.size == 2
@ -169,7 +169,7 @@ class EntrepeliculasyseriesProvider:MainAPI() {
//params = mapOf(Pair("h", postkey)),
data = mapOf(Pair("h", postkey)),
allowRedirects = false
).response.headers.values("location").apmap {
).okhttpResponse.headers.values("location").apmap {
loadExtractor(it, data, callback)
}
}

View file

@ -24,7 +24,7 @@ class FilmanProvider : MainAPI() {
val lists = document.select(".item-list,.series-list")
val categories = ArrayList<HomePageList>()
for (l in lists) {
val title = l.parent().select("h3").text()
val title = l.parent()!!.select("h3").text()
val items = l.select(".poster").map { i ->
val name = i.select("a[href]").attr("title")
val href = i.select("a[href]").attr("href")
@ -63,8 +63,8 @@ class FilmanProvider : MainAPI() {
fun getVideos(type: TvType, items: Elements): List<SearchResponse> {
return items.map { i ->
val href = i.attr("href")
val img = i.selectFirst("> img").attr("src").replace("/thumb/", "/big/")
val name = i.selectFirst(".title").text()
val img = i.selectFirst("> img")!!.attr("src").replace("/thumb/", "/big/")
val name = i.selectFirst(".title")!!.text()
if (type === TvType.TvSeries) {
TvSeriesSearchResponse(
name,
@ -95,7 +95,7 @@ class FilmanProvider : MainAPI() {
if (episodesElements.isEmpty()) {
return MovieLoadResponse(title, url, name, TvType.Movie, data, posterUrl, year, plot)
}
title = document.selectFirst(".info").parent().select("h2").text()
title = document.selectFirst(".info")?.parent()?.select("h2")?.text() ?: ""
val episodes = episodesElements.mapNotNull { episode ->
val e = episode.text()
val regex = Regex("""\[s(\d{1,3})e(\d{1,3})]""").find(e) ?: return@mapNotNull null
@ -130,7 +130,7 @@ class FilmanProvider : MainAPI() {
app.get(data).document.select("#links").first()
else Jsoup.parse(data)
document.select(".link-to-video")?.apmap { item ->
document?.select(".link-to-video")?.apmap { item ->
val decoded = base64Decode(item.select("a").attr("data-iframe"))
val link = mapper.readValue<LinkElement>(decoded).src
loadExtractor(link, null, callback)

View file

@ -23,9 +23,9 @@ class HDMProvider : MainAPI() {
return items.map { i ->
val href = i.attr("href")
val data = i.selectFirst("> div.item")
val img = data.selectFirst("> img").attr("src")
val name = data.selectFirst("> div.movie-details").text()
val data = i.selectFirst("> div.item")!!
val img = data.selectFirst("> img")!!.attr("src")
val name = data.selectFirst("> div.movie-details")!!.text()
MovieSearchResponse(name, href, this.name, TvType.Movie, img, null)
}
}
@ -57,9 +57,9 @@ class HDMProvider : MainAPI() {
val response = app.get(url).text
val document = Jsoup.parse(response)
val title = document.selectFirst("h2.movieTitle")?.text() ?: throw ErrorLoadingException("No Data Found")
val poster = document.selectFirst("div.post-thumbnail > img").attr("src")
val descript = document.selectFirst("div.synopsis > p").text()
val year = document.select("div.movieInfoAll > div.row > div.col-md-6")?.get(1)?.selectFirst("> p > a")?.text()
val poster = document.selectFirst("div.post-thumbnail > img")!!.attr("src")
val descript = document.selectFirst("div.synopsis > p")!!.text()
val year = document.select("div.movieInfoAll > div.row > div.col-md-6").getOrNull(1)?.selectFirst("> p > a")?.text()
?.toIntOrNull()
val data = "src/player/\\?v=(.*?)\"".toRegex().find(response)?.groupValues?.get(1) ?: return null

View file

@ -56,10 +56,10 @@ class IHaveNoTvProvider : MainAPI() {
res.selectFirst("a[href][title]")
}
val year = Regex("""•?\s+(\d{4})\s+•""").find(
res.selectFirst(".episodeMeta").text()
res.selectFirst(".episodeMeta")!!.text()
)?.destructured?.component1()?.toIntOrNull()
val title = aTag.attr("title")
val title = aTag!!.attr("title")
val href = fixUrl(aTag.attr("href"))
searchResults[href] = TvSeriesSearchResponse(
title,
@ -98,11 +98,11 @@ class IHaveNoTvProvider : MainAPI() {
}
val year =
Regex("""•?\s+(\d{4})\s+•""").find(
res.selectFirst(".episodeMeta").text()
res.selectFirst(".episodeMeta")!!.text()
)?.destructured?.component1()
?.toIntOrNull()
val title = aTag.attr("title")
val title = aTag!!.attr("title")
val href = fixUrl(aTag.attr("href"))
searchResults[href] = TvSeriesSearchResponse(
title,
@ -126,7 +126,7 @@ class IHaveNoTvProvider : MainAPI() {
val container = soup.selectFirst(".container-fluid h1")?.parent()
val title = if (isSeries) {
container?.selectFirst("h1")?.text()?.split("")?.firstOrNull().toString()
} else soup.selectFirst(".videoDetails").selectFirst("strong")?.text().toString()
} else soup.selectFirst(".videoDetails")!!.selectFirst("strong")?.text().toString()
val description = if (isSeries) {
container?.selectFirst("p")?.text()
} else {
@ -138,11 +138,11 @@ class IHaveNoTvProvider : MainAPI() {
val episodes = if (isSeries) {
container?.select(".episode")?.map { ep ->
val thumb = ep.selectFirst("img").attr("src")
val thumb = ep.selectFirst("img")!!.attr("src")
val epLink = fixUrl(ep.selectFirst("a[title]").attr("href"))
val epLink = fixUrl(ep.selectFirst("a[title]")!!.attr("href"))
val (season, epNum) = if (ep.selectFirst(".episodeMeta > strong") != null &&
ep.selectFirst(".episodeMeta > strong").html().contains("S")
ep.selectFirst(".episodeMeta > strong")!!.html().contains("S")
) {
val split = ep.selectFirst(".episodeMeta > strong")?.text()?.split("E")
Pair(
@ -152,14 +152,14 @@ class IHaveNoTvProvider : MainAPI() {
} else Pair<Int?, Int?>(null, null)
year = Regex("""•?\s+(\d{4})\s+•""").find(
ep.selectFirst(".episodeMeta").text()
ep.selectFirst(".episodeMeta")!!.text()
)?.destructured?.component1()?.toIntOrNull()
categories.addAll(
ep.select(".episodeMeta > a[href*=\"/category/\"]").map { it.text().trim() })
newEpisode(epLink) {
this.name = ep.selectFirst("a[title]").attr("title")
this.name = ep.selectFirst("a[title]")!!.attr("title")
this.season = season
this.episode = epNum
this.posterUrl = thumb
@ -173,13 +173,13 @@ class IHaveNoTvProvider : MainAPI() {
this.name,
TvType.Movie,
url,
soup.selectFirst("[rel=\"image_src\"]").attr("href"),
soup.selectFirst("[rel=\"image_src\"]")!!.attr("href"),
Regex("""•?\s+(\d{4})\s+•""").find(
soup.selectFirst(".videoDetails").text()
soup.selectFirst(".videoDetails")!!.text()
)?.destructured?.component1()?.toIntOrNull(),
description,
null,
soup.selectFirst(".videoDetails").select("a[href*=\"/category/\"]")
soup.selectFirst(".videoDetails")!!.select("a[href*=\"/category/\"]")
.map { it.text().trim() }
))
}

View file

@ -33,17 +33,14 @@ class KdramaHoodProvider : MainAPI() {
// Hardcoded homepage cause of site implementation
// Recently added
val recentlyInner = doc.selectFirst("div.peliculas")
val recentlyAddedTitle = recentlyInner.selectFirst("h1")?.text() ?: "Recently Added"
val recentlyAdded = recentlyInner.select("div.item_2.items > div.fit.item")?.mapNotNull {
if (it == null) {
return@mapNotNull null
}
val recentlyAddedTitle = recentlyInner!!.selectFirst("h1")?.text() ?: "Recently Added"
val recentlyAdded = recentlyInner.select("div.item_2.items > div.fit.item").mapNotNull {
val innerA = it.select("div.image > a") ?: return@mapNotNull null
val link = fixUrlNull(innerA.attr("href")) ?: return@mapNotNull null
val image = fixUrlNull(innerA.select("img")?.attr("src"))
val image = fixUrlNull(innerA.select("img").attr("src"))
val innerData = it.selectFirst("div.data")
val title = innerData.selectFirst("h1")?.text() ?: return@mapNotNull null
val title = innerData!!.selectFirst("h1")?.text() ?: return@mapNotNull null
val year = try {
val yearText = innerData.selectFirst("span.titulo_o")
?.text()?.takeLast(11)?.trim()?.take(4) ?: ""
@ -61,7 +58,7 @@ class KdramaHoodProvider : MainAPI() {
posterUrl = image,
year = year
)
}?.distinctBy { it.url } ?: listOf()
}.distinctBy { it.url } ?: listOf()
home.add(HomePageList(recentlyAddedTitle, recentlyAdded))
return HomePageResponse(home.filter { it.list.isNotEmpty() })
}
@ -102,15 +99,15 @@ class KdramaHoodProvider : MainAPI() {
val title = inner?.selectFirst("h1")?.text() ?: ""
val poster = fixUrlNull(doc.selectFirst("meta[property=og:image]")?.attr("content")) ?: ""
//Log.i(this.name, "Result => (poster) ${poster}")
val info = inner.selectFirst("div#info")
val descript = inner?.selectFirst("div.contenidotv > div > p")?.text()
val info = inner!!.selectFirst("div#info")
val descript = inner.selectFirst("div.contenidotv > div > p")?.text()
val year = try {
val startLink = "https://kdramahood.com/drama-release-year/"
var res: Int? = null
info.select("div.metadatac")?.forEach {
info?.select("div.metadatac")?.forEach {
if (res != null) { return@forEach }
if (it == null) { return@forEach }
val yearLink = it.select("a")?.attr("href") ?: return@forEach
val yearLink = it.select("a").attr("href") ?: return@forEach
if (yearLink.startsWith(startLink)) {
res = yearLink.substring(startLink.length).replace("/", "").toIntOrNull()
}
@ -118,13 +115,13 @@ class KdramaHoodProvider : MainAPI() {
res
} catch (e: Exception) { null }
val recs = doc.select("div.sidebartv > div.tvitemrel")?.mapNotNull {
val recs = doc.select("div.sidebartv > div.tvitemrel").mapNotNull {
val a = it?.select("a") ?: return@mapNotNull null
val aUrl = fixUrlNull(a.attr("href")) ?: return@mapNotNull null
val aImg = a.select("img")
val aCover = fixUrlNull(aImg?.attr("src")) ?: fixUrlNull(aImg?.attr("data-src"))
val aCover = fixUrlNull(aImg.attr("src")) ?: fixUrlNull(aImg.attr("data-src"))
val aNameYear = a.select("div.datatvrel") ?: return@mapNotNull null
val aName = aNameYear.select("h4")?.text() ?: aImg?.attr("alt") ?: return@mapNotNull null
val aName = aNameYear.select("h4").text() ?: aImg.attr("alt") ?: return@mapNotNull null
val aYear = aName.trim().takeLast(5).removeSuffix(")").toIntOrNull()
MovieSearchResponse(
url = aUrl,
@ -137,7 +134,7 @@ class KdramaHoodProvider : MainAPI() {
}
// Episodes Links
val episodeList = inner?.select("ul.episodios > li")?.mapNotNull { ep ->
val episodeList = inner.select("ul.episodios > li")?.mapNotNull { ep ->
//Log.i(this.name, "Result => (ep) ${ep}")
val listOfLinks = mutableListOf<String>()
val count = ep.select("div.numerando")?.text()?.toIntOrNull() ?: 0
@ -181,10 +178,10 @@ class KdramaHoodProvider : MainAPI() {
posterUrl = poster,
date = null
)
} ?: listOf()
}
//If there's only 1 episode, consider it a movie.
if (episodeList.size == 1) {
if (episodeList?.size == 1) {
return MovieLoadResponse(
name = title,
url = url,
@ -202,7 +199,7 @@ class KdramaHoodProvider : MainAPI() {
url = url,
apiName = this.name,
type = TvType.AsianDrama,
episodes = episodeList.reversed(),
episodes = episodeList?.reversed() ?: emptyList(),
posterUrl = poster,
year = year,
plot = descript,

View file

@ -118,10 +118,10 @@ class LookMovieProvider : MainAPI() {
val items = document.select("div.flex-wrap-movielist > div.movie-item-style-1")
return items.map { item ->
val titleHolder = item.selectFirst("> div.mv-item-infor > h6 > a")
val href = fixUrl(titleHolder.attr("href"))
val href = fixUrl(titleHolder!!.attr("href"))
val name = titleHolder.text()
val posterHolder = item.selectFirst("> div.image__placeholder > a")
val poster = posterHolder.selectFirst("> img")?.attr("data-src")
val poster = posterHolder!!.selectFirst("> img")?.attr("data-src")
val year = posterHolder.selectFirst("> p.year")?.text()?.toIntOrNull()
if (isMovie) {
MovieSearchResponse(
@ -199,17 +199,17 @@ class LookMovieProvider : MainAPI() {
val isMovie = url.contains("/movies/")
val watchHeader = document.selectFirst("div.watch-heading")
val nameHeader = watchHeader.selectFirst("> h1.bd-hd")
val year = nameHeader.selectFirst("> span")?.text()?.toIntOrNull()
val nameHeader = watchHeader!!.selectFirst("> h1.bd-hd")
val year = nameHeader!!.selectFirst("> span")?.text()?.toIntOrNull()
val title = nameHeader.ownText()
val rating =
parseRating(watchHeader.selectFirst("> div.movie-rate > div.rate > p > span").text())
parseRating(watchHeader.selectFirst("> div.movie-rate > div.rate > p > span")!!.text())
val imgElement = document.selectFirst("div.movie-img > p.movie__poster")
val img = imgElement?.attr("style")
var poster = if (img.isNullOrEmpty()) null else "url\\((.*?)\\)".toRegex()
.find(img)?.groupValues?.get(1)
if (poster.isNullOrEmpty()) poster = imgElement?.attr("data-background-image")
val descript = document.selectFirst("p.description-short").text()
val descript = document.selectFirst("p.description-short")!!.text()
val id = "${if (isMovie) "id_movie" else "id_show"}:(.*?),".toRegex()
.find(response)?.groupValues?.get(1)
?.replace(" ", "")

View file

@ -88,11 +88,11 @@ class MeloMovieProvider : MainAPI() {
private fun serializeData(element: Element): List<MeloMovieProvider.MeloMovieLink> {
val eps = element.select("> tbody > tr")
val parsed = eps.map {
val parsed = eps.mapNotNull {
try {
val tds = it.select("> td")
val name = tds[if (tds.size == 5) 1 else 0].text()
val url = fixUrl(tds.last().selectFirst("> a").attr("data-lnk").replace(" ", "%20"))
val url = fixUrl(tds.last()!!.selectFirst("> a")!!.attr("data-lnk").replace(" ", "%20"))
MeloMovieLink(name, url)
} catch (e: Exception) {
MeloMovieLink("", "")
@ -133,13 +133,13 @@ class MeloMovieProvider : MainAPI() {
val imdbUrl = findUsingRegex("var imdb = \"(.*?)\"")
val document = Jsoup.parse(response)
val poster = document.selectFirst("img.img-fluid").attr("src")
val poster = document.selectFirst("img.img-fluid")!!.attr("src")
val type = findUsingRegex("var posttype = ([0-9]*)")?.toInt() ?: return null
val titleInfo = document.selectFirst("div.movie_detail_title > div > div > h1")
val title = titleInfo.ownText()
val title = titleInfo!!.ownText()
val year =
titleInfo.selectFirst("> a")?.text()?.replace("(", "")?.replace(")", "")?.toIntOrNull()
val plot = document.selectFirst("div.col-lg-12 > p").text()
val plot = document.selectFirst("div.col-lg-12 > p")!!.text()
if (type == 1) { // MOVIE
val serialize = document.selectFirst("table.accordion__list")
@ -161,12 +161,12 @@ class MeloMovieProvider : MainAPI() {
?: throw ErrorLoadingException("No episodes found")
for (s in seasons) {
val season =
s.selectFirst("> div.card-header > button > span").text()
s.selectFirst("> div.card-header > button > span")!!.text()
.replace("Season: ", "").toIntOrNull()
val localEpisodes = s.select("> div.collapse > div > div > div.accordion__card")
for (e in localEpisodes) {
val episode =
e.selectFirst("> div.card-header > button > span").text()
e.selectFirst("> div.card-header > button > span")!!.text()
.replace("Episode: ", "").toIntOrNull()
val links =
e.selectFirst("> div.collapse > div > table.accordion__list") ?: continue

View file

@ -153,7 +153,7 @@ class MyCimaProvider : MainAPI() {
if (moreButton.isNotEmpty()) {
val n = doc.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a").size
val totals =
doc.select("div.Episodes--Seasons--Episodes a").first().text().getIntFromText()
doc.select("div.Episodes--Seasons--Episodes a").first()!!.text().getIntFromText()
val mEPS = arrayListOf(
n,
n + 40,
@ -229,7 +229,7 @@ class MyCimaProvider : MainAPI() {
val n =
seasonsite.select("div.Seasons--Episodes div.Episodes--Seasons--Episodes a").size
val totals =
seasonsite.select("div.Episodes--Seasons--Episodes a").first().text()
seasonsite.select("div.Episodes--Seasons--Episodes a").first()!!.text()
.getIntFromText()
val mEPS = arrayListOf(
n,

View file

@ -37,13 +37,13 @@ class NginxProvider : MainAPI() {
val isMovie = !nfoUrl.contains("tvshow.nfo")
val title = metadataDocument.selectFirst("title").text()
val title = metadataDocument.selectFirst("title")!!.text()
val description = metadataDocument.selectFirst("plot").text()
val description = metadataDocument.selectFirst("plot")!!.text()
if (isMovie) {
val poster = metadataDocument.selectFirst("thumb").text()
val trailer = metadataDocument.select("trailer")?.mapNotNull {
val poster = metadataDocument.selectFirst("thumb")!!.text()
val trailer = metadataDocument.select("trailer").mapNotNull {
it?.text()?.replace(
"plugin://plugin.video.youtube/play/?video_id=",
"https://www.youtube.com/watch?v="
@ -125,7 +125,7 @@ class NginxProvider : MainAPI() {
val epNum = nfoDocument.selectFirst("episode")?.text()?.toIntOrNull()
val poster =
seasonString + episode.attr("href").replace(".nfo", "-thumb.jpg")
val name = nfoDocument.selectFirst("title").text()
val name = nfoDocument.selectFirst("title")!!.text()
// val seasonInt = nfoDocument.selectFirst("season").text().toIntOrNull()
val date = nfoDocument.selectFirst("aired")?.text()
val plot = nfoDocument.selectFirst("plot")?.text()

View file

@ -29,14 +29,14 @@ class PeliSmartProvider: MainAPI() {
try {
val soup = app.get(url).document
val home = soup.select(".description-off").map {
val title = it.selectFirst("h3.entry-title a").text()
val link = it.selectFirst("a").attr("href")
val title = it.selectFirst("h3.entry-title a")!!.text()
val link = it.selectFirst("a")!!.attr("href")
TvSeriesSearchResponse(
title,
link,
this.name,
if (link.contains("pelicula")) TvType.Movie else TvType.TvSeries,
it.selectFirst("div img").attr("src"),
it.selectFirst("div img")!!.attr("src"),
null,
null,
)
@ -57,9 +57,9 @@ class PeliSmartProvider: MainAPI() {
val document = app.get(url).document
return document.select(".description-off").map {
val title = it.selectFirst("h3.entry-title a").text()
val href = it.selectFirst("a").attr("href")
val image = it.selectFirst("div img").attr("src")
val title = it.selectFirst("h3.entry-title a")!!.text()
val href = it.selectFirst("a")!!.attr("href")
val image = it.selectFirst("div img")!!.attr("src")
val isMovie = href.contains("pelicula")
if (isMovie) {
@ -88,13 +88,13 @@ class PeliSmartProvider: MainAPI() {
override suspend fun load(url: String): LoadResponse? {
val soup = app.get(url, timeout = 120).document
val title = soup.selectFirst(".wpb_wrapper h1").text()
val title = soup.selectFirst(".wpb_wrapper h1")!!.text()
val description = soup.selectFirst("div.wpb_wrapper p")?.text()?.trim()
val poster: String? = soup.selectFirst(".vc_single_image-img").attr("src")
val poster: String? = soup.selectFirst(".vc_single_image-img")!!.attr("src")
val episodes = soup.select("div.vc_tta-panel-body div a").map { li ->
val href = li.selectFirst("a").attr("href")
val href = li.selectFirst("a")!!.attr("href")
val preregex = Regex("(\\d+)\\. ")
val name = li.selectFirst("a").text().replace(preregex,"")
val name = li.selectFirst("a")!!.text().replace(preregex,"")
val regextest = Regex("(temporada-(\\d+)-capitulo-(\\d+)|temporada-(\\d+)-episodio-(\\d+))")
val test = regextest.find(href)?.destructured?.component1()?.replace(Regex("(temporada-|-)"),"")
val seasonid = test.let { str ->

View file

@ -28,14 +28,14 @@ class PelisflixProvider : MainAPI() {
try {
val soup = app.get(i.first).document
val home = soup.select("article.TPost.B").map {
val title = it.selectFirst("h2.title").text()
val link = it.selectFirst("a").attr("href")
val title = it.selectFirst("h2.title")!!.text()
val link = it.selectFirst("a")!!.attr("href")
TvSeriesSearchResponse(
title,
link,
this.name,
TvType.Movie,
it.selectFirst("figure img").attr("data-src"),
it.selectFirst("figure img")!!.attr("data-src"),
null,
null,
)
@ -54,9 +54,9 @@ class PelisflixProvider : MainAPI() {
val url = "$mainUrl/?s=$query"
val doc = app.get(url).document
return doc.select("article.TPost.B").map {
val href = it.selectFirst("a").attr("href")
val poster = it.selectFirst("figure img").attr("data-src")
val name = it.selectFirst("h2.title").text()
val href = it.selectFirst("a")!!.attr("href")
val poster = it.selectFirst("figure img")!!.attr("data-src")
val name = it.selectFirst("h2.title")!!.text()
val isMovie = href.contains("/pelicula/")
if (isMovie) {
MovieSearchResponse(
@ -86,24 +86,24 @@ class PelisflixProvider : MainAPI() {
val document = app.get(url).document
val title = document.selectFirst("h1.Title").text()
val title = document.selectFirst("h1.Title")!!.text()
val descRegex = Regex("(.Recuerda.*Pelisflix.+)")
val descRegex2 = Regex("(Actualmente.*.)")
val descRegex3 = Regex("(.*Director:.*)")
val descRegex4 = Regex("(.*Actores:.*)")
val descRegex5 = Regex("(Ver.*(\\)|)((\\d+).))")
val descipt = document.selectFirst("div.Description").text().replace(descRegex, "")
val descipt = document.selectFirst("div.Description")!!.text().replace(descRegex, "")
.replace(descRegex2, "").replace(descRegex3, "")
.replace(descRegex4, "").replace(descRegex5, "")
val desc2Regex = Regex("(G(e|é)nero:.*..)")
val descipt2 = document.selectFirst("div.Description").text().replace(desc2Regex, "")
val descipt2 = document.selectFirst("div.Description")!!.text().replace(desc2Regex, "")
val rating =
document.selectFirst("div.rating-content button.like-mov span.vot_cl")?.text()
?.toFloatOrNull()
?.times(0)?.toInt()
val year = document.selectFirst("span.Date")?.text()
val duration =
if (type == TvType.Movie) document.selectFirst(".Container .Container span.Time")
if (type == TvType.Movie) document.selectFirst(".Container .Container span.Time")!!
.text() else null
val postercss = document.selectFirst("head").toString()
val posterRegex =
@ -137,7 +137,7 @@ class PelisflixProvider : MainAPI() {
val epNum = episode.selectFirst("> td > span.Num")?.text()?.toIntOrNull()
val epthumb = episode.selectFirst("img")?.attr("src")
val aName = episode.selectFirst("> td.MvTbTtl > a")
val name = aName.text()
val name = aName!!.text()
val href = aName.attr("href")
val date = episode.selectFirst("> td.MvTbTtl > span")?.text()
episodeList.add(
@ -220,7 +220,7 @@ class PelisflixProvider : MainAPI() {
params = mapOf(Pair("h", postkey)),
data = mapOf(Pair("h", postkey)),
allowRedirects = false
).response.headers.values("location").apmap { link ->
).okhttpResponse.headers.values("location").apmap { link ->
val url1 = link.replace("#bu", "")
loadExtractor(url1, data, callback)
}

View file

@ -67,9 +67,9 @@ class PelisplusHDProvider:MainAPI() {
val document = app.get(url).document
return document.select("a.Posters-link").map {
val title = it.selectFirst(".listing-content p").text()
val href = it.selectFirst("a").attr("href")
val image = it.selectFirst(".Posters-img").attr("src")
val title = it.selectFirst(".listing-content p")!!.text()
val href = it.selectFirst("a")!!.attr("href")
val image = it.selectFirst(".Posters-img")!!.attr("src")
val isMovie = href.contains("/pelicula/")
if (isMovie) {
@ -98,12 +98,12 @@ class PelisplusHDProvider:MainAPI() {
override suspend fun load(url: String): LoadResponse? {
val soup = app.get(url, timeout = 120).document
val title = soup.selectFirst(".m-b-5").text()
val title = soup.selectFirst(".m-b-5")!!.text()
val description = soup.selectFirst("div.text-large")?.text()?.trim()
val poster: String? = soup.selectFirst(".img-fluid").attr("src")
val poster: String? = soup.selectFirst(".img-fluid")!!.attr("src")
val episodes = soup.select("div.tab-pane .btn").map { li ->
val href = li.selectFirst("a").attr("href")
val name = li.selectFirst(".btn-primary.btn-block").text()
val href = li.selectFirst("a")!!.attr("href")
val name = li.selectFirst(".btn-primary.btn-block")!!.text()
val seasonid = href.replace("/capitulo/","-")
.replace(Regex("$mainUrl/.*/.*/temporada/"),"").let { str ->
str.split("-").mapNotNull { subStr -> subStr.toIntOrNull() }
@ -119,7 +119,7 @@ class PelisplusHDProvider:MainAPI() {
)
}
val year = soup.selectFirst(".p-r-15 .text-semibold").text().toIntOrNull()
val year = soup.selectFirst(".p-r-15 .text-semibold")!!.text().toIntOrNull()
val tvType = if (url.contains("/pelicula/")) TvType.Movie else TvType.TvSeries
val tags = soup.select(".p-h-15.text-center a span.font-size-18.text-info.text-semibold")
.map { it?.text()?.trim().toString().replace(", ","") }

View file

@ -44,11 +44,11 @@ open class PelisplusProviderTemplate : MainAPI() {
return ArrayList(soup.select(".listing.items > .video-block").map { li ->
// Selects the href in <a href="...">
val href = fixUrl(li.selectFirst("a").attr("href"))
val poster = fixUrl(li.selectFirst("img").attr("src"))
val href = fixUrl(li.selectFirst("a")!!.attr("href"))
val poster = fixUrl(li.selectFirst("img")!!.attr("src"))
// .text() selects all the text in the element, be careful about doing this while too high up in the html hierarchy
val title = cleanName(li.selectFirst(".name").text())
val title = cleanName(li.selectFirst(".name")!!.text())
// Use get(0) and toIntOrNull() to prevent any possible crashes, [0] or toInt() will error the search on unexpected values.
val year = li.selectFirst(".date")?.text()?.split("-")?.get(0)?.toIntOrNull()
@ -73,13 +73,13 @@ open class PelisplusProviderTemplate : MainAPI() {
val html = app.get(url).text
val soup = Jsoup.parse(html)
val title = cleanName(soup.selectFirst("h1,h2,h3").text())
val title = cleanName(soup.selectFirst("h1,h2,h3")!!.text())
val description = soup.selectFirst(".post-entry")?.text()?.trim()
val poster = soup.selectFirst("head meta[property=og:image]").attr("content")
val poster = soup.selectFirst("head meta[property=og:image]")!!.attr("content")
var year : Int? = null
val episodes = soup.select(".listing.items.lists > .video-block").map { li ->
val href = fixUrl(li.selectFirst("a").attr("href"))
val href = fixUrl(li.selectFirst("a")!!.attr("href"))
val regexseason = Regex("(-[Tt]emporada-(\\d+)-[Cc]apitulo-(\\d+))")
val aaa = regexseason.find(href)?.destructured?.component1()?.replace(Regex("(-[Tt]emporada-|[Cc]apitulo-)"),"")
val seasonid = aaa.let { str ->
@ -88,14 +88,14 @@ open class PelisplusProviderTemplate : MainAPI() {
val isValid = seasonid?.size == 2
val episode = if (isValid) seasonid?.getOrNull(1) else null
val season = if (isValid) seasonid?.getOrNull(0) else null
val epThumb = fixUrl(li.selectFirst("img").attr("src"))
val epDate = li.selectFirst(".meta > .date").text()
val epThumb = fixUrl(li.selectFirst("img")!!.attr("src"))
val epDate = li.selectFirst(".meta > .date")!!.text()
if(year == null) {
year = epDate?.split("-")?.get(0)?.toIntOrNull()
}
newEpisode(li.selectFirst("a").attr("href")) {
newEpisode(li.selectFirst("a")!!.attr("href")) {
this.season = season
this.episode = episode
this.posterUrl = epThumb

View file

@ -29,14 +29,14 @@ class SeriesflixProvider : MainAPI() {
try {
val soup = app.get(i.first).document
val home = soup.select("article.TPost.B").map {
val title = it.selectFirst("h2.title").text()
val link = it.selectFirst("a").attr("href")
val title = it.selectFirst("h2.title")!!.text()
val link = it.selectFirst("a")!!.attr("href")
TvSeriesSearchResponse(
title,
link,
this.name,
TvType.Movie,
it.selectFirst("figure img").attr("src"),
it.selectFirst("figure img")!!.attr("src"),
null,
null,
)
@ -55,9 +55,9 @@ class SeriesflixProvider : MainAPI() {
val url = "$mainUrl/?s=$query"
val doc = app.get(url).document
return doc.select("article.TPost.B").map {
val href = it.selectFirst("a").attr("href")
val poster = it.selectFirst("figure img").attr("src")
val name = it.selectFirst("h2.title").text()
val href = it.selectFirst("a")!!.attr("href")
val poster = it.selectFirst("figure img")!!.attr("src")
val name = it.selectFirst("h2.title")!!.text()
val isMovie = href.contains("/movies/")
if (isMovie) {
MovieSearchResponse(
@ -88,15 +88,15 @@ class SeriesflixProvider : MainAPI() {
val document = app.get(url).document
val title = document.selectFirst("h1.Title").text()
val title = document.selectFirst("h1.Title")!!.text()
val descRegex = Regex("(Recuerda.*Seriesflix.)")
val descipt = document.selectFirst("div.Description > p").text().replace(descRegex, "")
val descipt = document.selectFirst("div.Description > p")!!.text().replace(descRegex, "")
val rating =
document.selectFirst("div.Vote > div.post-ratings > span")?.text()?.toRatingInt()
val year = document.selectFirst("span.Date")?.text()
// ?: does not work
val duration = try {
document.selectFirst("span.Time").text()
document.selectFirst("span.Time")!!.text()
} catch (e: Exception) {
null
}
@ -133,8 +133,8 @@ class SeriesflixProvider : MainAPI() {
val epNum = episode.selectFirst("> td > span.Num")?.text()?.toIntOrNull()
val epthumb = episode.selectFirst("img")?.attr("src")
val aName = episode.selectFirst("> td.MvTbTtl > a")
val name = aName.text()
val href = aName.attr("href")
val name = aName!!.text()
val href = aName!!.attr("href")
val date = episode.selectFirst("> td.MvTbTtl > span")?.text()
episodeList.add(
newEpisode(href) {
@ -215,7 +215,7 @@ class SeriesflixProvider : MainAPI() {
params = mapOf(Pair("h", postkey)),
data = mapOf(Pair("h", postkey)),
allowRedirects = false
).response.headers.values("location").apmap { link ->
).okhttpResponse.headers.values("location").apmap { link ->
val url1 = link.replace("#bu", "")
loadExtractor(url1, data, callback)
}

View file

@ -10,13 +10,13 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addDuration
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.animeproviders.ZoroProvider
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
import com.lagradost.cloudstream3.network.AppResponse
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
import com.lagradost.cloudstream3.utils.getQualityFromName
import com.lagradost.nicehttp.NiceResponse
import kotlinx.coroutines.delay
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
@ -82,7 +82,7 @@ open class SflixProvider : MainAPI() {
val metaInfo = it.select("div.fd-infor > span.fdi-item")
// val rating = metaInfo[0].text()
val quality = getQualityFromString(metaInfo?.getOrNull(1)?.text())
val quality = getQualityFromString(metaInfo.getOrNull(1)?.text())
if (isMovie) {
MovieSearchResponse(
@ -113,9 +113,9 @@ open class SflixProvider : MainAPI() {
val document = app.get(url).document
val details = document.select("div.detail_page-watch")
val img = details?.select("img.film-poster-img")
val posterUrl = img?.attr("src")
val title = img?.attr("title") ?: throw ErrorLoadingException("No Title")
val img = details.select("img.film-poster-img")
val posterUrl = img.attr("src")
val title = img.attr("title") ?: throw ErrorLoadingException("No Title")
/*
val year = Regex("""[Rr]eleased:\s*(\d{4})""").find(
@ -132,7 +132,7 @@ open class SflixProvider : MainAPI() {
val rating = document.selectFirst(".fs-item > .imdb")?.text()?.trim()
?.removePrefix("IMDB:")?.toRatingInt()
document.select("div.elements > .row > div > .row-line")?.forEach { element ->
document.select("div.elements > .row > div > .row-line").forEach { element ->
val type = element?.select(".type")?.text() ?: return@forEach
when {
type.contains("Released") -> {
@ -141,17 +141,17 @@ open class SflixProvider : MainAPI() {
)?.groupValues?.firstOrNull()?.toIntOrNull()
}
type.contains("Genre") -> {
tags = element.select("a")?.mapNotNull { it.text() }
tags = element.select("a").mapNotNull { it.text() }
}
type.contains("Cast") -> {
cast = element.select("a")?.mapNotNull { it.text() }
cast = element.select("a").mapNotNull { it.text() }
}
type.contains("Duration") -> {
duration = duration ?: element.ownText()?.trim()
duration = duration ?: element.ownText().trim()
}
}
}
val plot = details.select("div.description")?.text()?.replace("Overview:", "")?.trim()
val plot = details.select("div.description").text().replace("Overview:", "").trim()
val isMovie = url.contains("/movie/")
@ -164,12 +164,12 @@ open class SflixProvider : MainAPI() {
else dataId
val recommendations =
document.select("div.film_list-wrap > div.flw-item")?.mapNotNull { element ->
document.select("div.film_list-wrap > div.flw-item").mapNotNull { element ->
val titleHeader =
element.select("div.film-detail > .film-name > a") ?: return@mapNotNull null
val recUrl = fixUrlNull(titleHeader.attr("href")) ?: return@mapNotNull null
val recTitle = titleHeader.text() ?: return@mapNotNull null
val poster = element.select("div.film-poster > img")?.attr("data-src")
val poster = element.select("div.film-poster > img").attr("data-src")
MovieSearchResponse(
recTitle,
recUrl,
@ -191,7 +191,7 @@ open class SflixProvider : MainAPI() {
if (sourceId.isNullOrEmpty())
sourceId = element.attr("data-linkid")
if (element.select("span")?.text()?.trim()?.isValidServer() == true) {
if (element.select("span").text().trim().isValidServer()) {
if (sourceId.isNullOrEmpty()) {
fixUrlNull(element.attr("href"))
} else {
@ -222,7 +222,7 @@ open class SflixProvider : MainAPI() {
var seasonItems = seasonsDocument.select("div.dropdown-menu.dropdown-menu-model > a")
if (seasonItems.isNullOrEmpty())
seasonItems = seasonsDocument.select("div.dropdown-menu > a.dropdown-item")
seasonItems?.forEachIndexed { season, element ->
seasonItems.forEachIndexed { season, element ->
val seasonId = element.attr("data-id")
if (seasonId.isNullOrBlank()) return@forEachIndexed
@ -243,7 +243,7 @@ open class SflixProvider : MainAPI() {
episode++
val episodeNum =
(it.select("div.episode-number")?.text()
(it.select("div.episode-number").text()
?: episodeTitle).let { str ->
Regex("""\d+""").find(str)?.groupValues?.firstOrNull()
?.toIntOrNull()
@ -314,7 +314,7 @@ open class SflixProvider : MainAPI() {
// Supported streams, they're identical
app.get(episodesUrl).document.select("a").mapNotNull { element ->
val id = element?.attr("data-id") ?: return@mapNotNull null
if (element.select("span")?.text()?.trim()?.isValidServer() == true) {
if (element.select("span").text().trim().isValidServer()) {
"$prefix.$id".replace("/tv/", "/watch-tv/")
} else {
null
@ -334,7 +334,7 @@ open class SflixProvider : MainAPI() {
val serverId = url.substringAfterLast(".")
val iframeLink =
app.get("${this.mainUrl}/ajax/get_link/$serverId").mapped<IframeJson>().link
app.get("${this.mainUrl}/ajax/get_link/$serverId").parsed<IframeJson>().link
?: return@suspendSafeApiCall
// Some smarter ws11 or w10 selection might be required in the future.
@ -354,7 +354,7 @@ open class SflixProvider : MainAPI() {
private fun Element.toSearchResult(): SearchResponse {
val inner = this.selectFirst("div.film-poster")
val img = inner.select("img")
val img = inner!!.select("img")
val title = img.attr("title")
val posterUrl = img.attr("data-src") ?: img.attr("src")
val href = fixUrl(inner.select("a").attr("href"))
@ -454,11 +454,11 @@ open class SflixProvider : MainAPI() {
* @return the data and if it is new.
* */
private suspend fun getUpdatedData(
response: AppResponse,
response: NiceResponse,
data: PollingData,
baseUrl: String
): Pair<PollingData, Boolean> {
if (!response.response.isSuccessful) {
if (!response.okhttpResponse.isSuccessful) {
return negotiateNewSid(baseUrl)?.let {
it to true
} ?: data to false
@ -688,7 +688,7 @@ open class SflixProvider : MainAPI() {
// "Cache-Control" to "no-cache",
"TE" to "trailers"
)
).mapped<SourceObject>()
).parsed<SourceObject>()
mapped.tracks?.forEach { track ->
track?.toSubtitleFile()?.let { subtitleFile ->

View file

@ -28,14 +28,14 @@ class SoaptwoDayProvider:MainAPI() {
try {
val soup = app.get(url).document
val home = soup.select("div.container div.row div.col-sm-12.col-lg-12 div.row div.col-sm-12.col-lg-12 .col-xs-6").map {
val title = it.selectFirst("h5 a").text()
val link = it.selectFirst("a").attr("href")
val title = it.selectFirst("h5 a")!!.text()
val link = it.selectFirst("a")!!.attr("href")
TvSeriesSearchResponse(
title,
link,
this.name,
TvType.TvSeries,
fixUrl(it.selectFirst("img").attr("src")),
fixUrl(it.selectFirst("img")!!.attr("src")),
null,
null,
)
@ -52,9 +52,9 @@ class SoaptwoDayProvider:MainAPI() {
override suspend fun search(query: String): List<SearchResponse> {
val doc = app.get("$mainUrl/search/keyword/$query").document
return doc.select("div.container div.row div.col-sm-12.col-lg-12 div.row div.col-sm-12.col-lg-12 .col-xs-6").map {
val title = it.selectFirst("h5 a").text()
val image = fixUrl(it.selectFirst("img").attr("src"))
val href = fixUrl(it.selectFirst("a").attr("href"))
val title = it.selectFirst("h5 a")!!.text()
val image = fixUrl(it.selectFirst("img")!!.attr("src"))
val href = fixUrl(it.selectFirst("a")!!.attr("href"))
TvSeriesSearchResponse(
title,
href,
@ -80,34 +80,33 @@ class SoaptwoDayProvider:MainAPI() {
data = link
)
}
val otherInfoBody = soup.select("div.col-sm-8 div.panel-body")?.toString()
val otherInfoBody = soup.select("div.col-sm-8 div.panel-body").toString()
//Fetch casts
val casts = otherInfoBody?.substringAfter("Stars : ")
?.substringBefore("Genre : ")?.let {
Jsoup.parse(it)?.select("a")
}?.mapNotNull {
val castName = it?.text() ?: return@mapNotNull null
ActorData(
Actor(
name = castName
val casts = otherInfoBody.substringAfter("Stars : ")
.substringBefore("Genre : ").let {
Jsoup.parse(it).select("a")
}.mapNotNull {
val castName = it?.text() ?: return@mapNotNull null
ActorData(
Actor(
name = castName
)
)
)
}
}
//Fetch year
val year = otherInfoBody?.substringAfter("<h4>Release : </h4>")
?.substringBefore("<div")?.let {
val year = otherInfoBody.substringAfter("<h4>Release : </h4>")
.substringBefore("<div").let {
//Log.i(this.name, "Result => year string: $it")
Jsoup.parse(it)?.select("p")?.get(1)
Jsoup.parse(it).select("p")[1]
}?.text()?.take(4)?.toIntOrNull()
//Fetch genres
val genre = otherInfoBody?.substringAfter("<h4>Genre : </h4>")
?.substringBefore("<h4>Release : </h4>")?.let {
val genre = otherInfoBody.substringAfter("<h4>Genre : </h4>")
.substringBefore("<h4>Release : </h4>").let {
//Log.i(this.name, "Result => genre string: $it")
Jsoup.parse(it)?.select("a")
}?.mapNotNull { it?.text()?.trim() ?: return@mapNotNull null }
Jsoup.parse(it).select("a")
}.mapNotNull { it?.text()?.trim() ?: return@mapNotNull null }
val tvType = if (episodes.isEmpty()) TvType.Movie else TvType.TvSeries
return when (tvType) {
return when (val tvType = if (episodes.isEmpty()) TvType.Movie else TvType.TvSeries) {
TvType.TvSeries -> {
TvSeriesLoadResponse(
title,
@ -177,9 +176,9 @@ class SoaptwoDayProvider:MainAPI() {
val doc = app.get(data).document
val idplayer = doc.selectFirst("#divU")?.text()
val idplayer2 = doc.selectFirst("#divP")?.text()
val movieid = doc.selectFirst("div.row input#hId").attr("value")
val movieid = doc.selectFirst("div.row input#hId")!!.attr("value")
val tvType = try {
doc.selectFirst(".col-md-5 > div:nth-child(1) > div:nth-child(1) > img").attr("src") ?: ""
doc.selectFirst(".col-md-5 > div:nth-child(1) > div:nth-child(1) > img")!!.attr("src") ?: ""
} catch (e: Exception) {
""
}

View file

@ -224,7 +224,7 @@ class StreamingcommunityProvider : MainAPI() {
val document = app.get(url).document
val films =
document.selectFirst("the-search-page").attr("records-json").replace("&quot;", """"""")
document.selectFirst("the-search-page")!!.attr("records-json").replace("&quot;", """"""")
val searchresults = parseJson<List<VideoElement>>(films)
return searchresults.map { result ->
@ -289,7 +289,7 @@ class StreamingcommunityProvider : MainAPI() {
val year = datajs.releaseDate.substringBefore("-")
val correlatijs = document.selectFirst("slider-title").attr("titles-json")
val correlatijs = document.selectFirst("slider-title")!!.attr("titles-json")
val listacorr = mutableListOf<MovieSearchResponse>()
val correlatidata = parseJson<List<VideoElement>>(correlatijs)
val number : Int = if (correlatidata.size<=15) {correlatidata.size} else correlatidata.size-15
@ -332,7 +332,7 @@ class StreamingcommunityProvider : MainAPI() {
val episodeList = arrayListOf<Episode>()
val episodes =
Html.fromHtml(document.selectFirst("season-select").attr("seasons")).toString()
Html.fromHtml(document.selectFirst("season-select")!!.attr("seasons")).toString()
val jsonEpisodes = parseJson<List<Season>>(episodes)
jsonEpisodes.map { seasons ->
@ -365,7 +365,7 @@ class StreamingcommunityProvider : MainAPI() {
return newTvSeriesLoadResponse(name, url, type, episodeList) {
this.posterUrl = poster
this.year = year.filter { it.isDigit() }.toInt()
this.plot = document.selectFirst("div.plot-wrap > p").text()
this.plot = document.selectFirst("div.plot-wrap > p")!!.text()
this.duration = datajs.runtime?.toInt()
this.rating = (datajs.votes[0].average.toFloatOrNull()?.times(1000))?.toInt()
this.tags = datajs.genres.map { it.name }
@ -377,14 +377,14 @@ class StreamingcommunityProvider : MainAPI() {
} else {
return newMovieLoadResponse(
document.selectFirst("div > div > h1").text(),
document.selectFirst("div > div > h1")!!.text(),
document.select("a.play-hitzone").attr("href"),
type,
document.select("a.play-hitzone").attr("href")
) {
posterUrl = fixUrlNull(poster)
this.year = year.filter { it.isDigit() }.toInt()
this.plot = document.selectFirst("p.plot").text()
this.plot = document.selectFirst("p.plot")!!.text()
this.rating = datajs.votes[0].average.toFloatOrNull()?.times(1000)?.toInt()
this.tags = datajs.genres.map { it.name }
this.duration = datajs.runtime?.toInt()

View file

@ -27,14 +27,14 @@ class TantifilmProvider : MainAPI() {
try {
val soup = app.get(url).document
val home = soup.select("div.media3").map {
val title = it.selectFirst("p").text().substringBefore("(")
val link = it.selectFirst("a").attr("href")
val title = it.selectFirst("p")!!.text().substringBefore("(")
val link = it.selectFirst("a")!!.attr("href")
TvSeriesSearchResponse(
title,
link,
this.name,
TvType.Movie,
it.selectFirst("img").attr("src"),
it.selectFirst("img")!!.attr("src"),
null,
null,
)
@ -54,9 +54,9 @@ class TantifilmProvider : MainAPI() {
val url = "$mainUrl/search/$queryformatted"
val doc = app.get(url).document
return doc.select("div.film.film-2").map {
val href = it.selectFirst("a").attr("href")
val poster = it.selectFirst("img").attr("src")
val name = it.selectFirst("a").text().substringBefore("(")
val href = it.selectFirst("a")!!.attr("href")
val poster = it.selectFirst("img")!!.attr("src")
val name = it.selectFirst("a")!!.text().substringBefore("(")
MovieSearchResponse(
name,
href,
@ -72,30 +72,30 @@ class TantifilmProvider : MainAPI() {
override suspend fun load(url: String): LoadResponse {
val document = app.get(url).document
val type = if (document.selectFirst("div.category-film").text().contains("Serie")
val type = if (document.selectFirst("div.category-film")!!.text().contains("Serie")
.not()
) TvType.Movie else TvType.TvSeries
val title = document.selectFirst("div.title-film-left").text().substringBefore("(")
val title = document.selectFirst("div.title-film-left")!!.text().substringBefore("(")
val descipt = document.select("div.content-left-film > p").map { it.text() }
val rating =
document.selectFirst("div.star-rating.star-rating-f > span > span")
.attr("data-rateit-value")?.toFloatOrNull()
document.selectFirst("div.star-rating.star-rating-f > span > span")!!
.attr("data-rateit-value").toFloatOrNull()
?.times(2857)?.toInt()?.let { minOf(it, 10000) }
var year = document.selectFirst("div.title-film-left").text().substringAfter("(")
var year = document.selectFirst("div.title-film-left")!!.text().substringAfter("(")
.filter { it.isDigit() }
if (year.length > 4) {
year = year.dropLast(4)
year = if (year.length > 4) {
year.dropLast(4)
} else {
year = year
year
}
// ?: does not wor
val poster = document.selectFirst("div.image-right-film > img").attr("src")
val poster = document.selectFirst("div.image-right-film > img")!!.attr("src")
val recomm = document.select("div.mediaWrap.mediaWrapAlt.recomended_videos").map {
val href = it.selectFirst("a").attr("href")
val poster = it.selectFirst("img").attr("src")
val name = it.selectFirst("a").attr("title").substringBeforeLast("(")
val href = it.selectFirst("a")!!.attr("href")
val poster = it.selectFirst("img")!!.attr("src")
val name = it.selectFirst("a")!!.attr("title").substringBeforeLast("(")
MovieSearchResponse(
name,
href,
@ -111,10 +111,10 @@ class TantifilmProvider : MainAPI() {
if (type == TvType.TvSeries) {
val list = ArrayList<Pair<Int, String>>()
val urlvideocontainer = document.selectFirst("iframe").attr("src")
val urlvideocontainer = document.selectFirst("iframe")!!.attr("src")
val videocontainer = app.get(urlvideocontainer).document
videocontainer.select("nav.nav1 > select > option").forEach { element ->
val season = element.text()?.toIntOrNull()
val season = element.text().toIntOrNull()
val href = element.attr("value")
if (season != null && season > 0 && !href.isNullOrBlank()) {
list.add(Pair(season, fixUrl(href)))
@ -130,7 +130,7 @@ class TantifilmProvider : MainAPI() {
if (episodes.isNotEmpty()) {
episodes.forEach { episode ->
val href = episode.attr("value")
val epNum = episode.text()?.toIntOrNull()
val epNum = episode.text().toIntOrNull()
episodeList.add(
Episode(
href,
@ -149,7 +149,7 @@ class TantifilmProvider : MainAPI() {
type,
episodeList,
fixUrlNull(poster),
year?.toIntOrNull(),
year.toIntOrNull(),
descipt[0],
null,
rating,
@ -159,23 +159,21 @@ class TantifilmProvider : MainAPI() {
recomm
)
} else {
val url2 = document.selectFirst("iframe").attr("src")
val url2 = document.selectFirst("iframe")!!.attr("src")
val actorpagelink =
document.select("div.content-left-film > p:nth-child(2) > a").attr("href")
val actorpagelink2 = document.select("div.content-left-film > p > a").attr("href")
val Linkactor: String = if (actorpagelink.isNotEmpty()) {
actorpagelink
} else {
val Linkactor: String = actorpagelink.ifEmpty {
actorpagelink2
}
val actors: List<ActorData>? = if (Linkactor.isNotEmpty()) {
val actorpage = app.get(Linkactor + "cast/").document
actorpage.select("article.membro-cast")?.filter {
actorpage.select("article.membro-cast").filter {
it.selectFirst("img")
?.attr("src") != "https://www.filmtv.it/imgbank/DUMMY/no_portrait.jpg"
}?.mapNotNull { it ->
val name = it.selectFirst("div.info > h3").text()
}.mapNotNull {
val name = it.selectFirst("div.info > h3")!!.text()
val image = it.selectFirst("img")?.attr("src")
val roleString: String = if (it.selectFirst("h2")?.text() == "Regia") {
"Regia"
@ -196,7 +194,7 @@ class TantifilmProvider : MainAPI() {
null
}
val tags: List<String>? = if (descipt.size == 2) {
descipt[0].let { mutableListOf(it.substringBefore(" ")) }
mutableListOf(descipt[0].substringBefore(" "))
} else {
null
}
@ -212,7 +210,7 @@ class TantifilmProvider : MainAPI() {
url2
) {
posterUrl = fixUrlNull(poster)
this.year = year?.toIntOrNull()
this.year = year.toIntOrNull()
this.plot = plot
this.rating = rating
this.recommendations = recomm
@ -235,7 +233,7 @@ class TantifilmProvider : MainAPI() {
doc.select("option").map { fixUrl(it.attr("value")) }.filter { it.contains("label") }
iframe.forEach { id ->
val doc2 = app.get(id).document
val id2 = app.get(doc2.selectFirst("iframe").attr("src")).url
val id2 = app.get(doc2.selectFirst("iframe")!!.attr("src")).url
loadExtractor(id2, data, callback)
}
return true

View file

@ -98,7 +98,7 @@ class TheFlixToProvider : MainAPI() {
override suspend fun getMainPage(): HomePageResponse {
val items = ArrayList<HomePageList>()
val doc = app.get(mainUrl).document
val scriptText = doc.selectFirst("script[type=application/json]").data()
val scriptText = doc.selectFirst("script[type=application/json]")!!.data()
if (scriptText.contains("moviesListTrending")) {
val json = parseJson<HomeJson>(scriptText)
val homePageProps = json.props.pageProps
@ -181,7 +181,7 @@ class TheFlixToProvider : MainAPI() {
)
urls.apmap { url ->
val doc = app.get(url).document
val scriptText = doc.selectFirst("script[type=application/json]").data()
val scriptText = doc.selectFirst("script[type=application/json]")!!.data()
if (scriptText.contains("pageProps")) {
val json = parseJson<SearchJson>(scriptText)
val searchPageProps = json.props.pageProps.mainList
@ -397,7 +397,7 @@ class TheFlixToProvider : MainAPI() {
private suspend fun getLoadMan(url: String): LoadMain {
val og = app.get(url, cookies = latestCookies)
val soup = og.document
val script = soup.selectFirst("script[type=application/json]").data()
val script = soup.selectFirst("script[type=application/json]")!!.data()
return parseJson(script)
}

View file

@ -24,15 +24,15 @@ class VMoveeProvider : MainAPI() {
val details = item.selectFirst("> div.details")
val imgHolder = item.selectFirst("> div.image > div.thumbnail > a")
// val href = imgHolder.attr("href")
val poster = imgHolder.selectFirst("> img").attr("data-lazy-src")
val isTV = imgHolder.selectFirst("> span").text() == "TV"
val poster = imgHolder!!.selectFirst("> img")!!.attr("data-lazy-src")
val isTV = imgHolder.selectFirst("> span")!!.text() == "TV"
if (isTV) continue // no TV support yet
val titleHolder = details.selectFirst("> div.title > a")
val title = titleHolder.text()
val titleHolder = details!!.selectFirst("> div.title > a")
val title = titleHolder!!.text()
val href = titleHolder.attr("href")
val meta = details.selectFirst("> div.meta")
val year = meta.selectFirst("> span.year").text().toIntOrNull()
val year = meta!!.selectFirst("> span.year")!!.text().toIntOrNull()
// val rating = parseRating(meta.selectFirst("> span.rating").text().replace("IMDb ", ""))
// val descript = details.selectFirst("> div.contenido").text()
returnValue.add(
@ -114,10 +114,10 @@ class VMoveeProvider : MainAPI() {
val sheader = document.selectFirst("div.sheader")
val poster = sheader.selectFirst("> div.poster > img").attr("data-lazy-src")
val poster = sheader!!.selectFirst("> div.poster > img")!!.attr("data-lazy-src")
val data = sheader.selectFirst("> div.data")
val title = data.selectFirst("> h1").text()
val descript = document.selectFirst("div#info > div").text()
val title = data!!.selectFirst("> h1")!!.text()
val descript = document.selectFirst("div#info > div")!!.text()
val id = document.select("div.starstruck").attr("data-id")
return MovieLoadResponse(title, url, this.name, TvType.Movie, id, poster, null, descript, null, null)

View file

@ -27,12 +27,12 @@ class VfFilmProvider : MainAPI() {
for (item in items) {
val href = item.attr("href")
val poster = item.selectFirst("> div.Image > figure > img").attr("src")
val poster = item.selectFirst("> div.Image > figure > img")!!.attr("src")
.replace("//image", "https://image")
val name = item.selectFirst("> h3.Title").text()
val name = item.selectFirst("> h3.Title")!!.text()
val year = item.selectFirst("> span.Year").text()?.toIntOrNull()
val year = item.selectFirst("> span.Year")!!.text().toIntOrNull()
returnValue.add(MovieSearchResponse(name, href, this.name, TvType.Movie, poster, year))
}
@ -73,25 +73,25 @@ class VfFilmProvider : MainAPI() {
override suspend fun load(url: String): LoadResponse {
val response = app.get(url).text
val document = Jsoup.parse(response)
val title = document?.selectFirst("div.SubTitle")?.text()
val title = document.selectFirst("div.SubTitle")?.text()
?: throw ErrorLoadingException("Service might be unavailable")
val year = document.select("span.Date").text()?.toIntOrNull()
val year = document.select("span.Date").text().toIntOrNull()
val rating = document.select("span.AAIco-star").text()
// val rating = document.select("span.AAIco-star").text()
val duration = document.select("span.Time").text()?.toIntOrNull()
val duration = document.select("span.Time").text().toIntOrNull()
val poster = document.selectFirst("div.Image > figure > img").attr("src")
val poster = document.selectFirst("div.Image > figure > img")!!.attr("src")
.replace("//image", "https://image")
val descript = document.selectFirst("div.Description > p").text()
val descript = document.selectFirst("div.Description > p")!!.text()
val players = document.select("ul.TPlayerNv > li")
var number_player = 0
var found = false
for (player in players) {
if (player.selectFirst("> span").text() == "Vudeo") {
if (player.selectFirst("> span")!!.text() == "Vudeo") {
found = true
break
} else {

View file

@ -28,15 +28,15 @@ class VfSerieProvider : MainAPI() {
for (item in items) {
val href = item.attr("href")
val poster = item.selectFirst("> div.Image > figure > img").attr("src")
val poster = item.selectFirst("> div.Image > figure > img")!!.attr("src")
.replace("//image", "https://image")
if (poster == "$mainUrl/wp-content/themes/toroplay/img/cnt/noimg-thumbnail.png") { // if the poster is missing (the item is just a redirect to something like https://vf-serie.org/series-tv/)
continue
}
val name = item.selectFirst("> h3.Title").text()
val name = item.selectFirst("> h3.Title")!!.text()
val year = item.selectFirst("> span.Year").text()?.toIntOrNull()
val year = item.selectFirst("> span.Year")!!.text().toIntOrNull()
returnValue.add(
TvSeriesSearchResponse(
@ -74,12 +74,12 @@ class VfSerieProvider : MainAPI() {
val response = app.get(data).text
val document = Jsoup.parse(response)
val players = document.select("ul.TPlayerNv > li")
val trembedUrl = document.selectFirst("div.TPlayerTb > iframe").attr("src")
val trembedUrl = document.selectFirst("div.TPlayerTb > iframe")!!.attr("src")
var numberPlayer = Regex(".*trembed=(.*?)&").find(trembedUrl)?.groupValues?.get(1)!!
.toInt() // the starting trembed number of the first player website, some start at 0 other at 1
var found = false
for (player in players) {
if (player.selectFirst("> span").text() == "Vudeo") {
if (player.selectFirst("> span")!!.text() == "Vudeo") {
found = true
break
} else {
@ -110,21 +110,21 @@ class VfSerieProvider : MainAPI() {
val response = app.get(url).text
val document = Jsoup.parse(response)
val title =
document?.selectFirst(".Title")?.text()?.replace("Regarder Serie ", "")
document.selectFirst(".Title")?.text()?.replace("Regarder Serie ", "")
?.replace(" En Streaming", "")
?: throw ErrorLoadingException("Service might be unavailable")
val year = document.select("span.Date").text()?.toIntOrNull()
val rating = document.select("span.AAIco-star").text()?.toIntOrNull()
val year = document.select("span.Date").text().toIntOrNull()
val rating = document.select("span.AAIco-star").text().toIntOrNull()
//val duration = document.select("span.Time").text()?.toIntOrNull()
val backgroundPoster =
document.selectFirst("div.Image > figure > img").attr("src")
document.selectFirst("div.Image > figure > img")!!.attr("src")
.replace("//image", "https://image")
val descript = document.selectFirst("div.Description > p").text()
val descript = document.selectFirst("div.Description > p")!!.text()
val list = ArrayList<Int>()
@ -149,7 +149,7 @@ class VfSerieProvider : MainAPI() {
?.replace("//image", "https://image")
val aName = episode.selectFirst("> td.MvTbTtl > a")
val date = episode.selectFirst("> td.MvTbTtl > span")?.text()?.toString()
val name = aName.text()
val name = aName!!.text()
val href = aName.attr("href")
episodeList.add(
newEpisode(href) {

View file

@ -104,11 +104,11 @@ open class VidstreamProviderTemplate : MainAPI() {
return ArrayList(soup.select(".listing.items > .video-block").map { li ->
// Selects the href in <a href="...">
val href = fixUrl(li.selectFirst("a").attr("href"))
val href = fixUrl(li.selectFirst("a")!!.attr("href"))
val poster = li.selectFirst("img")?.attr("src")
// .text() selects all the text in the element, be careful about doing this while too high up in the html hierarchy
val title = li.selectFirst(".name").text()
val title = li.selectFirst(".name")!!.text()
// Use get(0) and toIntOrNull() to prevent any possible crashes, [0] or toInt() will error the search on unexpected values.
val year = li.selectFirst(".date")?.text()?.split("-")?.get(0)?.toIntOrNull()
@ -133,7 +133,7 @@ open class VidstreamProviderTemplate : MainAPI() {
val html = app.get(url).text
val soup = Jsoup.parse(html)
var title = soup.selectFirst("h1,h2,h3").text()
var title = soup.selectFirst("h1,h2,h3")!!.text()
title = if (!title.contains("Episode")) title else title.split("Episode")[0].trim()
val description = soup.selectFirst(".post-entry")?.text()?.trim()
@ -143,13 +143,13 @@ open class VidstreamProviderTemplate : MainAPI() {
val episodes =
soup.select(".listing.items.lists > .video-block").withIndex().map { (_, li) ->
val epTitle = if (li.selectFirst(".name") != null)
if (li.selectFirst(".name").text().contains("Episode"))
"Episode " + li.selectFirst(".name").text().split("Episode")[1].trim()
if (li.selectFirst(".name")!!.text().contains("Episode"))
"Episode " + li.selectFirst(".name")!!.text().split("Episode")[1].trim()
else
li.selectFirst(".name").text()
li.selectFirst(".name")!!.text()
else ""
val epThumb = li.selectFirst("img")?.attr("src")
val epDate = li.selectFirst(".meta > .date").text()
val epDate = li.selectFirst(".meta > .date")!!.text()
if (poster == null) {
poster = li.selectFirst("img")?.attr("onerror")?.split("=")?.get(1)
@ -159,9 +159,9 @@ open class VidstreamProviderTemplate : MainAPI() {
val epNum = Regex("""Episode (\d+)""").find(epTitle)?.destructured?.component1()
?.toIntOrNull()
if (year == null) {
year = epDate?.split("-")?.get(0)?.toIntOrNull()
year = epDate.split("-")[0].toIntOrNull()
}
newEpisode(li.selectFirst("a").attr("href")) {
newEpisode(li.selectFirst("a")!!.attr("href")) {
this.episode = epNum
this.posterUrl = epThumb
addDate(epDate)
@ -215,7 +215,7 @@ open class VidstreamProviderTemplate : MainAPI() {
urls.apmap { url ->
val response = app.get(url, timeout = 20).text
val document = Jsoup.parse(response)
document.select("div.main-inner")?.forEach { inner ->
document.select("div.main-inner").forEach { inner ->
// Always trim your text unless you want the risk of spaces at the start or end.
val title = inner.select(".widget-title").text().trim()
val elements = inner.select(".video-block").map {

View file

@ -20,9 +20,9 @@ class FrenchStreamProvider : MainAPI() {
val soup = app.post(link).document
return soup.select("div.short-in.nl").map { li ->
val href = fixUrl(li.selectFirst("a.short-poster").attr("href"))
val href = fixUrl(li.selectFirst("a.short-poster")!!.attr("href"))
val poster = li.selectFirst("img")?.attr("src")
val title = li.selectFirst("> a.short-poster").text().toString().replace(". ", "")
val title = li.selectFirst("> a.short-poster")!!.text().toString().replace(". ", "")
val year = li.selectFirst(".date")?.text()?.split("-")?.get(0)?.toIntOrNull()
if (title.contains(
"saison",
@ -54,24 +54,24 @@ class FrenchStreamProvider : MainAPI() {
override suspend fun load(url: String): LoadResponse {
val soup = app.get(url).document
val title = soup.selectFirst("h1#s-title").text().toString()
val title = soup.selectFirst("h1#s-title")!!.text().toString()
val isMovie = !title.contains("saison", ignoreCase = true)
val description =
soup.selectFirst("div.fdesc").text().toString()
soup.selectFirst("div.fdesc")!!.text().toString()
.split("streaming", ignoreCase = true)[1].replace(" : ", "")
var poster = fixUrlNull(soup.selectFirst("div.fposter > img")?.attr("src"))
val listEpisode = soup.select("div.elink")
if (isMovie) {
val tags = soup.select("ul.flist-col > li")?.getOrNull(1)
val tags = soup.select("ul.flist-col > li").getOrNull(1)
val tagsList = tags?.select("a")
?.mapNotNull { // all the tags like action, thriller ...; unused variable
it?.text()
}
return newMovieLoadResponse(title,url,TvType.Movie,url) {
this.posterUrl = poster
addRating(soup.select("div.fr-count > div")?.text())
this.year = soup.select("ul.flist-col > li")?.getOrNull(2)?.text()?.toIntOrNull()
addRating(soup.select("div.fr-count > div").text())
this.year = soup.select("ul.flist-col > li").getOrNull(2)?.text()?.toIntOrNull()
this.tags = tagsList
this.plot = description
addTrailer(soup.selectFirst("div.fleft > span > a")?.attr("href"))
@ -91,17 +91,16 @@ class FrenchStreamProvider : MainAPI() {
val episodes = episodeList.select("a").map { a ->
val epNum = a.text().split("Episode")[1].trim().toIntOrNull()
val epTitle = if (a.text()?.toString() != null)
if (a.text().contains("Episode")) {
val type = if ("honey" in a.attr("id")) {
"VF"
} else {
"VOSTFR"
}
"Episode " + epNum?.toString() + " en " + type
val epTitle = if (a.text().contains("Episode")) {
val type = if ("honey" in a.attr("id")) {
"VF"
} else {
a.text()
} else ""
"VOSTFR"
}
"Episode " + epNum?.toString() + " en " + type
} else {
a.text()
}
if (poster == null) {
poster = a.selectFirst("div.fposter > img")?.attr("src")
}
@ -133,13 +132,14 @@ class FrenchStreamProvider : MainAPI() {
episodeNumber: String,
is_vf_available: Boolean,
): String {
if (episodeNumber == "1") {
return if (episodeNumber == "1") {
if (is_vf_available) { // 1 translate differently if vf is available or not
return "FGHIJK"
} else { return "episode033" }
}
else {
return "episode" + (episodeNumber.toInt() + 32).toString()
"FGHIJK"
} else {
"episode033"
}
} else {
"episode" + (episodeNumber.toInt() + 32).toString()
}
}
@ -173,7 +173,7 @@ class FrenchStreamProvider : MainAPI() {
val serversvf =// French version servers
soup.select("div#$wantedEpisode > div.selink > ul.btnss $div> li")
.mapNotNull { li -> // list of all french version servers
val serverUrl = fixUrl(li.selectFirst("a").attr("href"))
val serverUrl = fixUrl(li.selectFirst("a")!!.attr("href"))
// val litext = li.text()
if (serverUrl.isNotBlank()) {
if (li.text().replace("&nbsp;", "").replace(" ", "").isNotBlank()) {
@ -208,7 +208,7 @@ class FrenchStreamProvider : MainAPI() {
.mapNotNull { a ->
val serverurl = fixUrlNull(a.attr("href")) ?: return@mapNotNull null
val parent = a.parents()[2]
val element = parent.selectFirst("a").text().plus(" ")
val element = parent.selectFirst("a")!!.text().plus(" ")
if (a.text().replace("&nbsp;", "").isNotBlank()) {
Pair(element.plus(a.text()), fixUrl(serverurl))
} else {
@ -239,14 +239,14 @@ class FrenchStreamProvider : MainAPI() {
val returnList = docs.mapNotNull {
val epList = it.selectFirst("> div.sect-c.floats.clearfix") ?: return@mapNotNull null
val title =
it.selectFirst("> div.sect-t.fx-row.icon-r > div.st-left > a.st-capt").text()
it.selectFirst("> div.sect-t.fx-row.icon-r > div.st-left > a.st-capt")!!.text()
val list = epList.select("> div.short")
val isMovieType = title.contains("Films") // if truen type is Movie
val currentList = list.map { head ->
val hrefItem = head.selectFirst("> div.short-in.nl > a")
val href = fixUrl(hrefItem.attr("href"))
val href = fixUrl(hrefItem!!.attr("href"))
val img = hrefItem.selectFirst("> img")
val posterUrl = img.attr("src")
val posterUrl = img!!.attr("src")
val name = img.attr("> div.short-title").toString()
return@map if (isMovieType) MovieSearchResponse(
name,

View file

@ -1,9 +1,13 @@
package com.lagradost.cloudstream3.network
import androidx.annotation.AnyThread
import com.lagradost.cloudstream3.USER_AGENT
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.network.Requests.Companion.await
import com.lagradost.nicehttp.Requests.Companion.await
import com.lagradost.nicehttp.getCookies
import kotlinx.coroutines.runBlocking
import okhttp3.Headers
import okhttp3.Headers.Companion.toHeaders
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
@ -13,14 +17,13 @@ import okhttp3.Response
* If false it will only try to get cookies when a request returns 403
* */
// As seen in https://github.com/anime-dl/anime-downloader/blob/master/anime_downloader/sites/erairaws.py
@AnyThread
class DdosGuardKiller(private val alwaysBypass: Boolean) : Interceptor {
val savedCookiesMap = mutableMapOf<String, Map<String, String>>()
private var ddosBypassPath: String? = null
override fun intercept(chain: Interceptor.Chain): Response = runBlocking {
override fun intercept(chain: Interceptor.Chain): Response = runBlocking {
val request = chain.request()
if (alwaysBypass) return@runBlocking bypassDdosGuard(request)
@ -46,7 +49,7 @@ class DdosGuardKiller(private val alwaysBypass: Boolean) : Interceptor {
}
}
val headers = getHeaders(request.headers.toMap(), null, cookies + request.cookies)
val headers = getHeaders(request.headers.toMap(), cookies + request.cookies)
return app.baseClient.newCall(
request.newBuilder()
.headers(headers)

View file

@ -1,449 +0,0 @@
package com.lagradost.cloudstream3.network
import android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import androidx.preference.PreferenceManager
import com.fasterxml.jackson.module.kotlin.readValue
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.USER_AGENT
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mapper
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.CompletionHandler
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.suspendCancellableCoroutine
import okhttp3.*
import okhttp3.Headers.Companion.toHeaders
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import java.io.File
import java.io.IOException
import java.net.URI
import java.security.SecureRandom
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
import kotlin.coroutines.resumeWithException
class Session(
client: OkHttpClient = app.baseClient
) : Requests() {
init {
this.baseClient = client
.newBuilder()
.cookieJar(CustomCookieJar())
.build()
}
inner class CustomCookieJar : CookieJar {
private var cookies = mapOf<String, Cookie>()
override fun loadForRequest(url: HttpUrl): List<Cookie> {
return this.cookies.values.toList()
}
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
this.cookies += cookies.map { it.name to it }
}
}
}
private const val DEFAULT_TIME = 10
private val DEFAULT_TIME_UNIT = TimeUnit.MINUTES
private const val DEFAULT_USER_AGENT = USER_AGENT
private val DEFAULT_HEADERS = mapOf("user-agent" to DEFAULT_USER_AGENT)
private val DEFAULT_DATA: Map<String, String> = mapOf()
private val DEFAULT_COOKIES: Map<String, String> = mapOf()
private val DEFAULT_REFERER: String? = null
/** WARNING! CAN ONLY BE READ ONCE */
val Response.text: String
get() {
return this.body?.string() ?: ""
}
val Response.url: String
get() {
return this.request.url.toString()
}
fun Headers.getCookies(cookieKey: String): Map<String, String> {
val cookieList =
this.filter { it.first.equals(cookieKey, ignoreCase = true) }
.getOrNull(0)?.second?.split(";")
return cookieList?.associate {
val split = it.split("=")
(split.getOrNull(0)?.trim() ?: "") to (split.getOrNull(1)?.trim() ?: "")
}?.filter { it.key.isNotBlank() && it.value.isNotBlank() } ?: mapOf()
}
val Response.cookies: Map<String, String>
get() {
return this.headers.getCookies("set-cookie")
}
val Request.cookies: Map<String, String>
get() {
return this.headers.getCookies("Cookie")
}
class AppResponse(
val response: Response
) {
/** Lazy, initialized on use. */
val text by lazy { response.text }
val url by lazy { response.url }
val cookies by lazy { response.cookies }
val body by lazy { response.body }
val code = response.code
val headers = response.headers
val document: Document by lazy { Jsoup.parse(text) }
/** Same as using mapper.readValue<T>() */
inline fun <reified T : Any> mapped(): T {
return mapper.readValue(this.text)
}
}
private fun getData(data: Any?): RequestBody {
return when (data) {
null -> FormBody.Builder().build()
is Map<*, *> -> {
val builder = FormBody.Builder()
data.forEach {
if (it.key is String && it.value is String)
builder.add(it.key as String, it.value as String)
}
builder.build()
}
else ->
data.toString().toRequestBody("text/plain;charset=UTF-8".toMediaTypeOrNull())
}
}
// https://github.com, id=test -> https://github.com?id=test
private fun appendUri(uri: String, appendQuery: String): String {
val oldUri = URI(uri)
return URI(
oldUri.scheme,
oldUri.authority,
oldUri.path,
if (oldUri.query == null) appendQuery else oldUri.query + "&" + appendQuery,
oldUri.fragment
).toString()
}
// Can probably be done recursively
private fun addParamsToUrl(url: String, params: Map<String, String?>): String {
var appendedUrl = url
params.forEach {
it.value?.let { value ->
appendedUrl = appendUri(appendedUrl, "${it.key}=${value}")
}
}
return appendedUrl
}
private fun getCache(cacheTime: Int, cacheUnit: TimeUnit): CacheControl {
return CacheControl.Builder().maxStale(cacheTime, cacheUnit).build()
}
/**
* Referer > Set headers > Set cookies > Default headers > Default Cookies
*/
fun getHeaders(
headers: Map<String, String>,
referer: String?,
cookie: Map<String, String>
): Headers {
val refererMap = (referer ?: DEFAULT_REFERER)?.let { mapOf("referer" to it) } ?: mapOf()
val cookieHeaders = (DEFAULT_COOKIES + cookie)
val cookieMap =
if (cookieHeaders.isNotEmpty()) mapOf(
"Cookie" to cookieHeaders.entries.joinToString(" ") {
"${it.key}=${it.value};"
}) else mapOf()
val tempHeaders = (DEFAULT_HEADERS + headers + cookieMap + refererMap)
return tempHeaders.toHeaders()
}
fun postRequestCreator(
url: String,
headers: Map<String, String> = emptyMap(),
referer: String? = null,
params: Map<String, String> = emptyMap(),
cookies: Map<String, String> = emptyMap(),
data: Any? = DEFAULT_DATA,
cacheTime: Int = DEFAULT_TIME,
cacheUnit: TimeUnit = DEFAULT_TIME_UNIT
): Request {
return Request.Builder()
.url(addParamsToUrl(url, params))
.cacheControl(getCache(cacheTime, cacheUnit))
.headers(getHeaders(headers, referer, cookies))
.post(getData(data))
.build()
}
fun getRequestCreator(
url: String,
headers: Map<String, String> = emptyMap(),
referer: String? = null,
params: Map<String, String> = emptyMap(),
cookies: Map<String, String> = emptyMap(),
cacheTime: Int = DEFAULT_TIME,
cacheUnit: TimeUnit = DEFAULT_TIME_UNIT
): Request {
return Request.Builder()
.url(addParamsToUrl(url, params))
.cacheControl(getCache(cacheTime, cacheUnit))
.headers(getHeaders(headers, referer, cookies))
.build()
}
fun putRequestCreator(
url: String,
headers: Map<String, String>,
referer: String?,
params: Map<String, String?>,
cookies: Map<String, String>,
data: Map<String, String?>,
cacheTime: Int,
cacheUnit: TimeUnit
): Request {
return Request.Builder()
.url(addParamsToUrl(url, params))
.cacheControl(getCache(cacheTime, cacheUnit))
.headers(getHeaders(headers, referer, cookies))
.put(getData(data))
.build()
}
fun optionsRequestCreator(
url: String,
headers: Map<String, String>,
referer: String?,
params: Map<String, String?>,
cookies: Map<String, String>,
data: Map<String, String?>,
cacheTime: Int,
cacheUnit: TimeUnit
): Request {
return Request.Builder()
.url(addParamsToUrl(url, params))
.cacheControl(getCache(cacheTime, cacheUnit))
.headers(getHeaders(headers, referer, cookies))
.method("OPTIONS", getData(data))
.build()
}
// https://stackoverflow.com/a/59322754
// Issues with Akwam otherwise
fun OkHttpClient.Builder.ignoreAllSSLErrors(): OkHttpClient.Builder {
val naiveTrustManager = @SuppressLint("CustomX509TrustManager")
object : X509TrustManager {
override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
override fun checkClientTrusted(certs: Array<X509Certificate>, authType: String) = Unit
override fun checkServerTrusted(certs: Array<X509Certificate>, authType: String) = Unit
}
val insecureSocketFactory = SSLContext.getInstance("TLSv1.2").apply {
val trustAllCerts = arrayOf<TrustManager>(naiveTrustManager)
init(null, trustAllCerts, SecureRandom())
}.socketFactory
sslSocketFactory(insecureSocketFactory, naiveTrustManager)
hostnameVerifier { _, _ -> true }
return this
}
open class Requests {
var baseClient = OkHttpClient()
fun initClient(context: Context): OkHttpClient {
val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)
val dns = settingsManager.getInt(context.getString(R.string.dns_pref), 0)
baseClient = OkHttpClient.Builder()
.followRedirects(true)
.followSslRedirects(true)
.ignoreAllSSLErrors()
.cache(
// Note that you need to add a ResponseInterceptor to make this 100% active.
// The server response dictates if and when stuff should be cached.
Cache(
directory = File(context.cacheDir, "http_cache"),
maxSize = 50L * 1024L * 1024L // 50 MiB
)
).apply {
when (dns) {
1 -> addGoogleDns()
2 -> addCloudFlareDns()
// 3 -> addOpenDns()
4 -> addAdGuardDns()
}
}
// Needs to be build as otherwise the other builders will change this object
.build()
return baseClient
}
class ContinuationCallback(
private val call: Call,
private val continuation: CancellableContinuation<Response>
) : Callback, CompletionHandler {
@ExperimentalCoroutinesApi
override fun onResponse(call: Call, response: Response) {
continuation.resume(response, null)
}
override fun onFailure(call: Call, e: IOException) {
if (!call.isCanceled()) {
continuation.resumeWithException(e)
}
}
override fun invoke(cause: Throwable?) {
try {
call.cancel()
} catch (_: Throwable) {
}
}
}
companion object {
suspend inline fun Call.await(): Response {
return suspendCancellableCoroutine { continuation ->
val callback = ContinuationCallback(this, continuation)
enqueue(callback)
continuation.invokeOnCancellation(callback)
}
}
}
suspend fun get(
url: String,
headers: Map<String, String> = emptyMap(),
referer: String? = null,
params: Map<String, String> = emptyMap(),
cookies: Map<String, String> = emptyMap(),
allowRedirects: Boolean = true,
cacheTime: Int = DEFAULT_TIME,
cacheUnit: TimeUnit = DEFAULT_TIME_UNIT,
timeout: Long = 0L,
interceptor: Interceptor? = null,
): AppResponse {
Log.i("GET", url)
val client = baseClient
.newBuilder()
.followRedirects(allowRedirects)
.followSslRedirects(allowRedirects)
.callTimeout(timeout, TimeUnit.SECONDS)
if (timeout > 0)
client
.connectTimeout(timeout, TimeUnit.SECONDS)
.readTimeout(timeout, TimeUnit.SECONDS)
if (interceptor != null) client.addInterceptor(interceptor)
val request =
getRequestCreator(url, headers, referer, params, cookies, cacheTime, cacheUnit)
val response = client.build().newCall(request).await()
return AppResponse(response)
}
fun executeRequest(request: Request): AppResponse {
return AppResponse(baseClient.newCall(request).execute())
}
suspend fun post(
url: String,
headers: Map<String, String> = mapOf(),
referer: String? = null,
params: Map<String, String> = mapOf(),
cookies: Map<String, String> = mapOf(),
data: Any? = DEFAULT_DATA,
allowRedirects: Boolean = true,
cacheTime: Int = DEFAULT_TIME,
cacheUnit: TimeUnit = DEFAULT_TIME_UNIT,
timeout: Long = 0L,
): AppResponse {
Log.i("POST", url)
val client = baseClient
.newBuilder()
.followRedirects(allowRedirects)
.followSslRedirects(allowRedirects)
.callTimeout(timeout, TimeUnit.SECONDS)
.build()
val request =
postRequestCreator(url, headers, referer, params, cookies, data, cacheTime, cacheUnit)
val response = client.newCall(request).await()
return AppResponse(response)
}
suspend fun options(
url: String,
headers: Map<String, String> = mapOf(),
referer: String? = null,
params: Map<String, String> = mapOf(),
cookies: Map<String, String> = mapOf(),
data: Map<String, String?> = DEFAULT_DATA,
allowRedirects: Boolean = true,
cacheTime: Int = DEFAULT_TIME,
cacheUnit: TimeUnit = DEFAULT_TIME_UNIT,
timeout: Long = 0L
): AppResponse {
Log.i("OPTIONS", url)
val client = baseClient
.newBuilder()
.followRedirects(allowRedirects)
.followSslRedirects(allowRedirects)
.callTimeout(timeout, TimeUnit.SECONDS)
.build()
val request =
optionsRequestCreator(
url,
headers,
referer,
params,
cookies,
data,
cacheTime,
cacheUnit
)
val response = client.newCall(request).await()
return AppResponse(response)
}
suspend fun put(
url: String,
headers: Map<String, String> = mapOf(),
referer: String? = null,
params: Map<String, String> = mapOf(),
cookies: Map<String, String> = mapOf(),
data: Map<String, String?> = DEFAULT_DATA,
allowRedirects: Boolean = true,
cacheTime: Int = DEFAULT_TIME,
cacheUnit: TimeUnit = DEFAULT_TIME_UNIT,
timeout: Long = 0L
): AppResponse {
Log.i("PUT", url)
val client = baseClient
.newBuilder()
.followRedirects(allowRedirects)
.followSslRedirects(allowRedirects)
.callTimeout(timeout, TimeUnit.SECONDS)
.build()
val request =
putRequestCreator(url, headers, referer, params, cookies, data, cacheTime, cacheUnit)
val response = client.newCall(request).await()
return AppResponse(response)
}
}

View file

@ -0,0 +1,68 @@
package com.lagradost.cloudstream3.network
import android.content.Context
import androidx.preference.PreferenceManager
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.USER_AGENT
import com.lagradost.nicehttp.Requests
import com.lagradost.nicehttp.getCookies
import com.lagradost.nicehttp.ignoreAllSSLErrors
import okhttp3.Cache
import okhttp3.Headers
import okhttp3.Headers.Companion.toHeaders
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.File
import java.util.concurrent.TimeUnit
fun Requests.initClient(context: Context): OkHttpClient {
val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)
val dns = settingsManager.getInt(context.getString(R.string.dns_pref), 0)
baseClient = OkHttpClient.Builder()
.followRedirects(true)
.followSslRedirects(true)
.ignoreAllSSLErrors()
.cache(
// Note that you need to add a ResponseInterceptor to make this 100% active.
// The server response dictates if and when stuff should be cached.
Cache(
directory = File(context.cacheDir, "http_cache"),
maxSize = 50L * 1024L * 1024L // 50 MiB
)
).apply {
when (dns) {
1 -> addGoogleDns()
2 -> addCloudFlareDns()
// 3 -> addOpenDns()
4 -> addAdGuardDns()
}
}
// Needs to be build as otherwise the other builders will change this object
.build()
return baseClient
}
val Request.cookies: Map<String, String>
get() {
return this.headers.getCookies("Cookie")
}
private val DEFAULT_HEADERS = mapOf("user-agent" to USER_AGENT)
/**
* Set headers > Set cookies > Default headers > Default Cookies
* TODO REMOVE AND REPLACE WITH NICEHTTP
*/
fun getHeaders(
headers: Map<String, String>,
cookie: Map<String, String>
): Headers {
val cookieMap =
if (cookie.isNotEmpty()) mapOf(
"Cookie" to cookie.entries.joinToString(" ") {
"${it.key}=${it.value};"
}) else mapOf()
val tempHeaders = (DEFAULT_HEADERS + headers + cookieMap)
return tempHeaders.toHeaders()
}

View file

@ -8,6 +8,7 @@ import com.lagradost.cloudstream3.USER_AGENT
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.nicehttp.requestCreator
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import okhttp3.Interceptor
@ -155,12 +156,12 @@ class WebViewResolver(val interceptUrl: Regex, val additionalUrls: List<Regex> =
request.method == "GET" -> app.get(
webViewUrl,
headers = request.requestHeaders
).response.toWebResourceResponse()
).okhttpResponse.toWebResourceResponse()
request.method == "POST" -> app.post(
webViewUrl,
headers = request.requestHeaders
).response.toWebResourceResponse()
).okhttpResponse.toWebResourceResponse()
else -> return@runBlocking super.shouldInterceptRequest(
view,
request
@ -206,28 +207,17 @@ class WebViewResolver(val interceptUrl: Regex, val additionalUrls: List<Regex> =
fun WebResourceRequest.toRequest(): Request {
val webViewUrl = this.url.toString()
return when (this.method) {
"POST" -> postRequestCreator(
webViewUrl,
this.requestHeaders,
null,
emptyMap(),
emptyMap(),
emptyMap<String, String>(),
10,
TimeUnit.MINUTES
)
// "GET",
else -> getRequestCreator(
webViewUrl,
this.requestHeaders,
null,
emptyMap(),
emptyMap(),
10,
TimeUnit.MINUTES
)
}
return requestCreator(
this.method,
webViewUrl,
this.requestHeaders,
null,
emptyMap(),
emptyMap(),
null,
10,
TimeUnit.MINUTES
)
}
fun Response.toWebResourceResponse(): WebResourceResponse {

View file

@ -26,7 +26,7 @@ class NyaaProvider : MainAPI() {
if (tds.size < 2) continue
val type = tds[0].select("> a").attr("title")
val titleHeader = tds[1].select("> a").last()
val href = titleHeader.attr("href")
val href = titleHeader!!.attr("href")
val title = titleHeader.text()
if (title.contains("[Batch]") || !type.contains("Anime")) continue
returnValues.add(TorrentSearchResponse(title, fixUrl(href), this.name, TvType.Torrent, null))
@ -38,8 +38,8 @@ class NyaaProvider : MainAPI() {
override suspend fun load(url: String): LoadResponse {
val response = app.get(url).text
val document = Jsoup.parse(response)
val title = document.selectFirst("h3.panel-title").text()
val description = document.selectFirst("div#torrent-description").text()
val title = document.selectFirst("h3.panel-title")!!.text()
val description = document.selectFirst("div#torrent-description")!!.text()
val downloadLinks = document.select("div.panel-footer > a")
val magnet = downloadLinks[1].attr("href")
val torrent = downloadLinks[0].attr("href")

View file

@ -33,6 +33,7 @@ import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.network.initClient
import com.lagradost.cloudstream3.syncproviders.AccountManager
import com.lagradost.cloudstream3.syncproviders.OAuth2API
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.aniListApi

View file

@ -84,8 +84,8 @@ object FillerEpisodeCheck {
val documented = Jsoup.parse(result) ?: return null
val hashMap = HashMap<Int, Boolean>()
documented.select("table.EpisodeList > tbody > tr").forEach {
val type = it.selectFirst("td.Type > span").text() == "Filler"
val episodeNumber = it.selectFirst("td.Number").text().toIntOrNull()
val type = it.selectFirst("td.Type > span")?.text() == "Filler"
val episodeNumber = it.selectFirst("td.Number")?.text()?.toIntOrNull()
if (episodeNumber != null) {
hashMap[episodeNumber] = type
}

View file

@ -13,7 +13,8 @@ import com.bumptech.glide.module.AppGlideModule
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.signature.ObjectKey
import com.lagradost.cloudstream3.network.DdosGuardKiller
import com.lagradost.cloudstream3.network.Requests
import com.lagradost.cloudstream3.network.initClient
import com.lagradost.nicehttp.Requests
import java.io.InputStream
@GlideModule

View file

@ -79,7 +79,7 @@ object SyncUtil {
suspend fun getUrlsFromId(id: String, type: String = "anilist") : List<String> {
val url =
"https://raw.githubusercontent.com/MALSync/MAL-Sync-Backup/master/data/$type/anime/$id.json"
val response = app.get(url, cacheTime = 1, cacheUnit = TimeUnit.DAYS).mapped<SyncPage>()
val response = app.get(url, cacheTime = 1, cacheUnit = TimeUnit.DAYS).parsed<SyncPage>()
val pages = response.pages ?: return emptyList()
return pages.gogoanime.values.union(pages.nineanime.values).union(pages.twistmoe.values).mapNotNull { it.url }
}