mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
59b5732925
97 changed files with 570 additions and 237 deletions
|
@ -376,6 +376,32 @@ data class ProvidersInfoJson(
|
||||||
@JsonProperty("status") var status: Int,
|
@JsonProperty("status") var status: Int,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
data class MainPageData(
|
||||||
|
val name: String,
|
||||||
|
val data: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
/** return list of MainPageData with url to name, make for more readable code */
|
||||||
|
fun mainPageOf(vararg elements: Pair<String, String>): List<MainPageData> {
|
||||||
|
return elements.map { (url, name) -> MainPageData(name = name, data = url) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun newHomePageResponse(
|
||||||
|
name: String,
|
||||||
|
list: List<SearchResponse>,
|
||||||
|
hasNext: Boolean? = null
|
||||||
|
): HomePageResponse {
|
||||||
|
return HomePageResponse(
|
||||||
|
listOf(HomePageList(name, list)),
|
||||||
|
hasNext = hasNext ?: list.isNotEmpty()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun newHomePageResponse(list: HomePageList, hasNext: Boolean? = null): HomePageResponse {
|
||||||
|
return HomePageResponse(listOf(list), hasNext = hasNext ?: list.list.isNotEmpty())
|
||||||
|
}
|
||||||
|
|
||||||
/**Every provider will **not** have try catch built in, so handle exceptions when calling these functions*/
|
/**Every provider will **not** have try catch built in, so handle exceptions when calling these functions*/
|
||||||
abstract class MainAPI {
|
abstract class MainAPI {
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -431,8 +457,14 @@ abstract class MainAPI {
|
||||||
open val vpnStatus = VPNStatus.None
|
open val vpnStatus = VPNStatus.None
|
||||||
open val providerType = ProviderType.DirectProvider
|
open val providerType = ProviderType.DirectProvider
|
||||||
|
|
||||||
|
open val mainPage = listOf(MainPageData("", ""))
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
open suspend fun getMainPage(): HomePageResponse? {
|
open suspend fun getMainPage(
|
||||||
|
page: Int,
|
||||||
|
categoryName: String,
|
||||||
|
categoryData: String
|
||||||
|
): HomePageResponse? {
|
||||||
throw NotImplementedError()
|
throw NotImplementedError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,7 +664,8 @@ fun TvType.isAnimeOp(): Boolean {
|
||||||
data class SubtitleFile(val lang: String, val url: String)
|
data class SubtitleFile(val lang: String, val url: String)
|
||||||
|
|
||||||
data class HomePageResponse(
|
data class HomePageResponse(
|
||||||
val items: List<HomePageList>
|
val items: List<HomePageList>,
|
||||||
|
val hasNext: Boolean = false
|
||||||
)
|
)
|
||||||
|
|
||||||
data class HomePageList(
|
data class HomePageList(
|
||||||
|
|
|
@ -104,7 +104,7 @@ class AllAnimeProvider : MainAPI() {
|
||||||
@JsonProperty("__typename") val _typename: String? = null
|
@JsonProperty("__typename") val _typename: String? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
// Pair(
|
// Pair(
|
||||||
|
|
|
@ -114,7 +114,7 @@ class AniPlayProvider : MainAPI() {
|
||||||
@JsonProperty("videoUrl") val url: String
|
@JsonProperty("videoUrl") val url: String
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val response = app.get("$mainUrl/api/home/latest-episodes?page=0").parsed<List<ApiMainPageAnime>>()
|
val response = app.get("$mainUrl/api/home/latest-episodes?page=0").parsed<List<ApiMainPageAnime>>()
|
||||||
|
|
||||||
val results = response.map{
|
val results = response.map{
|
||||||
|
|
|
@ -3,7 +3,6 @@ package com.lagradost.cloudstream3.animeproviders
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
|
||||||
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 java.net.URLDecoder
|
import java.net.URLDecoder
|
||||||
|
@ -45,7 +44,7 @@ class AniflixProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val soup = app.get(mainUrl).document
|
val soup = app.get(mainUrl).document
|
||||||
val elements = listOf(
|
val elements = listOf(
|
||||||
|
@ -75,7 +74,6 @@ class AniflixProvider : MainAPI() {
|
||||||
val token = getToken()
|
val token = getToken()
|
||||||
val url = "$mainUrl/_next/data/$token/search.json?keyword=$query"
|
val url = "$mainUrl/_next/data/$token/search.json?keyword=$query"
|
||||||
val response = app.get(url)
|
val response = app.get(url)
|
||||||
println("resp: $url ===> ${response.text}")
|
|
||||||
val searchResponse =
|
val searchResponse =
|
||||||
response.parsedSafe<Search>()
|
response.parsedSafe<Search>()
|
||||||
?: throw ErrorLoadingException("No Media")
|
?: throw ErrorLoadingException("No Media")
|
||||||
|
|
|
@ -62,7 +62,7 @@ class AnimeIndoProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = request(mainUrl).document
|
val document = request(mainUrl).document
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -58,7 +58,7 @@ class AnimePaheProvider : MainAPI() {
|
||||||
TvType.OVA
|
TvType.OVA
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
data class Data(
|
data class Data(
|
||||||
@JsonProperty("id") val id: Int,
|
@JsonProperty("id") val id: Int,
|
||||||
@JsonProperty("anime_id") val animeId: Int,
|
@JsonProperty("anime_id") val animeId: Int,
|
||||||
|
|
|
@ -47,7 +47,7 @@ class AnimeSailProvider : MainAPI() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = request(mainUrl).document
|
val document = request(mainUrl).document
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -64,7 +64,7 @@ class AnimeSaturnProvider : MainAPI() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
val list = ArrayList<HomePageList>()
|
val list = ArrayList<HomePageList>()
|
||||||
document.select("div.container:has(span.badge-saturn)").forEach {
|
document.select("div.container:has(span.badge-saturn)").forEach {
|
||||||
|
|
|
@ -130,7 +130,7 @@ class AnimeWorldProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = request(mainUrl).document
|
val document = request(mainUrl).document
|
||||||
val list = ArrayList<HomePageList>()
|
val list = ArrayList<HomePageList>()
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ class AnimefenixProvider:MainAPI() {
|
||||||
else DubStatus.Subbed
|
else DubStatus.Subbed
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/", "Animes"),
|
Pair("$mainUrl/", "Animes"),
|
||||||
Pair("$mainUrl/animes?type[]=movie&order=default", "Peliculas", ),
|
Pair("$mainUrl/animes?type[]=movie&order=default", "Peliculas", ),
|
||||||
|
|
|
@ -22,7 +22,7 @@ class AnimeflvIOProvider:MainAPI() {
|
||||||
TvType.OVA,
|
TvType.OVA,
|
||||||
TvType.Anime,
|
TvType.Anime,
|
||||||
)
|
)
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/series", "Series actualizadas",),
|
Pair("$mainUrl/series", "Series actualizadas",),
|
||||||
|
|
|
@ -34,7 +34,7 @@ class AnimeflvnetProvider : MainAPI() {
|
||||||
TvType.Anime,
|
TvType.Anime,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/browse?type[]=movie&order=updated", "Películas"),
|
Pair("$mainUrl/browse?type[]=movie&order=updated", "Películas"),
|
||||||
Pair("$mainUrl/browse?status[]=2&order=default", "Animes"),
|
Pair("$mainUrl/browse?status[]=2&order=default", "Animes"),
|
||||||
|
|
|
@ -26,7 +26,7 @@ class AnimekisaProvider : MainAPI() {
|
||||||
@JsonProperty("html") val html: String
|
@JsonProperty("html") val html: String
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/ajax/list/views?type=all", "All animes"),
|
Pair("$mainUrl/ajax/list/views?type=all", "All animes"),
|
||||||
Pair("$mainUrl/ajax/list/views?type=day", "Trending now"),
|
Pair("$mainUrl/ajax/list/views?type=day", "Trending now"),
|
||||||
|
|
|
@ -96,7 +96,7 @@ class DubbedAnimeProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val trendingUrl = "$mainUrl/xz/trending.php?_=$unixTimeMS"
|
val trendingUrl = "$mainUrl/xz/trending.php?_=$unixTimeMS"
|
||||||
val lastEpisodeUrl = "$mainUrl/xz/epgrid.php?p=1&_=$unixTimeMS"
|
val lastEpisodeUrl = "$mainUrl/xz/epgrid.php?p=1&_=$unixTimeMS"
|
||||||
val recentlyAddedUrl = "$mainUrl/xz/gridgrabrecent.php?p=1&_=$unixTimeMS"
|
val recentlyAddedUrl = "$mainUrl/xz/gridgrabrecent.php?p=1&_=$unixTimeMS"
|
||||||
|
|
|
@ -178,7 +178,7 @@ class GogoanimeProvider : MainAPI() {
|
||||||
TvType.OVA
|
TvType.OVA
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val headers = mapOf(
|
val headers = mapOf(
|
||||||
"authority" to "ajax.gogo-load.com",
|
"authority" to "ajax.gogo-load.com",
|
||||||
"sec-ch-ua" to "\"Google Chrome\";v=\"89\", \"Chromium\";v=\"89\", \";Not A Brand\";v=\"99\"",
|
"sec-ch-ua" to "\"Google Chrome\";v=\"89\", \"Chromium\";v=\"89\", \";Not A Brand\";v=\"99\"",
|
||||||
|
|
|
@ -46,7 +46,7 @@ class GomunimeProvider : MainAPI() {
|
||||||
@JsonProperty("html") val html: String
|
@JsonProperty("html") val html: String
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("e", "Episode Baru"),
|
Pair("e", "Episode Baru"),
|
||||||
Pair("c", "Completed"),
|
Pair("c", "Completed"),
|
||||||
|
|
|
@ -32,7 +32,7 @@ class JKAnimeProvider : MainAPI() {
|
||||||
TvType.Anime,
|
TvType.Anime,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair(
|
Pair(
|
||||||
"$mainUrl/directorio/?filtro=fecha&tipo=TV&estado=1&fecha=none&temporada=none&orden=desc",
|
"$mainUrl/directorio/?filtro=fecha&tipo=TV&estado=1&fecha=none&temporada=none&orden=desc",
|
||||||
|
|
|
@ -14,7 +14,7 @@ class KawaiifuProvider : MainAPI() {
|
||||||
|
|
||||||
override val supportedTypes = setOf(TvType.Anime, TvType.AnimeMovie)
|
override val supportedTypes = setOf(TvType.Anime, TvType.AnimeMovie)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val resp = app.get(mainUrl).text
|
val resp = app.get(mainUrl).text
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ class KimCartoonProvider : MainAPI() {
|
||||||
return if (url.startsWith("/")) mainUrl + url else url
|
return if (url.startsWith("/")) mainUrl + url else url
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val doc = app.get(mainUrl).document.select("#container")
|
val doc = app.get(mainUrl).document.select("#container")
|
||||||
val response = mutableListOf(
|
val response = mutableListOf(
|
||||||
HomePageList(
|
HomePageList(
|
||||||
|
|
|
@ -38,7 +38,7 @@ class KuramanimeProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -39,7 +39,7 @@ class KuronimeProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -34,7 +34,7 @@ class MonoschinosProvider : MainAPI() {
|
||||||
TvType.Anime,
|
TvType.Anime,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/emision", "En emisión"),
|
Pair("$mainUrl/emision", "En emisión"),
|
||||||
Pair(
|
Pair(
|
||||||
|
|
|
@ -23,7 +23,7 @@ class MundoDonghuaProvider : MainAPI() {
|
||||||
TvType.Anime,
|
TvType.Anime,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/lista-donghuas", "Donghuas"),
|
Pair("$mainUrl/lista-donghuas", "Donghuas"),
|
||||||
)
|
)
|
||||||
|
|
|
@ -40,7 +40,7 @@ class NeonimeProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -137,17 +137,21 @@ class NineAnimeProvider : MainAPI() {
|
||||||
private fun decode(input: String): String = java.net.URLDecoder.decode(input, "utf-8")
|
private fun decode(input: String): String = java.net.URLDecoder.decode(input, "utf-8")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override val mainPage = mainPageOf(
|
||||||
val items = listOf(
|
"$mainUrl/ajax/home/widget/trending?page=" to "Trending",
|
||||||
"$mainUrl/ajax/home/widget/trending?page=1" to "Trending",
|
"$mainUrl/ajax/home/widget/updated-all?page=" to "All",
|
||||||
"$mainUrl/ajax/home/widget/updated-all?page=1" to "All",
|
"$mainUrl/ajax/home/widget/updated-sub?page=" to "Recently Updated (SUB)",
|
||||||
"$mainUrl/ajax/home/widget/updated-sub?page=1" to "Recently Updated (SUB)",
|
"$mainUrl/ajax/home/widget/updated-dub?page=" to "Recently Updated (DUB)",
|
||||||
"$mainUrl/ajax/home/widget/updated-dub?page=1" to
|
"$mainUrl/ajax/home/widget/updated-china?page=" to "Recently Updated (Chinese)",
|
||||||
"Recently Updated (DUB)",
|
"$mainUrl/ajax/home/widget/random?page=" to "Random",
|
||||||
"$mainUrl/ajax/home/widget/updated-china?page=1" to
|
)
|
||||||
"Recently Updated (Chinese)",
|
|
||||||
"$mainUrl/ajax/home/widget/random?page=1" to "Random",
|
override suspend fun getMainPage(
|
||||||
).apmap { (url, name) ->
|
page: Int,
|
||||||
|
categoryName: String,
|
||||||
|
categoryData: String
|
||||||
|
): HomePageResponse {
|
||||||
|
val url = categoryData + page
|
||||||
val home = Jsoup.parse(
|
val home = Jsoup.parse(
|
||||||
app.get(
|
app.get(
|
||||||
url
|
url
|
||||||
|
@ -171,10 +175,7 @@ class NineAnimeProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HomePageList(name, home)
|
return newHomePageResponse(categoryName, home)
|
||||||
}
|
|
||||||
|
|
||||||
return HomePageResponse(items)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Response(
|
data class Response(
|
||||||
|
|
|
@ -40,7 +40,7 @@ class NontonAnimeIDProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -40,7 +40,7 @@ class OploverzProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -38,7 +38,7 @@ class OtakudesuProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -44,7 +44,7 @@ class TenshiProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val soup = app.get(mainUrl, interceptor = ddosGuardKiller).document
|
val soup = app.get(mainUrl, interceptor = ddosGuardKiller).document
|
||||||
for (section in soup.select("#content > section")) {
|
for (section in soup.select("#content > section")) {
|
||||||
|
|
|
@ -39,7 +39,7 @@ class TocanimeProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -30,7 +30,7 @@ class WcoProvider : MainAPI() {
|
||||||
TvType.OVA
|
TvType.OVA
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/ajax/list/recently_updated?type=tv", "Recently Updated Anime"),
|
Pair("$mainUrl/ajax/list/recently_updated?type=tv", "Recently Updated Anime"),
|
||||||
Pair("$mainUrl/ajax/list/recently_updated?type=movie", "Recently Updated Movies"),
|
Pair("$mainUrl/ajax/list/recently_updated?type=movie", "Recently Updated Movies"),
|
||||||
|
|
|
@ -77,7 +77,7 @@ class ZoroProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val html = app.get("$mainUrl/home").text
|
val html = app.get("$mainUrl/home").text
|
||||||
val document = Jsoup.parse(html)
|
val document = Jsoup.parse(html)
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ class EjaTv : MainAPI() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
// Maybe this based on app language or as setting?
|
// Maybe this based on app language or as setting?
|
||||||
val language = "English"
|
val language = "English"
|
||||||
val dataMap = mapOf(
|
val dataMap = mapOf(
|
||||||
|
|
|
@ -196,7 +196,7 @@ open class TmdbProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
|
|
||||||
// SAME AS DISCOVER IT SEEMS
|
// SAME AS DISCOVER IT SEEMS
|
||||||
// val popularSeries = tmdb.tvService().popular(1, "en-US").execute().body()?.results?.map {
|
// val popularSeries = tmdb.tvService().popular(1, "en-US").execute().body()?.results?.map {
|
||||||
|
|
|
@ -34,7 +34,7 @@ class AkwamProvider : MainAPI() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
// Title, Url
|
// Title, Url
|
||||||
val moviesUrl = listOf(
|
val moviesUrl = listOf(
|
||||||
"Movies" to "$mainUrl/movies",
|
"Movies" to "$mainUrl/movies",
|
||||||
|
|
|
@ -27,7 +27,7 @@ class AllMoviesForYouProvider : MainAPI() {
|
||||||
TvType.TvSeries
|
TvType.TvSeries
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val soup = app.get(mainUrl).document
|
val soup = app.get(mainUrl).document
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
|
|
|
@ -18,7 +18,7 @@ class AltadefinizioneProvider : MainAPI() {
|
||||||
TvType.Movie
|
TvType.Movie
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/azione/", "Azione"),
|
Pair("$mainUrl/azione/", "Azione"),
|
||||||
|
|
|
@ -110,7 +110,7 @@ class AsiaFlixProvider : MainAPI() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val headers = mapOf("X-Requested-By" to "asiaflix-web")
|
val headers = mapOf("X-Requested-By" to "asiaflix-web")
|
||||||
val response = app.get("$apiUrl/dashboard", headers = headers).text
|
val response = app.get("$apiUrl/dashboard", headers = headers).text
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ open class BflixProvider : MainAPI() {
|
||||||
|
|
||||||
//override val uniqueId: Int by lazy { "BflixProvider".hashCode() }
|
//override val uniqueId: Int by lazy { "BflixProvider".hashCode() }
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val soup = app.get("$mainUrl/home").document
|
val soup = app.get("$mainUrl/home").document
|
||||||
val testa = listOf(
|
val testa = listOf(
|
||||||
|
|
|
@ -41,7 +41,7 @@ class CimaNowProvider : MainAPI() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
|
|
||||||
val doc = app.get("$mainUrl/home", headers = mapOf("user-agent" to "MONKE")).document
|
val doc = app.get("$mainUrl/home", headers = mapOf("user-agent" to "MONKE")).document
|
||||||
val pages = doc.select("section").not("section:contains(أختر وجهتك المفضلة)").not("section:contains(تم اضافته حديثاً)").apmap {
|
val pages = doc.select("section").not("section:contains(أختر وجهتك المفضلة)").not("section:contains(تم اضافته حديثاً)").apmap {
|
||||||
|
|
|
@ -17,7 +17,7 @@ class CineblogProvider : MainAPI() {
|
||||||
TvType.TvSeries,
|
TvType.TvSeries,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/genere/azione/", "Azione"),
|
Pair("$mainUrl/genere/azione/", "Azione"),
|
||||||
|
|
|
@ -19,7 +19,7 @@ class CinecalidadProvider : MainAPI() {
|
||||||
)
|
)
|
||||||
override val vpnStatus = VPNStatus.MightBeNeeded //Due to evoload sometimes not loading
|
override val vpnStatus = VPNStatus.MightBeNeeded //Due to evoload sometimes not loading
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/ver-serie/", "Series"),
|
Pair("$mainUrl/ver-serie/", "Series"),
|
||||||
|
|
|
@ -19,7 +19,7 @@ class CuevanaProvider : MainAPI() {
|
||||||
TvType.TvSeries,
|
TvType.TvSeries,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair(mainUrl, "Recientemente actualizadas"),
|
Pair(mainUrl, "Recientemente actualizadas"),
|
||||||
|
|
|
@ -31,7 +31,7 @@ class DoramasYTProvider : MainAPI() {
|
||||||
TvType.AsianDrama,
|
TvType.AsianDrama,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/emision", "En emisión"),
|
Pair("$mainUrl/emision", "En emisión"),
|
||||||
Pair(
|
Pair(
|
||||||
|
|
|
@ -14,7 +14,7 @@ class DramaSeeProvider : MainAPI() {
|
||||||
override val hasDownloadSupport = true
|
override val hasDownloadSupport = true
|
||||||
override val supportedTypes = setOf(TvType.AsianDrama)
|
override val supportedTypes = setOf(TvType.AsianDrama)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val headers = mapOf("X-Requested-By" to mainUrl)
|
val headers = mapOf("X-Requested-By" to mainUrl)
|
||||||
val document = app.get(mainUrl, headers = headers).document
|
val document = app.get(mainUrl, headers = headers).document
|
||||||
val mainbody = document.getElementsByTag("body")
|
val mainbody = document.getElementsByTag("body")
|
||||||
|
|
|
@ -30,7 +30,7 @@ class DramaidProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -41,7 +41,7 @@ class EgyBestProvider : MainAPI() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
// url, title
|
// url, title
|
||||||
val doc = app.get(mainUrl).document
|
val doc = app.get(mainUrl).document
|
||||||
val pages = arrayListOf<HomePageList>()
|
val pages = arrayListOf<HomePageList>()
|
||||||
|
|
|
@ -15,7 +15,7 @@ class ElifilmsProvider : MainAPI() {
|
||||||
TvType.Movie,
|
TvType.Movie,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val newest = app.get(mainUrl).document.selectFirst("a.fav_link.premiera")?.attr("href")
|
val newest = app.get(mainUrl).document.selectFirst("a.fav_link.premiera")?.attr("href")
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
|
|
|
@ -18,7 +18,7 @@ class EntrepeliculasyseriesProvider:MainAPI() {
|
||||||
)
|
)
|
||||||
override val vpnStatus = VPNStatus.MightBeNeeded //Due to evoload sometimes not loading
|
override val vpnStatus = VPNStatus.MightBeNeeded //Due to evoload sometimes not loading
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/series/", "Series"),
|
Pair("$mainUrl/series/", "Series"),
|
||||||
|
|
|
@ -28,7 +28,7 @@ class EstrenosDoramasProvider : MainAPI() {
|
||||||
TvType.AsianDrama,
|
TvType.AsianDrama,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair(mainUrl, "Últimas series"),
|
Pair(mainUrl, "Últimas series"),
|
||||||
Pair("$mainUrl/category/peliculas", "Películas"),
|
Pair("$mainUrl/category/peliculas", "Películas"),
|
||||||
|
|
|
@ -35,7 +35,7 @@ class FaselHDProvider : MainAPI() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
// Title, Url
|
// Title, Url
|
||||||
val moviesUrl = listOf(
|
val moviesUrl = listOf(
|
||||||
Pair("Movies", "$mainUrl/all-movies/page/"+(0..10).random()),
|
Pair("Movies", "$mainUrl/all-movies/page/"+(0..10).random()),
|
||||||
|
|
|
@ -18,7 +18,7 @@ class FilmanProvider : MainAPI() {
|
||||||
TvType.TvSeries
|
TvType.TvSeries
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
val lists = document.select("#item-list,#series-list")
|
val lists = document.select("#item-list,#series-list")
|
||||||
val categories = ArrayList<HomePageList>()
|
val categories = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -23,7 +23,7 @@ class FilmpertuttiProvider : MainAPI() {
|
||||||
TvType.TvSeries
|
TvType.TvSeries
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/category/serie-tv/", "Serie Tv"),
|
Pair("$mainUrl/category/serie-tv/", "Serie Tv"),
|
||||||
|
|
|
@ -232,7 +232,7 @@ class FrenchStreamProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse? {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse? {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
val docs = document.select("div.sect")
|
val docs = document.select("div.sect")
|
||||||
val returnList = docs.mapNotNull {
|
val returnList = docs.mapNotNull {
|
||||||
|
|
|
@ -69,7 +69,7 @@ class HDMProvider : MainAPI() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val html = app.get(mainUrl, timeout = 25).text
|
val html = app.get(mainUrl, timeout = 25).text
|
||||||
val document = Jsoup.parse(html)
|
val document = Jsoup.parse(html)
|
||||||
val all = ArrayList<HomePageList>()
|
val all = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -19,7 +19,7 @@ class HDMovie5 : MainAPI() {
|
||||||
TvType.TvSeries,
|
TvType.TvSeries,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val doc = app.get(mainUrl).document.select("div.content")
|
val doc = app.get(mainUrl).document.select("div.content")
|
||||||
val list = mapOf(
|
val list = mapOf(
|
||||||
"Featured Movies" to "featured",
|
"Featured Movies" to "featured",
|
||||||
|
|
|
@ -28,7 +28,7 @@ class HDrezkaProvider : MainAPI() {
|
||||||
TvType.AsianDrama
|
TvType.AsianDrama
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
|
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ class IHaveNoTvProvider : MainAPI() {
|
||||||
|
|
||||||
override val supportedTypes = setOf(TvType.Documentary)
|
override val supportedTypes = setOf(TvType.Documentary)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
// Uhh, I am too lazy to scrape the "latest documentaries" and "recommended documentaries",
|
// Uhh, I am too lazy to scrape the "latest documentaries" and "recommended documentaries",
|
||||||
// so I am just scraping 3 random categories
|
// so I am just scraping 3 random categories
|
||||||
val allCategories = listOf(
|
val allCategories = listOf(
|
||||||
|
|
|
@ -22,7 +22,7 @@ class IdlixProvider : MainAPI() {
|
||||||
TvType.TvSeries,
|
TvType.TvSeries,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -26,7 +26,7 @@ class KdramaHoodProvider : MainAPI() {
|
||||||
@JsonProperty("file") val file: String
|
@JsonProperty("file") val file: String
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val doc = app.get("$mainUrl/home2").document
|
val doc = app.get("$mainUrl/home2").document
|
||||||
val home = ArrayList<HomePageList>()
|
val home = ArrayList<HomePageList>()
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ class LayarKacaProvider : MainAPI() {
|
||||||
TvType.AsianDrama
|
TvType.AsianDrama
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -22,7 +22,7 @@ class MultiplexProvider : MainAPI() {
|
||||||
TvType.AsianDrama
|
TvType.AsianDrama
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -44,7 +44,7 @@ class MyCimaProvider : MainAPI() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
// Title, Url
|
// Title, Url
|
||||||
val moviesUrl = listOf(
|
val moviesUrl = listOf(
|
||||||
"Movies" to "$mainUrl/movies/page/" + (0..25).random(),
|
"Movies" to "$mainUrl/movies/page/" + (0..25).random(),
|
||||||
|
|
|
@ -212,7 +212,7 @@ class NginxProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val authHeader =
|
val authHeader =
|
||||||
getAuthHeader() // call again because it isn't reloaded if in main class and storedCredentials loads after
|
getAuthHeader() // call again because it isn't reloaded if in main class and storedCredentials loads after
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ class PeliSmartProvider: MainAPI() {
|
||||||
)
|
)
|
||||||
override val vpnStatus = VPNStatus.MightBeNeeded //Due to evoload sometimes not loading
|
override val vpnStatus = VPNStatus.MightBeNeeded //Due to evoload sometimes not loading
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/peliculas/", "Peliculas"),
|
Pair("$mainUrl/peliculas/", "Peliculas"),
|
||||||
|
|
|
@ -18,7 +18,7 @@ class PelisflixProvider : MainAPI() {
|
||||||
TvType.TvSeries,
|
TvType.TvSeries,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/ver-peliculas-online-gratis-fullhdc3/", "Películas"),
|
Pair("$mainUrl/ver-peliculas-online-gratis-fullhdc3/", "Películas"),
|
||||||
|
|
|
@ -16,7 +16,7 @@ class PelisplusHDProvider:MainAPI() {
|
||||||
TvType.Movie,
|
TvType.Movie,
|
||||||
TvType.TvSeries,
|
TvType.TvSeries,
|
||||||
)
|
)
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
val map = mapOf(
|
val map = mapOf(
|
||||||
|
|
|
@ -142,7 +142,7 @@ open class PelisplusProviderTemplate : MainAPI() {
|
||||||
|
|
||||||
// This loads the homepage, which is basically a collection of search results with labels.
|
// This loads the homepage, which is basically a collection of search results with labels.
|
||||||
// Optional function, but make sure to enable hasMainPage if you program this.
|
// Optional function, but make sure to enable hasMainPage if you program this.
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val urls = homePageUrlList
|
val urls = homePageUrlList
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
// .pmap {} is used to fetch the different pages in parallel
|
// .pmap {} is used to fetch the different pages in parallel
|
||||||
|
|
|
@ -23,7 +23,7 @@ class PhimmoichillProvider : MainAPI() {
|
||||||
TvType.AsianDrama
|
TvType.AsianDrama
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -15,7 +15,7 @@ class PinoyHDXyzProvider : MainAPI() {
|
||||||
override val hasMainPage = true
|
override val hasMainPage = true
|
||||||
override val hasQuickSearch = false
|
override val hasQuickSearch = false
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val all = ArrayList<HomePageList>()
|
val all = ArrayList<HomePageList>()
|
||||||
val document = app.get(mainUrl, referer = mainUrl).document
|
val document = app.get(mainUrl, referer = mainUrl).document
|
||||||
val mainbody = document.getElementsByTag("body")
|
val mainbody = document.getElementsByTag("body")
|
||||||
|
|
|
@ -16,7 +16,7 @@ class PinoyMoviePediaProvider : MainAPI() {
|
||||||
override val hasMainPage = true
|
override val hasMainPage = true
|
||||||
override val hasQuickSearch = false
|
override val hasQuickSearch = false
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val all = ArrayList<HomePageList>()
|
val all = ArrayList<HomePageList>()
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
val mainbody = document.getElementsByTag("body")
|
val mainbody = document.getElementsByTag("body")
|
||||||
|
|
|
@ -90,7 +90,7 @@ class PinoyMoviesEsProvider : MainAPI() {
|
||||||
return all
|
return all
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val all = ArrayList<HomePageList>()
|
val all = ArrayList<HomePageList>()
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
val mainbody = document.getElementsByTag("body")
|
val mainbody = document.getElementsByTag("body")
|
||||||
|
|
|
@ -27,7 +27,7 @@ class RebahinProvider : MainAPI() {
|
||||||
TvType.AsianDrama
|
TvType.AsianDrama
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("Featured", "xtab1"),
|
Pair("Featured", "xtab1"),
|
||||||
Pair("Film Terbaru", "xtab2"),
|
Pair("Film Terbaru", "xtab2"),
|
||||||
|
|
|
@ -18,7 +18,7 @@ class SeriesflixProvider : MainAPI() {
|
||||||
TvType.TvSeries,
|
TvType.TvSeries,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/ver-series-online/", "Series"),
|
Pair("$mainUrl/ver-series-online/", "Series"),
|
||||||
|
|
|
@ -43,7 +43,7 @@ open class SflixProvider : MainAPI() {
|
||||||
)
|
)
|
||||||
override val vpnStatus = VPNStatus.None
|
override val vpnStatus = VPNStatus.None
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val html = app.get("$mainUrl/home").text
|
val html = app.get("$mainUrl/home").text
|
||||||
val document = Jsoup.parse(html)
|
val document = Jsoup.parse(html)
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ class SoaptwoDayProvider : MainAPI() {
|
||||||
TvType.TvSeries,
|
TvType.TvSeries,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/movielist/", "Movies"),
|
Pair("$mainUrl/movielist/", "Movies"),
|
||||||
|
|
|
@ -174,7 +174,7 @@ class StreamingcommunityProvider : MainAPI() {
|
||||||
val posterMap = hashMapOf<String, String>()
|
val posterMap = hashMapOf<String, String>()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
document.select("slider-title").subList(0, 6).map { it ->
|
document.select("slider-title").subList(0, 6).map { it ->
|
||||||
|
|
|
@ -18,7 +18,7 @@ class TantifilmProvider : MainAPI() {
|
||||||
TvType.TvSeries,
|
TvType.TvSeries,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val urls = listOf(
|
val urls = listOf(
|
||||||
Pair("$mainUrl/watch-genre/serie-tv/", "Serie Tv"),
|
Pair("$mainUrl/watch-genre/serie-tv/", "Serie Tv"),
|
||||||
|
|
|
@ -143,7 +143,7 @@ class TheFlixToProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val items = ArrayList<HomePageList>()
|
val items = ArrayList<HomePageList>()
|
||||||
val doc = app.get(mainUrl).document
|
val doc = app.get(mainUrl).document
|
||||||
val scriptText = doc.selectFirst("script[type=application/json]")!!.data()
|
val scriptText = doc.selectFirst("script[type=application/json]")!!.data()
|
||||||
|
|
|
@ -23,7 +23,7 @@ class UakinoProvider : MainAPI() {
|
||||||
TvType.Anime
|
TvType.Anime
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -210,7 +210,7 @@ open class VidstreamProviderTemplate : MainAPI() {
|
||||||
|
|
||||||
// This loads the homepage, which is basically a collection of search results with labels.
|
// This loads the homepage, which is basically a collection of search results with labels.
|
||||||
// Optional function, but make sure to enable hasMainPage if you program this.
|
// Optional function, but make sure to enable hasMainPage if you program this.
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val urls = homePageUrlList
|
val urls = homePageUrlList
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
// .pmap {} is used to fetch the different pages in parallel
|
// .pmap {} is used to fetch the different pages in parallel
|
||||||
|
|
|
@ -18,7 +18,7 @@ class WatchAsianProvider : MainAPI() {
|
||||||
override val hasDownloadSupport = true
|
override val hasDownloadSupport = true
|
||||||
override val supportedTypes = setOf(TvType.AsianDrama)
|
override val supportedTypes = setOf(TvType.AsianDrama)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val headers = mapOf("X-Requested-By" to mainUrl)
|
val headers = mapOf("X-Requested-By" to mainUrl)
|
||||||
val doc = app.get(mainUrl, headers = headers).document
|
val doc = app.get(mainUrl, headers = headers).document
|
||||||
val rowPair = mutableListOf<Pair<String, String>>()
|
val rowPair = mutableListOf<Pair<String, String>>()
|
||||||
|
|
|
@ -2,7 +2,6 @@ package com.lagradost.cloudstream3.movieproviders
|
||||||
|
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.Qualities
|
import com.lagradost.cloudstream3.utils.Qualities
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
|
@ -41,7 +40,7 @@ class XcineProvider : MainAPI() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
val sections = document.select("div.group-film")
|
val sections = document.select("div.group-film")
|
||||||
return HomePageResponse(sections.mapNotNull { section ->
|
return HomePageResponse(sections.mapNotNull { section ->
|
||||||
|
|
|
@ -19,7 +19,7 @@ class YomoviesProvider : MainAPI() {
|
||||||
TvType.TvSeries,
|
TvType.TvSeries,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun getMainPage(): HomePageResponse {
|
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
|
||||||
val document = app.get(mainUrl).document
|
val document = app.get(mainUrl).document
|
||||||
|
|
||||||
val homePageList = ArrayList<HomePageList>()
|
val homePageList = ArrayList<HomePageList>()
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.util.Log
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import com.bumptech.glide.load.HttpException
|
import com.bumptech.glide.load.HttpException
|
||||||
|
import com.lagradost.cloudstream3.BuildConfig
|
||||||
import com.lagradost.cloudstream3.ErrorLoadingException
|
import com.lagradost.cloudstream3.ErrorLoadingException
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
@ -11,6 +12,34 @@ import java.net.SocketTimeoutException
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import javax.net.ssl.SSLHandshakeException
|
import javax.net.ssl.SSLHandshakeException
|
||||||
|
|
||||||
|
const val DEBUG_EXCEPTION = "THIS IS A DEBUG EXCEPTION!"
|
||||||
|
|
||||||
|
class DebugException(message: String) : Exception("$DEBUG_EXCEPTION\n$message")
|
||||||
|
|
||||||
|
inline fun debugException(message: () -> String) {
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
throw DebugException(message.invoke())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun debugWarning(message: () -> String) {
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
logError(DebugException(message.invoke()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun debugAssert(assert: () -> Boolean, message: () -> String) {
|
||||||
|
if (BuildConfig.DEBUG && assert.invoke()) {
|
||||||
|
throw DebugException(message.invoke())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun debugWarning(assert: () -> Boolean, message: () -> String) {
|
||||||
|
if (BuildConfig.DEBUG && assert.invoke()) {
|
||||||
|
logError(DebugException(message.invoke()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun <T> LifecycleOwner.observe(liveData: LiveData<T>, action: (t: T) -> Unit) {
|
fun <T> LifecycleOwner.observe(liveData: LiveData<T>, action: (t: T) -> Unit) {
|
||||||
liveData.observe(this) { it?.let { t -> action(t) } }
|
liveData.observe(this) { it?.let { t -> action(t) } }
|
||||||
}
|
}
|
||||||
|
@ -61,7 +90,8 @@ suspend fun <T> suspendSafeApiCall(apiCall: suspend () -> T): T? {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> safeFail(throwable: Throwable): Resource<T> {
|
fun <T> safeFail(throwable: Throwable): Resource<T> {
|
||||||
val stackTraceMsg = (throwable.localizedMessage ?: "") + "\n\n" + throwable.stackTrace.joinToString(
|
val stackTraceMsg =
|
||||||
|
(throwable.localizedMessage ?: "") + "\n\n" + throwable.stackTrace.joinToString(
|
||||||
separator = "\n"
|
separator = "\n"
|
||||||
) {
|
) {
|
||||||
"${it.fileName} ${it.lineNumber}"
|
"${it.fileName} ${it.lineNumber}"
|
||||||
|
@ -92,16 +122,31 @@ suspend fun <T> safeApiCall(
|
||||||
safeFail(throwable)
|
safeFail(throwable)
|
||||||
}
|
}
|
||||||
is SocketTimeoutException -> {
|
is SocketTimeoutException -> {
|
||||||
Resource.Failure(true, null, null, "Connection Timeout\nPlease try again later.")
|
Resource.Failure(
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
"Connection Timeout\nPlease try again later."
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is HttpException -> {
|
is HttpException -> {
|
||||||
Resource.Failure(false, throwable.statusCode, null, throwable.message ?: "HttpException")
|
Resource.Failure(
|
||||||
|
false,
|
||||||
|
throwable.statusCode,
|
||||||
|
null,
|
||||||
|
throwable.message ?: "HttpException"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is UnknownHostException -> {
|
is UnknownHostException -> {
|
||||||
Resource.Failure(true, null, null, "Cannot connect to server, try again later.")
|
Resource.Failure(true, null, null, "Cannot connect to server, try again later.")
|
||||||
}
|
}
|
||||||
is ErrorLoadingException -> {
|
is ErrorLoadingException -> {
|
||||||
Resource.Failure(true, null, null, throwable.message ?: "Error loading, try again later.")
|
Resource.Failure(
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
throwable.message ?: "Error loading, try again later."
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is NotImplementedError -> {
|
is NotImplementedError -> {
|
||||||
Resource.Failure(false, null, null, "This operation is not implemented.")
|
Resource.Failure(false, null, null, "This operation is not implemented.")
|
||||||
|
|
|
@ -29,6 +29,7 @@ class APIRepository(val api: MainAPI) {
|
||||||
val hasMainPage = api.hasMainPage
|
val hasMainPage = api.hasMainPage
|
||||||
val name = api.name
|
val name = api.name
|
||||||
val mainUrl = api.mainUrl
|
val mainUrl = api.mainUrl
|
||||||
|
val mainPage = api.mainPage
|
||||||
val hasQuickSearch = api.hasQuickSearch
|
val hasQuickSearch = api.hasQuickSearch
|
||||||
|
|
||||||
suspend fun load(url: String): Resource<LoadResponse> {
|
suspend fun load(url: String): Resource<LoadResponse> {
|
||||||
|
@ -59,9 +60,13 @@ class APIRepository(val api: MainAPI) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getMainPage(): Resource<HomePageResponse?> {
|
suspend fun getMainPage(page: Int, nameIndex: Int? = null): Resource<List<HomePageResponse?>> {
|
||||||
return safeApiCall {
|
return safeApiCall {
|
||||||
api.getMainPage() ?: throw ErrorLoadingException()
|
nameIndex?.let { api.mainPage.getOrNull(it) }?.let { data ->
|
||||||
|
listOf(api.getMainPage(page, data.name, data.data))
|
||||||
|
} ?: api.mainPage.apmap { data ->
|
||||||
|
api.getMainPage(page, data.name, data.data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ class HomeChildItemAdapter(
|
||||||
) :
|
) :
|
||||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
var isHorizontal: Boolean = false
|
var isHorizontal: Boolean = false
|
||||||
|
var hasNext : Boolean = false
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
val layout = overrideLayout
|
val layout = overrideLayout
|
||||||
|
|
|
@ -20,7 +20,6 @@ import androidx.core.widget.NestedScrollView
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearSnapHelper
|
import androidx.recyclerview.widget.LinearSnapHelper
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
@ -44,11 +43,12 @@ import com.lagradost.cloudstream3.ui.WatchType
|
||||||
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
|
||||||
import com.lagradost.cloudstream3.ui.result.START_ACTION_RESUME_LATEST
|
import com.lagradost.cloudstream3.ui.result.START_ACTION_RESUME_LATEST
|
||||||
import com.lagradost.cloudstream3.ui.search.*
|
import com.lagradost.cloudstream3.ui.search.*
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchFragment.Companion.filterSearchResponse
|
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchHelper.handleSearchClickCallback
|
import com.lagradost.cloudstream3.ui.search.SearchHelper.handleSearchClickCallback
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.loadSearchResult
|
import com.lagradost.cloudstream3.utils.AppUtils.loadSearchResult
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.setMaxViewPoolSize
|
||||||
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
import com.lagradost.cloudstream3.utils.DataStore.setKey
|
||||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||||
|
@ -122,11 +122,27 @@ class HomeFragment : Fragment() {
|
||||||
|
|
||||||
val errorProfilePic = errorProfilePics.random()
|
val errorProfilePic = errorProfilePics.random()
|
||||||
|
|
||||||
fun Activity.loadHomepageList(item: HomePageList, deleteCallback: (() -> Unit)? = null) {
|
fun Activity.loadHomepageList(
|
||||||
|
item: HomePageList,
|
||||||
|
deleteCallback: (() -> Unit)? = null,
|
||||||
|
) {
|
||||||
|
loadHomepageList(
|
||||||
|
expand = HomeViewModel.ExpandableHomepageList(item, 1, false),
|
||||||
|
deleteCallback = deleteCallback,
|
||||||
|
expandCallback = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Activity.loadHomepageList(
|
||||||
|
expand: HomeViewModel.ExpandableHomepageList,
|
||||||
|
deleteCallback: (() -> Unit)? = null,
|
||||||
|
expandCallback: (suspend (String) -> HomeViewModel.ExpandableHomepageList?)? = null
|
||||||
|
) {
|
||||||
val context = this
|
val context = this
|
||||||
val bottomSheetDialogBuilder = BottomSheetDialog(context)
|
val bottomSheetDialogBuilder = BottomSheetDialog(context)
|
||||||
bottomSheetDialogBuilder.setContentView(R.layout.home_episodes_expanded)
|
bottomSheetDialogBuilder.setContentView(R.layout.home_episodes_expanded)
|
||||||
val title = bottomSheetDialogBuilder.findViewById<TextView>(R.id.home_expanded_text)!!
|
val title = bottomSheetDialogBuilder.findViewById<TextView>(R.id.home_expanded_text)!!
|
||||||
|
val item = expand.list
|
||||||
title.text = item.name
|
title.text = item.name
|
||||||
val recycle =
|
val recycle =
|
||||||
bottomSheetDialogBuilder.findViewById<AutofitRecyclerView>(R.id.home_expanded_recycler)!!
|
bottomSheetDialogBuilder.findViewById<AutofitRecyclerView>(R.id.home_expanded_recycler)!!
|
||||||
|
@ -179,8 +195,36 @@ class HomeFragment : Fragment() {
|
||||||
if (callback.action == SEARCH_ACTION_LOAD || callback.action == SEARCH_ACTION_PLAY_FILE) {
|
if (callback.action == SEARCH_ACTION_LOAD || callback.action == SEARCH_ACTION_PLAY_FILE) {
|
||||||
bottomSheetDialogBuilder.dismissSafe(this)
|
bottomSheetDialogBuilder.dismissSafe(this)
|
||||||
}
|
}
|
||||||
|
}.apply {
|
||||||
|
hasNext = expand.hasNext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recycle.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||||
|
var expandCount = 0
|
||||||
|
val name = expand.list.name
|
||||||
|
|
||||||
|
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||||
|
super.onScrollStateChanged(recyclerView, newState)
|
||||||
|
|
||||||
|
val adapter = recyclerView.adapter
|
||||||
|
if (adapter !is SearchAdapter) return
|
||||||
|
|
||||||
|
val count = adapter.itemCount
|
||||||
|
val currentHasNext = adapter.hasNext
|
||||||
|
if (!recyclerView.canScrollVertically(1) && currentHasNext && expandCount != count) {
|
||||||
|
expandCount = count
|
||||||
|
ioSafe {
|
||||||
|
expandCallback?.invoke(name)?.let { newExpand ->
|
||||||
|
(recyclerView.adapter as? SearchAdapter?)?.apply {
|
||||||
|
hasNext = newExpand.hasNext
|
||||||
|
updateList(newExpand.list.list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
val spanListener = { span: Int ->
|
val spanListener = { span: Int ->
|
||||||
recycle.spanCount = span
|
recycle.spanCount = span
|
||||||
//(recycle.adapter as SearchAdapter).notifyDataSetChanged()
|
//(recycle.adapter as SearchAdapter).notifyDataSetChanged()
|
||||||
|
@ -349,8 +393,6 @@ class HomeFragment : Fragment() {
|
||||||
return inflater.inflate(layout, container, false)
|
return inflater.inflate(layout, container, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var currentHomePage: HomePageResponse? = null
|
|
||||||
|
|
||||||
private fun toggleMainVisibility(visible: Boolean) {
|
private fun toggleMainVisibility(visible: Boolean) {
|
||||||
home_main_holder?.isVisible = visible
|
home_main_holder?.isVisible = visible
|
||||||
home_main_poster_recyclerview?.isVisible = visible
|
home_main_poster_recyclerview?.isVisible = visible
|
||||||
|
@ -541,18 +583,11 @@ class HomeFragment : Fragment() {
|
||||||
val d = data.value
|
val d = data.value
|
||||||
listHomepageItems.clear()
|
listHomepageItems.clear()
|
||||||
|
|
||||||
currentHomePage = d
|
// println("ITEMCOUNT: ${d.values.size} ${home_master_recycler?.adapter?.itemCount}")
|
||||||
(home_master_recycler?.adapter as? ParentItemAdapter?)?.updateList(
|
(home_master_recycler?.adapter as? ParentItemAdapter?)?.updateList(
|
||||||
d?.items?.mapNotNull {
|
d.values.toMutableList(),
|
||||||
try {
|
home_master_recycler
|
||||||
val filter = it.list.filterSearchResponse()
|
)
|
||||||
listHomepageItems.addAll(filter)
|
|
||||||
it.copy(list = filter)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
logError(e)
|
|
||||||
null
|
|
||||||
}
|
|
||||||
} ?: listOf())
|
|
||||||
|
|
||||||
home_loading?.isVisible = false
|
home_loading?.isVisible = false
|
||||||
home_loading_error?.isVisible = false
|
home_loading_error?.isVisible = false
|
||||||
|
@ -603,13 +638,6 @@ class HomeFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
|
|
||||||
ParentItemAdapter(mutableListOf(), { callback ->
|
|
||||||
homeHandleSearch(callback)
|
|
||||||
}, { item ->
|
|
||||||
activity?.loadHomepageList(item)
|
|
||||||
})
|
|
||||||
|
|
||||||
val toggleList = listOf(
|
val toggleList = listOf(
|
||||||
Pair(home_type_watching_btt, WatchType.WATCHING),
|
Pair(home_type_watching_btt, WatchType.WATCHING),
|
||||||
Pair(home_type_completed_btt, WatchType.COMPLETED),
|
Pair(home_type_completed_btt, WatchType.COMPLETED),
|
||||||
|
@ -861,9 +889,22 @@ class HomeFragment : Fragment() {
|
||||||
context?.fixPaddingStatusbarView(home_statusbar)
|
context?.fixPaddingStatusbarView(home_statusbar)
|
||||||
context?.fixPaddingStatusbar(home_loading_statusbar)
|
context?.fixPaddingStatusbar(home_loading_statusbar)
|
||||||
|
|
||||||
|
home_master_recycler.adapter =
|
||||||
home_master_recycler.adapter = adapter
|
ParentItemAdapter(mutableListOf(), { callback ->
|
||||||
home_master_recycler.layoutManager = GridLayoutManager(context, 1)
|
homeHandleSearch(callback)
|
||||||
|
}, { item ->
|
||||||
|
activity?.loadHomepageList(item, expandCallback = {
|
||||||
|
homeViewModel.expandAndReturn(it)
|
||||||
|
})
|
||||||
|
}, { name ->
|
||||||
|
homeViewModel.expand(name)
|
||||||
|
})
|
||||||
|
home_master_recycler?.setMaxViewPoolSize(0, Int.MAX_VALUE)
|
||||||
|
home_master_recycler.layoutManager = object : LinearLayoutManager(context) {
|
||||||
|
override fun supportsPredictiveItemAnimations(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} // GridLayoutManager(context, 1).also { it.supportsPredictiveItemAnimations() }
|
||||||
|
|
||||||
if (context?.isTvSettings() == false) {
|
if (context?.isTvSettings() == false) {
|
||||||
LinearSnapHelper().attachToRecyclerView(home_main_poster_recyclerview) // snap
|
LinearSnapHelper().attachToRecyclerView(home_main_poster_recyclerview) // snap
|
||||||
|
|
|
@ -6,29 +6,38 @@ import android.view.ViewGroup
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.ListUpdateCallback
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.lagradost.cloudstream3.HomePageList
|
import com.lagradost.cloudstream3.HomePageList
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
||||||
|
import com.lagradost.cloudstream3.ui.search.SearchFragment.Companion.filterSearchResponse
|
||||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||||
import kotlinx.android.synthetic.main.homepage_parent.view.*
|
import kotlinx.android.synthetic.main.homepage_parent.view.*
|
||||||
|
|
||||||
|
|
||||||
class ParentItemAdapter(
|
class ParentItemAdapter(
|
||||||
private var items: MutableList<HomePageList>,
|
private var items: MutableList<HomeViewModel.ExpandableHomepageList>,
|
||||||
private val clickCallback: (SearchClickCallback) -> Unit,
|
private val clickCallback: (SearchClickCallback) -> Unit,
|
||||||
private val moreInfoClickCallback: (HomePageList) -> Unit,
|
private val moreInfoClickCallback: (HomeViewModel.ExpandableHomepageList) -> Unit,
|
||||||
|
private val expandCallback: ((String) -> Unit)? = null,
|
||||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, i: Int): ParentViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, i: Int): ParentViewHolder {
|
||||||
|
//println("onCreateViewHolder $i")
|
||||||
val layout =
|
val layout =
|
||||||
if (parent.context.isTvSettings()) R.layout.homepage_parent_tv else R.layout.homepage_parent
|
if (parent.context.isTvSettings()) R.layout.homepage_parent_tv else R.layout.homepage_parent
|
||||||
return ParentViewHolder(
|
return ParentViewHolder(
|
||||||
LayoutInflater.from(parent.context).inflate(layout, parent, false),
|
LayoutInflater.from(parent.context).inflate(layout, parent, false),
|
||||||
clickCallback,
|
clickCallback,
|
||||||
moreInfoClickCallback
|
moreInfoClickCallback,
|
||||||
|
expandCallback
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
//println("onBindViewHolder $position")
|
||||||
|
|
||||||
when (holder) {
|
when (holder) {
|
||||||
is ParentViewHolder -> {
|
is ParentViewHolder -> {
|
||||||
holder.bind(items[position])
|
holder.bind(items[position])
|
||||||
|
@ -41,44 +50,100 @@ class ParentItemAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemId(position: Int): Long {
|
override fun getItemId(position: Int): Long {
|
||||||
return items[position].name.hashCode().toLong()
|
return items[position].list.name.hashCode().toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmName("updateListHomePageList")
|
||||||
fun updateList(newList: List<HomePageList>) {
|
fun updateList(newList: List<HomePageList>) {
|
||||||
// this moves all bad results to the bottom
|
updateList(newList.map { HomeViewModel.ExpandableHomepageList(it, 1, false) }
|
||||||
val endList = mutableListOf<HomePageList>()
|
.toMutableList())
|
||||||
val newFilteredList = mutableListOf<HomePageList>()
|
|
||||||
for (item in newList) {
|
|
||||||
if (item.list.isEmpty()) {
|
|
||||||
endList.add(item)
|
|
||||||
} else {
|
|
||||||
newFilteredList.add(item)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
newFilteredList.addAll(endList)
|
@JvmName("updateListExpandableHomepageList")
|
||||||
|
fun updateList(
|
||||||
|
newList: MutableList<HomeViewModel.ExpandableHomepageList>,
|
||||||
|
recyclerView: RecyclerView? = null
|
||||||
|
) {
|
||||||
|
// this
|
||||||
|
// 1. prevents deep copy that makes this.items == newList
|
||||||
|
// 2. filters out undesirable results
|
||||||
|
// 3. moves empty results to the bottom (sortedBy is a stable sort)
|
||||||
|
val new =
|
||||||
|
newList.map { it.copy(list = it.list.copy(list = it.list.list.filterSearchResponse())) }
|
||||||
|
.sortedBy { it.list.list.isEmpty() }
|
||||||
|
|
||||||
val diffResult = DiffUtil.calculateDiff(
|
val diffResult = DiffUtil.calculateDiff(
|
||||||
SearchDiffCallback(this.items, newFilteredList)
|
SearchDiffCallback(items, new)
|
||||||
)
|
)
|
||||||
|
|
||||||
items.clear()
|
items.clear()
|
||||||
items.addAll(newFilteredList)
|
items.addAll(new)
|
||||||
|
|
||||||
diffResult.dispatchUpdatesTo(this)
|
val mAdapter = this
|
||||||
|
diffResult.dispatchUpdatesTo(object : ListUpdateCallback {
|
||||||
|
override fun onInserted(position: Int, count: Int) {
|
||||||
|
mAdapter.notifyItemRangeInserted(position, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRemoved(position: Int, count: Int) {
|
||||||
|
mAdapter.notifyItemRangeRemoved(position, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMoved(fromPosition: Int, toPosition: Int) {
|
||||||
|
mAdapter.notifyItemMoved(fromPosition, toPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onChanged(position: Int, count: Int, payload: Any?) {
|
||||||
|
// I know kinda messy, what this does is using the update or bind instead of onCreateViewHolder -> bind
|
||||||
|
recyclerView?.apply {
|
||||||
|
// this loops every viewHolder in the recycle view and checks the position to see if it is within the update range
|
||||||
|
val missingUpdates = (position until (position + count)).toMutableSet()
|
||||||
|
for (i in 0 until mAdapter.itemCount) {
|
||||||
|
val viewHolder = getChildViewHolder(getChildAt(i))
|
||||||
|
val absolutePosition = viewHolder.absoluteAdapterPosition
|
||||||
|
if (absolutePosition >= position && absolutePosition < position + count) {
|
||||||
|
val expand = items.getOrNull(absolutePosition) ?: continue
|
||||||
|
if (viewHolder is ParentViewHolder) {
|
||||||
|
missingUpdates -= absolutePosition
|
||||||
|
if (viewHolder.title.text == expand.list.name) {
|
||||||
|
viewHolder.update(expand)
|
||||||
|
} else {
|
||||||
|
viewHolder.bind(expand)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// just in case some item did not get updated
|
||||||
|
for (i in missingUpdates) {
|
||||||
|
mAdapter.notifyItemChanged(i, payload)
|
||||||
|
}
|
||||||
|
} ?: run { // in case we don't have a nice
|
||||||
|
mAdapter.notifyItemRangeChanged(position, count, payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
//diffResult.dispatchUpdatesTo(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ParentViewHolder
|
class ParentViewHolder
|
||||||
constructor(
|
constructor(
|
||||||
itemView: View,
|
itemView: View,
|
||||||
private val clickCallback: (SearchClickCallback) -> Unit,
|
private val clickCallback: (SearchClickCallback) -> Unit,
|
||||||
private val moreInfoClickCallback: (HomePageList) -> Unit
|
private val moreInfoClickCallback: (HomeViewModel.ExpandableHomepageList) -> Unit,
|
||||||
|
private val expandCallback: ((String) -> Unit)? = null,
|
||||||
) :
|
) :
|
||||||
RecyclerView.ViewHolder(itemView) {
|
RecyclerView.ViewHolder(itemView) {
|
||||||
val title: TextView = itemView.home_parent_item_title
|
val title: TextView = itemView.home_parent_item_title
|
||||||
val recyclerView: RecyclerView = itemView.home_child_recyclerview
|
val recyclerView: RecyclerView = itemView.home_child_recyclerview
|
||||||
private val moreInfo: FrameLayout? = itemView.home_child_more_info
|
private val moreInfo: FrameLayout? = itemView.home_child_more_info
|
||||||
fun bind(info: HomePageList) {
|
|
||||||
title.text = info.name
|
fun update(expand: HomeViewModel.ExpandableHomepageList) {
|
||||||
|
val info = expand.list
|
||||||
|
(recyclerView.adapter as? HomeChildItemAdapter?)?.apply {
|
||||||
|
updateList(info.list.toMutableList())
|
||||||
|
hasNext = expand.hasNext
|
||||||
|
} ?: run {
|
||||||
recyclerView.adapter = HomeChildItemAdapter(
|
recyclerView.adapter = HomeChildItemAdapter(
|
||||||
info.list.toMutableList(),
|
info.list.toMutableList(),
|
||||||
clickCallback = clickCallback,
|
clickCallback = clickCallback,
|
||||||
|
@ -87,28 +152,68 @@ class ParentItemAdapter(
|
||||||
).apply {
|
).apply {
|
||||||
isHorizontal = info.isHorizontalImages
|
isHorizontal = info.isHorizontalImages
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bind(expand: HomeViewModel.ExpandableHomepageList) {
|
||||||
|
val info = expand.list
|
||||||
|
recyclerView.adapter = HomeChildItemAdapter(
|
||||||
|
info.list.toMutableList(),
|
||||||
|
clickCallback = clickCallback,
|
||||||
|
nextFocusUp = recyclerView.nextFocusUpId,
|
||||||
|
nextFocusDown = recyclerView.nextFocusDownId,
|
||||||
|
).apply {
|
||||||
|
isHorizontal = info.isHorizontalImages
|
||||||
|
hasNext = expand.hasNext
|
||||||
|
}
|
||||||
|
|
||||||
|
title.text = info.name
|
||||||
|
|
||||||
|
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||||
|
var expandCount = 0
|
||||||
|
val name = expand.list.name
|
||||||
|
|
||||||
|
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||||
|
super.onScrollStateChanged(recyclerView, newState)
|
||||||
|
|
||||||
|
val adapter = recyclerView.adapter
|
||||||
|
if (adapter !is HomeChildItemAdapter) return
|
||||||
|
|
||||||
|
val count = adapter.itemCount
|
||||||
|
val hasNext = adapter.hasNext
|
||||||
|
if (!recyclerView.canScrollHorizontally(1) && hasNext && expandCount != count) {
|
||||||
|
expandCount = count
|
||||||
|
expandCallback?.invoke(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
//(recyclerView.adapter as HomeChildItemAdapter).notifyDataSetChanged()
|
//(recyclerView.adapter as HomeChildItemAdapter).notifyDataSetChanged()
|
||||||
|
|
||||||
moreInfo?.setOnClickListener {
|
moreInfo?.setOnClickListener {
|
||||||
moreInfoClickCallback.invoke(info)
|
moreInfoClickCallback.invoke(expand)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SearchDiffCallback(
|
class SearchDiffCallback(
|
||||||
private val oldList: List<HomePageList>,
|
private val oldList: List<HomeViewModel.ExpandableHomepageList>,
|
||||||
private val newList: List<HomePageList>
|
private val newList: List<HomeViewModel.ExpandableHomepageList>
|
||||||
) :
|
) :
|
||||||
DiffUtil.Callback() {
|
DiffUtil.Callback() {
|
||||||
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
|
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
|
||||||
oldList[oldItemPosition].name == newList[newItemPosition].name
|
oldList[oldItemPosition].list.name == newList[newItemPosition].list.name
|
||||||
|
|
||||||
override fun getOldListSize() = oldList.size
|
override fun getOldListSize() = oldList.size
|
||||||
|
|
||||||
override fun getNewListSize() = newList.size
|
override fun getNewListSize() = newList.size
|
||||||
|
|
||||||
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
|
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
|
||||||
oldList[oldItemPosition] == newList[newItemPosition]
|
oldList[oldItemPosition] == newList[newItemPosition]
|
||||||
|
//{
|
||||||
|
// val ret = oldList[oldItemPosition].list.list.size == newList[newItemPosition].list.list.size
|
||||||
|
// println(">>>>>>>>>>>>>>>> $ret ${oldList[oldItemPosition].list.list.size} == ${newList[newItemPosition].list.list.size}")
|
||||||
|
// return ret
|
||||||
|
//}
|
||||||
}
|
}
|
|
@ -10,10 +10,12 @@ import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.context
|
import com.lagradost.cloudstream3.AcraApplication.Companion.context
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
||||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||||
import com.lagradost.cloudstream3.HomePageResponse
|
import com.lagradost.cloudstream3.HomePageList
|
||||||
import com.lagradost.cloudstream3.MainAPI
|
import com.lagradost.cloudstream3.MainAPI
|
||||||
import com.lagradost.cloudstream3.SearchResponse
|
import com.lagradost.cloudstream3.SearchResponse
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
|
import com.lagradost.cloudstream3.mvvm.debugAssert
|
||||||
|
import com.lagradost.cloudstream3.mvvm.debugWarning
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository
|
import com.lagradost.cloudstream3.ui.APIRepository
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi
|
import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi
|
||||||
|
@ -34,6 +36,7 @@ import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.collections.set
|
||||||
|
|
||||||
class HomeViewModel : ViewModel() {
|
class HomeViewModel : ViewModel() {
|
||||||
private var repo: APIRepository? = null
|
private var repo: APIRepository? = null
|
||||||
|
@ -41,9 +44,6 @@ class HomeViewModel : ViewModel() {
|
||||||
private val _apiName = MutableLiveData<String>()
|
private val _apiName = MutableLiveData<String>()
|
||||||
val apiName: LiveData<String> = _apiName
|
val apiName: LiveData<String> = _apiName
|
||||||
|
|
||||||
private val _page = MutableLiveData<Resource<HomePageResponse?>>()
|
|
||||||
val page: LiveData<Resource<HomePageResponse?>> = _page
|
|
||||||
|
|
||||||
private val _randomItems = MutableLiveData<List<SearchResponse>?>(null)
|
private val _randomItems = MutableLiveData<List<SearchResponse>?>(null)
|
||||||
val randomItems: LiveData<List<SearchResponse>?> = _randomItems
|
val randomItems: LiveData<List<SearchResponse>?> = _randomItems
|
||||||
|
|
||||||
|
@ -51,8 +51,10 @@ class HomeViewModel : ViewModel() {
|
||||||
return APIRepository(apis.first { it.hasMainPage })
|
return APIRepository(apis.first { it.hasMainPage })
|
||||||
}
|
}
|
||||||
|
|
||||||
private val _availableWatchStatusTypes = MutableLiveData<Pair<EnumSet<WatchType>, EnumSet<WatchType>>>()
|
private val _availableWatchStatusTypes =
|
||||||
val availableWatchStatusTypes: LiveData<Pair<EnumSet<WatchType>, EnumSet<WatchType>>> = _availableWatchStatusTypes
|
MutableLiveData<Pair<EnumSet<WatchType>, EnumSet<WatchType>>>()
|
||||||
|
val availableWatchStatusTypes: LiveData<Pair<EnumSet<WatchType>, EnumSet<WatchType>>> =
|
||||||
|
_availableWatchStatusTypes
|
||||||
private val _bookmarks = MutableLiveData<Pair<Boolean, List<SearchResponse>>>()
|
private val _bookmarks = MutableLiveData<Pair<Boolean, List<SearchResponse>>>()
|
||||||
val bookmarks: LiveData<Pair<Boolean, List<SearchResponse>>> = _bookmarks
|
val bookmarks: LiveData<Pair<Boolean, List<SearchResponse>>> = _bookmarks
|
||||||
|
|
||||||
|
@ -143,6 +145,67 @@ class HomeViewModel : ViewModel() {
|
||||||
onGoingLoad = load(api)
|
onGoingLoad = load(api)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class ExpandableHomepageList(
|
||||||
|
var list: HomePageList,
|
||||||
|
var currentPage: Int,
|
||||||
|
var hasNext: Boolean,
|
||||||
|
)
|
||||||
|
|
||||||
|
private val expandable: MutableMap<String, ExpandableHomepageList> = mutableMapOf()
|
||||||
|
private val _page =
|
||||||
|
MutableLiveData<Resource<Map<String, ExpandableHomepageList>>>(Resource.Loading())
|
||||||
|
val page: LiveData<Resource<Map<String, ExpandableHomepageList>>> = _page
|
||||||
|
|
||||||
|
val lock: MutableSet<String> = mutableSetOf()
|
||||||
|
|
||||||
|
suspend fun expandAndReturn(name: String) : ExpandableHomepageList? {
|
||||||
|
if (lock.contains(name)) return null
|
||||||
|
lock += name
|
||||||
|
|
||||||
|
repo?.apply {
|
||||||
|
expandable[name]?.let { current ->
|
||||||
|
debugAssert({ !current.hasNext }) {
|
||||||
|
"Expand called when not needed"
|
||||||
|
}
|
||||||
|
|
||||||
|
val nextPage = current.currentPage + 1
|
||||||
|
val next = getMainPage(nextPage, mainPage.indexOfFirst { it.name == name })
|
||||||
|
if (next is Resource.Success) {
|
||||||
|
next.value.filterNotNull().forEach { main ->
|
||||||
|
main.items.forEach { newList ->
|
||||||
|
val key = newList.name
|
||||||
|
expandable[key]?.apply {
|
||||||
|
hasNext = main.hasNext
|
||||||
|
currentPage = nextPage
|
||||||
|
|
||||||
|
debugWarning({ newList.list.any { outer -> this.list.list.any { it.url == outer.url } } }) {
|
||||||
|
"Expanded contained an item that was previously already in the list\n${list.name} = ${this.list.list}\n${newList.name} = ${newList.list}"
|
||||||
|
}
|
||||||
|
|
||||||
|
this.list.list += newList.list
|
||||||
|
this.list.list.distinctBy { it.url } // just to be sure we are not adding the same shit for some reason
|
||||||
|
} ?: debugWarning {
|
||||||
|
"Expanded an item not in main load named $key, current list is ${expandable.keys}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
current.hasNext = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_page.postValue(Resource.Success(expandable))
|
||||||
|
}
|
||||||
|
|
||||||
|
lock -= name
|
||||||
|
|
||||||
|
return expandable[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is soo over engineered, but idk how I can make it clean without making the main api harder to use :pensive:
|
||||||
|
fun expand(name: String) = viewModelScope.launch {
|
||||||
|
expandAndReturn(name)
|
||||||
|
}
|
||||||
|
|
||||||
private fun load(api: MainAPI?) = viewModelScope.launch {
|
private fun load(api: MainAPI?) = viewModelScope.launch {
|
||||||
repo = if (api != null) {
|
repo = if (api != null) {
|
||||||
APIRepository(api)
|
APIRepository(api)
|
||||||
|
@ -156,18 +219,28 @@ class HomeViewModel : ViewModel() {
|
||||||
if (repo?.hasMainPage == true) {
|
if (repo?.hasMainPage == true) {
|
||||||
_page.postValue(Resource.Loading())
|
_page.postValue(Resource.Loading())
|
||||||
|
|
||||||
val data = repo?.getMainPage()
|
when (val data = repo?.getMainPage(1, null)) {
|
||||||
when (data) {
|
|
||||||
is Resource.Success -> {
|
is Resource.Success -> {
|
||||||
try {
|
try {
|
||||||
val home = data.value
|
expandable.clear()
|
||||||
if (home?.items?.isNullOrEmpty() == false) {
|
data.value.forEach { home ->
|
||||||
|
home?.items?.forEach { list ->
|
||||||
|
expandable[list.name] =
|
||||||
|
ExpandableHomepageList(list, 1, home.hasNext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_page.postValue(Resource.Success(expandable))
|
||||||
|
val items = data.value.mapNotNull { it?.items }.flatten()
|
||||||
|
|
||||||
|
//val home = data.value
|
||||||
|
if (items.isNotEmpty()) {
|
||||||
val currentList =
|
val currentList =
|
||||||
home.items.shuffled().filter { !it.list.isNullOrEmpty() }.flatMap { it.list }
|
items.shuffled().filter { it.list.isNotEmpty() }
|
||||||
|
.flatMap { it.list }
|
||||||
.distinctBy { it.url }
|
.distinctBy { it.url }
|
||||||
.toList()
|
.toList()
|
||||||
|
|
||||||
if (!currentList.isNullOrEmpty()) {
|
if (currentList.isNotEmpty()) {
|
||||||
val randomItems = currentList.shuffled()
|
val randomItems = currentList.shuffled()
|
||||||
|
|
||||||
_randomItems.postValue(randomItems)
|
_randomItems.postValue(randomItems)
|
||||||
|
@ -178,13 +251,11 @@ class HomeViewModel : ViewModel() {
|
||||||
logError(e)
|
logError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is Resource.Failure -> {
|
||||||
|
_page.postValue(data!!)
|
||||||
|
}
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
data?.let {
|
|
||||||
_page.postValue(it)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_page.postValue(Resource.Success(HomePageResponse(emptyList())))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@ import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.loadHomepageLis
|
||||||
import com.lagradost.cloudstream3.ui.home.ParentItemAdapter
|
import com.lagradost.cloudstream3.ui.home.ParentItemAdapter
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
import com.lagradost.cloudstream3.ui.search.SearchClickCallback
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchFragment.Companion.filterSearchResponse
|
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||||
import com.lagradost.cloudstream3.ui.search.SearchViewModel
|
import com.lagradost.cloudstream3.ui.search.SearchViewModel
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper
|
import com.lagradost.cloudstream3.utils.UIHelper
|
||||||
|
@ -173,7 +172,7 @@ class QuickSearchFragment : Fragment() {
|
||||||
updateList(list.map { ongoing ->
|
updateList(list.map { ongoing ->
|
||||||
val ongoingList = HomePageList(
|
val ongoingList = HomePageList(
|
||||||
ongoing.apiName,
|
ongoing.apiName,
|
||||||
if (ongoing.data is Resource.Success) ongoing.data.value.filterSearchResponse() else ArrayList()
|
if (ongoing.data is Resource.Success) ongoing.data.value else ArrayList()
|
||||||
)
|
)
|
||||||
ongoingList
|
ongoingList
|
||||||
})
|
})
|
||||||
|
|
|
@ -27,6 +27,7 @@ class SearchAdapter(
|
||||||
private val resView: AutofitRecyclerView,
|
private val resView: AutofitRecyclerView,
|
||||||
private val clickCallback: (SearchClickCallback) -> Unit,
|
private val clickCallback: (SearchClickCallback) -> Unit,
|
||||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
var hasNext : Boolean = false
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
val layout = if(parent.context.IsBottomLayout()) R.layout.search_result_grid_expanded else R.layout.search_result_grid
|
val layout = if(parent.context.IsBottomLayout()) R.layout.search_result_grid_expanded else R.layout.search_result_grid
|
||||||
|
|
|
@ -426,7 +426,7 @@ class SearchFragment : Fragment() {
|
||||||
val newItems = list.map { ongoing ->
|
val newItems = list.map { ongoing ->
|
||||||
val ongoingList = HomePageList(
|
val ongoingList = HomePageList(
|
||||||
ongoing.apiName,
|
ongoing.apiName,
|
||||||
if (ongoing.data is Resource.Success) ongoing.data.value.filterSearchResponse() else ArrayList()
|
if (ongoing.data is Resource.Success) ongoing.data.value else ArrayList()
|
||||||
)
|
)
|
||||||
ongoingList
|
ongoingList
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ class SearchViewModel : ViewModel() {
|
||||||
_currentSearch.postValue(emptyList())
|
_currentSearch.postValue(emptyList())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var currentSearchIndex = 0
|
||||||
private var onGoingSearch: Job? = null
|
private var onGoingSearch: Job? = null
|
||||||
fun searchAndCancel(
|
fun searchAndCancel(
|
||||||
query: String,
|
query: String,
|
||||||
|
@ -50,6 +51,7 @@ class SearchViewModel : ViewModel() {
|
||||||
ignoreSettings: Boolean = false,
|
ignoreSettings: Boolean = false,
|
||||||
isQuickSearch: Boolean = false,
|
isQuickSearch: Boolean = false,
|
||||||
) {
|
) {
|
||||||
|
currentSearchIndex++
|
||||||
onGoingSearch?.cancel()
|
onGoingSearch?.cancel()
|
||||||
onGoingSearch = search(query, providersActive, ignoreSettings, isQuickSearch)
|
onGoingSearch = search(query, providersActive, ignoreSettings, isQuickSearch)
|
||||||
}
|
}
|
||||||
|
@ -70,6 +72,7 @@ class SearchViewModel : ViewModel() {
|
||||||
isQuickSearch: Boolean = false,
|
isQuickSearch: Boolean = false,
|
||||||
) =
|
) =
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
val currentIndex = currentSearchIndex
|
||||||
if (query.length <= 1) {
|
if (query.length <= 1) {
|
||||||
clearSearch()
|
clearSearch()
|
||||||
return@launch
|
return@launch
|
||||||
|
@ -91,21 +94,24 @@ class SearchViewModel : ViewModel() {
|
||||||
|
|
||||||
_searchResponse.postValue(Resource.Loading())
|
_searchResponse.postValue(Resource.Loading())
|
||||||
|
|
||||||
val currentList = ArrayList<OnGoingSearch>()
|
|
||||||
|
|
||||||
_currentSearch.postValue(ArrayList())
|
_currentSearch.postValue(ArrayList())
|
||||||
|
|
||||||
withContext(Dispatchers.IO) { // This interrupts UI otherwise
|
withContext(Dispatchers.IO) { // This interrupts UI otherwise
|
||||||
|
val currentList = ArrayList<OnGoingSearch>()
|
||||||
|
|
||||||
repos.filter { a ->
|
repos.filter { a ->
|
||||||
(ignoreSettings || (providersActive.isEmpty() || providersActive.contains(a.name))) && (!isQuickSearch || a.hasQuickSearch)
|
(ignoreSettings || (providersActive.isEmpty() || providersActive.contains(a.name))) && (!isQuickSearch || a.hasQuickSearch)
|
||||||
}.apmap { a -> // Parallel
|
}.apmap { a -> // Parallel
|
||||||
val search = if (isQuickSearch) a.quickSearch(query) else a.search(query)
|
val search = if (isQuickSearch) a.quickSearch(query) else a.search(query)
|
||||||
|
if(currentSearchIndex != currentIndex) return@apmap
|
||||||
currentList.add(OnGoingSearch(a.name, search))
|
currentList.add(OnGoingSearch(a.name, search))
|
||||||
_currentSearch.postValue(currentList)
|
_currentSearch.postValue(currentList)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_currentSearch.postValue(currentList)
|
|
||||||
|
|
||||||
|
if(currentSearchIndex != currentIndex) return@withContext // this should prevent rewrite of existing data bug
|
||||||
|
|
||||||
|
_currentSearch.postValue(currentList)
|
||||||
val list = ArrayList<SearchResponse>()
|
val list = ArrayList<SearchResponse>()
|
||||||
val nestedList =
|
val nestedList =
|
||||||
currentList.map { it.data }
|
currentList.map { it.data }
|
||||||
|
@ -128,3 +134,4 @@ class SearchViewModel : ViewModel() {
|
||||||
_searchResponse.postValue(Resource.Success(list))
|
_searchResponse.postValue(Resource.Success(list))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.core.text.toSpanned
|
import androidx.core.text.toSpanned
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.tvprovider.media.tv.PreviewChannelHelper
|
import androidx.tvprovider.media.tv.PreviewChannelHelper
|
||||||
import androidx.tvprovider.media.tv.TvContractCompat
|
import androidx.tvprovider.media.tv.TvContractCompat
|
||||||
import androidx.tvprovider.media.tv.WatchNextProgram
|
import androidx.tvprovider.media.tv.WatchNextProgram
|
||||||
|
@ -52,6 +53,11 @@ import java.net.URL
|
||||||
import java.net.URLDecoder
|
import java.net.URLDecoder
|
||||||
|
|
||||||
object AppUtils {
|
object AppUtils {
|
||||||
|
fun RecyclerView.setMaxViewPoolSize(maxViewTypeId: Int, maxPoolSize: Int) {
|
||||||
|
for (i in 0..maxViewTypeId)
|
||||||
|
recycledViewPool.setMaxRecycledViews(i, maxPoolSize)
|
||||||
|
}
|
||||||
|
|
||||||
//fun Context.deleteFavorite(data: SearchResponse) {
|
//fun Context.deleteFavorite(data: SearchResponse) {
|
||||||
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
|
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
|
||||||
// normalSafeApiCall {
|
// normalSafeApiCall {
|
||||||
|
|
|
@ -367,8 +367,8 @@
|
||||||
<string name="actor_background">Pomocniczy</string>
|
<string name="actor_background">Pomocniczy</string>
|
||||||
|
|
||||||
<string name="home_source">Źródło</string>
|
<string name="home_source">Źródło</string>
|
||||||
|
|
||||||
<string name="home_random">Losowy</string>
|
<string name="home_random">Losowy</string>
|
||||||
|
|
||||||
<string name="coming_soon">Już wkrótce…</string>
|
<string name="coming_soon">Już wkrótce…</string>
|
||||||
<string name="quality_cam">Cam</string>
|
<string name="quality_cam">Cam</string>
|
||||||
<string name="quality_cam_rip">Cam</string>
|
<string name="quality_cam_rip">Cam</string>
|
||||||
|
@ -391,4 +391,11 @@
|
||||||
<string name="error">Błąd</string>
|
<string name="error">Błąd</string>
|
||||||
<string name="subtitles_remove_captions">Usuń informacje dla niesłyszących z napisów</string>
|
<string name="subtitles_remove_captions">Usuń informacje dla niesłyszących z napisów</string>
|
||||||
<string name="subtitles_remove_bloat">Usuń nadmiarowe informacje z napisów</string>
|
<string name="subtitles_remove_bloat">Usuń nadmiarowe informacje z napisów</string>
|
||||||
|
<string name="next">Dalej</string>
|
||||||
|
<string name="provider_languages_tip">Wyświetlaj filmy w wybranych językach</string>
|
||||||
|
<string name="previous">Cofnij</string>
|
||||||
|
<string name="skip_setup">Pomiń</string>
|
||||||
|
<string name="app_layout_subtext">Dostosuj wygląd aplikacji do urządzenia</string>
|
||||||
|
<string name="preferred_media_subtext">Preferowany rodzaj filmów</string>
|
||||||
|
<string name="setup_done">Gotowe</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
<!--https://newbedev.com/concatenate-multiple-strings-in-xml-->
|
<!--https://newbedev.com/concatenate-multiple-strings-in-xml-->
|
||||||
<resources>
|
<resources>
|
||||||
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
|
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
|
||||||
<string name="extra_info_format" translatable="false" formatted="true">%d %s | %sMB</string>
|
<string name="extra_info_format" formatted="true" translatable="false">%d %s | %sMB</string>
|
||||||
<string name="storage_size_format" translatable="false" formatted="true">%s • %sGB</string>
|
<string name="storage_size_format" formatted="true" translatable="false">%s • %sGB</string>
|
||||||
<string name="download_size_format" translatable="false" formatted="true">%sMB / %sMB</string>
|
<string name="download_size_format" formatted="true" translatable="false">%sMB / %sMB</string>
|
||||||
<string name="mb_format" translatable="false" formatted="true">%dMB</string>
|
<string name="mb_format" formatted="true" translatable="false">%dMB</string>
|
||||||
<string name="episode_name_format" translatable="false" formatted="true">%s %s</string>
|
<string name="episode_name_format" formatted="true" translatable="false">%s %s</string>
|
||||||
<string name="ffw_text_format" translatable="false" formatted="true">+%d</string>
|
<string name="ffw_text_format" formatted="true" translatable="false">+%d</string>
|
||||||
<string name="rew_text_format" translatable="false" formatted="true">-%d</string>
|
<string name="rew_text_format" formatted="true" translatable="false">-%d</string>
|
||||||
<string name="ffw_text_regular_format" translatable="false" formatted="true">%d</string>
|
<string name="ffw_text_regular_format" formatted="true" translatable="false">%d</string>
|
||||||
<string name="rew_text_regular_format" translatable="false" formatted="true">%d</string>
|
<string name="rew_text_regular_format" formatted="true" translatable="false">%d</string>
|
||||||
<string name="rating_format" translatable="false" formatted="true">%.1f/10.0</string>
|
<string name="rating_format" formatted="true" translatable="false">%.1f/10.0</string>
|
||||||
<string name="year_format" translatable="false" formatted="true">%d</string>
|
<string name="year_format" formatted="true" translatable="false">%d</string>
|
||||||
<string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string>
|
<string name="app_dub_sub_episode_text_format" formatted="true">%s Ep %d</string>
|
||||||
<string name="cast_format" formatted="true">Cast: %s</string>
|
<string name="cast_format" formatted="true">Cast: %s</string>
|
||||||
<string name="next_episode_format" formatted="true">Bölüm %d şu tarihte yayınlanacak: </string>
|
<string name="next_episode_format" formatted="true">Bölüm %d şu tarihte yayınlanacak: </string>
|
||||||
|
@ -39,6 +39,7 @@
|
||||||
<string name="duration_format" formatted="true">%d dakika</string>
|
<string name="duration_format" formatted="true">%d dakika</string>
|
||||||
|
|
||||||
<string name="app_name">CloudStream</string>
|
<string name="app_name">CloudStream</string>
|
||||||
|
<string name="play_with_app_name">CloudStream ile oynat</string>
|
||||||
<string name="title_home">Ana sayfa</string>
|
<string name="title_home">Ana sayfa</string>
|
||||||
<string name="title_search">Arama</string>
|
<string name="title_search">Arama</string>
|
||||||
<string name="title_downloads">İndirilenler</string>
|
<string name="title_downloads">İndirilenler</string>
|
||||||
|
@ -66,6 +67,7 @@
|
||||||
<string name="type_re_watching">Yeniden izleniyor</string>
|
<string name="type_re_watching">Yeniden izleniyor</string>
|
||||||
|
|
||||||
<string name="play_movie_button">Filmi oynat</string>
|
<string name="play_movie_button">Filmi oynat</string>
|
||||||
|
<string name="play_livestream_button">Canlı yayını oynat</string>
|
||||||
<string name="play_torrent_button">Torrent oynat</string>
|
<string name="play_torrent_button">Torrent oynat</string>
|
||||||
<string name="pick_source">Kaynaklar</string>
|
<string name="pick_source">Kaynaklar</string>
|
||||||
<string name="pick_subtitle">Alt yazılar</string>
|
<string name="pick_subtitle">Alt yazılar</string>
|
||||||
|
@ -268,6 +270,7 @@
|
||||||
<string name="documentaries">Belgeseller</string>
|
<string name="documentaries">Belgeseller</string>
|
||||||
<string name="ova">OVA</string>
|
<string name="ova">OVA</string>
|
||||||
<string name="asian_drama">Asya dramaları</string>
|
<string name="asian_drama">Asya dramaları</string>
|
||||||
|
<string name="livestreams">Canlı yayınlar</string>
|
||||||
|
|
||||||
<!--singular-->
|
<!--singular-->
|
||||||
<string name="movies_singular">Film</string>
|
<string name="movies_singular">Film</string>
|
||||||
|
@ -278,6 +281,7 @@
|
||||||
<string name="torrent_singular">Torrent</string>
|
<string name="torrent_singular">Torrent</string>
|
||||||
<string name="documentaries_singular">Belgesel</string>
|
<string name="documentaries_singular">Belgesel</string>
|
||||||
<string name="asian_drama_singular">Asya draması</string>
|
<string name="asian_drama_singular">Asya draması</string>
|
||||||
|
<string name="live_singular">Canlı yayın</string>
|
||||||
|
|
||||||
<string name="source_error">Kaynak hatası</string>
|
<string name="source_error">Kaynak hatası</string>
|
||||||
<string name="remote_error">Sunucu hatası</string>
|
<string name="remote_error">Sunucu hatası</string>
|
||||||
|
@ -495,5 +499,15 @@
|
||||||
<string name="trailer">Fragman</string>
|
<string name="trailer">Fragman</string>
|
||||||
<string name="network_adress_example">Yayına bağlan</string>
|
<string name="network_adress_example">Yayına bağlan</string>
|
||||||
<string name="referer">Yönlendiren</string>
|
<string name="referer">Yönlendiren</string>
|
||||||
|
<string name="next">İleri</string>
|
||||||
|
<string name="provider_languages_tip">Videoları bu dillerde izle</string>
|
||||||
|
<string name="previous">Geri</string>
|
||||||
|
<string name="skip_setup">Kurulumu atla</string>
|
||||||
|
<!-- TODO: Remove or change this placeholder text -->
|
||||||
|
<string name="hello_blank_fragment">Merhaba boş parça</string>
|
||||||
|
<string name="app_layout_subtext">Cihazınıza uygun görünümü seçin</string>
|
||||||
|
<string name="crash_reporting_title">Çökme raporları</string>
|
||||||
|
<string name="preferred_media_subtext">Ne izlemek istiyorsunuz?</string>
|
||||||
|
<string name="setup_done">Bitti</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue