sora: fix crunchy

This commit is contained in:
alex 2024-01-01 18:42:32 +07:00
parent 1e2f746676
commit aada4b49fe
6 changed files with 56 additions and 34 deletions

View file

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

View file

@ -217,9 +217,10 @@ class Samehadaku : MainAPI() {
}
private fun String.fixQuality() : Int {
return when(this) {
"MP4HD" -> Qualities.P720.value
return when(this.uppercase()) {
"4K" -> Qualities.P2160.value
"FULLHD" -> Qualities.P1080.value
"MP4HD" -> Qualities.P720.value
else -> this.filter { it.isDigit() }.toIntOrNull() ?: Qualities.Unknown.value
}
}

View file

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

View file

@ -1505,7 +1505,8 @@ object SoraExtractor : SoraStream() {
"en-US",
"zh-CN",
)
val headers = getCrunchyrollToken()
val token = getCrunchyrollToken()
val headers = mapOf("Authorization" to "${token.tokenType} ${token.accessToken}")
val seasonIdData = app.get(
"$crunchyrollAPI/content/v2/cms/series/${id ?: return}/seasons", headers = headers
).parsedSafe<CrunchyrollResponses>()?.data?.let { s ->
@ -1532,17 +1533,18 @@ object SoraExtractor : SoraStream() {
it.title.equals(epsTitle, true) || it.slug_title.equals(
epsTitle.createSlug(), true
) || it.episode_number == episode
}?.streams_link
val sources =
app.get(fixUrl(streamsLink ?: return@apmap, crunchyrollAPI), headers = headers)
.parsedSafe<CrunchyrollSourcesResponses>()
}?.streams_link?.substringAfter("/videos/")?.substringBefore("/streams") ?: return@apmap
val sources = app.get(
"$crunchyrollAPI/cms/v2${token.bucket}/videos/$streamsLink/streams?Policy=${token.policy}&Signature=${token.signature}&Key-Pair-Id=${token.key_pair_id}",
headers = headers
).parsedSafe<CrunchyrollSourcesResponses>()
listOf(
"adaptive_hls", "vo_adaptive_hls"
).map { hls ->
val name = if (hls == "adaptive_hls") "Crunchyroll" else "Vrv"
val audio = if (audioL == "en-US") "English Dub" else "Raw"
val source = sources?.data?.firstOrNull()?.let {
val source = sources?.streams?.let {
if (hls == "adaptive_hls") it.adaptive_hls else it.vo_adaptive_hls
}
M3u8Helper.generateM3u8(
@ -1552,7 +1554,7 @@ object SoraExtractor : SoraStream() {
).forEach(callback)
}
sources?.meta?.subtitles?.map { sub ->
sources?.subtitles?.map { sub ->
subtitleCallback.invoke(
SubtitleFile(
"${fixCrunchyrollLang(sub.key) ?: sub.key} [ass]",
@ -1560,8 +1562,6 @@ object SoraExtractor : SoraStream() {
)
)
}
}
}
@ -2135,7 +2135,7 @@ object SoraExtractor : SoraStream() {
media.third.substringAfterLast("/") to iframe.substringAfterLast("/")
.substringBefore("-")
}
val res = app.get(fixUrl(iframe, api))
val res = app.get(fixUrl(iframe, api), verify = false)
delay(2000)
val serverUrl = res.document.selectFirst("script:containsData(pushState)")?.data()?.let {
""",\s*'([^']+)""".toRegex().find(it)?.groupValues?.get(1)

View file

@ -2,6 +2,15 @@ package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty
data class CrunchyrollAccessToken(
val accessToken: String? = null,
val tokenType: String? = null,
val bucket: String? = null,
val policy: String? = null,
val signature: String? = null,
val key_pair_id: String? = null,
)
data class ShowboxMedia(
val url: String,
val title: String,
@ -207,12 +216,17 @@ data class AnilistResponses(
)
data class CrunchyrollToken(
@JsonProperty("access_token") val accessToken: String? = null,
@JsonProperty("expires_in") val expiresIn: Int? = null,
@JsonProperty("token_type") val tokenType: String? = null,
@JsonProperty("scope") val scope: String? = null,
@JsonProperty("country") val country: String? = null
)
@JsonProperty("access_token") val accessToken: String? = null,
@JsonProperty("token_type") val tokenType: String? = null,
@JsonProperty("cms") val cms: Cms? = null,
) {
data class Cms(
@JsonProperty("bucket") var bucket: String? = null,
@JsonProperty("policy") var policy: String? = null,
@JsonProperty("signature") var signature: String? = null,
@JsonProperty("key_pair_id") var key_pair_id: String? = null,
)
}
data class CrunchyrollVersions(
@JsonProperty("audio_locale") val audio_locale: String? = null,
@ -227,22 +241,21 @@ data class CrunchyrollData(
@JsonProperty("episode_number") val episode_number: Int? = null,
@JsonProperty("versions") val versions: ArrayList<CrunchyrollVersions>? = null,
@JsonProperty("streams_link") val streams_link: String? = null,
@JsonProperty("adaptive_hls") val adaptive_hls: HashMap<String, HashMap<String, String>>? = hashMapOf(),
@JsonProperty("vo_adaptive_hls") val vo_adaptive_hls: HashMap<String, HashMap<String, String>>? = hashMapOf(),
)
data class CrunchyrollResponses(
@JsonProperty("data") val data: ArrayList<CrunchyrollData>? = arrayListOf(),
)
data class CrunchyrollMeta(
@JsonProperty("subtitles") val subtitles: HashMap<String, HashMap<String, String>>? = hashMapOf(),
)
data class CrunchyrollSourcesResponses(
@JsonProperty("data") val data: ArrayList<CrunchyrollData>? = arrayListOf(),
@JsonProperty("meta") val meta: CrunchyrollMeta? = null,
)
@JsonProperty("streams") val streams: Streams? = Streams(),
@JsonProperty("subtitles") val subtitles: HashMap<String, HashMap<String, String>>? = hashMapOf(),
) {
data class Streams(
@JsonProperty("adaptive_hls") val adaptive_hls: HashMap<String, HashMap<String, String>>? = hashMapOf(),
@JsonProperty("vo_adaptive_hls") val vo_adaptive_hls: HashMap<String, HashMap<String, String>>? = hashMapOf(),
)
}
data class MALSyncSites(
@JsonProperty("Zoro") val zoro: HashMap<String?, HashMap<String, String?>>? = hashMapOf(),

View file

@ -734,7 +734,7 @@ fun Document.findTvMoviesIframe(): String? {
}
//modified code from https://github.com/jmir1/aniyomi-extensions/blob/master/src/all/kamyroll/src/eu/kanade/tachiyomi/animeextension/all/kamyroll/AccessTokenInterceptor.kt
suspend fun getCrunchyrollToken(): Map<String, String> {
suspend fun getCrunchyrollToken(): CrunchyrollAccessToken {
val client = app.baseClient.newBuilder()
.proxy(Proxy(Proxy.Type.SOCKS, InetSocketAddress("cr-unblocker.us.to", 1080)))
.build()
@ -760,9 +760,17 @@ suspend fun getCrunchyrollToken(): Map<String, String> {
)
)
val response = tryParseJson<CrunchyrollToken>(client.newCall(request).execute().body.string())
return mapOf("Authorization" to "${response?.tokenType} ${response?.accessToken}")
val token = tryParseJson<CrunchyrollToken>(client.newCall(request).execute().body.string())
val headers = mapOf("Authorization" to "${token?.tokenType} ${token?.accessToken}")
val cms = app.get("$crunchyrollAPI/index/v2", headers = headers).parsedSafe<CrunchyrollToken>()?.cms
return CrunchyrollAccessToken(
token?.accessToken,
token?.tokenType,
cms?.bucket,
cms?.policy,
cms?.signature,
cms?.key_pair_id,
)
}
suspend fun getCrunchyrollId(aniId: String?): String? {
@ -796,7 +804,7 @@ suspend fun getCrunchyrollId(aniId: String?): String? {
return (externalLinks?.find { it.site == "VRV" }
?: externalLinks?.find { it.site == "Crunchyroll" })?.url?.let {
Regex("series/(\\w+)/?").find(it)?.groupValues?.get(1)
app.get(it).url.substringAfter("/series/").substringBefore("/")
}
}