sora: fix upcloud,vidcloud, aniwatch

This commit is contained in:
hexated 2023-07-24 01:05:02 +07:00
parent 39d5247101
commit f38a602b97
5 changed files with 38 additions and 27 deletions

View file

@ -1,7 +1,7 @@
import org.jetbrains.kotlin.konan.properties.Properties import org.jetbrains.kotlin.konan.properties.Properties
// use an integer for version numbers // use an integer for version numbers
version = 145 version = 146
android { android {
defaultConfig { defaultConfig {

View file

@ -930,7 +930,7 @@ object SoraExtractor : SoraStream() {
argamap( argamap(
{ {
invokeZoro(aniId, episode, subtitleCallback, callback) invokeAniwatch(malId, episode, subtitleCallback, callback)
}, },
{ {
invokeAnimeKaizoku(malId, epsTitle, season, episode, callback) invokeAnimeKaizoku(malId, epsTitle, season, episode, callback)
@ -1004,28 +1004,26 @@ object SoraExtractor : SoraStream() {
} }
private suspend fun invokeZoro( private suspend fun invokeAniwatch(
aniId: Int? = null, malId: Int? = null,
episode: Int? = null, episode: Int? = null,
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
) { ) {
val animeId =
app.get("https://raw.githubusercontent.com/MALSync/MAL-Sync-Backup/master/data/anilist/anime/${aniId ?: return}.json")
.parsedSafe<MALSyncResponses>()?.pages?.zoro?.keys?.map { it }
val headers = mapOf( val headers = mapOf(
"X-Requested-With" to "XMLHttpRequest", "X-Requested-With" to "XMLHttpRequest",
) )
val animeId = app.get("$malsyncAPI/mal/anime/${malId ?: return}").parsedSafe<MALSyncResponses>()?.sites?.zoro?.keys?.map { it }
animeId?.apmap { id -> animeId?.apmap { id ->
val episodeId = app.get("$zoroAPI/ajax/episode/list/${id ?: return@apmap}", headers = headers) val episodeId = app.get("$aniwatchAPI/ajax/v2/episode/list/${id ?: return@apmap}", headers = headers)
.parsedSafe<ZoroResponses>()?.html?.let { .parsedSafe<AniwatchResponses>()?.html?.let {
Jsoup.parse(it) Jsoup.parse(it)
}?.select("div.ss-list a")?.find { it.attr("data-number") == "${episode ?: 1}" } }?.select("div.ss-list a")?.find { it.attr("data-number") == "${episode ?: 1}" }
?.attr("data-id") ?.attr("data-id")
val servers = val servers =
app.get("$zoroAPI/ajax/episode/servers?episodeId=${episodeId ?: return@apmap}", headers = headers) app.get("$aniwatchAPI/ajax/v2/episode/servers?episodeId=${episodeId ?: return@apmap}", headers = headers)
.parsedSafe<ZoroResponses>()?.html?.let { Jsoup.parse(it) } .parsedSafe<AniwatchResponses>()?.html?.let { Jsoup.parse(it) }
?.select("div.item.server-item")?.map { ?.select("div.item.server-item")?.map {
Triple( Triple(
it.text(), it.text(),
@ -1035,22 +1033,21 @@ object SoraExtractor : SoraStream() {
} }
servers?.apmap servers@{ server -> servers?.apmap servers@{ server ->
val iframe = val iframe = app.get("$aniwatchAPI/ajax/v2/episode/sources?id=${server.second ?: return@servers}", headers = headers)
app.get("$zoroAPI/ajax/episode/sources?id=${server.second ?: return@servers}", headers = headers) .parsedSafe<AniwatchResponses>()?.link ?: return@servers
.parsedSafe<ZoroResponses>()?.link ?: return@servers
val audio = if (server.third == "sub") "Raw" else "English Dub" val audio = if (server.third == "sub") "Raw" else "English Dub"
if (server.first.contains(Regex("Vidstreaming|MegaCloud|Vidcloud"))) { if (server.first.contains(Regex("Vidstreaming|MegaCloud|Vidcloud"))) {
extractRabbitStream( extractRabbitStream(
"${server.first} [$audio]", "${server.first} [$audio]",
iframe, iframe,
"$zoroAPI/", "$aniwatchAPI/",
subtitleCallback, subtitleCallback,
callback, callback,
false, false,
decryptKey = RabbitStream.getZoroKey() decryptKey = RabbitStream.getZoroKey()
) { it } ) { it }
} else { } else {
loadExtractor(iframe, "$zoroAPI/", subtitleCallback, callback) loadExtractor(iframe, "$aniwatchAPI/", subtitleCallback, callback)
} }
} }

View file

@ -405,15 +405,15 @@ data class CrunchyrollSourcesResponses(
@JsonProperty("meta") val meta: CrunchyrollMeta? = null, @JsonProperty("meta") val meta: CrunchyrollMeta? = null,
) )
data class MALSyncPages( data class MALSyncSites(
@JsonProperty("Zoro") val zoro: HashMap<String?, HashMap<String, String?>>? = hashMapOf(), @JsonProperty("Zoro") val zoro: HashMap<String?, HashMap<String, String?>>? = hashMapOf(),
) )
data class MALSyncResponses( data class MALSyncResponses(
@JsonProperty("Pages") val pages: MALSyncPages? = null, @JsonProperty("Sites") val sites: MALSyncSites? = null,
) )
data class ZoroResponses( data class AniwatchResponses(
@JsonProperty("html") val html: String? = null, @JsonProperty("html") val html: String? = null,
@JsonProperty("link") val link: String? = null, @JsonProperty("link") val link: String? = null,
) )

View file

@ -16,7 +16,6 @@ import com.hexated.SoraExtractor.invokeMovieHab
import com.hexated.SoraExtractor.invokeNoverse import com.hexated.SoraExtractor.invokeNoverse
import com.hexated.SoraExtractor.invokeSeries9 import com.hexated.SoraExtractor.invokeSeries9
import com.hexated.SoraExtractor.invokeVidSrc import com.hexated.SoraExtractor.invokeVidSrc
import com.hexated.SoraExtractor.invokeXmovies
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.metaproviders.TmdbProvider import com.lagradost.cloudstream3.metaproviders.TmdbProvider
@ -100,7 +99,7 @@ open class SoraStream : TmdbProvider() {
const val filmxyAPI = "https://www.filmxy.vip" const val filmxyAPI = "https://www.filmxy.vip"
const val kimcartoonAPI = "https://kimcartoon.li" const val kimcartoonAPI = "https://kimcartoon.li"
const val xMovieAPI = "https://xemovies.to" const val xMovieAPI = "https://xemovies.to"
const val zoroAPI = "https://kaido.to" const val aniwatchAPI = "https://aniwatch.to"
const val crunchyrollAPI = "https://beta-api.crunchyroll.com" const val crunchyrollAPI = "https://beta-api.crunchyroll.com"
const val kissKhAPI = "https://kisskh.co" const val kissKhAPI = "https://kisskh.co"
const val lingAPI = "https://ling-online.net" const val lingAPI = "https://ling-online.net"

View file

@ -21,6 +21,7 @@ import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.APIHolder.unixTimeMS
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.AppUtils.toJson import com.lagradost.cloudstream3.utils.AppUtils.toJson
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
@ -578,7 +579,7 @@ suspend fun invokeSmashyIm(
Regex("['\"]?subtitle['\"]?:\\s*\"([^\"]+)").find(script)?.groupValues?.get(1) ?: return Regex("['\"]?subtitle['\"]?:\\s*\"([^\"]+)").find(script)?.groupValues?.get(1) ?: return
M3u8Helper.generateM3u8( M3u8Helper.generateM3u8(
name, "Smashy [$name]",
sources, sources,
"" ""
).forEach(callback) ).forEach(callback)
@ -955,7 +956,7 @@ suspend fun searchWatchOnline(
} }
//modified code from https://github.com/jmir1/aniyomi-extensions/blob/master/src/all/kamyroll/src/eu/kanade/tachiyomi/animeextension/all/kamyroll/AccessTokenInterceptor.kt //modified code from https://github.com/jmir1/aniyomi-extensions/blob/master/src/all/kamyroll/src/eu/kanade/tachiyomi/animeextension/all/kamyroll/AccessTokenInterceptor.kt
fun getCrunchyrollToken(): Map<String, String> { suspend fun getCrunchyrollToken(): Map<String, String> {
val client = app.baseClient.newBuilder() val client = app.baseClient.newBuilder()
.proxy(Proxy(Proxy.Type.SOCKS, InetSocketAddress("cr-unblocker.us.to", 1080))) .proxy(Proxy(Proxy.Type.SOCKS, InetSocketAddress("cr-unblocker.us.to", 1080)))
.build() .build()
@ -975,7 +976,7 @@ fun getCrunchyrollToken(): Map<String, String> {
"Authorization" to "Basic ${BuildConfig.CRUNCHYROLL_BASIC_TOKEN}" "Authorization" to "Basic ${BuildConfig.CRUNCHYROLL_BASIC_TOKEN}"
), ),
data = mapOf( data = mapOf(
"refresh_token" to BuildConfig.CRUNCHYROLL_REFRESH_TOKEN, "refresh_token" to app.get(BuildConfig.CRUNCHYROLL_REFRESH_TOKEN).text,
"grant_type" to "refresh_token", "grant_type" to "refresh_token",
"scope" to "offline_access" "scope" to "offline_access"
) )
@ -1840,8 +1841,8 @@ object RabbitStream {
if (sources == null || encryptedMap.encrypted == false) { if (sources == null || encryptedMap.encrypted == false) {
response.parsedSafe() response.parsedSafe()
} else { } else {
val decrypted = val (realKey, encData) = extractRealKey(sources, decryptKey)
decryptMapped<List<Sources>>(sources, decryptKey) val decrypted = decryptMapped<List<Sources>>(encData, realKey)
SourceObject( SourceObject(
sources = decrypted, sources = decrypted,
tracks = encryptedMap.tracks tracks = encryptedMap.tracks
@ -1984,7 +1985,21 @@ object RabbitStream {
} }
suspend fun getZoroKey(): String { suspend fun getZoroKey(): String {
return app.get("https://raw.githubusercontent.com/enimax-anime/key/e0/key.txt").text return app.get("https://raw.githubusercontent.com/enimax-anime/key/e6/key.txt").text
}
private fun extractRealKey(originalString: String?, stops: String) : Pair<String,String> {
val table = parseJson<List<List<Int>>>(stops)
val decryptedKey = StringBuilder()
var offset = 0
var encryptedString = originalString
table.forEach { (start, end) ->
decryptedKey.append(encryptedString?.substring(start - offset, end - offset))
encryptedString = encryptedString?.substring(0, start - offset) + encryptedString?.substring(end - offset)
offset += end - start
}
return decryptedKey.toString() to encryptedString.toString()
} }
private inline fun <reified T> decryptMapped(input: String, key: String): T? { private inline fun <reified T> decryptMapped(input: String, key: String): T? {