Add support type and Demographic on MangaListFilter

master
devi 2 years ago
parent 0540da57e6
commit 03d7e138e9

@ -34,9 +34,30 @@ abstract class MangaParser @InternalParsersApi constructor(
get() = emptySet()
/**
* Supported [ContentRating] variants for filtering. May be empty.
*
* For better performance use [EnumSet] for more than one item.
*/
open val availableContentRating: Set<ContentRating>
get() = emptySet()
/**
* Supported [Type] variants for filtering. May be empty.
*
* For better performance use [EnumSet] for more than one item.
*/
open val availableType: Set<Type>
get() = emptySet()
/**
* Supported [Demographic] variants for filtering. May be empty.
*
* For better performance use [EnumSet] for more than one item.
*/
open val availableDemographic: Set<Demographic>
get() = emptySet()
/**
* Whether parser supports filtering by more than one tag
*/
@ -163,6 +184,8 @@ abstract class MangaParser @InternalParsersApi constructor(
locale = null,
states = emptySet(),
contentRating = emptySet(),
type = emptySet(),
demographic = emptySet(),
),
)
}

@ -0,0 +1,9 @@
package org.koitharu.kotatsu.parsers.model
enum class Demographic {
SHOUNEN,
SHOUJO,
SEINEN,
JOSEI,
NONE,
}

@ -14,7 +14,9 @@ sealed interface MangaListFilter {
(tags.size <= 1 || parser.isMultipleTagsSupported) &&
(tagsExclude.isEmpty() || parser.isTagsExclusionSupported) &&
(contentRating.isEmpty() || parser.availableContentRating.containsAll(contentRating)) &&
(states.isEmpty() || parser.availableStates.containsAll(states))
(states.isEmpty() || parser.availableStates.containsAll(states) &&
(type.isEmpty() || parser.availableType.containsAll(type)) &&
(demographic.isEmpty() || parser.availableDemographic.containsAll(demographic)))
is Search -> parser.isSearchSupported
}
@ -35,10 +37,12 @@ sealed interface MangaListFilter {
@JvmField val locale: Locale?,
@JvmField val states: Set<MangaState>,
@JvmField val contentRating: Set<ContentRating>,
@JvmField val type: Set<Type>,
@JvmField val demographic: Set<Demographic>,
) : MangaListFilter {
override fun isEmpty(): Boolean =
tags.isEmpty() && tagsExclude.isEmpty() && locale == null && states.isEmpty() && contentRating.isEmpty()
tags.isEmpty() && tagsExclude.isEmpty() && locale == null && states.isEmpty() && contentRating.isEmpty() && type.isEmpty() && demographic.isEmpty()
fun newBuilder() = Builder(sortOrder)
.tags(tags)
@ -46,6 +50,8 @@ sealed interface MangaListFilter {
.locale(locale)
.states(states)
.contentRatings(contentRating)
.type(type)
.demographic(demographic)
class Builder(sortOrder: SortOrder) {
@ -55,6 +61,8 @@ sealed interface MangaListFilter {
private var _locale: Locale? = null
private var _states: Set<MangaState>? = null
private var _contentRating: Set<ContentRating>? = null
private var _type: Set<Type>? = null
private var _demographic: Set<Demographic>? = null
fun sortOrder(order: SortOrder) = apply {
_sortOrder = order
@ -80,6 +88,14 @@ sealed interface MangaListFilter {
_contentRating = rating
}
fun type(type: Set<Type>?) = apply {
_type = type
}
fun demographic(demographic: Set<Demographic>?) = apply {
_demographic = demographic
}
fun build() = Advanced(
sortOrder = _sortOrder,
tags = _tags.orEmpty(),
@ -87,6 +103,8 @@ sealed interface MangaListFilter {
locale = _locale,
states = _states.orEmpty(),
contentRating = _contentRating.orEmpty(),
type = _type.orEmpty(),
demographic = _demographic.orEmpty()
)
}
}

@ -0,0 +1,10 @@
package org.koitharu.kotatsu.parsers.model
enum class Type {
MANGA,
MANHWA,
MANHUA,
COMIC,
NOVEL,
OTHERS,
}

@ -36,6 +36,15 @@ internal class ComickFunParser(context: MangaLoaderContext) :
SortOrder.NEWEST,
)
override val availableType: Set<Type> = EnumSet.of(
Type.MANGA,
Type.MANHWA,
Type.MANHUA,
Type.OTHERS,
)
override val availableDemographic: Set<Demographic> = EnumSet.allOf(Demographic::class.java)
override val availableStates: Set<MangaState> =
EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED)
@ -56,10 +65,6 @@ internal class ComickFunParser(context: MangaLoaderContext) :
url.addQueryParameter("q", filter.query)
}
null -> {
url.addQueryParameter("sort", "view")
}
is MangaListFilter.Advanced -> {
filter.tags.forEach {
@ -93,6 +98,36 @@ internal class ComickFunParser(context: MangaLoaderContext) :
},
)
}
filter.type.forEach {
url.addQueryParameter(
"country",
when (it) {
Type.MANGA -> "jp"
Type.MANHWA -> "kr"
Type.MANHUA -> "cn"
Type.OTHERS -> "others"
else -> ""
},
)
}
filter.demographic.forEach {
url.addQueryParameter(
"demographic",
when (it) {
Demographic.SHOUNEN -> "1"
Demographic.SHOUJO -> "2"
Demographic.SEINEN -> "3"
Demographic.JOSEI -> "4"
Demographic.NONE -> "5"
},
)
}
}
null -> {
url.addQueryParameter("sort", "uploaded")
}
}
val ja = webClient.httpGet(url.build()).parseJsonArray()

@ -37,6 +37,8 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context
override val availableContentRating: Set<ContentRating> = EnumSet.allOf(ContentRating::class.java)
override val availableDemographic: Set<Demographic> = EnumSet.allOf(Demographic::class.java)
override val availableStates: Set<MangaState> =
EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED)
@ -96,6 +98,7 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context
SortOrder.POPULARITY_ASC -> "[followedCount]=asc"
},
)
filter.states.forEach {
append("&status[]=")
when (it) {
@ -106,6 +109,20 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context
else -> append("")
}
}
filter.demographic.forEach {
append("&publicationDemographic[]=")
append(
when (it) {
Demographic.SHOUNEN -> "shounen"
Demographic.SHOUJO -> "shoujo"
Demographic.SEINEN -> "seinen"
Demographic.JOSEI -> "josei"
Demographic.NONE -> "none"
},
)
}
filter.locale?.let {
append("&availableTranslatedLanguage[]=")
append(it.language)

@ -46,6 +46,10 @@ internal abstract class MangaReaderParser(
override val availableStates: Set<MangaState>
get() = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED)
override val availableType: Set<Type>
get() = EnumSet.of(Type.MANGA, Type.MANHWA, Type.MANHUA, Type.COMIC, Type.NOVEL)
override val isTagsExclusionSupported = true
protected open val listUrl = "/manga"
@ -110,6 +114,20 @@ internal abstract class MangaReaderParser(
}
}
filter.type.oneOrThrowIfMany()?.let {
append("&type=")
append(
when (it) {
Type.MANGA -> "manga"
Type.MANHWA -> "manhwa"
Type.MANHUA -> "manhua"
Type.COMIC -> "comic"
Type.NOVEL -> "novel"
else -> ""
},
)
}
append("&page=")
append(page.toString())
}

@ -68,6 +68,24 @@ fun Set<MangaState>?.oneOrThrowIfMany(): MangaState? {
}
}
@InternalParsersApi
fun Set<Type>?.oneOrThrowIfMany(): Type? {
return when {
isNullOrEmpty() -> null
size == 1 -> first()
else -> throw IllegalArgumentException(ErrorMessages.FILTER_MULTIPLE_STATES_NOT_SUPPORTED)
}
}
@InternalParsersApi
fun Set<Demographic>?.oneOrThrowIfMany(): Demographic? {
return when {
isNullOrEmpty() -> null
size == 1 -> first()
else -> throw IllegalArgumentException(ErrorMessages.FILTER_MULTIPLE_STATES_NOT_SUPPORTED)
}
}
@InternalParsersApi
fun Set<ContentRating>?.oneOrThrowIfMany(): ContentRating? {
return when {

@ -59,6 +59,8 @@ internal class MangaParserTest {
states = emptySet(),
tagsExclude = emptySet(),
contentRating = emptySet(),
type = emptySet(),
demographic = emptySet(),
),
).minByOrNull {
it.title.length
@ -133,6 +135,8 @@ internal class MangaParserTest {
locale = locales.random(),
states = setOf(),
contentRating = setOf(),
type = emptySet(),
demographic = emptySet(),
)
val list = parser.getList(offset = 0, filter)
checkMangaList(list, filter.locale.toString())

Loading…
Cancel
Save