mainApi changes

This commit is contained in:
LagradOst 2022-04-13 19:29:30 +02:00
parent 117730e9a8
commit 94561e0d5b
19 changed files with 358 additions and 325 deletions

View File

@ -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(

View File

@ -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)
}
}
}

View File

@ -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('/')

View File

@ -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())

View File

@ -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))

View File

@ -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()

View File

@ -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))

View File

@ -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
}

View File

@ -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 {

View File

@ -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))

View File

@ -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
}
}
}

View File

@ -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 }

View File

@ -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 {

View File

@ -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))
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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

View File

@ -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()
)

View File

@ -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"