added Anime support in SoraStream

This commit is contained in:
hexated 2022-10-20 04:46:22 +07:00
parent eee78d4b67
commit 00532d061e
3 changed files with 176 additions and 3 deletions

View File

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

View File

@ -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 { private fun getQuality(str: String): Int {
@ -342,4 +378,14 @@ private data class MovieHabData(
private data class MovieHabRes( private data class MovieHabRes(
@JsonProperty("data") val data: MovieHabData? = null, @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(),
) )

View File

@ -4,12 +4,15 @@ import com.fasterxml.jackson.annotation.JsonProperty
import com.hexated.RandomUserAgent.getRandomUserAgent import com.hexated.RandomUserAgent.getRandomUserAgent
import com.hexated.SoraExtractor.invoke123Movie import com.hexated.SoraExtractor.invoke123Movie
import com.hexated.SoraExtractor.invokeDbgo import com.hexated.SoraExtractor.invokeDbgo
import com.hexated.SoraExtractor.invokeGogo
import com.hexated.SoraExtractor.invokeLocalSources import com.hexated.SoraExtractor.invokeLocalSources
import com.hexated.SoraExtractor.invokeMovieHab import com.hexated.SoraExtractor.invokeMovieHab
import com.hexated.SoraExtractor.invokeOlgply import com.hexated.SoraExtractor.invokeOlgply
import com.hexated.SoraExtractor.invokeTwoEmbed import com.hexated.SoraExtractor.invokeTwoEmbed
import com.hexated.SoraExtractor.invokeVidSrc import com.hexated.SoraExtractor.invokeVidSrc
import com.lagradost.cloudstream3.* 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.metaproviders.TmdbProvider
import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.AppUtils.toJson 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> { 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", "$tmdbAPI/search/multi?api_key=$apiKey&language=en-US&query=$query&page=1&include_adult=false",
referer = "$mainAPI/" referer = "$mainAPI/"
).parsedSafe<Results>()?.results?.mapNotNull { media -> ).parsedSafe<Results>()?.results?.mapNotNull { media ->
media.toSearchResponse() media.toSearchResponse()
} ?: throw ErrorLoadingException("Invalid Json reponse") } ?: 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? { override suspend fun load(url: String): LoadResponse? {
val data = parseJson<Data>(url) val data = parseJson<Data>(url)
if (data.aniId?.isNotEmpty() == true) {
return loadAnime(data.aniId, data.malId)
}
val buildId = val buildId =
app.get("$mainAPI/").text.substringAfterLast("\"buildId\":\"").substringBefore("\",") app.get("$mainAPI/").text.substringAfterLast("\"buildId\":\"").substringBefore("\",")
val responses = val responses =
@ -265,10 +325,20 @@ open class SoraStream : TmdbProvider() {
invokeDbgo(res.imdbId, res.season, res.episode, subtitleCallback, callback) 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) 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 type: String? = null,
val season: Int? = null, val season: Int? = null,
val episode: Int? = null, val episode: Int? = null,
val aniId: String? = null,
val animeId: String? = null,
) )
data class Data( data class Data(
val id: Int? = null, val id: Int? = null,
val type: String? = null, val type: String? = null,
val aniId: String? = null,
val malId: Int? = null,
) )
data class Subtitles( data class Subtitles(
@ -388,4 +462,57 @@ open class SoraStream : TmdbProvider() {
@JsonProperty("tracks") val tracks: List<String>? = null, @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,
)
} }