From 03d7e138e9561c57af5dae957af85fb303e7d24e Mon Sep 17 00:00:00 2001 From: devi Date: Sat, 14 Sep 2024 10:55:56 +0200 Subject: [PATCH 1/4] Add support type and Demographic on MangaListFilter --- .../koitharu/kotatsu/parsers/MangaParser.kt | 23 ++++++++++ .../kotatsu/parsers/model/Demographic.kt | 9 ++++ .../kotatsu/parsers/model/MangaListFilter.kt | 22 +++++++++- .../koitharu/kotatsu/parsers/model/Type.kt | 10 +++++ .../parsers/site/all/ComickFunParser.kt | 43 +++++++++++++++++-- .../parsers/site/all/MangaDexParser.kt | 17 ++++++++ .../site/mangareader/MangaReaderParser.kt | 18 ++++++++ .../kotatsu/parsers/util/MangaParserEnv.kt | 18 ++++++++ .../kotatsu/parsers/MangaParserTest.kt | 4 ++ 9 files changed, 158 insertions(+), 6 deletions(-) create mode 100644 src/main/kotlin/org/koitharu/kotatsu/parsers/model/Demographic.kt create mode 100644 src/main/kotlin/org/koitharu/kotatsu/parsers/model/Type.kt diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt index 7de7f70e..8e8be672 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt @@ -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 get() = emptySet() + /** + * Supported [Type] variants for filtering. May be empty. + * + * For better performance use [EnumSet] for more than one item. + */ + open val availableType: Set + get() = emptySet() + + /** + * Supported [Demographic] variants for filtering. May be empty. + * + * For better performance use [EnumSet] for more than one item. + */ + open val availableDemographic: Set + 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(), ), ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/model/Demographic.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/model/Demographic.kt new file mode 100644 index 00000000..d94bda67 --- /dev/null +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/model/Demographic.kt @@ -0,0 +1,9 @@ +package org.koitharu.kotatsu.parsers.model + +enum class Demographic { + SHOUNEN, + SHOUJO, + SEINEN, + JOSEI, + NONE, +} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/model/MangaListFilter.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/model/MangaListFilter.kt index 2abe61f6..58af8e3e 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/model/MangaListFilter.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/model/MangaListFilter.kt @@ -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, @JvmField val contentRating: Set, + @JvmField val type: Set, + @JvmField val demographic: Set, ) : 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? = null private var _contentRating: Set? = null + private var _type: Set? = null + private var _demographic: Set? = null fun sortOrder(order: SortOrder) = apply { _sortOrder = order @@ -80,6 +88,14 @@ sealed interface MangaListFilter { _contentRating = rating } + fun type(type: Set?) = apply { + _type = type + } + + fun demographic(demographic: Set?) = 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() ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/model/Type.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/model/Type.kt new file mode 100644 index 00000000..3140fa7f --- /dev/null +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/model/Type.kt @@ -0,0 +1,10 @@ +package org.koitharu.kotatsu.parsers.model + +enum class Type { + MANGA, + MANHWA, + MANHUA, + COMIC, + NOVEL, + OTHERS, +} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ComickFunParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ComickFunParser.kt index f7bbcbfe..85bb1c5a 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ComickFunParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ComickFunParser.kt @@ -36,6 +36,15 @@ internal class ComickFunParser(context: MangaLoaderContext) : SortOrder.NEWEST, ) + override val availableType: Set = EnumSet.of( + Type.MANGA, + Type.MANHWA, + Type.MANHUA, + Type.OTHERS, + ) + + override val availableDemographic: Set = EnumSet.allOf(Demographic::class.java) + override val availableStates: Set = 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() diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaDexParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaDexParser.kt index 3f7980f2..50b72d0e 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaDexParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaDexParser.kt @@ -37,6 +37,8 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context override val availableContentRating: Set = EnumSet.allOf(ContentRating::class.java) + override val availableDemographic: Set = EnumSet.allOf(Demographic::class.java) + override val availableStates: Set = 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) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/MangaReaderParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/MangaReaderParser.kt index 99188a2c..0a3f0c90 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/MangaReaderParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/MangaReaderParser.kt @@ -46,6 +46,10 @@ internal abstract class MangaReaderParser( override val availableStates: Set get() = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED) + override val availableType: Set + 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()) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/MangaParserEnv.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/MangaParserEnv.kt index 79fb7bc0..c804e105 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/MangaParserEnv.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/MangaParserEnv.kt @@ -68,6 +68,24 @@ fun Set?.oneOrThrowIfMany(): MangaState? { } } +@InternalParsersApi +fun Set?.oneOrThrowIfMany(): Type? { + return when { + isNullOrEmpty() -> null + size == 1 -> first() + else -> throw IllegalArgumentException(ErrorMessages.FILTER_MULTIPLE_STATES_NOT_SUPPORTED) + } +} + +@InternalParsersApi +fun Set?.oneOrThrowIfMany(): Demographic? { + return when { + isNullOrEmpty() -> null + size == 1 -> first() + else -> throw IllegalArgumentException(ErrorMessages.FILTER_MULTIPLE_STATES_NOT_SUPPORTED) + } +} + @InternalParsersApi fun Set?.oneOrThrowIfMany(): ContentRating? { return when { diff --git a/src/test/kotlin/org/koitharu/kotatsu/parsers/MangaParserTest.kt b/src/test/kotlin/org/koitharu/kotatsu/parsers/MangaParserTest.kt index bdb66622..45e5eaa8 100644 --- a/src/test/kotlin/org/koitharu/kotatsu/parsers/MangaParserTest.kt +++ b/src/test/kotlin/org/koitharu/kotatsu/parsers/MangaParserTest.kt @@ -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()) From 4ff2061bb7de4b8e01499855b93aaa507c664014 Mon Sep 17 00:00:00 2001 From: davvarrr <70220050+davvarrr@users.noreply.github.com> Date: Sat, 14 Sep 2024 11:25:16 +0200 Subject: [PATCH 2/4] Update src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt Co-authored-by: Koitharu --- src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt index 8e8be672..a29b3215 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt @@ -47,7 +47,7 @@ abstract class MangaParser @InternalParsersApi constructor( * * For better performance use [EnumSet] for more than one item. */ - open val availableType: Set + open val availableTypes: Set get() = emptySet() /** From b566e4e7e41c5f46076957959e63c9083997f65b Mon Sep 17 00:00:00 2001 From: davvarrr <70220050+davvarrr@users.noreply.github.com> Date: Sat, 14 Sep 2024 11:25:23 +0200 Subject: [PATCH 3/4] Update src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt Co-authored-by: Koitharu --- src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt index a29b3215..98ce3c0e 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt @@ -55,7 +55,7 @@ abstract class MangaParser @InternalParsersApi constructor( * * For better performance use [EnumSet] for more than one item. */ - open val availableDemographic: Set + open val availableDemographics: Set get() = emptySet() /** From 0f4808f5b5ff481c8fd0145c11250af148878a14 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Tue, 17 Sep 2024 09:35:54 +0300 Subject: [PATCH 4/4] Use ContentType instead of Type --- .../koitharu/kotatsu/parsers/ErrorMessages.kt | 6 ++- .../koitharu/kotatsu/parsers/MangaParser.kt | 8 +-- .../kotatsu/parsers/model/ContentType.kt | 6 +++ .../kotatsu/parsers/model/MangaListFilter.kt | 26 ++++----- .../koitharu/kotatsu/parsers/model/Type.kt | 10 ---- .../parsers/site/all/ComickFunParser.kt | 24 ++++----- .../parsers/site/all/MangaDexParser.kt | 4 +- .../site/mangareader/MangaReaderParser.kt | 30 ++++++----- .../kotatsu/parsers/util/MangaParserEnv.kt | 54 +++++++------------ .../kotatsu/parsers/MangaParserTest.kt | 30 +++++------ 10 files changed, 95 insertions(+), 103 deletions(-) delete mode 100644 src/main/kotlin/org/koitharu/kotatsu/parsers/model/Type.kt diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/ErrorMessages.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/ErrorMessages.kt index 57ae550d..23f819cd 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/ErrorMessages.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/ErrorMessages.kt @@ -5,7 +5,11 @@ object ErrorMessages { const val FILTER_MULTIPLE_STATES_NOT_SUPPORTED = "Multiple states are not supported by this source" const val FILTER_MULTIPLE_GENRES_NOT_SUPPORTED = "Multiple genres are not supported by this source" const val FILTER_MULTIPLE_CONTENT_RATING_NOT_SUPPORTED = - "Multiple Content Rating are not supported by this source" + "Multiple Content ratings are not supported by this source" + const val FILTER_MULTIPLE_CONTENT_TYPES_NOT_SUPPORTED = + "Multiple Content types are not supported by this source" + const val FILTER_MULTIPLE_DEMOGRAPHICS_NOT_SUPPORTED = + "Multiple Demographics are not supported by this source" const val FILTER_BOTH_LOCALE_GENRES_NOT_SUPPORTED = "Filtering by both genres and locale is not supported by this source" const val FILTER_BOTH_STATES_GENRES_NOT_SUPPORTED = diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt index 98ce3c0e..9f2a0459 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/MangaParser.kt @@ -43,11 +43,11 @@ abstract class MangaParser @InternalParsersApi constructor( get() = emptySet() /** - * Supported [Type] variants for filtering. May be empty. + * Supported [ContentType] variants for filtering. May be empty. * * For better performance use [EnumSet] for more than one item. */ - open val availableTypes: Set + open val availableContentTypes: Set get() = emptySet() /** @@ -184,8 +184,8 @@ abstract class MangaParser @InternalParsersApi constructor( locale = null, states = emptySet(), contentRating = emptySet(), - type = emptySet(), - demographic = emptySet(), + types = emptySet(), + demographics = emptySet(), ), ) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/model/ContentType.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/model/ContentType.kt index e3eb1ecf..695440fb 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/model/ContentType.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/model/ContentType.kt @@ -7,6 +7,10 @@ enum class ContentType { */ MANGA, + MANHWA, + + MANHUA, + /** * Use this if the source provides mostly nsfw content. */ @@ -17,6 +21,8 @@ enum class ContentType { */ COMICS, + NOVEL, + /** * Use this type if no other suits your needs. For example, for an indie manga */ diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/model/MangaListFilter.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/model/MangaListFilter.kt index 58af8e3e..62c6e176 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/model/MangaListFilter.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/model/MangaListFilter.kt @@ -14,9 +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) && - (type.isEmpty() || parser.availableType.containsAll(type)) && - (demographic.isEmpty() || parser.availableDemographic.containsAll(demographic))) + (states.isEmpty() || parser.availableStates.containsAll(states)) && + (types.isEmpty() || parser.availableContentTypes.containsAll(types)) && + (demographics.isEmpty() || parser.availableDemographics.containsAll(demographics)) is Search -> parser.isSearchSupported } @@ -37,12 +37,12 @@ sealed interface MangaListFilter { @JvmField val locale: Locale?, @JvmField val states: Set, @JvmField val contentRating: Set, - @JvmField val type: Set, - @JvmField val demographic: Set, + @JvmField val types: Set, + @JvmField val demographics: Set, ) : MangaListFilter { override fun isEmpty(): Boolean = - tags.isEmpty() && tagsExclude.isEmpty() && locale == null && states.isEmpty() && contentRating.isEmpty() && type.isEmpty() && demographic.isEmpty() + tags.isEmpty() && tagsExclude.isEmpty() && locale == null && states.isEmpty() && contentRating.isEmpty() && types.isEmpty() && demographics.isEmpty() fun newBuilder() = Builder(sortOrder) .tags(tags) @@ -50,8 +50,8 @@ sealed interface MangaListFilter { .locale(locale) .states(states) .contentRatings(contentRating) - .type(type) - .demographic(demographic) + .type(types) + .demographic(demographics) class Builder(sortOrder: SortOrder) { @@ -61,7 +61,7 @@ sealed interface MangaListFilter { private var _locale: Locale? = null private var _states: Set? = null private var _contentRating: Set? = null - private var _type: Set? = null + private var _types: Set? = null private var _demographic: Set? = null fun sortOrder(order: SortOrder) = apply { @@ -88,8 +88,8 @@ sealed interface MangaListFilter { _contentRating = rating } - fun type(type: Set?) = apply { - _type = type + fun type(type: Set?) = apply { + _types = type } fun demographic(demographic: Set?) = apply { @@ -103,8 +103,8 @@ sealed interface MangaListFilter { locale = _locale, states = _states.orEmpty(), contentRating = _contentRating.orEmpty(), - type = _type.orEmpty(), - demographic = _demographic.orEmpty() + types = _types.orEmpty(), + demographics = _demographic.orEmpty(), ) } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/model/Type.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/model/Type.kt deleted file mode 100644 index 3140fa7f..00000000 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/model/Type.kt +++ /dev/null @@ -1,10 +0,0 @@ -package org.koitharu.kotatsu.parsers.model - -enum class Type { - MANGA, - MANHWA, - MANHUA, - COMIC, - NOVEL, - OTHERS, -} diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ComickFunParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ComickFunParser.kt index 85bb1c5a..fabf8e2a 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ComickFunParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/ComickFunParser.kt @@ -36,14 +36,14 @@ internal class ComickFunParser(context: MangaLoaderContext) : SortOrder.NEWEST, ) - override val availableType: Set = EnumSet.of( - Type.MANGA, - Type.MANHWA, - Type.MANHUA, - Type.OTHERS, + override val availableContentTypes: Set = EnumSet.of( + ContentType.MANGA, + ContentType.MANHWA, + ContentType.MANHUA, + ContentType.OTHER, ) - override val availableDemographic: Set = EnumSet.allOf(Demographic::class.java) + override val availableDemographics: Set = EnumSet.allOf(Demographic::class.java) override val availableStates: Set = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED) @@ -99,20 +99,20 @@ internal class ComickFunParser(context: MangaLoaderContext) : ) } - filter.type.forEach { + filter.types.forEach { url.addQueryParameter( "country", when (it) { - Type.MANGA -> "jp" - Type.MANHWA -> "kr" - Type.MANHUA -> "cn" - Type.OTHERS -> "others" + ContentType.MANGA -> "jp" + ContentType.MANHWA -> "kr" + ContentType.MANHUA -> "cn" + ContentType.OTHER -> "others" else -> "" }, ) } - filter.demographic.forEach { + filter.demographics.forEach { url.addQueryParameter( "demographic", when (it) { diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaDexParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaDexParser.kt index 50b72d0e..45c78eef 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaDexParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/all/MangaDexParser.kt @@ -37,7 +37,7 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context override val availableContentRating: Set = EnumSet.allOf(ContentRating::class.java) - override val availableDemographic: Set = EnumSet.allOf(Demographic::class.java) + override val availableDemographics: Set = EnumSet.allOf(Demographic::class.java) override val availableStates: Set = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED) @@ -110,7 +110,7 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context } } - filter.demographic.forEach { + filter.demographics.forEach { append("&publicationDemographic[]=") append( when (it) { diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/MangaReaderParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/MangaReaderParser.kt index 0a3f0c90..a6a81023 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/MangaReaderParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/mangareader/MangaReaderParser.kt @@ -46,8 +46,14 @@ internal abstract class MangaReaderParser( override val availableStates: Set get() = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED) - override val availableType: Set - get() = EnumSet.of(Type.MANGA, Type.MANHWA, Type.MANHUA, Type.COMIC, Type.NOVEL) + override val availableContentTypes: Set + get() = EnumSet.of( + ContentType.MANGA, + ContentType.MANHWA, + ContentType.MANHUA, + ContentType.COMICS, + ContentType.NOVEL, + ) override val isTagsExclusionSupported = true @@ -114,15 +120,15 @@ internal abstract class MangaReaderParser( } } - filter.type.oneOrThrowIfMany()?.let { + filter.types.oneOrThrowIfMany()?.let { append("&type=") append( when (it) { - Type.MANGA -> "manga" - Type.MANHWA -> "manhwa" - Type.MANHUA -> "manhua" - Type.COMIC -> "comic" - Type.NOVEL -> "novel" + ContentType.MANGA -> "manga" + ContentType.MANHWA -> "manhwa" + ContentType.MANHUA -> "manhua" + ContentType.COMICS -> "comic" + ContentType.NOVEL -> "novel" else -> "" }, ) @@ -241,18 +247,18 @@ internal abstract class MangaReaderParser( "En cours de publication", "Đang tiến hành", "Em lançamento", "em lançamento", "Em Lançamento", "Онгоінг", "Publishing", "Devam Ediyor", "Em Andamento", "In Corso", "Güncel", "Berjalan", "Продолжается", "Updating", "Lançando", "In Arrivo", "Emision", "En emision", "مستمر", "Curso", "En marcha", "Publicandose", "Publicando", "连载中", "Devam ediyor", "Devam Etmekte", - -> MangaState.ONGOING + -> MangaState.ONGOING "Completed", "Completo", "Complété", "Fini", "Achevé", "Terminé", "Terminé ⚫", "Tamamlandı", "Đã hoàn thành", "Hoàn Thành", "مكتملة", "Завершено", "Finished", "Finalizado", "Completata", "One-Shot", "Bitti", "Tamat", "Completado", "Concluído", "Concluido", "已完结", "Bitmiş", - -> MangaState.FINISHED + -> MangaState.FINISHED "Canceled", "Cancelled", "Cancelado", "cancellato", "Cancelados", "Dropped", "Discontinued", "abandonné", "Abandonné", - -> MangaState.ABANDONED + -> MangaState.ABANDONED "Hiatus", "On Hold", "Pausado", "En espera", "En pause", "En Pause", "En attente", - -> MangaState.PAUSED + -> MangaState.PAUSED else -> null } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/MangaParserEnv.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/MangaParserEnv.kt index c804e105..845c5e29 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/util/MangaParserEnv.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/util/MangaParserEnv.kt @@ -51,48 +51,34 @@ fun Element.parseFailed(message: String? = null): Nothing { } @InternalParsersApi -fun Set?.oneOrThrowIfMany(): MangaTag? { - return when { - isNullOrEmpty() -> null - size == 1 -> first() - else -> throw IllegalArgumentException(ErrorMessages.FILTER_MULTIPLE_GENRES_NOT_SUPPORTED) - } -} +fun Set?.oneOrThrowIfMany(): MangaTag? = oneOrThrowIfMany( + ErrorMessages.FILTER_MULTIPLE_GENRES_NOT_SUPPORTED, +) @InternalParsersApi -fun Set?.oneOrThrowIfMany(): MangaState? { - return when { - isNullOrEmpty() -> null - size == 1 -> first() - else -> throw IllegalArgumentException(ErrorMessages.FILTER_MULTIPLE_STATES_NOT_SUPPORTED) - } -} +fun Set?.oneOrThrowIfMany(): MangaState? = oneOrThrowIfMany( + ErrorMessages.FILTER_MULTIPLE_STATES_NOT_SUPPORTED, +) @InternalParsersApi -fun Set?.oneOrThrowIfMany(): Type? { - return when { - isNullOrEmpty() -> null - size == 1 -> first() - else -> throw IllegalArgumentException(ErrorMessages.FILTER_MULTIPLE_STATES_NOT_SUPPORTED) - } -} +fun Set?.oneOrThrowIfMany(): ContentType? = oneOrThrowIfMany( + ErrorMessages.FILTER_MULTIPLE_CONTENT_TYPES_NOT_SUPPORTED, +) @InternalParsersApi -fun Set?.oneOrThrowIfMany(): Demographic? { - return when { - isNullOrEmpty() -> null - size == 1 -> first() - else -> throw IllegalArgumentException(ErrorMessages.FILTER_MULTIPLE_STATES_NOT_SUPPORTED) - } -} +fun Set?.oneOrThrowIfMany(): Demographic? = oneOrThrowIfMany( + ErrorMessages.FILTER_MULTIPLE_DEMOGRAPHICS_NOT_SUPPORTED, +) @InternalParsersApi -fun Set?.oneOrThrowIfMany(): ContentRating? { - return when { - isNullOrEmpty() -> null - size == 1 -> first() - else -> throw IllegalArgumentException(ErrorMessages.FILTER_MULTIPLE_CONTENT_RATING_NOT_SUPPORTED) - } +fun Set?.oneOrThrowIfMany(): ContentRating? = oneOrThrowIfMany( + ErrorMessages.FILTER_MULTIPLE_CONTENT_RATING_NOT_SUPPORTED, +) + +private fun Set?.oneOrThrowIfMany(msg: String): T? = when { + isNullOrEmpty() -> null + size == 1 -> first() + else -> throw IllegalArgumentException(msg) } val MangaParser.domain: String diff --git a/src/test/kotlin/org/koitharu/kotatsu/parsers/MangaParserTest.kt b/src/test/kotlin/org/koitharu/kotatsu/parsers/MangaParserTest.kt index 45e5eaa8..c985985c 100644 --- a/src/test/kotlin/org/koitharu/kotatsu/parsers/MangaParserTest.kt +++ b/src/test/kotlin/org/koitharu/kotatsu/parsers/MangaParserTest.kt @@ -19,7 +19,7 @@ internal class MangaParserTest { @ParameterizedTest(name = "{index}|list|{0}") @MangaSources - fun list(source: MangaParserSource) = runTest(timeout = timeout) { + fun list(source: MangaParserSource) = runTest(timeout = timeout) { val parser = context.newParserInstance(source) val list = parser.getList(0, null) checkMangaList(list, "list") @@ -28,7 +28,7 @@ internal class MangaParserTest { @ParameterizedTest(name = "{index}|pagination|{0}") @MangaSources - fun pagination(source: MangaParserSource) = runTest(timeout = timeout) { + fun pagination(source: MangaParserSource) = runTest(timeout = timeout) { val parser = context.newParserInstance(source) val page1 = parser.getList(0, filter = null) val page2 = parser.getList(page1.size, filter = null) @@ -48,7 +48,7 @@ internal class MangaParserTest { @ParameterizedTest(name = "{index}|search|{0}") @MangaSources - fun search(source: MangaParserSource) = runTest(timeout = timeout) { + fun search(source: MangaParserSource) = runTest(timeout = timeout) { val parser = context.newParserInstance(source) val subject = parser.getList( offset = 0, @@ -59,8 +59,8 @@ internal class MangaParserTest { states = emptySet(), tagsExclude = emptySet(), contentRating = emptySet(), - type = emptySet(), - demographic = emptySet(), + types = emptySet(), + demographics = emptySet(), ), ).minByOrNull { it.title.length @@ -78,7 +78,7 @@ internal class MangaParserTest { @ParameterizedTest(name = "{index}|tags|{0}") @MangaSources - fun tags(source: MangaParserSource) = runTest(timeout = timeout) { + fun tags(source: MangaParserSource) = runTest(timeout = timeout) { val parser = context.newParserInstance(source) val tags = parser.getAvailableTags() assert(tags.isNotEmpty()) { "No tags found" } @@ -107,7 +107,7 @@ internal class MangaParserTest { @ParameterizedTest(name = "{index}|tags_multiple|{0}") @MangaSources - fun tagsMultiple(source: MangaParserSource) = runTest(timeout = timeout) { + fun tagsMultiple(source: MangaParserSource) = runTest(timeout = timeout) { val parser = context.newParserInstance(source) if (!parser.isMultipleTagsSupported) return@runTest val tags = parser.getAvailableTags().shuffled().take(2).toSet() @@ -122,7 +122,7 @@ internal class MangaParserTest { @ParameterizedTest(name = "{index}|locale|{0}") @MangaSources - fun locale(source: MangaParserSource) = runTest(timeout = timeout) { + fun locale(source: MangaParserSource) = runTest(timeout = timeout) { val parser = context.newParserInstance(source) val locales = parser.getAvailableLocales() if (locales.isEmpty()) { @@ -135,8 +135,8 @@ internal class MangaParserTest { locale = locales.random(), states = setOf(), contentRating = setOf(), - type = emptySet(), - demographic = emptySet(), + types = emptySet(), + demographics = emptySet(), ) val list = parser.getList(offset = 0, filter) checkMangaList(list, filter.locale.toString()) @@ -146,7 +146,7 @@ internal class MangaParserTest { @ParameterizedTest(name = "{index}|details|{0}") @MangaSources - fun details(source: MangaParserSource) = runTest(timeout = timeout) { + fun details(source: MangaParserSource) = runTest(timeout = timeout) { val parser = context.newParserInstance(source) val list = parser.getList(0, null) val manga = list[3] @@ -176,7 +176,7 @@ internal class MangaParserTest { @ParameterizedTest(name = "{index}|pages|{0}") @MangaSources - fun pages(source: MangaParserSource) = runTest(timeout = timeout) { + fun pages(source: MangaParserSource) = runTest(timeout = timeout) { val parser = context.newParserInstance(source) val list = parser.getList(0, null) val manga = list.first() @@ -200,7 +200,7 @@ internal class MangaParserTest { @ParameterizedTest(name = "{index}|favicon|{0}") @MangaSources - fun favicon(source: MangaParserSource) = runTest(timeout = timeout) { + fun favicon(source: MangaParserSource) = runTest(timeout = timeout) { val parser = context.newParserInstance(source) val favicons = parser.getFavicons() val types = setOf("png", "svg", "ico", "gif", "jpg", "jpeg") @@ -216,7 +216,7 @@ internal class MangaParserTest { @ParameterizedTest(name = "{index}|domain|{0}") @MangaSources - fun domain(source: MangaParserSource) = runTest(timeout = timeout) { + fun domain(source: MangaParserSource) = runTest(timeout = timeout) { val parser = context.newParserInstance(source) val defaultDomain = parser.domain val url = HttpUrl.Builder().host(defaultDomain).scheme("https").toString() @@ -232,7 +232,7 @@ internal class MangaParserTest { @ParameterizedTest(name = "{index}|authorization|{0}") @MangaSources @Disabled - fun authorization(source: MangaParserSource) = runTest(timeout = timeout) { + fun authorization(source: MangaParserSource) = runTest(timeout = timeout) { val parser = context.newParserInstance(source) if (parser is MangaParserAuthProvider) { val username = parser.getUsername()