From 2b7431c22b01b0fe8b1dd442ce83ce1891bbc76c Mon Sep 17 00:00:00 2001 From: CursedSheep <44673993+CursedSheep@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:39:23 +0800 Subject: [PATCH 1/5] Improve KwikExtractor Decrypt Function - Optimize and improve performance of KwikExtractor decrypt functionality --- .../en/animepahe/KwikExtractor.kt | 52 +++++-------------- 1 file changed, 12 insertions(+), 40 deletions(-) diff --git a/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/KwikExtractor.kt b/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/KwikExtractor.kt index 19b366a0..f8140aa0 100644 --- a/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/KwikExtractor.kt +++ b/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/KwikExtractor.kt @@ -35,7 +35,6 @@ import okhttp3.FormBody import okhttp3.Headers import okhttp3.OkHttpClient import okhttp3.Response -import kotlin.math.pow class KwikExtractor(private val client: OkHttpClient) { private var cookies: String = "" @@ -108,52 +107,25 @@ class KwikExtractor(private val client: OkHttpClient) { } private fun decrypt(fullString: String, key: String, v1: Int, v2: Int): String { - var r = "" + val keyIndexMap = key.withIndex().associate { it.value to it.index } + val sb = StringBuilder() var i = 0 + val toFind = key[v2] while (i < fullString.length) { - var s = "" - - while (fullString[i] != key[v2]) { - s += fullString[i] - ++i + val nextIndex = fullString.indexOf(toFind, i) + val decodedCharStr = buildString { + for (j in i until nextIndex) { + append(keyIndexMap[fullString[j]] ?: -1) + } } - var j = 0 - while (j < key.length) { - s = s.replace(key[j].toString(), j.toString()) - ++j - } - r += (getString(s, v2).toInt() - v1).toChar() - ++i - } - return r - } + i = nextIndex + 1 - private fun getString(content: String, s1: Int): String { - val s2 = 10 - val characterMap = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/" - - val slice2 = characterMap.slice(0 until s2) - var acc: Long = 0 - - for ((n, i) in content.reversed().withIndex()) { - acc += when (isNumber("$i")) { - true -> "$i".toLong() - false -> 0L - } * s1.toDouble().pow(n.toDouble()).toInt() + val decodedChar = (decodedCharStr.toInt(v2) - v1).toChar() + sb.append(decodedChar) } - var k = "" - - while (acc > 0) { - k = slice2[(acc % s2).toInt()] + k - acc = (acc - (acc % s2)) / s2 - } - - return when (k != "") { - true -> k - false -> "0" - } + return sb.toString() } } -- 2.47.2 From 8ba92faf1ff4b3263f47b4970695dbfa2531220c Mon Sep 17 00:00:00 2001 From: CursedSheep <44673993+CursedSheep@users.noreply.github.com> Date: Fri, 17 Jan 2025 17:04:21 +0800 Subject: [PATCH 2/5] Fix issue #550 --- .../animeextension/en/animepahe/AnimePahe.kt | 36 +++++-------------- .../en/animepahe/dto/AnimePaheDto.kt | 2 ++ 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/AnimePahe.kt b/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/AnimePahe.kt index f13f3227..44672a28 100644 --- a/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/AnimePahe.kt +++ b/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/AnimePahe.kt @@ -19,9 +19,6 @@ import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.parseAs -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withContext import kotlinx.serialization.json.Json import okhttp3.Headers import okhttp3.Request @@ -67,16 +64,8 @@ class AnimePahe : ConfigurableAnimeSource, AnimeHttpSource() { * @see episodeListRequest */ override fun animeDetailsRequest(anime: SAnime): Request { - val animeId = anime.getId() - // We're using coroutines here to run it inside another thread and - // prevent android.os.NetworkOnMainThreadException when trying to open - // webview or share it. - val session = runBlocking { - withContext(Dispatchers.IO) { - fetchSession(anime.title, animeId) - } - } - return GET("$baseUrl/anime/$session?anime_id=$animeId") + val session = anime.getSession() + return GET("$baseUrl/anime/$session") } override fun animeDetailsParse(response: Response): SAnime { @@ -106,8 +95,8 @@ class AnimePahe : ConfigurableAnimeSource, AnimeHttpSource() { SAnime.create().apply { title = anime.title thumbnail_url = anime.snapshot - val animeId = anime.id - setUrlWithoutDomain("/anime/?anime_id=$animeId") + val sessionId = anime.anime_session + setUrlWithoutDomain("/anime/?session_id=$sessionId") artist = anime.fansub } } @@ -124,8 +113,8 @@ class AnimePahe : ConfigurableAnimeSource, AnimeHttpSource() { SAnime.create().apply { title = anime.title thumbnail_url = anime.poster - val animeId = anime.id - setUrlWithoutDomain("/anime/?anime_id=$animeId") + val sessionId = anime.session + setUrlWithoutDomain("/anime/?session_id=$sessionId") } } return AnimesPage(animeList, false) @@ -146,7 +135,7 @@ class AnimePahe : ConfigurableAnimeSource, AnimeHttpSource() { * @see animeDetailsRequest */ override fun episodeListRequest(anime: SAnime): Request { - val session = fetchSession(anime.title, anime.getId()) + val session = anime.getSession() return GET("$baseUrl/api?m=release&id=$session&sort=episode_desc&page=1") } @@ -310,15 +299,6 @@ class AnimePahe : ConfigurableAnimeSource, AnimeHttpSource() { } // ============================= Utilities ============================== - private fun fetchSession(title: String, animeId: String): String { - return client.newCall(GET("$baseUrl/api?m=search&q=$title")) - .execute() - .body.string() - .substringAfter("\"id\":$animeId") - .substringAfter("\"session\":\"") - .substringBefore("\"") - } - private fun parseStatus(statusString: String): Int { return when (statusString) { "Currently Airing" -> SAnime.ONGOING @@ -327,7 +307,7 @@ class AnimePahe : ConfigurableAnimeSource, AnimeHttpSource() { } } - private fun SAnime.getId() = url.substringAfterLast("?anime_id=").substringBefore("\"") + private fun SAnime.getSession() = url.substringAfterLast("?session_id=").substringBefore("\"") private fun String.toDate(): Long { return runCatching { diff --git a/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/dto/AnimePaheDto.kt b/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/dto/AnimePaheDto.kt index 2adcd2f7..c2ab2410 100644 --- a/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/dto/AnimePaheDto.kt +++ b/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/dto/AnimePaheDto.kt @@ -23,6 +23,7 @@ data class LatestAnimeDto( @SerialName("anime_id") val id: Int, val fansub: String, + val anime_session: String, ) @Serializable @@ -30,6 +31,7 @@ data class SearchResultDto( val title: String, val poster: String, val id: Int, + val session: String, ) @Serializable -- 2.47.2 From cd4714ea42061307c9db0bd66b2ac0d5e987e6a2 Mon Sep 17 00:00:00 2001 From: CursedSheep <44673993+CursedSheep@users.noreply.github.com> Date: Fri, 17 Jan 2025 20:11:26 +0800 Subject: [PATCH 3/5] Update version --- src/en/animepahe/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/en/animepahe/build.gradle b/src/en/animepahe/build.gradle index 10eb74d8..732be294 100644 --- a/src/en/animepahe/build.gradle +++ b/src/en/animepahe/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'AnimePahe' extClass = '.AnimePahe' - extVersionCode = 27 + extVersionCode = 28 } apply from: "$rootDir/common.gradle" -- 2.47.2 From 05aad0f4bf5f6141b54b90fd2e43979d21dab0de Mon Sep 17 00:00:00 2001 From: CursedSheep <44673993+CursedSheep@users.noreply.github.com> Date: Sat, 18 Jan 2025 19:30:26 +0800 Subject: [PATCH 4/5] Improve solution for #550 - Revert back to using Anime Id instead of Session Id - Improve `fetchSession` by resolving anime using Anime Id only --- src/en/animepahe/build.gradle | 2 +- .../animeextension/en/animepahe/AnimePahe.kt | 33 ++++++++++++++----- .../en/animepahe/dto/AnimePaheDto.kt | 2 -- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/en/animepahe/build.gradle b/src/en/animepahe/build.gradle index 732be294..986c0de4 100644 --- a/src/en/animepahe/build.gradle +++ b/src/en/animepahe/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'AnimePahe' extClass = '.AnimePahe' - extVersionCode = 28 + extVersionCode = 29 } apply from: "$rootDir/common.gradle" diff --git a/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/AnimePahe.kt b/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/AnimePahe.kt index 44672a28..33d6e751 100644 --- a/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/AnimePahe.kt +++ b/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/AnimePahe.kt @@ -19,6 +19,9 @@ import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.parseAs +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext import kotlinx.serialization.json.Json import okhttp3.Headers import okhttp3.Request @@ -64,7 +67,15 @@ class AnimePahe : ConfigurableAnimeSource, AnimeHttpSource() { * @see episodeListRequest */ override fun animeDetailsRequest(anime: SAnime): Request { - val session = anime.getSession() + val animeId = anime.getId() + // We're using coroutines here to run it inside another thread and + // prevent android.os.NetworkOnMainThreadException when trying to open + // webview or share it. + val session = runBlocking { + withContext(Dispatchers.IO) { + fetchSession(animeId) + } + } return GET("$baseUrl/anime/$session") } @@ -95,8 +106,8 @@ class AnimePahe : ConfigurableAnimeSource, AnimeHttpSource() { SAnime.create().apply { title = anime.title thumbnail_url = anime.snapshot - val sessionId = anime.anime_session - setUrlWithoutDomain("/anime/?session_id=$sessionId") + val animeId = anime.id + setUrlWithoutDomain("/anime/?anime_id=$animeId") artist = anime.fansub } } @@ -113,8 +124,8 @@ class AnimePahe : ConfigurableAnimeSource, AnimeHttpSource() { SAnime.create().apply { title = anime.title thumbnail_url = anime.poster - val sessionId = anime.session - setUrlWithoutDomain("/anime/?session_id=$sessionId") + val animeId = anime.id + setUrlWithoutDomain("/anime/?anime_id=$animeId") } } return AnimesPage(animeList, false) @@ -135,7 +146,7 @@ class AnimePahe : ConfigurableAnimeSource, AnimeHttpSource() { * @see animeDetailsRequest */ override fun episodeListRequest(anime: SAnime): Request { - val session = anime.getSession() + val session = fetchSession(anime.getId()) return GET("$baseUrl/api?m=release&id=$session&sort=episode_desc&page=1") } @@ -299,6 +310,12 @@ class AnimePahe : ConfigurableAnimeSource, AnimeHttpSource() { } // ============================= Utilities ============================== + private fun fetchSession(animeId: String): String { + val resolveAnimeRequest = client.newCall(GET("$baseUrl/a/$animeId")).execute() + val sessionId = resolveAnimeRequest.request.url.pathSegments.last() + return sessionId + } + private fun parseStatus(statusString: String): Int { return when (statusString) { "Currently Airing" -> SAnime.ONGOING @@ -307,7 +324,7 @@ class AnimePahe : ConfigurableAnimeSource, AnimeHttpSource() { } } - private fun SAnime.getSession() = url.substringAfterLast("?session_id=").substringBefore("\"") + private fun SAnime.getId() = url.substringAfterLast("?anime_id=").substringBefore("\"") private fun String.toDate(): Long { return runCatching { @@ -358,4 +375,4 @@ class AnimePahe : ConfigurableAnimeSource, AnimeHttpSource() { """.trimMargin() } } -} +} \ No newline at end of file diff --git a/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/dto/AnimePaheDto.kt b/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/dto/AnimePaheDto.kt index c2ab2410..2adcd2f7 100644 --- a/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/dto/AnimePaheDto.kt +++ b/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/dto/AnimePaheDto.kt @@ -23,7 +23,6 @@ data class LatestAnimeDto( @SerialName("anime_id") val id: Int, val fansub: String, - val anime_session: String, ) @Serializable @@ -31,7 +30,6 @@ data class SearchResultDto( val title: String, val poster: String, val id: Int, - val session: String, ) @Serializable -- 2.47.2 From c4c3e6fc386bcd394025c24c0c598b144006b703 Mon Sep 17 00:00:00 2001 From: CursedSheep <44673993+CursedSheep@users.noreply.github.com> Date: Sat, 18 Jan 2025 20:01:07 +0800 Subject: [PATCH 5/5] Fix lint error --- .../kanade/tachiyomi/animeextension/en/animepahe/AnimePahe.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/AnimePahe.kt b/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/AnimePahe.kt index 33d6e751..c85d1679 100644 --- a/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/AnimePahe.kt +++ b/src/en/animepahe/src/eu/kanade/tachiyomi/animeextension/en/animepahe/AnimePahe.kt @@ -375,4 +375,4 @@ class AnimePahe : ConfigurableAnimeSource, AnimeHttpSource() { """.trimMargin() } } -} \ No newline at end of file +} -- 2.47.2