E-Hentai - tag filtering, browsing changes (#3639)

This commit is contained in:
Mike 2020-06-28 19:34:16 -04:00 committed by GitHub
parent 484fc498e1
commit d8b2c0c368
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 69 additions and 23 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'E-Hentai' extName = 'E-Hentai'
pkgNameSuffix = 'all.ehentai' pkgNameSuffix = 'all.ehentai'
extClass = '.EHFactory' extClass = '.EHFactory'
extVersionCode = 11 extVersionCode = 12
libVersion = '1.2' libVersion = '1.2'
} }

View File

@ -5,6 +5,11 @@ import android.net.Uri
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.Filter.CheckBox
import eu.kanade.tachiyomi.source.model.Filter.Group
import eu.kanade.tachiyomi.source.model.Filter.Select
import eu.kanade.tachiyomi.source.model.Filter.Text
import eu.kanade.tachiyomi.source.model.Filter.TriState
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
@ -29,9 +34,24 @@ open class EHentai(override val lang: String, private val ehLang: String) : Http
override val supportsLatest = true override val supportsLatest = true
// true if lang is a "natural human language"
private fun isLangNatural(): Boolean = lang !in listOf("none", "other")
private fun genericMangaParse(response: Response): MangasPage { private fun genericMangaParse(response: Response): MangasPage {
val doc = response.asJsoup() val doc = response.asJsoup()
val parsedMangas = doc.select("table.itg td.glname").map { val parsedMangas = doc.select("table.itg td.glname")
.let { elements ->
if (isLangNatural()) {
elements.filter { element ->
// only accept elements with a language tag matching ehLang or without a language tag
// could make this stricter and not accept elements without a language tag, possibly add a sharedpreference for it
element.select("div[title^=language]").firstOrNull()?.let { it.text() == ehLang } ?: true
}
} else {
elements
}
}
.map {
SManga.create().apply { SManga.create().apply {
// Get title // Get title
it.select("a")?.first()?.apply { it.select("a")?.first()?.apply {
@ -95,14 +115,26 @@ open class EHentai(override val lang: String, private val ehLang: String) : Http
if (it.text() == ">") it.attr("href") else null if (it.text() == ">") it.attr("href") else null
} }
override fun popularMangaRequest(page: Int) = latestUpdatesRequest(page) private val languageTag = "language:$ehLang"
// This source supports finding popular manga but will not respect language filters on the popular manga page!
// We currently display the latest updates instead until this is fixed override fun popularMangaRequest(page: Int) = if (isLangNatural()) {
// override fun popularMangaRequest(page: Int) = exGet("$baseUrl/toplist.php?tl=15", page) exGet("$baseUrl/?f_search=$languageTag&f_srdd=5&f_sr=on", page)
} else {
latestUpdatesRequest(page)
}
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val uri = Uri.parse("$baseUrl$QUERY_PREFIX").buildUpon() val uri = Uri.parse("$baseUrl$QUERY_PREFIX").buildUpon()
uri.appendQueryParameter("f_search", query) var modifiedQuery = when {
!isLangNatural() -> query
query.isBlank() -> languageTag
else -> "$query,$languageTag"
}
modifiedQuery += filters.filterIsInstance<TagFilter>()
.flatMap { it.markedTags() }
.joinToString(",")
.let { if (it.isNotEmpty()) ",$it" else it }
uri.appendQueryParameter("f_search", modifiedQuery)
filters.forEach { filters.forEach {
if (it is UriFilter) it.addToUri(uri) if (it is UriFilter) it.addToUri(uri)
} }
@ -299,17 +331,20 @@ open class EHentai(override val lang: String, private val ehLang: String) : Http
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
Watched(), Watched(),
GenreGroup(), GenreGroup(),
TagFilter("Misc Tags", triStateBoxesFrom(miscTags), ""),
TagFilter("Female Tags", triStateBoxesFrom(femaleTags), "female"),
TagFilter("Male Tags", triStateBoxesFrom(maleTags), "male"),
AdvancedGroup() AdvancedGroup()
) )
class Watched : Filter.CheckBox("Watched List"), UriFilter { class Watched : CheckBox("Watched List"), UriFilter {
override fun addToUri(builder: Uri.Builder) { override fun addToUri(builder: Uri.Builder) {
if (state) if (state)
builder.appendPath("watched") builder.appendPath("watched")
} }
} }
class GenreOption(name: String, private val genreId: String) : Filter.CheckBox(name, false), UriFilter { class GenreOption(name: String, private val genreId: String) : CheckBox(name, false), UriFilter {
override fun addToUri(builder: Uri.Builder) { override fun addToUri(builder: Uri.Builder) {
builder.appendQueryParameter("f_$genreId", if (state) "1" else "0") builder.appendQueryParameter("f_$genreId", if (state) "1" else "0")
} }
@ -328,14 +363,14 @@ open class EHentai(override val lang: String, private val ehLang: String) : Http
GenreOption("Misc", "misc") GenreOption("Misc", "misc")
)) ))
class AdvancedOption(name: String, private val param: String, defValue: Boolean = false) : Filter.CheckBox(name, defValue), UriFilter { class AdvancedOption(name: String, private val param: String, defValue: Boolean = false) : CheckBox(name, defValue), UriFilter {
override fun addToUri(builder: Uri.Builder) { override fun addToUri(builder: Uri.Builder) {
if (state) if (state)
builder.appendQueryParameter(param, "on") builder.appendQueryParameter(param, "on")
} }
} }
open class PageOption(name: String, private val queryKey: String) : Filter.Text(name), UriFilter { open class PageOption(name: String, private val queryKey: String) : Text(name), UriFilter {
override fun addToUri(builder: Uri.Builder) { override fun addToUri(builder: Uri.Builder) {
if (state.isNotBlank()) { if (state.isNotBlank()) {
if (builder.build().getQueryParameters("f_sp").isEmpty()) { if (builder.build().getQueryParameters("f_sp").isEmpty()) {
@ -351,7 +386,7 @@ open class EHentai(override val lang: String, private val ehLang: String) : Http
class MaxPagesOption : PageOption("Maximum Pages", "f_spt") class MaxPagesOption : PageOption("Maximum Pages", "f_spt")
class RatingOption : class RatingOption :
Filter.Select<String>( Select<String>(
"Minimum Rating", "Minimum Rating",
arrayOf( arrayOf(
"Any", "Any",
@ -385,6 +420,17 @@ open class EHentai(override val lang: String, private val ehLang: String) : Http
MaxPagesOption() MaxPagesOption()
)) ))
private val miscTags = "3d, animated, artbook, comic, forbidden content, full censorship, full color, group, hololive, how to, lvlapple, miwano ragu, model, mosaic censorship, multi-work series, novel, sawan no mole, soushuuhen, square-enix, story arc, tokuohyoe, udan, uncensored, webtoon, western cg, western imageset, western non-h, yukkuri"
private val femaleTags = "ahegao, anal, angel, apron, bandages, bbw, bdsm, beauty mark, big areolae, big ass, big breasts, big clit, big lips, big nipples, bikini, blackmail, bloomers, blowjob, bodysuit, bondage, breast expansion, bukkake, bunny girl, business suit, catgirl, centaur, cheating, chinese dress, christmas, collar, corset, cosplaying, cowgirl, crossdressing, cunnilingus, dark skin, daughter, deepthroat, defloration, demon girl, double penetration, dougi, dragon, drunk, elf, exhibitionism, farting, females only, femdom, filming, fingering, fishnets, footjob, fox girl, furry, futanari, garter belt, ghost, giantess, glasses, gloves, goblin, gothic lolita, growth, guro, gyaru, hair buns, hairy, hairy armpits, handjob, harem, hidden sex, horns, huge breasts, humiliation, impregnation, incest, inverted nipples, kemonomimi, kimono, kissing, lactation, latex, leg lock, leotard, lingerie, lizard girl, maid, masked face, masturbation, midget, miko, milf, mind break, mind control, monster girl, mother, muscle, nakadashi, netorare, nose hook, nun, nurse, oil, paizuri, panda girl, pantyhose, piercing, pixie cut, policewoman, ponytail, pregnant, rape, rimjob, robot, scat, schoolgirl uniform, sex toys, shemale, sister, small breasts, smell, sole dickgirl, sole female, squirting, stockings, sundress, sweating, swimsuit, swinging, tail, tall girl, teacher, tentacles, thigh high boots, tomboy, transformation, twins, twintails, unusual pupils, urination, vore, vtuber, widow, wings, witch, wolf girl, x-ray, yuri, zombie"
private val maleTags = "anal, bbm, big ass, big penis, bikini, blood, blowjob, bondage, catboy, cheating, chikan, condom, crab, crossdressing, dark skin, deepthroat, demon, dickgirl on male, dilf, dog boy, double anal, double penetration, dragon, drunk, exhibitionism, facial hair, feminization, footjob, fox boy, furry, glasses, group, guro, hairy, handjob, hidden sex, horns, huge penis, human on furry, kimono, lingerie, lizard guy, machine, maid, males only, masturbation, mmm threesome, monster, muscle, nakadashi, ninja, octopus, oni, pillory, policeman, possession, prostate massage, public use, schoolboy uniform, schoolgirl uniform, sex toys, shotacon, sleeping, snuff, sole male, stockings, sunglasses, swimsuit, tall man, tentacles, tomgirl, unusual pupils, virginity, waiter, x-ray, yaoi, zombie"
private fun triStateBoxesFrom(tagString: String): List<TagTriState> = tagString.split(", ").map { TagTriState(it) }
class TagTriState(tag: String) : TriState(tag)
class TagFilter(name: String, private val triStateBoxes: List<TagTriState>, private val nameSpace: String) : Group<TagTriState>(name, triStateBoxes) {
fun markedTags() = triStateBoxes.filter { it.isIncluded() }.map { "$nameSpace:${it.name}" } + triStateBoxes.filter { it.isExcluded() }.map { "-$nameSpace:${it.name}" }
}
// map languages to their internal ids // map languages to their internal ids
private val languageMappings = listOf( private val languageMappings = listOf(
Pair("japanese", listOf("0", "1024", "2048")), Pair("japanese", listOf("0", "1024", "2048")),