diff --git a/multisrc/overrides/mymangacms/phemanga/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/mymangacms/phemanga/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index 5f47cda3d..000000000
Binary files a/multisrc/overrides/mymangacms/phemanga/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/multisrc/overrides/mymangacms/phemanga/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/mymangacms/phemanga/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index 5622f03a6..000000000
Binary files a/multisrc/overrides/mymangacms/phemanga/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/multisrc/overrides/mymangacms/phemanga/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/mymangacms/phemanga/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index b279d4d2c..000000000
Binary files a/multisrc/overrides/mymangacms/phemanga/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/multisrc/overrides/mymangacms/phemanga/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/mymangacms/phemanga/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index fac42cf6d..000000000
Binary files a/multisrc/overrides/mymangacms/phemanga/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/multisrc/overrides/mymangacms/phemanga/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/mymangacms/phemanga/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 96a63ca6e..000000000
Binary files a/multisrc/overrides/mymangacms/phemanga/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/multisrc/overrides/mymangacms/phemanga/res/web_hi_res_512.png b/multisrc/overrides/mymangacms/phemanga/res/web_hi_res_512.png
deleted file mode 100644
index e7546a5a7..000000000
Binary files a/multisrc/overrides/mymangacms/phemanga/res/web_hi_res_512.png and /dev/null differ
diff --git a/multisrc/overrides/mymangacms/phemanga/src/PheManga.kt b/multisrc/overrides/mymangacms/phemanga/src/PheManga.kt
deleted file mode 100644
index f26e9ff44..000000000
--- a/multisrc/overrides/mymangacms/phemanga/src/PheManga.kt
+++ /dev/null
@@ -1,68 +0,0 @@
-package eu.kanade.tachiyomi.extension.vi.phemanga
-
-import eu.kanade.tachiyomi.multisrc.mymangacms.MyMangaCMS
-
-class PheManga : MyMangaCMS("Phê Manga", "https://phemanga.net", "vi") {
- override fun dateUpdatedParser(date: String): Long =
- runCatching { super.dateUpdatedParser(date.split(" - ")[1]) }.getOrNull() ?: 0L
-
- override fun getGenreList() = listOf(
- Genre("16+", 1),
- Genre("18+", 2),
- Genre("Action", 3),
- Genre("Adult", 4),
- Genre("Adventure", 5),
- Genre("Anime", 6),
- Genre("Comedy", 7),
- Genre("Comic", 8),
- Genre("Doujinshi", 9),
- Genre("Drama", 10),
- Genre("Ecchi", 11),
- Genre("Fantasy", 13),
- Genre("Full màu", 14),
- Genre("Game", 15),
- Genre("Gender Bender", 16),
- Genre("Harem", 17),
- Genre("Historical", 18),
- Genre("Horror", 19),
- Genre("Isekai/Dị giới/Trọng sinh", 20),
- Genre("Josei", 21),
- Genre("Live action", 22),
- Genre("Magic", 23),
- Genre("Manga", 24),
- Genre("Manhua", 25),
- Genre("Manhwa", 26),
- Genre("Martial Arts", 27),
- Genre("Mature", 28),
- Genre("Mecha", 29),
- Genre("Mystery", 30),
- Genre("Nấu Ăn", 31),
- Genre("Ngôn Tình", 32),
- Genre("NTR", 33),
- Genre("One shot", 34),
- Genre("Psychological", 35),
- Genre("Romance", 36),
- Genre("School Life", 37),
- Genre("Sci-fi", 38),
- Genre("Seinen", 39),
- Genre("Shoujo", 40),
- Genre("Shoujo Ai", 41),
- Genre("Shounen", 42),
- Genre("Shounen Ai", 43),
- Genre("Slice of life", 44),
- Genre("Smut", 45),
- Genre("Soft Yaoi", 46),
- Genre("Soft Yuri", 47),
- Genre("Sports", 48),
- Genre("Supernatural", 49),
- Genre("Tạp chí truyện tranh", 50),
- Genre("Tragedy", 51),
- Genre("Trap (Crossdressing)", 52),
- Genre("Trinh Thám", 53),
- Genre("Truyện scan", 54),
- Genre("Tu chân - tu tiên", 55),
- Genre("VnComic", 56),
- Genre("Webtoon", 57),
- Genre("Yuri", 58),
- )
-}
diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt
index c2fddcc97..825df39f7 100644
--- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt
+++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt
@@ -25,7 +25,6 @@ class MadaraGenerator : ThemeSourceGenerator {
SingleLang("247Manga", "https://247manga.com", "en", className = "Manga247", overrideVersionCode = 1),
SingleLang("365Manga", "https://365manga.com", "en", className = "ThreeSixtyFiveManga", overrideVersionCode = 1),
SingleLang("Adonis Fansub", "https://manga.adonisfansub.com", "tr", overrideVersionCode = 1),
- SingleLang("Adult Painful Nightz", "https://adults.painfulnightz.com", "en", isNsfw = true),
SingleLang("Adult Webtoon", "https://adultwebtoon.com", "en", isNsfw = true, overrideVersionCode = 1),
SingleLang("AiYuManga", "https://aiyumangascanlation.com", "es", overrideVersionCode = 1),
SingleLang("Akuma no Tenshi", "https://akumanotenshi.com", "pt-BR", className = "AkumaNoTenshi"),
@@ -211,7 +210,6 @@ class MadaraGenerator : ThemeSourceGenerator {
SingleLang("Manga-Scantrad", "https://manga-scantrad.io", "fr", className = "MangaScantrad", overrideVersionCode = 3),
SingleLang("Manga-TX", "https://manga-tx.com", "en", className = "Mangatxunoriginal"),
SingleLang("Manga18fx", "https://manga18fx.com", "en", isNsfw = true, overrideVersionCode = 5),
- SingleLang("Manga1st", "https://manga1st.com", "en", overrideVersionCode = 2),
SingleLang("Manga1st.online", "https://manga1st.online", "en", className = "MangaFirstOnline", overrideVersionCode = 1),
SingleLang("Manga347", "https://manga347.com", "en", overrideVersionCode = 3),
SingleLang("Manga3S", "https://manga3s.com", "en", overrideVersionCode = 4),
@@ -265,7 +263,6 @@ class MadaraGenerator : ThemeSourceGenerator {
SingleLang("MangaXP", "https://mangaxp.com", "en", overrideVersionCode = 1),
SingleLang("MangaYami", "https://www.mangayami.club", "en", overrideVersionCode = 2),
SingleLang("Manhatic", "https://manhatic.com", "ar", isNsfw = true),
- SingleLang("Manhua Dragon", "https://manhuadragon.com", "en"),
SingleLang("Manhua ES", "https://manhuaes.com", "en", overrideVersionCode = 6),
SingleLang("Manhua Kiss", "https://manhuakiss.com", "en", isNsfw = true, overrideVersionCode = 1),
SingleLang("Manhua Plus", "https://manhuaplus.com", "en", overrideVersionCode = 6),
diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mmrcms/MMRCMSGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mmrcms/MMRCMSGenerator.kt
index 561812dd7..856d6cd2a 100644
--- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mmrcms/MMRCMSGenerator.kt
+++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mmrcms/MMRCMSGenerator.kt
@@ -20,7 +20,6 @@ class MMRCMSGenerator : ThemeSourceGenerator {
SingleLang("Scan VF", "https://www.scan-vf.net", "fr", overrideVersionCode = 1),
SingleLang("Scan OP", "https://scan-op.cc", "fr"),
SingleLang("Komikid", "https://www.komikid.com", "id"),
- SingleLang("Fallen Angels Scans", "https://truyen.fascans.com", "vi"),
SingleLang("Mangadoor", "https://mangadoor.com", "es", overrideVersionCode = 1),
SingleLang("Utsukushii", "https://manga.utsukushii-bg.com", "bg", overrideVersionCode = 1),
SingleLang("Phoenix-Scans", "https://phoenix-scans.pl", "pl", className = "PhoenixScans", overrideVersionCode = 1),
diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mmrcms/SourceData.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mmrcms/SourceData.kt
index dfc6f3387..6e7748716 100644
--- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mmrcms/SourceData.kt
+++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mmrcms/SourceData.kt
@@ -14,7 +14,6 @@ object SourceData {
"https://scan-op.cc" -> """{"name":"Scan OP","base_url":"https://scan-op.cc","supports_latest":true,"item_url":"https://scan-op.cc/manga/","categories":[{"id":"1","name":"Comedy"},{"id":"2","name":"Doujinshi"},{"id":"3","name":"Drama"},{"id":"4","name":"Ecchi"},{"id":"5","name":"Fantasy"},{"id":"6","name":"Gender Bender"},{"id":"7","name":"Josei"},{"id":"8","name":"Mature"},{"id":"9","name":"Mecha"},{"id":"10","name":"Mystery"},{"id":"11","name":"One Shot"},{"id":"12","name":"Psychological"},{"id":"13","name":"Romance"},{"id":"14","name":"School Life"},{"id":"15","name":"Sci-fi"},{"id":"16","name":"Seinen"},{"id":"17","name":"Shoujo"},{"id":"18","name":"Shoujo Ai"},{"id":"19","name":"Shounen"},{"id":"20","name":"Shounen Ai"},{"id":"21","name":"Slice of Life"},{"id":"22","name":"Sports"},{"id":"23","name":"Supernatural"},{"id":"24","name":"Tragedy"},{"id":"25","name":"Yaoi"},{"id":"26","name":"Yuri"},{"id":"27","name":"Comics"},{"id":"28","name":"Autre"}],"tags":[{"id":"nouveau","name":"nouveau"}]}"""
"https://www.komikid.com" -> """{"name":"Komikid","base_url":"https://www.komikid.com","supports_latest":true,"item_url":"https://www.komikid.com/manga/","categories":[{"id":"1","name":"Action"},{"id":"2","name":"Adventure"},{"id":"3","name":"Comedy"},{"id":"4","name":"Doujinshi"},{"id":"5","name":"Drama"},{"id":"6","name":"Fantasy"},{"id":"7","name":"Gender Bender"},{"id":"8","name":"Historical"},{"id":"9","name":"Horror"},{"id":"10","name":"Josei"},{"id":"11","name":"Martial Arts"},{"id":"12","name":"Mature"},{"id":"13","name":"Mecha"},{"id":"14","name":"Mystery"},{"id":"15","name":"One Shot"},{"id":"16","name":"Psychological"},{"id":"17","name":"Romance"},{"id":"18","name":"School Life"},{"id":"19","name":"Sci-fi"},{"id":"20","name":"Seinen"},{"id":"21","name":"Shoujo"},{"id":"22","name":"Shoujo Ai"},{"id":"23","name":"Shounen"},{"id":"24","name":"Shounen Ai"},{"id":"25","name":"Slice of Life"},{"id":"26","name":"Sports"},{"id":"27","name":"Supernatural"},{"id":"28","name":"Tragedy"},{"id":"29","name":"Yaoi"},{"id":"30","name":"Yuri"}]}"""
"http://azbivo.webd.pro" -> """{"name":"Nikushima","base_url":"http://azbivo.webd.pro","supports_latest":false,"item_url":"\u003chtml\u003e \n \u003chead\u003e \n \u003cmeta http-equiv\u003d\"Content-Language\" content\u003d\"pl\"\u003e \n \u003cmeta http-equiv name\u003d\"pragma\" content\u003d\"no-cache\"\u003e \n \u003clink href\u003d\"style/style.css\" rel\u003d\"stylesheet\" type\u003d\"text/css\"\u003e \n \u003cmeta http-equiv\u003d\"Refresh\" content\u003d\"0; url\u003dhttps://www.webd.pl/_errnda.php?utm_source\u003dwn07\u0026amp;utm_medium\u003dwww\u0026amp;utm_campaign\u003dblock\"\u003e \n \u003cmeta name\u003d\"Robots\" content\u003d\"index, follow\"\u003e \n \u003cmeta name\u003d\"revisit-after\" content\u003d\"2 days\"\u003e \n \u003cmeta name\u003d\"rating\" content\u003d\"general\"\u003e \n \u003cmeta name\u003d\"keywords\" content\u003d\"STRONA ZAWIESZONA, WEBD, DOMENY, DOMENA, HOSTING, SERWER, INTERNET, PHP, MySQL, FTP, WEBMASTER, SERWERY WIRTUALNE, WWW, KONTO, MAIL, POCZTA, E-MAIL, NET, .COM, .ORG, TANIE, PHP+MySQL, DOMENY, DOMENA, HOSTING, SERWER, INTERNET, PHP, MySQL, FTP, WEBMASTER, SERWERY WIRTUALNE, WWW, KONTO, MAIL, POCZTA, E-MAIL, DOMENY, DOMENA, NET, .COM, .ORG, TANIE, PHP+MySQL, HOSTING, SERWER, INTERNET, PHP, MySQL, FTP, WEBMASTER, SERWERY WIRTUALNE, WWW, KONTO, MAIL, POCZTA, E-MAIL, NET, .COM, .ORG, TANIE, PHP+MySQL\"\u003e \n \u003cmeta name\u003d\"description\" content\u003d\"STRONA ZAWIESZONA - Oferujemy profesjonalny hosting z PHP + MySQL, rejestrujemy domeny. Sprawdz nasz hosting i przetestuj nasze serwery. Kupuj tanio domeny i serwery!\"\u003e \n \u003ctitle\u003eSTRONA ZAWIESZONA - WEBD.PL - Tw�j profesjonalny hosting za jedyne 4.99PLN! Serwery z PHP+MySQL, tanie domeny, serwer + domena .pl - taniej sie nie da!\u003c/title\u003e \n \u003cscript type\u003d\"text/javascript\"\u003e\nfunction init() {\n if (!document.getElementById) return\n var imgOriginSrc;\n var imgTemp \u003d new Array();\n var imgarr \u003d document.getElementsByTagName(\u0027img\u0027);\n for (var i \u003d 0; i \u003c imgarr.length; i++) {\n if (imgarr[i].getAttribute(\u0027hsrc\u0027)) {\n imgTemp[i] \u003d new Image();\n imgTemp[i].src \u003d imgarr[i].getAttribute(\u0027hsrc\u0027);\n imgarr[i].onmouseover \u003d function() {\n imgOriginSrc \u003d this.getAttribute(\u0027src\u0027);\n this.setAttribute(\u0027src\u0027,this.getAttribute(\u0027hsrc\u0027))\n }\n imgarr[i].onmouseout \u003d function() {\n this.setAttribute(\u0027src\u0027,imgOriginSrc)\n }\n }\n }\n}\nonload\u003dinit;\n\u003c/script\u003e \n \u003c/head\u003e \n \u003cbody\u003e\n Trwa przekierowanie .... \u0026gt;\u0026gt;\u0026gt;\u0026gt; \u003c!--\n--\u003e \n \u003c/body\u003e\n\u003c/html\u003e/","categories":[]}"""
- "https://truyen.fascans.com" -> """{"name":"Fallen Angels Scans","base_url":"https://truyen.fascans.com","supports_latest":true,"item_url":"https://truyen.fascans.com/manga/","categories":[{"id":"1","name":"Action"},{"id":"2","name":"Adventure"},{"id":"3","name":"Comedy"},{"id":"4","name":"Doujinshi"},{"id":"5","name":"Drama"},{"id":"6","name":"Ecchi"},{"id":"7","name":"Fantasy"},{"id":"8","name":"Gender Bender"},{"id":"9","name":"Harem"},{"id":"10","name":"Historical"},{"id":"11","name":"Horror"},{"id":"12","name":"Josei"},{"id":"13","name":"Martial Arts"},{"id":"14","name":"Mature"},{"id":"15","name":"Mecha"},{"id":"16","name":"Mystery"},{"id":"17","name":"One Shot"},{"id":"18","name":"Psychological"},{"id":"19","name":"Romance"},{"id":"20","name":"School Life"},{"id":"21","name":"Sci-fi"},{"id":"22","name":"Seinen"},{"id":"23","name":"Shoujo"},{"id":"24","name":"Shoujo Ai"},{"id":"25","name":"Shounen"},{"id":"26","name":"Shounen Ai"},{"id":"27","name":"Slice of Life"},{"id":"28","name":"Sports"},{"id":"29","name":"Supernatural"},{"id":"30","name":"Tragedy"},{"id":"31","name":"Yaoi"},{"id":"32","name":"Yuri"}]}"""
"https://mangadoor.com" -> """{"name":"Mangadoor","base_url":"https://mangadoor.com","supports_latest":true,"item_url":"https://mangadoor.com/manga/","categories":[{"id":"1","name":"Acción"},{"id":"2","name":"Aventura"},{"id":"3","name":"Comedia"},{"id":"4","name":"Drama"},{"id":"5","name":"Ecchi"},{"id":"6","name":"Fantasía"},{"id":"7","name":"Gender Bender"},{"id":"8","name":"Harem"},{"id":"9","name":"Histórico"},{"id":"10","name":"Horror"},{"id":"11","name":"Josei"},{"id":"12","name":"Artes Marciales"},{"id":"13","name":"Maduro"},{"id":"14","name":"Mecha"},{"id":"15","name":"Misterio"},{"id":"16","name":"One Shot"},{"id":"17","name":"Psicológico"},{"id":"18","name":"Romance"},{"id":"19","name":"Escolar"},{"id":"20","name":"Ciencia Ficción"},{"id":"21","name":"Seinen"},{"id":"22","name":"Shoujo"},{"id":"23","name":"Shoujo Ai"},{"id":"24","name":"Shounen"},{"id":"25","name":"Shounen Ai"},{"id":"26","name":"Recuentos de la vida"},{"id":"27","name":"Deportes"},{"id":"28","name":"Supernatural"},{"id":"29","name":"Tragedia"},{"id":"30","name":"Yaoi"},{"id":"31","name":"Yuri"},{"id":"32","name":"Demonios"},{"id":"33","name":"Juegos"},{"id":"34","name":"Policial"},{"id":"35","name":"Militar"},{"id":"36","name":"Thriller"},{"id":"37","name":"Autos"},{"id":"38","name":"Música"},{"id":"39","name":"Vampiros"},{"id":"40","name":"Magia"},{"id":"41","name":"Samurai"},{"id":"42","name":"Boys love"},{"id":"43","name":"Hentai"}]}"""
"https://mangas.in" -> """{"name":"Mangas.pw","base_url":"https://mangas.in","supports_latest":true,"item_url":"https://mangas.in/manga/","categories":[{"id":"1","name":"Action"},{"id":"2","name":"Adventure"},{"id":"3","name":"Comedy"},{"id":"4","name":"Doujinshi"},{"id":"5","name":"Drama"},{"id":"6","name":"Ecchi"},{"id":"7","name":"Fantasy"},{"id":"8","name":"Gender Bender"},{"id":"9","name":"Harem"},{"id":"10","name":"Historical"},{"id":"11","name":"Horror"},{"id":"12","name":"Josei"},{"id":"13","name":"Martial Arts"},{"id":"14","name":"Mature"},{"id":"15","name":"Mecha"},{"id":"16","name":"Mystery"},{"id":"17","name":"One Shot"},{"id":"18","name":"Psychological"},{"id":"19","name":"Romance"},{"id":"20","name":"School Life"},{"id":"21","name":"Sci-fi"},{"id":"22","name":"Seinen"},{"id":"23","name":"Shoujo"},{"id":"24","name":"Shoujo Ai"},{"id":"25","name":"Shounen"},{"id":"26","name":"Shounen Ai"},{"id":"27","name":"Slice of Life"},{"id":"28","name":"Sports"},{"id":"29","name":"Supernatural"},{"id":"30","name":"Tragedy"},{"id":"31","name":"Yaoi"},{"id":"32","name":"Yuri"},{"id":"33","name":"Hentai"},{"id":"34","name":"Smut"}]}"""
"https://manga.utsukushii-bg.com" -> """{"name":"Utsukushii","base_url":"https://manga.utsukushii-bg.com","supports_latest":true,"item_url":"https://manga.utsukushii-bg.com/manga/","categories":[{"id":"1","name":"Екшън"},{"id":"2","name":"Приключенски"},{"id":"3","name":"Комедия"},{"id":"4","name":"Драма"},{"id":"5","name":"Фентъзи"},{"id":"6","name":"Исторически"},{"id":"7","name":"Ужаси"},{"id":"8","name":"Джосей"},{"id":"9","name":"Бойни изкуства"},{"id":"10","name":"Меха"},{"id":"11","name":"Мистерия"},{"id":"12","name":"Самостоятелна/Пилотна глава"},{"id":"13","name":"Психологически"},{"id":"14","name":"Романтика"},{"id":"15","name":"Училищни"},{"id":"16","name":"Научна фантастика"},{"id":"17","name":"Сейнен"},{"id":"18","name":"Шоджо"},{"id":"19","name":"Реализъм"},{"id":"20","name":"Спорт"},{"id":"21","name":"Свръхестествено"},{"id":"22","name":"Трагедия"},{"id":"23","name":"Йокаи"},{"id":"24","name":"Паралелна вселена"},{"id":"25","name":"Супер сили"},{"id":"26","name":"Пародия"},{"id":"27","name":"Шонен"}]}"""
diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mymangacms/MyMangaCMSGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mymangacms/MyMangaCMSGenerator.kt
index 86d13bbf9..553a4afae 100644
--- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mymangacms/MyMangaCMSGenerator.kt
+++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mymangacms/MyMangaCMSGenerator.kt
@@ -18,14 +18,6 @@ class MyMangaCMSGenerator : ThemeSourceGenerator {
"vi",
overrideVersionCode = 9,
),
- SingleLang(
- "Phê Manga",
- "https://phemanga.net",
- "vi",
- true,
- "PheManga",
- "phemanga",
- ),
SingleLang("LKDTT", "https://lkdttee.com", "vi", true, overrideVersionCode = 4),
)
diff --git a/src/vi/blogtruyen/AndroidManifest.xml b/src/vi/blogtruyen/AndroidManifest.xml
deleted file mode 100644
index f022fb209..000000000
--- a/src/vi/blogtruyen/AndroidManifest.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/vi/blogtruyen/build.gradle b/src/vi/blogtruyen/build.gradle
deleted file mode 100644
index 019391573..000000000
--- a/src/vi/blogtruyen/build.gradle
+++ /dev/null
@@ -1,12 +0,0 @@
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-
-ext {
- extName = 'BlogTruyen'
- pkgNameSuffix = 'vi.blogtruyen'
- extClass = '.BlogTruyen'
- extVersionCode = 14
- isNsfw = true
-}
-
-apply from: "$rootDir/common.gradle"
diff --git a/src/vi/blogtruyen/res/mipmap-hdpi/ic_launcher.png b/src/vi/blogtruyen/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index 08acf9eee..000000000
Binary files a/src/vi/blogtruyen/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/src/vi/blogtruyen/res/mipmap-mdpi/ic_launcher.png b/src/vi/blogtruyen/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index 194bacf6f..000000000
Binary files a/src/vi/blogtruyen/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/src/vi/blogtruyen/res/mipmap-xhdpi/ic_launcher.png b/src/vi/blogtruyen/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index 67f7bc7e5..000000000
Binary files a/src/vi/blogtruyen/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/src/vi/blogtruyen/res/mipmap-xxhdpi/ic_launcher.png b/src/vi/blogtruyen/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 14bf7024a..000000000
Binary files a/src/vi/blogtruyen/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/src/vi/blogtruyen/res/mipmap-xxxhdpi/ic_launcher.png b/src/vi/blogtruyen/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 208871d0b..000000000
Binary files a/src/vi/blogtruyen/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/src/vi/blogtruyen/res/web_hi_res_512.png b/src/vi/blogtruyen/res/web_hi_res_512.png
deleted file mode 100644
index 7ccf314cf..000000000
Binary files a/src/vi/blogtruyen/res/web_hi_res_512.png and /dev/null differ
diff --git a/src/vi/blogtruyen/src/eu/kanade/tachiyomi/extension/vi/blogtruyen/BlogTruyen.kt b/src/vi/blogtruyen/src/eu/kanade/tachiyomi/extension/vi/blogtruyen/BlogTruyen.kt
deleted file mode 100644
index 0c73e9884..000000000
--- a/src/vi/blogtruyen/src/eu/kanade/tachiyomi/extension/vi/blogtruyen/BlogTruyen.kt
+++ /dev/null
@@ -1,432 +0,0 @@
-package eu.kanade.tachiyomi.extension.vi.blogtruyen
-
-import eu.kanade.tachiyomi.network.GET
-import eu.kanade.tachiyomi.network.POST
-import eu.kanade.tachiyomi.network.interceptor.rateLimit
-import eu.kanade.tachiyomi.source.model.Filter
-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 eu.kanade.tachiyomi.util.asJsoup
-import kotlinx.serialization.json.Json
-import kotlinx.serialization.json.jsonArray
-import kotlinx.serialization.json.jsonObject
-import kotlinx.serialization.json.jsonPrimitive
-import okhttp3.FormBody
-import okhttp3.Headers
-import okhttp3.HttpUrl.Companion.toHttpUrl
-import okhttp3.OkHttpClient
-import okhttp3.Request
-import okhttp3.Response
-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
-
-class BlogTruyen : ParsedHttpSource() {
-
- override val name = "BlogTruyen"
-
- override val baseUrl = "https://blogtruyen.vn"
-
- override val lang = "vi"
-
- override val supportsLatest = true
-
- override val client: OkHttpClient = network.cloudflareClient.newBuilder()
- .rateLimit(1)
- .build()
-
- private val json: Json by injectLazy()
-
- private val dateFormat: SimpleDateFormat = SimpleDateFormat("dd/MM/yyyy HH:mm", Locale.ENGLISH)
-
- companion object {
- const val PREFIX_ID_SEARCH = "id:"
- const val PREFIX_AUTHOR_SEARCH = "author:"
- const val PREFIX_TEAM_SEARCH = "team:"
- }
-
- override fun headersBuilder(): Headers.Builder =
- super.headersBuilder().add("Referer", "$baseUrl/")
-
- override fun popularMangaRequest(page: Int): Request =
- GET("$baseUrl/ajax/Search/AjaxLoadListManga?key=tatca&orderBy=3&p=$page", headers)
-
- override fun popularMangaParse(response: Response): MangasPage {
- val document = response.asJsoup()
-
- val manga = document.select(popularMangaSelector()).map {
- val tiptip = it.attr("data-tiptip")
- popularMangaFromElement(it, document.getElementById(tiptip)!!)
- }
-
- val hasNextPage = document.selectFirst(popularMangaNextPageSelector()) != null
-
- return MangasPage(manga, hasNextPage)
- }
-
- override fun popularMangaSelector() = ".list .tiptip"
-
- override fun popularMangaFromElement(element: Element): SManga =
- throw UnsupportedOperationException("Not used")
-
- private fun popularMangaFromElement(element: Element, tiptip: Element) = SManga.create().apply {
- val anchor = element.selectFirst("a")!!
- setUrlWithoutDomain(anchor.attr("href"))
- title = anchor.attr("title").replace("truyện tranh ", "").trim()
-
- thumbnail_url = tiptip.selectFirst("img")!!.attr("abs:src")
- description = tiptip.selectFirst(".al-j")!!.text()
- }
-
- override fun popularMangaNextPageSelector() = ".paging:last-child:not(.current_page)"
-
- override fun latestUpdatesRequest(page: Int): Request =
- GET(baseUrl + if (page != 1) "/page-$page" else "", headers)
-
- override fun latestUpdatesSelector() = ".storyitem .fl-l"
-
- override fun latestUpdatesFromElement(element: Element): SManga = SManga.create().apply {
- setUrlWithoutDomain(element.select("a").attr("href"))
- title = element.select("a").attr("title")
- thumbnail_url = element.select("img").attr("abs:src")
- }
-
- override fun latestUpdatesNextPageSelector() = "select.slcPaging option:last-child:not([selected])"
-
- override fun fetchSearchManga(
- page: Int,
- query: String,
- filters: FilterList,
- ): Observable {
- return when {
- query.startsWith(PREFIX_ID_SEARCH) -> {
- var id = query.removePrefix(PREFIX_ID_SEARCH).trim()
-
- // it's a chapter, resolve to manga ID
- if (id.startsWith("c")) {
- val document = client.newCall(GET("$baseUrl/$id", headers)).execute().asJsoup()
- id = document.selectFirst(".breadcrumbs a:last-child")!!.attr("href").removePrefix("/")
- }
-
- fetchMangaDetails(
- SManga.create().apply {
- url = "/$id"
- },
- )
- .map { MangasPage(listOf(it.apply { url = "/$id" }), false) }
- }
- else -> super.fetchSearchManga(page, query, filters)
- }
- }
-
- private fun extractIdFromQuery(prefix: String, query: String): String {
- val q = query.substringAfter(prefix).trim()
- return if (q.contains("-")) {
- q.substringAfterLast("-")
- } else {
- q
- }
- }
-
- private val ajaxSearchUrls: Map = mapOf(
- PREFIX_AUTHOR_SEARCH to "Author/AjaxLoadMangaByAuthor?orderBy=3",
- PREFIX_TEAM_SEARCH to "TranslateTeam/AjaxLoadMangaByTranslateTeam",
- )
-
- override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
- ajaxSearchUrls.keys.forEach {
- if (!query.startsWith(it)) {
- return@forEach
- }
- val id = extractIdFromQuery(it, query)
- val url = "$baseUrl/ajax/${ajaxSearchUrls[it]}".toHttpUrl().newBuilder()
- .addQueryParameter("id", id)
- .addQueryParameter("p", page.toString())
- .build()
- .toString()
- return GET(url, headers)
- }
-
- val url = "$baseUrl/timkiem/nangcao/1".toHttpUrl().newBuilder().apply {
- addQueryParameter("txt", query)
- addQueryParameter("p", page.toString())
-
- val genres = mutableListOf()
- val genresEx = mutableListOf()
- var status = 0
- (if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
- when (filter) {
- is GenreList -> filter.state.forEach {
- when (it.state) {
- Filter.TriState.STATE_INCLUDE -> genres.add(it.id)
- Filter.TriState.STATE_EXCLUDE -> genresEx.add(it.id)
- else -> {}
- }
- }
- is Author -> {
- addQueryParameter("aut", filter.state)
- }
- is Scanlator -> {
- addQueryParameter("gr", filter.state)
- }
- is Status -> {
- status = filter.state
- }
- else -> {}
- }
- }
-
- addPathSegment(status.toString())
- addPathSegment(genres.joinToString(","))
- addPathSegment(genresEx.joinToString(","))
- }.build().toString()
- return GET(url, headers)
- }
-
- override fun searchMangaParse(response: Response): MangasPage {
- val document = response.asJsoup()
-
- val manga = document.select(searchMangaSelector()).map {
- val tiptip = it.attr("data-tiptip")
- searchMangaFromElement(it, document.getElementById(tiptip)!!)
- }
-
- val hasNextPage = document.selectFirst(searchMangaNextPageSelector()) != null
-
- return MangasPage(manga, hasNextPage)
- }
-
- override fun searchMangaSelector() = popularMangaSelector()
-
- override fun searchMangaFromElement(element: Element): SManga =
- throw UnsupportedOperationException("Not used")
-
- private fun searchMangaFromElement(element: Element, tiptip: Element) =
- popularMangaFromElement(element, tiptip)
-
- override fun searchMangaNextPageSelector() = ".pagination .glyphicon-step-forward"
-
- private fun getMangaTitle(document: Document) = document.selectFirst(".entry-title a")!!
- .attr("title")
- .replaceFirst("truyện tranh", "", false)
- .trim()
-
- override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
- val anchor = document.selectFirst(".entry-title a")!!
- setUrlWithoutDomain(anchor.attr("href"))
- title = getMangaTitle(document)
-
- thumbnail_url = document.select(".thumbnail img").attr("abs:src")
- author = document.select("a[href*=tac-gia]").joinToString { it.text() }
- genre = document.select("span.category a").joinToString { it.text() }
- status = parseStatus(
- document.select("span.color-red:not(.bold)").text(),
- )
-
- description = StringBuilder().apply {
- // the actual synopsis
- val synopsisBlock = document.selectFirst(".manga-detail .detail .content")!!
-
- // replace the facebook blockquote in synopsis with the link (if there is one)
- val fbElement = synopsisBlock.selectFirst(".fb-page, .fb-group")
- if (fbElement != null) {
- val fbLink = fbElement.attr("data-href")
-
- val node = document.createElement("p")
- node.appendText(fbLink)
-
- fbElement.replaceWith(node)
- }
- appendLine(synopsisBlock.textWithNewlines().trim())
- appendLine()
-
- // other metadata
- document.select(".description p").forEach {
- val text = it.text()
- if (text.contains("Thể loại") ||
- text.contains("Tác giả") ||
- text.isBlank()
- ) {
- return@forEach
- }
-
- if (text.contains("Trạng thái")) {
- appendLine(text.substringBefore("Trạng thái").trim())
- return@forEach
- }
-
- if (text.contains("Nguồn") ||
- text.contains("Tham gia update") ||
- text.contains("Nhóm dịch")
- ) {
- val key = text.substringBefore(":")
- val value = it.select("a").joinToString { el -> el.text() }
- appendLine("$key: $value")
- return@forEach
- }
-
- it.select("a, span").append("\\n")
- appendLine(it.text().replace("\\n", "\n").replace("\n ", "\n").trim())
- }
- }.toString().trim()
- }
-
- private fun Element.textWithNewlines() = run {
- select("p").prepend("\\n")
- select("br").prepend("\\n")
- text().replace("\\n", "\n").replace("\n ", "\n")
- }
-
- private fun parseStatus(status: String) = when {
- status.contains("Đang tiến hành") -> SManga.ONGOING
- status.contains("Đã hoàn thành") -> SManga.COMPLETED
- status.contains("Tạm ngưng") -> SManga.ON_HIATUS
- else -> SManga.UNKNOWN
- }
-
- override fun chapterListParse(response: Response): List {
- val document = response.asJsoup()
- val title = getMangaTitle(document)
- return document.select(chapterListSelector()).map { chapterFromElement(it, title) }
- }
-
- override fun chapterListSelector() = "div.list-wrap > p"
-
- override fun chapterFromElement(element: Element): SChapter = throw UnsupportedOperationException("Not used")
-
- private fun chapterFromElement(element: Element, title: String): SChapter = SChapter.create().apply {
- val anchor = element.select("span > a").first()!!
-
- setUrlWithoutDomain(anchor.attr("href"))
- name = anchor.attr("title").replace(title, "", true).trim()
- date_upload = runCatching {
- dateFormat.parse(
- element.selectFirst("span.publishedDate")!!.text(),
- )?.time
- }.getOrNull() ?: 0L
- }
-
- private fun countViewRequest(mangaId: String, chapterId: String): Request = POST(
- "$baseUrl/Chapter/UpdateView",
- headers,
- FormBody.Builder()
- .add("mangaId", mangaId)
- .add("chapterId", chapterId)
- .build(),
- )
-
- private fun countView(document: Document) {
- val mangaId = document.getElementById("MangaId")!!.attr("value")
- val chapterId = document.getElementById("ChapterId")!!.attr("value")
- runCatching {
- client.newCall(countViewRequest(mangaId, chapterId)).execute().close()
- }
- }
-
- override fun pageListParse(document: Document): List {
- val pages = mutableListOf()
-
- document.select("#content > img").forEachIndexed { i, e ->
- pages.add(Page(i, imageUrl = e.attr("abs:src")))
- }
-
- // Some chapters use js script to render images
- document.select("#content > script:containsData(listImageCaption)").lastOrNull()
- ?.let { script ->
- val imagesStr = script.data().substringBefore(";").substringAfterLast("=").trim()
- val imageArr = json.parseToJsonElement(imagesStr).jsonArray
- imageArr.forEach {
- val imageUrl = it.jsonObject["url"]!!.jsonPrimitive.content
- pages.add(Page(pages.size, imageUrl = imageUrl))
- }
- }
-
- countView(document)
- return pages
- }
-
- override fun imageUrlParse(document: Document) = throw UnsupportedOperationException("Not used")
-
- private class Status : Filter.Select(
- "Status",
- arrayOf("Sao cũng được", "Đang tiến hành", "Đã hoàn thành", "Tạm ngưng"),
- )
-
- private class Author : Filter.Text("Tác giả")
- private class Scanlator : Filter.Text("Nhóm dịch")
- private class Genre(name: String, val id: Int) : Filter.TriState(name)
- private class GenreList(genres: List) : Filter.Group("Thể loại", genres)
-
- override fun getFilterList() = FilterList(
- Author(),
- Scanlator(),
- Status(),
- GenreList(getGenreList()),
- )
-
- private fun getGenreList() = listOf(
- Genre("16+", 54),
- Genre("18+", 45),
- Genre("Action", 1),
- Genre("Adult", 2),
- Genre("Adventure", 3),
- Genre("Anime", 4),
- Genre("Comedy", 5),
- Genre("Comic", 6),
- Genre("Doujinshi", 7),
- Genre("Drama", 49),
- Genre("Ecchi", 48),
- Genre("Even BT", 60),
- Genre("Fantasy", 50),
- Genre("Game", 61),
- Genre("Gender Bender", 51),
- Genre("Harem", 12),
- Genre("Historical", 13),
- Genre("Horror", 14),
- Genre("Isekai/Dị Giới", 63),
- Genre("Josei", 15),
- Genre("Live Action", 16),
- Genre("Magic", 46),
- Genre("Manga", 55),
- Genre("Manhua", 17),
- Genre("Manhwa", 18),
- Genre("Martial Arts", 19),
- Genre("Mature", 20),
- Genre("Mecha", 21),
- Genre("Mystery", 22),
- Genre("Nấu ăn", 56),
- Genre("NTR", 62),
- Genre("One shot", 23),
- Genre("Psychological", 24),
- Genre("Romance", 25),
- Genre("School Life", 26),
- Genre("Sci-fi", 27),
- Genre("Seinen", 28),
- Genre("Shoujo", 29),
- Genre("Shoujo Ai", 30),
- Genre("Shounen", 31),
- Genre("Shounen Ai", 32),
- Genre("Slice of Life", 33),
- Genre("Smut", 34),
- Genre("Soft Yaoi", 35),
- Genre("Soft Yuri", 36),
- Genre("Sports", 37),
- Genre("Supernatural", 38),
- Genre("Tạp chí truyện tranh", 39),
- Genre("Tragedy", 40),
- Genre("Trap", 58),
- Genre("Trinh thám", 57),
- Genre("Truyện scan", 41),
- Genre("Video clip", 53),
- Genre("VnComic", 42),
- Genre("Webtoon", 52),
- Genre("Yuri", 59),
- )
-}
diff --git a/src/vi/blogtruyen/src/eu/kanade/tachiyomi/extension/vi/blogtruyen/BlogTruyenUrlActivity.kt b/src/vi/blogtruyen/src/eu/kanade/tachiyomi/extension/vi/blogtruyen/BlogTruyenUrlActivity.kt
deleted file mode 100644
index a5859d34e..000000000
--- a/src/vi/blogtruyen/src/eu/kanade/tachiyomi/extension/vi/blogtruyen/BlogTruyenUrlActivity.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-package eu.kanade.tachiyomi.extension.vi.blogtruyen
-
-import android.app.Activity
-import android.content.ActivityNotFoundException
-import android.content.Intent
-import android.os.Bundle
-import android.util.Log
-import kotlin.system.exitProcess
-
-class BlogTruyenUrlActivity : Activity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- val pathSegments = intent?.data?.pathSegments
- if (pathSegments != null && pathSegments.size > 1) {
- try {
- startActivity(
- Intent().apply {
- action = "eu.kanade.tachiyomi.SEARCH"
- with(pathSegments[0]) {
- when {
- equals("tac-gia") -> putExtra("query", "${BlogTruyen.PREFIX_AUTHOR_SEARCH}${pathSegments[1]}")
- equals("nhom-dich") -> putExtra("query", "${BlogTruyen.PREFIX_TEAM_SEARCH}${pathSegments[1]}")
- else -> putExtra("query", "${BlogTruyen.PREFIX_ID_SEARCH}${pathSegments[0]}/${pathSegments[1]}")
- }
- }
- putExtra("filter", packageName)
- },
- )
- } catch (e: ActivityNotFoundException) {
- Log.e("BlogTruyenUrlActivity", e.toString())
- }
- } else {
- Log.e("BlogTruyenUrlActivity", "Could not parse URI from intent $intent")
- }
-
- finish()
- exitProcess(0)
- }
-}