Use ContentType instead of Type

master
Koitharu 2 years ago
parent b566e4e7e4
commit 0f4808f5b5
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -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 =

@ -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<Type>
open val availableContentTypes: Set<ContentType>
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(),
),
)
}

@ -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
*/

@ -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<MangaState>,
@JvmField val contentRating: Set<ContentRating>,
@JvmField val type: Set<Type>,
@JvmField val demographic: Set<Demographic>,
@JvmField val types: Set<ContentType>,
@JvmField val demographics: Set<Demographic>,
) : 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<MangaState>? = null
private var _contentRating: Set<ContentRating>? = null
private var _type: Set<Type>? = null
private var _types: Set<ContentType>? = null
private var _demographic: Set<Demographic>? = null
fun sortOrder(order: SortOrder) = apply {
@ -88,8 +88,8 @@ sealed interface MangaListFilter {
_contentRating = rating
}
fun type(type: Set<Type>?) = apply {
_type = type
fun type(type: Set<ContentType>?) = apply {
_types = type
}
fun demographic(demographic: Set<Demographic>?) = 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(),
)
}
}

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

@ -36,14 +36,14 @@ internal class ComickFunParser(context: MangaLoaderContext) :
SortOrder.NEWEST,
)
override val availableType: Set<Type> = EnumSet.of(
Type.MANGA,
Type.MANHWA,
Type.MANHUA,
Type.OTHERS,
override val availableContentTypes: Set<ContentType> = EnumSet.of(
ContentType.MANGA,
ContentType.MANHWA,
ContentType.MANHUA,
ContentType.OTHER,
)
override val availableDemographic: Set<Demographic> = EnumSet.allOf(Demographic::class.java)
override val availableDemographics: Set<Demographic> = EnumSet.allOf(Demographic::class.java)
override val availableStates: Set<MangaState> =
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) {

@ -37,7 +37,7 @@ 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 availableDemographics: Set<Demographic> = EnumSet.allOf(Demographic::class.java)
override val availableStates: Set<MangaState> =
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) {

@ -46,8 +46,14 @@ 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 availableContentTypes: Set<ContentType>
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
}

@ -51,48 +51,34 @@ fun Element.parseFailed(message: String? = null): Nothing {
}
@InternalParsersApi
fun Set<MangaTag>?.oneOrThrowIfMany(): MangaTag? {
return when {
isNullOrEmpty() -> null
size == 1 -> first()
else -> throw IllegalArgumentException(ErrorMessages.FILTER_MULTIPLE_GENRES_NOT_SUPPORTED)
}
}
fun Set<MangaTag>?.oneOrThrowIfMany(): MangaTag? = oneOrThrowIfMany(
ErrorMessages.FILTER_MULTIPLE_GENRES_NOT_SUPPORTED,
)
@InternalParsersApi
fun Set<MangaState>?.oneOrThrowIfMany(): MangaState? {
return when {
isNullOrEmpty() -> null
size == 1 -> first()
else -> throw IllegalArgumentException(ErrorMessages.FILTER_MULTIPLE_STATES_NOT_SUPPORTED)
}
}
fun Set<MangaState>?.oneOrThrowIfMany(): MangaState? = oneOrThrowIfMany(
ErrorMessages.FILTER_MULTIPLE_STATES_NOT_SUPPORTED,
)
@InternalParsersApi
fun Set<Type>?.oneOrThrowIfMany(): Type? {
return when {
isNullOrEmpty() -> null
size == 1 -> first()
else -> throw IllegalArgumentException(ErrorMessages.FILTER_MULTIPLE_STATES_NOT_SUPPORTED)
}
}
fun Set<ContentType>?.oneOrThrowIfMany(): ContentType? = oneOrThrowIfMany(
ErrorMessages.FILTER_MULTIPLE_CONTENT_TYPES_NOT_SUPPORTED,
)
@InternalParsersApi
fun Set<Demographic>?.oneOrThrowIfMany(): Demographic? {
return when {
isNullOrEmpty() -> null
size == 1 -> first()
else -> throw IllegalArgumentException(ErrorMessages.FILTER_MULTIPLE_STATES_NOT_SUPPORTED)
}
}
fun Set<Demographic>?.oneOrThrowIfMany(): Demographic? = oneOrThrowIfMany(
ErrorMessages.FILTER_MULTIPLE_DEMOGRAPHICS_NOT_SUPPORTED,
)
@InternalParsersApi
fun Set<ContentRating>?.oneOrThrowIfMany(): ContentRating? {
return when {
isNullOrEmpty() -> null
size == 1 -> first()
else -> throw IllegalArgumentException(ErrorMessages.FILTER_MULTIPLE_CONTENT_RATING_NOT_SUPPORTED)
}
fun Set<ContentRating>?.oneOrThrowIfMany(): ContentRating? = oneOrThrowIfMany(
ErrorMessages.FILTER_MULTIPLE_CONTENT_RATING_NOT_SUPPORTED,
)
private fun <T> Set<T>?.oneOrThrowIfMany(msg: String): T? = when {
isNullOrEmpty() -> null
size == 1 -> first()
else -> throw IllegalArgumentException(msg)
}
val MangaParser.domain: String

@ -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()

Loading…
Cancel
Save