mirror of
https://github.com/hexated/cloudstream-extensions-hexated.git
synced 2024-08-15 00:03:22 +00:00
fixed SoraVIP
This commit is contained in:
parent
0af97ed6b4
commit
657cd57e3c
3 changed files with 99 additions and 80 deletions
|
@ -1,5 +1,5 @@
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 22
|
version = 23
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
cloudstream {
|
||||||
|
|
|
@ -302,45 +302,30 @@ object SoraExtractor : SoraStream() {
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun invokeSoraVIP(
|
suspend fun invokeSoraVIP(
|
||||||
id: Int? = null,
|
title: String? = null,
|
||||||
|
orgTitle: String? = null,
|
||||||
|
year: Int? = null,
|
||||||
season: Int? = null,
|
season: Int? = null,
|
||||||
episode: Int? = null,
|
episode: Int? = null,
|
||||||
subtitleCallback: (SubtitleFile) -> Unit,
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
callback: (ExtractorLink) -> Unit
|
callback: (ExtractorLink) -> Unit
|
||||||
) {
|
) {
|
||||||
|
val apiUrl = base64DecodeAPI("aQ==YXA=cC8=YXA=bC4=Y2U=ZXI=LnY=b2s=a2w=bG8=Ly8=czo=dHA=aHQ=")
|
||||||
val url = if(season == null) {
|
val url = if(season == null) {
|
||||||
"$mainServerAPI/movies/$id/?_data=routes/movies/\$movieId"
|
"$apiUrl/search/one?title=$title&orgTitle=$orgTitle&year=$year"
|
||||||
} else {
|
} else {
|
||||||
"$mainServerAPI/tv-shows/$id/?_data=routes/tv-shows/\$tvId"
|
"$apiUrl/search/one?title=$title&orgTitle=$orgTitle&year=$year&season=$season"
|
||||||
}
|
|
||||||
val data = app.get(url).parsedSafe<DetailVipResult>()?.detail
|
|
||||||
val title = data?.title ?: data?.name
|
|
||||||
val origTitle = data?.original_title ?: data?.original_name
|
|
||||||
val providerId = if (season == null) {
|
|
||||||
val airDate = (data?.release_date ?: data?.first_air_date)?.substringBefore("-")
|
|
||||||
app.get(
|
|
||||||
"$mainServerAPI/api/provider?title=$title&type=movie&origTitle=$origTitle&year=$airDate&_data=routes/api/provider"
|
|
||||||
)
|
|
||||||
.parsedSafe<ProvidersResult>()?.provider?.first { it.provider == "Loklok" }?.id
|
|
||||||
|
|
||||||
} else {
|
|
||||||
val airDate = data?.seasons?.first { it.season_number == season }?.air_date?.substringBefore("-")
|
|
||||||
app.get(
|
|
||||||
"$mainServerAPI/api/provider?title=$title&type=tv&origTitle=$origTitle&year=$airDate&season=$season&_data=routes/api/provider"
|
|
||||||
)
|
|
||||||
.parsedSafe<ProvidersResult>()?.provider?.first { it.provider == "Loklok" }?.id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val query = if (season == null) {
|
val id = app.get(url).parsedSafe<DetailVipResult>()?.data?.id
|
||||||
"$mainServerAPI/movies/$id/watch?provider=Loklok&id=$providerId&_data=routes/movies/\$movieId.watch"
|
|
||||||
|
val sourcesUrl = if(season == null) {
|
||||||
|
"$apiUrl/movie/detail?id=$id"
|
||||||
} else {
|
} else {
|
||||||
"$mainServerAPI/tv-shows/$id/season/$season/episode/$episode?provider=Loklok&id=$providerId&_data=routes/tv-shows/\$tvId.season.\$seasonId.episode.\$episodeId"
|
"$apiUrl/tv/detail?id=$id&episodeId=${episode?.minus(1)}"
|
||||||
}
|
}
|
||||||
|
|
||||||
val json = app.get(
|
val json = app.get(sourcesUrl).parsedSafe<LoadVIPLinks>()
|
||||||
query,
|
|
||||||
headers = mapOf("User-Agent" to RandomUserAgent.getRandomUserAgent())
|
|
||||||
).parsedSafe<LoadLinks>()
|
|
||||||
|
|
||||||
json?.sources?.map { source ->
|
json?.sources?.map { source ->
|
||||||
callback.invoke(
|
callback.invoke(
|
||||||
|
@ -348,10 +333,9 @@ object SoraExtractor : SoraStream() {
|
||||||
"${this.name} (VIP)",
|
"${this.name} (VIP)",
|
||||||
"${this.name} (VIP)",
|
"${this.name} (VIP)",
|
||||||
source.url ?: return@map null,
|
source.url ?: return@map null,
|
||||||
"$mainServerAPI/",
|
"$apiUrl/",
|
||||||
source.quality?.toIntOrNull() ?: Qualities.Unknown.value,
|
source.quality ?: Qualities.Unknown.value,
|
||||||
isM3u8 = source.isM3U8,
|
isM3u8 = source.url.contains(".m3u8"),
|
||||||
headers = mapOf("Origin" to mainServerAPI)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -359,7 +343,7 @@ object SoraExtractor : SoraStream() {
|
||||||
json?.subtitles?.map { sub ->
|
json?.subtitles?.map { sub ->
|
||||||
subtitleCallback.invoke(
|
subtitleCallback.invoke(
|
||||||
SubtitleFile(
|
SubtitleFile(
|
||||||
getLanguage(sub.lang.toString()),
|
getLanguage(sub.language.toString()),
|
||||||
sub.url ?: return@map null
|
sub.url ?: return@map null
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -35,6 +35,7 @@ open class SoraStream : TmdbProvider() {
|
||||||
override val hasDownloadSupport = true
|
override val hasDownloadSupport = true
|
||||||
override val instantLinkLoading = true
|
override val instantLinkLoading = true
|
||||||
override val useMetaLoadResponse = true
|
override val useMetaLoadResponse = true
|
||||||
|
override val hasChromecastSupport = true
|
||||||
override val supportedTypes = setOf(
|
override val supportedTypes = setOf(
|
||||||
TvType.Movie,
|
TvType.Movie,
|
||||||
TvType.TvSeries,
|
TvType.TvSeries,
|
||||||
|
@ -83,14 +84,15 @@ open class SoraStream : TmdbProvider() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun base64DecodeAPI(api: String): String {
|
fun base64DecodeAPI(api: String): String {
|
||||||
return api.chunked(4).map { base64Decode(it) }.reversed().joinToString("")
|
return api.chunked(4).map { base64Decode(it) }.reversed().joinToString("")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun checkMainServer() {
|
private suspend fun checkMainServer() {
|
||||||
val check = app.get(mainServerAPI)
|
val check = app.get(mainServerAPI)
|
||||||
mainServerAPI = if(check.isSuccessful) {
|
mainServerAPI = if (check.isSuccessful) {
|
||||||
mainServerAPI
|
mainServerAPI
|
||||||
} else {
|
} else {
|
||||||
base64DecodeAPI("cHA=LmE=ZWw=cmM=dmU=Ny4=bjQ=cmE=aHQ=YW4=a2g=ZS0=dmk=bW8=eC0=bWk=cmU=Ly8=czo=dHA=aHQ=")
|
base64DecodeAPI("cHA=LmE=ZWw=cmM=dmU=Ny4=bjQ=cmE=aHQ=YW4=a2g=ZS0=dmk=bW8=eC0=bWk=cmU=Ly8=czo=dHA=aHQ=")
|
||||||
|
@ -128,7 +130,7 @@ open class SoraStream : TmdbProvider() {
|
||||||
page: Int,
|
page: Int,
|
||||||
request: MainPageRequest
|
request: MainPageRequest
|
||||||
): HomePageResponse {
|
): HomePageResponse {
|
||||||
checkMainServer()
|
// checkMainServer()
|
||||||
val type = if (request.data.contains("/movie")) "movie" else "tv"
|
val type = if (request.data.contains("/movie")) "movie" else "tv"
|
||||||
val home = app.get(request.data + page)
|
val home = app.get(request.data + page)
|
||||||
.parsedSafe<Results>()?.results
|
.parsedSafe<Results>()?.results
|
||||||
|
@ -168,12 +170,12 @@ open class SoraStream : TmdbProvider() {
|
||||||
).parsedSafe<Results>()?.results?.mapNotNull { media ->
|
).parsedSafe<Results>()?.results?.mapNotNull { media ->
|
||||||
media.toSearchResponse()
|
media.toSearchResponse()
|
||||||
}
|
}
|
||||||
if(mainResponse?.isNotEmpty() == true) searchResponse.addAll(mainResponse)
|
if (mainResponse?.isNotEmpty() == true) searchResponse.addAll(mainResponse)
|
||||||
|
|
||||||
val animeResponse =
|
// val animeResponse =
|
||||||
app.get("$mainServerAPI/search/anime/$query?_data=routes/search/anime/\$animeKeyword")
|
// app.get("$mainServerAPI/search/anime/$query?_data=routes/search/anime/\$animeKeyword")
|
||||||
.parsedSafe<SearchAnime>()?.searchResults?.results?.mapNotNull { anime -> anime.toSearchResponse() }
|
// .parsedSafe<SearchAnime>()?.searchResults?.results?.mapNotNull { anime -> anime.toSearchResponse() }
|
||||||
if(animeResponse?.isNotEmpty() == true) searchResponse.addAll(animeResponse)
|
// if (animeResponse?.isNotEmpty() == true) searchResponse.addAll(animeResponse)
|
||||||
|
|
||||||
return searchResponse
|
return searchResponse
|
||||||
}
|
}
|
||||||
|
@ -222,9 +224,11 @@ open class SoraStream : TmdbProvider() {
|
||||||
.parsedSafe<Detail>()?.pageProps
|
.parsedSafe<Detail>()?.pageProps
|
||||||
?: throw ErrorLoadingException("Invalid Json Response")
|
?: throw ErrorLoadingException("Invalid Json Response")
|
||||||
val res = responses.result ?: return null
|
val res = responses.result ?: return null
|
||||||
val title = res.title ?: res.name ?: res.originalTitle ?: res.originalName ?: return null
|
val title = res.title ?: res.name ?: return null
|
||||||
val year = (res.releaseDate ?: res.firstAirDate)?.split("-")?.first()?.toIntOrNull()
|
val orgTitle = res.originalTitle ?: res.originalName ?: return null
|
||||||
val type = getType(data.type)
|
val type = getType(data.type)
|
||||||
|
val year = (res.releaseDate ?: res.firstAirDate)?.split("-")?.first()?.toIntOrNull()
|
||||||
|
|
||||||
val actors = responses.cast?.mapNotNull { cast ->
|
val actors = responses.cast?.mapNotNull { cast ->
|
||||||
ActorData(
|
ActorData(
|
||||||
Actor(
|
Actor(
|
||||||
|
@ -254,7 +258,8 @@ open class SoraStream : TmdbProvider() {
|
||||||
eps.seasonNumber,
|
eps.seasonNumber,
|
||||||
eps.episodeNumber,
|
eps.episodeNumber,
|
||||||
title = title,
|
title = title,
|
||||||
year = year,
|
year = season.airDate?.split("-")?.first()?.toIntOrNull(),
|
||||||
|
orgTitle = orgTitle,
|
||||||
).toJson(),
|
).toJson(),
|
||||||
name = eps.name,
|
name = eps.name,
|
||||||
season = eps.seasonNumber,
|
season = eps.seasonNumber,
|
||||||
|
@ -293,6 +298,7 @@ open class SoraStream : TmdbProvider() {
|
||||||
data.type,
|
data.type,
|
||||||
title = title,
|
title = title,
|
||||||
year = year,
|
year = year,
|
||||||
|
orgTitle = orgTitle,
|
||||||
).toJson(),
|
).toJson(),
|
||||||
) {
|
) {
|
||||||
this.posterUrl = getOriImageUrl(res.backdropPath)
|
this.posterUrl = getOriImageUrl(res.backdropPath)
|
||||||
|
@ -327,7 +333,15 @@ open class SoraStream : TmdbProvider() {
|
||||||
|
|
||||||
argamap(
|
argamap(
|
||||||
{
|
{
|
||||||
invokeSoraVIP(res.id, res.season, res.episode, subtitleCallback, callback)
|
invokeSoraVIP(
|
||||||
|
res.title,
|
||||||
|
res.orgTitle,
|
||||||
|
res.year,
|
||||||
|
res.season,
|
||||||
|
res.episode,
|
||||||
|
subtitleCallback,
|
||||||
|
callback
|
||||||
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
val json = app.get(
|
val json = app.get(
|
||||||
|
@ -336,30 +350,26 @@ open class SoraStream : TmdbProvider() {
|
||||||
headers = mapOf("User-Agent" to getRandomUserAgent())
|
headers = mapOf("User-Agent" to getRandomUserAgent())
|
||||||
).parsedSafe<LoadLinks>()
|
).parsedSafe<LoadLinks>()
|
||||||
|
|
||||||
if (json?.sources.isNullOrEmpty()) {
|
json?.sources?.map { source ->
|
||||||
invokeLocalSources(referer, subtitleCallback, callback)
|
callback.invoke(
|
||||||
} else {
|
ExtractorLink(
|
||||||
json?.sources?.map { source ->
|
this.name,
|
||||||
callback.invoke(
|
this.name,
|
||||||
ExtractorLink(
|
source.url ?: return@map null,
|
||||||
this.name,
|
"$mainServerAPI/",
|
||||||
this.name,
|
source.quality?.toIntOrNull() ?: Qualities.Unknown.value,
|
||||||
source.url ?: return@map null,
|
isM3u8 = source.isM3U8,
|
||||||
"$mainServerAPI/",
|
headers = mapOf("Origin" to mainServerAPI)
|
||||||
source.quality?.toIntOrNull() ?: Qualities.Unknown.value,
|
|
||||||
isM3u8 = source.isM3U8,
|
|
||||||
headers = mapOf("Origin" to mainServerAPI)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
json?.subtitles?.map { sub ->
|
}
|
||||||
subtitleCallback.invoke(
|
json?.subtitles?.map { sub ->
|
||||||
SubtitleFile(
|
subtitleCallback.invoke(
|
||||||
sub.lang.toString(),
|
SubtitleFile(
|
||||||
sub.url ?: return@map null
|
getLanguage(sub.lang.toString()),
|
||||||
)
|
sub.url ?: return@map null
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -397,7 +407,11 @@ open class SoraStream : TmdbProvider() {
|
||||||
// )
|
// )
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
if (res.aniId?.isNotEmpty() == true) invokeGogo(res.aniId, res.animeId, callback)
|
if (res.aniId?.isNotEmpty() == true) invokeGogo(
|
||||||
|
res.aniId,
|
||||||
|
res.animeId,
|
||||||
|
callback
|
||||||
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
invokeHDMovieBox(res.title, res.season, res.episode, callback)
|
invokeHDMovieBox(res.title, res.season, res.episode, callback)
|
||||||
|
@ -406,17 +420,31 @@ open class SoraStream : TmdbProvider() {
|
||||||
invokeSeries9(res.title, res.season, res.episode, subtitleCallback, callback)
|
invokeSeries9(res.title, res.season, res.episode, subtitleCallback, callback)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
invokeIdlix(res.title, res.year, res.season, res.episode, subtitleCallback, callback)
|
invokeIdlix(
|
||||||
|
res.title,
|
||||||
|
res.year,
|
||||||
|
res.season,
|
||||||
|
res.episode,
|
||||||
|
subtitleCallback,
|
||||||
|
callback
|
||||||
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
invokeNoverse(res.title, res.season, res.episode, callback)
|
invokeNoverse(res.title, res.season, res.episode, callback)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
invokeUniqueStream(res.title, res.year, res.season, res.episode, subtitleCallback, callback)
|
invokeUniqueStream(
|
||||||
|
res.title,
|
||||||
|
res.year,
|
||||||
|
res.season,
|
||||||
|
res.episode,
|
||||||
|
subtitleCallback,
|
||||||
|
callback
|
||||||
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
invokeFilmxy(res.imdbId, res.season, res.episode, subtitleCallback, callback)
|
invokeFilmxy(res.imdbId, res.season, res.episode, subtitleCallback, callback)
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@ -432,6 +460,7 @@ open class SoraStream : TmdbProvider() {
|
||||||
val animeId: String? = null,
|
val animeId: String? = null,
|
||||||
val title: String? = null,
|
val title: String? = null,
|
||||||
val year: Int? = null,
|
val year: Int? = null,
|
||||||
|
val orgTitle: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class Data(
|
data class Data(
|
||||||
|
@ -444,6 +473,7 @@ open class SoraStream : TmdbProvider() {
|
||||||
data class Subtitles(
|
data class Subtitles(
|
||||||
@JsonProperty("url") val url: String? = null,
|
@JsonProperty("url") val url: String? = null,
|
||||||
@JsonProperty("lang") val lang: String? = null,
|
@JsonProperty("lang") val lang: String? = null,
|
||||||
|
@JsonProperty("language") val language: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class Sources(
|
data class Sources(
|
||||||
|
@ -457,6 +487,16 @@ open class SoraStream : TmdbProvider() {
|
||||||
@JsonProperty("subtitles") val subtitles: ArrayList<Subtitles>? = arrayListOf(),
|
@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(
|
data class Results(
|
||||||
@JsonProperty("results") val results: ArrayList<Media>? = arrayListOf(),
|
@JsonProperty("results") val results: ArrayList<Media>? = arrayListOf(),
|
||||||
)
|
)
|
||||||
|
@ -479,6 +519,7 @@ open class SoraStream : TmdbProvider() {
|
||||||
@JsonProperty("id") val id: Int? = null,
|
@JsonProperty("id") val id: Int? = null,
|
||||||
@JsonProperty("name") val name: String? = null,
|
@JsonProperty("name") val name: String? = null,
|
||||||
@JsonProperty("season_number") val seasonNumber: Int? = null,
|
@JsonProperty("season_number") val seasonNumber: Int? = null,
|
||||||
|
@JsonProperty("air_date") val airDate: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class Cast(
|
data class Cast(
|
||||||
|
@ -609,18 +650,12 @@ open class SoraStream : TmdbProvider() {
|
||||||
@JsonProperty("season_number") val season_number: Int? = null,
|
@JsonProperty("season_number") val season_number: Int? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class DetailVip(
|
data class DataVip(
|
||||||
@JsonProperty("title") val title: String? = null,
|
@JsonProperty("id") val id: String? = null,
|
||||||
@JsonProperty("name") val name: String? = null,
|
|
||||||
@JsonProperty("original_title") val original_title: String? = null,
|
|
||||||
@JsonProperty("original_name") val original_name: String? = null,
|
|
||||||
@JsonProperty("release_date") val release_date: String? = null,
|
|
||||||
@JsonProperty("first_air_date") val first_air_date: String? = null,
|
|
||||||
@JsonProperty("seasons") val seasons: ArrayList<SeasonsVip>? = arrayListOf(),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
data class DetailVipResult(
|
data class DetailVipResult(
|
||||||
@JsonProperty("detail") val detail: DetailVip? = null,
|
@JsonProperty("data") val data: DataVip? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class Providers(
|
data class Providers(
|
||||||
|
|
Loading…
Reference in a new issue