[Kickassanime] added Crunchyroll

This commit is contained in:
hexated 2023-01-21 17:40:41 +07:00
parent 55db4c2c1b
commit 6e25ed7485
2 changed files with 61 additions and 5 deletions

View file

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

View file

@ -1,5 +1,6 @@
package com.hexated package com.hexated
import android.util.Base64
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
@ -149,7 +150,7 @@ class Kickassanime : MainAPI() {
server.ext_servers?.find { it.name == "Vidstreaming" }?.link server.ext_servers?.find { it.name == "Vidstreaming" }?.link
) )
}?.filterNotNull() }?.filterNotNull()
val isDub = data.contains("-dub-")
sources?.flatMap { sources?.flatMap {
httpsify(it).fixIframe() httpsify(it).fixIframe()
}?.apmap { (name, iframe) -> }?.apmap { (name, iframe) ->
@ -168,7 +169,10 @@ class Kickassanime : MainAPI() {
name?.contains(Regex("(?i)(gogo)")) == true -> { name?.contains(Regex("(?i)(gogo)")) == true -> {
invokeGogo(link, subtitleCallback, callback) invokeGogo(link, subtitleCallback, callback)
} }
else -> {} name?.contains(Regex("(?i)(SAPPHIRE-DUCK)")) == true -> {
invokeSapphire(link, isDub, subtitleCallback, callback)
}
else -> return@apmap null
} }
} }
@ -188,7 +192,7 @@ class Kickassanime : MainAPI() {
).document.selectFirst("script:containsData(Base64.decode)")?.data() ).document.selectFirst("script:containsData(Base64.decode)")?.data()
?.substringAfter("Base64.decode(\"")?.substringBefore("\")")?.let { base64Decode(it) } ?: return ?.substringAfter("Base64.decode(\"")?.substringBefore("\")")?.let { base64Decode(it) } ?: return
if(url.contains("/dailymotion/")) { if(name == "DAILYMOTION") {
val iframe = Jsoup.parse(data).select("iframe").attr("src") val iframe = Jsoup.parse(data).select("iframe").attr("src")
loadExtractor(iframe, mainUrl, subtitleCallback, callback) loadExtractor(iframe, mainUrl, subtitleCallback, callback)
} else { } else {
@ -258,6 +262,37 @@ class Kickassanime : MainAPI() {
} }
private suspend fun invokeSapphire(
url: String? = null,
isDub: Boolean = false,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit,
) {
var data = app.get("$url&action=config", referer = url).text
for(i in 1..20) {
data = data.decodeBase64()
if(data.startsWith("{")) break
}
tryParseJson<SapphireSources>(data).let { res ->
res?.streams?.filter { it.format == "adaptive_hls" }?.map { source ->
val name = if(isDub) source.audio_lang else source.hardsub_lang.orEmpty().ifEmpty { "raw" }
M3u8Helper.generateM3u8(
"Crunchyroll [$name]",
source.url ?: return@map null,
"https://static.crunchyroll.com/",
).forEach(callback)
}
res?.subtitles?.map { sub ->
subtitleCallback.invoke(
SubtitleFile(
sub.language ?: "",
sub.url ?: return@map null
)
)
}
}
}
private suspend fun invokeGogo( private suspend fun invokeGogo(
link: String, link: String,
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
@ -314,6 +349,10 @@ class Kickassanime : MainAPI() {
} }
} }
private fun String.decodeBase64(): String {
return Base64.decode(this, Base64.DEFAULT).toString(Charsets.UTF_8)
}
private fun decode(input: String): String = private fun decode(input: String): String =
URLDecoder.decode(input, "utf-8").replace(" ", "%20") URLDecoder.decode(input, "utf-8").replace(" ", "%20")
@ -465,7 +504,24 @@ class Kickassanime : MainAPI() {
data class MaveSources( data class MaveSources(
@JsonProperty("hls") val hls: String? = null, @JsonProperty("hls") val hls: String? = null,
@JsonProperty("subtitles") val subtitles: ArrayList<MaveSubtitles>? = null, @JsonProperty("subtitles") val subtitles: ArrayList<MaveSubtitles>? = arrayListOf(),
)
data class SapphireSubtitles(
@JsonProperty("language") val language: String? = null,
@JsonProperty("url") val url: String? = null,
)
data class SapphireStreams(
@JsonProperty("format") val format: String? = null,
@JsonProperty("audio_lang") val audio_lang: String? = null,
@JsonProperty("hardsub_lang") val hardsub_lang: String? = null,
@JsonProperty("url") val url: String? = null,
)
data class SapphireSources(
@JsonProperty("streams") val streams: ArrayList<SapphireStreams>? = arrayListOf(),
@JsonProperty("subtitles") val subtitles: ArrayList<SapphireSubtitles>? = arrayListOf(),
) )
} }