From e64df9ebc4e52df9525c116ef0358e71527ffd9f Mon Sep 17 00:00:00 2001 From: Chopper <156493704+choppeh@users.noreply.github.com> Date: Sat, 29 Mar 2025 04:14:31 -0300 Subject: [PATCH] TeamLanhLung: Merge A3Manga with TeamLanhLung and fix search manga (#8271) * Merge A3Manga and TeamLanhLung and fix search manga * Use parseAs from utils --- lib-multisrc/a3manga/build.gradle.kts | 5 - .../tachiyomi/multisrc/a3manga/A3Manga.kt | 247 ------------------ .../vi/teamlanhlung}/AndroidManifest.xml | 11 +- src/vi/teamlanhlung/build.gradle | 4 +- .../extension/vi/teamlanhlung/TeamLanhLung.kt | 239 ++++++++++++++++- .../vi/teamlanhlung/TeamLanhLungDto.kt | 2 +- .../teamlanhlung/TeamLanhLungUrlActivity.kt | 8 +- 7 files changed, 249 insertions(+), 267 deletions(-) delete mode 100644 lib-multisrc/a3manga/build.gradle.kts delete mode 100644 lib-multisrc/a3manga/src/eu/kanade/tachiyomi/multisrc/a3manga/A3Manga.kt rename {lib-multisrc/a3manga => src/vi/teamlanhlung}/AndroidManifest.xml (66%) rename lib-multisrc/a3manga/src/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaDto.kt => src/vi/teamlanhlung/src/eu/kanade/tachiyomi/extension/vi/teamlanhlung/TeamLanhLungDto.kt (89%) rename lib-multisrc/a3manga/src/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaUrlActivity.kt => src/vi/teamlanhlung/src/eu/kanade/tachiyomi/extension/vi/teamlanhlung/TeamLanhLungUrlActivity.kt (81%) diff --git a/lib-multisrc/a3manga/build.gradle.kts b/lib-multisrc/a3manga/build.gradle.kts deleted file mode 100644 index e2f11e9c1..000000000 --- a/lib-multisrc/a3manga/build.gradle.kts +++ /dev/null @@ -1,5 +0,0 @@ -plugins { - id("lib-multisrc") -} - -baseVersionCode = 3 diff --git a/lib-multisrc/a3manga/src/eu/kanade/tachiyomi/multisrc/a3manga/A3Manga.kt b/lib-multisrc/a3manga/src/eu/kanade/tachiyomi/multisrc/a3manga/A3Manga.kt deleted file mode 100644 index 532d1a16f..000000000 --- a/lib-multisrc/a3manga/src/eu/kanade/tachiyomi/multisrc/a3manga/A3Manga.kt +++ /dev/null @@ -1,247 +0,0 @@ -package eu.kanade.tachiyomi.multisrc.a3manga - -import android.util.Base64 -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.POST -import eu.kanade.tachiyomi.source.model.FilterList -import eu.kanade.tachiyomi.source.model.MangasPage -import eu.kanade.tachiyomi.source.model.Page -import eu.kanade.tachiyomi.source.model.SChapter -import eu.kanade.tachiyomi.source.model.SManga -import eu.kanade.tachiyomi.source.online.ParsedHttpSource -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json -import okhttp3.FormBody -import okhttp3.Headers -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response -import org.jsoup.Jsoup -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import rx.Observable -import uy.kohesive.injekt.injectLazy -import java.text.SimpleDateFormat -import java.util.Locale -import java.util.TimeZone -import javax.crypto.Cipher -import javax.crypto.SecretKeyFactory -import javax.crypto.spec.IvParameterSpec -import javax.crypto.spec.PBEKeySpec -import javax.crypto.spec.SecretKeySpec - -open class A3Manga( - override val name: String, - override val baseUrl: String, - override val lang: String, -) : ParsedHttpSource() { - - override val supportsLatest: Boolean = false - - override val client: OkHttpClient = network.cloudflareClient - - private val json: Json by injectLazy() - - override fun headersBuilder(): Headers.Builder = super.headersBuilder().add("Referer", "$baseUrl/") - - override fun popularMangaRequest(page: Int): Request = GET("$baseUrl/page/$page/", headers) - - override fun popularMangaSelector() = ".comic-list .comic-item" - - override fun popularMangaFromElement(element: Element) = SManga.create().apply { - setUrlWithoutDomain(element.select(".comic-title-link a").attr("href")) - title = element.select(".comic-title").text().trim() - thumbnail_url = element.select(".img-thumbnail").attr("abs:src") - } - - override fun popularMangaNextPageSelector() = "li.next:not(.disabled)" - - override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException() - - override fun latestUpdatesSelector() = throw UnsupportedOperationException() - - override fun latestUpdatesFromElement(element: Element) = throw UnsupportedOperationException() - - override fun latestUpdatesNextPageSelector() = throw UnsupportedOperationException() - - override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { - return when { - query.startsWith(PREFIX_ID_SEARCH) -> { - val id = query.removePrefix(PREFIX_ID_SEARCH).trim() - fetchMangaDetails( - SManga.create().apply { - url = "/truyen-tranh/$id/" - }, - ) - .map { - it.url = "/truyen-tranh/$id/" - MangasPage(listOf(it), false) - } - } - else -> super.fetchSearchManga(page, query, filters) - } - } - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = - POST( - "$baseUrl/wp-admin/admin-ajax.php", - headers, - FormBody.Builder() - .add("action", "searchtax") - .add("keyword", query) - .build(), - ) - - override fun searchMangaSelector(): String = throw UnsupportedOperationException() - - override fun searchMangaFromElement(element: Element): SManga = throw UnsupportedOperationException() - - override fun searchMangaNextPageSelector() = throw UnsupportedOperationException() - - override fun searchMangaParse(response: Response): MangasPage { - val dto = response.parseAs() - - if (!dto.success) { - return MangasPage(emptyList(), false) - } - - val manga = dto.data - .filter { it.cstatus != "Nhóm dịch" } - .map { - SManga.create().apply { - setUrlWithoutDomain(it.link) - title = it.title - thumbnail_url = it.img - } - } - - return MangasPage(manga, false) - } - - override fun mangaDetailsParse(document: Document) = SManga.create().apply { - title = document.select(".info-title").text() - author = document.select(".comic-info strong:contains(Tác giả) + span").text().trim() - description = document.select(".intro-container .text-justify").text().substringBefore("— Xem Thêm —") - genre = document.select(".comic-info .tags a").joinToString { tag -> - tag.text().split(' ').joinToString(separator = " ") { word -> - word.replaceFirstChar { it.titlecase() } - } - } - thumbnail_url = document.select(".img-thumbnail").attr("abs:src") - - val statusString = document.select(".comic-info strong:contains(Tình trạng) + span").text() - status = when (statusString) { - "Đang tiến hành" -> SManga.ONGOING - "Trọn bộ " -> SManga.COMPLETED - else -> SManga.UNKNOWN - } - } - - override fun chapterListSelector(): String = ".chapter-table table tbody tr" - - override fun chapterFromElement(element: Element) = SChapter.create().apply { - setUrlWithoutDomain(element.select("a").attr("href")) - name = element.select("a .hidden-sm").text() - date_upload = runCatching { - dateFormat.parse(element.select("td").last()!!.text())?.time - }.getOrNull() ?: 0 - } - - protected fun decodeImgList(document: Document): String { - val htmlContentScript = document.selectFirst("script:containsData(htmlContent)")?.html() - ?.substringAfter("var htmlContent=\"") - ?.substringBefore("\";") - ?.replace("\\\"", "\"") - ?.replace("\\\\", "\\") - ?.replace("\\/", "/") - ?: throw Exception("Couldn't find script with image data.") - val htmlContent = json.decodeFromString(htmlContentScript) - val ciphertext = Base64.decode(htmlContent.ciphertext, Base64.DEFAULT) - val iv = htmlContent.iv.decodeHex() - val salt = htmlContent.salt.decodeHex() - - val passwordScript = document.selectFirst("script:containsData(chapterHTML)")?.html() - ?: throw Exception("Couldn't find password to decrypt image data.") - val passphrase = passwordScript.substringAfter("var chapterHTML=CryptoJSAesDecrypt('") - .substringBefore("',htmlContent") - .replace("'+'", "") - - val keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM) - val spec = PBEKeySpec(passphrase.toCharArray(), salt, 999, 256) - val keyS = SecretKeySpec(keyFactory.generateSecret(spec).encoded, "AES") - - val cipher = Cipher.getInstance(CIPHER_TRANSFORMATION) - cipher.init(Cipher.DECRYPT_MODE, keyS, IvParameterSpec(iv)) - - 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, element -> - val encryptedUrl = element.attributes().find { it.key.startsWith("data") }?.value - val effectiveUrl = encryptedUrl?.decodeUrl() ?: element.attr("abs:src") - Page(idx, imageUrl = effectiveUrl) - } - } - - 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) { - return null - } - - // 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, ".") - } - } - - override fun imageUrlParse(document: Document) = throw UnsupportedOperationException() - - private inline fun Response.parseAs(): T { - return json.decodeFromString(body.string()) - } - - // https://stackoverflow.com/a/66614516 - private fun String.decodeHex(): ByteArray { - check(length % 2 == 0) { "Must have an even length" } - - return chunked(2) - .map { it.toInt(16).toByte() } - .toByteArray() - } - - companion object { - const val KEY_ALGORITHM = "PBKDF2WithHmacSHA512" - const val CIPHER_TRANSFORMATION = "AES/CBC/PKCS7PADDING" - - const val PREFIX_ID_SEARCH = "id:" - val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.US).apply { - timeZone = TimeZone.getTimeZone("Asia/Ho_Chi_Minh") - } - - 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/lib-multisrc/a3manga/AndroidManifest.xml b/src/vi/teamlanhlung/AndroidManifest.xml similarity index 66% rename from lib-multisrc/a3manga/AndroidManifest.xml rename to src/vi/teamlanhlung/AndroidManifest.xml index 196677396..a9475b0ab 100644 --- a/lib-multisrc/a3manga/AndroidManifest.xml +++ b/src/vi/teamlanhlung/AndroidManifest.xml @@ -2,7 +2,7 @@ @@ -12,10 +12,11 @@ - - - + diff --git a/src/vi/teamlanhlung/build.gradle b/src/vi/teamlanhlung/build.gradle index 7e2fa5d21..5665e1f26 100644 --- a/src/vi/teamlanhlung/build.gradle +++ b/src/vi/teamlanhlung/build.gradle @@ -1,9 +1,7 @@ ext { extName = 'Team Lanh Lung' extClass = '.TeamLanhLung' - themePkg = 'a3manga' - baseUrl = 'https://teamlanhlung3.shop' - overrideVersionCode = 18 + extVersionCode = 22 isNsfw = true } diff --git a/src/vi/teamlanhlung/src/eu/kanade/tachiyomi/extension/vi/teamlanhlung/TeamLanhLung.kt b/src/vi/teamlanhlung/src/eu/kanade/tachiyomi/extension/vi/teamlanhlung/TeamLanhLung.kt index d29d5b410..87236322e 100644 --- a/src/vi/teamlanhlung/src/eu/kanade/tachiyomi/extension/vi/teamlanhlung/TeamLanhLung.kt +++ b/src/vi/teamlanhlung/src/eu/kanade/tachiyomi/extension/vi/teamlanhlung/TeamLanhLung.kt @@ -1,5 +1,240 @@ package eu.kanade.tachiyomi.extension.vi.teamlanhlung -import eu.kanade.tachiyomi.multisrc.a3manga.A3Manga +import android.util.Base64 +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.POST +import eu.kanade.tachiyomi.source.model.FilterList +import eu.kanade.tachiyomi.source.model.MangasPage +import eu.kanade.tachiyomi.source.model.Page +import eu.kanade.tachiyomi.source.model.SChapter +import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.online.ParsedHttpSource +import keiyoushi.utils.parseAs +import okhttp3.FormBody +import okhttp3.Headers +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import org.jsoup.Jsoup +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import rx.Observable +import java.text.SimpleDateFormat +import java.util.Locale +import java.util.TimeZone +import javax.crypto.Cipher +import javax.crypto.SecretKeyFactory +import javax.crypto.spec.IvParameterSpec +import javax.crypto.spec.PBEKeySpec +import javax.crypto.spec.SecretKeySpec -class TeamLanhLung : A3Manga("Team Lạnh Lùng", "https://teamlanhlung3.shop", "vi") +class TeamLanhLung : ParsedHttpSource() { + + override val name: String = "Team Lạnh Lùng" + + override val baseUrl: String = "https://teamlanhlung5.shop" + + override val lang: String = "vi" + + override val supportsLatest: Boolean = false + + override val client: OkHttpClient = network.cloudflareClient + + override fun headersBuilder(): Headers.Builder = super.headersBuilder().add("Referer", "$baseUrl/") + + override fun popularMangaRequest(page: Int): Request = GET("$baseUrl/page/$page/", headers) + + override fun popularMangaSelector() = ".comic-list .comic-item:not(.grayscale-img)" + + override fun popularMangaFromElement(element: Element) = SManga.create().apply { + setUrlWithoutDomain(element.select(".comic-title-link a").attr("href")) + title = element.select(".comic-title").text().trim() + thumbnail_url = element.select(".img-thumbnail").attr("abs:src") + } + + override fun popularMangaNextPageSelector() = "li.next:not(.disabled)" + + override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException() + + override fun latestUpdatesSelector() = throw UnsupportedOperationException() + + override fun latestUpdatesFromElement(element: Element) = throw UnsupportedOperationException() + + override fun latestUpdatesNextPageSelector() = throw UnsupportedOperationException() + + override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { + return when { + query.startsWith(PREFIX_ID_SEARCH) -> { + val id = query.removePrefix(PREFIX_ID_SEARCH).trim() + fetchMangaDetails( + SManga.create().apply { + url = "/truyen-tranh/$id/" + }, + ) + .map { + it.url = "/truyen-tranh/$id/" + MangasPage(listOf(it), false) + } + } + else -> super.fetchSearchManga(page, query, filters) + } + } + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = + POST( + "$baseUrl/wp-admin/admin-ajax.php", + headers, + FormBody.Builder() + .add("action", "searchtax") + .add("keyword", query) + .build(), + ) + + override fun searchMangaSelector(): String = throw UnsupportedOperationException() + + override fun searchMangaFromElement(element: Element): SManga = throw UnsupportedOperationException() + + override fun searchMangaNextPageSelector() = throw UnsupportedOperationException() + + override fun searchMangaParse(response: Response): MangasPage { + val dto = response.parseAs() + + if (!dto.success) { + return MangasPage(emptyList(), false) + } + + val manga = dto.data + .map { + SManga.create().apply { + setUrlWithoutDomain(it.link) + title = it.title + thumbnail_url = it.img + } + } + + return MangasPage(manga, false) + } + + override fun mangaDetailsParse(document: Document) = SManga.create().apply { + title = document.select(".info-title").text() + author = document.select(".comic-info strong:contains(Tác giả) + span").text().trim() + description = document.select(".intro-container .text-justify").text().substringBefore("— Xem Thêm —") + genre = document.select(".comic-info .tags a").joinToString { tag -> + tag.text().split(' ').joinToString(separator = " ") { word -> + word.replaceFirstChar { it.titlecase() } + } + } + thumbnail_url = document.select(".img-thumbnail").attr("abs:src") + + val statusString = document.select(".comic-info strong:contains(Tình trạng) + span").text() + status = when (statusString) { + "Đang tiến hành" -> SManga.ONGOING + "Trọn bộ " -> SManga.COMPLETED + else -> SManga.UNKNOWN + } + } + + override fun chapterListSelector(): String = ".chapter-table table tbody tr" + + override fun chapterFromElement(element: Element) = SChapter.create().apply { + setUrlWithoutDomain(element.select("a").attr("href")) + name = element.select("a .hidden-sm").text() + date_upload = runCatching { + dateFormat.parse(element.select("td").last()!!.text())?.time + }.getOrNull() ?: 0 + } + + protected fun decodeImgList(document: Document): String { + val htmlContentScript = document.selectFirst("script:containsData(htmlContent)")?.html() + ?.substringAfter("var htmlContent=\"") + ?.substringBefore("\";") + ?.replace("\\\"", "\"") + ?.replace("\\\\", "\\") + ?.replace("\\/", "/") + ?: throw Exception("Couldn't find script with image data.") + val htmlContent = htmlContentScript.parseAs() + val ciphertext = Base64.decode(htmlContent.ciphertext, Base64.DEFAULT) + val iv = htmlContent.iv.decodeHex() + val salt = htmlContent.salt.decodeHex() + + val passwordScript = document.selectFirst("script:containsData(chapterHTML)")?.html() + ?: throw Exception("Couldn't find password to decrypt image data.") + val passphrase = passwordScript.substringAfter("var chapterHTML=CryptoJSAesDecrypt('") + .substringBefore("',htmlContent") + .replace("'+'", "") + + val keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM) + val spec = PBEKeySpec(passphrase.toCharArray(), salt, 999, 256) + val keyS = SecretKeySpec(keyFactory.generateSecret(spec).encoded, "AES") + + val cipher = Cipher.getInstance(CIPHER_TRANSFORMATION) + cipher.init(Cipher.DECRYPT_MODE, keyS, IvParameterSpec(iv)) + + 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, element -> + val encryptedUrl = element.attributes().find { it.key.startsWith("data") }?.value + val effectiveUrl = encryptedUrl?.decodeUrl() ?: element.attr("abs:src") + Page(idx, imageUrl = effectiveUrl) + } + } + + 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) { + return null + } + + // 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, ".") + } + } + + override fun imageUrlParse(document: Document) = throw UnsupportedOperationException() + + // https://stackoverflow.com/a/66614516 + private fun String.decodeHex(): ByteArray { + check(length % 2 == 0) { "Must have an even length" } + + return chunked(2) + .map { it.toInt(16).toByte() } + .toByteArray() + } + + companion object { + const val KEY_ALGORITHM = "PBKDF2WithHmacSHA512" + const val CIPHER_TRANSFORMATION = "AES/CBC/PKCS7PADDING" + + const val PREFIX_ID_SEARCH = "id:" + val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.US).apply { + timeZone = TimeZone.getTimeZone("Asia/Ho_Chi_Minh") + } + + 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/lib-multisrc/a3manga/src/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaDto.kt b/src/vi/teamlanhlung/src/eu/kanade/tachiyomi/extension/vi/teamlanhlung/TeamLanhLungDto.kt similarity index 89% rename from lib-multisrc/a3manga/src/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaDto.kt rename to src/vi/teamlanhlung/src/eu/kanade/tachiyomi/extension/vi/teamlanhlung/TeamLanhLungDto.kt index 1f8000df3..9b685e1cc 100644 --- a/lib-multisrc/a3manga/src/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaDto.kt +++ b/src/vi/teamlanhlung/src/eu/kanade/tachiyomi/extension/vi/teamlanhlung/TeamLanhLungDto.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.multisrc.a3manga +package eu.kanade.tachiyomi.extension.vi.teamlanhlung import kotlinx.serialization.Serializable diff --git a/lib-multisrc/a3manga/src/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaUrlActivity.kt b/src/vi/teamlanhlung/src/eu/kanade/tachiyomi/extension/vi/teamlanhlung/TeamLanhLungUrlActivity.kt similarity index 81% rename from lib-multisrc/a3manga/src/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaUrlActivity.kt rename to src/vi/teamlanhlung/src/eu/kanade/tachiyomi/extension/vi/teamlanhlung/TeamLanhLungUrlActivity.kt index 218130652..4b41717f5 100644 --- a/lib-multisrc/a3manga/src/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaUrlActivity.kt +++ b/src/vi/teamlanhlung/src/eu/kanade/tachiyomi/extension/vi/teamlanhlung/TeamLanhLungUrlActivity.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.multisrc.a3manga +package eu.kanade.tachiyomi.extension.vi.teamlanhlung import android.app.Activity import android.content.ActivityNotFoundException @@ -10,7 +10,7 @@ import kotlin.system.exitProcess /* Springboard that accepts https:///truyen-tranh/$id/ intents */ -class A3MangaUrlActivity : Activity() { +class TeamLanhLungUrlActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val pathSegments = intent?.data?.pathSegments @@ -25,10 +25,10 @@ class A3MangaUrlActivity : Activity() { }, ) } catch (e: ActivityNotFoundException) { - Log.e("A3MangaThemeUrlActivity", e.toString()) + Log.e("TeamLanhLungUrlActivity", e.toString()) } } else { - Log.e("A3MangaThemeUrlActivity", "Could not parse URI from intent $intent") + Log.e("TeamLanhLungUrlActivity", "Could not parse URI from intent $intent") } finish()