experimental inf homepage (9anime test)

This commit is contained in:
LagradOst 2022-07-30 05:43:57 +02:00
parent 334af5acfb
commit e64c84500d
89 changed files with 379 additions and 199 deletions

View File

@ -376,6 +376,32 @@ data class ProvidersInfoJson(
@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*/
abstract class MainAPI {
companion object {
@ -431,8 +457,14 @@ abstract class MainAPI {
open val vpnStatus = VPNStatus.None
open val providerType = ProviderType.DirectProvider
open val mainPage = listOf(MainPageData("", ""))
@WorkerThread
open suspend fun getMainPage(): HomePageResponse? {
open suspend fun getMainPage(
page: Int,
categoryName: String,
categoryData: String
): HomePageResponse? {
throw NotImplementedError()
}
@ -632,7 +664,8 @@ fun TvType.isAnimeOp(): Boolean {
data class SubtitleFile(val lang: String, val url: String)
data class HomePageResponse(
val items: List<HomePageList>
val items: List<HomePageList>,
val hasNext: Boolean = false
)
data class HomePageList(

View File

@ -104,7 +104,7 @@ class AllAnimeProvider : MainAPI() {
@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 urls = listOf(
// Pair(

View File

@ -114,7 +114,7 @@ class AniPlayProvider : MainAPI() {
@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 results = response.map{

View File

@ -45,7 +45,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 soup = app.get(mainUrl).document
val elements = listOf(

View File

@ -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 homePageList = ArrayList<HomePageList>()

View File

@ -58,7 +58,7 @@ class AnimePaheProvider : MainAPI() {
TvType.OVA
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
data class Data(
@JsonProperty("id") val id: Int,
@JsonProperty("anime_id") val animeId: Int,

View File

@ -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 homePageList = ArrayList<HomePageList>()

View File

@ -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 list = ArrayList<HomePageList>()
document.select("div.container:has(span.badge-saturn)").forEach {

View File

@ -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 list = ArrayList<HomePageList>()

View File

@ -30,7 +30,7 @@ class AnimefenixProvider:MainAPI() {
else DubStatus.Subbed
}
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val urls = listOf(
Pair("$mainUrl/", "Animes"),
Pair("$mainUrl/animes?type[]=movie&order=default", "Peliculas", ),

View File

@ -22,7 +22,7 @@ class AnimeflvIOProvider:MainAPI() {
TvType.OVA,
TvType.Anime,
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val items = ArrayList<HomePageList>()
val urls = listOf(
Pair("$mainUrl/series", "Series actualizadas",),

View File

@ -34,7 +34,7 @@ class AnimeflvnetProvider : MainAPI() {
TvType.Anime,
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val urls = listOf(
Pair("$mainUrl/browse?type[]=movie&order=updated", "Películas"),
Pair("$mainUrl/browse?status[]=2&order=default", "Animes"),

View File

@ -26,7 +26,7 @@ class AnimekisaProvider : MainAPI() {
@JsonProperty("html") val html: String
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val urls = listOf(
Pair("$mainUrl/ajax/list/views?type=all", "All animes"),
Pair("$mainUrl/ajax/list/views?type=day", "Trending now"),

View File

@ -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 lastEpisodeUrl = "$mainUrl/xz/epgrid.php?p=1&_=$unixTimeMS"
val recentlyAddedUrl = "$mainUrl/xz/gridgrabrecent.php?p=1&_=$unixTimeMS"

View File

@ -178,7 +178,7 @@ class GogoanimeProvider : MainAPI() {
TvType.OVA
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val headers = mapOf(
"authority" to "ajax.gogo-load.com",
"sec-ch-ua" to "\"Google Chrome\";v=\"89\", \"Chromium\";v=\"89\", \";Not A Brand\";v=\"99\"",

View File

@ -46,7 +46,7 @@ class GomunimeProvider : MainAPI() {
@JsonProperty("html") val html: String
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val urls = listOf(
Pair("e", "Episode Baru"),
Pair("c", "Completed"),

View File

@ -32,7 +32,7 @@ class JKAnimeProvider : MainAPI() {
TvType.Anime,
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val urls = listOf(
Pair(
"$mainUrl/directorio/?filtro=fecha&tipo=TV&estado=1&fecha=none&temporada=none&orden=desc",

View File

@ -14,7 +14,7 @@ class KawaiifuProvider : MainAPI() {
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 resp = app.get(mainUrl).text

View File

@ -17,7 +17,7 @@ class KimCartoonProvider : MainAPI() {
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 response = mutableListOf(
HomePageList(

View File

@ -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 homePageList = ArrayList<HomePageList>()

View File

@ -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 homePageList = ArrayList<HomePageList>()

View File

@ -34,7 +34,7 @@ class MonoschinosProvider : MainAPI() {
TvType.Anime,
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val urls = listOf(
Pair("$mainUrl/emision", "En emisión"),
Pair(

View File

@ -23,7 +23,7 @@ class MundoDonghuaProvider : MainAPI() {
TvType.Anime,
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val urls = listOf(
Pair("$mainUrl/lista-donghuas", "Donghuas"),
)

View File

@ -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 homePageList = ArrayList<HomePageList>()

View File

@ -137,44 +137,45 @@ class NineAnimeProvider : MainAPI() {
private fun decode(input: String): String = java.net.URLDecoder.decode(input, "utf-8")
}
override suspend fun getMainPage(): HomePageResponse {
val items = listOf(
"$mainUrl/ajax/home/widget/trending?page=1" to "Trending",
"$mainUrl/ajax/home/widget/updated-all?page=1" to "All",
"$mainUrl/ajax/home/widget/updated-sub?page=1" to "Recently Updated (SUB)",
"$mainUrl/ajax/home/widget/updated-dub?page=1" to
"Recently Updated (DUB)",
"$mainUrl/ajax/home/widget/updated-china?page=1" to
"Recently Updated (Chinese)",
"$mainUrl/ajax/home/widget/random?page=1" to "Random",
).apmap { (url, name) ->
val home = Jsoup.parse(
app.get(
url
).parsed<Response>().html
).select("div.item").mapNotNull { element ->
val title = element.selectFirst(".info > .name") ?: return@mapNotNull null
val link = title.attr("href")
val poster = element.selectFirst(".poster > a > img")?.attr("src")
val meta = element.selectFirst(".poster > a > .meta > .inner > .left")
val subbedEpisodes = meta?.selectFirst(".sub")?.text()?.toIntOrNull()
val dubbedEpisodes = meta?.selectFirst(".dub")?.text()?.toIntOrNull()
override val mainPage = mainPageOf(
"$mainUrl/ajax/home/widget/trending?page=" to "Trending",
"$mainUrl/ajax/home/widget/updated-all?page=" to "All",
"$mainUrl/ajax/home/widget/updated-sub?page=" to "Recently Updated (SUB)",
"$mainUrl/ajax/home/widget/updated-dub?page=" to "Recently Updated (DUB)",
"$mainUrl/ajax/home/widget/updated-china?page=" to "Recently Updated (Chinese)",
"$mainUrl/ajax/home/widget/random?page=" to "Random",
)
newAnimeSearchResponse(title.text() ?: return@mapNotNull null, link) {
this.posterUrl = poster
addDubStatus(
dubbedEpisodes != null,
subbedEpisodes != null,
dubbedEpisodes,
subbedEpisodes
)
}
override suspend fun getMainPage(
page: Int,
categoryName: String,
categoryData: String
): HomePageResponse {
val url = categoryData + page
val home = Jsoup.parse(
app.get(
url
).parsed<Response>().html
).select("div.item").mapNotNull { element ->
val title = element.selectFirst(".info > .name") ?: return@mapNotNull null
val link = title.attr("href")
val poster = element.selectFirst(".poster > a > img")?.attr("src")
val meta = element.selectFirst(".poster > a > .meta > .inner > .left")
val subbedEpisodes = meta?.selectFirst(".sub")?.text()?.toIntOrNull()
val dubbedEpisodes = meta?.selectFirst(".dub")?.text()?.toIntOrNull()
newAnimeSearchResponse(title.text() ?: return@mapNotNull null, link) {
this.posterUrl = poster
addDubStatus(
dubbedEpisodes != null,
subbedEpisodes != null,
dubbedEpisodes,
subbedEpisodes
)
}
HomePageList(name, home)
}
return HomePageResponse(items)
return newHomePageResponse(categoryName, home)
}
data class Response(

View File

@ -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 homePageList = ArrayList<HomePageList>()

View File

@ -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 homePageList = ArrayList<HomePageList>()

View File

@ -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 homePageList = ArrayList<HomePageList>()

View File

@ -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 soup = app.get(mainUrl, interceptor = ddosGuardKiller).document
for (section in soup.select("#content > section")) {

View File

@ -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 homePageList = ArrayList<HomePageList>()

View File

@ -30,7 +30,7 @@ class WcoProvider : MainAPI() {
TvType.OVA
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val urls = listOf(
Pair("$mainUrl/ajax/list/recently_updated?type=tv", "Recently Updated Anime"),
Pair("$mainUrl/ajax/list/recently_updated?type=movie", "Recently Updated Movies"),

View File

@ -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 document = Jsoup.parse(html)

View File

@ -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?
val language = "English"
val dataMap = mapOf(

View File

@ -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
// val popularSeries = tmdb.tvService().popular(1, "en-US").execute().body()?.results?.map {

View File

@ -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
val moviesUrl = listOf(
"Movies" to "$mainUrl/movies",

View File

@ -27,7 +27,7 @@ class AllMoviesForYouProvider : MainAPI() {
TvType.TvSeries
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val items = ArrayList<HomePageList>()
val soup = app.get(mainUrl).document
val urls = listOf(

View File

@ -18,7 +18,7 @@ class AltadefinizioneProvider : MainAPI() {
TvType.Movie
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val items = ArrayList<HomePageList>()
val urls = listOf(
Pair("$mainUrl/azione/", "Azione"),

View File

@ -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 response = app.get("$apiUrl/dashboard", headers = headers).text

View File

@ -23,7 +23,7 @@ open class BflixProvider : MainAPI() {
//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 soup = app.get("$mainUrl/home").document
val testa = listOf(

View File

@ -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 pages = doc.select("section").not("section:contains(أختر وجهتك المفضلة)").not("section:contains(تم اضافته حديثاً)").apmap {

View File

@ -17,7 +17,7 @@ class CineblogProvider : MainAPI() {
TvType.TvSeries,
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val items = ArrayList<HomePageList>()
val urls = listOf(
Pair("$mainUrl/genere/azione/", "Azione"),

View File

@ -19,7 +19,7 @@ class CinecalidadProvider : MainAPI() {
)
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 urls = listOf(
Pair("$mainUrl/ver-serie/", "Series"),

View File

@ -19,7 +19,7 @@ class CuevanaProvider : MainAPI() {
TvType.TvSeries,
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val items = ArrayList<HomePageList>()
val urls = listOf(
Pair(mainUrl, "Recientemente actualizadas"),

View File

@ -31,7 +31,7 @@ class DoramasYTProvider : MainAPI() {
TvType.AsianDrama,
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val urls = listOf(
Pair("$mainUrl/emision", "En emisión"),
Pair(

View File

@ -14,7 +14,7 @@ class DramaSeeProvider : MainAPI() {
override val hasDownloadSupport = true
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 document = app.get(mainUrl, headers = headers).document
val mainbody = document.getElementsByTag("body")

View File

@ -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 homePageList = ArrayList<HomePageList>()

View File

@ -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
val doc = app.get(mainUrl).document
val pages = arrayListOf<HomePageList>()

View File

@ -15,7 +15,7 @@ class ElifilmsProvider : MainAPI() {
TvType.Movie,
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val items = ArrayList<HomePageList>()
val newest = app.get(mainUrl).document.selectFirst("a.fav_link.premiera")?.attr("href")
val urls = listOf(

View File

@ -18,7 +18,7 @@ class EntrepeliculasyseriesProvider:MainAPI() {
)
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 urls = listOf(
Pair("$mainUrl/series/", "Series"),

View File

@ -28,7 +28,7 @@ class EstrenosDoramasProvider : MainAPI() {
TvType.AsianDrama,
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val urls = listOf(
Pair(mainUrl, "Últimas series"),
Pair("$mainUrl/category/peliculas", "Películas"),

View File

@ -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
val moviesUrl = listOf(
Pair("Movies", "$mainUrl/all-movies/page/"+(0..10).random()),

View File

@ -18,7 +18,7 @@ class FilmanProvider : MainAPI() {
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 lists = document.select("#item-list,#series-list")
val categories = ArrayList<HomePageList>()

View File

@ -23,7 +23,7 @@ class FilmpertuttiProvider : MainAPI() {
TvType.TvSeries
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val items = ArrayList<HomePageList>()
val urls = listOf(
Pair("$mainUrl/category/serie-tv/", "Serie Tv"),

View File

@ -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 docs = document.select("div.sect")
val returnList = docs.mapNotNull {

View File

@ -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 document = Jsoup.parse(html)
val all = ArrayList<HomePageList>()

View File

@ -19,7 +19,7 @@ class HDMovie5 : MainAPI() {
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 list = mapOf(
"Featured Movies" to "featured",

View File

@ -28,7 +28,7 @@ class HDrezkaProvider : MainAPI() {
TvType.AsianDrama
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val items = ArrayList<HomePageList>()

View File

@ -14,7 +14,7 @@ class IHaveNoTvProvider : MainAPI() {
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",
// so I am just scraping 3 random categories
val allCategories = listOf(

View File

@ -22,7 +22,7 @@ class IdlixProvider : MainAPI() {
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 homePageList = ArrayList<HomePageList>()

View File

@ -26,7 +26,7 @@ class KdramaHoodProvider : MainAPI() {
@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 home = ArrayList<HomePageList>()

View File

@ -21,7 +21,7 @@ class LayarKacaProvider : MainAPI() {
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 homePageList = ArrayList<HomePageList>()

View File

@ -22,7 +22,7 @@ class MultiplexProvider : MainAPI() {
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 homePageList = ArrayList<HomePageList>()

View File

@ -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
val moviesUrl = listOf(
"Movies" to "$mainUrl/movies/page/" + (0..25).random(),

View File

@ -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 =
getAuthHeader() // call again because it isn't reloaded if in main class and storedCredentials loads after

View File

@ -17,7 +17,7 @@ class PeliSmartProvider: MainAPI() {
)
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 urls = listOf(
Pair("$mainUrl/peliculas/", "Peliculas"),

View File

@ -18,7 +18,7 @@ class PelisflixProvider : MainAPI() {
TvType.TvSeries,
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val items = ArrayList<HomePageList>()
val urls = listOf(
Pair("$mainUrl/ver-peliculas-online-gratis-fullhdc3/", "Películas"),

View File

@ -16,7 +16,7 @@ class PelisplusHDProvider:MainAPI() {
TvType.Movie,
TvType.TvSeries,
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val items = ArrayList<HomePageList>()
val document = app.get(mainUrl).document
val map = mapOf(

View File

@ -142,7 +142,7 @@ open class PelisplusProviderTemplate : MainAPI() {
// 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.
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val urls = homePageUrlList
val homePageList = ArrayList<HomePageList>()
// .pmap {} is used to fetch the different pages in parallel

View File

@ -23,7 +23,7 @@ class PhimmoichillProvider : MainAPI() {
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 homePageList = ArrayList<HomePageList>()

View File

@ -15,7 +15,7 @@ class PinoyHDXyzProvider : MainAPI() {
override val hasMainPage = true
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 document = app.get(mainUrl, referer = mainUrl).document
val mainbody = document.getElementsByTag("body")

View File

@ -16,7 +16,7 @@ class PinoyMoviePediaProvider : MainAPI() {
override val hasMainPage = true
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 document = app.get(mainUrl).document
val mainbody = document.getElementsByTag("body")

View File

@ -90,7 +90,7 @@ class PinoyMoviesEsProvider : MainAPI() {
return all
}
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val all = ArrayList<HomePageList>()
val document = app.get(mainUrl).document
val mainbody = document.getElementsByTag("body")

View File

@ -27,7 +27,7 @@ class RebahinProvider : MainAPI() {
TvType.AsianDrama
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val urls = listOf(
Pair("Featured", "xtab1"),
Pair("Film Terbaru", "xtab2"),

View File

@ -18,7 +18,7 @@ class SeriesflixProvider : MainAPI() {
TvType.TvSeries,
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val items = ArrayList<HomePageList>()
val urls = listOf(
Pair("$mainUrl/ver-series-online/", "Series"),

View File

@ -41,7 +41,7 @@ open class SflixProvider : MainAPI() {
)
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 document = Jsoup.parse(html)

View File

@ -19,7 +19,7 @@ class SoaptwoDayProvider : MainAPI() {
TvType.TvSeries,
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val items = ArrayList<HomePageList>()
val urls = listOf(
Pair("$mainUrl/movielist/", "Movies"),

View File

@ -174,7 +174,7 @@ class StreamingcommunityProvider : MainAPI() {
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 document = app.get(mainUrl).document
document.select("slider-title").subList(0, 6).map { it ->

View File

@ -18,7 +18,7 @@ class TantifilmProvider : MainAPI() {
TvType.TvSeries,
)
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val items = ArrayList<HomePageList>()
val urls = listOf(
Pair("$mainUrl/watch-genre/serie-tv/", "Serie Tv"),

View File

@ -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 doc = app.get(mainUrl).document
val scriptText = doc.selectFirst("script[type=application/json]")!!.data()

View File

@ -23,7 +23,7 @@ class UakinoProvider : MainAPI() {
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 homePageList = ArrayList<HomePageList>()

View File

@ -210,7 +210,7 @@ open class VidstreamProviderTemplate : MainAPI() {
// 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.
override suspend fun getMainPage(): HomePageResponse {
override suspend fun getMainPage(page: Int, categoryName: String, categoryData: String): HomePageResponse {
val urls = homePageUrlList
val homePageList = ArrayList<HomePageList>()
// .pmap {} is used to fetch the different pages in parallel

View File

@ -18,7 +18,7 @@ class WatchAsianProvider : MainAPI() {
override val hasDownloadSupport = true
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 doc = app.get(mainUrl, headers = headers).document
val rowPair = mutableListOf<Pair<String, String>>()

View File

@ -2,7 +2,6 @@ package com.lagradost.cloudstream3.movieproviders
import com.lagradost.cloudstream3.*
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.Qualities
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 sections = document.select("div.group-film")
return HomePageResponse(sections.mapNotNull { section ->

View File

@ -19,7 +19,7 @@ class YomoviesProvider : MainAPI() {
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 homePageList = ArrayList<HomePageList>()

View File

@ -4,6 +4,7 @@ import android.util.Log
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import com.bumptech.glide.load.HttpException
import com.lagradost.cloudstream3.BuildConfig
import com.lagradost.cloudstream3.ErrorLoadingException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@ -11,6 +12,34 @@ import java.net.SocketTimeoutException
import java.net.UnknownHostException
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) {
liveData.observe(this) { it?.let { t -> action(t) } }
}
@ -61,11 +90,12 @@ suspend fun <T> suspendSafeApiCall(apiCall: suspend () -> T): T? {
}
fun <T> safeFail(throwable: Throwable): Resource<T> {
val stackTraceMsg = (throwable.localizedMessage ?: "") + "\n\n" + throwable.stackTrace.joinToString(
separator = "\n"
) {
"${it.fileName} ${it.lineNumber}"
}
val stackTraceMsg =
(throwable.localizedMessage ?: "") + "\n\n" + throwable.stackTrace.joinToString(
separator = "\n"
) {
"${it.fileName} ${it.lineNumber}"
}
return Resource.Failure(false, null, null, stackTraceMsg)
}
@ -92,16 +122,31 @@ suspend fun <T> safeApiCall(
safeFail(throwable)
}
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 -> {
Resource.Failure(false, throwable.statusCode, null, throwable.message ?: "HttpException")
Resource.Failure(
false,
throwable.statusCode,
null,
throwable.message ?: "HttpException"
)
}
is UnknownHostException -> {
Resource.Failure(true, null, null, "Cannot connect to server, try again later.")
}
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 -> {
Resource.Failure(false, null, null, "This operation is not implemented.")

View File

@ -29,6 +29,7 @@ class APIRepository(val api: MainAPI) {
val hasMainPage = api.hasMainPage
val name = api.name
val mainUrl = api.mainUrl
val mainPage = api.mainPage
val hasQuickSearch = api.hasQuickSearch
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 {
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)
}
}
}

View File

@ -20,10 +20,8 @@ import androidx.core.widget.NestedScrollView
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSnapHelper
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.button.MaterialButton
import com.lagradost.cloudstream3.*
@ -44,7 +42,6 @@ import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
import com.lagradost.cloudstream3.ui.result.START_ACTION_RESUME_LATEST
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.settings.SettingsFragment.Companion.isTrueTvSettings
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
@ -349,8 +346,6 @@ class HomeFragment : Fragment() {
return inflater.inflate(layout, container, false)
}
private var currentHomePage: HomePageResponse? = null
private fun toggleMainVisibility(visible: Boolean) {
home_main_holder?.isVisible = visible
home_main_poster_recyclerview?.isVisible = visible
@ -541,18 +536,8 @@ class HomeFragment : Fragment() {
val d = data.value
listHomepageItems.clear()
currentHomePage = d
(home_master_recycler?.adapter as? ParentItemAdapter?)?.updateList(
d?.items?.mapNotNull {
try {
val filter = it.list.filterSearchResponse()
listHomepageItems.addAll(filter)
it.copy(list = filter)
} catch (e: Exception) {
logError(e)
null
}
} ?: listOf())
// println("ITEMCOUNT: ${d.values.size} ${home_master_recycler?.adapter?.itemCount}")
(home_master_recycler?.adapter as? ParentItemAdapter?)?.updateList(d.values.toMutableList())
home_loading?.isVisible = false
home_loading_error?.isVisible = false
@ -603,13 +588,6 @@ class HomeFragment : Fragment() {
}
}
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
ParentItemAdapter(mutableListOf(), { callback ->
homeHandleSearch(callback)
}, { item ->
activity?.loadHomepageList(item)
})
val toggleList = listOf(
Pair(home_type_watching_btt, WatchType.WATCHING),
Pair(home_type_completed_btt, WatchType.COMPLETED),
@ -861,9 +839,19 @@ class HomeFragment : Fragment() {
context?.fixPaddingStatusbarView(home_statusbar)
context?.fixPaddingStatusbar(home_loading_statusbar)
home_master_recycler.adapter = adapter
home_master_recycler.layoutManager = GridLayoutManager(context, 1)
home_master_recycler.adapter =
ParentItemAdapter(mutableListOf(), { callback ->
homeHandleSearch(callback)
}, { item ->
activity?.loadHomepageList(item)
}, { name ->
homeViewModel.expand(name)
})
home_master_recycler.layoutManager = object : LinearLayoutManager(context) {
override fun supportsPredictiveItemAnimations(): Boolean {
return false
}
}; // GridLayoutManager(context, 1).also { it.supportsPredictiveItemAnimations() }
if (context?.isTvSettings() == false) {
LinearSnapHelper().attachToRecyclerView(home_main_poster_recyclerview) // snap

View File

@ -13,18 +13,22 @@ import com.lagradost.cloudstream3.ui.search.SearchClickCallback
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
import kotlinx.android.synthetic.main.homepage_parent.view.*
class ParentItemAdapter(
private var items: MutableList<HomePageList>,
private var items: MutableList<HomeViewModel.ExpandableHomepageList>,
private val clickCallback: (SearchClickCallback) -> Unit,
private val moreInfoClickCallback: (HomePageList) -> Unit,
private val expandCallback: ((String) -> Unit)? = null,
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, i: Int): ParentViewHolder {
val layout =
if (parent.context.isTvSettings()) R.layout.homepage_parent_tv else R.layout.homepage_parent
return ParentViewHolder(
LayoutInflater.from(parent.context).inflate(layout, parent, false),
clickCallback,
moreInfoClickCallback
moreInfoClickCallback,
expandCallback
)
}
@ -41,28 +45,41 @@ class ParentItemAdapter(
}
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>) {
// this moves all bad results to the bottom
val endList = mutableListOf<HomePageList>()
val newFilteredList = mutableListOf<HomePageList>()
for (item in newList) {
if (item.list.isEmpty()) {
endList.add(item)
} else {
newFilteredList.add(item)
}
}
newFilteredList.addAll(endList)
updateList(newList.map { HomeViewModel.ExpandableHomepageList(it, 1, false) }
.toMutableList())
}
@JvmName("updateListExpandableHomepageList")
fun updateList(newList: MutableList<HomeViewModel.ExpandableHomepageList>) {
val diffResult = DiffUtil.calculateDiff(
SearchDiffCallback(this.items, newFilteredList)
SearchDiffCallback(items, newList)
)
items.clear()
items.addAll(newFilteredList)
items.addAll(newList.map { it.copy(list = it.list.copy()) }) // I have to do this otherwise it is a "copy" and dispatchUpdatesTo wont work
/*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?) {
mAdapter.notifyItemRangeChanged(position, count, payload)
}
})*/
diffResult.dispatchUpdatesTo(this)
}
@ -71,14 +88,16 @@ class ParentItemAdapter(
constructor(
itemView: View,
private val clickCallback: (SearchClickCallback) -> Unit,
private val moreInfoClickCallback: (HomePageList) -> Unit
private val moreInfoClickCallback: (HomePageList) -> Unit,
private val expandCallback: ((String) -> Unit)? = null,
) :
RecyclerView.ViewHolder(itemView) {
val title: TextView = itemView.home_parent_item_title
val recyclerView: RecyclerView = itemView.home_child_recyclerview
private val moreInfo: FrameLayout? = itemView.home_child_more_info
fun bind(info: HomePageList) {
title.text = info.name
fun bind(expand: HomeViewModel.ExpandableHomepageList) {
val info = expand.list
recyclerView.adapter = HomeChildItemAdapter(
info.list.toMutableList(),
clickCallback = clickCallback,
@ -88,6 +107,23 @@ class ParentItemAdapter(
isHorizontal = info.isHorizontalImages
}
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 count = recyclerView.adapter?.itemCount ?: return
if (!recyclerView.canScrollHorizontally(1) && expand.hasNext && expandCount != count) {
expandCount = count
expandCallback?.invoke(name)
}
}
})
//(recyclerView.adapter as HomeChildItemAdapter).notifyDataSetChanged()
moreInfo?.setOnClickListener {
@ -98,17 +134,22 @@ class ParentItemAdapter(
}
class SearchDiffCallback(
private val oldList: List<HomePageList>,
private val newList: List<HomePageList>
private val oldList: List<HomeViewModel.ExpandableHomepageList>,
private val newList: List<HomeViewModel.ExpandableHomepageList>
) :
DiffUtil.Callback() {
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 getNewListSize() = newList.size
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
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
//}
}

View File

@ -10,10 +10,12 @@ import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
import com.lagradost.cloudstream3.AcraApplication.Companion.context
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
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.SearchResponse
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.ui.APIRepository
import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi
@ -34,6 +36,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.*
import kotlin.collections.set
class HomeViewModel : ViewModel() {
private var repo: APIRepository? = null
@ -41,9 +44,6 @@ class HomeViewModel : ViewModel() {
private val _apiName = MutableLiveData<String>()
val apiName: LiveData<String> = _apiName
private val _page = MutableLiveData<Resource<HomePageResponse?>>()
val page: LiveData<Resource<HomePageResponse?>> = _page
private val _randomItems = MutableLiveData<List<SearchResponse>?>(null)
val randomItems: LiveData<List<SearchResponse>?> = _randomItems
@ -51,8 +51,10 @@ class HomeViewModel : ViewModel() {
return APIRepository(apis.first { it.hasMainPage })
}
private val _availableWatchStatusTypes = MutableLiveData<Pair<EnumSet<WatchType>, EnumSet<WatchType>>>()
val availableWatchStatusTypes: LiveData<Pair<EnumSet<WatchType>, EnumSet<WatchType>>> = _availableWatchStatusTypes
private val _availableWatchStatusTypes =
MutableLiveData<Pair<EnumSet<WatchType>, EnumSet<WatchType>>>()
val availableWatchStatusTypes: LiveData<Pair<EnumSet<WatchType>, EnumSet<WatchType>>> =
_availableWatchStatusTypes
private val _bookmarks = MutableLiveData<Pair<Boolean, List<SearchResponse>>>()
val bookmarks: LiveData<Pair<Boolean, List<SearchResponse>>> = _bookmarks
@ -143,6 +145,64 @@ class HomeViewModel : ViewModel() {
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()
// 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 {
if (lock.contains(name)) return@launch
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}"
}
val before = list.list.size
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
expandable[key] = this
val after = list.list.size
} ?: 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
}
private fun load(api: MainAPI?) = viewModelScope.launch {
repo = if (api != null) {
APIRepository(api)
@ -156,35 +216,43 @@ class HomeViewModel : ViewModel() {
if (repo?.hasMainPage == true) {
_page.postValue(Resource.Loading())
val data = repo?.getMainPage()
when (data) {
when (val data = repo?.getMainPage(1, null)) {
is Resource.Success -> {
try {
val home = data.value
if (home?.items?.isNullOrEmpty() == false) {
expandable.clear()
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 =
home.items.shuffled().filter { !it.list.isNullOrEmpty() }.flatMap { it.list }
items.shuffled().filter { it.list.isNotEmpty() }
.flatMap { it.list }
.distinctBy { it.url }
.toList()
if (!currentList.isNullOrEmpty()) {
if (currentList.isNotEmpty()) {
val randomItems = currentList.shuffled()
_randomItems.postValue(randomItems)
}
}
} catch (e : Exception) {
} catch (e: Exception) {
_randomItems.postValue(emptyList())
logError(e)
}
}
is Resource.Failure -> {
_page.postValue(data!!)
}
else -> Unit
}
data?.let {
_page.postValue(it)
}
} else {
_page.postValue(Resource.Success(HomePageResponse(emptyList())))
}
}
@ -194,7 +262,7 @@ class HomeViewModel : ViewModel() {
loadAndCancel(noneApi)
else if (preferredApiName == randomApi.name || api == null) {
val validAPIs = context?.filterProviderByPreferredMedia()
if(validAPIs.isNullOrEmpty()) {
if (validAPIs.isNullOrEmpty()) {
loadAndCancel(noneApi)
} else {
val apiRandom = validAPIs.random()