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

@ -8,35 +8,137 @@ import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.model.MangaTag 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.MangaListFilterOptions
import org.koitharu.kotatsu.parsers.model.MangaParserSource 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.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.util.* 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.* import java.util.*
// Do not use "hentaicb.sbs" domain, may cause duplicate tags!
@MangaSourceParser("HENTAICUBE", "CBHentai", "vi", ContentType.HENTAI) @MangaSourceParser("HENTAICUBE", "CBHentai", "vi", ContentType.HENTAI)
internal class HentaiCube(context: MangaLoaderContext) : internal class HentaiCube(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.HENTAICUBE, "hentaicube.xyz") { MadaraParser(context, MangaParserSource.HENTAICUBE, "hentaicube.xyz") {
override val configKeyDomain = ConfigKey.Domain("hentaicube.xyz", "hentaicb.sbs")
override val datePattern = "dd/MM/yyyy" override val datePattern = "dd/MM/yyyy"
override val postReq = true override val postReq = true
override val authorSearchSupported = true
override val postDataReq = "action=manga_views&manga=" override val postDataReq = "action=manga_views&manga="
private val availableTags = suspendLazy(initializer = ::fetchTags)
override suspend fun getFilterOptions() = MangaListFilterOptions( override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchTags(), availableTags = availableTags.get(),
) )
override fun createMangaTag(a: Element): MangaTag? { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
return MangaTag( val pages = page + 1
title = a.text().replace(Regex("\\(\\d+\\)"), ""),
key = a.attr("href").substringAfter("/theloai/").removeSuffix("/"), val url = buildString {
source = source, 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> { override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(domain) val fullUrl = chapter.url.toAbsoluteUrl(domain)
val doc = webClient.httpGet(fullUrl).parseHtml() val doc = webClient.httpGet(fullUrl).parseHtml()
@ -59,7 +161,7 @@ internal class HentaiCube(context: MangaLoaderContext) :
return elements.mapToSet { element -> return elements.mapToSet { element ->
val href = element.attr("href") val href = element.attr("href")
val key = href.substringAfter("/theloai/").removeSuffix("/") val key = href.substringAfter("/theloai/").removeSuffix("/")
val title = element.text().replace(Regex("\\(\\d+\\)"), "") val title = element.text().replace(Regex("\\(\\d+\\)"), "").trim() // force trim
MangaTag( MangaTag(
key = key, key = key,
title = title, title = title,

Loading…
Cancel
Save