mirror of
https://github.com/hexated/cloudstream-extensions-hexated.git
synced 2024-08-15 00:03:22 +00:00
added Anime support in SoraStream
This commit is contained in:
parent
eee78d4b67
commit
00532d061e
3 changed files with 176 additions and 3 deletions
|
@ -1,5 +1,5 @@
|
|||
// use an integer for version numbers
|
||||
version = 8
|
||||
version = 9
|
||||
|
||||
|
||||
cloudstream {
|
||||
|
|
|
@ -261,6 +261,42 @@ object SoraExtractor : SoraStream() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// suspend fun invokeOpenvids(
|
||||
// id: Int? = null,
|
||||
// season: Int? = null,
|
||||
// episode: Int? = null,
|
||||
// subtitleCallback: (SubtitleFile) -> Unit,
|
||||
// callback: (ExtractorLink) -> Unit
|
||||
// ) {
|
||||
//
|
||||
// }
|
||||
|
||||
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)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun getQuality(str: String): Int {
|
||||
|
@ -343,3 +379,13 @@ private data class MovieHabData(
|
|||
private data class MovieHabRes(
|
||||
@JsonProperty("data") val data: MovieHabData? = null,
|
||||
)
|
||||
|
||||
private data class Sources(
|
||||
@JsonProperty("url") val url: String? = null,
|
||||
@JsonProperty("quality") val quality: String? = null,
|
||||
@JsonProperty("isM3U8") val isM3U8: Boolean = true,
|
||||
)
|
||||
|
||||
private data class LoadLinks(
|
||||
@JsonProperty("sources") val sources: ArrayList<Sources>? = arrayListOf(),
|
||||
)
|
|
@ -4,12 +4,15 @@ import com.fasterxml.jackson.annotation.JsonProperty
|
|||
import com.hexated.RandomUserAgent.getRandomUserAgent
|
||||
import com.hexated.SoraExtractor.invoke123Movie
|
||||
import com.hexated.SoraExtractor.invokeDbgo
|
||||
import com.hexated.SoraExtractor.invokeGogo
|
||||
import com.hexated.SoraExtractor.invokeLocalSources
|
||||
import com.hexated.SoraExtractor.invokeMovieHab
|
||||
import com.hexated.SoraExtractor.invokeOlgply
|
||||
import com.hexated.SoraExtractor.invokeTwoEmbed
|
||||
import com.hexated.SoraExtractor.invokeVidSrc
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
|
||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
|
||||
import com.lagradost.cloudstream3.metaproviders.TmdbProvider
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
||||
|
@ -106,17 +109,74 @@ 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> {
|
||||
return app.get(
|
||||
val searchResponse = mutableListOf<SearchResponse>()
|
||||
|
||||
val mainResponse = app.get(
|
||||
"$tmdbAPI/search/multi?api_key=$apiKey&language=en-US&query=$query&page=1&include_adult=false",
|
||||
referer = "$mainAPI/"
|
||||
).parsedSafe<Results>()?.results?.mapNotNull { media ->
|
||||
media.toSearchResponse()
|
||||
} ?: throw ErrorLoadingException("Invalid Json reponse")
|
||||
searchResponse.addAll(mainResponse)
|
||||
|
||||
val animeResponse =
|
||||
app.get("$mainServerAPI/search/anime/$query?_data=routes/search/anime/\$animeKeyword")
|
||||
.parsedSafe<SearchAnime>()?.searchResults?.results?.mapNotNull { anime -> anime.toSearchResponse() }
|
||||
?: throw ErrorLoadingException("Invalid Json reponse")
|
||||
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 =
|
||||
|
@ -265,10 +325,20 @@ open class SoraStream : TmdbProvider() {
|
|||
invokeDbgo(res.imdbId, res.season, res.episode, subtitleCallback, callback)
|
||||
},
|
||||
{
|
||||
invoke123Movie(res.id, res.imdbId, res.season, res.episode, subtitleCallback, callback)
|
||||
invoke123Movie(
|
||||
res.id,
|
||||
res.imdbId,
|
||||
res.season,
|
||||
res.episode,
|
||||
subtitleCallback,
|
||||
callback
|
||||
)
|
||||
},
|
||||
{
|
||||
invokeMovieHab(res.id, res.season, res.episode, subtitleCallback, callback)
|
||||
},
|
||||
{
|
||||
invokeGogo(res.aniId, res.animeId, callback)
|
||||
})
|
||||
|
||||
|
||||
|
@ -282,11 +352,15 @@ open class SoraStream : TmdbProvider() {
|
|||
val type: String? = null,
|
||||
val season: Int? = null,
|
||||
val episode: Int? = null,
|
||||
val aniId: String? = null,
|
||||
val animeId: String? = null,
|
||||
)
|
||||
|
||||
data class Data(
|
||||
val id: Int? = null,
|
||||
val type: String? = null,
|
||||
val aniId: String? = null,
|
||||
val malId: Int? = null,
|
||||
)
|
||||
|
||||
data class Subtitles(
|
||||
|
@ -388,4 +462,57 @@ 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,
|
||||
)
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue