Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix KickAssAnime extractor & update urls #3012

Merged
merged 2 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/en/kickassanime/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
ext {
extName = 'KickAssAnime'
extClass = '.KickAssAnime'
extVersionCode = 37
extVersionCode = 38
}

apply from: "$rootDir/common.gradle"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
import java.util.Locale

class KickAssAnime : ConfigurableAnimeSource, AnimeHttpSource() {
Expand All @@ -53,11 +54,10 @@ class KickAssAnime : ConfigurableAnimeSource, AnimeHttpSource() {

private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
.clearBaseUrl()
}

private val json = Json {
ignoreUnknownKeys = true
}
private val json: Json by injectLazy()

// ============================== Popular ===============================
override fun popularAnimeRequest(page: Int) = GET("$apiUrl/popular?page=$page")
Expand Down Expand Up @@ -290,6 +290,17 @@ class KickAssAnime : ConfigurableAnimeSource, AnimeHttpSource() {
).reversed()
}

private fun SharedPreferences.clearBaseUrl(): SharedPreferences {
if (getString(PREF_DOMAIN_KEY, "")!! in PREF_DOMAIN_ENTRY_VALUES) {
return this
}
edit()
.remove(PREF_DOMAIN_KEY)
.putString(PREF_DOMAIN_KEY, PREF_DOMAIN_DEFAULT)
.apply()
return this
}

companion object {
private val SERVERS = arrayOf("DuckStream", "BirdStream", "VidStreaming")

Expand Down Expand Up @@ -323,9 +334,9 @@ class KickAssAnime : ConfigurableAnimeSource, AnimeHttpSource() {

private const val PREF_DOMAIN_KEY = "preferred_domain"
private const val PREF_DOMAIN_TITLE = "Preferred domain (requires app restart)"
private const val PREF_DOMAIN_DEFAULT = "https://kickassanime.am"
private val PREF_DOMAIN_ENTRIES = arrayOf("kickassanime.am", "kaas.to", "kaas.ro")
private val PREF_DOMAIN_ENTRY_VALUES = arrayOf("https://kickassanime.am", "https://kaas.to", "https://kaas.ro")
private const val PREF_DOMAIN_DEFAULT = "https://kaas.to"
private val PREF_DOMAIN_ENTRIES = arrayOf("kaas.to", "kaas.ro", "kickassanimes.io", "www1.kickassanime.mx")
private val PREF_DOMAIN_ENTRY_VALUES = PREF_DOMAIN_ENTRIES.map { "https://$it" }.toTypedArray()

private const val PREF_HOSTER_KEY = "hoster_selection"
private const val PREF_HOSTER_TITLE = "Enable/Disable Hosts"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ import eu.kanade.tachiyomi.lib.cryptoaes.CryptoAES
import eu.kanade.tachiyomi.lib.cryptoaes.CryptoAES.decodeHex
import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.parseAs
import kotlinx.serialization.json.Json
import okhttp3.CacheControl
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
Expand All @@ -20,27 +18,6 @@ class KickAssAnimeExtractor(
private val json: Json,
private val headers: Headers,
) {
// Stolen from AniWatch
// Prevent (automatic) caching the .JS file for different episodes, because it
// changes everytime, and a cached old .js will have a invalid AES password,
// invalidating the decryption algorithm.
// We cache it manually when initializing the class.
private val cacheControl = CacheControl.Builder().noStore().build()
private val newClient = client.newBuilder()
.cache(null)
.build()

private val keyMaps by lazy {
buildMap {
put("bird", newClient.newCall(GET("https://raw.githubusercontent.com/enimax-anime/kaas/bird/key.txt", cache = cacheControl)).execute().body.string().toByteArray())
put("duck", newClient.newCall(GET("https://raw.githubusercontent.com/enimax-anime/kaas/duck/key.txt", cache = cacheControl)).execute().body.string().toByteArray())
}
}

private val signaturesMap by lazy {
newClient.newCall(GET("https://raw.githubusercontent.com/enimax-anime/gogo/main/KAA.json", cache = cacheControl)).execute().parseAs<Map<String, List<String>>>()
}

fun videosFromUrl(url: String, name: String): List<Video> {
val host = url.toHttpUrl().host
val mid = if (name == "DuckStream") "mid" else "id"
Expand All @@ -51,11 +28,11 @@ class KickAssAnimeExtractor(
val html = client.newCall(GET(url, headers)).execute().body.string()

val key = when (name) {
"VidStreaming" -> keyMaps["duck"]!!
"DuckStream" -> keyMaps["duck"]!!
"BirdStream" -> keyMaps["bird"]!!
"VidStreaming" -> "e13d38099bf562e8b9851a652d2043d3"
"DuckStream" -> "4504447b74641ad972980a6b8ffd7631"
"BirdStream" -> "4b14d0ff625163e3c9c7a47926484bf2"
else -> return emptyList()
}
}.toByteArray()

val (sig, timeStamp, route) = getSignature(html, name, query, key) ?: return emptyList()
val sourceUrl = buildString {
Expand Down Expand Up @@ -127,9 +104,9 @@ class KickAssAnimeExtractor(

private fun getSignature(html: String, server: String, query: String, key: ByteArray): Triple<String, String, String>? {
val order = when (server) {
"VidStreaming" -> signaturesMap["vid"]!!
"DuckStream" -> signaturesMap["duck"]!!
"BirdStream" -> signaturesMap["bird"]!!
"VidStreaming" -> listOf("IP", "USERAGENT", "ROUTE", "MID", "TIMESTAMP", "KEY")
"DuckStream" -> listOf("IP", "USERAGENT", "ROUTE", "MID", "TIMESTAMP", "KEY")
"BirdStream" -> listOf("IP", "USERAGENT", "ROUTE", "MID", "KEY")
else -> return null
}

Expand Down