Global refactoring: partial migrate to ListFilterOptions/ListFilterCapabilities
This commit is contained in:
@@ -64,6 +64,8 @@ All functions in `MangaParser` class are documented. Pay attention to some pecul
|
||||
find issues during unit testing.
|
||||
- If your source website (or it's api) uses pages for pagination instead of offset you should extend `PagedMangaParser`
|
||||
instead of `MangaParser`.
|
||||
- If your source website (or it's api) do not provide pagination (has only one page of content) you should extend
|
||||
`SinglePageMangaParser` instead of `MangaParser` nor `PagedMangaParser.
|
||||
- Your parser may also implement the `Interceptor` interface for additional manipulation of all network requests and/or
|
||||
responses, including image loading.
|
||||
|
||||
|
||||
@@ -32,103 +32,35 @@ abstract class MangaParser @InternalParsersApi constructor(
|
||||
* For better performance use [EnumSet] for more than one item.
|
||||
*/
|
||||
@Deprecated("")
|
||||
open val availableStates: Set<MangaState>
|
||||
internal open val availableStates: Set<MangaState>
|
||||
get() = emptySet()
|
||||
|
||||
open val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isMultipleTagsSupported = isMultipleTagsSupported,
|
||||
isTagsExclusionSupported = isTagsExclusionSupported,
|
||||
isSearchSupported = isSearchSupported,
|
||||
isSearchWithFiltersSupported = searchSupportedWithMultipleFilters,
|
||||
isYearSupported = isSearchYearSupported,
|
||||
isYearRangeSupported = isSearchYearRangeSupported,
|
||||
isSourceLocaleSupported = isSearchOriginalLanguages,
|
||||
isSearchSupported = true,
|
||||
isSearchWithFiltersSupported = false,
|
||||
)
|
||||
|
||||
/**
|
||||
* Supported [ContentRating] variants for filtering. May be empty.
|
||||
*
|
||||
* For better performance use [EnumSet] for more than one item.
|
||||
*/
|
||||
@Deprecated("Use getListFilterCapabilities instead")
|
||||
open val availableContentRating: Set<ContentRating>
|
||||
get() = emptySet()
|
||||
|
||||
/**
|
||||
* Supported [ContentType] variants for filtering. May be empty.
|
||||
*
|
||||
* For better performance use [EnumSet] for more than one item.
|
||||
*/
|
||||
@Deprecated("Use getListFilterCapabilities instead")
|
||||
open val availableContentTypes: Set<ContentType>
|
||||
get() = emptySet()
|
||||
|
||||
/**
|
||||
* Supported [Demographic] variants for filtering. May be empty.
|
||||
*
|
||||
* For better performance use [EnumSet] for more than one item.
|
||||
*/
|
||||
@Deprecated("Use getListFilterCapabilities instead")
|
||||
open val availableDemographics: Set<Demographic>
|
||||
get() = emptySet()
|
||||
|
||||
/**
|
||||
* Whether parser supports filtering by more than one tag
|
||||
*/
|
||||
@Deprecated("Use getListFilterCapabilities instead")
|
||||
open val isMultipleTagsSupported: Boolean = true
|
||||
internal open val isMultipleTagsSupported: Boolean = true
|
||||
|
||||
/**
|
||||
* Whether parser supports tagsExclude field in filter
|
||||
*/
|
||||
@Deprecated("Use getListFilterCapabilities instead")
|
||||
open val isTagsExclusionSupported: Boolean = false
|
||||
|
||||
/**
|
||||
* Whether parser supports searching by string query using [MangaListFilter.Search]
|
||||
*/
|
||||
@Deprecated("Use getListFilterCapabilities instead")
|
||||
open val isSearchSupported: Boolean = true
|
||||
|
||||
/**
|
||||
* Whether parser supports searching by string query using [MangaListFilter.Advanced]
|
||||
*/
|
||||
@Deprecated("Use getListFilterCapabilities instead")
|
||||
open val searchSupportedWithMultipleFilters: Boolean = false
|
||||
|
||||
/**
|
||||
* Whether parser supports searching by year
|
||||
*/
|
||||
@Deprecated("Use getListFilterCapabilities instead")
|
||||
open val isSearchYearSupported: Boolean = false
|
||||
|
||||
/**
|
||||
* Whether parser supports searching by year range
|
||||
*/
|
||||
@Deprecated("Use getListFilterCapabilities instead")
|
||||
open val isSearchYearRangeSupported: Boolean = false
|
||||
|
||||
/**
|
||||
* Whether parser supports searching Original Languages
|
||||
*/
|
||||
@Deprecated("Use getListFilterCapabilities instead")
|
||||
open val isSearchOriginalLanguages: Boolean = false
|
||||
|
||||
|
||||
@Deprecated(
|
||||
message = "Use availableSortOrders instead",
|
||||
replaceWith = ReplaceWith("availableSortOrders"),
|
||||
)
|
||||
open val sortOrders: Set<SortOrder>
|
||||
get() = availableSortOrders
|
||||
internal open val isTagsExclusionSupported: Boolean = false
|
||||
|
||||
val config by lazy { context.getConfig(source) }
|
||||
|
||||
open val sourceLocale: Locale
|
||||
get() = if (source.locale.isEmpty()) Locale.ROOT else Locale(source.locale)
|
||||
|
||||
val isNsfwSource = source.contentType == ContentType.HENTAI
|
||||
protected val isNsfwSource = source.contentType == ContentType.HENTAI
|
||||
|
||||
/**
|
||||
* Provide default domain and available alternatives, if any.
|
||||
@@ -145,7 +77,7 @@ abstract class MangaParser @InternalParsersApi constructor(
|
||||
.build()
|
||||
|
||||
/**
|
||||
* Used as fallback if value of `sortOrder` passed to [getList] is null
|
||||
* Used as fallback if value of `order` passed to [getList] is null
|
||||
*/
|
||||
open val defaultSortOrder: SortOrder
|
||||
get() {
|
||||
@@ -161,7 +93,7 @@ abstract class MangaParser @InternalParsersApi constructor(
|
||||
*
|
||||
* @param offset starting from 0 and used for pagination.
|
||||
* Note than passed value may not be divisible by internal page size, so you should adjust it manually.
|
||||
* @param order one of [availableSortOrders] or null for default value
|
||||
* @param order one of [availableSortOrders] or [defaultSortOrder] for default value
|
||||
* @param filter is a set of filter rules
|
||||
*/
|
||||
abstract suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga>
|
||||
@@ -182,39 +114,24 @@ abstract class MangaParser @InternalParsersApi constructor(
|
||||
/**
|
||||
* Fetch direct link to the page image.
|
||||
*/
|
||||
open suspend fun getPageUrl(page: MangaPage): String = page.url.toAbsoluteUrl(domain)
|
||||
internal open suspend fun getPageUrl(page: MangaPage): String = page.url.toAbsoluteUrl(domain)
|
||||
|
||||
/**
|
||||
* Fetch available tags (genres) for source
|
||||
*/
|
||||
@Deprecated("Use getListFilterDatasets instead")
|
||||
open suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
|
||||
internal open suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
|
||||
|
||||
open suspend fun getFilterOptions(): MangaListFilterOptions = coroutineScope {
|
||||
val tagsDeferred = async { getAvailableTags() }
|
||||
val localesDeferred = async { getAvailableLocales() }
|
||||
MangaListFilterOptions(
|
||||
availableTags = tagsDeferred.await(),
|
||||
availableStates = availableStates,
|
||||
availableContentRating = availableContentRating,
|
||||
availableContentTypes = availableContentTypes,
|
||||
availableDemographics = availableDemographics,
|
||||
availableLocales = localesDeferred.await(),
|
||||
availableContentRating = emptySet(),
|
||||
availableLocales = emptySet(),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch available locales for multilingual sources
|
||||
*/
|
||||
@Deprecated("Use getListFilterDatasets instead")
|
||||
open suspend fun getAvailableLocales(): Set<Locale> = emptySet()
|
||||
|
||||
@Deprecated(
|
||||
message = "Use getAvailableTags instead",
|
||||
replaceWith = ReplaceWith("getAvailableTags()"),
|
||||
)
|
||||
suspend fun getTags(): Set<MangaTag> = getAvailableTags()
|
||||
|
||||
/**
|
||||
* Parse favicons from the main page of the source`s website
|
||||
*/
|
||||
@@ -230,10 +147,4 @@ abstract class MangaParser @InternalParsersApi constructor(
|
||||
open suspend fun getRelatedManga(seed: Manga): List<Manga> {
|
||||
return RelatedMangaFinder(listOf(this)).invoke(seed)
|
||||
}
|
||||
|
||||
protected fun getParser(source: MangaParserSource) = if (this.source == source) {
|
||||
this
|
||||
} else {
|
||||
context.newParserInstance(source)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
package org.koitharu.kotatsu.parsers.model
|
||||
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import java.util.*
|
||||
|
||||
@Deprecated("Use MangaListFilterV2 instead")
|
||||
sealed interface MangaListFilter {
|
||||
|
||||
fun isEmpty(): Boolean
|
||||
|
||||
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) &&
|
||||
(parser.searchSupportedWithMultipleFilters) && (parser.isSearchOriginalLanguages) &&
|
||||
(parser.isSearchYearSupported) && (parser.isSearchYearRangeSupported)) &&
|
||||
(types.isEmpty() || parser.availableContentTypes.containsAll(types)) &&
|
||||
(demographics.isEmpty() || parser.availableDemographics.containsAll(demographics))
|
||||
|
||||
is Search -> parser.isSearchSupported
|
||||
}
|
||||
|
||||
data class Search(
|
||||
@JvmField val query: String,
|
||||
) : MangaListFilter {
|
||||
|
||||
override val sortOrder: SortOrder? = null
|
||||
|
||||
override fun isEmpty() = query.isBlank()
|
||||
}
|
||||
|
||||
data class Advanced(
|
||||
override val sortOrder: SortOrder,
|
||||
@JvmField val tags: Set<MangaTag>,
|
||||
@JvmField val tagsExclude: Set<MangaTag>,
|
||||
@JvmField val locale: Locale?,
|
||||
@JvmField val localeMangas: Locale?,
|
||||
@JvmField val states: Set<MangaState>,
|
||||
@JvmField val contentRating: Set<ContentRating>,
|
||||
@JvmField val query: String?,
|
||||
@JvmField val year: Int?,
|
||||
@JvmField val yearFrom: Int?,
|
||||
@JvmField val yearTo: Int?,
|
||||
@JvmField val types: Set<ContentType>,
|
||||
@JvmField val demographics: Set<Demographic>,
|
||||
) : MangaListFilter {
|
||||
|
||||
override fun isEmpty(): Boolean =
|
||||
tags.isEmpty() && tagsExclude.isEmpty() && locale == null && localeMangas == null && states.isEmpty() && contentRating.isEmpty() && query == null && year == null && yearFrom == null && yearTo == null && types.isEmpty() && demographics.isEmpty()
|
||||
|
||||
fun newBuilder() = Builder(sortOrder)
|
||||
.tags(tags)
|
||||
.tagsExclude(tagsExclude)
|
||||
.locale(locale)
|
||||
.localeMangas(localeMangas)
|
||||
.states(states)
|
||||
.contentRatings(contentRating)
|
||||
.query(query)
|
||||
.year(year)
|
||||
.yearFrom(yearFrom)
|
||||
.yearTo(yearTo)
|
||||
.type(types)
|
||||
.demographic(demographics)
|
||||
|
||||
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 _localeMangas: Locale? = null
|
||||
private var _states: Set<MangaState>? = null
|
||||
private var _contentRating: Set<ContentRating>? = null
|
||||
private var _query: String? = null
|
||||
private var _year: Int? = null
|
||||
private var _yearFrom: Int? = null
|
||||
private var _yearTo: Int? = null
|
||||
private var _types: Set<ContentType>? = null
|
||||
private var _demographic: Set<Demographic>? = 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 localeMangas(localeMangas: Locale?) = apply {
|
||||
_localeMangas = localeMangas
|
||||
}
|
||||
|
||||
fun states(states: Set<MangaState>?) = apply {
|
||||
_states = states
|
||||
}
|
||||
|
||||
fun contentRatings(rating: Set<ContentRating>?) = apply {
|
||||
_contentRating = rating
|
||||
}
|
||||
|
||||
fun query(query: String?) = apply {
|
||||
_query = query
|
||||
}
|
||||
|
||||
fun year(year: Int?) = apply {
|
||||
_year = year
|
||||
}
|
||||
|
||||
fun yearFrom(yearFrom: Int?) = apply {
|
||||
_yearFrom = yearFrom
|
||||
}
|
||||
|
||||
fun yearTo(yearTo: Int?) = apply {
|
||||
_yearTo = yearTo
|
||||
}
|
||||
|
||||
fun type(type: Set<ContentType>?) = apply {
|
||||
_types = type
|
||||
}
|
||||
|
||||
fun demographic(demographic: Set<Demographic>?) = apply {
|
||||
_demographic = demographic
|
||||
}
|
||||
|
||||
fun build() = Advanced(
|
||||
sortOrder = _sortOrder,
|
||||
tags = _tags.orEmpty(),
|
||||
tagsExclude = _tagsExclude.orEmpty(),
|
||||
locale = _locale,
|
||||
localeMangas = _localeMangas,
|
||||
states = _states.orEmpty(),
|
||||
contentRating = _contentRating.orEmpty(),
|
||||
query = _query,
|
||||
year = _year,
|
||||
yearFrom = _yearFrom,
|
||||
yearTo = _yearTo,
|
||||
types = _types.orEmpty(),
|
||||
demographics = _demographic.orEmpty(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,48 @@ package org.koitharu.kotatsu.parsers.model
|
||||
import org.koitharu.kotatsu.parsers.InternalParsersApi
|
||||
|
||||
data class MangaListFilterCapabilities @InternalParsersApi constructor(
|
||||
|
||||
/**
|
||||
* Whether parser supports filtering by more than one tag
|
||||
* @see [MangaListFilterV2.tags]
|
||||
* @see [MangaListFilterOptions.availableTags]
|
||||
*/
|
||||
val isMultipleTagsSupported: Boolean,
|
||||
|
||||
/**
|
||||
* Whether parser supports tagsExclude field in filter
|
||||
* @see [MangaListFilterV2.tagsExclude]
|
||||
* @see [MangaListFilterOptions.availableTags]
|
||||
*/
|
||||
val isTagsExclusionSupported: Boolean,
|
||||
|
||||
/**
|
||||
* Whether parser supports searching by string query
|
||||
* @see [MangaListFilterV2.query]
|
||||
*/
|
||||
val isSearchSupported: Boolean,
|
||||
|
||||
/**
|
||||
* Whether parser supports searching by string query combined within other filters
|
||||
*/
|
||||
val isSearchWithFiltersSupported: Boolean,
|
||||
|
||||
/**
|
||||
* Whether parser supports searching/filtering by year
|
||||
* @see [MangaListFilterV2.year]
|
||||
*/
|
||||
val isYearSupported: Boolean = false,
|
||||
|
||||
/**
|
||||
* Whether parser supports searching by year range
|
||||
* @see [MangaListFilterV2.yearFrom] and [MangaListFilterV2.yearTo]
|
||||
*/
|
||||
val isYearRangeSupported: Boolean = false,
|
||||
val isSourceLocaleSupported: Boolean = false,
|
||||
|
||||
/**
|
||||
* Whether parser supports searching Original Languages
|
||||
* @see [MangaListFilterV2.originalLocale]
|
||||
* @see [MangaListFilterOptions.availableLocales]
|
||||
*/
|
||||
val isOriginalLocaleSupported: Boolean = false,
|
||||
)
|
||||
|
||||
@@ -4,10 +4,42 @@ import org.koitharu.kotatsu.parsers.InternalParsersApi
|
||||
import java.util.*
|
||||
|
||||
data class MangaListFilterOptions @InternalParsersApi constructor(
|
||||
|
||||
/**
|
||||
* Available tags (genres)
|
||||
*/
|
||||
val availableTags: Set<MangaTag>,
|
||||
|
||||
/**
|
||||
* Supported [MangaState] variants for filtering. May be empty.
|
||||
*
|
||||
* For better performance use [EnumSet] for more than one item.
|
||||
*/
|
||||
val availableStates: Set<MangaState> = emptySet(),
|
||||
|
||||
/**
|
||||
* Supported [ContentRating] variants for filtering. May be empty.
|
||||
*
|
||||
* For better performance use [EnumSet] for more than one item.
|
||||
*/
|
||||
val availableContentRating: Set<ContentRating> = emptySet(),
|
||||
|
||||
/**
|
||||
* Supported [ContentType] variants for filtering. May be empty.
|
||||
*
|
||||
* For better performance use [EnumSet] for more than one item.
|
||||
*/
|
||||
val availableContentTypes: Set<ContentType> = emptySet(),
|
||||
|
||||
/**
|
||||
* Supported [Demographic] variants for filtering. May be empty.
|
||||
*
|
||||
* For better performance use [EnumSet] for more than one item.
|
||||
*/
|
||||
val availableDemographics: Set<Demographic> = emptySet(),
|
||||
|
||||
/**
|
||||
* Supported content locales for multilingual sources
|
||||
*/
|
||||
val availableLocales: Set<Locale> = emptySet(),
|
||||
)
|
||||
|
||||
@@ -7,7 +7,7 @@ data class MangaListFilterV2(
|
||||
@JvmField val tags: Set<MangaTag> = emptySet(),
|
||||
@JvmField val tagsExclude: Set<MangaTag> = emptySet(),
|
||||
@JvmField val locale: Locale? = null,
|
||||
@JvmField val sourceLocale: Locale? = null,
|
||||
@JvmField val originalLocale: Locale? = null,
|
||||
@JvmField val states: Set<MangaState> = emptySet(),
|
||||
@JvmField val contentRating: Set<ContentRating> = emptySet(),
|
||||
@JvmField val types: Set<ContentType> = emptySet(),
|
||||
@@ -20,7 +20,7 @@ data class MangaListFilterV2(
|
||||
fun isEmpty(): Boolean = tags.isEmpty() &&
|
||||
tagsExclude.isEmpty() &&
|
||||
locale == null &&
|
||||
sourceLocale == null &&
|
||||
originalLocale == null &&
|
||||
states.isEmpty() &&
|
||||
contentRating.isEmpty() &&
|
||||
query == null &&
|
||||
|
||||
@@ -68,7 +68,7 @@ internal class BatoToParser(context: MangaLoaderContext) : PagedMangaParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -44,7 +44,7 @@ internal class ComickFunParser(context: MangaLoaderContext) :
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = true,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -58,7 +58,7 @@ internal class ExHentaiParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override val isAuthorized: Boolean
|
||||
|
||||
@@ -70,14 +70,27 @@ class HitomiLaParser(context: MangaLoaderContext) : MangaParser(context, MangaPa
|
||||
Locale.JAPANESE to "japanese",
|
||||
)
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isMultipleTagsSupported = true,
|
||||
isTagsExclusionSupported = false,
|
||||
isSearchSupported = true,
|
||||
isSearchWithFiltersSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
availableTags = fetchAvailableTags(),
|
||||
availableStates = emptySet(),
|
||||
availableContentRating = emptySet(),
|
||||
availableLocales = localeMap.keys,
|
||||
)
|
||||
|
||||
private fun Locale?.getSiteLang(): String = when (this) {
|
||||
null -> "all"
|
||||
else -> localeMap[this] ?: "all"
|
||||
}
|
||||
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = localeMap.keys
|
||||
|
||||
override suspend fun getAvailableTags(): Set<MangaTag> = coroutineScope {
|
||||
private suspend fun fetchAvailableTags(): Set<MangaTag> = coroutineScope {
|
||||
('a'..'z').map { alphabet ->
|
||||
async {
|
||||
val doc = webClient.httpGet("https://$domain/alltags-$alphabet.html").parseHtml()
|
||||
|
||||
@@ -22,6 +22,21 @@ internal class ImHentai(context: MangaLoaderContext) :
|
||||
|
||||
override val configKeyDomain = ConfigKey.Domain("imhentai.xxx")
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isMultipleTagsSupported = true,
|
||||
isTagsExclusionSupported = false,
|
||||
isSearchSupported = true,
|
||||
isSearchWithFiltersSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
availableTags = fetchAvailableTags(),
|
||||
availableLocales = setOf(
|
||||
Locale.ENGLISH, Locale.JAPANESE, Locale("es"), Locale.FRENCH, Locale("kr"), Locale.GERMAN, Locale("ru"),
|
||||
),
|
||||
)
|
||||
|
||||
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
|
||||
super.onCreateConfig(keys)
|
||||
keys.add(userAgentKey)
|
||||
@@ -90,7 +105,7 @@ internal class ImHentai(context: MangaLoaderContext) :
|
||||
|
||||
//Tags are deliberately reduced because there are too many and this slows down the application.
|
||||
//only the most popular ones are taken.
|
||||
override suspend fun getAvailableTags(): Set<MangaTag> {
|
||||
private suspend fun fetchAvailableTags(): Set<MangaTag> {
|
||||
return coroutineScope {
|
||||
(1..3).map { page ->
|
||||
async { getTags(page) }
|
||||
@@ -113,10 +128,6 @@ internal class ImHentai(context: MangaLoaderContext) :
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
|
||||
Locale.ENGLISH, Locale.JAPANESE, Locale("es"), Locale.FRENCH, Locale("kr"), Locale.GERMAN, Locale("ru"),
|
||||
)
|
||||
|
||||
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
|
||||
val fullUrl = manga.url.toAbsoluteUrl(domain)
|
||||
val doc = webClient.httpGet(fullUrl).parseHtml()
|
||||
|
||||
@@ -41,7 +41,7 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context
|
||||
isSearchWithFiltersSupported = true,
|
||||
isYearSupported = true,
|
||||
isYearRangeSupported = true,
|
||||
isSourceLocaleSupported = true,
|
||||
isOriginalLocaleSupported = true,
|
||||
)
|
||||
|
||||
override val availableSortOrders: EnumSet<SortOrder> = EnumSet.allOf(SortOrder::class.java)
|
||||
@@ -150,7 +150,7 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context
|
||||
append(it.language)
|
||||
}
|
||||
|
||||
filter.sourceLocale?.let {
|
||||
filter.originalLocale?.let {
|
||||
append("&originalLanguage[]=")
|
||||
append(it.language)
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ internal abstract class MangaFireParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -29,7 +29,7 @@ internal class MangaPark(context: MangaLoaderContext) :
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -75,7 +75,7 @@ class MangaReaderToParser(context: MangaLoaderContext) : PagedMangaParser(contex
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -48,7 +48,7 @@ internal abstract class NineMangaParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -42,7 +42,7 @@ internal class NineNineNineHentaiParser(context: MangaLoaderContext) :
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -48,7 +48,7 @@ internal abstract class AnimeBootstrapParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -29,7 +29,7 @@ internal class FlixScans(context: MangaLoaderContext) : PagedMangaParser(context
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -33,7 +33,7 @@ internal class TeamXNovel(context: MangaLoaderContext) : PagedMangaParser(contex
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -35,7 +35,7 @@ internal abstract class CupFoxParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -35,7 +35,7 @@ internal class AsuraScansParser(context: MangaLoaderContext) :
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -30,7 +30,7 @@ internal class BeeToon(context: MangaLoaderContext) :
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -20,17 +20,27 @@ internal class FlixScansOrg(context: MangaLoaderContext) :
|
||||
PagedMangaParser(context, MangaParserSource.FLIXSCANSORG, 18) {
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
|
||||
override val availableStates: Set<MangaState> = EnumSet.allOf(MangaState::class.java)
|
||||
override val availableContentRating: Set<ContentRating> = EnumSet.of(ContentRating.ADULT)
|
||||
override val configKeyDomain = ConfigKey.Domain("flixscans.org")
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isMultipleTagsSupported = true,
|
||||
isTagsExclusionSupported = false,
|
||||
isSearchSupported = false,
|
||||
isSearchWithFiltersSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
availableTags = fetchAvailableTags(),
|
||||
availableStates = EnumSet.allOf(MangaState::class.java),
|
||||
availableContentRating = EnumSet.of(ContentRating.ADULT),
|
||||
)
|
||||
|
||||
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
|
||||
super.onCreateConfig(keys)
|
||||
keys.add(userAgentKey)
|
||||
}
|
||||
|
||||
override val isSearchSupported = false
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
val json = when {
|
||||
!filter.query.isNullOrEmpty() -> {
|
||||
@@ -101,7 +111,7 @@ internal class FlixScansOrg(context: MangaLoaderContext) :
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getAvailableTags(): Set<MangaTag> {
|
||||
private suspend fun fetchAvailableTags(): Set<MangaTag> {
|
||||
val doc = webClient.httpGet("https://$domain/search/advance").parseHtml()
|
||||
val json = JSONArray(doc.requireElementById("__NUXT_DATA__").data())
|
||||
val tagsList = json.getJSONArray(3).toString().replace("[", "").replace("]", "").split(",")
|
||||
|
||||
@@ -38,7 +38,7 @@ internal class Mangaowl(context: MangaLoaderContext) :
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -34,7 +34,7 @@ internal class TempleScanEsp(context: MangaLoaderContext) :
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -29,8 +29,6 @@ class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaParser(
|
||||
|
||||
private val chapterDateFormat = SimpleDateFormat("yyyy-MM-dd", sourceLocale)
|
||||
|
||||
override val availableContentRating: Set<ContentRating> = EnumSet.of(ContentRating.SAFE, ContentRating.ADULT)
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
|
||||
SortOrder.ALPHABETICAL,
|
||||
SortOrder.ALPHABETICAL_DESC,
|
||||
@@ -40,6 +38,20 @@ class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaParser(
|
||||
SortOrder.RATING,
|
||||
)
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isMultipleTagsSupported = true,
|
||||
isTagsExclusionSupported = false,
|
||||
isSearchSupported = true,
|
||||
isSearchWithFiltersSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
availableTags = fetchAvailableTags(),
|
||||
availableStates = emptySet(),
|
||||
availableContentRating = EnumSet.of(ContentRating.SAFE, ContentRating.ADULT),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
@@ -283,7 +295,7 @@ class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaParser(
|
||||
}
|
||||
|
||||
|
||||
override suspend fun getAvailableTags(): Set<MangaTag> {
|
||||
private suspend fun fetchAvailableTags(): Set<MangaTag> {
|
||||
val doc = webClient.httpGet("https://$domain/library", getRequestHeaders()).parseHtml()
|
||||
val elements = doc.body().select("div#books-genders > div > div")
|
||||
return elements.mapNotNullToSet { element ->
|
||||
|
||||
@@ -47,7 +47,7 @@ internal abstract class FmreaderParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
init {
|
||||
|
||||
@@ -40,7 +40,7 @@ internal abstract class FoolSlideParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
init {
|
||||
|
||||
@@ -5,7 +5,6 @@ import org.jsoup.nodes.Document
|
||||
import org.koitharu.kotatsu.parsers.ErrorMessages
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.PagedMangaParser
|
||||
import org.koitharu.kotatsu.parsers.SinglePageMangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
@@ -25,13 +24,25 @@ internal class FuryoSociety(context: MangaLoaderContext) :
|
||||
|
||||
override val userAgentKey = ConfigKey.UserAgent(UserAgents.CHROME_DESKTOP)
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isMultipleTagsSupported = false,
|
||||
isTagsExclusionSupported = false,
|
||||
isSearchSupported = false,
|
||||
isSearchWithFiltersSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
availableTags = emptySet(),
|
||||
availableStates = emptySet(),
|
||||
availableContentRating = emptySet(),
|
||||
)
|
||||
|
||||
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
|
||||
super.onCreateConfig(keys)
|
||||
keys.add(userAgentKey)
|
||||
}
|
||||
|
||||
override val isSearchSupported = false
|
||||
|
||||
override suspend fun getFavicons(): Favicons {
|
||||
return Favicons(
|
||||
listOf(
|
||||
@@ -80,10 +91,6 @@ internal class FuryoSociety(context: MangaLoaderContext) :
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
|
||||
|
||||
|
||||
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
|
||||
val fullUrl = manga.url.toAbsoluteUrl(domain)
|
||||
val doc = webClient.httpGet(fullUrl).parseHtml()
|
||||
@@ -95,7 +102,6 @@ internal class FuryoSociety(context: MangaLoaderContext) :
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
private fun getChapters(doc: Document): List<MangaChapter> {
|
||||
return doc.body().select("div.list.fs-chapter-list div.element").mapChapters(reversed = true) { i, div ->
|
||||
val a = div.selectFirstOrThrow("div.title a")
|
||||
|
||||
@@ -35,7 +35,7 @@ internal class LugnicaScans(context: MangaLoaderContext) :
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -35,7 +35,7 @@ internal class ScansMangasMe(context: MangaLoaderContext) :
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -32,7 +32,7 @@ internal class ScantradUnion(context: MangaLoaderContext) :
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -38,7 +38,7 @@ internal abstract class GalleryAdultsParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -14,6 +14,7 @@ import java.util.*
|
||||
@MangaSourceParser("ASMHENTAI", "AsmHentai", type = ContentType.HENTAI)
|
||||
internal class AsmHentai(context: MangaLoaderContext) :
|
||||
GalleryAdultsParser(context, MangaParserSource.ASMHENTAI, "asmhentai.com") {
|
||||
|
||||
override val selectGallery = ".preview_item"
|
||||
override val selectGalleryLink = ".image a"
|
||||
override val selectGalleryImg = ".image img"
|
||||
@@ -21,11 +22,13 @@ internal class AsmHentai(context: MangaLoaderContext) :
|
||||
override val selectAuthor = "div.tags:contains(Artists:) .tag_list a span.tag"
|
||||
override val idImg = "fimg"
|
||||
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.JAPANESE,
|
||||
Locale.CHINESE,
|
||||
Locale("tr"),
|
||||
override suspend fun getFilterOptions() = super.getFilterOptions().copy(
|
||||
availableLocales = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.JAPANESE,
|
||||
Locale.CHINESE,
|
||||
Locale("tr"),
|
||||
),
|
||||
)
|
||||
|
||||
override fun Element.parseTags() = select("a").mapToSet {
|
||||
|
||||
@@ -21,10 +21,12 @@ internal class DoujinDesuUk(context: MangaLoaderContext) :
|
||||
override val selectLanguageChapter = "div.tag-container:contains(Languages) a"
|
||||
override val idImg = "image-container"
|
||||
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.JAPANESE,
|
||||
Locale.CHINESE,
|
||||
override suspend fun getFilterOptions() = super.getFilterOptions().copy(
|
||||
availableLocales = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.JAPANESE,
|
||||
Locale.CHINESE,
|
||||
),
|
||||
)
|
||||
|
||||
override fun parseMangaList(doc: Document): List<Manga> {
|
||||
|
||||
@@ -23,18 +23,23 @@ internal class Hentai3(context: MangaLoaderContext) :
|
||||
override val selectUrlChapter = "#main-cover a"
|
||||
override val idImg = ".js-main-img"
|
||||
|
||||
override val isMultipleTagsSupported = true
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = super.filterCapabilities.copy(
|
||||
isMultipleTagsSupported = true,
|
||||
)
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)
|
||||
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.FRENCH,
|
||||
Locale.JAPANESE,
|
||||
Locale("es"),
|
||||
Locale("ru"),
|
||||
Locale.ITALIAN,
|
||||
Locale("pt"),
|
||||
override suspend fun getFilterOptions() = super.getFilterOptions().copy(
|
||||
availableLocales = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.FRENCH,
|
||||
Locale.JAPANESE,
|
||||
Locale("es"),
|
||||
Locale("ru"),
|
||||
Locale.ITALIAN,
|
||||
Locale("pt"),
|
||||
),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
|
||||
@@ -24,6 +24,20 @@ internal class HentaiEnvy(context: MangaLoaderContext) :
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)
|
||||
|
||||
override suspend fun getFilterOptions() = super.getFilterOptions().copy(
|
||||
availableLocales = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.FRENCH,
|
||||
Locale.JAPANESE,
|
||||
Locale.CHINESE,
|
||||
Locale("es"),
|
||||
Locale("ru"),
|
||||
Locale("ko"),
|
||||
Locale.GERMAN,
|
||||
Locale("pt"),
|
||||
),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
@@ -63,16 +77,4 @@ internal class HentaiEnvy(context: MangaLoaderContext) :
|
||||
}
|
||||
return parseMangaList(webClient.httpGet(url).parseHtml())
|
||||
}
|
||||
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.FRENCH,
|
||||
Locale.JAPANESE,
|
||||
Locale.CHINESE,
|
||||
Locale("es"),
|
||||
Locale("ru"),
|
||||
Locale("ko"),
|
||||
Locale.GERMAN,
|
||||
Locale("pt"),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -21,25 +21,32 @@ internal class HentaiForce(context: MangaLoaderContext) :
|
||||
override val selectLanguageChapter = "div.tag-container:contains(Languages:) a"
|
||||
override val idImg = ".gallery-reader-img-wrapper img"
|
||||
|
||||
override val isMultipleTagsSupported = true
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = super.filterCapabilities.copy(
|
||||
isMultipleTagsSupported = true,
|
||||
)
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)
|
||||
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.FRENCH,
|
||||
Locale.JAPANESE,
|
||||
Locale.CHINESE,
|
||||
Locale("es"),
|
||||
Locale("ru"),
|
||||
Locale("ko"),
|
||||
Locale.GERMAN,
|
||||
Locale("id"),
|
||||
Locale.ITALIAN,
|
||||
Locale("pt"),
|
||||
Locale("th"),
|
||||
Locale("vi"),
|
||||
)
|
||||
override suspend fun getFilterOptions(): MangaListFilterOptions {
|
||||
return super.getFilterOptions().copy(
|
||||
availableLocales = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.FRENCH,
|
||||
Locale.JAPANESE,
|
||||
Locale.CHINESE,
|
||||
Locale("es"),
|
||||
Locale("ru"),
|
||||
Locale("ko"),
|
||||
Locale.GERMAN,
|
||||
Locale("id"),
|
||||
Locale.ITALIAN,
|
||||
Locale("pt"),
|
||||
Locale("th"),
|
||||
Locale("vi"),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getPageUrl(page: MangaPage): String {
|
||||
val doc = webClient.httpGet(page.url.toAbsoluteUrl(domain)).parseHtml()
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.jsoup.nodes.Element
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilterOptions
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.parsers.site.galleryadults.GalleryAdultsParser
|
||||
@@ -20,15 +21,19 @@ internal class HentaiRox(context: MangaLoaderContext) :
|
||||
override val selectAuthor = "li:contains(Artists:) span.item_name"
|
||||
override val selectLanguageChapter = "li:contains(Languages:) .item_name"
|
||||
|
||||
override suspend fun getAvailableLocales(): Set<Locale> = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.FRENCH,
|
||||
Locale.JAPANESE,
|
||||
Locale("es"),
|
||||
Locale("ru"),
|
||||
Locale("ko"),
|
||||
Locale.GERMAN,
|
||||
)
|
||||
override suspend fun getFilterOptions(): MangaListFilterOptions {
|
||||
return super.getFilterOptions().copy(
|
||||
availableLocales = setOf(
|
||||
Locale.ENGLISH,
|
||||
Locale.FRENCH,
|
||||
Locale.JAPANESE,
|
||||
Locale("es"),
|
||||
Locale("ru"),
|
||||
Locale("ko"),
|
||||
Locale.GERMAN,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun Element.parseTags() = select("a.tag, .gallery_title a").mapToSet {
|
||||
val key = it.attr("href").removeSuffix('/').substringAfterLast('/')
|
||||
|
||||
@@ -24,7 +24,7 @@ internal abstract class GuyaParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -53,7 +53,7 @@ internal abstract class HeanCms(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -28,11 +28,17 @@ internal abstract class HeanCmsAlt(
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
|
||||
|
||||
override val isSearchSupported = false
|
||||
|
||||
protected open val listUrl = "/comics"
|
||||
protected open val datePattern = "MMMM d, yyyy"
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isMultipleTagsSupported = false,
|
||||
isTagsExclusionSupported = false,
|
||||
isSearchSupported = false,
|
||||
isSearchWithFiltersSupported = false,
|
||||
)
|
||||
|
||||
init {
|
||||
paginator.firstPage = 1
|
||||
searchPaginator.firstPage = 1
|
||||
@@ -41,6 +47,12 @@ internal abstract class HeanCmsAlt(
|
||||
protected open val selectManga = "div.grid.grid-cols-2 div:not([class]):contains(M)"
|
||||
protected open val selectMangaTitle = "h5"
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
availableTags = emptySet(),
|
||||
availableStates = emptySet(),
|
||||
availableContentRating = emptySet(),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
@@ -75,8 +87,6 @@ internal abstract class HeanCmsAlt(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
|
||||
|
||||
protected open val selectDesc = "div.description-container"
|
||||
protected open val selectAlt = "div.series-alternative-names"
|
||||
protected open val selectChapter = "ul.MuiList-root a"
|
||||
|
||||
@@ -35,15 +35,17 @@ internal abstract class HotComicsParser(
|
||||
|
||||
protected open val onePage = false
|
||||
|
||||
protected open val isSearchSupported: Boolean = true
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isMultipleTagsSupported = false,
|
||||
isTagsExclusionSupported = false,
|
||||
isSearchSupported = true,
|
||||
isSearchSupported = isSearchSupported,
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -36,7 +36,7 @@ internal abstract class IkenParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -35,7 +35,7 @@ internal abstract class MadaraParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -25,9 +25,10 @@ internal class Manga18Fx(context: MangaLoaderContext) :
|
||||
searchPaginator.firstPage = 1
|
||||
}
|
||||
|
||||
override val availableContentRating: Set<ContentRating> = emptySet()
|
||||
|
||||
override val availableStates: Set<MangaState> get() = emptySet()
|
||||
override suspend fun getFilterOptions() = super.getFilterOptions().copy(
|
||||
availableStates = emptySet(),
|
||||
availableContentRating = emptySet(),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
val url = buildString {
|
||||
|
||||
@@ -28,9 +28,10 @@ internal class Manhwa18Cc(context: MangaLoaderContext) :
|
||||
searchPaginator.firstPage = 1
|
||||
}
|
||||
|
||||
override val availableContentRating: Set<ContentRating> = emptySet()
|
||||
|
||||
override val availableStates: Set<MangaState> get() = emptySet()
|
||||
override suspend fun getFilterOptions() = super.getFilterOptions().copy(
|
||||
availableStates = emptySet(),
|
||||
availableContentRating = emptySet(),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
val url = buildString {
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
package org.koitharu.kotatsu.parsers.site.madara.en
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.*
|
||||
import okhttp3.Headers
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody
|
||||
@@ -16,18 +12,25 @@ import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.EnumSet
|
||||
import java.util.*
|
||||
|
||||
@MangaSourceParser("HENTAIMANGA", "HentaiManga", "en", ContentType.HENTAI)
|
||||
internal class HentaiManga(context: MangaLoaderContext) :
|
||||
MadaraParser(context, MangaParserSource.HENTAIMANGA, "hentaimanga.me", 36) {
|
||||
override val postReq = true
|
||||
override val withoutAjax = true
|
||||
override val isTagsExclusionSupported = false
|
||||
override val availableSortOrders: Set<SortOrder> =
|
||||
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
|
||||
override val availableStates: Set<MangaState> = emptySet()
|
||||
override val availableContentRating: Set<ContentRating> = emptySet()
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = super.filterCapabilities.copy(
|
||||
isMultipleTagsSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = super.getFilterOptions().copy(
|
||||
availableStates = emptySet(),
|
||||
availableContentRating = emptySet(),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
val pages = page + 1
|
||||
|
||||
@@ -20,14 +20,17 @@ internal class IsekaiScan(context: MangaLoaderContext) :
|
||||
SortOrder.POPULARITY,
|
||||
SortOrder.UPDATED,
|
||||
)
|
||||
override val availableContentRating: Set<ContentRating> = emptySet()
|
||||
override val availableStates: Set<MangaState> = emptySet()
|
||||
|
||||
init {
|
||||
paginator.firstPage = 1
|
||||
searchPaginator.firstPage = 1
|
||||
}
|
||||
|
||||
override suspend fun getFilterOptions() = super.getFilterOptions().copy(
|
||||
availableStates = emptySet(),
|
||||
availableContentRating = emptySet(),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
|
||||
@@ -23,15 +23,16 @@ internal class MangaDass(context: MangaLoaderContext) :
|
||||
override val selectChapter = "li.a-h"
|
||||
override val selectDesc = "div.ss-manga"
|
||||
|
||||
override val availableStates: Set<MangaState> get() = emptySet()
|
||||
|
||||
override val availableContentRating: Set<ContentRating> = emptySet()
|
||||
|
||||
init {
|
||||
paginator.firstPage = 1
|
||||
searchPaginator.firstPage = 1
|
||||
}
|
||||
|
||||
override suspend fun getFilterOptions() = super.getFilterOptions().copy(
|
||||
availableStates = emptySet(),
|
||||
availableContentRating = emptySet(),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
|
||||
@@ -17,13 +17,20 @@ internal class MangaDna(context: MangaLoaderContext) :
|
||||
|
||||
override val datePattern = "dd MMM yyyy"
|
||||
override val withoutAjax = true
|
||||
override val isTagsExclusionSupported = false
|
||||
override val availableSortOrders: Set<SortOrder> =
|
||||
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
|
||||
override val selectDesc = "div.dsct"
|
||||
override val selectChapter = "li.a-h"
|
||||
override val availableStates: Set<MangaState> = emptySet()
|
||||
override val availableContentRating: Set<ContentRating> = emptySet()
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = super.filterCapabilities.copy(
|
||||
isTagsExclusionSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = super.getFilterOptions().copy(
|
||||
availableStates = emptySet(),
|
||||
availableContentRating = emptySet(),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
val url = buildString {
|
||||
|
||||
@@ -23,15 +23,18 @@ internal class MangaPure(context: MangaLoaderContext) :
|
||||
SortOrder.UPDATED,
|
||||
)
|
||||
|
||||
override val availableStates: Set<MangaState> = emptySet()
|
||||
|
||||
override val availableContentRating: Set<ContentRating> = emptySet()
|
||||
|
||||
init {
|
||||
paginator.firstPage = 1
|
||||
searchPaginator.firstPage = 1
|
||||
}
|
||||
|
||||
override suspend fun getFilterOptions(): MangaListFilterOptions {
|
||||
return super.getFilterOptions().copy(
|
||||
availableStates = emptySet(),
|
||||
availableContentRating = emptySet(),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
|
||||
@@ -14,12 +14,12 @@ internal class Manhwaz(context: MangaLoaderContext) :
|
||||
override val listUrl = "genre/manhwa"
|
||||
override val tagPrefix = "genre/"
|
||||
override val withoutAjax = true
|
||||
override val isTagsExclusionSupported = false
|
||||
override val selectTestAsync = "div.list-chapter"
|
||||
|
||||
override val availableStates: Set<MangaState> = emptySet()
|
||||
|
||||
override val availableContentRating: Set<ContentRating> = emptySet()
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = super.filterCapabilities.copy(
|
||||
isTagsExclusionSupported = false,
|
||||
)
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
|
||||
SortOrder.UPDATED,
|
||||
@@ -33,6 +33,11 @@ internal class Manhwaz(context: MangaLoaderContext) :
|
||||
searchPaginator.firstPage = 1
|
||||
}
|
||||
|
||||
override suspend fun getFilterOptions() = super.getFilterOptions().copy(
|
||||
availableStates = emptySet(),
|
||||
availableContentRating = emptySet(),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
|
||||
@@ -24,13 +24,21 @@ internal class ManyToon(context: MangaLoaderContext) :
|
||||
override val listUrl = "comic/"
|
||||
override val postReq = true
|
||||
override val withoutAjax = true
|
||||
override val isTagsExclusionSupported = false
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> =
|
||||
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
|
||||
|
||||
override val availableStates: Set<MangaState> = emptySet()
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = super.filterCapabilities.copy(
|
||||
isTagsExclusionSupported = false,
|
||||
)
|
||||
|
||||
override val availableContentRating: Set<ContentRating> = emptySet()
|
||||
override suspend fun getFilterOptions(): MangaListFilterOptions {
|
||||
return super.getFilterOptions().copy(
|
||||
availableStates = emptySet(),
|
||||
availableContentRating = emptySet(),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
val pages = page + 1
|
||||
|
||||
@@ -10,16 +10,20 @@ import java.util.*
|
||||
@MangaSourceParser("DRAGONTRANSLATION", "Dragon Translation", "es")
|
||||
internal class DragonTranslationParser(context: MangaLoaderContext) :
|
||||
MadaraParser(context, MangaParserSource.DRAGONTRANSLATION, "dragontranslation.net", 30) {
|
||||
|
||||
override val selectPage = "div#chapter_imgs img"
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
|
||||
override val availableStates: Set<MangaState> = emptySet()
|
||||
override val availableContentRating: Set<ContentRating> = emptySet()
|
||||
|
||||
init {
|
||||
paginator.firstPage = 1
|
||||
searchPaginator.firstPage = 1
|
||||
}
|
||||
|
||||
override suspend fun getFilterOptions() = super.getFilterOptions().copy(
|
||||
availableStates = emptySet(),
|
||||
availableContentRating = emptySet(),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
|
||||
@@ -16,16 +16,23 @@ internal class TmoManga(context: MangaLoaderContext) :
|
||||
override val listUrl = "biblioteca/"
|
||||
override val selectGenre = "div.summary-content a.tags_manga"
|
||||
override val withoutAjax = true
|
||||
override val isTagsExclusionSupported = false
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.POPULARITY)
|
||||
override val availableStates: Set<MangaState> = emptySet()
|
||||
override val availableContentRating: Set<ContentRating> = emptySet()
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = super.filterCapabilities.copy(
|
||||
isTagsExclusionSupported = false,
|
||||
)
|
||||
|
||||
init {
|
||||
paginator.firstPage = 1
|
||||
searchPaginator.firstPage = 1
|
||||
}
|
||||
|
||||
override suspend fun getFilterOptions() = super.getFilterOptions().copy(
|
||||
availableStates = emptySet(),
|
||||
availableContentRating = emptySet(),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
|
||||
@@ -65,7 +65,7 @@ internal abstract class MadthemeParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -44,7 +44,7 @@ internal abstract class MangAdventureParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -51,7 +51,7 @@ internal abstract class MangaReaderParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.koitharu.kotatsu.parsers.site.mangareader.en
|
||||
|
||||
import androidx.collection.ArrayMap
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Request
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
@@ -25,11 +27,13 @@ internal class RizzComic(context: MangaLoaderContext) :
|
||||
SortOrder.POPULARITY,
|
||||
SortOrder.ALPHABETICAL_DESC,
|
||||
)
|
||||
override val availableStates: Set<MangaState> =
|
||||
EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED)
|
||||
override val isMultipleTagsSupported = true
|
||||
override val isSearchSupported = true
|
||||
override val isTagsExclusionSupported = false
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = super.filterCapabilities.copy(
|
||||
isMultipleTagsSupported = true,
|
||||
isSearchSupported = true,
|
||||
isTagsExclusionSupported = false,
|
||||
)
|
||||
|
||||
private val filterUrl = "/Index/filter_series"
|
||||
private val searchUrl = "/Index/live_search"
|
||||
@@ -55,6 +59,10 @@ internal class RizzComic(context: MangaLoaderContext) :
|
||||
return randomPartRegex.find(slug)?.groupValues?.get(1) ?: ""
|
||||
}
|
||||
|
||||
override suspend fun getFilterOptions() = super.getFilterOptions().copy(
|
||||
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
if (page > 1) {
|
||||
return emptyList()
|
||||
@@ -149,13 +157,14 @@ internal class RizzComic(context: MangaLoaderContext) :
|
||||
else -> "all"
|
||||
}
|
||||
|
||||
override suspend fun getAvailableTags(): Set<MangaTag> {
|
||||
override suspend fun getOrCreateTagMap(): Map<String, MangaTag> = mutex.withLock {
|
||||
tagCache?.let { return@withLock it }
|
||||
val url = "https://$domain/series"
|
||||
val doc = webClient.httpGet(url).parseHtml()
|
||||
|
||||
val genreElements = doc.select("input.genre-item")
|
||||
|
||||
return genreElements.mapNotNullToSet { element ->
|
||||
val genres = genreElements.mapNotNull { element ->
|
||||
val id = element.attr("value")
|
||||
val name = element.nextElementSibling()?.text()
|
||||
|
||||
@@ -169,5 +178,6 @@ internal class RizzComic(context: MangaLoaderContext) :
|
||||
null
|
||||
}
|
||||
}
|
||||
genres.associateByTo(ArrayMap(genres.size)) { it.title }.also { tagCache = it }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilterV2
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
|
||||
@@ -5,7 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilterV2
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
|
||||
@@ -5,7 +5,6 @@ import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilterV2
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
|
||||
@@ -20,8 +20,12 @@ internal class RevolutionScantrad(context: MangaLoaderContext) :
|
||||
) {
|
||||
override val listUrl = "/series.html"
|
||||
override val datePattern = "yyyy"
|
||||
override val isTagsExclusionSupported = false
|
||||
override val isSearchSupported = false
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = super.filterCapabilities.copy(
|
||||
isTagsExclusionSupported = false,
|
||||
isSearchSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
if (page > 1) {
|
||||
|
||||
@@ -72,7 +72,7 @@ internal abstract class MmrcmsParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -30,7 +30,7 @@ internal abstract class OneMangaParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -4,7 +4,6 @@ import kotlinx.coroutines.coroutineScope
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.PagedMangaParser
|
||||
import org.koitharu.kotatsu.parsers.SinglePageMangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
@@ -29,10 +28,20 @@ internal abstract class PizzaReaderParser(
|
||||
}
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL)
|
||||
override val availableStates: Set<MangaState> =
|
||||
EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED)
|
||||
override val availableContentRating: Set<ContentRating> = EnumSet.of(ContentRating.SAFE, ContentRating.ADULT)
|
||||
override val isTagsExclusionSupported = true
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isMultipleTagsSupported = true,
|
||||
isTagsExclusionSupported = true,
|
||||
isSearchSupported = true,
|
||||
isSearchWithFiltersSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
availableTags = emptySet(),
|
||||
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED),
|
||||
availableContentRating = EnumSet.of(ContentRating.SAFE, ContentRating.ADULT),
|
||||
)
|
||||
|
||||
@JvmField
|
||||
protected val ongoing: Set<String> = hashSetOf(
|
||||
@@ -198,9 +207,6 @@ internal abstract class PizzaReaderParser(
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
override suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
|
||||
|
||||
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
|
||||
val fullUrl = manga.url.toAbsoluteUrl(domain)
|
||||
val json = webClient.httpGet(fullUrl).parseJson().getJSONObject("comic")
|
||||
|
||||
@@ -25,14 +25,25 @@ class LerManga(context: MangaLoaderContext) : PagedMangaParser(context, MangaPar
|
||||
|
||||
override val configKeyDomain = ConfigKey.Domain("lermanga.org")
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isMultipleTagsSupported = false,
|
||||
isTagsExclusionSupported = false,
|
||||
isSearchSupported = false,
|
||||
isSearchWithFiltersSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
availableTags = fetchAvailableTags(),
|
||||
availableStates = emptySet(),
|
||||
availableContentRating = emptySet(),
|
||||
)
|
||||
|
||||
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
|
||||
super.onCreateConfig(keys)
|
||||
keys.add(userAgentKey)
|
||||
}
|
||||
|
||||
override val isMultipleTagsSupported = false
|
||||
override val isSearchSupported = false
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
@@ -97,7 +108,7 @@ class LerManga(context: MangaLoaderContext) : PagedMangaParser(context, MangaPar
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getAvailableTags(): Set<MangaTag> {
|
||||
private suspend fun fetchAvailableTags(): Set<MangaTag> {
|
||||
val doc = webClient.httpGet("https://$domain").parseHtml().requireElementById("menu-header")
|
||||
return doc.select("#menu-item:contains(GÊNERO) ul li a").mapNotNullToSet { a ->
|
||||
MangaTag(
|
||||
|
||||
@@ -25,9 +25,19 @@ internal class LuratoonScansParser(context: MangaLoaderContext) :
|
||||
|
||||
override fun getRequestHeaders(): Headers = Headers.Builder().add("User-Agent", config[userAgentKey]).build()
|
||||
|
||||
override val isSearchSupported = false
|
||||
override val isTagsExclusionSupported = false
|
||||
override val isMultipleTagsSupported = false
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isMultipleTagsSupported = false,
|
||||
isTagsExclusionSupported = false,
|
||||
isSearchSupported = false,
|
||||
isSearchWithFiltersSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
availableTags = emptySet(),
|
||||
availableStates = emptySet(),
|
||||
availableContentRating = emptySet(),
|
||||
)
|
||||
|
||||
override suspend fun getList(order: SortOrder, filter: MangaListFilterV2): List<Manga> {
|
||||
require(filter.query.isNullOrEmpty()) { ErrorMessages.SEARCH_NOT_SUPPORTED }
|
||||
@@ -124,8 +134,6 @@ internal class LuratoonScansParser(context: MangaLoaderContext) :
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val response = chain.proceed(chain.request())
|
||||
if (response.mimeType == "application/octet-stream") {
|
||||
|
||||
@@ -25,7 +25,7 @@ class OnePieceEx(context: MangaLoaderContext) : SinglePageMangaParser(context, M
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -26,7 +26,7 @@ class YugenMangas(context: MangaLoaderContext) : SinglePageMangaParser(context,
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -32,7 +32,7 @@ internal class AComics(context: MangaLoaderContext) :
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
init {
|
||||
|
||||
@@ -19,6 +19,7 @@ import java.util.*
|
||||
class MangaWtfParser(
|
||||
context: MangaLoaderContext,
|
||||
) : PagedMangaParser(context, MangaParserSource.MANGA_WTF, pageSize = 20) {
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> =
|
||||
EnumSet.of(
|
||||
SortOrder.POPULARITY,
|
||||
@@ -30,17 +31,24 @@ class MangaWtfParser(
|
||||
@InternalParsersApi
|
||||
override val configKeyDomain = ConfigKey.Domain("manga.wtf")
|
||||
|
||||
override val isTagsExclusionSupported = true
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isMultipleTagsSupported = true,
|
||||
isTagsExclusionSupported = true,
|
||||
isSearchSupported = true,
|
||||
isSearchWithFiltersSupported = false,
|
||||
)
|
||||
|
||||
override val availableStates: Set<MangaState> =
|
||||
EnumSet.of(
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
availableTags = fetchAvailableTags(),
|
||||
availableStates = EnumSet.of(
|
||||
MangaState.UPCOMING,
|
||||
MangaState.PAUSED,
|
||||
MangaState.ONGOING,
|
||||
MangaState.FINISHED,
|
||||
)
|
||||
|
||||
override val availableContentRating: Set<ContentRating> = EnumSet.allOf(ContentRating::class.java)
|
||||
),
|
||||
availableContentRating = EnumSet.allOf(ContentRating::class.java),
|
||||
)
|
||||
|
||||
init {
|
||||
paginator.firstPage = 0
|
||||
@@ -161,10 +169,8 @@ class MangaWtfParser(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getAvailableTags(): Set<MangaTag> {
|
||||
val url =
|
||||
urlBuilder("api")
|
||||
.addPathSegment("label")
|
||||
private suspend fun fetchAvailableTags(): Set<MangaTag> {
|
||||
val url = urlBuilder("api").addPathSegment("label")
|
||||
val json = webClient.httpGet(url.build()).parseJson()
|
||||
return json.getJSONArray("content").mapJSONToSet { jo ->
|
||||
MangaTag(
|
||||
|
||||
@@ -74,7 +74,7 @@ internal abstract class GroupleParser(
|
||||
isSearchWithFiltersSupported = true,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = true,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -40,7 +40,7 @@ internal abstract class LibSocialParser(
|
||||
isSearchWithFiltersSupported = true,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -30,7 +30,7 @@ internal abstract class ScanParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -29,7 +29,7 @@ class YaoiFlix(context: MangaLoaderContext) : PagedMangaParser(context, MangaPar
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -35,7 +35,7 @@ class YurinekoParser(context: MangaLoaderContext) : PagedMangaParser(context, Ma
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -72,7 +72,7 @@ internal abstract class WpComicsParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -6,7 +6,6 @@ import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.exception.NotFoundException
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilterV2
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaState
|
||||
|
||||
@@ -6,7 +6,6 @@ import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.exception.NotFoundException
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilterV2
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaState
|
||||
|
||||
@@ -42,7 +42,7 @@ internal abstract class ZeistMangaParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
@JvmField
|
||||
|
||||
@@ -46,7 +46,7 @@ internal abstract class ZMangaParser(
|
||||
isSearchWithFiltersSupported = false,
|
||||
isYearSupported = false,
|
||||
isYearRangeSupported = false,
|
||||
isSourceLocaleSupported = false,
|
||||
isOriginalLocaleSupported = false,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
|
||||
@@ -122,7 +122,7 @@ internal class MangaParserTest {
|
||||
}
|
||||
val filter = MangaListFilterV2(
|
||||
locale = locales.random(),
|
||||
sourceLocale = locales.random(),
|
||||
originalLocale = locales.random(),
|
||||
)
|
||||
val list = parser.getList(offset = 0, order = parser.defaultSortOrder, filter)
|
||||
checkMangaList(list, filter.locale.toString())
|
||||
|
||||
Reference in New Issue
Block a user