diff --git a/src/vi/truyengihot/AndroidManifest.xml b/src/vi/truyengihot/AndroidManifest.xml new file mode 100644 index 000000000..7436ac50e --- /dev/null +++ b/src/vi/truyengihot/AndroidManifest.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + diff --git a/src/vi/truyengihot/build.gradle b/src/vi/truyengihot/build.gradle new file mode 100644 index 000000000..b69015c83 --- /dev/null +++ b/src/vi/truyengihot/build.gradle @@ -0,0 +1,12 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' + +ext { + extName = 'TruyenGiHot' + pkgNameSuffix = 'vi.truyengihot' + extClass = '.TruyenGiHot' + extVersionCode = 1 + isNsfw = true +} + +apply from: "$rootDir/common.gradle" diff --git a/src/vi/truyengihot/res/mipmap-hdpi/ic_launcher.png b/src/vi/truyengihot/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..075c1c96b Binary files /dev/null and b/src/vi/truyengihot/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/vi/truyengihot/res/mipmap-mdpi/ic_launcher.png b/src/vi/truyengihot/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..e69678a35 Binary files /dev/null and b/src/vi/truyengihot/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/vi/truyengihot/res/mipmap-xhdpi/ic_launcher.png b/src/vi/truyengihot/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..a965e14fa Binary files /dev/null and b/src/vi/truyengihot/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/vi/truyengihot/res/mipmap-xxhdpi/ic_launcher.png b/src/vi/truyengihot/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..d9275ec29 Binary files /dev/null and b/src/vi/truyengihot/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/vi/truyengihot/res/mipmap-xxxhdpi/ic_launcher.png b/src/vi/truyengihot/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..1d1bf08d5 Binary files /dev/null and b/src/vi/truyengihot/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/vi/truyengihot/res/web_hi_res_512.png b/src/vi/truyengihot/res/web_hi_res_512.png new file mode 100644 index 000000000..f21dcfc01 Binary files /dev/null and b/src/vi/truyengihot/res/web_hi_res_512.png differ diff --git a/src/vi/truyengihot/src/eu/kanade/tachiyomi/extension/vi/truyengihot/TruyenGiHot.kt b/src/vi/truyengihot/src/eu/kanade/tachiyomi/extension/vi/truyengihot/TruyenGiHot.kt new file mode 100644 index 000000000..5ce93e9fc --- /dev/null +++ b/src/vi/truyengihot/src/eu/kanade/tachiyomi/extension/vi/truyengihot/TruyenGiHot.kt @@ -0,0 +1,632 @@ +package eu.kanade.tachiyomi.extension.vi.truyengihot + +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 kotlinx.serialization.json.Json +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive +import okhttp3.FormBody +import okhttp3.Headers +import okhttp3.HttpUrl +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.OkHttpClient +import okhttp3.Request +import org.jsoup.Jsoup +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import rx.Observable +import uy.kohesive.injekt.injectLazy +import java.util.Calendar + +class TruyenGiHot : ParsedHttpSource() { + + override val name: String = "TruyenGiHot" + + override val baseUrl: String = "https://truyengihotne.net" + + override val lang: String = "vi" + + override val supportsLatest: Boolean = true + + override val client: OkHttpClient = network.cloudflareClient.newBuilder() + .rateLimit(1) + .build() + + override fun headersBuilder(): Headers.Builder = + super.headersBuilder().add("Referer", "$baseUrl/") + + private val json: Json by injectLazy() + + companion object { + const val PREFIX_ID_SEARCH = "id:" + } + + override fun popularMangaRequest(page: Int): Request = + searchMangaRequest( + page, + "", + FilterList( + SortFilter( + getSortItems(), + Filter.Sort.Selection(2, false) + ) + ) + ) + + override fun popularMangaSelector(): String = searchMangaSelector() + + override fun popularMangaFromElement(element: Element): SManga = + searchMangaFromElement(element) + + override fun popularMangaNextPageSelector(): String = searchMangaNextPageSelector() + + override fun latestUpdatesRequest(page: Int): Request = + searchMangaRequest( + page, + "", + FilterList( + SortFilter( + getSortItems(), + Filter.Sort.Selection(0, false) + ) + ) + ) + + override fun latestUpdatesSelector(): String = searchMangaSelector() + + override fun latestUpdatesFromElement(element: Element): SManga = + searchMangaFromElement(element) + + override fun latestUpdatesNextPageSelector(): String = searchMangaNextPageSelector() + + 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() + if (!id.endsWith(".html")) { + id += ".html" + } + if (!id.startsWith("/")) { + id = "/" + id + } + + fetchMangaDetails( + SManga.create().apply { + url = id + } + ) + .map { MangasPage(listOf(it.apply { url = id }), false) } + } + else -> super.fetchSearchManga(page, query, filters) + } + } + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + val url = + "$baseUrl/tim-kiem-nang-cao.html?listType=table&page=$page".toHttpUrl().newBuilder() + .apply { + val genres = mutableListOf() + val genresEx = mutableListOf() + + addQueryParameter("text_add", query) + + (if (filters.isEmpty()) getFilterList() else filters).forEach { + when (it) { + is UriFilter -> it.addToUri(this) + is GenreFilter -> it.state.forEach { genre -> + when (genre.state) { + Filter.TriState.STATE_INCLUDE -> genres.add(genre.id) + Filter.TriState.STATE_EXCLUDE -> genresEx.add(genre.id) + else -> {} + } + } + else -> {} + } + } + + addQueryParameter("tag_add", genres.joinToString(",")) + addQueryParameter("tag_remove", genresEx.joinToString(",")) + }.build().toString() + return GET(url, headers) + } + + override fun searchMangaSelector(): String = "ul.cw-list li" + + override fun searchMangaFromElement(element: Element): SManga = SManga.create().apply { + val anchor = element.select("span.title a") + setUrlWithoutDomain(anchor.attr("href")) + title = anchor.text() + thumbnail_url = baseUrl + element.select("span.thumb").attr("style") + .substringAfter("url('") + .substringBefore("')") + } + + override fun searchMangaNextPageSelector(): String = "li.page-next a:not(.disabled)" + + override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply { + title = document.select(".cover-title").text() + author = document.select("p.cover-artist:contains(Tác giả) a").joinToString { it.text() } + genre = document.select("a.manga-tags").joinToString { it.text().removePrefix("#") } + thumbnail_url = document.select("div.cover-image img").attr("abs:src") + + val tags = document.select("img.top-tags.top-tags-full").map { + it.attr("src").substringAfterLast("/").substringBefore(".png") + } + status = when { + tags.contains("ongoing") -> SManga.ONGOING + tags.contains("drop") -> SManga.CANCELLED + tags.contains("full") -> SManga.COMPLETED + else -> SManga.UNKNOWN + } + + description = document.select("div.product-synopsis-content").run { + select("p").first()?.prepend("|truyengihay-split|") + text().substringAfter("|truyengihay-split|").substringBefore(" Xem thêm") + } + } + + override fun chapterListSelector(): String = "ul.episode-list li a" + + override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply { + setUrlWithoutDomain(element.attr("href")) + + val infoBlock = element.selectFirst("span.info") + name = infoBlock.select("span.no").text() + date_upload = parseChapterDate(infoBlock.select("span.date").text()) + } + + private fun parseChapterDate(date: String): Long { + val trimmedDate = date.substringBefore(" trước").split(" ") + + val calendar = Calendar.getInstance().apply { + val amount = -trimmedDate[0].toInt() + val field = when (trimmedDate[1]) { + "giây" -> Calendar.SECOND + "phút" -> Calendar.MINUTE + "giờ" -> Calendar.HOUR_OF_DAY + "ngày" -> Calendar.DAY_OF_MONTH + "tuần" -> Calendar.WEEK_OF_MONTH + "tháng" -> Calendar.MONTH + "năm" -> Calendar.YEAR + else -> Calendar.SECOND + } + add(field, amount) + } + + return calendar.timeInMillis + } + + override fun pageListParse(document: Document): List { + val tokenScript = document.selectFirst("script:containsData(_token)")?.data() + ?: throw Exception("Không tìm được token lấy ảnh của chapter") + val token = tokenScript + .substringAfter("_token = \"") + .substringBefore("\";") + + val chapterInfoScript = document.selectFirst("script:containsData(mangaSLUG)")?.data() + ?: throw Exception("Không tìm thấy thông tin của chapter") + val chapterInfo = chapterInfoScript.split(";", "\n").associate { + if (!it.contains("=")) { + return@associate Pair("", "") + } + val kv = it.trim().split("=") + val key = kv[0].removePrefix("var ").trim() + val value = kv[1].trim().removeSurrounding("\"") + Pair(key, value) + } + + val formBody = FormBody.Builder() + .add("token", token) + .add("chapter_id", chapterInfo["cid"]!!) + .add("m_slug", chapterInfo["mangaSLUG"]!!) + .add("m_id", chapterInfo["mangaID"]!!) + .add("chapter", chapterInfo["chapter"]!!) + .add("g_id", chapterInfo["g_id"]!!) + .build() + val request = POST("$baseUrl/frontend_controllers/chapter/content.php", headers, formBody) + val response = client.newCall(request).execute().body!!.use { + it.string() + } + + val pageHtml = json.parseToJsonElement(response).jsonObject["content"]!!.jsonPrimitive.content + val pages = Jsoup.parseBodyFragment(pageHtml, baseUrl) + + if (pages.getElementById("getImage_form") != null) { + throw Exception("Truyện đã bị khoá!") + } + + return Jsoup.parseBodyFragment(pageHtml, baseUrl).select("img").mapIndexed { idx, it -> + Page(idx, imageUrl = it.attr("abs:src")) + } + } + + override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used") + + override fun getFilterList(): FilterList = FilterList( + SearchTypeFilter(), + CategoryFilter(), + PublicationTypeFilter(), + CountryFilter(), + StatusFilter(), + ScanlatorFilter(), + SortFilter(getSortItems()), + GenreFilter(), + ) + + interface UriFilter { + fun addToUri(builder: HttpUrl.Builder) + } + + open class UriPartFilter( + name: String, + private val query: String, + private val vals: Array>, + state: Int = 0, + ) : UriFilter, Filter.Select(name, vals.map { it.first }.toTypedArray(), state) { + override fun addToUri(builder: HttpUrl.Builder) { + builder.addQueryParameter(query, vals[state].second) + } + } + + private class SearchTypeFilter : UriPartFilter( + "Tìm từ khoá theo", + "text_type", + arrayOf( + Pair("Tên truyện", "name"), + Pair("Tác giả", "authors"), + ) + ) + + private class CategoryFilter : UriPartFilter( + "Phân loại", + "type_add", + arrayOf( + Pair("Tất cả", ""), + Pair("Truyện 18+", "truyen-tranh"), + Pair("Ngôn tình", "ngon-tinh") + ) + ) + + private class PublicationTypeFilter : UriPartFilter( + "Thể loại", + "genre_add", + arrayOf( + Pair("Tất cả", ""), + Pair("Manga", "manga"), + Pair("Manhua", "manhua"), + Pair("Manhwa", "manhwa"), + Pair("Tự sáng tác", "tu-sang-tac"), + Pair("Khác", "khac"), + ) + ) + + private class CountryFilter : UriPartFilter( + "Quốc gia", + "country_add", + arrayOf( + Pair("Tất cả", ""), + Pair("Âu Mỹ", "au-my"), + Pair("Hàn Quốc", "han-quoc"), + Pair("Khác", "khac"), + Pair("Nhật Bản", "nhat-ban"), + Pair("Trung Quốc", "trung-quoc"), + Pair("Việt Nam", "viet-nam") + ) + ) + + private class StatusFilter : UriPartFilter( + "Trạng thái", + "status_add", + arrayOf( + Pair("Tất cả", "0"), + Pair("Full", "1"), + Pair("Ongoing", "2"), + Pair("Drop", "3") + ) + ) + + private class SortFilter( + private val vals: Array>, + state: Selection = Selection(2, false), + ) : UriFilter, + Filter.Sort("Sắp xếp", vals.map { it.first }.toTypedArray(), state) { + override fun addToUri(builder: HttpUrl.Builder) { + builder.addQueryParameter("order_add", vals[state?.index ?: 2].second) + builder.addQueryParameter( + "order_by_add", + if (state?.ascending == true) "ASC" else "DESC" + ) + } + } + + private fun getSortItems(): Array> = arrayOf( + Pair("Mới cập nhật", "last_update"), + Pair("Lượt xem", "views"), + Pair("Hot", "total_vote"), + Pair("Vote", "count_vote"), + Pair("Tên A-Z", "name") + ) + + private class Genre(name: String, val id: String) : Filter.TriState(name) + + // console.log([...document.querySelectorAll(".wrapper-search-tag .search-content span")].map(e => `Genre("${e.innerText.trim()}", "${e.dataset.val}")`).join(",\n")) + private class GenreFilter : Filter.Group( + "Chủ đề", + listOf( + Genre("16+", "16"), + Genre("18+", "18"), + Genre("1Vs1", "1vs1"), + Genre("3d", "3d"), + Genre("3some", "3some"), + Genre("Ác nữ", "ac-nu"), + Genre("Ác Quỷ", "ac-quy"), + Genre("Action", "action"), + Genre("Adult", "adult"), + Genre("Adventure", "adventure"), + Genre("ai cập", "ai-cap"), + Genre("Âm Nhạc", "am-nhac"), + Genre("Anh chị em", "anh-chi-em"), + Genre("anh chị em kế", "anh-chi-em-ke"), + Genre("anh hùng", "anh-hung"), + Genre("Anime", "anime"), + Genre("artist cg", "artist-cg"), + Genre("Âu Cổ", "au-co"), + Genre("Bách Hợp", "bach-hop"), + Genre("bad boy", "bad-boy"), + Genre("bạn thân", "ban-than"), + Genre("Bạo Lực", "bao-luc"), + Genre("Bdsm", "bdsm"), + Genre("BE", "be"), + Genre("Bí Ẩn", "bi-an"), + Genre("Bi kịch", "bi-kich"), + Genre("bị vứt bỏ", "bi-vut-bo"), + Genre("big breast", "big-breast"), + Genre("BL/Bách hợp", "bl-bach-hop"), + Genre("blowjobs", "blowjobs"), + Genre("bỏ trốn", "bo-tron"), + Genre("cái chết", "cai-chet"), + Genre("Cận đại", "can-dai"), + Genre("Cấu Huyết", "cau-huyet"), + Genre("Châu Âu", "chau-au"), + Genre("che", "che"), + Genre("Chiến Tranh", "chien-tranh"), + Genre("Chuyển Sinh", "chuyen-sinh"), + Genre("Chuyển Thế", "chuyen-the"), + Genre("Cổ Đại", "co-dai"), + Genre("Cổ Trang", "co-trang"), + Genre("con gái nô", "con-gai-no"), + Genre("con ngoài dã thú", "con-ngoai-da-thu"), + Genre("công sở", "cong-so"), + Genre("Cung Đấu", "cung-dau"), + Genre("đẹp trai Nam chính", "dep-trai-nam-chinh"), + Genre("Dị Giới", "di-gioi"), + Genre("Dị Năng", "di-nang"), + Genre("Điền Văn", "dien-van"), + Genre("dl site", "dl-site"), + Genre("Đô Thị", "do-thi"), + Genre("Đoản Văn", "doan-van"), + Genre("độc ác Nữ chính", "doc-ac-nu-chinh"), + Genre("Drama", "drama"), + Genre("Được nhận nuôi", "duoc-nhan-nuoi"), + Genre("Ecchi", "ecchi"), + Genre("Fantasy", "fantasy"), + Genre("Game", "game"), + Genre("Gây cấn", "gay-can"), + Genre("Gia Đình", "gia-dinh"), + Genre("giả gái/trai", "gia-gai-trai"), + Genre("Giai cấp quý tộc", "giai-cap-quy-toc"), + Genre("giam cầm", "giam-cam"), + Genre("giang hồ", "giang-ho"), + Genre("Hài Hước", "hai-huoc"), + Genre("hàng khủng", "hang-khung"), + Genre("hàng xóm", "hang-xom"), + Genre("Hành Động", "hanh-dong"), + Genre("Harem", "harem"), + Genre("HE", "he"), + Genre("Hệ Thống", "he-thong"), + Genre("Hentai", "hentai"), + Genre("Hiện Đại", "hien-dai"), + Genre("Hiểu lầm", "hieu-lam"), + Genre("Hoán Đổi", "hoan-doi"), + Genre("Hoàng gia", "hoang-gia"), + Genre("Hoạt Hình", "hoat-hinh"), + Genre("Học Đường", "hoc-duong"), + Genre("học sinh", "hoc-sinh"), + Genre("hối hận", "hoi-han"), + Genre("Hồi hộp", "hoi-hop"), + Genre("Huyền Ảo", "huyen-ao"), + Genre("Ít che", "it-che"), + Genre("kaka*page", "kaka-page"), + Genre("khổ dâm", "kho-dam"), + Genre("Khoa Học", "khoa-hoc"), + Genre("không che", "khong-che"), + Genre("Không Màu", "khong-mau"), + Genre("Kiếm Hiệp", "kiem-hiep"), + Genre("Kinh Dị", "kinh-di"), + Genre("Lãng mạn", "lang-man"), + Genre("lezh*n", "lezh-n"), + Genre("Lịch Sử", "lich-su"), + Genre("Light Novel", "light-novel"), + Genre("Live action", "live-action"), + Genre("loạn luân", "loan-luan"), + Genre("Loli", "loli"), + Genre("ma", "ma"), + Genre("Ma Cà Rồng", "ma-ca-rong"), + Genre("mang thai", "mang-thai"), + Genre("Manga", "manga"), + Genre("Manhua", "manhua"), + Genre("Manhwa", "manhwa"), + Genre("Mạt Thế", "mat-the"), + Genre("mẹ kế", "me-ke"), + Genre("Mô tả đế chế", "mo-ta-de-che"), + Genre("mystery", "mystery"), + Genre("nam duy nhất", "nam-duy-nhat"), + Genre("nav*r", "nav-r"), + Genre("nét vẽ Đẹp", "net-ve-dep"), + Genre("Netflix", "netflix"), + Genre("Ngây thơ", "ngay-tho"), + Genre("ngoại tình", "ngoai-tinh"), + Genre("Ngôn Tình", "ngon-tinh"), + Genre("Ngược", "nguoc"), + Genre("người hầu", "nguoi-hau"), + Genre("nhân thú", "nhan-thu"), + Genre("Nhân vật chính", "nhan-vat-chinh"), + Genre("nhân vật game", "nhan-vat-game"), + Genre("Ninja", "ninja"), + Genre("nô lệ", "no-le"), + Genre("ntr", "ntr"), + Genre("Nữ Cường", "nu-cuong"), + Genre("nữ duy nhất", "nu-duy-nhat"), + Genre("Nữ Phụ", "nu-phu"), + Genre("Oan gia", "oan-gia"), + Genre("OE", "oe"), + Genre("old man", "old-man"), + Genre("oneshot", "oneshot"), + Genre("otome game", "otome-game"), + Genre("otp", "otp"), + Genre("phản diện", "phan-dien"), + Genre("Phép Thuật", "phep-thuat"), + Genre("Phiêu Lưu", "phieu-luu"), + Genre("Phim Bộ", "phim-bo"), + Genre("Phim Chiếu Rạp", "phim-chieu-rap"), + Genre("Phim Lẻ", "phim-le"), + Genre("prologue", "prologue"), + Genre("psychological", "psychological"), + Genre("quái vật", "quai-vat"), + Genre("Quân Sự", "quan-su"), + Genre("Quý tộc", "quy-toc"), + Genre("rape", "rape"), + Genre("Sắc", "sac"), + Genre("Sạch", "sach"), + Genre("SE", "se"), + Genre("seinen", "seinen"), + Genre("sex toy", "sex-toy"), + Genre("shoujo", "shoujo"), + Genre("Shoujo Ai", "shoujo-ai"), + Genre("Siêu Năng Lực", "sieu-nang-luc"), + Genre("slice of life", "slice-of-life"), + Genre("Smut", "smut"), + Genre("Sở thích tra tấn", "so-thich-tra-tan"), + Genre("Sủng", "sung"), + Genre("supernatural", "supernatural"), + Genre("tái sinh", "tai-sinh"), + Genre("Tâm Lý", "tam-ly"), + Genre("thẩm du", "tham-du"), + Genre("Thám Hiểm", "tham-hiem"), + Genre("Thần Thoại", "than-thoai"), + Genre("thánh nữ", "thanh-nu"), + Genre("thanh xuân vườn trường", "thanh-xuan-vuon-truong"), + Genre("thầy/cô giáo", "thay-co-giao"), + Genre("thay Đổi cốt truyện", "thay-doi-cot-truyen"), + Genre("thay Đổi giới tính", "thay-doi-gioi-tinh"), + Genre("Thể Thao", "the-thao"), + Genre("thuần hóa", "thuan-hoa"), + Genre("Tiên Hiệp", "tien-hiep"), + Genre("Tiểu Thuyết", "tieu-thuyet"), + Genre("Tình Cảm", "tinh-cam"), + Genre("Tình Tay Ba", "tinh-tay-ba"), + Genre("Tổng Tài", "tong-tai"), + Genre("trà xanh", "tra-xanh"), + Genre("Trailer", "trailer"), + Genre("Trinh Thám", "trinh-tham"), + Genre("Trọng Sinh", "trong-sinh"), + Genre("Truyện Màu", "truyen-mau"), + Genre("tsundere", "tsundere"), + Genre("Tự Sáng Tác", "tu-sang-tac"), + Genre("tưởng tượng", "tuong-tuong"), + Genre("tuyển tập", "tuyen-tap"), + Genre("vị hôn thê", "vi-hon-the"), + Genre("Việt Nam", "viet-nam"), + Genre("Võ Thuật", "vo-thuat"), + Genre("Vũ Trụ", "vu-tru"), + Genre("Webtoon", "webtoon"), + Genre("xúc tua", "xuc-tua"), + Genre("Xuyên Không", "xuyen-khong"), + Genre("Xuyên không/Trọng sinh", "xuyen-khong-trong-sinh"), + Genre("Yandere", "yandere"), + Genre("Yuri", "yuri") + ) + ) + + // console.log([...document.querySelectorAll(".wrapper-search-group .search-content span")].map(e => `Pair("${e.innerText.trim()}", "${e.dataset.val}")`).join(",\n")) + private class ScanlatorFilter : UriPartFilter( + "Nhóm dịch", + "group_add", + arrayOf( + Pair("Tất cả", "0"), + Pair("Aling - Tiểu Thuyết", "383"), + Pair("Angela Diệp Lạc", "361"), + Pair("AUTHOR TIỂU MÂY", "362"), + Pair("Boom novel", "403"), + Pair("Cà chua Team", "421"), + Pair("Camellia", "300"), + Pair("Cậu Muốn Review Gì Nào?", "342"), + Pair("Chloe's Library", "392"), + Pair("Delion", "376"), + Pair("Ecchi Land", "26"), + Pair("Fluer", "396"), + Pair("Gangster", "327"), + Pair("Hien serena", "330"), + Pair("Hoạ Y", "417"), + Pair("Khu Vườn Bí Mật Của Rosaria", "401"), + Pair("Laziel", "377"), + Pair("Lazy Bee", "420"), + Pair("Lil Pan", "334"), + Pair("Lindy", "399"), + Pair("Lọ Lem Hangul", "6"), + Pair("Lycoris Radiata - Tiểu Hoa", "407"), + Pair("MARY CƠM TRÓ", "423"), + Pair("Mary Hạ Lục", "38"), + Pair("Mây", "349"), + Pair("Mảy Dus GL", "425"), + Pair("Mảy Lành Mạnh", "424"), + Pair("Mây Mây", "409"), + Pair("meoluoihamchoi", "385"), + Pair("Miêu Tặc", "343"), + Pair("Mộc Trà", "306"), + Pair("Một Chiếc Mèo Màu Đen", "390"), + Pair("Nam Tử Sa Page", "20"), + Pair("Nô Vồ", "393"), + Pair("NỒI CƠM TRÓ", "382"), + Pair("NỒI CƠM TRÓ 18+", "426"), + Pair("Ổ Của Sien", "321"), + Pair("Reviewer", "369"), + Pair("Reviews", "419"), + Pair("RINNIE", "341"), + Pair("Rose The One", "337"), + Pair("Roselight Team", "402"), + Pair("Song Tử", "305"), + Pair("The Present Translator", "404"), + Pair("Thiên Mộc Thất Tú", "304"), + Pair("Thư Viện Latsya", "370"), + Pair("Tiệm Kẹo Dẻo Ngòn Ngon", "418"), + Pair("Tiểu Miêu Ngốc", "395"), + Pair("Tiểu Thuyết Nhà Mây", "347"), + Pair("Tiểu Vũ", "360"), + Pair("TIỂU VY", "388"), + Pair("tieu.yet", "355"), + Pair("Trà Và Bánh", "40"), + Pair("Traham", "319"), + Pair("Truyện dịch Team Behira", "410"), + Pair("Truyện Tổng Hợp", "23"), + Pair("Windyzzz", "379"), + Pair("Xóm Bán Hoa", "364"), + Pair("Yu", "406"), + Pair("Đào Lý Tửu", "345"), + Pair("Đảo San Hô", "397"), + Pair("Điền Thất", "373") + ) + ) +} diff --git a/src/vi/truyengihot/src/eu/kanade/tachiyomi/extension/vi/truyengihot/TruyenGiHotUrlActivity.kt b/src/vi/truyengihot/src/eu/kanade/tachiyomi/extension/vi/truyengihot/TruyenGiHotUrlActivity.kt new file mode 100644 index 000000000..f2b2842cb --- /dev/null +++ b/src/vi/truyengihot/src/eu/kanade/tachiyomi/extension/vi/truyengihot/TruyenGiHotUrlActivity.kt @@ -0,0 +1,34 @@ +package eu.kanade.tachiyomi.extension.vi.truyengihot + +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 TruyenGiHotUrlActivity : Activity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val pathSegments = intent?.data?.pathSegments + if (pathSegments != null && pathSegments.size > 0) { + val id = pathSegments[0] + try { + startActivity( + Intent().apply { + action = "eu.kanade.tachiyomi.SEARCH" + putExtra("query", "${TruyenGiHot.PREFIX_ID_SEARCH}$id") + putExtra("filter", packageName) + } + ) + } catch (e: ActivityNotFoundException) { + Log.e("TruyenGiHotUrlActivity", e.toString()) + } + } else { + Log.e("TruyenGiHotUrlActivity", "Could not parse URI from intent $intent") + } + + finish() + exitProcess(0) + } +}