From 3a5f8c9fd35a908d726ae33203aaf11d9b7fbd35 Mon Sep 17 00:00:00 2001 From: Vetle Ledaal Date: Sat, 28 Oct 2023 15:45:34 +0000 Subject: [PATCH] =?UTF-8?q?=E1=BB=94=20C=C3=BA=20M=C3=A8o:=20Update=20doma?= =?UTF-8?q?in=20and=20decrypt=20page=20URLs=20(#18771)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../overrides/a3manga/ocumeo/src/OCuMeo.kt | 52 +++++++++++++++++++ .../tachiyomi/multisrc/a3manga/A3Manga.kt | 8 ++- .../multisrc/a3manga/A3MangaGenerator.kt | 2 +- 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 multisrc/overrides/a3manga/ocumeo/src/OCuMeo.kt diff --git a/multisrc/overrides/a3manga/ocumeo/src/OCuMeo.kt b/multisrc/overrides/a3manga/ocumeo/src/OCuMeo.kt new file mode 100644 index 000000000..8a56b9897 --- /dev/null +++ b/multisrc/overrides/a3manga/ocumeo/src/OCuMeo.kt @@ -0,0 +1,52 @@ +package eu.kanade.tachiyomi.extension.vi.ocumeo + +import eu.kanade.tachiyomi.multisrc.a3manga.A3Manga +import eu.kanade.tachiyomi.source.model.Page +import org.jsoup.Jsoup +import org.jsoup.nodes.Document + +class OCuMeo : A3Manga("Ổ Cú Mèo", "https://www.ocumoe.com", "vi") { + + override fun pageListParse(document: Document): List { + val imgListHtml = decodeImgList(document) + + return Jsoup.parseBodyFragment(imgListHtml).select("img").mapIndexed { idx, element -> + val encryptedUrl = element.attributes().find { it.key.startsWith("data") }?.value + Page(idx, imageUrl = encryptedUrl?.decodeUrl()) + } + } + + private fun String.decodeUrl(): String { + // We expect the URL to start with `https://`, where the last 3 characters are encoded. + // The length of the encoded character is not known, but it is the same across all. + // Essentially we are looking for the two encoded slashes, which tells us the length. + val patternIdx = patternsLengthCheck.indexOfFirst { pattern -> + val matchResult = pattern.find(this) + val g1 = matchResult?.groupValues?.get(1) + val g2 = matchResult?.groupValues?.get(2) + g1 == g2 && g1 != null + } + if (patternIdx == -1) { + throw Exception("Failed to decrypt URL") + } + + // With a known length we can predict all the encoded characters. + // This is a slightly more expensive pattern, hence the separation. + val matchResult = patternsSubstitution[patternIdx].find(this) + return matchResult?.destructured?.let { (colon, slash, period) -> + this + .replace(colon, ":") + .replace(slash, "/") + .replace(period, ".") + } ?: throw Exception("Failed to reconstruct URL") + } + + companion object { + private val patternsLengthCheck: List = (20 downTo 1).map { i -> + """^https.{$i}(.{$i})(.{$i})""".toRegex() + } + private val patternsSubstitution: List = (20 downTo 1).map { i -> + """^https(.{$i})(.{$i}).*(.{$i})(?:webp|jpeg|tiff|.{3})$""".toRegex() + } + } +} diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/a3manga/A3Manga.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/a3manga/A3Manga.kt index a5da4d251..79d7d3802 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/a3manga/A3Manga.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/a3manga/A3Manga.kt @@ -147,7 +147,7 @@ open class A3Manga( }.getOrNull() ?: 0 } - override fun pageListParse(document: Document): List { + protected fun decodeImgList(document: Document): String { val htmlContentScript = document.selectFirst("script:containsData(htmlContent)")?.html() ?.substringAfter("var htmlContent=\"") ?.substringBefore("\";") @@ -175,6 +175,12 @@ open class A3Manga( val imgListHtml = cipher.doFinal(ciphertext).toString(Charsets.UTF_8) + return imgListHtml + } + + override fun pageListParse(document: Document): List { + val imgListHtml = decodeImgList(document) + return Jsoup.parseBodyFragment(imgListHtml).select("img").mapIndexed { idx, it -> Page(idx, imageUrl = it.attr("abs:src")) } diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaGenerator.kt index 98280cf5f..3a1a86ec3 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaGenerator.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaGenerator.kt @@ -15,7 +15,7 @@ class A3MangaGenerator : ThemeSourceGenerator { SingleLang("A3 Manga", "https://www.a3mnga.com", "vi"), SingleLang("Team Lanh Lung", "https://teamlanhlung.vip", "vi", sourceName = "Team Lạnh Lùng", overrideVersionCode = 1), SingleLang("Ngon Phong", "https://www.ngonphong.com", "vi", sourceName = "Ngôn Phong", overrideVersionCode = 1), - SingleLang("O Cu Meo", "https://www.ocumeo.com", "vi", sourceName = "Ổ Cú Mèo"), + SingleLang("O Cu Meo", "https://www.ocumoe.com", "vi", sourceName = "Ổ Cú Mèo", overrideVersionCode = 1), ) companion object {