Improve filtering

pull/421/head
Koitharu 2 years ago
parent efb5d34279
commit b274b51699
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -47,6 +47,11 @@ abstract class MangaParser @InternalParsersApi constructor(
*/ */
open val isTagsExclusionSupported: Boolean = false open val isTagsExclusionSupported: Boolean = false
/**
* Whether parser supports searching by string query using [MangaListFilter.Search]
*/
open val isSearchSupported: Boolean = true
@Deprecated( @Deprecated(
message = "Use availableSortOrders instead", message = "Use availableSortOrders instead",
replaceWith = ReplaceWith("availableSortOrders"), replaceWith = ReplaceWith("availableSortOrders"),
@ -149,21 +154,42 @@ abstract class MangaParser @InternalParsersApi constructor(
return getList( return getList(
offset, offset,
MangaListFilter.Advanced( MangaListFilter.Advanced(
sortOrder ?: defaultSortOrder, sortOrder = sortOrder ?: defaultSortOrder,
tags.orEmpty(), tags = tags.orEmpty(),
tagsExclude.orEmpty(), tagsExclude = tagsExclude.orEmpty(),
null, locale = null,
emptySet(), states = emptySet(),
emptySet(), contentRating = emptySet(),
), ),
) )
} }
@Suppress("DEPRECATION")
open suspend fun getList(offset: Int, filter: MangaListFilter?): List<Manga> { open suspend fun getList(offset: Int, filter: MangaListFilter?): List<Manga> {
return when (filter) { return when (filter) {
is MangaListFilter.Advanced -> getList(offset, null, filter.tags, filter.tagsExclude, filter.sortOrder) is MangaListFilter.Advanced -> getList(
is MangaListFilter.Search -> getList(offset, filter.query, null, null, defaultSortOrder) offset = offset,
null -> getList(offset, null, null, null, defaultSortOrder) query = null,
tags = filter.tags,
tagsExclude = filter.tagsExclude,
sortOrder = filter.sortOrder,
)
is MangaListFilter.Search -> getList(
offset = offset,
query = filter.query,
tags = null,
tagsExclude = null,
sortOrder = defaultSortOrder,
)
null -> getList(
offset = offset,
query = null,
tags = null,
tagsExclude = null,
sortOrder = defaultSortOrder,
)
} }
} }

@ -50,9 +50,29 @@ abstract class PagedMangaParser(
open suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> { open suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {
return when (filter) { return when (filter) {
is MangaListFilter.Advanced -> getListPage(page, null, filter.tags, filter.tagsExclude, filter.sortOrder) is MangaListFilter.Advanced -> getListPage(
is MangaListFilter.Search -> getListPage(page, filter.query, null, null, defaultSortOrder) page = page,
null -> getListPage(page, null, null, null, defaultSortOrder) query = null,
tags = filter.tags,
tagsExclude = filter.tagsExclude,
sortOrder = filter.sortOrder,
)
is MangaListFilter.Search -> getListPage(
page = page,
query = filter.query,
tags = null,
tagsExclude = null,
sortOrder = defaultSortOrder,
)
null -> getListPage(
page = page,
query = null,
tags = null,
tagsExclude = null,
sortOrder = defaultSortOrder,
)
} }
} }

@ -1,5 +1,6 @@
package org.koitharu.kotatsu.parsers.model package org.koitharu.kotatsu.parsers.model
import org.koitharu.kotatsu.parsers.MangaParser
import java.util.* import java.util.*
sealed interface MangaListFilter { sealed interface MangaListFilter {
@ -8,6 +9,16 @@ sealed interface MangaListFilter {
val sortOrder: SortOrder? val sortOrder: SortOrder?
fun isValid(parser: MangaParser): Boolean = when (this) {
is Advanced -> (sortOrder in parser.availableSortOrders) &&
(tags.size <= 1 || parser.isMultipleTagsSupported) &&
(tagsExclude.isEmpty() || parser.isTagsExclusionSupported) &&
(contentRating.isEmpty() || parser.availableContentRating.containsAll(contentRating)) &&
(states.isEmpty() || parser.availableStates.containsAll(states))
is Search -> parser.isSearchSupported
}
data class Search( data class Search(
@JvmField val query: String, @JvmField val query: String,
) : MangaListFilter { ) : MangaListFilter {
@ -26,6 +37,57 @@ sealed interface MangaListFilter {
@JvmField val contentRating: Set<ContentRating>, @JvmField val contentRating: Set<ContentRating>,
) : MangaListFilter { ) : MangaListFilter {
override fun isEmpty(): Boolean = tags.isEmpty() && tagsExclude.isEmpty() && locale == null && states.isEmpty() && contentRating.isEmpty() override fun isEmpty(): Boolean =
tags.isEmpty() && tagsExclude.isEmpty() && locale == null && states.isEmpty() && contentRating.isEmpty()
fun newBuilder() = Builder(sortOrder)
.tags(tags)
.tagsExclude(tagsExclude)
.locale(locale)
.states(states)
.contentRatings(contentRating)
class Builder(sortOrder: SortOrder) {
private var _sortOrder: SortOrder = sortOrder
private var _tags: Set<MangaTag>? = null
private var _tagsExclude: Set<MangaTag>? = null
private var _locale: Locale? = null
private var _states: Set<MangaState>? = null
private var _contentRating: Set<ContentRating>? = null
fun sortOrder(order: SortOrder) = apply {
_sortOrder = order
}
fun tags(tags: Set<MangaTag>?) = apply {
_tags = tags
}
fun tagsExclude(tags: Set<MangaTag>?) = apply {
_tagsExclude = tags
}
fun locale(locale: Locale?) = apply {
_locale = locale
}
fun states(states: Set<MangaState>?) = apply {
_states = states
}
fun contentRatings(rating: Set<ContentRating>?) = apply {
_contentRating = rating
}
fun build() = Advanced(
sortOrder = _sortOrder,
tags = _tags.orEmpty(),
tagsExclude = _tagsExclude.orEmpty(),
locale = _locale,
states = _states.orEmpty(),
contentRating = _contentRating.orEmpty(),
)
}
} }
} }

@ -9,30 +9,14 @@ import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser import org.koitharu.kotatsu.parsers.PagedMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.ContentType import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.util.*
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaListFilter
import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.RATING_UNKNOWN
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.SuspendLazy
import org.koitharu.kotatsu.parsers.util.domain
import org.koitharu.kotatsu.parsers.util.generateUid
import org.koitharu.kotatsu.parsers.util.json.getStringOrNull import org.koitharu.kotatsu.parsers.util.json.getStringOrNull
import org.koitharu.kotatsu.parsers.util.json.mapJSON import org.koitharu.kotatsu.parsers.util.json.mapJSON
import org.koitharu.kotatsu.parsers.util.json.mapJSONToSet import org.koitharu.kotatsu.parsers.util.json.mapJSONToSet
import org.koitharu.kotatsu.parsers.util.json.toJSONList import org.koitharu.kotatsu.parsers.util.json.toJSONList
import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.oneOrThrowIfMany
import org.koitharu.kotatsu.parsers.util.parseHtml
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import org.koitharu.kotatsu.parsers.util.toCamelCase
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.EnumSet import java.util.*
import java.util.Locale
@MangaSourceParser("NINENINENINEHENTAI", "999Hentai", type = ContentType.HENTAI) @MangaSourceParser("NINENINENINEHENTAI", "999Hentai", type = ContentType.HENTAI)
internal class NineNineNineHentaiParser(context: MangaLoaderContext) : internal class NineNineNineHentaiParser(context: MangaLoaderContext) :

@ -19,6 +19,7 @@ internal class FlixScansOrg(context: MangaLoaderContext) : PagedMangaParser(cont
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val availableStates: Set<MangaState> = EnumSet.allOf(MangaState::class.java) override val availableStates: Set<MangaState> = EnumSet.allOf(MangaState::class.java)
override val configKeyDomain = ConfigKey.Domain("flixscans.org") override val configKeyDomain = ConfigKey.Domain("flixscans.org")
override val isSearchSupported = false
override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> { override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {

@ -22,6 +22,8 @@ internal class ReaperComics(context: MangaLoaderContext) :
override val configKeyDomain = ConfigKey.Domain("reaperscans.com") override val configKeyDomain = ConfigKey.Domain("reaperscans.com")
override val isSearchSupported = false
override val headers: Headers = Headers.Builder() override val headers: Headers = Headers.Builder()
.add("User-Agent", UserAgents.CHROME_DESKTOP) .add("User-Agent", UserAgents.CHROME_DESKTOP)
.build() .build()

@ -21,6 +21,8 @@ internal class TempleScanEsp(context: MangaLoaderContext) :
override val configKeyDomain = ConfigKey.Domain("templescanesp.net") override val configKeyDomain = ConfigKey.Domain("templescanesp.net")
override val isSearchSupported = false
override val headers: Headers = Headers.Builder() override val headers: Headers = Headers.Builder()
.add("User-Agent", UserAgents.CHROME_DESKTOP) .add("User-Agent", UserAgents.CHROME_DESKTOP)
.build() .build()

@ -23,6 +23,8 @@ internal class FuryoSociety(context: MangaLoaderContext) :
override val configKeyDomain = ConfigKey.Domain("furyosociety.com") override val configKeyDomain = ConfigKey.Domain("furyosociety.com")
override val isSearchSupported = false
override val headers: Headers = Headers.Builder() override val headers: Headers = Headers.Builder()
.add("User-Agent", UserAgents.CHROME_DESKTOP) .add("User-Agent", UserAgents.CHROME_DESKTOP)
.build() .build()

@ -25,6 +25,8 @@ internal class LugnicaScans(context: MangaLoaderContext) : PagedMangaParser(cont
override val availableStates: Set<MangaState> = override val availableStates: Set<MangaState> =
EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED) EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED)
override val isSearchSupported = false
override val configKeyDomain = ConfigKey.Domain("lugnica-scans.com") override val configKeyDomain = ConfigKey.Domain("lugnica-scans.com")
override val headers: Headers = Headers.Builder() override val headers: Headers = Headers.Builder()

@ -23,6 +23,8 @@ internal abstract class HeanCmsAlt(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val isSearchSupported = false
protected open val listUrl = "/comics" protected open val listUrl = "/comics"
protected open val datePattern = "MMMM d, yyyy" protected open val datePattern = "MMMM d, yyyy"

@ -19,6 +19,7 @@ internal class RizzComic(context: MangaLoaderContext) :
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL)
override val availableStates: Set<MangaState> = emptySet() override val availableStates: Set<MangaState> = emptySet()
override val isMultipleTagsSupported = false override val isMultipleTagsSupported = false
override val isSearchSupported = false
// TODO Query created in json // TODO Query created in json
override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> { override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {

@ -25,6 +25,7 @@ class LerManga(context: MangaLoaderContext) : PagedMangaParser(context, MangaSou
override val configKeyDomain = ConfigKey.Domain("lermanga.org") override val configKeyDomain = ConfigKey.Domain("lermanga.org")
override val isMultipleTagsSupported = false override val isMultipleTagsSupported = false
override val isSearchSupported = false
override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> { override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {

@ -21,7 +21,7 @@ internal abstract class ScanParser(
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.ALPHABETICAL, SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.RATING) EnumSet.of(SortOrder.ALPHABETICAL, SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.RATING)
override val isSearchSupported = false
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> { override suspend fun getListPage(page: Int, filter: MangaListFilter?): List<Manga> {

Loading…
Cancel
Save