forked from recloudstream/cloudstream
		
	updated anime API for dub/sub
This commit is contained in:
		
							parent
							
								
									32a0658611
								
							
						
					
					
						commit
						2f9c76d9b5
					
				
					 13 changed files with 280 additions and 262 deletions
				
			
		|  | @ -255,7 +255,8 @@ fun sortSubs(urls: List<SubtitleFile>): List<SubtitleFile> { | ||||||
| 
 | 
 | ||||||
| /** https://www.imdb.com/title/tt2861424/ -> tt2861424 */ | /** https://www.imdb.com/title/tt2861424/ -> tt2861424 */ | ||||||
| fun imdbUrlToId(url: String): String? { | fun imdbUrlToId(url: String): String? { | ||||||
|     return Regex("/title/(tt[0-9]*)").find(url)?.groupValues?.get(1) ?: Regex("tt[0-9]{5,}").find(url)?.groupValues?.get(0) |     return Regex("/title/(tt[0-9]*)").find(url)?.groupValues?.get(1) | ||||||
|  |         ?: Regex("tt[0-9]{5,}").find(url)?.groupValues?.get(0) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fun imdbUrlToIdNullable(url: String?): String? { | fun imdbUrlToIdNullable(url: String?): String? { | ||||||
|  | @ -390,12 +391,12 @@ fun LoadResponse?.isAnimeBased(): Boolean { | ||||||
| 
 | 
 | ||||||
| data class AnimeEpisode( | data class AnimeEpisode( | ||||||
|     val url: String, |     val url: String, | ||||||
|     val name: String? = null, |     var name: String? = null, | ||||||
|     val posterUrl: String? = null, |     var posterUrl: String? = null, | ||||||
|     val date: String? = null, |     var date: String? = null, | ||||||
|     val rating: Int? = null, |     var rating: Int? = null, | ||||||
|     val descript: String? = null, |     var description: String? = null, | ||||||
|     val episode: Int? = null, |     var episode: Int? = null, | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| data class TorrentLoadResponse( | data class TorrentLoadResponse( | ||||||
|  | @ -416,32 +417,47 @@ data class TorrentLoadResponse( | ||||||
| ) : LoadResponse | ) : LoadResponse | ||||||
| 
 | 
 | ||||||
| data class AnimeLoadResponse( | data class AnimeLoadResponse( | ||||||
|     val engName: String?, |     var engName: String? = null, | ||||||
|     val japName: String?, |     var japName: String? = null, | ||||||
|     override val name: String, |     override val name: String, | ||||||
|     override val url: String, |     override val url: String, | ||||||
|     override val apiName: String, |     override val apiName: String, | ||||||
|     override val type: TvType, |     override val type: TvType, | ||||||
| 
 | 
 | ||||||
|     override val posterUrl: String?, |     override var posterUrl: String? = null, | ||||||
|     override val year: Int?, |     override var year: Int? = null, | ||||||
| 
 | 
 | ||||||
|     val dubEpisodes: List<AnimeEpisode>?, |     var episodes: HashMap<DubStatus, List<AnimeEpisode>> = hashMapOf(), | ||||||
|     val subEpisodes: List<AnimeEpisode>?, |     var showStatus: ShowStatus? = null, | ||||||
|     val showStatus: ShowStatus?, |  | ||||||
| 
 | 
 | ||||||
|     override val plot: String?, |     override var plot: String? = null, | ||||||
|     override val tags: List<String>? = null, |     override var tags: List<String>? = null, | ||||||
|     val synonyms: List<String>? = null, |     var synonyms: List<String>? = null, | ||||||
| 
 | 
 | ||||||
|     val malId: Int? = null, |     var malId: Int? = null, | ||||||
|     val anilistId: Int? = null, |     var anilistId: Int? = null, | ||||||
|     override val rating: Int? = null, |     override var rating: Int? = null, | ||||||
|     override val duration: String? = null, |     override var duration: String? = null, | ||||||
|     override val trailerUrl: String? = null, |     override var trailerUrl: String? = null, | ||||||
|     override val recommendations: List<SearchResponse>? = null, |     override var recommendations: List<SearchResponse>? = null, | ||||||
| ) : LoadResponse | ) : LoadResponse | ||||||
| 
 | 
 | ||||||
|  | fun AnimeLoadResponse.addEpisodes(status : DubStatus, episodes : List<AnimeEpisode>?) { | ||||||
|  |     if(episodes == null) return | ||||||
|  |     this.episodes[status] = episodes | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fun MainAPI.newAnimeLoadResponse( | ||||||
|  |     name: String, | ||||||
|  |     url: String, | ||||||
|  |     type: TvType, | ||||||
|  |     initializer: AnimeLoadResponse.() -> Unit = { } | ||||||
|  | ): AnimeLoadResponse { | ||||||
|  |     val builder = AnimeLoadResponse(name = name, url = url, apiName = this.name, type = type) | ||||||
|  |     builder.initializer() | ||||||
|  |     return builder | ||||||
|  | } | ||||||
|  | 
 | ||||||
| data class MovieLoadResponse( | data class MovieLoadResponse( | ||||||
|     override val name: String, |     override val name: String, | ||||||
|     override val url: String, |     override val url: String, | ||||||
|  | @ -449,11 +465,11 @@ data class MovieLoadResponse( | ||||||
|     override val type: TvType, |     override val type: TvType, | ||||||
|     val dataUrl: String, |     val dataUrl: String, | ||||||
| 
 | 
 | ||||||
|     override val posterUrl: String?, |     override val posterUrl: String? = null, | ||||||
|     override val year: Int?, |     override val year: Int? = null, | ||||||
|     override val plot: String?, |     override val plot: String? = null, | ||||||
| 
 | 
 | ||||||
|     val imdbId: String?, |     val imdbId: String? = null, | ||||||
|     override val rating: Int? = null, |     override val rating: Int? = null, | ||||||
|     override val tags: List<String>? = null, |     override val tags: List<String>? = null, | ||||||
|     override val duration: String? = null, |     override val duration: String? = null, | ||||||
|  | @ -462,9 +478,9 @@ data class MovieLoadResponse( | ||||||
| ) : LoadResponse | ) : LoadResponse | ||||||
| 
 | 
 | ||||||
| data class TvSeriesEpisode( | data class TvSeriesEpisode( | ||||||
|     val name: String?, |     val name: String? = null, | ||||||
|     val season: Int?, |     val season: Int? = null, | ||||||
|     val episode: Int?, |     val episode: Int? = null, | ||||||
|     val data: String, |     val data: String, | ||||||
|     val posterUrl: String? = null, |     val posterUrl: String? = null, | ||||||
|     val date: String? = null, |     val date: String? = null, | ||||||
|  | @ -479,12 +495,12 @@ data class TvSeriesLoadResponse( | ||||||
|     override val type: TvType, |     override val type: TvType, | ||||||
|     val episodes: List<TvSeriesEpisode>, |     val episodes: List<TvSeriesEpisode>, | ||||||
| 
 | 
 | ||||||
|     override val posterUrl: String?, |     override val posterUrl: String? = null, | ||||||
|     override val year: Int?, |     override val year: Int? = null, | ||||||
|     override val plot: String?, |     override val plot: String? = null, | ||||||
| 
 | 
 | ||||||
|     val showStatus: ShowStatus?, |     val showStatus: ShowStatus? = null, | ||||||
|     val imdbId: String?, |     val imdbId: String? = null, | ||||||
|     override val rating: Int? = null, |     override val rating: Int? = null, | ||||||
|     override val tags: List<String>? = null, |     override val tags: List<String>? = null, | ||||||
|     override val duration: String? = null, |     override val duration: String? = null, | ||||||
|  |  | ||||||
|  | @ -1,21 +1,19 @@ | ||||||
| package com.lagradost.cloudstream3.animeproviders | package com.lagradost.cloudstream3.animeproviders | ||||||
| 
 | 
 | ||||||
| import com.lagradost.cloudstream3.* |  | ||||||
| import com.lagradost.cloudstream3.utils.* |  | ||||||
| import com.lagradost.cloudstream3.network.get |  | ||||||
| import com.lagradost.cloudstream3.network.text |  | ||||||
| import com.lagradost.cloudstream3.utils.ExtractorLink |  | ||||||
| import org.jsoup.Jsoup |  | ||||||
| import java.util.* |  | ||||||
| 
 |  | ||||||
| import com.fasterxml.jackson.annotation.JsonProperty | import com.fasterxml.jackson.annotation.JsonProperty | ||||||
| import com.fasterxml.jackson.module.kotlin.readValue | import com.fasterxml.jackson.module.kotlin.readValue | ||||||
| import kotlin.collections.ArrayList | import com.lagradost.cloudstream3.* | ||||||
|  | import com.lagradost.cloudstream3.network.get | ||||||
|  | import com.lagradost.cloudstream3.network.text | ||||||
|  | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
|  | import com.lagradost.cloudstream3.utils.M3u8Helper | ||||||
|  | import com.lagradost.cloudstream3.utils.getQualityFromName | ||||||
|  | import org.jsoup.Jsoup | ||||||
| import org.mozilla.javascript.Context | import org.mozilla.javascript.Context | ||||||
| import org.mozilla.javascript.Scriptable | import org.mozilla.javascript.Scriptable | ||||||
| import java.net.URI | import java.net.URI | ||||||
| import java.net.URLDecoder | import java.net.URLDecoder | ||||||
| import com.lagradost.cloudstream3.utils.getQualityFromName | import java.util.* | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class AllAnimeProvider : MainAPI() { | class AllAnimeProvider : MainAPI() { | ||||||
|  | @ -41,17 +39,17 @@ class AllAnimeProvider : MainAPI() { | ||||||
|     override val supportedTypes: Set<TvType> |     override val supportedTypes: Set<TvType> | ||||||
|         get() = setOf(TvType.Anime, TvType.AnimeMovie) |         get() = setOf(TvType.Anime, TvType.AnimeMovie) | ||||||
| 
 | 
 | ||||||
|     private data class Data ( |     private data class Data( | ||||||
|         @JsonProperty("shows") val shows: Shows |         @JsonProperty("shows") val shows: Shows | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     private data class Shows ( |     private data class Shows( | ||||||
|         @JsonProperty("pageInfo") val pageInfo: PageInfo, |         @JsonProperty("pageInfo") val pageInfo: PageInfo, | ||||||
|         @JsonProperty("edges") val edges: List<Edges>, |         @JsonProperty("edges") val edges: List<Edges>, | ||||||
|         @JsonProperty("__typename") val _typename: String |         @JsonProperty("__typename") val _typename: String | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     private data class Edges ( |     private data class Edges( | ||||||
|         @JsonProperty("_id") val Id: String?, |         @JsonProperty("_id") val Id: String?, | ||||||
|         @JsonProperty("name") val name: String, |         @JsonProperty("name") val name: String, | ||||||
|         @JsonProperty("englishName") val englishName: String?, |         @JsonProperty("englishName") val englishName: String?, | ||||||
|  | @ -68,34 +66,35 @@ class AllAnimeProvider : MainAPI() { | ||||||
|         @JsonProperty("status") val status: String?, |         @JsonProperty("status") val status: String?, | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     private data class AvailableEpisodes ( |     private data class AvailableEpisodes( | ||||||
|         @JsonProperty("sub") val sub: Int, |         @JsonProperty("sub") val sub: Int, | ||||||
|         @JsonProperty("dub") val dub: Int, |         @JsonProperty("dub") val dub: Int, | ||||||
|         @JsonProperty("raw") val raw: Int |         @JsonProperty("raw") val raw: Int | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     private data class AiredStart ( |     private data class AiredStart( | ||||||
|         @JsonProperty("year") val year: Int, |         @JsonProperty("year") val year: Int, | ||||||
|         @JsonProperty("month") val month: Int, |         @JsonProperty("month") val month: Int, | ||||||
|         @JsonProperty("date") val date: Int |         @JsonProperty("date") val date: Int | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     private data class Season ( |     private data class Season( | ||||||
|         @JsonProperty("quarter") val quarter: String, |         @JsonProperty("quarter") val quarter: String, | ||||||
|         @JsonProperty("year") val year: Int |         @JsonProperty("year") val year: Int | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     private data class PageInfo ( |     private data class PageInfo( | ||||||
|         @JsonProperty("total") val total: Int, |         @JsonProperty("total") val total: Int, | ||||||
|         @JsonProperty("__typename") val _typename: String |         @JsonProperty("__typename") val _typename: String | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     private data class AllAnimeQuery ( |     private data class AllAnimeQuery( | ||||||
|         @JsonProperty("data") val data: Data |         @JsonProperty("data") val data: Data | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     override fun search(query: String): ArrayList<SearchResponse> { |     override fun search(query: String): ArrayList<SearchResponse> { | ||||||
|         val link = """$mainUrl/graphql?variables=%7B%22search%22%3A%7B%22allowAdult%22%3Afalse%2C%22query%22%3A%22$query%22%7D%2C%22limit%22%3A26%2C%22page%22%3A1%2C%22translationType%22%3A%22sub%22%7D&extensions=%7B%22persistedQuery%22%3A%7B%22version%22%3A1%2C%22sha256Hash%22%3A%229343797cc3d9e3f444e2d3b7db9a84d759b816a4d84512ea72d079f85bb96e98%22%7D%7D""" |         val link = | ||||||
|  |             """$mainUrl/graphql?variables=%7B%22search%22%3A%7B%22allowAdult%22%3Afalse%2C%22query%22%3A%22$query%22%7D%2C%22limit%22%3A26%2C%22page%22%3A1%2C%22translationType%22%3A%22sub%22%7D&extensions=%7B%22persistedQuery%22%3A%7B%22version%22%3A1%2C%22sha256Hash%22%3A%229343797cc3d9e3f444e2d3b7db9a84d759b816a4d84512ea72d079f85bb96e98%22%7D%7D""" | ||||||
|         var res = get(link).text |         var res = get(link).text | ||||||
|         if (res.contains("PERSISTED_QUERY_NOT_FOUND")) { |         if (res.contains("PERSISTED_QUERY_NOT_FOUND")) { | ||||||
|             res = get(link).text |             res = get(link).text | ||||||
|  | @ -116,15 +115,15 @@ class AllAnimeProvider : MainAPI() { | ||||||
|                 TvType.Anime, |                 TvType.Anime, | ||||||
|                 it.thumbnail, |                 it.thumbnail, | ||||||
|                 it.airedStart?.year, |                 it.airedStart?.year, | ||||||
|                 EnumSet.of(DubStatus.Subbed),  //, DubStatus.Dubbed), |                 EnumSet.of(DubStatus.Subbed, DubStatus.Dubbed), | ||||||
|                 it.englishName, |                 it.englishName, | ||||||
|                 null, //it.availableEpisodes?.dub, |                 it.availableEpisodes?.dub, | ||||||
|                 it.availableEpisodes?.sub |                 it.availableEpisodes?.sub | ||||||
|             ) |             ) | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private data class AvailableEpisodesDetail ( |     private data class AvailableEpisodesDetail( | ||||||
|         @JsonProperty("sub") val sub: List<String>, |         @JsonProperty("sub") val sub: List<String>, | ||||||
|         @JsonProperty("dub") val dub: List<String>, |         @JsonProperty("dub") val dub: List<String>, | ||||||
|         @JsonProperty("raw") val raw: List<String> |         @JsonProperty("raw") val raw: List<String> | ||||||
|  | @ -137,7 +136,6 @@ class AllAnimeProvider : MainAPI() { | ||||||
|         rhino.optimizationLevel = -1 |         rhino.optimizationLevel = -1 | ||||||
|         val scope: Scriptable = rhino.initStandardObjects() |         val scope: Scriptable = rhino.initStandardObjects() | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         val html = get(url).text |         val html = get(url).text | ||||||
|         val soup = Jsoup.parse(html) |         val soup = Jsoup.parse(html) | ||||||
| 
 | 
 | ||||||
|  | @ -161,43 +159,28 @@ class AllAnimeProvider : MainAPI() { | ||||||
| 
 | 
 | ||||||
|         val episodes = showData.availableEpisodes.let { |         val episodes = showData.availableEpisodes.let { | ||||||
|             if (it == null) return@let Pair(null, null) |             if (it == null) return@let Pair(null, null) | ||||||
|             Pair(if (it.sub != 0) ArrayList((1 .. it.sub).map { epNum -> |             Pair(if (it.sub != 0) ArrayList((1..it.sub).map { epNum -> | ||||||
|                 AnimeEpisode( |                 AnimeEpisode( | ||||||
|                     "$mainUrl/anime/${showData.Id}/episodes/sub/$epNum", |                     "$mainUrl/anime/${showData.Id}/episodes/sub/$epNum", episode = epNum | ||||||
|                     null, |  | ||||||
|                     null, |  | ||||||
|                     null, |  | ||||||
|                     null, |  | ||||||
|                     null, |  | ||||||
|                     epNum |  | ||||||
|                 ) |                 ) | ||||||
|             }) else null, if (it.dub != 0) ArrayList((1 .. it.dub).map { epNum -> |             }) else null, if (it.dub != 0) ArrayList((1..it.dub).map { epNum -> | ||||||
|                 AnimeEpisode( |                 AnimeEpisode( | ||||||
|                     "$mainUrl/anime/${showData.Id}/episodes/dub/$epNum", |                     "$mainUrl/anime/${showData.Id}/episodes/dub/$epNum", episode = epNum | ||||||
|                     null, |  | ||||||
|                     null, |  | ||||||
|                     null, |  | ||||||
|                     null, |  | ||||||
|                     null, |  | ||||||
|                     epNum |  | ||||||
|                 ) |                 ) | ||||||
|             }) else null) |             }) else null) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return AnimeLoadResponse( |         return newAnimeLoadResponse(title, url, TvType.Anime) { | ||||||
|             null, |             posterUrl = poster | ||||||
|             null, |             year = showData.airedStart?.year | ||||||
|             title, | 
 | ||||||
|             url, |             addEpisodes(DubStatus.Subbed, episodes.first) | ||||||
|             this.name, |             addEpisodes(DubStatus.Dubbed, episodes.second) | ||||||
|             TvType.Anime, | 
 | ||||||
|             poster, |             showStatus = getStatus(showData.status.toString()) | ||||||
|             showData.airedStart?.year, | 
 | ||||||
|             null, // no dub, because there is no way to switch from dub to sub //episodes.second, |             plot = description?.replace(Regex("""<(.*?)>"""), "") | ||||||
|             episodes.first, |         } | ||||||
|             getStatus(showData.status.toString()), |  | ||||||
|             description?.replace(Regex("""\<(.*?)\>"""), "") |  | ||||||
|         ) |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private val embedBlackList = listOf( |     private val embedBlackList = listOf( | ||||||
|  | @ -216,7 +199,7 @@ class AllAnimeProvider : MainAPI() { | ||||||
|                     return true |                     return true | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 if (url.contains(it as String)) { |                 if (url.contains(it)) { | ||||||
|                     return true |                     return true | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | @ -232,14 +215,14 @@ class AllAnimeProvider : MainAPI() { | ||||||
|         return out |         return out | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private data class Links ( |     private data class Links( | ||||||
|         @JsonProperty("link") val link: String, |         @JsonProperty("link") val link: String, | ||||||
|         @JsonProperty("hls") val hls: Boolean?, |         @JsonProperty("hls") val hls: Boolean?, | ||||||
|         @JsonProperty("resolutionStr") val resolutionStr: String, |         @JsonProperty("resolutionStr") val resolutionStr: String, | ||||||
|         @JsonProperty("src") val src: String? |         @JsonProperty("src") val src: String? | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|     private data class AllAnimeVideoApiResponse ( |     private data class AllAnimeVideoApiResponse( | ||||||
|         @JsonProperty("links") val links: List<Links> |         @JsonProperty("links") val links: List<Links> | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
|  | @ -273,7 +256,8 @@ class AllAnimeProvider : MainAPI() { | ||||||
| 
 | 
 | ||||||
|         val html = get(data).text |         val html = get(data).text | ||||||
| 
 | 
 | ||||||
|         val sources = Regex("""sourceUrl[:=]"(.+?)"""").findAll(html).toList().map { URLDecoder.decode(it.destructured.component1().sanitize(), "UTF-8") } |         val sources = Regex("""sourceUrl[:=]"(.+?)"""").findAll(html).toList() | ||||||
|  |             .map { URLDecoder.decode(it.destructured.component1().sanitize(), "UTF-8") } | ||||||
|         sources.forEach { |         sources.forEach { | ||||||
|             var link = it |             var link = it | ||||||
|             if (URI(link).isAbsolute || link.startsWith("//")) { |             if (URI(link).isAbsolute || link.startsWith("//")) { | ||||||
|  | @ -305,16 +289,26 @@ class AllAnimeProvider : MainAPI() { | ||||||
|                     val links = mapper.readValue<AllAnimeVideoApiResponse>(response.text).links |                     val links = mapper.readValue<AllAnimeVideoApiResponse>(response.text).links | ||||||
|                     links.forEach { server -> |                     links.forEach { server -> | ||||||
|                         if (server.hls != null && server.hls) { |                         if (server.hls != null && server.hls) { | ||||||
|                             getM3u8Qualities(server.link, "$apiEndPoint/player?uri=" + (if (URI(server.link).host.isNotEmpty()) server.link else apiEndPoint + URI(server.link).path), server.resolutionStr).forEach(callback) |                             getM3u8Qualities( | ||||||
|                         } else { |  | ||||||
|                             callback(ExtractorLink( |  | ||||||
|                                 "AllAnime - " + URI(server.link).host, |  | ||||||
|                                 server.resolutionStr, |  | ||||||
|                                 server.link, |                                 server.link, | ||||||
|                                 "$apiEndPoint/player?uri=" + (if (URI(server.link).host.isNotEmpty()) server.link else apiEndPoint + URI(server.link).path), |                                 "$apiEndPoint/player?uri=" + (if (URI(server.link).host.isNotEmpty()) server.link else apiEndPoint + URI( | ||||||
|                                 getQualityFromName("1080"), |                                     server.link | ||||||
|                                 false |                                 ).path), | ||||||
|                             )) |                                 server.resolutionStr | ||||||
|  |                             ).forEach(callback) | ||||||
|  |                         } else { | ||||||
|  |                             callback( | ||||||
|  |                                 ExtractorLink( | ||||||
|  |                                     "AllAnime - " + URI(server.link).host, | ||||||
|  |                                     server.resolutionStr, | ||||||
|  |                                     server.link, | ||||||
|  |                                     "$apiEndPoint/player?uri=" + (if (URI(server.link).host.isNotEmpty()) server.link else apiEndPoint + URI( | ||||||
|  |                                         server.link | ||||||
|  |                                     ).path), | ||||||
|  |                                     getQualityFromName("1080"), | ||||||
|  |                                     false | ||||||
|  |                                 ) | ||||||
|  |                             ) | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  | @ -76,21 +76,15 @@ class AnimeFlickProvider : MainAPI() { | ||||||
|             AnimeEpisode(link, name) |             AnimeEpisode(link, name) | ||||||
|         }.reversed() |         }.reversed() | ||||||
| 
 | 
 | ||||||
|         return AnimeLoadResponse( |         return newAnimeLoadResponse(title, url, getType(title)) { | ||||||
|             title, |             posterUrl = poster | ||||||
|             null, |             this.year = year | ||||||
|             title, | 
 | ||||||
|             url, |             addEpisodes(DubStatus.Subbed, episodes) | ||||||
|             this.name, | 
 | ||||||
|             getType(title), |             plot = description | ||||||
|             poster, |             tags = genres | ||||||
|             year, |         } | ||||||
|             null, |  | ||||||
|             episodes, |  | ||||||
|             null, |  | ||||||
|             description, |  | ||||||
|             genres |  | ||||||
|         ) |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun loadLinks( |     override fun loadLinks( | ||||||
|  |  | ||||||
|  | @ -293,30 +293,26 @@ class AnimePaheProvider : MainAPI() { | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             AnimeLoadResponse( |             newAnimeLoadResponse(animeTitle, url, getType(tvType.toString())) { | ||||||
|                 animeTitle, |                 engName = animeTitle | ||||||
|                 japTitle, |                 japName = japTitle | ||||||
|                 animeTitle, | 
 | ||||||
|                 url, |                 this.posterUrl = poster | ||||||
|                 this.name, |                 this.year = year | ||||||
|                 getType(tvType.toString()), | 
 | ||||||
|                 poster, |                 addEpisodes(DubStatus.Subbed, episodes) | ||||||
|                 year, |                 this.showStatus = status | ||||||
|                 null, |                 plot = synopsis | ||||||
|                 episodes, |                 tags = if (!doc.select(".anime-genre > ul a").isEmpty()) { | ||||||
|                 status, |  | ||||||
|                 synopsis, |  | ||||||
|                 if (!doc.select(".anime-genre > ul a").isEmpty()) { |  | ||||||
|                     ArrayList(doc.select(".anime-genre > ul a").map { it.text().toString() }) |                     ArrayList(doc.select(".anime-genre > ul a").map { it.text().toString() }) | ||||||
|                 } else { |                 } else { | ||||||
|                     null |                     null | ||||||
|                 }, |                 } | ||||||
|                 ArrayList(), | 
 | ||||||
|                 malId, |                 this.malId = malId | ||||||
|                 anilistId, |                 this.anilistId = anilistId | ||||||
|                 null, |                 this.trailerUrl = trailer | ||||||
|                 trailer |             } | ||||||
|             ) |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -325,7 +321,6 @@ class AnimePaheProvider : MainAPI() { | ||||||
|         return s?.toIntOrNull() != null |         return s?.toIntOrNull() != null | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     private fun cookieStrToMap(cookie: String): Map<String, String> { |     private fun cookieStrToMap(cookie: String): Map<String, String> { | ||||||
|         val cookies = mutableMapOf<String, String>() |         val cookies = mutableMapOf<String, String>() | ||||||
|         for (string in cookie.split("; ")) { |         for (string in cookie.split("; ")) { | ||||||
|  | @ -347,7 +342,6 @@ class AnimePaheProvider : MainAPI() { | ||||||
|         val slice2 = characterMap.slice(0 until s2) |         val slice2 = characterMap.slice(0 until s2) | ||||||
|         var acc: Long = 0 |         var acc: Long = 0 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         for ((n, i) in content.reversed().withIndex()) { |         for ((n, i) in content.reversed().withIndex()) { | ||||||
|             acc += (when (isNumber("$i")) { |             acc += (when (isNumber("$i")) { | ||||||
|                 true -> "$i".toLong() |                 true -> "$i".toLong() | ||||||
|  |  | ||||||
|  | @ -109,7 +109,7 @@ class DubbedAnimeProvider : MainAPI() { | ||||||
|             HomePageList("Trending", parseDocumentTrending(trendingUrl)), |             HomePageList("Trending", parseDocumentTrending(trendingUrl)), | ||||||
|             HomePageList("Recently Added", parseDocument(recentlyAddedUrl)), |             HomePageList("Recently Added", parseDocument(recentlyAddedUrl)), | ||||||
|             HomePageList("Recent Releases", parseDocument(lastEpisodeUrl, true)), |             HomePageList("Recent Releases", parseDocument(lastEpisodeUrl, true)), | ||||||
|            // HomePageList("All", parseDocument(allUrl)) |             // HomePageList("All", parseDocument(allUrl)) | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         return HomePageResponse(listItems) |         return HomePageResponse(listItems) | ||||||
|  | @ -268,20 +268,12 @@ class DubbedAnimeProvider : MainAPI() { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             val img = fixUrl(document.select("div.fkimgs > img").attr("src")) |             val img = fixUrl(document.select("div.fkimgs > img").attr("src")) | ||||||
|             return AnimeLoadResponse( |             return newAnimeLoadResponse(title, url, TvType.Anime) { | ||||||
|                 null, |                 posterUrl = img | ||||||
|                 null, |                 this.year = year | ||||||
|                 title, |                 addEpisodes(DubStatus.Dubbed, episodes) | ||||||
|                 url, |                 plot = descript | ||||||
|                 this.name, |             } | ||||||
|                 TvType.Anime, |  | ||||||
|                 img, |  | ||||||
|                 year, |  | ||||||
|                 ArrayList(episodes), |  | ||||||
|                 null, |  | ||||||
|                 null, |  | ||||||
|                 descript, |  | ||||||
|             ) |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -185,24 +185,18 @@ class GogoanimeProvider : MainAPI() { | ||||||
|                 "Episode " + it.selectFirst(".name").text().replace("EP", "").trim() |                 "Episode " + it.selectFirst(".name").text().replace("EP", "").trim() | ||||||
|             ) |             ) | ||||||
|         }.reversed() |         }.reversed() | ||||||
|         return AnimeLoadResponse( | 
 | ||||||
|             title, |         return newAnimeLoadResponse(title, link, getType(type.toString())) { | ||||||
|             nativeName, |             japName = nativeName | ||||||
|             title, |             engName = title | ||||||
|             link, |             posterUrl = poster | ||||||
|             this.name, |             this.year = year | ||||||
|             getType(type.toString()), |             addEpisodes(DubStatus.Subbed, episodes) // TODO CHECK | ||||||
|             poster, |             plot = description | ||||||
|             year, |             tags = genre | ||||||
|             null, | 
 | ||||||
|             episodes, |             showStatus = getStatus(status.toString()) | ||||||
|             getStatus(status.toString()), |         } | ||||||
|             description, |  | ||||||
|             ArrayList(genre), |  | ||||||
|             null, |  | ||||||
|             null, |  | ||||||
|             null, |  | ||||||
|         ) |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private fun extractVideos(uri: String): List<ExtractorLink> { |     private fun extractVideos(uri: String): List<ExtractorLink> { | ||||||
|  |  | ||||||
|  | @ -109,23 +109,13 @@ class KawaiifuProvider : MainAPI() { | ||||||
|         } |         } | ||||||
|         val poster = soup.selectFirst("a.thumb > img").attr("src") |         val poster = soup.selectFirst("a.thumb > img").attr("src") | ||||||
| 
 | 
 | ||||||
| 
 |         return newAnimeLoadResponse(title, url, TvType.Anime) { | ||||||
|         return AnimeLoadResponse( |             this.year = year | ||||||
|             title, |             posterUrl = poster | ||||||
|             null, |             addEpisodes(DubStatus.Subbed, episodes) | ||||||
|             title, |             plot = description | ||||||
|             url, |             this.tags = tags | ||||||
|             this.name, |         } | ||||||
|             TvType.Anime, |  | ||||||
|             poster, |  | ||||||
|             year, |  | ||||||
|             null, |  | ||||||
|             episodes, |  | ||||||
|             ShowStatus.Ongoing, |  | ||||||
|             description, |  | ||||||
|             ArrayList(tags), |  | ||||||
|             ArrayList() |  | ||||||
|         ) |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun loadLinks( |     override fun loadLinks( | ||||||
|  |  | ||||||
|  | @ -268,24 +268,19 @@ class TenshiProvider : MainAPI() { | ||||||
|         val synonyms = |         val synonyms = | ||||||
|             document.select("li.synonym.meta-data > div.info-box > span.value").map { it?.text()?.trim().toString() } |             document.select("li.synonym.meta-data > div.info-box > span.value").map { it?.text()?.trim().toString() } | ||||||
| 
 | 
 | ||||||
|         return AnimeLoadResponse( |         return newAnimeLoadResponse(canonicalTitle,url,getType(type ?: "")) { | ||||||
|             englishTitle, |             engName = englishTitle | ||||||
|             japaneseTitle, |             japName = japaneseTitle | ||||||
|             canonicalTitle, | 
 | ||||||
|             url, |             posterUrl = poster | ||||||
|             this.name, |             this.year = year.toIntOrNull() | ||||||
|             getType(type ?: ""), | 
 | ||||||
|             poster, |             addEpisodes(DubStatus.Subbed,episodes) | ||||||
|             year.toIntOrNull(), |             showStatus = status | ||||||
|             null, |             tags = genre | ||||||
|             episodes, |             this.synonyms = synonyms | ||||||
|             status, |             plot = synopsis | ||||||
|             synopsis, |         } | ||||||
|             ArrayList(genre), |  | ||||||
|             ArrayList(synonyms), |  | ||||||
|             null, |  | ||||||
|             null, |  | ||||||
|         ) |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -208,22 +208,16 @@ class WcoProvider : MainAPI() { | ||||||
|         val genre = document.select("div.elements div.row > div:nth-child(1) > div.row-line:nth-child(5) > a") |         val genre = document.select("div.elements div.row > div:nth-child(1) > div.row-line:nth-child(5) > a") | ||||||
|             .map { it?.text()?.trim().toString() } |             .map { it?.text()?.trim().toString() } | ||||||
| 
 | 
 | ||||||
|         return AnimeLoadResponse( |         return newAnimeLoadResponse(canonicalTitle,url,getType(type ?: "")) { | ||||||
|             canonicalTitle, |             japName = japaneseTitle | ||||||
|             japaneseTitle, |             engName = canonicalTitle | ||||||
|             canonicalTitle, |             posterUrl = poster | ||||||
|             url, |             this.year = year | ||||||
|             this.name, |             addEpisodes(if(isDubbed) DubStatus.Dubbed else DubStatus.Subbed,episodes) | ||||||
|             getType(type ?: ""), |             showStatus = status | ||||||
|             poster, |             plot = synopsis | ||||||
|             year, |             tags = genre | ||||||
|             if (isDubbed) episodes else null, |         } | ||||||
|             if (!isDubbed) episodes else null, |  | ||||||
|             status, |  | ||||||
|             synopsis, |  | ||||||
|             ArrayList(genre), |  | ||||||
|             ArrayList(), |  | ||||||
|         ) |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     override fun loadLinks( |     override fun loadLinks( | ||||||
|  |  | ||||||
|  | @ -230,21 +230,17 @@ class ZoroProvider : MainAPI() { | ||||||
|                 it.selectFirst(".ssli-order")?.text()?.toIntOrNull() |                 it.selectFirst(".ssli-order")?.text()?.toIntOrNull() | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
|         return AnimeLoadResponse( | 
 | ||||||
|             title, |         return newAnimeLoadResponse(title, url, TvType.Anime) { | ||||||
|             japaneseTitle, |             japName = japaneseTitle | ||||||
|             title, |             engName = title | ||||||
|             url, |             posterUrl = poster | ||||||
|             this.name, |             this.year = year | ||||||
|             TvType.Anime, |             addEpisodes(DubStatus.Subbed, episodes) | ||||||
|             poster, |             showStatus = status | ||||||
|             year, |             plot = description | ||||||
|             null, |             this.tags = tags | ||||||
|             episodes, |         } | ||||||
|             status, |  | ||||||
|             description, |  | ||||||
|             tags, |  | ||||||
|         ) |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private fun getM3u8FromRapidCloud(url: String): String { |     private fun getM3u8FromRapidCloud(url: String): String { | ||||||
|  |  | ||||||
|  | @ -235,7 +235,7 @@ class ResultFragment : Fragment() { | ||||||
|     private var currentId: Int? = null |     private var currentId: Int? = null | ||||||
|     private var currentIsMovie: Boolean? = null |     private var currentIsMovie: Boolean? = null | ||||||
|     private var episodeRanges: List<String>? = null |     private var episodeRanges: List<String>? = null | ||||||
| 
 |     private var dubRange: Set<DubStatus>? = null | ||||||
|     var url: String? = null |     var url: String? = null | ||||||
| 
 | 
 | ||||||
|     private fun fromIndexToSeasonText(selection: Int?): String { |     private fun fromIndexToSeasonText(selection: Int?): String { | ||||||
|  | @ -681,7 +681,6 @@ class ResultFragment : Fragment() { | ||||||
|                         } |                         } | ||||||
|                         outputFile.writeText(text) |                         outputFile.writeText(text) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|                         val vlcIntent = Intent(VLC_INTENT_ACTION_RESULT) |                         val vlcIntent = Intent(VLC_INTENT_ACTION_RESULT) | ||||||
| 
 | 
 | ||||||
|                         vlcIntent.setPackage(VLC_PACKAGE) |                         vlcIntent.setPackage(VLC_PACKAGE) | ||||||
|  | @ -858,6 +857,25 @@ class ResultFragment : Fragment() { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         observe(viewModel.dubStatus) { status -> | ||||||
|  |             result_dub_select?.text = status.toString() | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         observe(viewModel.dubSubSelections) { range -> | ||||||
|  |             dubRange = range | ||||||
|  |             result_dub_select?.visibility = if (range.size <= 1) GONE else VISIBLE | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         result_dub_select.setOnClickListener { | ||||||
|  |             val ranges = dubRange | ||||||
|  |             if (ranges != null) { | ||||||
|  |                 it.popupMenuNoIconsAndNoStringRes(ranges.map { status -> Pair(status.ordinal, status.toString()) } | ||||||
|  |                     .toList()) { | ||||||
|  |                     viewModel.changeDubStatus(requireContext(), DubStatus.values()[itemId]) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         observe(viewModel.selectedRange) { range -> |         observe(viewModel.selectedRange) { range -> | ||||||
|             result_episode_select?.text = range |             result_episode_select?.text = range | ||||||
|         } |         } | ||||||
|  | @ -962,8 +980,10 @@ class ResultFragment : Fragment() { | ||||||
|                             if (metadataInfoArray.size > 0) { |                             if (metadataInfoArray.size > 0) { | ||||||
|                                 result_metadata.visibility = VISIBLE |                                 result_metadata.visibility = VISIBLE | ||||||
|                                 val text = SpannableStringBuilder() |                                 val text = SpannableStringBuilder() | ||||||
|                                 val grayColor = ctx.colorFromAttribute(R.attr.grayTextColor) //ContextCompat.getColor(requireContext(), R.color.grayTextColor) |                                 val grayColor = | ||||||
|                                 val textColor = ctx.colorFromAttribute(R.attr.textColor) //ContextCompat.getColor(requireContext(), R.color.textColor) |                                     ctx.colorFromAttribute(R.attr.grayTextColor) //ContextCompat.getColor(requireContext(), R.color.grayTextColor) | ||||||
|  |                                 val textColor = | ||||||
|  |                                     ctx.colorFromAttribute(R.attr.textColor) //ContextCompat.getColor(requireContext(), R.color.textColor) | ||||||
|                                 for (meta in metadataInfoArray) { |                                 for (meta in metadataInfoArray) { | ||||||
|                                     text.color(grayColor) { append(getString(meta.first) + ": ") } |                                     text.color(grayColor) { append(getString(meta.first) + ": ") } | ||||||
|                                         .color(textColor) { append("${meta.second}\n") } |                                         .color(textColor) { append("${meta.second}\n") } | ||||||
|  |  | ||||||
|  | @ -55,13 +55,20 @@ class ResultViewModel : ViewModel() { | ||||||
|     val publicEpisodes: LiveData<Resource<List<ResultEpisode>>> get() = _publicEpisodes |     val publicEpisodes: LiveData<Resource<List<ResultEpisode>>> get() = _publicEpisodes | ||||||
|     val publicEpisodesCount: LiveData<Int> get() = _publicEpisodesCount |     val publicEpisodesCount: LiveData<Int> get() = _publicEpisodesCount | ||||||
| 
 | 
 | ||||||
|     private val dubStatus: MutableLiveData<DubStatus> = MutableLiveData() |     val dubStatus: MutableLiveData<DubStatus> get() = _dubStatus | ||||||
|  |     private val _dubStatus: MutableLiveData<DubStatus> = MutableLiveData() | ||||||
| 
 | 
 | ||||||
|     private val page: MutableLiveData<LoadResponse> = MutableLiveData() |     private val page: MutableLiveData<LoadResponse> = MutableLiveData() | ||||||
|     val id: MutableLiveData<Int> = MutableLiveData() |     val id: MutableLiveData<Int> = MutableLiveData() | ||||||
|     val selectedSeason: MutableLiveData<Int> = MutableLiveData(-2) |     val selectedSeason: MutableLiveData<Int> = MutableLiveData(-2) | ||||||
|     val seasonSelections: MutableLiveData<List<Int?>> = MutableLiveData() |     val seasonSelections: MutableLiveData<List<Int?>> = MutableLiveData() | ||||||
| 
 | 
 | ||||||
|  |     val dubSubSelections: MutableLiveData<Set<DubStatus>> get() = _dubSubSelections | ||||||
|  |     private val _dubSubSelections: MutableLiveData<Set<DubStatus>> = MutableLiveData() | ||||||
|  | 
 | ||||||
|  |     val dubSubEpisodes: MutableLiveData<Map<DubStatus, List<ResultEpisode>>?> get() = _dubSubEpisodes | ||||||
|  |     private val _dubSubEpisodes: MutableLiveData<Map<DubStatus, List<ResultEpisode>>?> = MutableLiveData() | ||||||
|  | 
 | ||||||
|     private val _watchStatus: MutableLiveData<WatchType> = MutableLiveData() |     private val _watchStatus: MutableLiveData<WatchType> = MutableLiveData() | ||||||
|     val watchStatus: LiveData<WatchType> get() = _watchStatus |     val watchStatus: LiveData<WatchType> get() = _watchStatus | ||||||
| 
 | 
 | ||||||
|  | @ -110,7 +117,7 @@ class ResultViewModel : ViewModel() { | ||||||
|         val seasons = seasonTypes.toList().map { it.first }.sortedBy { it } |         val seasons = seasonTypes.toList().map { it.first }.sortedBy { it } | ||||||
|         seasonSelections.postValue(seasons) |         seasonSelections.postValue(seasons) | ||||||
|         if (seasons.isEmpty()) { // WHAT THE FUCK DID YOU DO????? HOW DID YOU DO THIS |         if (seasons.isEmpty()) { // WHAT THE FUCK DID YOU DO????? HOW DID YOU DO THIS | ||||||
|             _publicEpisodes.postValue(Resource.Success( ArrayList())) |             _publicEpisodes.postValue(Resource.Success(ArrayList())) | ||||||
|             return |             return | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -160,7 +167,7 @@ class ResultViewModel : ViewModel() { | ||||||
|             selectedRange.postValue(allRange) |             selectedRange.postValue(allRange) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         _publicEpisodes.postValue(Resource.Success( currentList)) |         _publicEpisodes.postValue(Resource.Success(currentList)) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun changeSeason(context: Context, selection: Int?) { |     fun changeSeason(context: Context, selection: Int?) { | ||||||
|  | @ -171,6 +178,13 @@ class ResultViewModel : ViewModel() { | ||||||
|         filterEpisodes(context, _episodes.value, null, range) |         filterEpisodes(context, _episodes.value, null, range) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     fun changeDubStatus(context: Context, status: DubStatus?) { | ||||||
|  |         dubSubEpisodes.value?.get(status)?.let { episodes -> | ||||||
|  |             dubStatus.postValue(status) | ||||||
|  |             updateEpisodes(context, null, episodes, null) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     private fun updateEpisodes(context: Context, localId: Int?, list: List<ResultEpisode>, selection: Int?) { |     private fun updateEpisodes(context: Context, localId: Int?, list: List<ResultEpisode>, selection: Int?) { | ||||||
|         _episodes.postValue(list) |         _episodes.postValue(list) | ||||||
|         val set = HashMap<Int, Int>() |         val set = HashMap<Int, Int>() | ||||||
|  | @ -237,7 +251,7 @@ class ResultViewModel : ViewModel() { | ||||||
|         return name |         return name | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun load(context: Context, url: String, apiName: String, showFillers : Boolean) = viewModelScope.launch { |     fun load(context: Context, url: String, apiName: String, showFillers: Boolean) = viewModelScope.launch { | ||||||
|         _resultResponse.postValue(Resource.Loading(url)) |         _resultResponse.postValue(Resource.Loading(url)) | ||||||
|         _publicEpisodes.postValue(Resource.Loading()) |         _publicEpisodes.postValue(Resource.Loading()) | ||||||
| 
 | 
 | ||||||
|  | @ -273,16 +287,22 @@ class ResultViewModel : ViewModel() { | ||||||
| 
 | 
 | ||||||
|                 when (d) { |                 when (d) { | ||||||
|                     is AnimeLoadResponse -> { |                     is AnimeLoadResponse -> { | ||||||
|                         val isDub = d.dubEpisodes != null && d.dubEpisodes.isNotEmpty() |                         //TODO context.getKey<>() isdub | ||||||
|                         dubStatus.postValue(if (isDub) DubStatus.Dubbed else DubStatus.Subbed) |  | ||||||
| 
 | 
 | ||||||
|                         val dataList = (if (isDub) d.dubEpisodes else d.subEpisodes) |                         val isDub = | ||||||
|  |                             d.episodes.containsKey(DubStatus.Dubbed) && !d.episodes[DubStatus.Dubbed].isNullOrEmpty() | ||||||
|  |                         val dubStatus = if (isDub) DubStatus.Dubbed else DubStatus.Subbed | ||||||
|  |                         _dubStatus.postValue(dubStatus) | ||||||
| 
 | 
 | ||||||
|                         val fillerEpisodes = if(showFillers) safeApiCall { getFillerEpisodes(d.name) } else null |                         _dubSubSelections.postValue(d.episodes.keys) | ||||||
|  |                         val fillerEpisodes = if (showFillers) safeApiCall { getFillerEpisodes(d.name) } else null | ||||||
| 
 | 
 | ||||||
|                         if (dataList != null) { // TODO dub and sub at the same time |                         var idIndex = mainId | ||||||
|  |                         val res = d.episodes.map { ep -> | ||||||
|                             val episodes = ArrayList<ResultEpisode>() |                             val episodes = ArrayList<ResultEpisode>() | ||||||
|                             for ((index, i) in dataList.withIndex()) { |                             for ((index, i) in ep.value.withIndex()) { | ||||||
|  |                                 idIndex++ | ||||||
|  | 
 | ||||||
|                                 val episode = i.episode ?: (index + 1) |                                 val episode = i.episode ?: (index + 1) | ||||||
|                                 episodes.add( |                                 episodes.add( | ||||||
|                                     context.buildResultEpisode( |                                     context.buildResultEpisode( | ||||||
|  | @ -292,17 +312,22 @@ class ResultViewModel : ViewModel() { | ||||||
|                                         null, // TODO FIX SEASON |                                         null, // TODO FIX SEASON | ||||||
|                                         i.url, |                                         i.url, | ||||||
|                                         apiName, |                                         apiName, | ||||||
|                                         (mainId + index + 1), |                                         idIndex, | ||||||
|                                         index, |                                         index, | ||||||
|                                         i.rating, |                                         i.rating, | ||||||
|                                         i.descript, |                                         i.description, | ||||||
|                                         if (fillerEpisodes is Resource.Success) fillerEpisodes.value?.let { |                                         if (fillerEpisodes is Resource.Success) fillerEpisodes.value?.let { | ||||||
|                                             it.contains(episode) && it[episode] == true |                                             it.contains(episode) && it[episode] == true | ||||||
|                                         } |                                         } ?: false else false, | ||||||
|                                             ?: false else false, |  | ||||||
|                                     ) |                                     ) | ||||||
|                                 ) |                                 ) | ||||||
|                             } |                             } | ||||||
|  | 
 | ||||||
|  |                             Pair(ep.key, episodes) | ||||||
|  |                         }.toMap() | ||||||
|  | 
 | ||||||
|  |                         _dubSubEpisodes.postValue(res) | ||||||
|  |                         res[dubStatus]?.let { episodes -> | ||||||
|                             updateEpisodes(context, mainId, episodes, -1) |                             updateEpisodes(context, mainId, episodes, -1) | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|  | @ -366,11 +391,10 @@ class ResultViewModel : ViewModel() { | ||||||
|                             ), -1 |                             ), -1 | ||||||
|                         ) |                         ) | ||||||
|                     } |                     } | ||||||
| 
 |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             else -> { |             else -> { | ||||||
| 
 |                 // nothing | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -431,8 +431,23 @@ | ||||||
|                             android:layout_gravity="center_vertical" |                             android:layout_gravity="center_vertical" | ||||||
|                             android:layout_marginStart="0dp" |                             android:layout_marginStart="0dp" | ||||||
|                             style="@style/MultiSelectButton" |                             style="@style/MultiSelectButton" | ||||||
|                     > |                     /> | ||||||
|                     </com.google.android.material.button.MaterialButton> | 
 | ||||||
|  |                     <com.google.android.material.button.MaterialButton | ||||||
|  |                             tools:visibility="visible" | ||||||
|  |                             tools:text="Dubbed" | ||||||
|  | 
 | ||||||
|  |                             android:nextFocusUp="@id/result_descript" | ||||||
|  |                             android:nextFocusRight="@id/result_season_button" | ||||||
|  |                             android:nextFocusLeft="@id/result_season_button" | ||||||
|  |                             android:nextFocusDown="@id/result_episodes" | ||||||
|  | 
 | ||||||
|  |                             android:id="@+id/result_dub_select" | ||||||
|  |                             android:visibility="gone" | ||||||
|  |                             android:layout_gravity="center_vertical" | ||||||
|  |                             android:layout_marginStart="0dp" | ||||||
|  |                             style="@style/MultiSelectButton" | ||||||
|  |                     /> | ||||||
|                     <TextView |                     <TextView | ||||||
|                             android:layout_width="wrap_content" |                             android:layout_width="wrap_content" | ||||||
|                             android:layout_height="wrap_content" |                             android:layout_height="wrap_content" | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue