added new anime Sources into SoraExtractor

This commit is contained in:
hexated 2022-11-18 18:00:36 +07:00
parent 4f629f48ec
commit 9ec65f3b24
4 changed files with 243 additions and 1975 deletions

View file

@ -1,5 +1,5 @@
// use an integer for version numbers
version = 30
version = 31
cloudstream {

File diff suppressed because it is too large Load diff

View file

@ -19,6 +19,7 @@ val session = Session(Requests().baseClient)
object SoraExtractor : SoraStream() {
/*
suspend fun invokeLocalSources(
url: String,
subtitleCallback: (SubtitleFile) -> Unit,
@ -56,6 +57,7 @@ object SoraExtractor : SoraStream() {
}
}
*/
suspend fun invokeTwoEmbed(
id: Int? = null,
@ -352,30 +354,6 @@ object SoraExtractor : SoraStream() {
}
}
*/
suspend fun invokeGogo(
aniId: String? = null,
animeId: String? = null,
callback: (ExtractorLink) -> Unit
) {
val res =
app.get("$mainServerAPI/anime/$aniId/episode/$animeId?_data=routes/anime/\$animeId.episode.\$episodeId")
.parsedSafe<LoadLinks>()
res?.sources?.map { source ->
callback.invoke(
ExtractorLink(
this.name,
this.name,
source.url ?: return@map null,
"$mainServerAPI/",
getQualityFromName(source.quality),
isM3u8 = source.isM3U8,
headers = mapOf("Origin" to mainServerAPI)
)
)
}
}
suspend fun invokeHDMovieBox(
title: String? = null,
@ -385,11 +363,11 @@ object SoraExtractor : SoraStream() {
) {
val fixTitle = title.fixTitle()
val url = "$hdMovieBoxAPI/watch/$fixTitle"
val ref = if (season == null) {
"$hdMovieBoxAPI/watch/$fixTitle"
} else {
"$hdMovieBoxAPI/watch/$fixTitle/season-$season/episode-$episode"
}
// val ref = if (season == null) {
// "$hdMovieBoxAPI/watch/$fixTitle"
// } else {
// "$hdMovieBoxAPI/watch/$fixTitle/season-$season/episode-$episode"
// }
val doc = app.get(url).document
val id = if (season == null) {
@ -570,9 +548,11 @@ object SoraExtractor : SoraStream() {
val srcm3u8 = resDoc.selectFirst("script:containsData(let url =)")?.data()?.let {
Regex("['|\"](.*?.m3u8)['|\"]").find(it)?.groupValues?.getOrNull(1)
} ?: return@apmap null
val quality = app.get(srcm3u8, referer = source, headers = mapOf(
val quality = app.get(
srcm3u8, referer = source, headers = mapOf(
"Accept" to "*/*",
)).text.let { quality ->
)
).text.let { quality ->
if (quality.contains("RESOLUTION=1920")) Qualities.P1080.value else Qualities.P720.value
}
callback.invoke(
@ -650,7 +630,8 @@ object SoraExtractor : SoraStream() {
} else {
"${filmxyAPI}/tv/$imdbId"
}
val filmxyCookies = getFilmxyCookies(imdbId, season) ?: throw ErrorLoadingException("No Cookies Found")
val filmxyCookies =
getFilmxyCookies(imdbId, season) ?: throw ErrorLoadingException("No Cookies Found")
val cookiesDoc = mapOf(
"G_ENABLED_IDPS" to "google",
@ -664,7 +645,8 @@ object SoraExtractor : SoraStream() {
val doc = request.document
val script = doc.selectFirst("script:containsData(var isSingle)")?.data().toString()
val sourcesData = Regex("listSE\\s*=\\s?(.*?),[\\n|\\s]").find(script)?.groupValues?.get(1)
val sourcesDetail = Regex("linkDetails\\s*=\\s?(.*?),[\\n|\\s]").find(script)?.groupValues?.get(1)
val sourcesDetail =
Regex("linkDetails\\s*=\\s?(.*?),[\\n|\\s]").find(script)?.groupValues?.get(1)
//Gson is shit, but i don't care
val sourcesJson = JsonParser().parse(sourcesData).asJsonObject
@ -678,9 +660,12 @@ object SoraExtractor : SoraStream() {
sourcesJson.getAsJsonObject("s$sson").getAsJsonArray("e$eps")
}.asJsonArray
val scriptUser = doc.select("script").find { it.data().contains("var userNonce") }?.data().toString()
val userNonce = Regex("var\\suserNonce.*?[\"|'](\\S+?)[\"|'];").find(scriptUser)?.groupValues?.get(1)
val userId = Regex("var\\suser_id.*?[\"|'](\\S+?)[\"|'];").find(scriptUser)?.groupValues?.get(1)
val scriptUser =
doc.select("script").find { it.data().contains("var userNonce") }?.data().toString()
val userNonce =
Regex("var\\suserNonce.*?[\"|'](\\S+?)[\"|'];").find(scriptUser)?.groupValues?.get(1)
val userId =
Regex("var\\suser_id.*?[\"|'](\\S+?)[\"|'];").find(scriptUser)?.groupValues?.get(1)
val linkIDs = sources.joinToString("") {
"&linkIDs%5B%5D=$it"
}.replace("\"", "")
@ -709,8 +694,10 @@ object SoraExtractor : SoraStream() {
sources.map { source ->
val src = source.asString
val link = json.getAsJsonPrimitive(src).asString
val quality = sourcesDetailJson.getAsJsonObject(src).getAsJsonPrimitive("resolution").asString
val server = sourcesDetailJson.getAsJsonObject(src).getAsJsonPrimitive("server").asString
val quality =
sourcesDetailJson.getAsJsonObject(src).getAsJsonPrimitive("resolution").asString
val server =
sourcesDetailJson.getAsJsonObject(src).getAsJsonPrimitive("server").asString
val size = sourcesDetailJson.getAsJsonObject(src).getAsJsonPrimitive("size").asString
callback.invoke(
@ -749,7 +736,9 @@ object SoraExtractor : SoraStream() {
}.first { it.contains("Season-$season", true) && it.contains("Episode-$episode", true) }
} ?: return
val source = app.get(fixUrl(iframe, kimcartoonAPI)).document.select("div#divContentVideo iframe").attr("src")
val source =
app.get(fixUrl(iframe, kimcartoonAPI)).document.select("div#divContentVideo iframe")
.attr("src")
loadExtractor(source, "$kimcartoonAPI/", subtitleCallback) { link ->
callback.invoke(
ExtractorLink(
@ -779,7 +768,8 @@ object SoraExtractor : SoraStream() {
"versioncode" to "11",
"clienttype" to "ios_jike_default"
)
val vipAPI = base64DecodeAPI("cA==YXA=cy8=Y20=di8=LnQ=b2s=a2w=bG8=aS4=YXA=ZS0=aWw=b2I=LW0=Z2E=Ly8=czo=dHA=aHQ=")
val vipAPI =
base64DecodeAPI("cA==YXA=cy8=Y20=di8=LnQ=b2s=a2w=bG8=aS4=YXA=ZS0=aWw=b2I=LW0=Z2E=Ly8=czo=dHA=aHQ=")
val vipUrl = base64DecodeAPI("b20=LmM=b2s=a2w=bG8=Ly8=czo=dHA=aHQ=")
val doc = app.get(
@ -823,10 +813,12 @@ object SoraExtractor : SoraStream() {
if (!jsonResponse.isSuccessful) return
val json = jsonResponse.parsedSafe<Load>()?.data?.episodeVo?.first { it.seriesNo == (episode ?: 0) }
val json = jsonResponse.parsedSafe<Load>()?.data?.episodeVo?.first {
it.seriesNo == (episode ?: 0)
}
json?.definitionList?.apmap { video ->
delay(2000)
delay(1000)
app.get(
"${vipAPI}/media/previewInfo?category=${type}&contentId=${id}&episodeId=${json.id}&definition=${video.code}",
headers = headers
@ -934,7 +926,8 @@ object SoraExtractor : SoraStream() {
) {
val fixTitle = title?.replace("", "-")
val id =
app.get("$consumetFlixhqAPI/$title").parsedSafe<FlixhqSearchResponse>()?.results?.find {
app.get("$consumetFlixhqAPI/$title")
.parsedSafe<ConsumetSearchResponse>()?.results?.find {
if (season == null) {
it.title?.equals(
"$fixTitle",
@ -945,7 +938,8 @@ object SoraExtractor : SoraStream() {
}
}?.id ?: return
val episodeId = app.get("$consumetFlixhqAPI/info?id=$id").parsedSafe<FlixhqDetails>()?.let {
val episodeId =
app.get("$consumetFlixhqAPI/info?id=$id").parsedSafe<ConsumetDetails>()?.let {
if (season == null) {
it.episodes?.first()?.id
} else {
@ -957,10 +951,10 @@ object SoraExtractor : SoraStream() {
"vidcloud",
"upcloud"
).apmap { server ->
delay(2000)
delay(1000)
val sources =
app.get("$consumetFlixhqAPI/watch?episodeId=$episodeId&mediaId=$id&server=$server")
.parsedSafe<FlixhqSourcesResponse>()
.parsedSafe<ConsumetSourcesResponse>()
val name = fixTitle(server)
sources?.sources?.map {
callback.invoke(
@ -1052,8 +1046,20 @@ object SoraExtractor : SoraStream() {
link?.substringBefore("=http") ?: return@apmap null,
"$kissKhAPI/",
subtitleCallback,
callback
) { links ->
callback.invoke(
ExtractorLink(
"StreamSS",
"StreamSS",
links.url,
links.referer,
links.quality,
links.isM3u8,
links.headers,
links.extractorData
)
)
}
}
}
}
@ -1072,6 +1078,58 @@ object SoraExtractor : SoraStream() {
}
suspend fun invoZoro(
id: Int? = null,
season: Int? = null,
episode: Int? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val malId = app.get("$tmdb2mal/?id=$id&s=$season").text.trim()
val (engTitle, japTitle) = app.get("https://animixplay.to/assets/mal/$malId.json")
.parsedSafe<AnimixData>()?.let {
it.title_english to it.title
} ?: return
val animeId =
app.get("$consumetZoroAPI/$japTitle").parsedSafe<ConsumetSearchResponse>()?.results?.find {
val title = it.title ?: return
(title.equals(engTitle, true) || title.equals(japTitle, true) ) && it.type == "TV"
}?.id ?: return
val episodeId = app.get("$consumetZoroAPI/info?id=$animeId")
.parsedSafe<ConsumetDetails>()?.episodes?.find {
it.number == episode
}?.id ?: return
val sources = app.get("$consumetZoroAPI/watch?episodeId=$episodeId")
.parsedSafe<ConsumetSourcesResponse>() ?: return
sources.sources?.map {
callback.invoke(
ExtractorLink(
"Zoro",
"Zoro",
it.url ?: return@map null,
"",
getQualityFromName(it.quality),
it.isM3U8 ?: true
)
)
}
sources.subtitles?.map {
subtitleCallback.invoke(
SubtitleFile(
it.lang ?: "",
it.url ?: return@map null
)
)
}
}
}
data class FilmxyCookies(
@ -1120,7 +1178,8 @@ suspend fun getFilmxyCookies(imdbId: String? = null, season: Int? = null): Filmx
val cookieJar = session.baseClient.cookieJar.loadForRequest(cookieUrl.toHttpUrl())
phpsessid = cookieJar.first { it.name == "PHPSESSID" }.value
val wLog = cookieJar.first { it.name == "wordpress_logged_in_8bf9d5433ac88cc9a3a396d6b154cd01" }.value
val wLog =
cookieJar.first { it.name == "wordpress_logged_in_8bf9d5433ac88cc9a3a396d6b154cd01" }.value
val wSec = cookieJar.first { it.name == "wordpress_sec_8bf9d5433ac88cc9a3a396d6b154cd01" }.value
return FilmxyCookies(phpsessid, wLog, wSec)
@ -1289,46 +1348,46 @@ data class Load(
@JsonProperty("data") val data: MediaDetail? = null,
)
data class FlixhqHeaders(
data class ConsumetHeaders(
@JsonProperty("Referer") val referer: String? = null,
)
data class FlixhqSubtitles(
data class ConsumetSubtitles(
@JsonProperty("url") val url: String? = null,
@JsonProperty("lang") val lang: String? = null,
)
data class FlixhqSources(
data class ConsumetSources(
@JsonProperty("url") val url: String? = null,
@JsonProperty("quality") val quality: String? = null,
@JsonProperty("isM3U8") val isM3U8: Boolean? = null,
)
data class FlixhqSourcesResponse(
@JsonProperty("headers") val headers: FlixhqHeaders? = null,
@JsonProperty("sources") val sources: ArrayList<FlixhqSources>? = arrayListOf(),
@JsonProperty("subtitles") val subtitles: ArrayList<FlixhqSubtitles>? = arrayListOf(),
data class ConsumetSourcesResponse(
@JsonProperty("headers") val headers: ConsumetHeaders? = null,
@JsonProperty("sources") val sources: ArrayList<ConsumetSources>? = arrayListOf(),
@JsonProperty("subtitles") val subtitles: ArrayList<ConsumetSubtitles>? = arrayListOf(),
)
data class FlixhqEpisodes(
data class ConsumetEpisodes(
@JsonProperty("id") val id: String? = null,
@JsonProperty("number") val number: Int? = null,
@JsonProperty("season") val season: Int? = null,
)
data class FlixhqDetails(
@JsonProperty("episodes") val episodes: ArrayList<FlixhqEpisodes>? = arrayListOf(),
data class ConsumetDetails(
@JsonProperty("episodes") val episodes: ArrayList<ConsumetEpisodes>? = arrayListOf(),
)
data class FlixhqResults(
data class ConsumetResults(
@JsonProperty("id") val id: String? = null,
@JsonProperty("title") val title: String? = null,
@JsonProperty("releaseDate") val releaseDate: String? = null,
@JsonProperty("type") val type: String? = null,
)
data class FlixhqSearchResponse(
@JsonProperty("results") val results: ArrayList<FlixhqResults>? = arrayListOf(),
data class ConsumetSearchResponse(
@JsonProperty("results") val results: ArrayList<ConsumetResults>? = arrayListOf(),
)
data class KisskhSources(
@ -1355,3 +1414,9 @@ data class KisskhResults(
@JsonProperty("title") val title: String?,
)
data class AnimixData(
@JsonProperty("title") val title: String? = null,
@JsonProperty("title_english") val title_english: String? = null,
@JsonProperty("title_japanese") val title_japanese: String? = null,
)

View file

@ -1,13 +1,11 @@
package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
import com.hexated.RandomUserAgent.getRandomUserAgent
import com.hexated.SoraExtractor.invoKisskh
import com.hexated.SoraExtractor.invoke123Movie
import com.hexated.SoraExtractor.invokeDbgo
import com.hexated.SoraExtractor.invokeFilmxy
import com.hexated.SoraExtractor.invokeFlixhq
import com.hexated.SoraExtractor.invokeGogo
import com.hexated.SoraExtractor.invokeHDMovieBox
import com.hexated.SoraExtractor.invokeIdlix
import com.hexated.SoraExtractor.invokeKimcartoon
@ -21,14 +19,12 @@ import com.hexated.SoraExtractor.invokeUniqueStream
import com.hexated.SoraExtractor.invokeVidSrc
import com.hexated.SoraExtractor.invokeXmovies
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.metaproviders.TmdbProvider
import com.hexated.SoraExtractor.invoZoro
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import kotlin.math.roundToInt
open class SoraStream : TmdbProvider() {
@ -48,6 +44,8 @@ open class SoraStream : TmdbProvider() {
companion object {
private const val tmdbAPI = "https://api.themoviedb.org/3"
private const val apiKey = "b030404650f279792a8d3287232358e3" // PLEASE DON'T STEAL
const val tmdb2mal = "https://tmdb2mal.slidemovies.org"
val mainAPI = base64DecodeAPI("cHA=LmE=ZWw=cmM=dmU=aC4=dGM=d2E=eHA=Ly8=czo=dHA=aHQ=")
var mainServerAPI =
base64DecodeAPI("cA==YXA=bC4=Y2U=ZXI=LnY=aWU=b3Y=LW0=cmE=c28=Ly8=czo=dHA=aHQ=")
@ -67,6 +65,7 @@ open class SoraStream : TmdbProvider() {
const val kimcartoonAPI = "https://kimcartoon.li"
const val xMovieAPI = "https://xemovies.net"
const val consumetFlixhqAPI = "https://api.consumet.org/movies/flixhq"
const val consumetZoroAPI = "https://api.consumet.org/anime/zoro"
const val kissKhAPI = "https://kisskh.me"
fun getType(t: String?): TvType {
@ -157,17 +156,6 @@ open class SoraStream : TmdbProvider() {
}
}
private fun Anime.toSearchResponse(): AnimeSearchResponse? {
return newAnimeSearchResponse(
title?.romaji ?: title?.english ?: title?.native ?: title?.userPreferred ?: return null,
Data(aniId = id, malId = malId).toJson(),
TvType.Anime
) {
this.posterUrl = image
addSub(totalEpisodes)
}
}
override suspend fun search(query: String): List<SearchResponse> {
val searchResponse = mutableListOf<SearchResponse>()
@ -179,51 +167,12 @@ open class SoraStream : TmdbProvider() {
}
if (mainResponse?.isNotEmpty() == true) searchResponse.addAll(mainResponse)
// val animeResponse =
// app.get("$mainServerAPI/search/anime/$query?_data=routes/search/anime/\$animeKeyword")
// .parsedSafe<SearchAnime>()?.searchResults?.results?.mapNotNull { anime -> anime.toSearchResponse() }
// if (animeResponse?.isNotEmpty() == true) searchResponse.addAll(animeResponse)
return searchResponse
}
private suspend fun loadAnime(aniId: String? = null, malId: Int? = null): LoadResponse? {
val res = app.get("$mainServerAPI/anime/$aniId/overview?_data=routes/anime/\$animeId")
.parsedSafe<DetailAnimeResult>()?.detail ?: throw ErrorLoadingException()
val episodes = res.episodes?.map { eps ->
Episode(
LinkData(aniId = aniId, animeId = eps.id).toJson(),
name = eps.title,
episode = eps.number
)
}
return newAnimeLoadResponse(
res.title?.romaji ?: res.title?.english ?: res.title?.native ?: res.title?.userPreferred
?: return null,
"",
TvType.Anime
) {
posterUrl = res.image
this.year = res.releaseDate
plot = res.description
this.tags = res.genres
this.recommendations = res.recommendations?.mapNotNull { it.toSearchResponse() }
addMalId(malId)
addAniListId(aniId?.toIntOrNull())
addEpisodes(DubStatus.Subbed, episodes)
}
}
override suspend fun load(url: String): LoadResponse? {
val data = parseJson<Data>(url)
if (data.aniId?.isNotEmpty() == true) {
return loadAnime(data.aniId, data.malId)
}
val buildId =
app.get("$mainAPI/").text.substringAfterLast("\"buildId\":\"").substringBefore("\",")
val responses =
@ -327,16 +276,16 @@ open class SoraStream : TmdbProvider() {
): Boolean {
val res = parseJson<LinkData>(data)
val query = if (res.type == "tv") {
"$mainServerAPI/tv-shows/${res.id}/season/${res.season}/episode/${res.episode}?_data=routes/tv-shows/\$tvId.season.\$seasonId.episode.\$episodeId"
} else {
"$mainServerAPI/movies/${res.id}/watch?_data=routes/movies/\$movieId.watch"
}
val referer = if (res.type == "tv") {
"$mainServerAPI/tv-shows/${res.id}/season/${res.season}/episode/${res.episode}"
} else {
"$mainServerAPI/movies/${res.id}/watch"
}
// val query = if (res.type == "tv") {
// "$mainServerAPI/tv-shows/${res.id}/season/${res.season}/episode/${res.episode}?_data=routes/tv-shows/\$tvId.season.\$seasonId.episode.\$episodeId"
// } else {
// "$mainServerAPI/movies/${res.id}/watch?_data=routes/movies/\$movieId.watch"
// }
// val referer = if (res.type == "tv") {
// "$mainServerAPI/tv-shows/${res.id}/season/${res.season}/episode/${res.episode}"
// } else {
// "$mainServerAPI/movies/${res.id}/watch"
// }
argamap(
{
@ -349,35 +298,35 @@ open class SoraStream : TmdbProvider() {
callback
)
},
{
val json = app.get(
query,
referer = referer,
headers = mapOf("User-Agent" to getRandomUserAgent())
).parsedSafe<LoadLinks>()
json?.sources?.map { source ->
callback.invoke(
ExtractorLink(
this.name,
this.name,
source.url ?: return@map null,
"$mainServerAPI/",
source.quality?.toIntOrNull() ?: Qualities.Unknown.value,
isM3u8 = source.isM3U8,
headers = mapOf("Origin" to mainServerAPI)
)
)
}
json?.subtitles?.map { sub ->
subtitleCallback.invoke(
SubtitleFile(
getLanguage(sub.lang.toString()),
sub.url ?: return@map null
)
)
}
},
// {
// val json = app.get(
// query,
// referer = referer,
// headers = mapOf("User-Agent" to getRandomUserAgent())
// ).parsedSafe<LoadLinks>()
//
// json?.sources?.map { source ->
// callback.invoke(
// ExtractorLink(
// this.name,
// this.name,
// source.url ?: return@map null,
// "$mainServerAPI/",
// source.quality?.toIntOrNull() ?: Qualities.Unknown.value,
// isM3u8 = source.isM3U8,
// headers = mapOf("Origin" to mainServerAPI)
// )
// )
// }
// json?.subtitles?.map { sub ->
// subtitleCallback.invoke(
// SubtitleFile(
// getLanguage(sub.lang.toString()),
// sub.url ?: return@map null
// )
// )
// }
// },
{
invokeTwoEmbed(res.id, res.season, res.episode, subtitleCallback, callback)
},
@ -413,9 +362,11 @@ open class SoraStream : TmdbProvider() {
// )
// },
{
if (res.aniId?.isNotEmpty() == true) invokeGogo(
res.aniId,
res.animeId,
if (res.season != null) invoZoro(
res.id,
res.season,
res.episode,
subtitleCallback,
callback
)
},
@ -505,16 +456,6 @@ open class SoraStream : TmdbProvider() {
@JsonProperty("subtitles") val subtitles: ArrayList<Subtitles>? = arrayListOf(),
)
data class SourcesVIP(
@JsonProperty("url") val url: String? = null,
@JsonProperty("quality") val quality: Int? = null,
)
data class LoadVIPLinks(
@JsonProperty("sources") val sources: ArrayList<SourcesVIP>? = arrayListOf(),
@JsonProperty("subtitles") val subtitles: ArrayList<Subtitles>? = arrayListOf(),
)
data class Results(
@JsonProperty("results") val results: ArrayList<Media>? = arrayListOf(),
)
@ -610,81 +551,6 @@ open class SoraStream : TmdbProvider() {
@JsonProperty("tracks") val tracks: List<String>? = null,
)
data class TitleAnime(
@JsonProperty("romaji") val romaji: String? = null,
@JsonProperty("english") val english: String? = null,
@JsonProperty("native") val native: String? = null,
@JsonProperty("userPreferred") val userPreferred: String? = null,
)
data class Anime(
@JsonProperty("title") val title: TitleAnime? = null,
@JsonProperty("id") val id: String? = null,
@JsonProperty("malId") val malId: Int? = null,
@JsonProperty("image") val image: String? = null,
@JsonProperty("totalEpisodes") val totalEpisodes: Int? = null,
)
data class SearchResults(
@JsonProperty("results") val results: ArrayList<Anime>? = null,
)
data class SearchAnime(
@JsonProperty("searchResults") val searchResults: SearchResults? = null,
)
data class TrailerAnime(
@JsonProperty("id") val id: String? = null,
)
data class EpisodesAnime(
@JsonProperty("id") val id: String? = null,
@JsonProperty("title") val title: String? = null,
@JsonProperty("number") val number: Int? = null,
)
data class DetailAnime(
@JsonProperty("title") val title: TitleAnime? = null,
@JsonProperty("id") val aniId: String? = null,
@JsonProperty("malId") val malId: Int? = null,
@JsonProperty("image") val image: String? = null,
@JsonProperty("description") val description: String? = null,
@JsonProperty("releaseDate") val releaseDate: Int? = null,
@JsonProperty("rating") val rating: Int? = null,
@JsonProperty("duration") val duration: Int? = null,
@JsonProperty("type") val type: String? = null,
@JsonProperty("recommendations") val recommendations: ArrayList<Anime>? = arrayListOf(),
@JsonProperty("episodes") val episodes: ArrayList<EpisodesAnime>? = arrayListOf(),
@JsonProperty("genres") val genres: ArrayList<String>? = arrayListOf(),
@JsonProperty("trailer") val trailer: TrailerAnime? = null,
)
data class DetailAnimeResult(
@JsonProperty("detail") val detail: DetailAnime? = null,
)
data class SeasonsVip(
@JsonProperty("air_date") val air_date: String? = null,
@JsonProperty("season_number") val season_number: Int? = null,
)
data class DataVip(
@JsonProperty("id") val id: String? = null,
)
data class DetailVipResult(
@JsonProperty("data") val data: DataVip? = null,
)
data class Providers(
@JsonProperty("id") val id: String? = null,
@JsonProperty("provider") val provider: String? = null,
)
data class ProvidersResult(
@JsonProperty("provider") val provider: ArrayList<Providers>? = arrayListOf(),
)
data class MovieHabData(
@JsonProperty("link") val link: String? = null,
@JsonProperty("token") val token: String? = null,