[CBHentai] Add author search + Fix duplicate tags (#1918)

master
Draken 10 months ago committed by GitHub
parent b5bd5b8cdf
commit eff26f6303
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -34,6 +34,7 @@ internal abstract class MadaraParser(
// Change these values only if the site does not support manga listings via ajax
protected open val withoutAjax = false
protected open val authorSearchSupported = false
override val availableSortOrders: Set<SortOrder> = setupAvailableSortOrders()
@ -71,6 +72,7 @@ internal abstract class MadaraParser(
isSearchSupported = true,
isSearchWithFiltersSupported = true,
isYearSupported = true,
isAuthorSearchSupported = authorSearchSupported
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
@ -273,11 +275,13 @@ internal abstract class MadaraParser(
append(filter.year.toString())
}
// Support author
//filter.author?.let {
// append("&author=")
// append(filter.author)
//}
if (!filter.author.isNullOrEmpty()) {
filter.author.let {
append("&author=")
// should be like "minamida-usuke"
append(it.lowercase().replace(" ", "-"))
}
}
// Support artist
//filter.artist?.let {
@ -454,9 +458,16 @@ internal abstract class MadaraParser(
}
protected open fun parseMangaList(doc: Document): List<Manga> {
return doc.select("div.row.c-tabs-item__content").ifEmpty {
val elements = doc.select("div.row.c-tabs-item__content").ifEmpty {
doc.select("div.page-item-detail")
}.map { div ->
}
// Avoid "Content not found or removed" errors
if (elements.isEmpty()) {
return emptyList()
}
return elements.map { div ->
val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href")
val summary = div.selectFirst(".tab-summary") ?: div.selectFirst(".item-summary")
val author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText()
@ -534,7 +545,7 @@ internal abstract class MadaraParser(
protected open val selectAlt =
".post-content_item:contains(Alt) .summary-content, .post-content_item:contains(Nomes alternativos: ) .summary-content"
protected open fun createMangaTag(a: Element): MangaTag? {
protected open suspend fun createMangaTag(a: Element): MangaTag? {
return MangaTag(
key = a.attr("href").removeSuffix("/").substringAfterLast('/'),
title = a.text().toTitleCase(),

@ -8,34 +8,136 @@ import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.MangaListFilter
import org.koitharu.kotatsu.parsers.model.MangaListFilterOptions
import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.ContentRating
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.util.*
import org.koitharu.kotatsu.parsers.util.suspendlazy.getOrNull
import org.koitharu.kotatsu.parsers.util.suspendlazy.suspendLazy
import java.util.*
// Do not use "hentaicb.sbs" domain, may cause duplicate tags!
@MangaSourceParser("HENTAICUBE", "CBHentai", "vi", ContentType.HENTAI)
internal class HentaiCube(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.HENTAICUBE, "hentaicube.xyz") {
override val configKeyDomain = ConfigKey.Domain("hentaicube.xyz", "hentaicb.sbs")
override val datePattern = "dd/MM/yyyy"
override val postReq = true
override val authorSearchSupported = true
override val postDataReq = "action=manga_views&manga="
private val availableTags = suspendLazy(initializer = ::fetchTags)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchTags(),
availableTags = availableTags.get(),
)
override fun createMangaTag(a: Element): MangaTag? {
return MangaTag(
title = a.text().replace(Regex("\\(\\d+\\)"), ""),
key = a.attr("href").substringAfter("/theloai/").removeSuffix("/"),
source = source,
)
}
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
val pages = page + 1
val url = buildString {
if (!filter.author.isNullOrEmpty()) {
append("https://")
append(domain)
append("/tacgia/")
append(filter.author.lowercase().replace(" ", "-"))
if (pages > 1) {
append("/page/")
append(pages.toString())
}
append("/?m_orderby=")
when (order) {
SortOrder.POPULARITY -> append("views")
SortOrder.UPDATED -> append("latest")
SortOrder.NEWEST -> append("new-manga")
SortOrder.ALPHABETICAL -> {}
SortOrder.RATING -> append("trending")
SortOrder.RELEVANCE -> {}
else -> append("latest") // default
}
return@buildString
}
append("https://")
append(domain)
if (pages > 1) {
append("/page/")
append(pages.toString())
}
append("/?s=")
filter.query?.let {
append(filter.query.urlEncoded())
}
append("&post_type=wp-manga")
if (filter.tags.isNotEmpty()) {
filter.tags.forEach {
append("&genre[]=")
append(it.key)
}
}
filter.states.forEach {
append("&status[]=")
when (it) {
MangaState.ONGOING -> append("on-going")
MangaState.FINISHED -> append("end")
MangaState.ABANDONED -> append("canceled")
MangaState.PAUSED -> append("on-hold")
MangaState.UPCOMING -> append("upcoming")
}
}
filter.contentRating.oneOrThrowIfMany()?.let {
append("&adult=")
append(
when (it) {
ContentRating.SAFE -> "0"
ContentRating.ADULT -> "1"
else -> ""
},
)
}
if (filter.year != 0) {
append("&release=")
append(filter.year.toString())
}
append("&m_orderby=")
when (order) {
SortOrder.POPULARITY -> append("views")
SortOrder.UPDATED -> append("latest")
SortOrder.NEWEST -> append("new-manga")
SortOrder.ALPHABETICAL -> append("alphabet")
SortOrder.RATING -> append("rating")
SortOrder.RELEVANCE -> {}
else -> {}
}
}
return parseMangaList(webClient.httpGet(url).parseHtml())
}
override suspend fun createMangaTag(a: Element): MangaTag? {
val allTags = availableTags.getOrNull().orEmpty()
val title = a.text().replace(Regex("\\(\\d+\\)"), "").trim() // force trim to remove space
// compare to avoid duplicate tags with the same title
return allTags.find {
it.title.trim().equals(title, ignoreCase = true) // try to search with trim
}
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain)
@ -54,17 +156,17 @@ internal class HentaiCube(context: MangaLoaderContext) :
}
private suspend fun fetchTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/the-loai-genres").parseHtml()
val elements = doc.select("ul.list-unstyled li a")
return elements.mapToSet { element ->
val href = element.attr("href")
val key = href.substringAfter("/theloai/").removeSuffix("/")
val title = element.text().replace(Regex("\\(\\d+\\)"), "")
MangaTag(
key = key,
title = title,
source = source,
)
}.toSet()
}
val doc = webClient.httpGet("https://$domain/the-loai-genres").parseHtml()
val elements = doc.select("ul.list-unstyled li a")
return elements.mapToSet { element ->
val href = element.attr("href")
val key = href.substringAfter("/theloai/").removeSuffix("/")
val title = element.text().replace(Regex("\\(\\d+\\)"), "").trim() // force trim
MangaTag(
key = key,
title = title,
source = source,
)
}.toSet()
}
}

Loading…
Cancel
Save