fixed 2 small issues and code cleanup

This commit is contained in:
LagradOst 2022-01-14 19:14:24 +01:00
parent 0f1229354a
commit d87090c573
26 changed files with 166 additions and 110 deletions

View file

@ -60,7 +60,7 @@ class DubbedAnimeProvider : MainAPI() {
return document.select("li > a").map { return document.select("li > a").map {
val href = fixUrl(it.attr("href")) val href = fixUrl(it.attr("href"))
val title = it.selectFirst("> div > div.cittx").text() val title = it.selectFirst("> div > div.cittx").text()
val poster = fixUrl(it.selectFirst("> div > div.imghddde > img").attr("src")) val poster = fixUrlNull(it.selectFirst("> div > div.imghddde > img")?.attr("src"))
AnimeSearchResponse( AnimeSearchResponse(
title, title,
href, href,
@ -136,7 +136,7 @@ class DubbedAnimeProvider : MainAPI() {
for (i in items) { for (i in items) {
val href = fixUrl(i.attr("href")) val href = fixUrl(i.attr("href"))
val title = i.selectFirst("div.gridtitlek").text() val title = i.selectFirst("div.gridtitlek").text()
val img = fixUrl(i.selectFirst("img.grid__img").attr("src")) val img = fixUrlNull(i.selectFirst("img.grid__img")?.attr("src"))
returnValue.add( returnValue.add(
if (getIsMovie(href)) { if (getIsMovie(href)) {
MovieSearchResponse( MovieSearchResponse(

View file

@ -172,9 +172,8 @@ 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 params = mapOf("ep_start" to "0", "ep_end" to "2000", "id" to animeId)
val responseHTML = app.get(episodeloadApi, params = params).text
val epiDoc = Jsoup.parse(responseHTML) val episodes = app.get(episodeloadApi, params = params).document.select("a").map {
val episodes = epiDoc.select("a").map {
AnimeEpisode( AnimeEpisode(
fixUrl(it.attr("href").trim()), fixUrl(it.attr("href").trim()),
"Episode " + it.selectFirst(".name").text().replace("EP", "").trim() "Episode " + it.selectFirst(".name").text().replace("EP", "").trim()

View file

@ -104,7 +104,7 @@ class WatchCartoonOnlineProvider : MainAPI() {
return if (!isMovie) { return if (!isMovie) {
val title = document.selectFirst("td.vsbaslik > h2").text() val title = document.selectFirst("td.vsbaslik > h2").text()
val poster = fixUrl(document.selectFirst("div#cat-img-desc > div > img").attr("src")) 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 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 episodes = document.select("div#catlist-listview > ul > li > a").reversed().map {

View file

@ -8,12 +8,9 @@ import com.lagradost.cloudstream3.utils.M3u8Helper
import com.lagradost.cloudstream3.utils.getQualityFromName import com.lagradost.cloudstream3.utils.getQualityFromName
open class WatchSB : ExtractorApi() { open class WatchSB : ExtractorApi() {
override val name: String override val name = "WatchSB"
get() = "WatchSB" override val mainUrl = "https://watchsb.com"
override val mainUrl: String override val requiresReferer = false
get() = "https://watchsb.com"
override val requiresReferer: Boolean
get() = false
override fun getUrl(url: String, referer: String?): List<ExtractorLink> { override fun getUrl(url: String, referer: String?): List<ExtractorLink> {
val response = app.get( val response = app.get(

View file

@ -3,6 +3,7 @@ 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.*
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import okio.Buffer import okio.Buffer
import org.jsoup.Jsoup import org.jsoup.Jsoup
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
@ -29,8 +30,7 @@ class AllMoviesForYouProvider : MainAPI() {
override fun search(query: String): List<SearchResponse> { override fun search(query: String): List<SearchResponse> {
val url = "$mainUrl/?s=$query" val url = "$mainUrl/?s=$query"
val response = app.get(url).text val document = app.get(url).document
val document = Jsoup.parse(response)
val items = document.select("ul.MovieList > li > article > a") val items = document.select("ul.MovieList > li > article > a")
val returnValue = ArrayList<SearchResponse>() val returnValue = ArrayList<SearchResponse>()
@ -42,7 +42,17 @@ class AllMoviesForYouProvider : MainAPI() {
if (type == TvType.Movie) { if (type == TvType.Movie) {
returnValue.add(MovieSearchResponse(title, href, this.name, type, img, null)) returnValue.add(MovieSearchResponse(title, href, this.name, type, img, null))
} else if (type == TvType.TvSeries) { } else if (type == TvType.TvSeries) {
returnValue.add(TvSeriesSearchResponse(title, href, this.name, type, img, null, null)) returnValue.add(
TvSeriesSearchResponse(
title,
href,
this.name,
type,
img,
null,
null
)
)
} }
} }
return returnValue return returnValue
@ -69,16 +79,17 @@ class AllMoviesForYouProvider : MainAPI() {
override fun load(url: String): LoadResponse { override fun load(url: String): LoadResponse {
val type = getType(url) val type = getType(url)
val response = app.get(url).text val document = app.get(url).document
val document = Jsoup.parse(response)
val title = document.selectFirst("h1.Title").text() val title = document.selectFirst("h1.Title").text()
val descipt = document.selectFirst("div.Description > p").text() val descipt = document.selectFirst("div.Description > p").text()
val rating = val rating =
document.selectFirst("div.Vote > div.post-ratings > span")?.text()?.toFloatOrNull()?.times(1000)?.toInt() document.selectFirst("div.Vote > div.post-ratings > span")?.text()?.toFloatOrNull()
?.times(1000)?.toInt()
val year = document.selectFirst("span.Date")?.text() val year = document.selectFirst("span.Date")?.text()
val duration = document.selectFirst("span.Time").text() val duration = document.selectFirst("span.Time").text()
val backgroundPoster = fixUrl(document.selectFirst("div.Image > figure > img").attr("data-src")) val backgroundPoster =
fixUrlNull(document.selectFirst("div.Image > figure > img")?.attr("data-src"))
if (type == TvType.TvSeries) { if (type == TvType.TvSeries) {
val list = ArrayList<Pair<Int, String>>() val list = ArrayList<Pair<Int, String>>()
@ -112,7 +123,7 @@ class AllMoviesForYouProvider : MainAPI() {
season.first, season.first,
epNum, epNum,
href, href,
if (poster != null) fixUrl(poster) else null, fixUrlNull(poster),
date date
) )
) )
@ -136,7 +147,12 @@ class AllMoviesForYouProvider : MainAPI() {
val data = getLink(document) val data = getLink(document)
?: throw ErrorLoadingException("No Links Found") ?: throw ErrorLoadingException("No Links Found")
return newMovieLoadResponse(title,url,type,mapper.writeValueAsString(data.filter { it != "about:blank" })) { return newMovieLoadResponse(
title,
url,
type,
data.filter { it != "about:blank" }.toJson()
) {
posterUrl = backgroundPoster posterUrl = backgroundPoster
this.year = year?.toIntOrNull() this.year = year?.toIntOrNull()
this.plot = descipt this.plot = descipt
@ -152,7 +168,6 @@ class AllMoviesForYouProvider : MainAPI() {
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
if (data == "about:blank") return false
if (data.startsWith("$mainUrl/episode/")) { if (data.startsWith("$mainUrl/episode/")) {
val response = app.get(data).text val response = app.get(data).text
getLink(Jsoup.parse(response))?.let { links -> getLink(Jsoup.parse(response))?.let { links ->
@ -184,7 +199,15 @@ class AllMoviesForYouProvider : MainAPI() {
val postDocument = Jsoup.parse(form) val postDocument = Jsoup.parse(form)
postDocument.selectFirst("a.downloadbtn")?.attr("href")?.let { url -> postDocument.selectFirst("a.downloadbtn")?.attr("href")?.let { url ->
callback(ExtractorLink(this.name, this.name, url, mainUrl, Qualities.Unknown.value)) callback(
ExtractorLink(
this.name,
this.name,
url,
mainUrl,
Qualities.Unknown.value
)
)
} }
} }
} else if (requestUrl.startsWith("https://dood")) { } else if (requestUrl.startsWith("https://dood")) {
@ -197,7 +220,15 @@ class AllMoviesForYouProvider : MainAPI() {
} }
} }
} else { } else {
callback(ExtractorLink(this.name, this.name, realDataUrl, mainUrl, Qualities.Unknown.value)) callback(
ExtractorLink(
this.name,
this.name,
realDataUrl,
mainUrl,
Qualities.Unknown.value
)
)
} }
return true return true
} }

View file

@ -1,6 +1,5 @@
package com.lagradost.cloudstream3.movieproviders package com.lagradost.cloudstream3.movieproviders
import android.util.Log
import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.readValue
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.* import com.lagradost.cloudstream3.extractors.*
@ -156,10 +155,6 @@ class DramaSeeProvider : MainAPI() {
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
if (data.isEmpty()) return false
if (data == "[]") return false
if (data == "about:blank") return false
mapper.readValue<List<String>>(data).forEach { item -> mapper.readValue<List<String>>(data).forEach { item ->
if (item.isNotEmpty()) { if (item.isNotEmpty()) {
var url = item.trim() var url = item.trim()

View file

@ -186,10 +186,6 @@ class KdramaHoodProvider : MainAPI() {
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
if (data.isEmpty()) return false
if (data == "[]") return false
if (data == "about:blank") return false
var count = 0 var count = 0
mapper.readValue<List<String>>(data).forEach { item -> mapper.readValue<List<String>>(data).forEach { item ->
if (item.isNotEmpty()) { if (item.isNotEmpty()) {

View file

@ -5,6 +5,7 @@ import com.fasterxml.jackson.module.kotlin.readValue
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.unixTime import com.lagradost.cloudstream3.APIHolder.unixTime
import com.lagradost.cloudstream3.extractors.M3u8Manifest import com.lagradost.cloudstream3.extractors.M3u8Manifest
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.getQualityFromName import com.lagradost.cloudstream3.utils.getQualityFromName
import org.jsoup.Jsoup import org.jsoup.Jsoup
@ -146,7 +147,10 @@ class LookMovieProvider : MainAPI() {
data class LookMovieLinkLoad(val url: String, val extraUrl: String, val isMovie: Boolean) data class LookMovieLinkLoad(val url: String, val extraUrl: String, val isMovie: Boolean)
private fun addSubtitles(subs: List<LookMovieTokenSubtitle>?, subtitleCallback: (SubtitleFile) -> Unit) { private fun addSubtitles(
subs: List<LookMovieTokenSubtitle>?,
subtitleCallback: (SubtitleFile) -> Unit
) {
if (subs == null) return if (subs == null) return
subs.forEach { subs.forEach {
if (it.file.endsWith(".vtt")) if (it.file.endsWith(".vtt"))
@ -203,13 +207,16 @@ class LookMovieProvider : MainAPI() {
val nameHeader = watchHeader.selectFirst("> h1.bd-hd") val nameHeader = watchHeader.selectFirst("> h1.bd-hd")
val year = nameHeader.selectFirst("> span")?.text()?.toIntOrNull() val year = nameHeader.selectFirst("> span")?.text()?.toIntOrNull()
val title = nameHeader.ownText() val title = nameHeader.ownText()
val rating = parseRating(watchHeader.selectFirst("> div.movie-rate > div.rate > p > span").text()) val rating =
parseRating(watchHeader.selectFirst("> div.movie-rate > div.rate > p > span").text())
val imgElement = document.selectFirst("div.movie-img > p.movie__poster") val imgElement = document.selectFirst("div.movie-img > p.movie__poster")
val img = imgElement?.attr("style") val img = imgElement?.attr("style")
var poster = if (img.isNullOrEmpty()) null else "url\\((.*?)\\)".toRegex().find(img)?.groupValues?.get(1) var poster = if (img.isNullOrEmpty()) null else "url\\((.*?)\\)".toRegex()
.find(img)?.groupValues?.get(1)
if (poster.isNullOrEmpty()) poster = imgElement?.attr("data-background-image") 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) val id = "${if (isMovie) "id_movie" else "id_show"}:(.*?),".toRegex()
.find(response)?.groupValues?.get(1)
?.replace(" ", "") ?.replace(" ", "")
?: return null ?: return null
val realSlug = url.replace("$mainUrl/${if (isMovie) "movies" else "shows"}/view/", "") val realSlug = url.replace("$mainUrl/${if (isMovie) "movies" else "shows"}/view/", "")
@ -217,13 +224,13 @@ class LookMovieProvider : MainAPI() {
"$mainUrl/api/v1/security/${if (isMovie) "movie" else "show"}-access?${if (isMovie) "id_movie=$id" else "slug=$realSlug"}&token=1&sk=&step=1" "$mainUrl/api/v1/security/${if (isMovie) "movie" else "show"}-access?${if (isMovie) "id_movie=$id" else "slug=$realSlug"}&token=1&sk=&step=1"
if (isMovie) { if (isMovie) {
val localData = mapper.writeValueAsString( val localData =
LookMovieLinkLoad( LookMovieLinkLoad(
realUrl, realUrl,
"$mainUrl/manifests/movies/json/$id/\$unixtime/\$accessToken/master.m3u8", "$mainUrl/manifests/movies/json/$id/\$unixtime/\$accessToken/master.m3u8",
true true
) ).toJson()
)
return MovieLoadResponse( return MovieLoadResponse(
title, title,
url, url,
@ -242,10 +249,14 @@ class LookMovieProvider : MainAPI() {
val accessToken = root.data?.accessToken ?: return null val accessToken = root.data?.accessToken ?: return null
val window = val window =
"window\\['show_storage'] =((.|\\n)*?<)".toRegex().find(response)?.groupValues?.get(1) "window\\['show_storage'] =((.|\\n)*?<)".toRegex().find(response)?.groupValues?.get(
1
)
?: return null ?: return null
// val id = "id_show:(.*?),".toRegex().find(response.text)?.groupValues?.get(1) ?: return null // val id = "id_show:(.*?),".toRegex().find(response.text)?.groupValues?.get(1) ?: return null
val season = "seasons:.*\\[((.|\\n)*?)]".toRegex().find(window)?.groupValues?.get(1) ?: return null val season = "seasons:.*\\[((.|\\n)*?)]".toRegex().find(window)?.groupValues?.get(1)
?: return null
fun String.fixSeasonJson(replace: String): String { fun String.fixSeasonJson(replace: String): String {
return this.replace("$replace:", "\"$replace\":") return this.replace("$replace:", "\"$replace\":")
} }
@ -260,13 +271,13 @@ class LookMovieProvider : MainAPI() {
val realJson = "[" + json.substring(0, json.lastIndexOf(',')) + "]" val realJson = "[" + json.substring(0, json.lastIndexOf(',')) + "]"
val episodes = mapper.readValue<List<LookMovieEpisode>>(realJson).map { val episodes = mapper.readValue<List<LookMovieEpisode>>(realJson).map {
val localData = mapper.writeValueAsString( val localData =
LookMovieLinkLoad( LookMovieLinkLoad(
"$mainUrl/manifests/shows/json/$accessToken/\$unixtime/${it.idEpisode}/master.m3u8", "$mainUrl/manifests/shows/json/$accessToken/\$unixtime/${it.idEpisode}/master.m3u8",
"https://lookmovie.io/api/v1/shows/episode-subtitles/?id_episode=${it.idEpisode}", "https://lookmovie.io/api/v1/shows/episode-subtitles/?id_episode=${it.idEpisode}",
false false
) ).toJson()
)
TvSeriesEpisode( TvSeriesEpisode(
it.title, it.title,

View file

@ -3,6 +3,8 @@ package com.lagradost.cloudstream3.movieproviders
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
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.parseJson
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.getQualityFromName import com.lagradost.cloudstream3.utils.getQualityFromName
import org.jsoup.Jsoup import org.jsoup.Jsoup
@ -93,7 +95,7 @@ class MeloMovieProvider : MainAPI() {
MeloMovieLink("", "") MeloMovieLink("", "")
} }
}.filter { it.link != "" && it.name != "" } }.filter { it.link != "" && it.name != "" }
return mapper.writeValueAsString(parsed) return parsed.toJson()
} }
override fun loadLinks( override fun loadLinks(
@ -102,7 +104,7 @@ class MeloMovieProvider : MainAPI() {
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
val links = mapper.readValue<List<MeloMovieLink>>(data) val links = parseJson<List<MeloMovieLink>>(data)
for (link in links) { for (link in links) {
callback.invoke(ExtractorLink(this.name, link.name, link.link, "", getQualityFromName(link.name), false)) callback.invoke(ExtractorLink(this.name, link.name, link.link, "", getQualityFromName(link.name), false))
} }

View file

@ -7,14 +7,12 @@ import com.lagradost.cloudstream3.TvType
*/ */
class PelisplusProvider : PelisplusProviderTemplate() { class PelisplusProvider : PelisplusProviderTemplate() {
// mainUrl is good to have as a holder for the url to make future changes easier. // mainUrl is good to have as a holder for the url to make future changes easier.
override val mainUrl: String override val mainUrl = "https://pelisplus.icu"
get() = "https://pelisplus.icu"
// name is for how the provider will be named which is visible in the UI, no real rules for this. // name is for how the provider will be named which is visible in the UI, no real rules for this.
override val name: String override val name = "Pelisplus"
get() = "Pelisplus"
override val homePageUrlList: List<String> = listOf( override val homePageUrlList = listOf(
mainUrl, mainUrl,
"$mainUrl/movies", "$mainUrl/movies",
"$mainUrl/series", "$mainUrl/series",
@ -24,6 +22,5 @@ class PelisplusProvider : PelisplusProviderTemplate() {
// This is just extra metadata about what type of movies the provider has. // This is just extra metadata about what type of movies the provider has.
// Needed for search functionality. // Needed for search functionality.
override val supportedTypes: Set<TvType> override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie)
get() = setOf(TvType.TvSeries, TvType.Movie)
} }

View file

@ -1,12 +1,10 @@
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
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.lang.Exception
class PinoyHDXyzProvider : MainAPI() { class PinoyHDXyzProvider : MainAPI() {
override val name = "Pinoy-HD" override val name = "Pinoy-HD"
@ -211,10 +209,6 @@ class PinoyHDXyzProvider : MainAPI() {
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
if (data.isEmpty()) return false
if (data == "about:blank") return false
if (data == "[]") return false
mapper.readValue<List<String>>(data).forEach { item -> mapper.readValue<List<String>>(data).forEach { item ->
if (item.isNotEmpty()) { if (item.isNotEmpty()) {
val url = item.trim() val url = item.trim()

View file

@ -1,13 +1,11 @@
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.FEmbed import com.lagradost.cloudstream3.extractors.FEmbed
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.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor import com.lagradost.cloudstream3.utils.loadExtractor
import java.lang.Exception
class PinoyMoviePediaProvider : MainAPI() { class PinoyMoviePediaProvider : MainAPI() {
override val name = "Pinoy Moviepedia" override val name = "Pinoy Moviepedia"
@ -179,10 +177,6 @@ class PinoyMoviePediaProvider : MainAPI() {
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
if (data.isEmpty()) return false
if (data == "[]") return false
if (data == "about:blank") return false
// parse movie servers // parse movie servers
mapper.readValue<List<String>>(data).forEach { link -> mapper.readValue<List<String>>(data).forEach { link ->
if (link.contains("fembed.com")) { if (link.contains("fembed.com")) {

View file

@ -2,7 +2,7 @@ package com.lagradost.cloudstream3.movieproviders
import android.util.Log import android.util.Log
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.* import com.lagradost.cloudstream3.extractors.FEmbed
import com.lagradost.cloudstream3.network.DdosGuardKiller import com.lagradost.cloudstream3.network.DdosGuardKiller
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor import com.lagradost.cloudstream3.utils.loadExtractor
@ -191,8 +191,6 @@ class PinoyMoviesEsProvider : MainAPI() {
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
if (data == "about:blank") return false
if (data.isEmpty()) return false
val sources = mutableListOf<ExtractorLink>() val sources = mutableListOf<ExtractorLink>()
try { try {
if (data.contains("playcontainer")) { if (data.contains("playcontainer")) {

View file

@ -24,6 +24,7 @@ class SflixProvider(providerUrl: String, providerName: String) : MainAPI() {
TvType.Movie, TvType.Movie,
TvType.TvSeries, TvType.TvSeries,
) )
override val vpnStatus = VPNStatus.None
private fun Element.toSearchResult(): SearchResponse { private fun Element.toSearchResult(): SearchResponse {
val img = this.select("img") val img = this.select("img")
@ -83,9 +84,6 @@ class SflixProvider(providerUrl: String, providerName: String) : MainAPI() {
return HomePageResponse(all) return HomePageResponse(all)
} }
override val vpnStatus: VPNStatus
get() = VPNStatus.None
override fun search(query: String): List<SearchResponse> { override fun search(query: String): List<SearchResponse> {
val url = "$mainUrl/search/${query.replace(" ", "-")}" val url = "$mainUrl/search/${query.replace(" ", "-")}"
val html = app.get(url).text val html = app.get(url).text

View file

@ -1,6 +1,5 @@
package com.lagradost.cloudstream3.movieproviders package com.lagradost.cloudstream3.movieproviders
import android.util.Log
import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.readValue
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.extractors.* import com.lagradost.cloudstream3.extractors.*
@ -170,9 +169,6 @@ class WatchAsianProvider : MainAPI() {
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
if (data == "about:blank") return false
if (data == "[]") return false
if (data.isEmpty()) return false
val links = if (data.startsWith(mainUrl)) { val links = if (data.startsWith(mainUrl)) {
getServerLinks(data) getServerLinks(data)
} else { data } } else { data }

View file

@ -1,10 +1,8 @@
package com.lagradost.cloudstream3.movieproviders package com.lagradost.cloudstream3.movieproviders
import org.jsoup.Jsoup
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.extractorApis
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.extractorApis
class FrenchStreamProvider : MainAPI() { class FrenchStreamProvider : MainAPI() {
@ -24,7 +22,11 @@ class FrenchStreamProvider : MainAPI() {
val poster = li.selectFirst("img")?.attr("src") 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() val year = li.selectFirst(".date")?.text()?.split("-")?.get(0)?.toIntOrNull()
if (title.contains("saison", ignoreCase = true)) { // if saison in title ==> it's a TV serie if (title.contains(
"saison",
ignoreCase = true
)
) { // if saison in title ==> it's a TV serie
TvSeriesSearchResponse( TvSeriesSearchResponse(
title, title,
href, href,
@ -47,7 +49,7 @@ class FrenchStreamProvider : MainAPI() {
}) })
} }
override fun load(url: String): LoadResponse? { override fun load(url: String): LoadResponse {
val soup = app.get(url).document val soup = app.get(url).document
val title = soup.selectFirst("h1#s-title").text().toString() val title = soup.selectFirst("h1#s-title").text().toString()
@ -55,7 +57,7 @@ class FrenchStreamProvider : MainAPI() {
val description = val description =
soup.selectFirst("div.fdesc").text().toString() soup.selectFirst("div.fdesc").text().toString()
.split("streaming", ignoreCase = true)[1].replace(" : ", "") .split("streaming", ignoreCase = true)[1].replace(" : ", "")
var poster: String? = soup.selectFirst("div.fposter > img").attr("src").toString() var poster = fixUrlNull(soup.selectFirst("div.fposter > img")?.attr("src"))
val listEpisode = soup.selectFirst("div.elink") val listEpisode = soup.selectFirst("div.elink")
if (isMovie) { if (isMovie) {

View file

@ -19,6 +19,7 @@ import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.maxStale
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.unixTime import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.unixTime
import com.lagradost.cloudstream3.syncproviders.SyncAPI import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.utils.AppUtils.splitQuery import com.lagradost.cloudstream3.utils.AppUtils.splitQuery
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject
import java.net.URL import java.net.URL
@ -128,7 +129,8 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
private val mapper = JsonMapper.builder().addModule(KotlinModule()) private val mapper = JsonMapper.builder().addModule(KotlinModule())
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()!! .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()!!
private val aniListStatusString = arrayOf("CURRENT", "COMPLETED", "PAUSED", "DROPPED", "PLANNING", "REPEATING") private val aniListStatusString =
arrayOf("CURRENT", "COMPLETED", "PAUSED", "DROPPED", "PLANNING", "REPEATING")
const val ANILIST_UNIXTIME_KEY: String = "anilist_unixtime" // When token expires const val ANILIST_UNIXTIME_KEY: String = "anilist_unixtime" // When token expires
const val ANILIST_TOKEN_KEY: String = "anilist_token" // anilist token for api const val ANILIST_TOKEN_KEY: String = "anilist_token" // anilist token for api
@ -137,7 +139,8 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
const val ANILIST_SHOULD_UPDATE_LIST: String = "anilist_should_update_list" const val ANILIST_SHOULD_UPDATE_LIST: String = "anilist_should_update_list"
private fun fixName(name: String): String { private fun fixName(name: String): String {
return name.lowercase(Locale.ROOT).replace(" ", "").replace("[^a-zA-Z0-9]".toRegex(), "") return name.lowercase(Locale.ROOT).replace(" ", "")
.replace("[^a-zA-Z0-9]".toRegex(), "")
} }
private fun searchShows(name: String): GetSearchRoot? { private fun searchShows(name: String): GetSearchRoot? {
@ -200,13 +203,12 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
val data = val data =
mapOf( mapOf(
"query" to query, "query" to query,
"variables" to mapper.writeValueAsString( "variables" to
mapOf( mapOf(
"search" to name, "search" to name,
"page" to 1, "page" to 1,
"type" to "ANIME" "type" to "ANIME"
) ).toJson()
)
) )
val res = app.post( val res = app.post(
@ -235,7 +237,12 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
"(\\d+)" // year "(\\d+)" // year
) )
val blackListRegex = val blackListRegex =
Regex(""" (${blackList.joinToString(separator = "|").replace("(", "\\(").replace(")", "\\)")})""") Regex(
""" (${
blackList.joinToString(separator = "|").replace("(", "\\(")
.replace(")", "\\)")
})"""
)
//println("NAME $name NEW NAME ${name.replace(blackListRegex, "")}") //println("NAME $name NEW NAME ${name.replace(blackListRegex, "")}")
val shows = searchShows(name.replace(blackListRegex, "")) val shows = searchShows(name.replace(blackListRegex, ""))
@ -607,7 +614,12 @@ class AniListApi(index: Int) : AccountManager(index), SyncAPI {
return data != "" return data != ""
} }
private fun postDataAboutId(id: Int, type: AniListStatusType, score: Int?, progress: Int?): Boolean { private fun postDataAboutId(
id: Int,
type: AniListStatusType,
score: Int?,
progress: Int?
): Boolean {
try { try {
val q = val q =
"""mutation (${'$'}id: Int = $id, ${'$'}status: MediaListStatus = ${ """mutation (${'$'}id: Int = $id, ${'$'}status: MediaListStatus = ${

View file

@ -36,8 +36,7 @@ class MALApi(index: Int) : AccountManager(index), SyncAPI {
override val redirectUrl = "mallogin" override val redirectUrl = "mallogin"
override val idPrefix = "mal" override val idPrefix = "mal"
override val mainUrl = "https://myanimelist.net" override val mainUrl = "https://myanimelist.net"
override val icon: Int override val icon = R.drawable.mal_logo
get() = R.drawable.mal_logo
override fun logOut() { override fun logOut() {
removeAccountKeys() removeAccountKeys()

View file

@ -9,8 +9,6 @@ class NyaaProvider : MainAPI() {
override val name = "Nyaa" override val name = "Nyaa"
override val hasChromecastSupport = false override val hasChromecastSupport = false
// override val hasDownloadSupport: Boolean
// get() = false
override val mainUrl = "https://nyaa.si" override val mainUrl = "https://nyaa.si"
override val supportedTypes = setOf(TvType.Torrent) override val supportedTypes = setOf(TvType.Torrent)
override val vpnStatus = VPNStatus.Torrent override val vpnStatus = VPNStatus.Torrent

View file

@ -21,21 +21,28 @@ class APIRepository(val api: MainAPI) {
override val supportedTypes = emptySet<TvType>() override val supportedTypes = emptySet<TvType>()
} }
val noneRepo = APIRepository(noneApi) fun isInvalidData(data : String): Boolean {
return data.isEmpty() || data == "[]" || data == "about:blank"
}
} }
val hasMainPage: Boolean get() = api.hasMainPage val hasMainPage = api.hasMainPage
val name: String get() = api.name val name = api.name
val mainUrl: String get() = api.mainUrl val mainUrl = api.mainUrl
val hasQuickSearch: Boolean get() = api.hasQuickSearch val hasQuickSearch = api.hasQuickSearch
suspend fun load(url: String): Resource<LoadResponse> { suspend fun load(url: String): Resource<LoadResponse> {
if(isInvalidData(url)) throw ErrorLoadingException()
return safeApiCall { return safeApiCall {
api.load(api.fixUrl(url)) ?: throw ErrorLoadingException() api.load(api.fixUrl(url)) ?: throw ErrorLoadingException()
} }
} }
suspend fun search(query: String): Resource<List<SearchResponse>> { suspend fun search(query: String): Resource<List<SearchResponse>> {
if (query.isEmpty())
return Resource.Success(emptyList())
return safeApiCall { return safeApiCall {
return@safeApiCall (api.search(query) return@safeApiCall (api.search(query)
?: throw ErrorLoadingException()) ?: throw ErrorLoadingException())
@ -45,6 +52,9 @@ class APIRepository(val api: MainAPI) {
} }
suspend fun quickSearch(query: String): Resource<List<SearchResponse>> { suspend fun quickSearch(query: String): Resource<List<SearchResponse>> {
if (query.isEmpty())
return Resource.Success(emptyList())
return safeApiCall { return safeApiCall {
api.quickSearch(query) ?: throw ErrorLoadingException() api.quickSearch(query) ?: throw ErrorLoadingException()
} }
@ -62,6 +72,9 @@ class APIRepository(val api: MainAPI) {
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
return normalSafeApiCall { api.loadLinks(data, isCasting, subtitleCallback, callback) } ?: false if (isInvalidData(data)) return false // this makes providers cleaner
return normalSafeApiCall { api.loadLinks(data, isCasting, subtitleCallback, callback) }
?: false
} }
} }

View file

@ -28,6 +28,7 @@ import com.lagradost.cloudstream3.sortUrls
import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator
import com.lagradost.cloudstream3.ui.player.SubtitleData import com.lagradost.cloudstream3.ui.player.SubtitleData
import com.lagradost.cloudstream3.ui.result.ResultEpisode import com.lagradost.cloudstream3.ui.result.ResultEpisode
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.CastHelper.awaitLinks import com.lagradost.cloudstream3.utils.CastHelper.awaitLinks
import com.lagradost.cloudstream3.utils.CastHelper.getMediaInfo import com.lagradost.cloudstream3.utils.CastHelper.getMediaInfo
import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject
@ -294,7 +295,7 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi
) )
val done = val done =
JSONObject(mapper.writeValueAsString(jsonCopy)) JSONObject(jsonCopy.toJson())
val mediaInfo = getMediaInfo( val mediaInfo = getMediaInfo(
epData, epData,

View file

@ -107,7 +107,6 @@ class HomeFragment : Fragment() {
} }
fun Context.selectHomepage(selectedApiName: String?, callback: (String) -> Unit) { fun Context.selectHomepage(selectedApiName: String?, callback: (String) -> Unit) {
println("CURRENT $selectedApiName")
val validAPIs = filterProviderByPreferredMedia().toMutableList() val validAPIs = filterProviderByPreferredMedia().toMutableList()
validAPIs.add(0, randomApi) validAPIs.add(0, randomApi)
@ -303,9 +302,9 @@ class HomeFragment : Fragment() {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
fixGrid() fixGrid()
home_change_api.setOnClickListener(apiChangeClickListener) home_change_api?.setOnClickListener(apiChangeClickListener)
home_change_api_loading.setOnClickListener(apiChangeClickListener) home_change_api_loading?.setOnClickListener(apiChangeClickListener)
home_api_fab.setOnClickListener(apiChangeClickListener) home_api_fab?.setOnClickListener(apiChangeClickListener)
observe(homeViewModel.apiName) { apiName -> observe(homeViewModel.apiName) { apiName ->
currentApiName = apiName currentApiName = apiName

View file

@ -1048,6 +1048,21 @@ open class FullScreenPlayer : AbstractPlayerFragment(R.layout.fragment_player) {
return@setOnTouchListener handleMotionEvent(callView, event) return@setOnTouchListener handleMotionEvent(callView, event)
} }
exo_progress?.setOnTouchListener { _, event ->
// this makes the bar not disappear when sliding
when (event.action) {
MotionEvent.ACTION_DOWN -> {
currentTapIndex++
}
MotionEvent.ACTION_MOVE -> {
currentTapIndex++
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_BUTTON_RELEASE -> {
autoHide()
}
}
return@setOnTouchListener false
}
// init UI // init UI
try { try {
uiReset() uiReset()

View file

@ -19,6 +19,7 @@ import android.os.ParcelFileDescriptor
import android.provider.MediaStore import android.provider.MediaStore
import android.util.Log import android.util.Log
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.fasterxml.jackson.module.kotlin.readValue
import com.google.android.gms.cast.framework.CastContext import com.google.android.gms.cast.framework.CastContext
import com.google.android.gms.cast.framework.CastState import com.google.android.gms.cast.framework.CastState
import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.ConnectionResult
@ -28,6 +29,7 @@ import com.lagradost.cloudstream3.MainActivity
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.SearchResponse import com.lagradost.cloudstream3.SearchResponse
import com.lagradost.cloudstream3.mapper import com.lagradost.cloudstream3.mapper
import com.lagradost.cloudstream3.movieproviders.MeloMovieProvider
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.ui.result.ResultFragment import com.lagradost.cloudstream3.ui.result.ResultFragment
import com.lagradost.cloudstream3.utils.FillerEpisodeCheck.toClassDir import com.lagradost.cloudstream3.utils.FillerEpisodeCheck.toClassDir
@ -92,6 +94,10 @@ object AppUtils {
return mapper.writeValueAsString(this) return mapper.writeValueAsString(this)
} }
inline fun <reified T> parseJson(value : String): T {
return mapper.readValue(value)
}
/**| S1:E2 Hello World /**| S1:E2 Hello World
* | Episode 2. Hello world * | Episode 2. Hello world
* | Hello World * | Hello World

View file

@ -13,6 +13,7 @@ import com.google.android.gms.common.images.WebImage
import com.lagradost.cloudstream3.ui.MetadataHolder import com.lagradost.cloudstream3.ui.MetadataHolder
import com.lagradost.cloudstream3.ui.player.SubtitleData import com.lagradost.cloudstream3.ui.player.SubtitleData
import com.lagradost.cloudstream3.ui.result.ResultEpisode import com.lagradost.cloudstream3.ui.result.ResultEpisode
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.Coroutines.main import com.lagradost.cloudstream3.utils.Coroutines.main
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -107,7 +108,7 @@ object CastHelper {
val index = if (startIndex == null || startIndex < 0) 0 else startIndex val index = if (startIndex == null || startIndex < 0) 0 else startIndex
val mediaItem = val mediaItem =
getMediaInfo(epData, holder, index, JSONObject(mapper.writeValueAsString(holder)), subtitles) getMediaInfo(epData, holder, index, JSONObject(holder.toJson()), subtitles)
awaitLinks( awaitLinks(
this.remoteMediaClient?.load( this.remoteMediaClient?.load(

View file

@ -12,6 +12,7 @@
android:nextFocusLeft="@id/apply_btt" android:nextFocusLeft="@id/apply_btt"
android:id="@+id/listview1" android:id="@+id/listview1"
android:layout_marginBottom="60dp"
android:minHeight="0dp" android:minHeight="0dp"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:requiresFadingEdge="vertical" android:requiresFadingEdge="vertical"
@ -21,6 +22,7 @@
android:layout_rowWeight="1" android:layout_rowWeight="1"
/> />
<HorizontalScrollView <HorizontalScrollView
android:layout_marginTop="-60dp"
android:paddingStart="10dp" android:paddingStart="10dp"
android:paddingEnd="10dp" android:paddingEnd="10dp"
android:clipToPadding="true" android:clipToPadding="true"