mirror of
https://github.com/hexated/cloudstream-extensions-hexated.git
synced 2024-08-15 00:03:22 +00:00
sora: fix crunchy
This commit is contained in:
parent
1e2f746676
commit
aada4b49fe
6 changed files with 56 additions and 34 deletions
|
@ -1,5 +1,5 @@
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 18
|
version = 19
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
cloudstream {
|
||||||
|
|
|
@ -217,9 +217,10 @@ class Samehadaku : MainAPI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun String.fixQuality() : Int {
|
private fun String.fixQuality() : Int {
|
||||||
return when(this) {
|
return when(this.uppercase()) {
|
||||||
"MP4HD" -> Qualities.P720.value
|
"4K" -> Qualities.P2160.value
|
||||||
"FULLHD" -> Qualities.P1080.value
|
"FULLHD" -> Qualities.P1080.value
|
||||||
|
"MP4HD" -> Qualities.P720.value
|
||||||
else -> this.filter { it.isDigit() }.toIntOrNull() ?: Qualities.Unknown.value
|
else -> this.filter { it.isDigit() }.toIntOrNull() ?: Qualities.Unknown.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = 210
|
version = 211
|
||||||
|
|
||||||
android {
|
android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
|
|
@ -1505,7 +1505,8 @@ object SoraExtractor : SoraStream() {
|
||||||
"en-US",
|
"en-US",
|
||||||
"zh-CN",
|
"zh-CN",
|
||||||
)
|
)
|
||||||
val headers = getCrunchyrollToken()
|
val token = getCrunchyrollToken()
|
||||||
|
val headers = mapOf("Authorization" to "${token.tokenType} ${token.accessToken}")
|
||||||
val seasonIdData = app.get(
|
val seasonIdData = app.get(
|
||||||
"$crunchyrollAPI/content/v2/cms/series/${id ?: return}/seasons", headers = headers
|
"$crunchyrollAPI/content/v2/cms/series/${id ?: return}/seasons", headers = headers
|
||||||
).parsedSafe<CrunchyrollResponses>()?.data?.let { s ->
|
).parsedSafe<CrunchyrollResponses>()?.data?.let { s ->
|
||||||
|
@ -1532,17 +1533,18 @@ object SoraExtractor : SoraStream() {
|
||||||
it.title.equals(epsTitle, true) || it.slug_title.equals(
|
it.title.equals(epsTitle, true) || it.slug_title.equals(
|
||||||
epsTitle.createSlug(), true
|
epsTitle.createSlug(), true
|
||||||
) || it.episode_number == episode
|
) || it.episode_number == episode
|
||||||
}?.streams_link
|
}?.streams_link?.substringAfter("/videos/")?.substringBefore("/streams") ?: return@apmap
|
||||||
val sources =
|
val sources = app.get(
|
||||||
app.get(fixUrl(streamsLink ?: return@apmap, crunchyrollAPI), headers = headers)
|
"$crunchyrollAPI/cms/v2${token.bucket}/videos/$streamsLink/streams?Policy=${token.policy}&Signature=${token.signature}&Key-Pair-Id=${token.key_pair_id}",
|
||||||
.parsedSafe<CrunchyrollSourcesResponses>()
|
headers = headers
|
||||||
|
).parsedSafe<CrunchyrollSourcesResponses>()
|
||||||
|
|
||||||
listOf(
|
listOf(
|
||||||
"adaptive_hls", "vo_adaptive_hls"
|
"adaptive_hls", "vo_adaptive_hls"
|
||||||
).map { hls ->
|
).map { hls ->
|
||||||
val name = if (hls == "adaptive_hls") "Crunchyroll" else "Vrv"
|
val name = if (hls == "adaptive_hls") "Crunchyroll" else "Vrv"
|
||||||
val audio = if (audioL == "en-US") "English Dub" else "Raw"
|
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
|
if (hls == "adaptive_hls") it.adaptive_hls else it.vo_adaptive_hls
|
||||||
}
|
}
|
||||||
M3u8Helper.generateM3u8(
|
M3u8Helper.generateM3u8(
|
||||||
|
@ -1552,7 +1554,7 @@ object SoraExtractor : SoraStream() {
|
||||||
).forEach(callback)
|
).forEach(callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
sources?.meta?.subtitles?.map { sub ->
|
sources?.subtitles?.map { sub ->
|
||||||
subtitleCallback.invoke(
|
subtitleCallback.invoke(
|
||||||
SubtitleFile(
|
SubtitleFile(
|
||||||
"${fixCrunchyrollLang(sub.key) ?: sub.key} [ass]",
|
"${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("/")
|
media.third.substringAfterLast("/") to iframe.substringAfterLast("/")
|
||||||
.substringBefore("-")
|
.substringBefore("-")
|
||||||
}
|
}
|
||||||
val res = app.get(fixUrl(iframe, api))
|
val res = app.get(fixUrl(iframe, api), verify = false)
|
||||||
delay(2000)
|
delay(2000)
|
||||||
val serverUrl = res.document.selectFirst("script:containsData(pushState)")?.data()?.let {
|
val serverUrl = res.document.selectFirst("script:containsData(pushState)")?.data()?.let {
|
||||||
""",\s*'([^']+)""".toRegex().find(it)?.groupValues?.get(1)
|
""",\s*'([^']+)""".toRegex().find(it)?.groupValues?.get(1)
|
||||||
|
|
|
@ -2,6 +2,15 @@ package com.hexated
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
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(
|
data class ShowboxMedia(
|
||||||
val url: String,
|
val url: String,
|
||||||
val title: String,
|
val title: String,
|
||||||
|
@ -207,12 +216,17 @@ data class AnilistResponses(
|
||||||
)
|
)
|
||||||
|
|
||||||
data class CrunchyrollToken(
|
data class CrunchyrollToken(
|
||||||
@JsonProperty("access_token") val accessToken: String? = null,
|
@JsonProperty("access_token") val accessToken: String? = null,
|
||||||
@JsonProperty("expires_in") val expiresIn: Int? = null,
|
@JsonProperty("token_type") val tokenType: String? = null,
|
||||||
@JsonProperty("token_type") val tokenType: String? = null,
|
@JsonProperty("cms") val cms: Cms? = null,
|
||||||
@JsonProperty("scope") val scope: String? = null,
|
) {
|
||||||
@JsonProperty("country") val country: String? = 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(
|
data class CrunchyrollVersions(
|
||||||
@JsonProperty("audio_locale") val audio_locale: String? = null,
|
@JsonProperty("audio_locale") val audio_locale: String? = null,
|
||||||
|
@ -227,22 +241,21 @@ data class CrunchyrollData(
|
||||||
@JsonProperty("episode_number") val episode_number: Int? = null,
|
@JsonProperty("episode_number") val episode_number: Int? = null,
|
||||||
@JsonProperty("versions") val versions: ArrayList<CrunchyrollVersions>? = null,
|
@JsonProperty("versions") val versions: ArrayList<CrunchyrollVersions>? = null,
|
||||||
@JsonProperty("streams_link") val streams_link: String? = 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(
|
data class CrunchyrollResponses(
|
||||||
@JsonProperty("data") val data: ArrayList<CrunchyrollData>? = arrayListOf(),
|
@JsonProperty("data") val data: ArrayList<CrunchyrollData>? = arrayListOf(),
|
||||||
)
|
)
|
||||||
|
|
||||||
data class CrunchyrollMeta(
|
|
||||||
@JsonProperty("subtitles") val subtitles: HashMap<String, HashMap<String, String>>? = hashMapOf(),
|
|
||||||
)
|
|
||||||
|
|
||||||
data class CrunchyrollSourcesResponses(
|
data class CrunchyrollSourcesResponses(
|
||||||
@JsonProperty("data") val data: ArrayList<CrunchyrollData>? = arrayListOf(),
|
@JsonProperty("streams") val streams: Streams? = Streams(),
|
||||||
@JsonProperty("meta") val meta: CrunchyrollMeta? = null,
|
@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(
|
data class MALSyncSites(
|
||||||
@JsonProperty("Zoro") val zoro: HashMap<String?, HashMap<String, String?>>? = hashMapOf(),
|
@JsonProperty("Zoro") val zoro: HashMap<String?, HashMap<String, String?>>? = hashMapOf(),
|
||||||
|
|
|
@ -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
|
//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()
|
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()
|
||||||
|
@ -760,9 +760,17 @@ suspend fun getCrunchyrollToken(): Map<String, String> {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val response = tryParseJson<CrunchyrollToken>(client.newCall(request).execute().body.string())
|
val token = tryParseJson<CrunchyrollToken>(client.newCall(request).execute().body.string())
|
||||||
return mapOf("Authorization" to "${response?.tokenType} ${response?.accessToken}")
|
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? {
|
suspend fun getCrunchyrollId(aniId: String?): String? {
|
||||||
|
@ -796,7 +804,7 @@ suspend fun getCrunchyrollId(aniId: String?): String? {
|
||||||
|
|
||||||
return (externalLinks?.find { it.site == "VRV" }
|
return (externalLinks?.find { it.site == "VRV" }
|
||||||
?: externalLinks?.find { it.site == "Crunchyroll" })?.url?.let {
|
?: externalLinks?.find { it.site == "Crunchyroll" })?.url?.let {
|
||||||
Regex("series/(\\w+)/?").find(it)?.groupValues?.get(1)
|
app.get(it).url.substringAfter("/series/").substringBefore("/")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue