[ExHentai] Improve tags loading

pull/421/head
Koitharu 2 years ago
parent 4e2d739840
commit 7c89f53988
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -1,11 +1,11 @@
package org.koitharu.kotatsu.parsers.site.all
import androidx.collection.ArrayMap
import androidx.collection.ArraySet
import androidx.collection.SparseArrayCompat
import androidx.collection.set
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.jsoup.internal.StringUtil
import org.jsoup.nodes.Element
import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaParserAuthProvider
@ -26,9 +26,8 @@ internal class ExHentaiParser(
context: MangaLoaderContext,
) : PagedMangaParser(context, MangaSource.EXHENTAI, pageSize = 25), MangaParserAuthProvider {
override val availableSortOrders: Set<SortOrder> = Collections.singleton(
SortOrder.NEWEST,
)
override val availableSortOrders: Set<SortOrder> = setOf(SortOrder.NEWEST)
override val isTagsExclusionSupported: Boolean = true
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain(
@ -44,6 +43,7 @@ internal class ExHentaiParser(
private var updateDm = false
private val nextPages = SparseArrayCompat<Long>()
private val suspiciousContentKey = ConfigKey.ShowSuspiciousContent(false)
private val tagsMap = SuspendLazy(::fetchTags)
override val isAuthorized: Boolean
get() {
@ -93,27 +93,18 @@ internal class ExHentaiParser(
is MangaListFilter.Advanced -> {
filter.toSearchQuery()?.let { sq ->
append("&f_search=")
append(sq.urlEncoded())
}
var fCats = 0
if (filter.tags.isNotEmpty()) {
filter.tags.forEach {
if (it.title.startsWith("- ")) {
it.key.toIntOrNull()?.let { fCats = fCats or it } ?: run {
search += it.key + " "
}
} else {
append(" tag:".urlEncoded())
append(it.key)
}
filter.tags.forEach { tag ->
tag.key.toIntOrNull()?.let {
fCats = fCats or it
}
}
if (filter.locale != null) {
append(" language:".urlEncoded())
append(filter.locale.toLanguagePath())
}
if (fCats != 0) {
append("&f_cats=")
append(1023 - fCats)
@ -182,15 +173,14 @@ internal class ExHentaiParser(
val title = root.getElementById("gd2")
val tagList = root.getElementById("taglist")
val tabs = doc.body().selectFirst("table.ptt")?.selectFirst("tr")
val lang =
root.getElementById("gd3")?.selectFirst("tr:contains(Language)")?.selectFirst(".gdt2")?.text() ?: "Unknown"
val lang = root.getElementById("gd3")
?.selectFirst("tr:contains(Language)")
?.selectFirst(".gdt2")?.text()
val tagMap = getOrCreateTagMap()
val tagF =
tagList?.selectFirst("tr:contains(female:)")?.select("a")?.mapNotNullToSet { tagMap[it.text()] }.orEmpty()
val tagM =
tagList?.selectFirst("tr:contains(male:)")?.select("a")?.mapNotNullToSet { tagMap[it.text()] }.orEmpty()
val tags = tagF + tagM
val tagMap = tagsMap.get()
val tags = ArraySet<MangaTag>()
tagList?.selectFirst("tr:contains(female:)")?.select("a")?.mapNotNullTo(tags) { tagMap[it.text()] }
tagList?.selectFirst("tr:contains(male:)")?.select("a")?.mapNotNullTo(tags) { tagMap[it.text()] }
return manga.copy(
title = title?.getElementById("gn")?.text()?.cleanupTitle() ?: manga.title,
@ -265,21 +255,17 @@ internal class ExHentaiParser(
"unusual pupils,urination,vore,vtuber,widow,wings,witch,wolf girl,x-ray,yuri,zombie,sole male,males only,yaoi," +
"tomgirl,tall man,oni,shotacon,prostate massage,policeman,males only,huge penis,fox boy,feminization,dog boy,dickgirl on male,big penis"
private var tagCache: ArrayMap<String, MangaTag>? = null
private val mutex = Mutex()
override suspend fun getAvailableTags(): Set<MangaTag> {
return getOrCreateTagMap().values.toSet()
return tagsMap.get().values.toSet()
}
private suspend fun getOrCreateTagMap(): Map<String, MangaTag> = mutex.withLock {
tagCache?.let { return@withLock it }
private suspend fun fetchTags(): Map<String, MangaTag> {
val tagMap = ArrayMap<String, MangaTag>()
val tagElements = tags.split(",")
for (el in tagElements) {
if (el.isEmpty()) continue
tagMap[el] = MangaTag(
title = el,
title = el.toTitleCase(Locale.ENGLISH),
key = el,
source = source,
)
@ -289,16 +275,14 @@ internal class ExHentaiParser(
val root = doc.body().requireElementById("searchbox").selectFirstOrThrow("table")
root.select("div.cs").mapNotNullToSet { div ->
val id = div.id().substringAfterLast('_').toIntOrNull() ?: return@mapNotNullToSet null
val name = "- " + div.text().toTitleCase()
val name = div.text().toTitleCase(Locale.ENGLISH)
tagMap[name] = MangaTag(
title = name,
key = id.toString(),
source = source,
)
}
tagCache = tagMap
return@withLock tagMap
return tagMap
}
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
@ -403,4 +387,32 @@ internal class ExHentaiParser(
?.queryParameter("next")
?.toLongOrNull() ?: 1
}
private fun MangaListFilter.Advanced.toSearchQuery(): String? {
val joiner = StringUtil.StringJoiner(" ")
for (tag in tags) {
if (tag.key.isNumeric()) {
continue
}
joiner.add("tag:\"")
joiner.append(tag.key)
joiner.append("\"$")
}
for (tag in tagsExclude) {
if (tag.key.isNumeric()) {
continue
}
joiner.add("-tag:\"")
joiner.append(tag.key)
joiner.append("\"$")
}
locale?.let { lc ->
joiner.add("language:\"")
joiner.append(lc.toLanguagePath())
joiner.append("\"$")
}
return joiner.complete().takeUnless { it.isEmpty() }
}
private fun String.isNumeric() = all { c -> c.isDigit() }
}

@ -61,7 +61,11 @@ internal class MangaParserTest {
offset = 0,
filter = MangaListFilter.Advanced(
sortOrder = SortOrder.POPULARITY,
tags = emptySet(), locale = null, states = emptySet(), tagsExclude = emptySet(), contentRating = emptySet()
tags = emptySet(),
locale = null,
states = emptySet(),
tagsExclude = emptySet(),
contentRating = emptySet(),
),
).minByOrNull {
it.title.length
@ -92,7 +96,7 @@ internal class MangaParserTest {
assert(tags.all { it.source == source })
val tag = tags.last()
val list = parser.getList(offset = 0, tags = setOf(tag), tagsExclude = setOf(tag), sortOrder = null)
val list = parser.getList(offset = 0, tags = setOf(tag), null, sortOrder = null)
checkMangaList(list, "${tag.title} (${tag.key})")
assert(list.all { it.source == source })
}
@ -101,17 +105,13 @@ internal class MangaParserTest {
@MangaSources
fun tagsMultiple(source: MangaSource) = runTest(timeout = timeout) {
val parser = context.newParserInstance(source)
if (!parser.isMultipleTagsSupported) return@runTest
val tags = parser.getAvailableTags().shuffled().take(2).toSet()
val list = try {
parser.getList(offset = 0, tags = tags, tagsExclude = tags, sortOrder = null)
} catch (e: IllegalArgumentException) {
if (e.message == "Multiple genres are not supported by this source") {
return@runTest
} else {
throw e
}
}
val filter = MangaListFilter.Advanced.Builder(parser.availableSortOrders.first())
.tags(tags)
.build()
val list = parser.getList(0, filter)
checkMangaList(list, "${tags.joinToString { it.title }} (${tags.joinToString { it.key }})")
assert(list.all { it.source == source })
}

Loading…
Cancel
Save