forked from recloudstream/cloudstream
		
	mainApi changes
This commit is contained in:
		
							parent
							
								
									117730e9a8
								
							
						
					
					
						commit
						94561e0d5b
					
				
					 19 changed files with 358 additions and 325 deletions
				
			
		|  | @ -111,6 +111,12 @@ object APIHolder { | |||
|     } | ||||
| 
 | ||||
|     var apis: List<MainAPI> = arrayListOf() | ||||
|     private var apiMap: Map<String, Int>? = null | ||||
| 
 | ||||
|     private fun initMap() { | ||||
|         if (apiMap == null) | ||||
|             apiMap = apis.mapIndexed { index, api -> api.name to index }.toMap() | ||||
|     } | ||||
| 
 | ||||
|     fun getApiFromName(apiName: String?): MainAPI { | ||||
|         return getApiFromNameNull(apiName) ?: apis[defProvider] | ||||
|  | @ -118,11 +124,9 @@ object APIHolder { | |||
| 
 | ||||
|     fun getApiFromNameNull(apiName: String?): MainAPI? { | ||||
|         if (apiName == null) return null | ||||
|         for (api in allProviders) { | ||||
|             if (apiName == api.name) | ||||
|                 return api | ||||
|         } | ||||
|         return null | ||||
|         initMap() | ||||
| 
 | ||||
|         return apiMap?.get(apiName)?.let { apis.getOrNull(it) } | ||||
|     } | ||||
| 
 | ||||
|     fun getApiFromUrlNull(url: String?): MainAPI? { | ||||
|  | @ -622,10 +626,65 @@ interface SearchResponse { | |||
|     val apiName: String | ||||
|     var type: TvType? | ||||
|     var posterUrl: String? | ||||
|     var posterHeaders: Map<String, String>? | ||||
|     var id: Int? | ||||
|     var quality: SearchQuality? | ||||
| } | ||||
| 
 | ||||
| fun MainAPI.newMovieSearchResponse( | ||||
|     name: String, | ||||
|     url: String, | ||||
|     type: TvType = TvType.Movie, | ||||
|     fix: Boolean = true, | ||||
|     initializer: MovieSearchResponse.() -> Unit = { }, | ||||
| ): MovieSearchResponse { | ||||
|     val builder = MovieSearchResponse(name, if (fix) fixUrl(url) else url, this.name, type) | ||||
|     builder.initializer() | ||||
| 
 | ||||
|     return builder | ||||
| } | ||||
| 
 | ||||
| fun MainAPI.newTvSeriesSearchResponse( | ||||
|     name: String, | ||||
|     url: String, | ||||
|     type: TvType = TvType.TvSeries, | ||||
|     fix: Boolean = true, | ||||
|     initializer: TvSeriesSearchResponse.() -> Unit = { }, | ||||
| ): TvSeriesSearchResponse { | ||||
|     val builder = TvSeriesSearchResponse(name, if (fix) fixUrl(url) else url, this.name, type) | ||||
|     builder.initializer() | ||||
| 
 | ||||
|     return builder | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| fun MainAPI.newAnimeSearchResponse( | ||||
|     name: String, | ||||
|     url: String, | ||||
|     type: TvType = TvType.Anime, | ||||
|     fix: Boolean = true, | ||||
|     initializer: AnimeSearchResponse.() -> Unit = { }, | ||||
| ): AnimeSearchResponse { | ||||
|     val builder = AnimeSearchResponse(name, if (fix) fixUrl(url) else url, this.name, type) | ||||
|     builder.initializer() | ||||
| 
 | ||||
|     return builder | ||||
| } | ||||
| 
 | ||||
| fun SearchResponse.addQuality(quality: String) { | ||||
|     this.quality = getQualityFromString(quality) | ||||
| } | ||||
| 
 | ||||
| fun SearchResponse.addPoster(url: String?, headers: Map<String, String>? = null) { | ||||
|     this.posterUrl = url | ||||
|     this.posterHeaders = headers | ||||
| } | ||||
| 
 | ||||
| fun LoadResponse.addPoster(url: String?, headers: Map<String, String>? = null) { | ||||
|     this.posterUrl = url | ||||
|     this.posterHeaders = headers | ||||
| } | ||||
| 
 | ||||
| enum class ActorRole { | ||||
|     Main, | ||||
|     Supporting, | ||||
|  | @ -648,19 +707,62 @@ data class AnimeSearchResponse( | |||
|     override val name: String, | ||||
|     override val url: String, | ||||
|     override val apiName: String, | ||||
|     override var type: TvType?, | ||||
|     override var type: TvType? = null, | ||||
| 
 | ||||
|     override var posterUrl: String?, | ||||
|     val year: Int? = null, | ||||
|     val dubStatus: EnumSet<DubStatus>? = null, | ||||
|     override var posterUrl: String? = null, | ||||
|     var year: Int? = null, | ||||
|     var dubStatus: EnumSet<DubStatus>? = null, | ||||
| 
 | ||||
|     var otherName: String? = null, | ||||
|     var episodes: MutableMap<DubStatus, Int> = mutableMapOf(), | ||||
| 
 | ||||
|     val otherName: String? = null, | ||||
|     val dubEpisodes: Int? = null, | ||||
|     val subEpisodes: Int? = null, | ||||
|     override var id: Int? = null, | ||||
|     override var quality: SearchQuality? = null, | ||||
|     override var posterHeaders: Map<String, String>? = null, | ||||
| ) : SearchResponse | ||||
| 
 | ||||
| fun AnimeSearchResponse.addDubStatus(status: DubStatus, episodes: Int? = null) { | ||||
|     this.dubStatus = dubStatus?.also { it.add(status) } ?: EnumSet.of(status) | ||||
|     if (this.type?.isMovieType() != true) | ||||
|         if (episodes != null && episodes > 0) | ||||
|             this.episodes[status] = episodes | ||||
| } | ||||
| 
 | ||||
| fun AnimeSearchResponse.addDubStatus(isDub: Boolean, episodes: Int? = null) { | ||||
|     addDubStatus(if (isDub) DubStatus.Dubbed else DubStatus.Subbed, episodes) | ||||
| } | ||||
| 
 | ||||
| fun AnimeSearchResponse.addDub(episodes: Int?) { | ||||
|     if(episodes == null || episodes <= 0) return | ||||
|     addDubStatus(DubStatus.Dubbed, episodes) | ||||
| } | ||||
| 
 | ||||
| fun AnimeSearchResponse.addSub(episodes: Int?) { | ||||
|     if(episodes == null || episodes <= 0) return | ||||
|     addDubStatus(DubStatus.Subbed, episodes) | ||||
| } | ||||
| 
 | ||||
| fun AnimeSearchResponse.addDubStatus( | ||||
|     dubExist: Boolean, | ||||
|     subExist: Boolean, | ||||
|     dubEpisodes: Int? = null, | ||||
|     subEpisodes: Int? = null | ||||
| ) { | ||||
|     if (dubExist) | ||||
|         addDubStatus(DubStatus.Dubbed, dubEpisodes) | ||||
| 
 | ||||
|     if (subExist) | ||||
|         addDubStatus(DubStatus.Subbed, subEpisodes) | ||||
| } | ||||
| 
 | ||||
| fun AnimeSearchResponse.addDubStatus(status: String, episodes: Int? = null) { | ||||
|     if (status.contains("(dub)", ignoreCase = true)) { | ||||
|         addDubStatus(DubStatus.Dubbed) | ||||
|     } else if (status.contains("(sub)", ignoreCase = true)) { | ||||
|         addDubStatus(DubStatus.Subbed) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| data class TorrentSearchResponse( | ||||
|     override val name: String, | ||||
|     override val url: String, | ||||
|  | @ -670,31 +772,34 @@ data class TorrentSearchResponse( | |||
|     override var posterUrl: String?, | ||||
|     override var id: Int? = null, | ||||
|     override var quality: SearchQuality? = null, | ||||
|     override var posterHeaders: Map<String, String>? = null, | ||||
| ) : SearchResponse | ||||
| 
 | ||||
| data class MovieSearchResponse( | ||||
|     override val name: String, | ||||
|     override val url: String, | ||||
|     override val apiName: String, | ||||
|     override var type: TvType?, | ||||
|     override var type: TvType? = null, | ||||
| 
 | ||||
|     override var posterUrl: String?, | ||||
|     override var posterUrl: String? = null, | ||||
|     val year: Int? = null, | ||||
|     override var id: Int? = null, | ||||
|     override var quality: SearchQuality? = null, | ||||
|     override var posterHeaders: Map<String, String>? = null, | ||||
| ) : SearchResponse | ||||
| 
 | ||||
| data class TvSeriesSearchResponse( | ||||
|     override val name: String, | ||||
|     override val url: String, | ||||
|     override val apiName: String, | ||||
|     override var type: TvType?, | ||||
|     override var type: TvType? = null, | ||||
| 
 | ||||
|     override var posterUrl: String?, | ||||
|     val year: Int?, | ||||
|     val episodes: Int?, | ||||
|     override var posterUrl: String? = null, | ||||
|     val year: Int? = null, | ||||
|     val episodes: Int? = null, | ||||
|     override var id: Int? = null, | ||||
|     override var quality: SearchQuality? = null, | ||||
|     override var posterHeaders: Map<String, String>? = null, | ||||
| ) : SearchResponse | ||||
| 
 | ||||
| interface LoadResponse { | ||||
|  | @ -713,6 +818,7 @@ interface LoadResponse { | |||
|     var actors: List<ActorData>? | ||||
|     var comingSoon: Boolean | ||||
|     var syncData: MutableMap<String, String> | ||||
|     var posterHeaders: Map<String, String>? | ||||
| 
 | ||||
|     companion object { | ||||
|         private val malIdPrefix = malApi.idPrefix | ||||
|  | @ -844,6 +950,7 @@ data class TorrentLoadResponse( | |||
|     override var actors: List<ActorData>? = null, | ||||
|     override var comingSoon: Boolean = false, | ||||
|     override var syncData: MutableMap<String, String> = mutableMapOf(), | ||||
|     override var posterHeaders: Map<String, String>? = null, | ||||
| ) : LoadResponse | ||||
| 
 | ||||
| data class AnimeLoadResponse( | ||||
|  | @ -871,6 +978,7 @@ data class AnimeLoadResponse( | |||
|     override var actors: List<ActorData>? = null, | ||||
|     override var comingSoon: Boolean = false, | ||||
|     override var syncData: MutableMap<String, String> = mutableMapOf(), | ||||
|     override var posterHeaders: Map<String, String>? = null, | ||||
| ) : LoadResponse | ||||
| 
 | ||||
| fun AnimeLoadResponse.addEpisodes(status: DubStatus, episodes: List<Episode>?) { | ||||
|  | @ -882,7 +990,7 @@ fun MainAPI.newAnimeLoadResponse( | |||
|     name: String, | ||||
|     url: String, | ||||
|     type: TvType, | ||||
|     comingSoonIfNone: Boolean, | ||||
|     comingSoonIfNone: Boolean = true, | ||||
|     initializer: AnimeLoadResponse.() -> Unit = { }, | ||||
| ): AnimeLoadResponse { | ||||
|     val builder = AnimeLoadResponse(name = name, url = url, apiName = this.name, type = type) | ||||
|  | @ -898,15 +1006,6 @@ fun MainAPI.newAnimeLoadResponse( | |||
|     return builder | ||||
| } | ||||
| 
 | ||||
| fun MainAPI.newAnimeLoadResponse( | ||||
|     name: String, | ||||
|     url: String, | ||||
|     type: TvType, | ||||
|     initializer: AnimeLoadResponse.() -> Unit = { }, | ||||
| ): AnimeLoadResponse { | ||||
|     return newAnimeLoadResponse(name, url, type, true, initializer) | ||||
| } | ||||
| 
 | ||||
| data class MovieLoadResponse( | ||||
|     override var name: String, | ||||
|     override var url: String, | ||||
|  | @ -926,6 +1025,7 @@ data class MovieLoadResponse( | |||
|     override var actors: List<ActorData>? = null, | ||||
|     override var comingSoon: Boolean = false, | ||||
|     override var syncData: MutableMap<String, String> = mutableMapOf(), | ||||
|     override var posterHeaders: Map<String, String>? = null, | ||||
| ) : LoadResponse | ||||
| 
 | ||||
| fun <T> MainAPI.newMovieLoadResponse( | ||||
|  | @ -1046,6 +1146,7 @@ data class TvSeriesLoadResponse( | |||
|     override var actors: List<ActorData>? = null, | ||||
|     override var comingSoon: Boolean = false, | ||||
|     override var syncData: MutableMap<String, String> = mutableMapOf(), | ||||
|     override var posterHeaders: Map<String, String>? = null, | ||||
| ) : LoadResponse | ||||
| 
 | ||||
| fun MainAPI.newTvSeriesLoadResponse( | ||||
|  |  | |||
|  | @ -14,7 +14,6 @@ import org.mozilla.javascript.Context | |||
| import org.mozilla.javascript.Scriptable | ||||
| import java.net.URI | ||||
| import java.net.URLDecoder | ||||
| import java.util.* | ||||
| 
 | ||||
| 
 | ||||
| class AllAnimeProvider : MainAPI() { | ||||
|  | @ -88,49 +87,48 @@ class AllAnimeProvider : MainAPI() { | |||
|         @JsonProperty("data") val data: Data | ||||
|     ) | ||||
| 
 | ||||
|     data class RandomMain ( | ||||
|         @JsonProperty("data" ) var data : DataRan? = DataRan() | ||||
|     data class RandomMain( | ||||
|         @JsonProperty("data") var data: DataRan? = DataRan() | ||||
|     ) | ||||
| 
 | ||||
|     data class DataRan ( | ||||
|         @JsonProperty("queryRandomRecommendation" ) var queryRandomRecommendation : ArrayList<QueryRandomRecommendation> = arrayListOf() | ||||
|     data class DataRan( | ||||
|         @JsonProperty("queryRandomRecommendation") var queryRandomRecommendation: ArrayList<QueryRandomRecommendation> = arrayListOf() | ||||
|     ) | ||||
| 
 | ||||
|     data class QueryRandomRecommendation ( | ||||
|         @JsonProperty("_id"               ) val Id                : String? = null, | ||||
|         @JsonProperty("name"              ) val name              : String? = null, | ||||
|         @JsonProperty("englishName"       ) val englishName       : String? = null, | ||||
|         @JsonProperty("nativeName"        ) val nativeName        : String? = null, | ||||
|         @JsonProperty("thumbnail"         ) val thumbnail         : String? = null, | ||||
|         @JsonProperty("airedStart"        ) val airedStart        : String? = null, | ||||
|         @JsonProperty("availableChapters" ) val availableChapters : String? = null, | ||||
|         @JsonProperty("availableEpisodes" ) val availableEpisodes : String? = null, | ||||
|         @JsonProperty("__typename"        ) val _typename         : String? = null | ||||
|     data class QueryRandomRecommendation( | ||||
|         @JsonProperty("_id") val Id: String? = null, | ||||
|         @JsonProperty("name") val name: String? = null, | ||||
|         @JsonProperty("englishName") val englishName: String? = null, | ||||
|         @JsonProperty("nativeName") val nativeName: String? = null, | ||||
|         @JsonProperty("thumbnail") val thumbnail: String? = null, | ||||
|         @JsonProperty("airedStart") val airedStart: String? = null, | ||||
|         @JsonProperty("availableChapters") val availableChapters: String? = null, | ||||
|         @JsonProperty("availableEpisodes") val availableEpisodes: String? = null, | ||||
|         @JsonProperty("__typename") val _typename: String? = null | ||||
|     ) | ||||
| 
 | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val items = ArrayList<HomePageList>() | ||||
|         val urls = listOf( | ||||
|             Pair("Top Anime", | ||||
|                 "$mainUrl/graphql?variables=%7B%22search%22%3A%7B%22allowAdult%22%3Afalse%2C%22sortBy%22%3A%22Top%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"), | ||||
|             Pair("Animes", | ||||
|                 "$mainUrl/graphql?variables=%7B%22search%22%3A%7B%22allowAdult%22%3Afalse%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"), | ||||
|             Pair( | ||||
|                 "Top Anime", | ||||
|                 "$mainUrl/graphql?variables=%7B%22search%22%3A%7B%22allowAdult%22%3Afalse%2C%22sortBy%22%3A%22Top%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" | ||||
|             ), | ||||
|             Pair( | ||||
|                 "Animes", | ||||
|                 "$mainUrl/graphql?variables=%7B%22search%22%3A%7B%22allowAdult%22%3Afalse%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 random = "$mainUrl/graphql?variables=%7B%22format%22%3A%22anime%22%7D&extensions=%7B%22persistedQuery%22%3A%7B%22version%22%3A1%2C%22sha256Hash%22%3A%2221ac672633498a3698e8f6a93ce6c2b3722b29a216dcca93363bf012c360cd54%22%7D%7D" | ||||
|         val random = | ||||
|             "$mainUrl/graphql?variables=%7B%22format%22%3A%22anime%22%7D&extensions=%7B%22persistedQuery%22%3A%7B%22version%22%3A1%2C%22sha256Hash%22%3A%2221ac672633498a3698e8f6a93ce6c2b3722b29a216dcca93363bf012c360cd54%22%7D%7D" | ||||
|         val ranlink = app.get(random).text | ||||
|         val jsonran = parseJson<RandomMain>(ranlink) | ||||
|         val ranhome = jsonran.data?.queryRandomRecommendation?.map { | ||||
|             AnimeSearchResponse( | ||||
|                 it.name!!, | ||||
|                 "$mainUrl/anime/${it.Id}", | ||||
|                 this.name, | ||||
|                 TvType.Anime, | ||||
|                 it.thumbnail, | ||||
|                 null, | ||||
|                 EnumSet.of(DubStatus.Subbed, DubStatus.Dubbed), | ||||
|                 it.nativeName, | ||||
|             ) | ||||
|             newAnimeSearchResponse(it.name!!,"$mainUrl/anime/${it.Id}", fix = false) { | ||||
|                 this.posterUrl = it.thumbnail | ||||
|                 this.otherName = it.nativeName | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         items.add(HomePageList("Random", ranhome!!)) | ||||
|  | @ -144,18 +142,14 @@ class AllAnimeProvider : MainAPI() { | |||
|                 !(it.availableEpisodes?.raw == 0 && it.availableEpisodes.sub == 0 && it.availableEpisodes.dub == 0) | ||||
|             } | ||||
|             results.map { | ||||
|                 home.add(AnimeSearchResponse( | ||||
|                     it.name, | ||||
|                     "$mainUrl/anime/${it.Id}", | ||||
|                     this.name, | ||||
|                     TvType.Anime, | ||||
|                     it.thumbnail, | ||||
|                     it.airedStart?.year, | ||||
|                     EnumSet.of(DubStatus.Subbed, DubStatus.Dubbed), | ||||
|                     it.englishName, | ||||
|                     it.availableEpisodes?.dub, | ||||
|                     it.availableEpisodes?.sub | ||||
|                 )) | ||||
|                 home.add( | ||||
|                     newAnimeSearchResponse(it.name, "$mainUrl/anime/${it.Id}", fix = false) { | ||||
|                         this.posterUrl = it.thumbnail | ||||
|                         this.year = it.airedStart?.year | ||||
|                         this.otherName = it.englishName | ||||
|                         addDub(it.availableEpisodes?.dub) | ||||
|                         addSub(it.availableEpisodes?.sub) | ||||
|                     }) | ||||
|             } | ||||
|             items.add(HomePageList(HomeName, home)) | ||||
|         } | ||||
|  | @ -180,18 +174,13 @@ class AllAnimeProvider : MainAPI() { | |||
|         } | ||||
| 
 | ||||
|         return results.map { | ||||
|             AnimeSearchResponse( | ||||
|                 it.name, | ||||
|                 "$mainUrl/anime/${it.Id}", | ||||
|                 this.name, | ||||
|                 TvType.Anime, | ||||
|                 it.thumbnail, | ||||
|                 it.airedStart?.year, | ||||
|                 EnumSet.of(DubStatus.Subbed, DubStatus.Dubbed), | ||||
|                 it.englishName, | ||||
|                 it.availableEpisodes?.dub, | ||||
|                 it.availableEpisodes?.sub | ||||
|             ) | ||||
|             newAnimeSearchResponse(it.name, "$mainUrl/anime/${it.Id}", fix = false) { | ||||
|                 this.posterUrl = it.thumbnail | ||||
|                 this.year = it.airedStart?.year | ||||
|                 this.otherName = it.englishName | ||||
|                 addDub(it.availableEpisodes?.dub) | ||||
|                 addSub(it.availableEpisodes?.sub) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,7 +12,6 @@ import com.lagradost.cloudstream3.utils.ExtractorLink | |||
| import com.lagradost.cloudstream3.utils.JsUnpacker | ||||
| import com.lagradost.cloudstream3.utils.getQualityFromName | ||||
| import org.jsoup.Jsoup | ||||
| import java.util.* | ||||
| import kotlin.math.pow | ||||
| 
 | ||||
| class AnimePaheProvider : MainAPI() { | ||||
|  | @ -84,19 +83,14 @@ class AnimePaheProvider : MainAPI() { | |||
|             try { | ||||
|                 val response = app.get(i.first).text | ||||
|                 val episodes = mapper.readValue<AnimePaheLatestReleases>(response).data.map { | ||||
| 
 | ||||
|                     AnimeSearchResponse( | ||||
|                     newAnimeSearchResponse( | ||||
|                         it.animeTitle, | ||||
|                         "https://pahe.win/a/${it.animeId}?slug=${it.animeTitle}", | ||||
|                         this.name, | ||||
|                         TvType.Anime, | ||||
|                         it.snapshot, | ||||
|                         null, | ||||
|                         EnumSet.of(DubStatus.Subbed), | ||||
|                         null, | ||||
|                         null, | ||||
|                         it.episode | ||||
|                     ) | ||||
|                         fix = false | ||||
|                     ) { | ||||
|                         this.posterUrl = it.snapshot | ||||
|                         addDubStatus(DubStatus.Subbed, it.episode) | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 items.add(HomePageList(i.second, episodes)) | ||||
|  | @ -151,18 +145,14 @@ class AnimePaheProvider : MainAPI() { | |||
|         val data = req.let { mapper.readValue<AnimePaheSearch>(it) } | ||||
| 
 | ||||
|         return data.data.map { | ||||
|             AnimeSearchResponse( | ||||
|             newAnimeSearchResponse( | ||||
|                 it.title, | ||||
|                 "https://pahe.win/a/${it.id}?slug=${it.title}", | ||||
|                 this.name, | ||||
|                 TvType.Anime, | ||||
|                 it.poster, | ||||
|                 it.year, | ||||
|                 EnumSet.of(DubStatus.Subbed), | ||||
|                 null, | ||||
|                 null, | ||||
|                 it.episodes | ||||
|             ) | ||||
|                 fix = false | ||||
|             ) { | ||||
|                 this.posterUrl = it.poster | ||||
|                 addDubStatus(DubStatus.Subbed, it.episodes) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -189,7 +179,6 @@ class AnimePaheProvider : MainAPI() { | |||
|         @JsonProperty("data") val data: List<AnimeData> | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
|     private suspend fun generateListOfEpisodes(link: String): ArrayList<Episode> { | ||||
|         try { | ||||
|             val attrs = link.split('/') | ||||
|  |  | |||
|  | @ -9,7 +9,6 @@ import com.lagradost.cloudstream3.utils.ExtractorLink | |||
| import com.lagradost.cloudstream3.utils.Qualities | ||||
| import org.json.JSONObject | ||||
| import org.jsoup.nodes.Element | ||||
| import java.util.* | ||||
| 
 | ||||
| class AnimeWorldProvider : MainAPI() { | ||||
|     override var mainUrl = "https://www.animeworld.tv" | ||||
|  | @ -31,6 +30,7 @@ class AnimeWorldProvider : MainAPI() { | |||
|                 else -> TvType.Anime | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         fun getStatus(t: String?): ShowStatus? { | ||||
|             return when (t?.lowercase()) { | ||||
|                 "finito" -> ShowStatus.Completed | ||||
|  | @ -54,25 +54,20 @@ class AnimeWorldProvider : MainAPI() { | |||
| 
 | ||||
|         val statusElement = this.select("div.status") // .first() | ||||
|         val dub = statusElement.select(".dub").isNotEmpty() | ||||
|         val dubStatus = if (dub) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(DubStatus.Subbed) | ||||
|         val episode = statusElement.select(".ep").text().split(' ').last().toIntOrNull() | ||||
| 
 | ||||
|         val episode = if (showEpisode) statusElement.select(".ep").text().split(' ').last() | ||||
|             .toIntOrNull() else null | ||||
|         val type = when { | ||||
|             statusElement.select(".movie").isNotEmpty() -> TvType.AnimeMovie | ||||
|             statusElement.select(".ova").isNotEmpty() -> TvType.OVA | ||||
|             else -> TvType.Anime | ||||
|         } | ||||
| 
 | ||||
|         return AnimeSearchResponse( | ||||
|             title, | ||||
|             url, | ||||
|             name, | ||||
|             type, | ||||
|             poster, | ||||
|             dubStatus = dubStatus, | ||||
|             otherName = if (otherTitle != title) otherTitle else null, | ||||
|             dubEpisodes = if (showEpisode && type != TvType.AnimeMovie && dub) episode else null, | ||||
|             subEpisodes = if (showEpisode && type != TvType.AnimeMovie && !dub) episode else null | ||||
|         ) | ||||
|         return newAnimeSearchResponse(title, url, type) { | ||||
|             addDubStatus(dub, episode) | ||||
|             this.otherName = otherTitle | ||||
|             this.posterUrl = poster | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|  | @ -113,14 +108,17 @@ class AnimeWorldProvider : MainAPI() { | |||
|                 arr[0].split(' ')[0].toIntOrNull() | ||||
|             else | ||||
|                 arr[1].split(' ')[0].toIntOrNull()?.let { | ||||
|                     arr[0].removeSuffix("h").toIntOrNull()?.times(60)!!.plus(it) } | ||||
|                     arr[0].removeSuffix("h").toIntOrNull()?.times(60)!!.plus(it) | ||||
|                 } | ||||
|         } | ||||
| 
 | ||||
|         val document = app.get(url).document | ||||
| 
 | ||||
|         val widget = document.select("div.widget.info") | ||||
|         val title = widget.select(".info .title").text().removeSuffix(" (ITA)") | ||||
|         val otherTitle = widget.select(".info .title").attr("data-jtitle").removeSuffix(" (ITA)") | ||||
|         val description = widget.select(".desc .long").first()?.text() ?: widget.select(".desc").text() | ||||
|         val description = | ||||
|             widget.select(".desc .long").first()?.text() ?: widget.select(".desc").text() | ||||
|         val poster = document.select(".thumb img").attr("src") | ||||
| 
 | ||||
|         val type: TvType = getType(widget.select("dd").first()?.text()) | ||||
|  |  | |||
|  | @ -2,8 +2,9 @@ package com.lagradost.cloudstream3.animeproviders | |||
| 
 | ||||
| import com.fasterxml.jackson.annotation.JsonProperty | ||||
| import com.lagradost.cloudstream3.* | ||||
| import com.lagradost.cloudstream3.utils.* | ||||
| import com.lagradost.cloudstream3.utils.AppUtils.parseJson | ||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | ||||
| import com.lagradost.cloudstream3.utils.loadExtractor | ||||
| import java.util.* | ||||
| 
 | ||||
| class AnimeflvnetProvider:MainAPI() { | ||||
|  | @ -13,6 +14,11 @@ class AnimeflvnetProvider:MainAPI() { | |||
|             else if (t.contains("Película")) TvType.AnimeMovie | ||||
|             else TvType.Anime | ||||
|         } | ||||
|         fun getDubStatus(title: String): DubStatus { | ||||
|             return if (title.contains("Latino") || title.contains("Castellano")) | ||||
|                 DubStatus.Dubbed | ||||
|             else DubStatus.Subbed | ||||
|         } | ||||
|     } | ||||
|     override var mainUrl = "https://www3.animeflv.net" | ||||
|     override var name = "Animeflv.net" | ||||
|  | @ -43,19 +49,10 @@ class AnimeflvnetProvider:MainAPI() { | |||
|                     val url = it.selectFirst("a").attr("href").replace(epRegex,"") | ||||
|                         .replace("ver/","anime/") | ||||
|                     val epNum = it.selectFirst("span.Capi").text().replace("Episodio ","").toIntOrNull() | ||||
|                     AnimeSearchResponse( | ||||
|                         title, | ||||
|                         fixUrl(url), | ||||
|                         this.name, | ||||
|                         TvType.Anime, | ||||
|                         fixUrl(poster), | ||||
|                         null, | ||||
|                         if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of( | ||||
|                             DubStatus.Dubbed | ||||
|                         ) else EnumSet.of(DubStatus.Subbed), | ||||
|                         subEpisodes = epNum, | ||||
|                         dubEpisodes = epNum, | ||||
|                     ) | ||||
|                     newAnimeSearchResponse(title, url) { | ||||
|                         this.posterUrl = fixUrl(poster) | ||||
|                         addDubStatus(getDubStatus(title), epNum) | ||||
|                     } | ||||
|                 }) | ||||
|         ) | ||||
|         for ((url, name) in urls) { | ||||
|  | @ -64,15 +61,10 @@ class AnimeflvnetProvider:MainAPI() { | |||
|                 val home = doc.select("ul.ListAnimes li article").map { | ||||
|                     val title = it.selectFirst("h3.Title").text() | ||||
|                     val poster = it.selectFirst("figure img").attr("src") | ||||
|                     AnimeSearchResponse( | ||||
|                         title, | ||||
|                         fixUrl(it.selectFirst("a").attr("href")), | ||||
|                         this.name, | ||||
|                         TvType.Anime, | ||||
|                         fixUrl(poster), | ||||
|                         null, | ||||
|                         if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of(DubStatus.Dubbed) else EnumSet.of(DubStatus.Subbed), | ||||
|                     ) | ||||
|                     newAnimeSearchResponse(title, fixUrl(it.selectFirst("a").attr("href"))) { | ||||
|                         this.posterUrl = fixUrl(poster) | ||||
|                         addDubStatus(MonoschinosProvider.getDubStatus(title)) | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 items.add(HomePageList(name, home)) | ||||
|  |  | |||
|  | @ -201,20 +201,10 @@ class GogoanimeProvider : MainAPI() { | |||
|                 items.add(HomePageList(i.second, (parseRegex.findAll(html.text).map { | ||||
|                     val (link, epNum, title, poster) = it.destructured | ||||
|                     val isSub = listOf(1, 3).contains(i.first.toInt()) | ||||
|                     AnimeSearchResponse( | ||||
|                         title, | ||||
|                         link, | ||||
|                         this.name, | ||||
|                         TvType.Anime, | ||||
|                         poster, | ||||
|                         null, | ||||
|                         if (isSub) EnumSet.of(DubStatus.Subbed) else EnumSet.of( | ||||
|                             DubStatus.Dubbed | ||||
|                         ), | ||||
|                         null, | ||||
|                         if (!isSub) epNum.toIntOrNull() else null, | ||||
|                         if (isSub) epNum.toIntOrNull() else null, | ||||
|                     ) | ||||
|                     newAnimeSearchResponse(title, link) { | ||||
|                         this.posterUrl = poster | ||||
|                         addDubStatus(!isSub, epNum.toIntOrNull()) | ||||
|                     } | ||||
|                 }).toList())) | ||||
|             } catch (e: Exception) { | ||||
|                 e.printStackTrace() | ||||
|  |  | |||
|  | @ -14,6 +14,12 @@ class MonoschinosProvider : MainAPI() { | |||
|             else if (t.contains("Pelicula")) TvType.AnimeMovie | ||||
|             else TvType.Anime | ||||
|         } | ||||
| 
 | ||||
|         fun getDubStatus(title: String): DubStatus { | ||||
|             return if (title.contains("Latino") || title.contains("Castellano")) | ||||
|                 DubStatus.Dubbed | ||||
|             else DubStatus.Subbed | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override var mainUrl = "https://monoschinos2.com" | ||||
|  | @ -50,19 +56,10 @@ class MonoschinosProvider : MainAPI() { | |||
|                     val url = it.selectFirst("a").attr("href").replace("ver/", "anime/") | ||||
|                         .replace(epRegex, "sub-espanol") | ||||
|                     val epNum = it.selectFirst(".positioning h5").text().toIntOrNull() | ||||
|                     AnimeSearchResponse( | ||||
|                         title, | ||||
|                         url, | ||||
|                         this.name, | ||||
|                         TvType.Anime, | ||||
|                         poster, | ||||
|                         null, | ||||
|                         if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of( | ||||
|                             DubStatus.Dubbed | ||||
|                         ) else EnumSet.of(DubStatus.Subbed), | ||||
|                         subEpisodes = epNum, | ||||
|                         dubEpisodes = epNum, | ||||
|                     ) | ||||
|                     newAnimeSearchResponse(title, url) { | ||||
|                         this.posterUrl = fixUrl(poster) | ||||
|                         addDubStatus(getDubStatus(title), epNum) | ||||
|                     } | ||||
|                 }) | ||||
|         ) | ||||
| 
 | ||||
|  | @ -71,17 +68,10 @@ class MonoschinosProvider : MainAPI() { | |||
|                 val home = app.get(i.first, timeout = 120).document.select(".col-6").map { | ||||
|                     val title = it.selectFirst(".seristitles").text() | ||||
|                     val poster = it.selectFirst("img.animemainimg").attr("src") | ||||
|                     AnimeSearchResponse( | ||||
|                         title, | ||||
|                         fixUrl(it.selectFirst("a").attr("href")), | ||||
|                         this.name, | ||||
|                         TvType.Anime, | ||||
|                         fixUrl(poster), | ||||
|                         null, | ||||
|                         if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of( | ||||
|                             DubStatus.Dubbed | ||||
|                         ) else EnumSet.of(DubStatus.Subbed), | ||||
|                     ) | ||||
|                     newAnimeSearchResponse(title, fixUrl(it.selectFirst("a").attr("href"))) { | ||||
|                         this.posterUrl = fixUrl(poster) | ||||
|                         addDubStatus(getDubStatus(title)) | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 items.add(HomePageList(i.second, home)) | ||||
|  |  | |||
|  | @ -17,12 +17,25 @@ class NineAnimeProvider : MainAPI() { | |||
|     override val hasDownloadSupport = true | ||||
|     override val supportedTypes = setOf(TvType.Anime) | ||||
| 
 | ||||
|     companion object { | ||||
|         fun getDubStatus(title: String): DubStatus { | ||||
|             return if (title.contains("(dub)", ignoreCase = true)) { | ||||
|                 DubStatus.Dubbed | ||||
|             } else { | ||||
|                 DubStatus.Subbed | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val items = listOf( | ||||
|             Pair("$mainUrl/ajax/home/widget?name=trending", "Trending"), | ||||
|             Pair("$mainUrl/ajax/home/widget?name=updated_all", "All"), | ||||
|             Pair("$mainUrl/ajax/home/widget?name=updated_sub&page=1", "Recently Updated (SUB)"), | ||||
|             Pair("$mainUrl/ajax/home/widget?name=updated_dub&page=1", "Recently Updated (DUB)"), | ||||
|             Pair( | ||||
|                 "$mainUrl/ajax/home/widget?name=updated_dub&page=1", | ||||
|                 "Recently Updated (DUB)(DUB)" | ||||
|             ), | ||||
|             Pair( | ||||
|                 "$mainUrl/ajax/home/widget?name=updated_chinese&page=1", | ||||
|                 "Recently Updated (Chinese)" | ||||
|  | @ -37,17 +50,11 @@ class NineAnimeProvider : MainAPI() { | |||
|                 val title = it.selectFirst("a.name").text() | ||||
|                 val link = it.selectFirst("a").attr("href") | ||||
|                 val poster = it.selectFirst("a.poster img").attr("src") | ||||
|                 AnimeSearchResponse( | ||||
|                     title, | ||||
|                     link, | ||||
|                     this.name, | ||||
|                     TvType.Anime, | ||||
|                     poster, | ||||
|                     null, | ||||
|                     if (title.contains("(DUB)") || title.contains("(Dub)")) EnumSet.of( | ||||
|                         DubStatus.Dubbed | ||||
|                     ) else EnumSet.of(DubStatus.Subbed), | ||||
|                 ) | ||||
| 
 | ||||
|                 newAnimeSearchResponse(title, link) { | ||||
|                     this.posterUrl = poster | ||||
|                     addDubStatus(getDubStatus(title)) | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             HomePageList(name, home) | ||||
|  | @ -206,24 +213,18 @@ class NineAnimeProvider : MainAPI() { | |||
|             Episode(link, name) | ||||
|         } ?: return null | ||||
| 
 | ||||
| 
 | ||||
|         val recommendations = | ||||
|             doc.select("div.container aside.main section div.body ul.anime-list li")?.mapNotNull { element -> | ||||
|                 val recTitle = element.select("a.name").text() ?: return@mapNotNull null | ||||
|                 val image = element.select("a.poster img")?.attr("src") | ||||
|                 val recUrl = fixUrl(element.select("a").attr("href")) | ||||
|                 AnimeSearchResponse( | ||||
|                     recTitle, | ||||
|                     fixUrl(recUrl), | ||||
|                     this.name, | ||||
|                     TvType.Anime, | ||||
|                     image, | ||||
|                     dubStatus = | ||||
|                     if (recTitle.contains("(DUB)") || recTitle.contains("(Dub)")) EnumSet.of( | ||||
|                         DubStatus.Dubbed | ||||
|                     ) else EnumSet.of(DubStatus.Subbed), | ||||
|                 ) | ||||
|             } | ||||
|             doc.select("div.container aside.main section div.body ul.anime-list li") | ||||
|                 ?.mapNotNull { element -> | ||||
|                     val recTitle = element.select("a.name")?.text() ?: return@mapNotNull null | ||||
|                     val image = element.select("a.poster img")?.attr("src") | ||||
|                     val recUrl = fixUrl(element.select("a").attr("href")) | ||||
|                     newAnimeSearchResponse(recTitle, recUrl) { | ||||
|                         this.posterUrl = image | ||||
|                         addDubStatus(getDubStatus(recTitle)) | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|         val infodoc = doc.selectFirst("div.info .meta .col1").text() | ||||
|         val tvType = if (infodoc.contains("Movie")) TvType.AnimeMovie else TvType.Anime | ||||
|         val status = | ||||
|  | @ -231,13 +232,14 @@ class NineAnimeProvider : MainAPI() { | |||
|             else if (infodoc.contains("Airing")) ShowStatus.Ongoing | ||||
|             else null | ||||
|         val tags = doc.select("div.info .meta .col1 div:contains(Genre) a").map { it.text() } | ||||
| 
 | ||||
|         return newAnimeLoadResponse(title, url, tvType) { | ||||
|             posterUrl = poster | ||||
|             addEpisodes(DubStatus.Subbed, episodes) | ||||
|             plot = description | ||||
|             this.posterUrl = poster | ||||
|             this.plot = description | ||||
|             this.recommendations = recommendations | ||||
|             showStatus = status | ||||
|             this.showStatus = status | ||||
|             this.tags = tags | ||||
|             addEpisodes(DubStatus.Subbed, episodes) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -260,7 +262,8 @@ class NineAnimeProvider : MainAPI() { | |||
|         callback: (ExtractorLink) -> Unit | ||||
|     ): Boolean { | ||||
|         val document = app.get(data).document | ||||
|         val animeid = document.selectFirst("div.player-wrapper.watchpage").attr("data-id") ?: return false | ||||
|         val animeid = | ||||
|             document.selectFirst("div.player-wrapper.watchpage").attr("data-id") ?: return false | ||||
|         val animeidencoded = encode(getVrf(animeid) ?: return false) | ||||
| 
 | ||||
|         Jsoup.parse( | ||||
|  | @ -287,7 +290,7 @@ class NineAnimeProvider : MainAPI() { | |||
|                         parseJson<Links>(epserver) | ||||
|                     } else null)?.url?.let { it1 -> getLink(it1.replace("=", "")) } | ||||
|                         ?.replace("/embed/", "/e/") | ||||
|                 } catch (e : Exception) { | ||||
|                 } catch (e: Exception) { | ||||
|                     logError(e) | ||||
|                     null | ||||
|                 } | ||||
|  |  | |||
|  | @ -17,7 +17,6 @@ import okhttp3.Interceptor | |||
| import org.jsoup.Jsoup | ||||
| import org.jsoup.nodes.Element | ||||
| import java.net.URI | ||||
| import java.util.* | ||||
| 
 | ||||
| private const val OPTIONS = "OPTIONS" | ||||
| 
 | ||||
|  | @ -52,30 +51,31 @@ class ZoroProvider : MainAPI() { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     val epRegex = Regex("Ep (\\d+)/") | ||||
|     private fun Element.toSearchResult(): SearchResponse? { | ||||
|         val href = fixUrl(this.select("a").attr("href")) | ||||
|         val title = this.select("h3.film-name").text() | ||||
|         /*val episodes = this.select("div.fd-infor > span.fdi-item")?.get(1)?.text()?.let { eps -> | ||||
|             val dubSub = this.select(".film-poster > .tick.ltr").text() | ||||
|         //val episodes = this.selectFirst(".film-poster > .tick-eps")?.text()?.toIntOrNull() | ||||
| 
 | ||||
|         val dubExist = dubSub.contains("dub", ignoreCase = true) | ||||
|         val subExist = dubSub.contains("sub", ignoreCase = true) | ||||
|         val episodes = this.selectFirst(".film-poster > .tick.rtl > .tick-eps")?.text()?.let { eps -> | ||||
|             //println("REGEX:::: $eps") | ||||
|             // current episode / max episode | ||||
|             val epRegex = Regex("Ep (\\d+)/")//Regex("Ep (\\d+)/(\\d+)") | ||||
|             //Regex("Ep (\\d+)/(\\d+)") | ||||
|             epRegex.find(eps)?.groupValues?.get(1)?.toIntOrNull() | ||||
|         }*/ | ||||
|         } | ||||
|         if (href.contains("/news/") || title.trim().equals("News", ignoreCase = true)) return null | ||||
|         val posterUrl = fixUrl(this.select("img").attr("data-src")) | ||||
|         val type = getType(this.select("div.fd-infor > span.fdi-item").text()) | ||||
| 
 | ||||
|         return AnimeSearchResponse( | ||||
|             title, | ||||
|             href, | ||||
|             this@ZoroProvider.name, | ||||
|             type, | ||||
|             posterUrl, | ||||
|             null, | ||||
|             null, | ||||
|         ) | ||||
|         return newAnimeSearchResponse(title, href, type) { | ||||
|             this.posterUrl = posterUrl | ||||
|             addDubStatus(dubExist, subExist, episodes, episodes) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     override suspend fun getMainPage(): HomePageResponse { | ||||
|         val html = app.get("$mainUrl/home").text | ||||
|         val document = Jsoup.parse(html) | ||||
|  | @ -152,30 +152,14 @@ class ZoroProvider : MainAPI() { | |||
|             val dubExist = dubsub?.contains("DUB") ?: false | ||||
|             val subExist = dubsub?.contains("SUB") ?: false || dubsub?.contains("RAW") ?: false | ||||
| 
 | ||||
|             val set = if (dubExist && subExist) { | ||||
|                 EnumSet.of(DubStatus.Dubbed, DubStatus.Subbed) | ||||
|             } else if (dubExist) { | ||||
|                 EnumSet.of(DubStatus.Dubbed) | ||||
|             } else { | ||||
|                 EnumSet.of(DubStatus.Subbed) | ||||
|             } | ||||
| 
 | ||||
|             val tvType = | ||||
|                 getType(it.selectFirst(".film-detail > .fd-infor > .fdi-item")?.text().toString()) | ||||
|             val href = fixUrl(it.selectFirst(".film-name a").attr("href")) | ||||
| 
 | ||||
|             AnimeSearchResponse( | ||||
|                 title, | ||||
|                 href, | ||||
|                 name, | ||||
|                 tvType, | ||||
|                 poster, | ||||
|                 null, | ||||
|                 set, | ||||
|                 null, | ||||
|                 if (dubExist) episodes else null, | ||||
|                 if (subExist) episodes else null, | ||||
|             ) | ||||
|             newAnimeSearchResponse(title, href, tvType) { | ||||
|                 this.posterUrl = poster | ||||
|                 addDubStatus(dubExist, subExist, episodes, episodes) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -187,8 +171,8 @@ class ZoroProvider : MainAPI() { | |||
|     } | ||||
| 
 | ||||
|     data class ZoroSyncData( | ||||
|         @JsonProperty("mal_id") val malId : String?, | ||||
|         @JsonProperty("anilist_id") val aniListId : String?, | ||||
|         @JsonProperty("mal_id") val malId: String?, | ||||
|         @JsonProperty("anilist_id") val aniListId: String?, | ||||
|     ) | ||||
| 
 | ||||
|     override suspend fun load(url: String): LoadResponse { | ||||
|  |  | |||
|  | @ -14,6 +14,11 @@ class DoramasYTProvider : MainAPI() { | |||
|             else if (t.contains("Pelicula")) TvType.Movie | ||||
|             else TvType.TvSeries | ||||
|         } | ||||
|         fun getDubStatus(title: String): DubStatus { | ||||
|             return if (title.contains("Latino") || title.contains("Castellano")) | ||||
|                 DubStatus.Dubbed | ||||
|             else DubStatus.Subbed | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override var mainUrl = "https://doramasyt.com" | ||||
|  | @ -53,39 +58,22 @@ class DoramasYTProvider : MainAPI() { | |||
|                     val url = it.selectFirst("a").attr("href").replace("ver/", "dorama/") | ||||
|                         .replace(epRegex, "sub-espanol") | ||||
|                     val epNum = it.selectFirst("h3").text().toIntOrNull() | ||||
|                     AnimeSearchResponse( | ||||
|                         title, | ||||
|                         url, | ||||
|                         this.name, | ||||
|                         TvType.Anime, | ||||
|                         poster, | ||||
|                         null, | ||||
|                         if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of( | ||||
|                             DubStatus.Dubbed | ||||
|                         ) else EnumSet.of(DubStatus.Subbed), | ||||
|                         subEpisodes = epNum, | ||||
|                         dubEpisodes = epNum, | ||||
|                     ) | ||||
|                     newAnimeSearchResponse(title,url) { | ||||
|                         this.posterUrl = fixUrl(poster) | ||||
|                         addDubStatus(getDubStatus(title), epNum) | ||||
|                     } | ||||
|                 }) | ||||
|         ) | ||||
| 
 | ||||
|         for (i in urls) { | ||||
|             try { | ||||
| 
 | ||||
|                 val home = app.get(i.first, timeout = 120).document.select(".col-6").map { | ||||
|                     val title = it.selectFirst(".animedtls p").text() | ||||
|                     val poster = it.selectFirst(".anithumb img").attr("src") | ||||
|                     AnimeSearchResponse( | ||||
|                         title, | ||||
|                         it.selectFirst("a").attr("href"), | ||||
|                         this.name, | ||||
|                         TvType.Anime, | ||||
|                         poster, | ||||
|                         null, | ||||
|                         if (title.contains("Latino") || title.contains("Castellano")) EnumSet.of( | ||||
|                             DubStatus.Dubbed | ||||
|                         ) else EnumSet.of(DubStatus.Subbed), | ||||
|                     ) | ||||
|                     newAnimeSearchResponse(title, fixUrl(it.selectFirst("a").attr("href"))) { | ||||
|                         this.posterUrl = fixUrl(poster) | ||||
|                         addDubStatus(getDubStatus(title)) | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 items.add(HomePageList(i.second, home)) | ||||
|  |  | |||
|  | @ -85,7 +85,7 @@ open class VidstreamProviderTemplate : MainAPI() { | |||
| 
 | ||||
|         val description = soup.selectFirst(".post-entry")?.text()?.trim() | ||||
|         var poster: String? = null | ||||
|         var year : Int? = null | ||||
|         var year: Int? = null | ||||
| 
 | ||||
|         val episodes = | ||||
|             soup.select(".listing.items.lists > .video-block").withIndex().map { (_, li) -> | ||||
|  | @ -105,7 +105,7 @@ open class VidstreamProviderTemplate : MainAPI() { | |||
| 
 | ||||
|                 val epNum = Regex("""Episode (\d+)""").find(epTitle)?.destructured?.component1() | ||||
|                     ?.toIntOrNull() | ||||
|                 if(year == null) { | ||||
|                 if (year == null) { | ||||
|                     year = epDate?.split("-")?.get(0)?.toIntOrNull() | ||||
|                 } | ||||
|                 newEpisode(li.selectFirst("a").attr("href")) { | ||||
|  | @ -173,25 +173,13 @@ open class VidstreamProviderTemplate : MainAPI() { | |||
|                     val isSeries = (name.contains("Season") || name.contains("Episode")) | ||||
| 
 | ||||
|                     if (isSeries) { | ||||
|                         TvSeriesSearchResponse( | ||||
|                             name, | ||||
|                             link, | ||||
|                             this.name, | ||||
|                             TvType.TvSeries, | ||||
|                             image, | ||||
|                             null, | ||||
|                             null, | ||||
|                         ) | ||||
|                         newTvSeriesSearchResponse(name, link) { | ||||
|                             posterUrl = image | ||||
|                         } | ||||
|                     } else { | ||||
|                         MovieSearchResponse( | ||||
|                             name, | ||||
|                             link, | ||||
|                             this.name, | ||||
|                             TvType.Movie, | ||||
|                             image, | ||||
|                             null, | ||||
|                             null, | ||||
|                         ) | ||||
|                         newMovieSearchResponse(name, link) { | ||||
|                             posterUrl = image | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|  |  | |||
|  | @ -770,7 +770,7 @@ class HomeFragment : Fragment() { | |||
| 
 | ||||
|                     home_main_text?.text = | ||||
|                         random.name + if (random is AnimeSearchResponse && !random.dubStatus.isNullOrEmpty()) { | ||||
|                             random.dubStatus.joinToString( | ||||
|                             random.dubStatus?.joinToString( | ||||
|                                 prefix = " • ", | ||||
|                                 separator = " | " | ||||
|                             ) { it.name } | ||||
|  |  | |||
|  | @ -710,7 +710,8 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio | |||
|                         CastButtonFactory.setUpMediaRouteButton(act, media_route_button) | ||||
|                         val castContext = CastContext.getSharedInstance(act.applicationContext) | ||||
| 
 | ||||
|                         media_route_button?.isGone = castContext.castState == CastState.NO_DEVICES_AVAILABLE | ||||
|                         media_route_button?.isGone = | ||||
|                             castContext.castState == CastState.NO_DEVICES_AVAILABLE | ||||
| 
 | ||||
|                         castContext.addCastStateListener { state -> | ||||
|                             media_route_button?.isGone = state == CastState.NO_DEVICES_AVAILABLE | ||||
|  | @ -1299,7 +1300,6 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio | |||
|         } | ||||
| 
 | ||||
|         observe(syncModel.syncIds) { | ||||
|             println("VALUES::: $it") | ||||
|             syncdata = it | ||||
|         } | ||||
| 
 | ||||
|  | @ -1657,8 +1657,8 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio | |||
| 
 | ||||
|                     val posterImageLink = d.posterUrl | ||||
|                     if (!posterImageLink.isNullOrEmpty()) { | ||||
|                         result_poster?.setImage(posterImageLink) | ||||
|                         result_poster_blur?.setImageBlur(posterImageLink, 10, 3) | ||||
|                         result_poster?.setImage(posterImageLink, d.posterHeaders) | ||||
|                         result_poster_blur?.setImageBlur(posterImageLink, 10, 3, d.posterHeaders) | ||||
|                         //Full screen view of Poster image | ||||
|                         if (context?.isTrueTvSettings() == false) // Poster not clickable on tv | ||||
|                             result_poster_holder?.setOnClickListener { | ||||
|  |  | |||
|  | @ -52,7 +52,8 @@ class SearchFragment : Fragment() { | |||
|         fun List<SearchResponse>.filterSearchResponse(): List<SearchResponse> { | ||||
|             return this.filter { response -> | ||||
|                 if (response is AnimeSearchResponse) { | ||||
|                     (response.dubStatus.isNullOrEmpty()) || (response.dubStatus.any { | ||||
|                     val status = response.dubStatus | ||||
|                     (status.isNullOrEmpty()) || (status.any { | ||||
|                         APIRepository.dubStatusActive.contains(it) | ||||
|                     }) | ||||
|                 } else { | ||||
|  | @ -225,11 +226,13 @@ class SearchFragment : Fragment() { | |||
|                             } | ||||
|                         }.sortedBy { it.name.lowercase() } | ||||
| 
 | ||||
|                         val names = currentValidApis.map {  if(isMultiLang) "${ | ||||
|                             SubtitleHelper.getFlagFromIso( | ||||
|                                 it.lang | ||||
|                             )?.plus(" ") ?: "" | ||||
|                         }${it.name}" else it.name } | ||||
|                         val names = currentValidApis.map { | ||||
|                             if (isMultiLang) "${ | ||||
|                                 SubtitleHelper.getFlagFromIso( | ||||
|                                     it.lang | ||||
|                                 )?.plus(" ") ?: "" | ||||
|                             }${it.name}" else it.name | ||||
|                         } | ||||
|                         for ((index, api) in currentValidApis.map { it.name }.withIndex()) { | ||||
|                             listView?.setItemChecked(index, currentSelectedApis.contains(api)) | ||||
|                         } | ||||
|  |  | |||
|  | @ -47,7 +47,7 @@ object SearchResultBuilder { | |||
|         textIsDub?.isVisible = false | ||||
|         textIsSub?.isVisible = false | ||||
| 
 | ||||
|         when(card.quality) { | ||||
|         when (card.quality) { | ||||
|             SearchQuality.BlueRay -> R.string.quality_blueray | ||||
|             SearchQuality.Cam -> R.string.quality_cam | ||||
|             SearchQuality.CamRip -> R.string.quality_cam_rip | ||||
|  | @ -75,7 +75,7 @@ object SearchResultBuilder { | |||
|         cardText?.text = card.name | ||||
| 
 | ||||
|         cardView.isVisible = true | ||||
|         if (!cardView.setImage(card.posterUrl)) { | ||||
|         if (!cardView.setImage(card.posterUrl, card.posterHeaders)) { | ||||
|             cardView.setImageResource(R.drawable.default_cover) | ||||
|         } | ||||
| 
 | ||||
|  | @ -182,20 +182,24 @@ object SearchResultBuilder { | |||
|                 } | ||||
|             } | ||||
|             is AnimeSearchResponse -> { | ||||
|                 if (card.dubStatus != null && card.dubStatus.size > 0) { | ||||
|                     if (card.dubStatus.contains(DubStatus.Dubbed)) { | ||||
|                 val dubStatus = card.dubStatus | ||||
|                 if (!dubStatus.isNullOrEmpty()) { | ||||
|                     if (dubStatus.contains(DubStatus.Dubbed)) { | ||||
|                         textIsDub?.visibility = View.VISIBLE | ||||
|                     } | ||||
|                     if (card.dubStatus.contains(DubStatus.Subbed)) { | ||||
|                     if (dubStatus.contains(DubStatus.Subbed)) { | ||||
|                         textIsSub?.visibility = View.VISIBLE | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 val dubEpisodes = card.episodes[DubStatus.Dubbed] | ||||
|                 val subEpisodes = card.episodes[DubStatus.Subbed] | ||||
| 
 | ||||
|                 textIsDub?.apply { | ||||
|                     val dubText = context.getString(R.string.app_dubbed_text) | ||||
|                     text = if (card.dubEpisodes != null && card.dubEpisodes > 0) { | ||||
|                     text = if (dubEpisodes != null && dubEpisodes > 0) { | ||||
|                         context.getString(R.string.app_dub_sub_episode_text_format) | ||||
|                             .format(dubText, card.dubEpisodes) | ||||
|                             .format(dubText, dubEpisodes) | ||||
|                     } else { | ||||
|                         dubText | ||||
|                     } | ||||
|  | @ -203,9 +207,9 @@ object SearchResultBuilder { | |||
| 
 | ||||
|                 textIsSub?.apply { | ||||
|                     val subText = context.getString(R.string.app_subbed_text) | ||||
|                     text = if (card.subEpisodes != null && card.subEpisodes > 0) { | ||||
|                     text = if (subEpisodes != null && subEpisodes > 0) { | ||||
|                         context.getString(R.string.app_dub_sub_episode_text_format) | ||||
|                             .format(subText, card.subEpisodes) | ||||
|                             .format(subText, subEpisodes) | ||||
|                     } else { | ||||
|                         subText | ||||
|                     } | ||||
|  |  | |||
|  | @ -16,7 +16,8 @@ class SyncSearchViewModel { | |||
|         override var type: TvType?, | ||||
|         override var posterUrl: String?, | ||||
|         override var id: Int?, | ||||
|         override var quality: SearchQuality? = null | ||||
|         override var quality: SearchQuality? = null, | ||||
|         override var posterHeaders: Map<String, String>? = null, | ||||
|     ) : SearchResponse | ||||
| 
 | ||||
|     private fun SyncAPI.SyncSearchResult.toSearchResponse(): SyncSearchResultSearchResponse { | ||||
|  |  | |||
|  | @ -43,7 +43,8 @@ object DataStoreHelper { | |||
|         @JsonProperty("type") override var type: TvType? = null, | ||||
|         @JsonProperty("posterUrl") override var posterUrl: String?, | ||||
|         @JsonProperty("year") val year: Int?, | ||||
|         @JsonProperty("quality") override var quality: SearchQuality? = null | ||||
|         @JsonProperty("quality") override var quality: SearchQuality? = null, | ||||
|         @JsonProperty("posterHeaders") override var posterHeaders: Map<String, String>? = null, | ||||
|     ) : SearchResponse | ||||
| 
 | ||||
|     data class ResumeWatchingResult( | ||||
|  | @ -60,7 +61,8 @@ object DataStoreHelper { | |||
|         @JsonProperty("episode") val episode: Int?, | ||||
|         @JsonProperty("season") val season: Int?, | ||||
|         @JsonProperty("isFromDownload") val isFromDownload: Boolean, | ||||
|         @JsonProperty("quality") override var quality: SearchQuality? = null | ||||
|         @JsonProperty("quality") override var quality: SearchQuality? = null, | ||||
|         @JsonProperty("posterHeaders") override var posterHeaders: Map<String, String>? = null, | ||||
|     ) : SearchResponse | ||||
| 
 | ||||
|     var currentAccount: String = "0" //TODO ACCOUNT IMPLEMENTATION | ||||
|  |  | |||
|  | @ -148,11 +148,11 @@ object UIHelper { | |||
|         return color | ||||
|     } | ||||
| 
 | ||||
|     fun ImageView?.setImage(url: String?): Boolean { | ||||
|     fun ImageView?.setImage(url: String?, headers: Map<String, String>? = null): Boolean { | ||||
|         if (this == null || url.isNullOrBlank()) return false | ||||
|         return try { | ||||
|             GlideApp.with(this.context) | ||||
|                 .load(GlideUrl(url)).transition( | ||||
|                 .load(GlideUrl(url) { headers ?: emptyMap() }).transition( | ||||
|                     DrawableTransitionOptions.withCrossFade() | ||||
|                 ) | ||||
|                 .into(this) | ||||
|  | @ -163,11 +163,17 @@ object UIHelper { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fun ImageView?.setImageBlur(url: String?, radius: Int, sample: Int = 3) { | ||||
|     fun ImageView?.setImageBlur( | ||||
|         url: String?, | ||||
|         radius: Int, | ||||
|         sample: Int = 3, | ||||
|         headers: Map<String, String>? = null | ||||
|     ) { | ||||
|         if (this == null || url.isNullOrBlank()) return | ||||
|         try { | ||||
|             GlideApp.with(this.context) | ||||
|                 .load(GlideUrl(url)).apply(bitmapTransform(BlurTransformation(radius, sample))) | ||||
|                 .load(GlideUrl(url) { headers ?: emptyMap() }) | ||||
|                 .apply(bitmapTransform(BlurTransformation(radius, sample))) | ||||
|                 .transition( | ||||
|                     DrawableTransitionOptions.withCrossFade() | ||||
|                 ) | ||||
|  |  | |||
|  | @ -24,6 +24,11 @@ | |||
|             android:layout_height="match_parent" | ||||
|             android:foreground="?android:attr/selectableItemBackgroundBorderless" | ||||
|             android:contentDescription="@string/search_poster_img_des" /> | ||||
|     <TextView | ||||
|             tools:text="@string/quality_hd" | ||||
|             android:id="@+id/text_quality" | ||||
|             style="@style/SearchBox" | ||||
|             android:background="@drawable/type_bg_color"/> | ||||
|     <!-- | ||||
|     <LinearLayout | ||||
|             android:orientation="vertical" | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue