diff --git a/.run/A3MangaGenerator.run.xml b/.run/A3MangaGenerator.run.xml
new file mode 100644
index 000000000..c72cdcdba
--- /dev/null
+++ b/.run/A3MangaGenerator.run.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/multisrc/overrides/a3manga/a3manga/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/a3manga/a3manga/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..c232b90b3
Binary files /dev/null and b/multisrc/overrides/a3manga/a3manga/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/a3manga/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/a3manga/a3manga/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..c5422b58d
Binary files /dev/null and b/multisrc/overrides/a3manga/a3manga/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/a3manga/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/a3manga/a3manga/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..720e67f3d
Binary files /dev/null and b/multisrc/overrides/a3manga/a3manga/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/a3manga/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/a3manga/a3manga/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..bf3ce20a6
Binary files /dev/null and b/multisrc/overrides/a3manga/a3manga/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/a3manga/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/a3manga/a3manga/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..be7125539
Binary files /dev/null and b/multisrc/overrides/a3manga/a3manga/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/a3manga/res/web_hi_res_512.png b/multisrc/overrides/a3manga/a3manga/res/web_hi_res_512.png
new file mode 100644
index 000000000..678499563
Binary files /dev/null and b/multisrc/overrides/a3manga/a3manga/res/web_hi_res_512.png differ
diff --git a/multisrc/overrides/a3manga/default/AndroidManifest.xml b/multisrc/overrides/a3manga/default/AndroidManifest.xml
new file mode 100644
index 000000000..9a92f3a79
--- /dev/null
+++ b/multisrc/overrides/a3manga/default/AndroidManifest.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/multisrc/overrides/a3manga/ngonphong/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/a3manga/ngonphong/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..0c6c219ff
Binary files /dev/null and b/multisrc/overrides/a3manga/ngonphong/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/ngonphong/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/a3manga/ngonphong/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..1626ab78e
Binary files /dev/null and b/multisrc/overrides/a3manga/ngonphong/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/ngonphong/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/a3manga/ngonphong/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..e897210d4
Binary files /dev/null and b/multisrc/overrides/a3manga/ngonphong/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/ngonphong/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/a3manga/ngonphong/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..8100eda75
Binary files /dev/null and b/multisrc/overrides/a3manga/ngonphong/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/ngonphong/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/a3manga/ngonphong/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..d5e88a2ac
Binary files /dev/null and b/multisrc/overrides/a3manga/ngonphong/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/ngonphong/res/web_hi_res_512.png b/multisrc/overrides/a3manga/ngonphong/res/web_hi_res_512.png
new file mode 100644
index 000000000..6e3ea71cc
Binary files /dev/null and b/multisrc/overrides/a3manga/ngonphong/res/web_hi_res_512.png differ
diff --git a/multisrc/overrides/a3manga/ngonphong/src/NgonPhong.kt b/multisrc/overrides/a3manga/ngonphong/src/NgonPhong.kt
new file mode 100644
index 000000000..95f2cfc0a
--- /dev/null
+++ b/multisrc/overrides/a3manga/ngonphong/src/NgonPhong.kt
@@ -0,0 +1,7 @@
+package eu.kanade.tachiyomi.extension.vi.ngonphong
+
+import eu.kanade.tachiyomi.multisrc.a3manga.A3Manga
+
+class NgonPhong : A3Manga("Ngôn Phong", "https://www.ngonphong.com", "vi") {
+ override val id: Long = 7268977637085631557
+}
diff --git a/multisrc/overrides/a3manga/ocumeo/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/a3manga/ocumeo/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..64de658f5
Binary files /dev/null and b/multisrc/overrides/a3manga/ocumeo/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/ocumeo/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/a3manga/ocumeo/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..a50fbf960
Binary files /dev/null and b/multisrc/overrides/a3manga/ocumeo/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/ocumeo/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/a3manga/ocumeo/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..062e4bf96
Binary files /dev/null and b/multisrc/overrides/a3manga/ocumeo/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/ocumeo/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/a3manga/ocumeo/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..e180f6f6e
Binary files /dev/null and b/multisrc/overrides/a3manga/ocumeo/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/ocumeo/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/a3manga/ocumeo/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..dec6ff00c
Binary files /dev/null and b/multisrc/overrides/a3manga/ocumeo/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/ocumeo/res/web_hi_res_512.png b/multisrc/overrides/a3manga/ocumeo/res/web_hi_res_512.png
new file mode 100644
index 000000000..dfff10b7b
Binary files /dev/null and b/multisrc/overrides/a3manga/ocumeo/res/web_hi_res_512.png differ
diff --git a/multisrc/overrides/a3manga/teamlanhlung/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/a3manga/teamlanhlung/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..e1d509058
Binary files /dev/null and b/multisrc/overrides/a3manga/teamlanhlung/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/teamlanhlung/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/a3manga/teamlanhlung/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..c7411cfca
Binary files /dev/null and b/multisrc/overrides/a3manga/teamlanhlung/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/teamlanhlung/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/a3manga/teamlanhlung/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..a123f228c
Binary files /dev/null and b/multisrc/overrides/a3manga/teamlanhlung/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/teamlanhlung/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/a3manga/teamlanhlung/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..b507ebb5d
Binary files /dev/null and b/multisrc/overrides/a3manga/teamlanhlung/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/teamlanhlung/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/a3manga/teamlanhlung/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..70102554b
Binary files /dev/null and b/multisrc/overrides/a3manga/teamlanhlung/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/multisrc/overrides/a3manga/teamlanhlung/res/web_hi_res_512.png b/multisrc/overrides/a3manga/teamlanhlung/res/web_hi_res_512.png
new file mode 100644
index 000000000..bc89f156a
Binary files /dev/null and b/multisrc/overrides/a3manga/teamlanhlung/res/web_hi_res_512.png differ
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
new file mode 100644
index 000000000..512bf63b9
--- /dev/null
+++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/a3manga/A3Manga.kt
@@ -0,0 +1,207 @@
+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("Not used")
+
+ override fun latestUpdatesSelector() = throw UnsupportedOperationException("Not used")
+
+ override fun latestUpdatesFromElement(element: Element) = throw UnsupportedOperationException("Not used")
+
+ override fun latestUpdatesNextPageSelector() = throw UnsupportedOperationException("Not used")
+
+ 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("Not used")
+
+ override fun searchMangaFromElement(element: Element): SManga = throw UnsupportedOperationException("Not used")
+
+ override fun searchMangaNextPageSelector() = throw UnsupportedOperationException("Not used")
+
+ 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 = kotlin.runCatching {
+ dateFormat.parse(element.select("td").last().text())?.time
+ }.getOrNull() ?: 0L
+ }
+
+ override fun pageListParse(document: Document): List {
+ 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 Jsoup.parseBodyFragment(imgListHtml).select("img").mapIndexed { idx, it ->
+ Page(idx, imageUrl = it.attr("abs:src"))
+ }
+ }
+
+ override fun imageUrlParse(document: Document) = throw UnsupportedOperationException("Not used")
+
+ private inline fun Response.parseAs(): T {
+ return json.decodeFromString(body?.string().orEmpty())
+ }
+
+ // 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")
+ }
+ }
+}
diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaDto.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaDto.kt
new file mode 100644
index 000000000..1f8000df3
--- /dev/null
+++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaDto.kt
@@ -0,0 +1,27 @@
+package eu.kanade.tachiyomi.multisrc.a3manga
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class SearchResponseDto(
+ val data: List,
+ val success: Boolean,
+)
+
+@Serializable
+data class SearchEntryDto(
+ val cstatus: String,
+ val img: String,
+ val isocm: Int,
+ val link: String,
+ val star: Float,
+ val title: String,
+ val vote: String,
+)
+
+@Serializable
+data class CipherDto(
+ val ciphertext: String,
+ val iv: String,
+ val salt: String,
+)
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
new file mode 100644
index 000000000..9a0500766
--- /dev/null
+++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaGenerator.kt
@@ -0,0 +1,27 @@
+package eu.kanade.tachiyomi.multisrc.a3manga
+
+import generator.ThemeSourceData.SingleLang
+import generator.ThemeSourceGenerator
+
+class A3MangaGenerator : ThemeSourceGenerator {
+
+ override val themePkg = "a3manga"
+
+ override val themeClass = "A3Manga"
+
+ override val baseVersionCode: Int = 1
+
+ override val sources = listOf(
+ SingleLang("A3 Manga", "https://www.a3mnga.com", "vi"),
+ SingleLang("Team Lanh Lung", "https://teamlanhlung.com", "vi", sourceName = "Team Lạnh Lùng"),
+ 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"),
+ )
+
+ companion object {
+ @JvmStatic
+ fun main(args: Array) {
+ A3MangaGenerator().createAll()
+ }
+ }
+}
diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaUrlActivity.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaUrlActivity.kt
new file mode 100644
index 000000000..936a2d15f
--- /dev/null
+++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/a3manga/A3MangaUrlActivity.kt
@@ -0,0 +1,37 @@
+package eu.kanade.tachiyomi.multisrc.a3manga
+
+import android.app.Activity
+import android.content.ActivityNotFoundException
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import kotlin.system.exitProcess
+
+/*
+ Springboard that accepts https:///truyen-tranh/$id/ intents
+ */
+class A3MangaUrlActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val pathSegments = intent?.data?.pathSegments
+ if (pathSegments != null && pathSegments.size > 1) {
+ val id = pathSegments[1]
+ try {
+ startActivity(
+ Intent().apply {
+ action = "eu.kanade.tachiyomi.SEARCH"
+ putExtra("query", "id:$id")
+ putExtra("filter", packageName)
+ }
+ )
+ } catch (e: ActivityNotFoundException) {
+ Log.e("A3MangaThemeUrlActivity", e.toString())
+ }
+ } else {
+ Log.e("A3MangaThemeUrlActivity", "Could not parse URI from intent $intent")
+ }
+
+ finish()
+ exitProcess(0)
+ }
+}
diff --git a/src/vi/ngonphong/AndroidManifest.xml b/src/vi/ngonphong/AndroidManifest.xml
deleted file mode 100644
index 30deb7f79..000000000
--- a/src/vi/ngonphong/AndroidManifest.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
diff --git a/src/vi/ngonphong/build.gradle b/src/vi/ngonphong/build.gradle
deleted file mode 100644
index d858067a8..000000000
--- a/src/vi/ngonphong/build.gradle
+++ /dev/null
@@ -1,11 +0,0 @@
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-
-ext {
- extName = 'Ngon Phong'
- pkgNameSuffix = 'vi.ngonphong'
- extClass = '.NgonPhong'
- extVersionCode = 1
-}
-
-apply from: "$rootDir/common.gradle"
diff --git a/src/vi/ngonphong/res/mipmap-hdpi/ic_launcher.png b/src/vi/ngonphong/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index a73203efd..000000000
Binary files a/src/vi/ngonphong/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/src/vi/ngonphong/res/mipmap-mdpi/ic_launcher.png b/src/vi/ngonphong/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index 18fd15859..000000000
Binary files a/src/vi/ngonphong/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/src/vi/ngonphong/res/mipmap-xhdpi/ic_launcher.png b/src/vi/ngonphong/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index 5747009a8..000000000
Binary files a/src/vi/ngonphong/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/src/vi/ngonphong/res/mipmap-xxhdpi/ic_launcher.png b/src/vi/ngonphong/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index ce75efef7..000000000
Binary files a/src/vi/ngonphong/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/src/vi/ngonphong/res/mipmap-xxxhdpi/ic_launcher.png b/src/vi/ngonphong/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 34f4ec9df..000000000
Binary files a/src/vi/ngonphong/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/src/vi/ngonphong/res/web_hi_res_512.png b/src/vi/ngonphong/res/web_hi_res_512.png
deleted file mode 100644
index d4e9fee2e..000000000
Binary files a/src/vi/ngonphong/res/web_hi_res_512.png and /dev/null differ
diff --git a/src/vi/ngonphong/src/eu/kanade/tachiyomi/extension/vi/ngonphong/NgonPhong.kt b/src/vi/ngonphong/src/eu/kanade/tachiyomi/extension/vi/ngonphong/NgonPhong.kt
deleted file mode 100644
index c9777068d..000000000
--- a/src/vi/ngonphong/src/eu/kanade/tachiyomi/extension/vi/ngonphong/NgonPhong.kt
+++ /dev/null
@@ -1,137 +0,0 @@
-package eu.kanade.tachiyomi.extension.vi.ngonphong
-
-import eu.kanade.tachiyomi.network.GET
-import eu.kanade.tachiyomi.source.model.FilterList
-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 okhttp3.Headers
-import okhttp3.OkHttpClient
-import okhttp3.Request
-import org.jsoup.nodes.Document
-import org.jsoup.nodes.Element
-import java.text.SimpleDateFormat
-import java.util.Locale
-
-class NgonPhong : ParsedHttpSource() {
-
- override val name = "Ngon Phong"
-
- override val baseUrl = "https://ngonphongcomics.com"
-
- override val lang = "vi"
-
- override val supportsLatest = true
-
- override val client: OkHttpClient = network.cloudflareClient
-
- override fun headersBuilder(): Headers.Builder = super.headersBuilder()
- .add("Referer", baseUrl)
-
- // Popular
-
- override fun popularMangaRequest(page: Int): Request {
- return GET("$baseUrl/danh-sach-truyen/?sort=view&trang=$page", headers)
- }
-
- override fun popularMangaSelector() = "div.comic-item"
-
- override fun popularMangaFromElement(element: Element): SManga {
- return SManga.create().apply {
- element.select(".comic-title-link > a").let {
- title = it.attr("title") ?: it.text()
- setUrlWithoutDomain(it.attr("href"))
- }
- thumbnail_url = element.select("img.img-thumbnail").attr("abs:src")
- }
- }
-
- override fun popularMangaNextPageSelector() = "ul.phantrang li a[title=next]"
-
- // Latest
-
- override fun latestUpdatesRequest(page: Int): Request {
- return GET("$baseUrl/danh-sach-truyen/?sort=latest&trang=$page", headers)
- }
-
- override fun latestUpdatesSelector() = popularMangaSelector()
-
- override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element)
-
- override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
-
- // Search
-
- override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
- return GET("$baseUrl/?s=$query", headers)
- }
-
- override fun searchMangaSelector() = "table.comic-list-table tbody tr"
-
- override fun searchMangaFromElement(element: Element): SManga {
- return SManga.create().apply {
- element.select("a").first().let {
- title = it.text()
- setUrlWithoutDomain(it.attr("href"))
- }
- }
- }
-
- override fun searchMangaNextPageSelector(): String? = null
-
- // Details
-
- override fun mangaDetailsParse(document: Document): SManga {
- return SManga.create().apply {
- document.select("div.comic-intro div.row").let { info ->
- title = info.select("h2").text()
- author = info.select("span.green").text()
- genre = info.select("strong:contains(Thể loại:) ~ a").joinToString { it.text() }
- status = info.select("strong:contains(Tình trạng:) + span").text().toStatus()
- thumbnail_url = info.select("img.img-thumbnail").attr("abs:src")
- }
- description = document.select("div.comic-intro div.row + div p").text()
- }
- }
-
- private fun String.toStatus() = when {
- this.contains("Đang cập nhật", ignoreCase = true) -> SManga.ONGOING
- this.contains("Hoàn thành", ignoreCase = true) -> SManga.COMPLETED
- else -> SManga.UNKNOWN
- }
-
- // Chapters
-
- override fun chapterListSelector() = "table.table tbody tr"
-
- override fun chapterFromElement(element: Element): SChapter {
- return SChapter.create().apply {
- element.select("a").let {
- name = it.text()
- setUrlWithoutDomain(it.attr("href"))
- }
- date_upload = element.select("td:nth-child(2)").text().toChapterDate()
- }
- }
-
- private fun String.toChapterDate(): Long {
- return try {
- SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()).parse(this)?.time ?: 0L
- } catch (_: Exception) {
- 0L
- }
- }
-
- // Pages
-
- override fun pageListParse(document: Document): List {
- return document.select("script:containsData(htmlContent)").first().data().substringAfter("htmlContent=[")
- .substringBefore("];").replace(Regex("""["\\]"""), "").split(",")
- .mapIndexed { i, image -> Page(i, "", image) }
- }
-
- override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used")
-
- override fun getFilterList() = FilterList()
-}