Doujindesu: Change website appearance (#13605)

* Update build.gradle

Updated extVersionCode

* Update DoujinDesu.kt

* Remove duplicate genre
* Updated and added latest genre available (on Doujindesu website)
* Updated convenience filter
* Waiting for the Doujindesu domain (not the naked IP's)

* Update ParseStatus

* Update Many Feature

- Better Filter
- Add Some Missing Genre's
- Change Genre From `Array` to `List` for Multiple Genre Search
- Update Parse Status

* Update Many Feature 2.0

- Better genre
- Better filter
- Full genre
- Fix ParseStatus

* Blank again

hhmm......
it actualy can be used in automatic refreshing library download, and now they blank again
still confused in basicInformationFromElement 

updates :
fix missing genres

* Description finally showed

but fortunately the status, author, and genres still can't appear

* Apply suggestion and fix mangaDetails

Fixed :
- Stats
- Author
- Artist
- Genres

* Apply suggestion and re-run

* Fix typo
This commit is contained in:
TheKingTermux 2022-10-10 00:12:34 +07:00 committed by GitHub
parent 5d09f08d37
commit 5a820925c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 209 additions and 137 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'DoujinDesu'
pkgNameSuffix = 'id.doujindesu'
extClass = '.DoujinDesu'
extVersionCode = 2
extVersionCode = 3
isNsfw = true
}

View File

@ -30,8 +30,8 @@ class DoujinDesu : ParsedHttpSource() {
}
private fun parseStatus(status: String) = when {
status.lowercase(Locale.US).contains("finished") -> SManga.ONGOING
status.lowercase(Locale.US).contains("publishing") -> SManga.COMPLETED
status.lowercase(Locale.US).contains("publishing") -> SManga.ONGOING
status.lowercase(Locale.US).contains("finished") -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
@ -41,9 +41,9 @@ class DoujinDesu : ParsedHttpSource() {
}
}
private class Genre(title: String, val key: String) : Filter.TriState(title) {
private class Genre(name: String, val id: String = name) : Filter.CheckBox(name) {
override fun toString(): String {
return name
return id
}
}
@ -62,7 +62,6 @@ class DoujinDesu : ParsedHttpSource() {
private val orderBy = arrayOf(
Order("All", ""),
Order("A-Z", "title"),
Order("Z-A", "titlereverse"),
Order("Latest Update", "update"),
Order("Latest Added", "latest"),
Order("Popular", "popular")
@ -74,132 +73,194 @@ class DoujinDesu : ParsedHttpSource() {
Status("Finished", "Finished")
)
private val genreList = arrayOf(
Genre("All", ""),
Genre("Age Regression", "age-regression"),
Genre("Ahegao", "ahegao"),
Genre("All The Way Through", "all-the-way-through"),
Genre("Amputee", "amputee"),
Genre("Anal", "anal"),
Genre("Anorexia", "anorexia"),
Genre("Apron", "apron"),
Genre("Artist CG", "artist-cg"),
Genre("Aunt", "aunt"),
Genre("Bald", "bald"),
Genre("Bestiality", "bestiality"),
Genre("Big As", "big-as"),
Genre("Big Ass", "big-ass"),
Genre("Big Breast", "big-breast"),
Genre("Big Penis", "big-penis"),
Genre("Bike Shorts", "bike-shorts"),
Genre("Bikini", "bikini"),
Genre("Birth", "birth"),
Genre("Bisexual", "bisexual"),
Genre("Blackmail", "blackmail"),
Genre("Blindfold", "blindfold"),
Genre("Bloomers", "bloomers"),
Genre("Blowjob", "blowjob"),
Genre("Body Swap", "body-swap"),
Genre("Bodysuit", "bodysuit"),
Genre("Bondage", "bondage"),
Genre("Business Suit", "business-suit"),
Genre("Cheating", "cheating"),
Genre("Collar", "collar"),
Genre("Condom", "condom"),
Genre("Cousin", "cousin"),
Genre("Crossdressing", "crossdressing"),
Genre("Cunnilingus", "cunnilingus"),
Genre("Dark Skin", "dark-skin"),
Genre("Daughter", "daughter"),
Genre("Defloartion", "defloartion"),
Genre("Defloration", "defloration"),
Genre("Demon", "demon"),
Genre("Demon Girl", "demon-girl"),
Genre("Dick Growth", "dick-growth"),
Genre("DILF", "dilf"),
Genre("Double Penetration", "double-penetration"),
Genre("Drugs", "drugs"),
Genre("Drunk", "drunk"),
Genre("Elf", "elf"),
Genre("Emotionless Sex", "emotionless-sex"),
Genre("Exhibitionism", "exhibitionism"),
Genre("Eyepatch", "eyepatch"),
Genre("Fantasy", "fantasy"),
Genre("Females Only", "females-only"),
Genre("Femdom", "femdom"),
Genre("Filming", "filming"),
Genre("Fingering", "fingering"),
Genre("Footjob", "footjob"),
Genre("Full Color", "full-color"),
Genre("Furry", "furry"),
Genre("Futanari", "futanari"),
Genre("Garter Belt", "garter-belt"),
Genre("Gender Bender", "gender-bender"),
Genre("Ghost", "ghost"),
Genre("Glasses", "glasses"),
Genre("Gore", "gore"),
Genre("Group", "group"),
Genre("Guro", "guro"),
Genre("Gyaru", "gyaru"),
Genre("Hairy", "hairy"),
Genre("Handjob", "handjob"),
Genre("Harem", "harem"),
Genre("Horns", "horns"),
Genre("Huge Breast", "huge-breast"),
Genre("Humiliation", "humiliation"),
Genre("Impregnation", "impregnation"),
Genre("Incest", "incest"),
Genre("Inflation", "inflation"),
Genre("Insect", "insect"),
Genre("Inseki", "inseki"),
Genre("Inverted Nipples", "inverted-nipples"),
Genre("Invisible", "invisible"),
Genre("Kemomimi", "kemomimi"),
Genre("Kimono", "kimono"),
Genre("Lactation", "lactation"),
Genre("Leotard", "leotard"),
Genre("Lingerie", "lingerie"),
Genre("Loli", "loli"),
Genre("Lolipai", "lolipai"),
Genre("Maid", "maid"),
Genre("Males Only", "males-only"),
Genre("Masturbation", "masturbation"),
Genre("Miko", "miko"),
Genre("MILF", "milf"),
Genre("Mind Break", "mind-break"),
Genre("Mind Control", "mind-control"),
Genre("Minigirl", "minigirl"),
Genre("Miniguy", "miniguy"),
Genre("Monster", "monster"),
Genre("Monster Girl", "monster-girl"),
Genre("Mother", "mother"),
Genre("Multi-work Series", "multi-work-series"),
Genre("Muscle", "muscle")
)
private val categoryNames = arrayOf(
Category("All", ""),
Category("Manga", "Manga"),
Category("Manhua", "Manhua"),
Category("Doujinshi", "Doujinshi"),
Category("Manga", "Manga"),
Category("Manhwa", "Manhwa")
)
private fun genreList() = listOf(
Genre("Age Progression"),
Genre("Age Regression"),
Genre("Ahegao"),
Genre("All The Way Through"),
Genre("Amputee"),
Genre("Anal"),
Genre("Anorexia"),
Genre("Apron"),
Genre("Artist CG"),
Genre("Aunt"),
Genre("Bald"),
Genre("Bestiality"),
Genre("Big Ass"),
Genre("Big Breast"),
Genre("Big Penis"),
Genre("Bike Shorts"),
Genre("Bikini"),
Genre("Birth"),
Genre("Bisexual"),
Genre("Blackmail"),
Genre("Blindfold"),
Genre("Bloomers"),
Genre("Blowjob"),
Genre("Body Swap"),
Genre("Bodysuit"),
Genre("Bondage"),
Genre("Bowjob"),
Genre("Business Suit"),
Genre("Cheating"),
Genre("Collar"),
Genre("Collor"),
Genre("Condom"),
Genre("Cousin"),
Genre("Crossdressing"),
Genre("Cunnilingus"),
Genre("Dark Skin"),
Genre("Daughter"),
Genre("Defloartion"),
Genre("Demon"),
Genre("Demon Girl"),
Genre("Dick Growth"),
Genre("DILF"),
Genre("Double Penetration"),
Genre("Drugs"),
Genre("Drunk"),
Genre("Elf"),
Genre("Emotionless Sex"),
Genre("Exhibitionism"),
Genre("Eyepatch"),
Genre("Females Only"),
Genre("Femdom"),
Genre("Filming"),
Genre("Fingering"),
Genre("Footjob"),
Genre("Full Color"),
Genre("Furry"),
Genre("Futanari"),
Genre("Garter Belt"),
Genre("Gender Bender"),
Genre("Ghost"),
Genre("Glasses"),
Genre("Gore"),
Genre("Group"),
Genre("Guro"),
Genre("Gyaru"),
Genre("Hairy"),
Genre("Handjob"),
Genre("Harem"),
Genre("Horns"),
Genre("Huge Breast"),
Genre("Huge Penis"),
Genre("Humiliation"),
Genre("Impregnation"),
Genre("Incest"),
Genre("Inflation"),
Genre("Insect"),
Genre("Inseki"),
Genre("Inverted Nipples"),
Genre("Invisible"),
Genre("Kemomimi"),
Genre("Kimono"),
Genre("Lactation"),
Genre("Leotard"),
Genre("Lingerie"),
Genre("Loli"),
Genre("Lolipai"),
Genre("Maid"),
Genre("Males"),
Genre("Males Only"),
Genre("Masturbation"),
Genre("Miko"),
Genre("MILF"),
Genre("Mind Break"),
Genre("Mind Control"),
Genre("Minigirl"),
Genre("Miniguy"),
Genre("Monster"),
Genre("Monster Girl"),
Genre("Mother"),
Genre("Multi-work Series"),
Genre("Muscle"),
Genre("Nakadashi"),
Genre("Necrophilia"),
Genre("Netorare"),
Genre("Niece"),
Genre("Nipple Fuck"),
Genre("Nurse"),
Genre("Old Man"),
Genre("Only"),
Genre("Oyakodon"),
Genre("Paizuri"),
Genre("Pantyhose"),
Genre("Possession"),
Genre("Pregnant"),
Genre("Prostitution"),
Genre("Rape"),
Genre("Rimjob"),
Genre("Scat"),
Genre("School Uniform"),
Genre("Sex Toys"),
Genre("Shemale"),
Genre("Shota"),
Genre("Sister"),
Genre("Sleeping"),
Genre("Slime"),
Genre("Small Breast"),
Genre("Snuff"),
Genre("Sole Female"),
Genre("Sole Male"),
Genre("Stocking"),
Genre("Story Arc"),
Genre("Sumata"),
Genre("Sweating"),
Genre("Swimsuit"),
Genre("Tanlines"),
Genre("Teacher"),
Genre("Tentacles"),
Genre("Tomboy"),
Genre("Tomgirl"),
Genre("Torture"),
Genre("Twins"),
Genre("Twintails"),
Genre("Uncensored"),
Genre("Unusual Pupils"),
Genre("Virginity"),
Genre("Webtoon"),
Genre("Widow"),
Genre("X-Ray"),
Genre("Yandere"),
Genre("Yaoi"),
Genre("Yuri")
)
private class CategoryNames(categories: Array<Category>) : Filter.Select<Category>("Category", categories, 0)
private class OrderBy(orders: Array<Order>) : Filter.Select<Order>("Order", orders, 0)
private class GenreList(genres: Array<Genre>) : Filter.Select<Genre>("Genre", genres, 0)
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genre", genres)
private class StatusList(statuses: Array<Status>) : Filter.Select<Status>("Status", statuses, 0)
private fun basicInformationFromElement(element: Element): SManga {
val manga = SManga.create()
manga.title = element.select("div > div > a").attr("alt")
manga.setUrlWithoutDomain(element.select("div > div > a").attr("href"))
manga.thumbnail_url = element.select("div > div > a > div > img").attr("src")
element.select("a").let {
manga.title = it.attr("title")
manga.setUrlWithoutDomain(it.attr("href"))
}
element.select("a > figure.thumbnail > img").first()?.let {
manga.thumbnail_url = imageFromElement(it)
}
return manga
}
protected open fun imageFromElement(element: Element): String? {
return when {
element.hasAttr("data-src") -> element.attr("abs:data-src")
element.hasAttr("data-lazy-src") -> element.attr("abs:data-lazy-src")
element.hasAttr("srcset") -> element.attr("abs:srcset").substringBefore(" ")
else -> element.attr("abs:src")
}
}
private fun getNumberFromString(epsStr: String): String {
return epsStr.filter { it.isDigit() }
}
@ -218,7 +279,7 @@ class DoujinDesu : ParsedHttpSource() {
override fun popularMangaFromElement(element: Element): SManga = basicInformationFromElement(element)
override fun popularMangaRequest(page: Int): Request {
return GET("$baseUrl/komik-list/page/$page/?&order=popular")
return GET("$baseUrl/manga/page/$page/?&order=popular", headers)
}
// Latest
@ -226,40 +287,43 @@ class DoujinDesu : ParsedHttpSource() {
override fun latestUpdatesFromElement(element: Element): SManga = basicInformationFromElement(element)
override fun latestUpdatesRequest(page: Int): Request {
return GET("$baseUrl/komik-list/page/$page/?order=update")
return GET("$baseUrl/manga/page/$page/?order=update", headers)
}
// Element Selectors
override fun latestUpdatesSelector(): String = "#main > div.relat > article"
override fun popularMangaSelector(): String = "#main > div.relat > article"
override fun searchMangaSelector(): String = "#main > div.relat > article"
override fun latestUpdatesSelector(): String = "#archives > div.entries > article"
override fun popularMangaSelector(): String = "#archives > div.entries > article"
override fun searchMangaSelector(): String = "#archives > div.entries > article"
override fun popularMangaNextPageSelector(): String = "#nextpagination"
override fun popularMangaNextPageSelector(): String = "nav.pagination > ul > li.last > a"
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
// Search & FIlter
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
var url = "$baseUrl/komik-list/page/$page/".toHttpUrlOrNull()?.newBuilder()!!.addQueryParameter("title", query)
var url = "$baseUrl/manga/page/$page/".toHttpUrlOrNull()?.newBuilder()!!.addQueryParameter("title", query)
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
when (filter) {
is CategoryNames -> {
val category = filter.values[filter.state]
url.addQueryParameter("type", category.key)
url.addQueryParameter("typex", category.key)
}
is OrderBy -> {
val order = filter.values[filter.state]
url.addQueryParameter("order", order.key)
}
is GenreList -> {
val genre = filter.values[filter.state]
url.addQueryParameter("genre", genre.key)
filter.state
.filter { it.state }
.let { list ->
if (list.isNotEmpty()) { list.forEach { genre -> url.addQueryParameter("genre[]", genre.id) } }
}
}
is StatusList -> {
val status = filter.values[filter.state]
url.addQueryParameter("status", status.key)
url.addQueryParameter("statusx", status.key)
}
}
}
@ -269,25 +333,33 @@ class DoujinDesu : ParsedHttpSource() {
override fun searchMangaFromElement(element: Element): SManga = basicInformationFromElement(element)
override fun getFilterList() = FilterList(
Filter.Header("NB: Filter diabaikan jika memakai pencarian teks!"),
Filter.Separator(),
StatusList(statusList),
CategoryNames(categoryNames),
OrderBy(orderBy),
GenreList(genreList),
StatusList(statusList)
GenreList(genreList())
)
// Detail Parse
override fun mangaDetailsParse(document: Document): SManga {
val infoElement = document.select("section.metadata").first()
val manga = SManga.create()
manga.description = when {
document.select("div.infox > div.entry-content.entry-content-single > p").isEmpty() -> "No description specified"
else -> document.select("div.infox > div.entry-content.entry-content-single > p").first().text()
document.select("section.metadata > div.pb-2 > p:nth-child(1)").isEmpty() -> "Tidak ada deskripsi yang tersedia bosque"
else -> document.select("section.metadata > div.pb-2 > p:nth-child(1)").first().text()
}
manga.author = document.select("div.infox > div.spe > span:nth-child(5)").text()
manga.genre = document.select("div.genre-info > a[itemprop=genre]").joinToString { it.text() }
manga.status = parseStatus(document.select("div.infox > div.spe > span:nth-child(1)").text())
manga.thumbnail_url = document.select("div.thumb > img").attr("src")
manga.artist = document.select("div.infox > div.spe > span:nth-child(6)").text()
val genres = mutableListOf<String>()
infoElement.select("div.tags > a").forEach { element ->
val genre = element.text()
genres.add(genre)
}
manga.author = document.select("section.metadata > table:nth-child(2) > tbody > tr.pages > td:contains(Author) + td:nth-child(2) > a").joinToString { it.text() }
manga.genre = infoElement.select("div.tags > a").joinToString { it.text() }
manga.status = parseStatus(document.select("section.metadata > table:nth-child(2) > tbody > tr:nth-child(1) > td:nth-child(2) > a").first().text())
manga.thumbnail_url = document.select("figure.thumbnail > img").attr("src")
manga.artist = document.select("section.metadata > table:nth-child(2) > tbody > tr.pages > td:contains(Character) + td:nth-child(2) > a").joinToString { it.text() }
return manga
}
@ -314,7 +386,7 @@ class DoujinDesu : ParsedHttpSource() {
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not Used")
override fun pageListParse(document: Document): List<Page> {
return document.select("div.reader-area > img").mapIndexed { i, element ->
return document.select("#reader > div.main > div > img").mapIndexed { i, element ->
Page(i, "", element.attr("src"))
}
}