From 29d5f3848ab20beff05abd3f8a18730dfc0d8676 Mon Sep 17 00:00:00 2001 From: LagradOst Date: Thu, 19 Aug 2021 22:05:18 +0200 Subject: [PATCH] small cleanup --- .../com/lagradost/cloudstream3/MainAPI.kt | 16 +- .../lagradost/cloudstream3/MainActivity.kt | 7 + .../animeproviders/AnimePaheProvider.kt | 176 +++++----- .../animeproviders/GogoanimeProvider.kt | 6 +- .../animeproviders/ShiroProvider.kt | 315 ------------------ .../animeproviders/TenshiProvider.kt | 2 +- .../WatchCartoonOnlineProvider.kt | 4 +- .../animeproviders/WcoProvider.kt | 6 +- .../movieproviders/HDMProvider.kt | 2 +- .../movieproviders/LookMovieProvider.kt | 6 +- .../movieproviders/MeloMovieProvider.kt | 4 +- .../movieproviders/TrailersToProvider.kt | 6 +- .../movieproviders/VMoveeProvider.kt | 4 +- .../ui/download/DownloadChildAdapter.kt | 2 +- .../ui/download/DownloadHeaderAdapter.kt | 19 +- .../ui/download/EasyDownloadButton.kt | 12 +- .../ui/home/HomeChildItemAdapter.kt | 12 +- .../cloudstream3/ui/home/HomeFragment.kt | 24 +- .../cloudstream3/ui/player/PlayerFragment.kt | 16 +- .../cloudstream3/ui/result/EpisodeAdapter.kt | 14 +- .../cloudstream3/ui/result/ResultFragment.kt | 17 +- .../cloudstream3/ui/search/SearchAdaptor.kt | 11 +- .../cloudstream3/ui/search/SearchFragment.kt | 20 +- .../lagradost/cloudstream3/utils/UIHelper.kt | 19 +- .../utils/VideoDownloadManager.kt | 28 +- .../cloudstream3/widget/FlowLayout.kt | 9 +- 26 files changed, 215 insertions(+), 542 deletions(-) delete mode 100644 app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt index 4927dd76..2804d5e8 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt @@ -65,20 +65,24 @@ object APIHolder { fun Activity.getApiSettings(): HashSet { val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) + val hashSet = HashSet() + hashSet.addAll(apis.map { it.name }) + return settingsManager.getStringSet( this.getString(R.string.search_providers_list_key), - setOf(apis[defProvider].name) - )?.toHashSet() ?: hashSetOf(apis[defProvider].name) + hashSet + )?.toHashSet() ?: hashSet } fun Activity.getApiTypeSettings(): HashSet { val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) - val list = settingsManager.getStringSet( - this.getString(R.string.search_types_list_key), - setOf(apis[defProvider].name) - ) val hashSet = HashSet() hashSet.addAll(TvType.values()) + val list = settingsManager.getStringSet( + this.getString(R.string.search_types_list_key), + hashSet.map { it.name }.toMutableSet() + ) + if(list.isNullOrEmpty()) return hashSet val names = TvType.values().map { it.name }.toHashSet() diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index 39e08daa..c00251b5 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -296,6 +296,13 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { /*thread { createISO() }*/ + + var providersString = "Current providers are:\n" + for (api in apis) { + providersString += "+ ${api.mainUrl}\n" + } + println(providersString) + handleAppIntent(intent) thread { diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimePaheProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimePaheProvider.kt index 0b9e2efd..0770e59c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimePaheProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/AnimePaheProvider.kt @@ -11,35 +11,39 @@ import org.jsoup.Jsoup import java.util.* import kotlin.collections.ArrayList - class AnimePaheProvider : MainAPI() { companion object { + const val MAIN_URL = "https://animepahe.com" + var cookies = CookieJar() private fun getType(t: String): TvType { return if (t.contains("OVA") || t.contains("Special")) TvType.ONA else if (t.contains("Movie")) TvType.AnimeMovie else TvType.Anime } + fun generateSession(): Boolean { if (cookies.entries.size != 0) return true return try { - val response = khttp.get("https://animepahe.com/") + val response = khttp.get("$MAIN_URL/") cookies = response.cookies true } catch (e: Exception) { false } } + val YTSM = "ysmm = '([^']+)".toRegex() - val KWIK_PARAMS_RE = Regex("""\(\"(\w+)\",\d+,\"(\w+)\",(\d+),(\d+),\d+\)""") + val KWIK_PARAMS_RE = Regex("""\("(\w+)",\d+,"(\w+)",(\d+),(\d+),\d+\)""") val KWIK_D_URL = Regex("action=\"([^\"]+)\"") val KWIK_D_TOKEN = Regex("value=\"([^\"]+)\"") - val YOUTUBE_VIDEO_LINK = Regex("""(^(?:https?:)?(?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube(?:\-nocookie)?\.(?:[A-Za-z]{2,4}|[A-Za-z]{2,3}\.[A-Za-z]{2})\/)(?:watch|embed\/|vi?\/)*(?:\?[\w=&]*vi?=)?[^#&\?\/]{11}.*${'$'})""") + val YOUTUBE_VIDEO_LINK = + Regex("""(^(?:https?:)?(?://)?(?:www\.)?(?:youtu\.be/|youtube(?:-nocookie)?\.(?:[A-Za-z]{2,4}|[A-Za-z]{2,3}\.[A-Za-z]{2})/)(?:watch|embed/|vi?/)*(?:\?[\w=&]*vi?=)?[^#&?/]{11}.*${'$'})""") } override val mainUrl: String - get() = "https://animepahe.com" + get() = MAIN_URL override val name: String get() = "AnimePahe" override val hasQuickSearch: Boolean @@ -54,19 +58,19 @@ class AnimePaheProvider : MainAPI() { TvType.ONA ) - override fun getMainPage(): HomePageResponse? { - data class Data ( - @JsonProperty("id") val id : Int, - @JsonProperty("anime_id") val animeId : Int, - @JsonProperty("anime_title") val animeTitle : String, - @JsonProperty("episode") val episode : Int, - @JsonProperty("snapshot") val snapshot : String, - @JsonProperty("created_at") val createdAt : String, + override fun getMainPage(): HomePageResponse { + data class Data( + @JsonProperty("id") val id: Int, + @JsonProperty("anime_id") val animeId: Int, + @JsonProperty("anime_title") val animeTitle: String, + @JsonProperty("episode") val episode: Int, + @JsonProperty("snapshot") val snapshot: String, + @JsonProperty("created_at") val createdAt: String, ) - data class AnimePaheLatestReleases ( - @JsonProperty("total") val total : Int, - @JsonProperty("data") val data : List + data class AnimePaheLatestReleases( + @JsonProperty("total") val total: Int, + @JsonProperty("data") val data: List ) val urls = listOf( @@ -98,36 +102,36 @@ class AnimePaheProvider : MainAPI() { e.printStackTrace() } } - if(items.size <= 0) throw ErrorLoadingException() + if (items.size <= 0) throw ErrorLoadingException() return HomePageResponse(items) } override fun search(query: String): ArrayList { - data class AnimePaheSearchData ( - @JsonProperty("id") val id : Int, - @JsonProperty("slug") val slug : String, - @JsonProperty("title") val title : String, - @JsonProperty("type") val type : String, - @JsonProperty("episodes") val episodes : Int, - @JsonProperty("status") val status : String, - @JsonProperty("season") val season : String, - @JsonProperty("year") val year : Int, - @JsonProperty("score") val score : Double, - @JsonProperty("poster") val poster : String, - @JsonProperty("session") val session : String, - @JsonProperty("relevance") val relevance : String + data class AnimePaheSearchData( + @JsonProperty("id") val id: Int, + @JsonProperty("slug") val slug: String, + @JsonProperty("title") val title: String, + @JsonProperty("type") val type: String, + @JsonProperty("episodes") val episodes: Int, + @JsonProperty("status") val status: String, + @JsonProperty("season") val season: String, + @JsonProperty("year") val year: Int, + @JsonProperty("score") val score: Double, + @JsonProperty("poster") val poster: String, + @JsonProperty("session") val session: String, + @JsonProperty("relevance") val relevance: String ) - data class AnimePaheSearch ( - @JsonProperty("total") val total : Int, - @JsonProperty("data") val data : List + data class AnimePaheSearch( + @JsonProperty("total") val total: Int, + @JsonProperty("data") val data: List ) - val url = "https://animepahe.com/api?m=search&l=8&q=$query" - val headers = mapOf("referer" to "https://animepahe.com/") + val url = "$mainUrl/api?m=search&l=8&q=$query" + val headers = mapOf("referer" to "$mainUrl/") - val req = khttp.get(url, headers=headers) + val req = khttp.get(url, headers = headers) val data = req.let { mapper.readValue(it.text) } return ArrayList(data.data.map { @@ -172,11 +176,11 @@ class AnimePaheProvider : MainAPI() { private fun generateListOfEpisodes(link: String): ArrayList { try { - val attrs = link.split('/') + val attrs = link.split('/') val id = attrs[attrs.size - 1] - val uri = "https://animepahe.com/api?m=release&id=$id&sort=episode_asc&page=1" - val headers = mapOf("referer" to "https://animepahe.com/") + val uri = "$mainUrl/api?m=release&id=$id&sort=episode_asc&page=1" + val headers = mapOf("referer" to "$mainUrl/") val req = khttp.get(uri, headers = headers) val data = req.let { mapper.readValue(it.text) } @@ -188,7 +192,7 @@ class AnimePaheProvider : MainAPI() { val episodes = ArrayList() fun getEpisodeTitle(k: AnimeData): String { - return if (k.title.length == 0) { + return if (k.title.isEmpty()) { "Episode ${k.episode}" } else { k.title @@ -199,9 +203,13 @@ class AnimePaheProvider : MainAPI() { data.data.forEach { episodes.add( AnimeEpisode( - "https://animepahe.com/api?m=links&id=${it.animeId}&session=${it.session}&p=kwik!!TRUE!!", + "$mainUrl/api?m=links&id=${it.animeId}&session=${it.session}&p=kwik!!TRUE!!", getEpisodeTitle(it), - if (it.snapshot.length == 0) {null} else {it.snapshot}, + if (it.snapshot.length == 0) { + null + } else { + it.snapshot + }, it.createdAt ) ) @@ -212,7 +220,7 @@ class AnimePaheProvider : MainAPI() { if (ep <= total) { episodes.add( AnimeEpisode( - "https://animepahe.com/api?m=release&id=${id}&sort=episode_asc&page=${page + 1}&ep=${ep}!!FALSE!!" + "$mainUrl/api?m=release&id=${id}&sort=episode_asc&page=${page + 1}&ep=${ep}!!FALSE!!" ) ) ++ep @@ -222,7 +230,7 @@ class AnimePaheProvider : MainAPI() { } return episodes } catch (e: Exception) { - return ArrayList() + return ArrayList() } } @@ -235,7 +243,7 @@ class AnimePaheProvider : MainAPI() { val japTitle = doc.selectFirst("h2.japanese")?.text() val poster = doc.selectFirst(".anime-poster a").attr("href") - val TvType = doc.selectFirst("""a[href*="/anime/type/"]""")?.text() + val tvType = doc.selectFirst("""a[href*="/anime/type/"]""")?.text() val trailer: String? = if (html.contains("https://www.youtube.com/watch")) { YOUTUBE_VIDEO_LINK.find(html)?.destructured?.component1() @@ -243,9 +251,11 @@ class AnimePaheProvider : MainAPI() { null } - val episodes = generateListOfEpisodes(url) ?: ArrayList() - val year = """Aired:<\/strong>[^,]*, (\d+)""".toRegex().find(html)!!.destructured?.component1()?.toIntOrNull() - val status = when ("""Status:<\/strong>[^a]*a href=[\"']\/anime\/(.*?)[\"']""".toRegex().find(html)!!.destructured?.component1().toString()) { + val episodes = generateListOfEpisodes(url) + val year = """Aired:[^,]*, (\d+)""".toRegex().find(html)!!.destructured.component1() + .toIntOrNull() + val status = when ("""Status:[^a]*a href=["']/anime/(.*?)["']""".toRegex() + .find(html)!!.destructured.component1()) { "airing" -> ShowStatus.Ongoing "completed" -> ShowStatus.Completed else -> null @@ -259,9 +269,9 @@ class AnimePaheProvider : MainAPI() { val split = aTag.attr("href").split("/") if (aTag.attr("href").contains("anilist.co")) { - anilistId = split[split.size-1].toIntOrNull() + anilistId = split[split.size - 1].toIntOrNull() } else if (aTag.attr("href").contains("myanimelist.net")) { - malId = split[split.size-1].toIntOrNull() + malId = split[split.size - 1].toIntOrNull() } } @@ -271,7 +281,7 @@ class AnimePaheProvider : MainAPI() { title.toString(), url, this.name, - getType(TvType.toString()), + getType(tvType.toString()), poster, year, null, @@ -280,7 +290,9 @@ class AnimePaheProvider : MainAPI() { synopsis, if (!doc.select(".anime-genre > ul a").isEmpty()) { ArrayList(doc.select(".anime-genre > ul a").map { it.text().toString() }) - } else { null }, + } else { + null + }, ArrayList(), malId, anilistId, @@ -301,21 +313,25 @@ class AnimePaheProvider : MainAPI() { for (string in cookie.split("; ")) { val split = string.split("=").toMutableList() val name = split.removeFirst().trim() - val value = if (split.size == 0) {"true"} else {split.joinToString("=")} + val value = if (split.size == 0) { + "true" + } else { + split.joinToString("=") + } cookies[name] = value } return cookies.toMap() } - private fun getString(content: String, s1: Int, s2:Int): String { - val characterMap: String = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/"; + private fun getString(content: String, s1: Int, s2: Int): String { + val characterMap = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/" - val slice2 = characterMap.slice(0..s2-1) + val slice2 = characterMap.slice(0 until s2) var acc: Long = 0 for ((n, i) in content.reversed().withIndex()) { - acc += (when(isNumber("$i")) { + acc += (when (isNumber("$i")) { true -> "$i".toLong() false -> "0".toLong() }) * Math.pow(s1.toDouble(), n.toDouble()).toInt() @@ -335,7 +351,6 @@ class AnimePaheProvider : MainAPI() { } private fun decrypt(fullString: String, key: String, v1: Int, v2: Int): String { - var r = "" var i = 0 @@ -363,7 +378,7 @@ class AnimePaheProvider : MainAPI() { val newList = ArrayList, Pair>>() while (allItems.size > 1) { - newList.add(Pair, Pair>(allItems[0], allItems[1])) + newList.add(Pair(allItems[0], allItems[1])) allItems.removeAt(0) allItems.removeAt(0) } @@ -371,7 +386,8 @@ class AnimePaheProvider : MainAPI() { } private fun decodeAdfly(codedKey: String): String { - var r = ""; var j = "" + var r = "" + var j = "" for ((n, l) in codedKey.withIndex()) { if (n % 2 != 0) { @@ -385,7 +401,7 @@ class AnimePaheProvider : MainAPI() { val numbers = sequence { for ((i, n) in encodedUri.withIndex()) { if (isNumber(n)) { - yield(Pair(i, n.toInt())) + yield(Pair(i, n.toInt())) } } } @@ -398,21 +414,20 @@ class AnimePaheProvider : MainAPI() { } var returnValue = String(encodedUri.joinToString("").toByteArray(), Charsets.UTF_8) returnValue = String(android.util.Base64.decode(returnValue, android.util.Base64.DEFAULT), Charsets.ISO_8859_1) - return returnValue.slice(16..returnValue.length-17) + return returnValue.slice(16..returnValue.length - 17) } - private data class VideoQuality ( - @JsonProperty("id") val id : Int?, - @JsonProperty("audio") val audio : String?, - @JsonProperty("kwik") val kwik : String?, - @JsonProperty("kwik_adfly") val kwikAdfly : String + private data class VideoQuality( + @JsonProperty("id") val id: Int?, + @JsonProperty("audio") val audio: String?, + @JsonProperty("kwik") val kwik: String?, + @JsonProperty("kwik_adfly") val kwikAdfly: String ) - private data class AnimePaheEpisodeLoadLinks ( - @JsonProperty("data") val data : List> + private data class AnimePaheEpisodeLoadLinks( + @JsonProperty("data") val data: List> ) - private fun bypassAdfly(adflyUri: String): String { if (!generateSession()) { return bypassAdfly(adflyUri) @@ -423,7 +438,11 @@ class AnimePaheProvider : MainAPI() { var tries = 0 while (responseCode != 200 && tries < 20) { - adflyContent = khttp.get(khttp.get(adflyUri, cookies=cookies, allowRedirects = false).headers.getValue("location"), cookies=cookies, allowRedirects = false) + adflyContent = khttp.get( + khttp.get(adflyUri, cookies = cookies, allowRedirects = false).headers.getValue("location"), + cookies = cookies, + allowRedirects = false + ) cookies.putAll(adflyContent.cookies.toMap()) responseCode = adflyContent.statusCode ++tries @@ -435,10 +454,11 @@ class AnimePaheProvider : MainAPI() { } private fun getStreamUrlFromKwik(adflyUri: String): String { - val fContent = khttp.get(bypassAdfly(adflyUri), headers=mapOf("referer" to "https://kwik.cx/"), cookies=cookies) + val fContent = + khttp.get(bypassAdfly(adflyUri), headers = mapOf("referer" to "https://kwik.cx/"), cookies = cookies) cookies.putAll(fContent.cookies.toMap()) - val (fullString, key, v1, v2) = KWIK_PARAMS_RE.find(fContent.text.toString())!!.destructured + val (fullString, key, v1, v2) = KWIK_PARAMS_RE.find(fContent.text)!!.destructured val decrypted = decrypt(fullString, key, v1.toInt(), v2.toInt()) val uri = KWIK_D_URL.find(decrypted)!!.destructured.component1() val tok = KWIK_D_TOKEN.find(decrypted)!!.destructured.component1() @@ -451,9 +471,9 @@ class AnimePaheProvider : MainAPI() { content = khttp.post( uri, allowRedirects = false, - data=mapOf("_token" to tok), - headers=mapOf("referer" to fContent.url), - cookies=cookieStrToMap(fContent.headers.getValue("set-cookie").replace("path=/,", "")) + data = mapOf("_token" to tok), + headers = mapOf("referer" to fContent.url), + cookies = cookieStrToMap(fContent.headers.getValue("set-cookie").replace("path=/,", "")) ) code = content.statusCode ++tries @@ -466,7 +486,7 @@ class AnimePaheProvider : MainAPI() { private fun extractVideoLinks(episodeLink: String): List { var link = episodeLink - val headers = mapOf("referer" to "https://animepahe.com/") + val headers = mapOf("referer" to "$mainUrl/") if (link.contains("!!TRUE!!")) { link = link.replace("!!TRUE!!", "") @@ -485,7 +505,7 @@ class AnimePaheProvider : MainAPI() { null } }).filterNotNull())[0] - link = "https://animepahe.com/api?m=links&id=${ep.animeId}&session=${ep.session}&p=kwik" + link = "$mainUrl/api?m=links&id=${ep.animeId}&session=${ep.session}&p=kwik" } val req = khttp.get(link, headers = headers) val data = mapper.readValue(req.text) diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/GogoanimeProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/GogoanimeProvider.kt index 85ebcad3..69ee462d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/GogoanimeProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/GogoanimeProvider.kt @@ -48,11 +48,11 @@ class GogoanimeProvider : MainAPI() { "dnt" to "1", "sec-ch-ua-mobile" to "?0", "user-agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36", - "origin" to "https://gogoanime.vc", + "origin" to mainUrl, "sec-fetch-site" to "cross-site", "sec-fetch-mode" to "cors", "sec-fetch-dest" to "empty", - "referer" to "https://gogoanime.vc/" + "referer" to "$mainUrl/" ) val parseRegex = Regex("""
  • \s*\n.*\n.*\n.*?img src="(.*?)"""") @@ -179,7 +179,7 @@ class GogoanimeProvider : MainAPI() { title, link, this.name, - GogoanimeProvider.getType(type.toString()), + getType(type.toString()), poster, year, null, diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt deleted file mode 100644 index 457a68f4..00000000 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt +++ /dev/null @@ -1,315 +0,0 @@ -package com.lagradost.cloudstream3.animeproviders - -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.module.kotlin.readValue -import com.lagradost.cloudstream3.* -import com.lagradost.cloudstream3.utils.ExtractorLink -import com.lagradost.cloudstream3.extractors.Vidstream -import java.net.URLEncoder -import java.util.* -import kotlin.collections.ArrayList - -const val SHIRO_TIMEOUT_TIME = 60.0 - -class ShiroProvider : MainAPI() { - companion object { - var token: String? = null - - fun getType(t: String?): TvType { - return when (t) { - "TV" -> TvType.Anime - "OVA" -> TvType.ONA - "movie" -> TvType.Movie - else -> TvType.Anime - } - } - } - - private fun autoLoadToken(): Boolean { - if (token != null) return true - return loadToken() - } - - private fun loadToken(): Boolean { - return try { - val response = khttp.get(mainUrl, headers = baseHeader) - - val jsMatch = Regex("""src="(/static/js/main.*?)"""").find(response.text) - val (destructed) = jsMatch!!.destructured - val jsLocation = "$mainUrl$destructed" - val js = khttp.get(jsLocation, headers = baseHeader) - val tokenMatch = Regex("""token:"(.*?)"""").find(js.text) - token = (tokenMatch!!.destructured).component1() - - token != null - } catch (e: Exception) { - false - } - } - - override val mainUrl: String - get() = "https://shiro.is" - - override val name: String - get() = "Shiro" - - override val hasQuickSearch: Boolean - get() = true - - override val hasMainPage: Boolean - get() = true - - data class ShiroSearchResponseShow( - @JsonProperty("image") val image: String, - @JsonProperty("_id") val _id: String, - @JsonProperty("slug") val slug: String, - @JsonProperty("name") val name: String, - @JsonProperty("episodeCount") val episodeCount: String?, - @JsonProperty("language") val language: String?, - @JsonProperty("type") val type: String?, - @JsonProperty("year") val year: String?, - @JsonProperty("canonicalTitle") val canonicalTitle: String, - @JsonProperty("english") val english: String?, - ) - - data class ShiroSearchResponse( - @JsonProperty("data") val data: List, - @JsonProperty("status") val status: String, - ) - - data class ShiroFullSearchResponseCurrentPage( - @JsonProperty("items") val items: List, - ) - - data class ShiroFullSearchResponseNavItems( - @JsonProperty("currentPage") val currentPage: ShiroFullSearchResponseCurrentPage, - ) - - data class ShiroFullSearchResponseNav( - @JsonProperty("nav") val nav: ShiroFullSearchResponseNavItems, - ) - - data class ShiroFullSearchResponse( - @JsonProperty("data") val data: ShiroFullSearchResponseNav, - @JsonProperty("status") val status: String, - ) - - data class ShiroVideo( - @JsonProperty("video_id") val video_id: String, - @JsonProperty("host") val host: String, - ) - - data class ShiroEpisodes( - @JsonProperty("anime") val anime: AnimePageData?, - @JsonProperty("anime_slug") val anime_slug: String, - @JsonProperty("create") val create: String, - @JsonProperty("dayOfTheWeek") val dayOfTheWeek: String, - @JsonProperty("episode_number") val episode_number: Int, - @JsonProperty("slug") val slug: String, - @JsonProperty("update") val update: String, - @JsonProperty("_id") val _id: String, - @JsonProperty("videos") val videos: List, - ) - - data class AnimePageData( - @JsonProperty("banner") val banner: String?, - @JsonProperty("canonicalTitle") val canonicalTitle: String?, - @JsonProperty("episodeCount") val episodeCount: String, - @JsonProperty("genres") val genres: List?, - @JsonProperty("image") val image: String, - @JsonProperty("japanese") val japanese: String?, - @JsonProperty("english") val english: String?, - @JsonProperty("language") val language: String, - @JsonProperty("name") val name: String, - @JsonProperty("slug") val slug: String, - @JsonProperty("synopsis") val synopsis: String, - @JsonProperty("type") val type: String?, - @JsonProperty("views") val views: Int?, - @JsonProperty("year") val year: String?, - @JsonProperty("_id") val _id: String, - @JsonProperty("episodes") var episodes: List?, - @JsonProperty("synonyms") var synonyms: List?, - @JsonProperty("status") val status: String?, - @JsonProperty("schedule") val schedule: String?, - ) - - data class AnimePage( - @JsonProperty("data") val data: AnimePageData, - @JsonProperty("status") val status: String, - ) - - data class ShiroHomePageData( - @JsonProperty("trending_animes") val trending_animes: List, - @JsonProperty("ongoing_animes") val ongoing_animes: List, - @JsonProperty("latest_animes") val latest_animes: List, - @JsonProperty("latest_episodes") val latest_episodes: List, - ) - - data class ShiroHomePage( - @JsonProperty("status") val status: String, - @JsonProperty("data") val data: ShiroHomePageData, - @JsonProperty("random") var random: AnimePage?, - ) - - private fun toHomePageList(list: List, name: String): HomePageList { - return HomePageList(name, list.map { data -> - val type = getType(data.type) - val isDubbed = - data.language == "dubbed" - - val set: EnumSet = - EnumSet.of(if (isDubbed) DubStatus.Dubbed else DubStatus.Subbed) - - val episodeCount = data.episodeCount.toIntOrNull() - - return@map AnimeSearchResponse( - data.name.replace("Dubbed", ""), // i.english ?: i.canonicalTitle, - "$mainUrl/anime/${data.slug}", - this.name, - type, - "https://cdn.shiro.is/${data.image}", - data.year?.toIntOrNull(), - data.canonicalTitle, - set, - if (isDubbed) episodeCount else null, - if (!isDubbed) episodeCount else null, - ) - }.toList()) - } - - private fun turnSearchIntoResponse(data: ShiroSearchResponseShow): AnimeSearchResponse { - val type = getType(data.type) - val isDubbed = - if (data.language != null) - data.language == "dubbed" - else - data.slug.contains("dubbed") - val set: EnumSet = - EnumSet.of(if (isDubbed) DubStatus.Dubbed else DubStatus.Subbed) - - val episodeCount = data.episodeCount?.toIntOrNull() - - return AnimeSearchResponse( - data.name.replace("Dubbed", ""), // i.english ?: i.canonicalTitle, - "$mainUrl/anime/${data.slug}", - this.name, - type, - "https://cdn.shiro.is/${data.image}", - data.year?.toIntOrNull(), - data.canonicalTitle, - set, - if (isDubbed) episodeCount else null, - if (!isDubbed) episodeCount else null, - ) - } - - override fun getMainPage(): HomePageResponse? { - if (!autoLoadToken()) return null - - val url = "https://tapi.shiro.is/latest?token=$token" - val response = khttp.get(url, timeout = SHIRO_TIMEOUT_TIME) - val res = response.text.let { mapper.readValue(it) } - - val d = res.data - return HomePageResponse( - listOf( - toHomePageList(d.trending_animes, "Trending"), - toHomePageList(d.ongoing_animes, "Ongoing"), - toHomePageList(d.latest_animes, "Latest") - ) - ) - } - - override fun quickSearch(query: String): ArrayList? { - if (!autoLoadToken()) return null - - val returnValue: ArrayList = ArrayList() - - val response = khttp.get( - "https://tapi.shiro.is/anime/auto-complete/${ - URLEncoder.encode( - query, - "UTF-8" - ) - }?token=$token".replace("+", "%20") - ) - if (response.text == "{\"status\":\"Found\",\"data\":[]}") return returnValue // OR ELSE WILL CAUSE WEIRD ERROR - - val mapped = response.let { mapper.readValue(it.text) } - for (i in mapped.data) { - returnValue.add(turnSearchIntoResponse(i)) - } - return returnValue - } - - override fun search(query: String): ArrayList? { - if (!autoLoadToken()) return null - val returnValue: ArrayList = ArrayList() - val response = khttp.get( - "https://tapi.shiro.is/advanced?search=${ - URLEncoder.encode( - query, - "UTF-8" - ) - }&token=$token".replace("+", "%20") - ) - if (response.text == "{\"status\":\"Found\",\"data\":[]}") return returnValue // OR ELSE WILL CAUSE WEIRD ERROR - - val mapped = response.let { mapper.readValue(it.text) } - for (i in mapped.data.nav.currentPage.items) { - returnValue.add(turnSearchIntoResponse(i)) - } - return returnValue - } - - override fun load(url: String): LoadResponse? { - if (!autoLoadToken()) return null - val slug = url.replace("$mainUrl/anime/", "").replace("$mainUrl/", "") - val rurl = "https://tapi.shiro.is/anime/slug/${slug}?token=${token}" - val response = khttp.get(rurl, timeout = 120.0) - val mapped = response.let { mapper.readValue(it.text) } - val data = mapped.data - val isDubbed = data.language == "dubbed" - val episodes = - ArrayList( - data.episodes?.distinctBy { it.episode_number }?.sortedBy { it.episode_number } - ?.filter { it.videos.isNotEmpty() } - ?.map { AnimeEpisode(it.videos.first().video_id) } - ?: ArrayList()) - val status = when (data.status) { - "current" -> ShowStatus.Ongoing - "finished" -> ShowStatus.Completed - else -> null - } - - return AnimeLoadResponse( - data.english, - data.japanese, - data.name.replace("Dubbed", ""),//data.canonicalTitle ?: data.name.replace("Dubbed", ""), - "$mainUrl/anime/${url}", - this.name, - getType(data.type ?: ""), - "https://cdn.shiro.is/${data.image}", - data.year?.toIntOrNull(), - if (isDubbed) episodes else null, - if (!isDubbed) episodes else null, - status, - data.synopsis, - ArrayList(data.genres ?: ArrayList()), - ArrayList(data.synonyms ?: ArrayList()), - null, - null, - ) - } - - override fun loadLinks( - data: String, - isCasting: Boolean, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ): Boolean { - return Vidstream().getUrl(data, isCasting) { - callback.invoke(it) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/TenshiProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/TenshiProvider.kt index 6fd5b431..0976cb91 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/TenshiProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/TenshiProvider.kt @@ -217,7 +217,7 @@ class TenshiProvider : MainAPI() { canonicalTitle, url, this.name, - TenshiProvider.getType(type ?: ""), + getType(type ?: ""), poster, year.toIntOrNull(), null, diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WatchCartoonOnlineProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WatchCartoonOnlineProvider.kt index 5ee7ab33..aa9ede09 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WatchCartoonOnlineProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WatchCartoonOnlineProvider.kt @@ -23,7 +23,7 @@ class WatchCartoonOnlineProvider : MainAPI() { TvType.Anime, ) - override fun search(query: String): ArrayList? { + override fun search(query: String): List { val url = "https://www.wcostream.com/search" val response = @@ -69,7 +69,7 @@ class WatchCartoonOnlineProvider : MainAPI() { return returnValue } - override fun load(url: String): LoadResponse? { + override fun load(url: String): LoadResponse { val response = khttp.get(url) val document = Jsoup.parse(response.text) diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WcoProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WcoProvider.kt index 4e5c086d..4a8d73d6 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WcoProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/WcoProvider.kt @@ -34,7 +34,7 @@ class WcoProvider : MainAPI() { TvType.ONA ) - override fun getMainPage(): HomePageResponse? { + override fun getMainPage(): HomePageResponse { val urls = listOf( Pair("$mainUrl/ajax/list/recently_updated?type=tv", "Recently Updated Anime"), Pair("$mainUrl/ajax/list/recently_updated?type=movie", "Recently Updated Movies"), @@ -114,7 +114,7 @@ class WcoProvider : MainAPI() { return returnValue } - override fun search(query: String): ArrayList { + override fun search(query: String): List { val url = "$mainUrl/search" val response = khttp.get(url, params = mapOf("keyword" to query)) var document = Jsoup.parse(response.text) @@ -133,7 +133,7 @@ class WcoProvider : MainAPI() { return returnValue } - override fun quickSearch(query: String): ArrayList { + override fun quickSearch(query: String): List { val returnValue: ArrayList = ArrayList() val response = khttp.post( diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDMProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDMProvider.kt index 08d62553..bf3b1323 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDMProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/HDMProvider.kt @@ -18,7 +18,7 @@ class HDMProvider : MainAPI() { TvType.Movie, ) - override fun search(query: String): ArrayList { + override fun search(query: String): List { val url = "$mainUrl/search/$query" val response = khttp.get(url) val document = Jsoup.parse(response.text) diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/LookMovieProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/LookMovieProvider.kt index 15ecdfe6..fc7ae9b8 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/LookMovieProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/LookMovieProvider.kt @@ -69,7 +69,7 @@ class LookMovieProvider : MainAPI() { @JsonProperty("season") var season: String, ) - override fun quickSearch(query: String): ArrayList { + override fun quickSearch(query: String): List { val movieUrl = "$mainUrl/api/v1/movies/search/?q=$query" val movieResponse = khttp.get(movieUrl) val movies = mapper.readValue(movieResponse.text).result @@ -114,7 +114,7 @@ class LookMovieProvider : MainAPI() { return returnValue } - override fun search(query: String): ArrayList { + override fun search(query: String): List { fun search(query: String, isMovie: Boolean): ArrayList { val url = "$mainUrl/${if (isMovie) "movies" else "shows"}/search/?q=$query" val response = khttp.get(url) @@ -248,7 +248,7 @@ class LookMovieProvider : MainAPI() { val accessToken = root.data?.accessToken ?: return null val window = - "window\\[\\'show_storage\\'\\] =((.|\\n)*?\\<)".toRegex().find(response.text)?.groupValues?.get(1) + "window\\['show_storage'] =((.|\\n)*?<)".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 diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MeloMovieProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MeloMovieProvider.kt index 68d7928f..ef7d3167 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MeloMovieProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/MeloMovieProvider.kt @@ -31,11 +31,11 @@ class MeloMovieProvider : MainAPI() { data class MeloMovieLink(val name: String, val link: String) - override fun quickSearch(query: String): ArrayList { + override fun quickSearch(query: String): List { return search(query) } - override fun search(query: String): ArrayList { + override fun search(query: String): List { val url = "$mainUrl/movie/search/?name=$query" val returnValue: ArrayList = ArrayList() val response = khttp.get(url) diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TrailersToProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TrailersToProvider.kt index e5ecf411..ac2e0db8 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TrailersToProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TrailersToProvider.kt @@ -71,7 +71,7 @@ class TrailersToProvider : MainAPI() { //section.section > div.container > div.owl-carousel } - override fun quickSearch(query: String): ArrayList { + override fun quickSearch(query: String): List { val url = "$mainUrl/en/quick-search?q=$query" val response = khttp.get(url) val document = Jsoup.parse(response.text) @@ -99,7 +99,7 @@ class TrailersToProvider : MainAPI() { return returnValue } - override fun search(query: String): ArrayList { + override fun search(query: String): List { val url = "$mainUrl/en/popular/movies-tvshows-collections?q=$query" val response = khttp.get(url) val document = Jsoup.parse(response.text) @@ -180,7 +180,7 @@ class TrailersToProvider : MainAPI() { } else if (url.contains("/episode/")) { val response = khttp.get(url) val document = Jsoup.parse(response.text) - val qSub = document.select("subtitle-content") + //val qSub = document.select("subtitle-content") val subUrl = document.select("subtitle-content")?.attr("data-url") ?: "" val subData = fixUrl(document.selectFirst("content").attr("data-url") ?: return false) diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/VMoveeProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/VMoveeProvider.kt index ed4a2cf8..86222e1b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/VMoveeProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/VMoveeProvider.kt @@ -19,7 +19,7 @@ class VMoveeProvider : MainAPI() { TvType.Movie, ) - override fun search(query: String): ArrayList? { + override fun search(query: String): List { val url = "$mainUrl/?s=$query" val response = khttp.get(url) val document = Jsoup.parse(response.text) @@ -110,7 +110,7 @@ class VMoveeProvider : MainAPI() { return super.loadLinks(data, isCasting, subtitleCallback, callback) } - override fun load(url: String): LoadResponse? { + override fun load(url: String): LoadResponse { val response = khttp.get(url) val document = Jsoup.parse(response.text) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadChildAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadChildAdapter.kt index 67a1fc13..63461aa1 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadChildAdapter.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadChildAdapter.kt @@ -56,7 +56,7 @@ class DownloadChildAdapter( override fun onViewRecycled(holder: RecyclerView.ViewHolder) { if (holder is DownloadButtonViewHolder) { holder.downloadButton.dispose() - mBoundViewHolders.remove(holder); + mBoundViewHolders.remove(holder) } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadHeaderAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadHeaderAdapter.kt index 2bb63070..ea1a4978 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadHeaderAdapter.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadHeaderAdapter.kt @@ -9,10 +9,8 @@ import android.widget.TextView import androidx.cardview.widget.CardView import androidx.core.widget.ContentLoadingProgressBar import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.load.model.GlideUrl import com.lagradost.cloudstream3.R -import com.lagradost.cloudstream3.utils.IDisposable +import com.lagradost.cloudstream3.utils.UIHelper.setImage import com.lagradost.cloudstream3.utils.VideoDownloadHelper import kotlinx.android.synthetic.main.download_header_episode.view.* import java.util.* @@ -54,7 +52,7 @@ class DownloadHeaderAdapter( override fun onViewRecycled(holder: RecyclerView.ViewHolder) { if (holder is DownloadButtonViewHolder) { holder.downloadButton.dispose() - mBoundViewHolders.remove(holder); + mBoundViewHolders.remove(holder) } } @@ -93,7 +91,7 @@ class DownloadHeaderAdapter( ) : RecyclerView.ViewHolder(itemView), DownloadButtonViewHolder { override var downloadButton = EasyDownloadButton() - private val poster: ImageView = itemView.download_header_poster + private val poster: ImageView? = itemView.download_header_poster private val title: TextView = itemView.download_header_title private val extraInfo: TextView = itemView.download_header_info private val holder: CardView = itemView.episode_holder @@ -107,17 +105,8 @@ class DownloadHeaderAdapter( fun bind(card: VisualDownloadHeaderCached) { localCard = card val d = card.data - if (d.poster != null) { - val glideUrl = - GlideUrl(d.poster) - - poster.context.let { - Glide.with(it) - .load(glideUrl) - .into(poster) - } - } + poster?.setImage(d.poster) title.text = d.name val mbString = "%.1f".format(card.totalBytes / 1000000f) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/EasyDownloadButton.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/EasyDownloadButton.kt index 298cfb44..5515154a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/EasyDownloadButton.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/EasyDownloadButton.kt @@ -38,8 +38,8 @@ class EasyDownloadButton : IDisposable { clickCallback: (DownloadClickEvent) -> Unit, ) { setUpDownloadButton(setupCurrentBytes, setupTotalBytes, progressBar, textView, data, downloadButton, { - downloadButton?.setIconResource(it.first) - downloadButton?.text = it.second + downloadButton.setIconResource(it.first) + downloadButton.text = it.second }, clickCallback) } @@ -53,7 +53,7 @@ class EasyDownloadButton : IDisposable { clickCallback: (DownloadClickEvent) -> Unit, ) { setUpDownloadButton(setupCurrentBytes, setupTotalBytes, progressBar, textView, data, downloadImage, { - downloadImage?.setImageResource(it.first) + downloadImage.setImageResource(it.first) }, clickCallback) } @@ -98,20 +98,20 @@ class EasyDownloadButton : IDisposable { if (currentBytes == 0L) { changeDownloadImage(VideoDownloadManager.DownloadType.IsStopped) textView?.visibility = View.GONE - progressBar?.visibility = View.GONE + progressBar.visibility = View.GONE } else { if (lastState == VideoDownloadManager.DownloadType.IsStopped) { changeDownloadImage(VideoDownloadManager.getDownloadState(data.id)) } textView?.visibility = View.VISIBLE - progressBar?.visibility = View.VISIBLE + progressBar.visibility = View.VISIBLE val currentMbString = "%.1f".format(setCurrentBytes / 1000000f) val totalMbString = "%.1f".format(setTotalBytes / 1000000f) textView?.text = "${currentMbString}MB / ${totalMbString}MB" - progressBar?.let { bar -> + progressBar.let { bar -> bar.max = (setTotalBytes / 1000).toInt() if (animate) { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeChildItemAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeChildItemAdapter.kt index fe7b16cf..2f30c9ca 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeChildItemAdapter.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeChildItemAdapter.kt @@ -13,6 +13,7 @@ import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_LOAD import com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_SHOW_METADATA import com.lagradost.cloudstream3.ui.search.SearchClickCallback +import com.lagradost.cloudstream3.utils.UIHelper.setImage import kotlinx.android.synthetic.main.home_result_grid.view.* class HomeChildItemAdapter( @@ -72,16 +73,7 @@ class HomeChildItemAdapter( cardText.text = card.name //imageTextProvider.text = card.apiName - if (!card.posterUrl.isNullOrEmpty()) { - - val glideUrl = - GlideUrl(card.posterUrl) - - Glide.with(cardView.context) - .load(glideUrl) - .into(cardView) - - } + cardView.setImage(card.posterUrl) bg.setOnClickListener { clickCallback.invoke(SearchClickCallback(SEARCH_ACTION_LOAD, it, card)) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt index 78d3234d..83397c22 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt @@ -2,7 +2,6 @@ package com.lagradost.cloudstream3.ui.home import android.annotation.SuppressLint import android.app.Activity -import android.content.Context import android.content.Intent import android.content.res.Configuration import android.net.Uri @@ -16,15 +15,10 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.load.model.GlideUrl import com.google.android.material.bottomsheet.BottomSheetDialog import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.APIHolder.apis import com.lagradost.cloudstream3.MainActivity.Companion.backEvent -import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar -import com.lagradost.cloudstream3.utils.UIHelper.getGridIsCompact -import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.observe import com.lagradost.cloudstream3.ui.AutofitRecyclerView @@ -36,12 +30,15 @@ import com.lagradost.cloudstream3.ui.search.SearchAdapter import com.lagradost.cloudstream3.ui.search.SearchHelper.handleSearchClickCallback import com.lagradost.cloudstream3.utils.AppUtils.loadSearchResult import com.lagradost.cloudstream3.utils.DataStore.getKey -import com.lagradost.cloudstream3.utils.DataStore.removeKey import com.lagradost.cloudstream3.utils.DataStore.setKey import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultWatchState import com.lagradost.cloudstream3.utils.Event import com.lagradost.cloudstream3.utils.HOMEPAGE_API +import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar +import com.lagradost.cloudstream3.utils.UIHelper.getGridIsCompact import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIcons +import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes +import com.lagradost.cloudstream3.utils.UIHelper.setImage import kotlinx.android.synthetic.main.fragment_home.* const val HOME_BOOKMARK_VALUE = "home_bookmarked_last" @@ -148,18 +145,7 @@ class HomeFragment : Fragment() { home_main_text.text = random.name + if (random is AnimeSearchResponse) { random.dubStatus?.joinToString(prefix = " • ", separator = " | ") { it.name } } else "" - val glideUrl = - GlideUrl(random.posterUrl) - requireContext().let { - Glide.with(it) - .load(glideUrl) - .into(home_main_poster) -/* - Glide.with(it) - .load(glideUrl) - .apply(RequestOptions.bitmapTransform(BlurTransformation(80, 3))) - .into(result_poster_blur)*/ - } + home_main_poster?.setImage(random.posterUrl) toggleMainVisibility(true) return random diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerFragment.kt index a975703b..cf80cfe6 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerFragment.kt @@ -545,17 +545,17 @@ class PlayerFragment : Fragment() { val isAnime = data.isAnimeBased()//(data is AnimeLoadResponse && (data.type == TvType.Anime || data.type == TvType.ONA)) - skip_op.setVis(isAnime && !nextEp) + skip_op?.setVis(isAnime && !nextEp) skip_episode.setVis((!isAnime || nextEp) && hasNext) } else { val isAnime = data.isAnimeBased() if (isAnime) { - skip_op.setVis(true) + skip_op?.setVis(true) skip_episode.setVis(false) } else { skip_episode.setVis(data.isEpisodeBased()) - skip_op.setVis(false) + skip_op?.setVis(false) } } } @@ -684,7 +684,7 @@ class PlayerFragment : Fragment() { exo_progress.isClickable = isClick //next_episode_btt.isClickable = isClick playback_speed_btt.isClickable = isClick - skip_op.isClickable = isClick + skip_op?.isClickable = isClick skip_episode.isClickable = isClick resize_player.isClickable = isClick exo_progress.isEnabled = isClick @@ -1301,7 +1301,7 @@ class PlayerFragment : Fragment() { resize_player.visibility = GONE } - skip_op.setOnClickListener { + skip_op?.setOnClickListener { skipOP() } @@ -1787,7 +1787,7 @@ class PlayerFragment : Fragment() { } override fun onPlayerError(error: ExoPlaybackException) { - println("CURRENT URL: " + currentUrl?.url ?: uri) + println("CURRENT URL: " + currentUrl?.url) // Lets pray this doesn't spam Toasts :) when (error.type) { ExoPlaybackException.TYPE_SOURCE -> { @@ -1854,7 +1854,9 @@ class PlayerFragment : Fragment() { initPlayer(getCurrentUrl()) } } else { - Toast.makeText(context, "No Links Found", Toast.LENGTH_SHORT).show() + context?.let { ctx -> + Toast.makeText(ctx, "No Links Found", LENGTH_SHORT).show() + } } } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt index 9f4888e8..421cede6 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt @@ -1,7 +1,6 @@ package com.lagradost.cloudstream3.ui.result import android.annotation.SuppressLint -import android.view.Gravity import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -11,13 +10,12 @@ import android.widget.Toast import androidx.annotation.LayoutRes import androidx.core.widget.ContentLoadingProgressBar import androidx.recyclerview.widget.RecyclerView -import com.bumptech.glide.Glide -import com.bumptech.glide.load.model.GlideUrl import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD import com.lagradost.cloudstream3.ui.download.DownloadButtonViewHolder import com.lagradost.cloudstream3.ui.download.DownloadClickEvent import com.lagradost.cloudstream3.ui.download.EasyDownloadButton +import com.lagradost.cloudstream3.utils.UIHelper.setImage import com.lagradost.cloudstream3.utils.VideoDownloadHelper import com.lagradost.cloudstream3.utils.VideoDownloadManager import kotlinx.android.synthetic.main.result_episode.view.episode_holder @@ -71,7 +69,7 @@ class EpisodeAdapter( override fun onViewRecycled(holder: RecyclerView.ViewHolder) { if (holder is DownloadButtonViewHolder) { holder.downloadButton.dispose() - mBoundViewHolders.remove(holder); + mBoundViewHolders.remove(holder) } } @@ -152,13 +150,7 @@ class EpisodeAdapter( if (card.poster != null) { episodePoster?.visibility = View.VISIBLE - if (episodePoster != null) { - val glideUrl = - GlideUrl(card.poster) - Glide.with(episodePoster.context) - .load(glideUrl) - .into(episodePoster) - } + episodePoster?.setImage(card.poster) } else { episodePoster?.visibility = View.GONE } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt index d4a45a0e..2dea1a1d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt @@ -61,6 +61,7 @@ import com.lagradost.cloudstream3.utils.Coroutines.main import com.lagradost.cloudstream3.utils.DataStore.getFolderName import com.lagradost.cloudstream3.utils.DataStore.setKey import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos +import com.lagradost.cloudstream3.utils.UIHelper.setImage import com.lagradost.cloudstream3.utils.VideoDownloadManager.sanitizeFilename import jp.wasabeef.glide.transformations.BlurTransformation @@ -398,7 +399,7 @@ class ResultFragment : Fragment() { fun startChromecast(startIndex: Int) { val eps = currentEpisodes ?: return context?.startCast( - apiName ?: return, + apiName, currentIsMovie ?: return, currentHeaderName, currentPoster, @@ -850,19 +851,7 @@ class ResultFragment : Fragment() { } if (d.posterUrl != null) { - val glideUrl = - GlideUrl(d.posterUrl) - requireContext().let { - - Glide.with(it) - .load(glideUrl) - .into(result_poster) - - Glide.with(it) - .load(glideUrl) - .apply(bitmapTransform(BlurTransformation(80, 3))) - .into(result_poster_blur) - } + result_poster?.setImage(d.posterUrl) } if (d.plot != null) { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchAdaptor.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchAdaptor.kt index 9f8ed893..54c6ce9b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchAdaptor.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchAdaptor.kt @@ -19,6 +19,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.getGridFormatId import com.lagradost.cloudstream3.utils.UIHelper.getGridIsCompact import com.lagradost.cloudstream3.utils.UIHelper.toPx import com.lagradost.cloudstream3.ui.AutofitRecyclerView +import com.lagradost.cloudstream3.utils.UIHelper.setImage import kotlinx.android.synthetic.main.search_result_compact.view.backgroundCard import kotlinx.android.synthetic.main.search_result_compact.view.imageText import kotlinx.android.synthetic.main.search_result_compact.view.imageView @@ -104,15 +105,7 @@ class SearchAdapter( cardText.text = card.name //imageTextProvider.text = card.apiName - if (!card.posterUrl.isNullOrEmpty()) { - - val glideUrl = - GlideUrl(card.posterUrl) - - Glide.with(cardView.context) - .load(glideUrl) - .into(cardView) - } + cardView.setImage(card.posterUrl) bg.setOnClickListener { clickCallback.invoke(SearchClickCallback(SEARCH_ACTION_LOAD, it, card)) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt index cb71dc3b..7eda47f6 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt @@ -171,11 +171,11 @@ class SearchFragment : Fragment() { getString(if (isOn) R.string.search_provider_text_types else R.string.search_provider_text_providers) if (isOn) { - listView2?.visibility = View.VISIBLE - listView?.visibility = View.GONE + listView2.visibility = View.VISIBLE + listView.visibility = View.GONE } else { - listView?.visibility = View.VISIBLE - listView2?.visibility = View.GONE + listView.visibility = View.VISIBLE + listView2.visibility = View.GONE } } @@ -190,7 +190,7 @@ class SearchFragment : Fragment() { listView.setOnItemClickListener { _, _, i, _ -> val types = HashSet() for ((index, api) in apis.withIndex()) { - if (listView?.checkedItemPositions[index]) { + if (listView.checkedItemPositions[index]) { types.addAll(api.supportedTypes) } } @@ -204,14 +204,14 @@ class SearchFragment : Fragment() { var isSupported = false for ((typeIndex, type) in typeChoices.withIndex()) { - if (listView2?.checkedItemPositions[typeIndex]) { + if (listView2.checkedItemPositions[typeIndex]) { if (api.supportedTypes.any { type.second.contains(it) }) { isSupported = true } } } - listView?.setItemChecked( + listView.setItemChecked( index, isSupported ) @@ -221,7 +221,7 @@ class SearchFragment : Fragment() { } dialog.setOnDismissListener { - context?.setKey(SEARCH_PROVIDER_TOGGLE, toggle.isChecked ?: true) + context?.setKey(SEARCH_PROVIDER_TOGGLE, toggle.isChecked) } applyButton.setOnClickListener { @@ -229,7 +229,7 @@ class SearchFragment : Fragment() { val activeTypes = HashSet() for ((index, name) in typeChoices.withIndex()) { - if (listView2?.checkedItemPositions[index]) { + if (listView2.checkedItemPositions[index]) { activeTypes.addAll(typeChoices[index].second) } } @@ -241,7 +241,7 @@ class SearchFragment : Fragment() { val activeApis = HashSet() for ((index, name) in apiNames.withIndex()) { - if (listView?.checkedItemPositions[index]) { + if (listView.checkedItemPositions[index]) { activeApis.add(name) } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt index aaac8b89..d330ae94 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt @@ -8,17 +8,16 @@ import android.content.Context import android.content.pm.PackageManager import android.content.res.Resources import android.graphics.Color -import android.media.AudioAttributes -import android.media.AudioFocusRequest -import android.media.AudioManager import android.os.Build import android.view.Gravity import android.view.MenuItem import android.view.View import android.view.WindowManager import android.view.inputmethod.InputMethodManager +import android.widget.ImageView import androidx.annotation.AttrRes import androidx.annotation.ColorInt +import androidx.annotation.RequiresApi import androidx.appcompat.view.ContextThemeWrapper import androidx.appcompat.view.menu.MenuBuilder import androidx.appcompat.widget.PopupMenu @@ -31,6 +30,8 @@ import androidx.core.graphics.red import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.preference.PreferenceManager +import com.bumptech.glide.Glide +import com.bumptech.glide.load.model.GlideUrl import com.lagradost.cloudstream3.R import kotlin.math.roundToInt @@ -83,6 +84,17 @@ object UIHelper { return color } + fun ImageView?.setImage(url : String?) { + if(this == null || url.isNullOrBlank()) return + try { + Glide.with(this.context) + .load(GlideUrl(url)) + .into(this) + } catch (e : Exception) { + e.printStackTrace() + } + } + fun adjustAlpha(@ColorInt color: Int, factor: Float): Int { val alpha = (Color.alpha(color) * factor).roundToInt() val red = Color.red(color) @@ -243,6 +255,7 @@ object UIHelper { return settingsManager?.getBoolean("pip_enabled", true) ?: true && isInPlayer } + @RequiresApi(Build.VERSION_CODES.O) fun Context.hasPIPPermission(): Boolean { val appOps = getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadManager.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadManager.kt index f1a9cc5f..13b212f2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadManager.kt @@ -19,15 +19,14 @@ import androidx.core.net.toUri import com.bumptech.glide.Glide import com.lagradost.cloudstream3.MainActivity import com.lagradost.cloudstream3.R -import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.normalSafeApiCall import com.lagradost.cloudstream3.services.VideoDownloadService import com.lagradost.cloudstream3.utils.Coroutines.main -import com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread import com.lagradost.cloudstream3.utils.DataStore.getKey import com.lagradost.cloudstream3.utils.DataStore.removeKey import com.lagradost.cloudstream3.utils.DataStore.setKey +import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.withContext @@ -37,7 +36,6 @@ import java.net.URL import java.net.URLConnection import java.util.* - const val DOWNLOAD_CHANNEL_ID = "cloudstream3.general" const val DOWNLOAD_CHANNEL_NAME = "Downloads" const val DOWNLOAD_CHANNEL_DESCRIPT = "The download notification channel" @@ -180,18 +178,22 @@ object VideoDownloadManager { private val cachedBitmaps = hashMapOf() private fun Context.getImageBitmapFromUrl(url: String): Bitmap? { - if (cachedBitmaps.containsKey(url)) { - return cachedBitmaps[url] - } + try { + if (cachedBitmaps.containsKey(url)) { + return cachedBitmaps[url] + } - val bitmap = Glide.with(this) - .asBitmap() - .load(url).into(720, 720) - .get() - if (bitmap != null) { - cachedBitmaps[url] = bitmap + val bitmap = Glide.with(this) + .asBitmap() + .load(url).into(720, 720) + .get() + if (bitmap != null) { + cachedBitmaps[url] = bitmap + } + return null + } catch (e : Exception) { + return null } - return null } private fun createNotification( diff --git a/app/src/main/java/com/lagradost/cloudstream3/widget/FlowLayout.kt b/app/src/main/java/com/lagradost/cloudstream3/widget/FlowLayout.kt index 892701f6..4e8097cf 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/widget/FlowLayout.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/widget/FlowLayout.kt @@ -8,11 +8,10 @@ import com.lagradost.cloudstream3.R import kotlin.math.max class FlowLayout : ViewGroup { - constructor(context: Context?) : super(context) {} + constructor(context: Context?) : super(context) @JvmOverloads - constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int = 0) : super(context, attrs, defStyleAttr) { - } + constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int = 0) : super(context, attrs, defStyleAttr) override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val realWidth = MeasureSpec.getSize(widthMeasureSpec) @@ -92,7 +91,7 @@ class FlowLayout : ViewGroup { spacing = 0 } - constructor(source: MarginLayoutParams?) : super(source) {} - internal constructor(source: ViewGroup.LayoutParams?) : super(source) {} + constructor(source: MarginLayoutParams?) : super(source) + internal constructor(source: ViewGroup.LayoutParams?) : super(source) } } \ No newline at end of file