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