fixed SoraVIP

This commit is contained in:
hexated 2022-11-04 22:54:25 +07:00
parent 0af97ed6b4
commit 657cd57e3c
3 changed files with 99 additions and 80 deletions

View File

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

View File

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

View File

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