Add support type and Demographic on MangaListFilter
This commit is contained in:
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
10
src/main/kotlin/org/koitharu/kotatsu/parsers/model/Type.kt
Normal file
10
src/main/kotlin/org/koitharu/kotatsu/parsers/model/Type.kt
Normal file
@@ -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())
|
||||
|
||||
Reference in New Issue
Block a user