parent
271c770af0
commit
b5e1e8686d
|
@ -0,0 +1,12 @@
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
|
ext {
|
||||||
|
appName = 'Tachiyomi: HentaiVN'
|
||||||
|
pkgNameSuffix = 'vi.hentaivn'
|
||||||
|
extClass = '.HentaiVN'
|
||||||
|
extVersionCode = 1
|
||||||
|
libVersion = '1.2'
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$rootDir/common.gradle"
|
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 9.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
After Width: | Height: | Size: 79 KiB |
|
@ -0,0 +1,352 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.vi.hentaivn
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.source.model.*
|
||||||
|
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||||
|
import okhttp3.HttpUrl
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import org.jsoup.nodes.Document
|
||||||
|
import org.jsoup.nodes.Element
|
||||||
|
import java.text.ParseException
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
class HentaiVN : ParsedHttpSource() {
|
||||||
|
|
||||||
|
override val baseUrl = "https://hentaivn.net"
|
||||||
|
override val lang = "vi"
|
||||||
|
override val name = "HentaiVN"
|
||||||
|
override val supportsLatest = true
|
||||||
|
override val client: OkHttpClient = network.cloudflareClient
|
||||||
|
|
||||||
|
private val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH)
|
||||||
|
|
||||||
|
override fun chapterFromElement(element: Element): SChapter {
|
||||||
|
val chapter = SChapter.create()
|
||||||
|
element.select("a").first().let {
|
||||||
|
chapter.name = it.select("h2").text()
|
||||||
|
chapter.setUrlWithoutDomain(it.attr("href"))
|
||||||
|
}
|
||||||
|
chapter.date_upload = parseDate(element.select("td:nth-child(2)").text().trim())
|
||||||
|
return chapter
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseDate(dateString: String): Long {
|
||||||
|
val date: Date
|
||||||
|
try {
|
||||||
|
date = dateFormat.parse(dateString)
|
||||||
|
} catch (e: ParseException) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return date.time
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun chapterListSelector() = ".page-info > table.listing > tbody > tr"
|
||||||
|
|
||||||
|
override fun imageUrlParse(document: Document) = ""
|
||||||
|
|
||||||
|
override fun latestUpdatesFromElement(element: Element): SManga {
|
||||||
|
val manga = SManga.create()
|
||||||
|
element.select(".box-description a").first().let {
|
||||||
|
manga.setUrlWithoutDomain(it.attr("href"))
|
||||||
|
manga.title = it.text().trim()
|
||||||
|
}
|
||||||
|
return manga
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun latestUpdatesNextPageSelector() = "ul.pagination > li:contains(Next)"
|
||||||
|
|
||||||
|
override fun latestUpdatesRequest(page: Int): Request {
|
||||||
|
return GET("$baseUrl/chap-moi.html?page=$page", headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun latestUpdatesSelector() = ".main > .block-left > .block-item > ul > li.item"
|
||||||
|
|
||||||
|
override fun mangaDetailsParse(document: Document): SManga {
|
||||||
|
val infoElement = document.select(".main > .page-left > .left-info > .page-info")
|
||||||
|
val manga = SManga.create()
|
||||||
|
manga.author = infoElement.select("p:contains(Tác giả) a").text()
|
||||||
|
manga.description = infoElement.select(":root > p:contains(Nội dung) +p").text()
|
||||||
|
manga.genre = infoElement.select("p:contains(Thể loại) a").joinToString { it.text() }
|
||||||
|
manga.thumbnail_url = document.select(".main > .page-right > .right-info > .page-ava > img").attr("src")
|
||||||
|
manga.status = parseStatus(infoElement.select("p:contains(Tình Trạng) a").first().text())
|
||||||
|
return manga
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseStatus(status: String) = when {
|
||||||
|
status.contains("Đang tiến hành") -> SManga.ONGOING
|
||||||
|
status.contains("Đã hoàn thành") -> SManga.COMPLETED
|
||||||
|
else -> SManga.UNKNOWN
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pageListParse(document: Document) = document.select("#image > img").mapIndexed { i, element -> Page(i, "", element.attr("src")) }
|
||||||
|
|
||||||
|
override fun popularMangaFromElement(element: Element) = latestUpdatesFromElement(element)
|
||||||
|
|
||||||
|
override fun popularMangaNextPageSelector() = latestUpdatesNextPageSelector()
|
||||||
|
|
||||||
|
override fun popularMangaRequest(page: Int): Request {
|
||||||
|
return GET("$baseUrl/tieu-diem.html?page=$page", headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popularMangaSelector() = latestUpdatesSelector()
|
||||||
|
|
||||||
|
override fun searchMangaFromElement(element: Element): SManga {
|
||||||
|
val manga = SManga.create()
|
||||||
|
element.select(".search-des > a").first().let {
|
||||||
|
manga.setUrlWithoutDomain(it.attr("href"))
|
||||||
|
manga.title = it.text().trim()
|
||||||
|
}
|
||||||
|
return manga
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun searchMangaNextPageSelector() = "ul.pagination > li:contains(Cuối)"
|
||||||
|
|
||||||
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
|
val url = HttpUrl.parse("$baseUrl/forum/search-plus.php?name=$query&page=$page&dou=&char=&group=0&search=")!!.newBuilder()
|
||||||
|
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
|
||||||
|
when (filter) {
|
||||||
|
is TextField -> url.addQueryParameter(filter.key, filter.state)
|
||||||
|
is GenreList -> filter.state
|
||||||
|
.filter { it.state }
|
||||||
|
.map { it.id }
|
||||||
|
.forEach { url.addQueryParameter("tag[]", it) }
|
||||||
|
is GroupList -> {
|
||||||
|
val group = getGroupList()[filter.state]
|
||||||
|
url.addQueryParameter("group", group.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GET(url.toString(), headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun searchMangaSelector() = "#container .search-li"
|
||||||
|
|
||||||
|
private class TextField(name: String, val key: String) : Filter.Text(name)
|
||||||
|
private class Genre(name: String, val id: String) : Filter.CheckBox(name)
|
||||||
|
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Thể loại", genres)
|
||||||
|
private class TransGroup(name: String, val id: String) : Filter.CheckBox(name) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private class GroupList(groups: Array<TransGroup>) : Filter.Select<TransGroup>("Nhóm dịch", groups)
|
||||||
|
|
||||||
|
override fun getFilterList() = FilterList(
|
||||||
|
TextField("Doujinshi", "dou"),
|
||||||
|
TextField("Nhân vật", "char"),
|
||||||
|
GenreList(getGenreList()),
|
||||||
|
GroupList(getGroupList())
|
||||||
|
)
|
||||||
|
|
||||||
|
// jQuery.makeArray($('#container > div > div > div.box-box.textbox > form > ul:nth-child(7) > li').map((i, e) => `Genre("${e.textContent}", "${e.children[0].value}")`)).join(',\n')
|
||||||
|
// https://hentaivn.net/forum/search-plus.php
|
||||||
|
private fun getGenreList() = listOf(
|
||||||
|
Genre("3D Hentai", "3"),
|
||||||
|
Genre("Action", "5"),
|
||||||
|
Genre("Adult", "116"),
|
||||||
|
Genre("Adventure", "203"),
|
||||||
|
Genre("Ahegao", "20"),
|
||||||
|
Genre("Anal", "21"),
|
||||||
|
Genre("Angel", "249"),
|
||||||
|
Genre("Ảnh động", "131"),
|
||||||
|
Genre("Animal", "127"),
|
||||||
|
Genre("Animal girl", "22"),
|
||||||
|
Genre("Artist", "115"),
|
||||||
|
Genre("BBW", "251"),
|
||||||
|
Genre("BDSM", "24"),
|
||||||
|
Genre("Bestiality", "25"),
|
||||||
|
Genre("Big Ass", "133"),
|
||||||
|
Genre("Big Boobs", "23"),
|
||||||
|
Genre("Big Penis", "32"),
|
||||||
|
Genre("Bloomers", "27"),
|
||||||
|
Genre("BlowJobs", "28"),
|
||||||
|
Genre("Body Swap", "29"),
|
||||||
|
Genre("Bodysuit", "30"),
|
||||||
|
Genre("Bondage", "254"),
|
||||||
|
Genre("Breast Sucking", "33"),
|
||||||
|
Genre("BreastJobs", "248"),
|
||||||
|
Genre("Brocon", "31"),
|
||||||
|
Genre("Brother", "242"),
|
||||||
|
Genre("Business Suit", "241"),
|
||||||
|
Genre("Catgirls", "39"),
|
||||||
|
Genre("Che ít", "101"),
|
||||||
|
Genre("Che nhiều", "129"),
|
||||||
|
Genre("Cheating", "34"),
|
||||||
|
Genre("Chikan", "35"),
|
||||||
|
Genre("Có che", "100"),
|
||||||
|
Genre("Comedy", "36"),
|
||||||
|
Genre("Comic", "120"),
|
||||||
|
Genre("Condom", "210"),
|
||||||
|
Genre("Cosplay", "38"),
|
||||||
|
Genre("Cousin", "2"),
|
||||||
|
Genre("Dark Skin", "40"),
|
||||||
|
Genre("Demon", "132"),
|
||||||
|
Genre("DemonGirl", "212"),
|
||||||
|
Genre("Devil", "104"),
|
||||||
|
Genre("DevilGirl", "105"),
|
||||||
|
Genre("Dirty", "253"),
|
||||||
|
Genre("Dirty Old Man", "41"),
|
||||||
|
Genre("Double Penetration", "42"),
|
||||||
|
Genre("Doujinshi", "44"),
|
||||||
|
Genre("Drama", "4"),
|
||||||
|
Genre("Drug", "43"),
|
||||||
|
Genre("Ecchi", "45"),
|
||||||
|
Genre("Elder Sister", "245"),
|
||||||
|
Genre("Elf", "125"),
|
||||||
|
Genre("Exhibitionism", "46"),
|
||||||
|
Genre("Fantasy", "123"),
|
||||||
|
Genre("Father", "243"),
|
||||||
|
Genre("Femdom", "47"),
|
||||||
|
Genre("Fingering", "48"),
|
||||||
|
Genre("Footjob", "108"),
|
||||||
|
Genre("Full Color", "37"),
|
||||||
|
Genre("Furry", "202"),
|
||||||
|
Genre("Futanari", "50"),
|
||||||
|
Genre("Game", "130"),
|
||||||
|
Genre("GangBang", "51"),
|
||||||
|
Genre("Garter Belts", "206"),
|
||||||
|
Genre("Gender Bender", "52"),
|
||||||
|
Genre("Ghost", "106"),
|
||||||
|
Genre("Glasses", "56"),
|
||||||
|
Genre("Group", "53"),
|
||||||
|
Genre("Guro", "55"),
|
||||||
|
Genre("Hairy", "247"),
|
||||||
|
Genre("Handjob", "57"),
|
||||||
|
Genre("Harem", "58"),
|
||||||
|
Genre("HentaiVN", "102"),
|
||||||
|
Genre("Historical", "80"),
|
||||||
|
Genre("Horror", "122"),
|
||||||
|
Genre("Housewife", "59"),
|
||||||
|
Genre("Humiliation", "60"),
|
||||||
|
Genre("Idol", "61"),
|
||||||
|
Genre("Imouto", "244"),
|
||||||
|
Genre("Incest", "62"),
|
||||||
|
Genre("Insect (Côn Trùng)", "26"),
|
||||||
|
Genre("Không che", "99"),
|
||||||
|
Genre("Kimono", "110"),
|
||||||
|
Genre("Loli", "63"),
|
||||||
|
Genre("Maids", "64"),
|
||||||
|
Genre("Manhwa", "114"),
|
||||||
|
Genre("Mature", "119"),
|
||||||
|
Genre("Miko", "124"),
|
||||||
|
Genre("Milf", "126"),
|
||||||
|
Genre("Mind Break", "121"),
|
||||||
|
Genre("Mind Control", "113"),
|
||||||
|
Genre("Monster", "66"),
|
||||||
|
Genre("Monstergirl", "67"),
|
||||||
|
Genre("Mother", "103"),
|
||||||
|
Genre("Nakadashi", "205"),
|
||||||
|
Genre("Netori", "1"),
|
||||||
|
Genre("Non-hen", "201"),
|
||||||
|
Genre("NTR", "68"),
|
||||||
|
Genre("Nurse", "69"),
|
||||||
|
Genre("Old Man", "211"),
|
||||||
|
Genre("Oneshot", "71"),
|
||||||
|
Genre("Oral", "70"),
|
||||||
|
Genre("Osananajimi", "209"),
|
||||||
|
Genre("Paizuri", "72"),
|
||||||
|
Genre("Pantyhose", "204"),
|
||||||
|
Genre("Pregnant", "73"),
|
||||||
|
Genre("Rape", "98"),
|
||||||
|
Genre("Romance", "117"),
|
||||||
|
Genre("Ryona", "207"),
|
||||||
|
Genre("Scat", "134"),
|
||||||
|
Genre("School Uniform", "74"),
|
||||||
|
Genre("SchoolGirl", "75"),
|
||||||
|
Genre("Series", "87"),
|
||||||
|
Genre("Sex Toys", "88"),
|
||||||
|
Genre("Shimapan", "246"),
|
||||||
|
Genre("Short Hentai", "118"),
|
||||||
|
Genre("Shota", "77"),
|
||||||
|
Genre("Shoujo", "76"),
|
||||||
|
Genre("Siscon", "79"),
|
||||||
|
Genre("Sister", "78"),
|
||||||
|
Genre("Slave", "82"),
|
||||||
|
Genre("Sleeping", "213"),
|
||||||
|
Genre("Small Boobs", "84"),
|
||||||
|
Genre("Sports", "83"),
|
||||||
|
Genre("Stockings", "81"),
|
||||||
|
Genre("Supernatural", "85"),
|
||||||
|
Genre("Sweating", "250"),
|
||||||
|
Genre("Swimsuit", "86"),
|
||||||
|
Genre("Teacher", "91"),
|
||||||
|
Genre("Tentacles", "89"),
|
||||||
|
Genre("Time Stop", "109"),
|
||||||
|
Genre("Tomboy", "90"),
|
||||||
|
Genre("Tracksuit", "252"),
|
||||||
|
Genre("Transformation", "256"),
|
||||||
|
Genre("Trap", "92"),
|
||||||
|
Genre("Tsundere", "111"),
|
||||||
|
Genre("Tự sướng", "65"),
|
||||||
|
Genre("Twins", "93"),
|
||||||
|
Genre("Vampire", "107"),
|
||||||
|
Genre("Vanilla", "208"),
|
||||||
|
Genre("Virgin", "95"),
|
||||||
|
Genre("X-ray", "94"),
|
||||||
|
Genre("Yandere", "112"),
|
||||||
|
Genre("Yaoi", "96"),
|
||||||
|
Genre("Yuri", "97"),
|
||||||
|
Genre("Zombie", "128")
|
||||||
|
)
|
||||||
|
|
||||||
|
// jQuery.makeArray($('#container > div > div > div.box-box.textbox > form > ul:nth-child(8) > li').map((i, e) => `TransGroup("${e.textContent}", "${e.children[0].value}")`)).join(',\n')
|
||||||
|
// https://hentaivn.net/forum/search-plus.php
|
||||||
|
private fun getGroupList() = arrayOf(
|
||||||
|
TransGroup("Tất cả", "0"),
|
||||||
|
TransGroup("Đang cập nhật", "1"),
|
||||||
|
TransGroup("Góc Hentai", "3"),
|
||||||
|
TransGroup("Hakihome", "4"),
|
||||||
|
TransGroup("LXERS", "5"),
|
||||||
|
TransGroup("Hentai-Homies", "6"),
|
||||||
|
TransGroup("BUZPLANET", "7"),
|
||||||
|
TransGroup("Trang Sally", "8"),
|
||||||
|
TransGroup("Loli Rules The World", "9"),
|
||||||
|
TransGroup("XXX Inc", "10"),
|
||||||
|
TransGroup("Kobato9x", "11"),
|
||||||
|
TransGroup("Blazing Soul", "12"),
|
||||||
|
TransGroup("TAYXUONG", "13"),
|
||||||
|
TransGroup("[S]ky [G]arden [G]roup", "14"),
|
||||||
|
TransGroup("Bloomer-kun", "15"),
|
||||||
|
TransGroup("DHT", "16"),
|
||||||
|
TransGroup("TruyenHen18", "17"),
|
||||||
|
TransGroup("iHentaiManga", "18"),
|
||||||
|
TransGroup("Quân cảng Kancolle X", "19"),
|
||||||
|
TransGroup("LHMANGA", "20"),
|
||||||
|
TransGroup("Ship of The Dream", "21"),
|
||||||
|
TransGroup("Fallen Angels", "22"),
|
||||||
|
TransGroup("TruyenHentai2H", "23"),
|
||||||
|
TransGroup("Lạc Thiên", "24"),
|
||||||
|
TransGroup("69HENTAIXXX", "25"),
|
||||||
|
TransGroup("DHL", "26"),
|
||||||
|
TransGroup("Hentai-AdutsManga", "27"),
|
||||||
|
TransGroup("Hatsu Kaze Desu Translator Team", "28"),
|
||||||
|
TransGroup("IHentai69", "29"),
|
||||||
|
TransGroup("Zest", "30"),
|
||||||
|
TransGroup("Demon Victory Team", "31"),
|
||||||
|
TransGroup("NTR Victory Team", "32"),
|
||||||
|
TransGroup("Rori Saikou", "33"),
|
||||||
|
TransGroup("Bullet Burn Team", "34"),
|
||||||
|
TransGroup("RE Team", "35"),
|
||||||
|
TransGroup("Rebelliones", "36"),
|
||||||
|
TransGroup("Shinto", "37"),
|
||||||
|
TransGroup("Sexual Paradise", "38"),
|
||||||
|
TransGroup("FA Dislike Team", "39"),
|
||||||
|
TransGroup("Triggered Team", "41"),
|
||||||
|
TransGroup("T.K Translation Team", "42"),
|
||||||
|
TransGroup("Mabu MG", "43"),
|
||||||
|
TransGroup("Team Zentsu", "44"),
|
||||||
|
TransGroup("Sweeter Than Salt", "46"),
|
||||||
|
TransGroup("Cà rà cà rà Cặt", "47"),
|
||||||
|
TransGroup("Paradise Of The Happiness", "48"),
|
||||||
|
TransGroup("Furry Break the 4th Wall", "49"),
|
||||||
|
TransGroup("The Ignite Team", "50"),
|
||||||
|
TransGroup("Cuồng Loli", "51"),
|
||||||
|
TransGroup("Depressed Lolicons Squad - DLS", "52"),
|
||||||
|
TransGroup("Heaven Of The Fuck", "53")
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue