Migration to MangaListFilterCapabilities

master
Koitharu 2 years ago
parent 5030548500
commit 1c15e569bf
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -2,8 +2,8 @@ import tasks.ReportGenerateTask
plugins { plugins {
id 'java-library' id 'java-library'
id 'org.jetbrains.kotlin.jvm' version '2.0.10-RC' id 'org.jetbrains.kotlin.jvm' version '2.0.20'
id 'com.google.devtools.ksp' version '2.0.10-RC-1.0.23' id 'com.google.devtools.ksp' version '2.0.20-1.0.25'
id 'maven-publish' id 'maven-publish'
} }
@ -37,6 +37,7 @@ compileTestKotlin {
kotlin { kotlin {
jvmToolchain(8) jvmToolchain(8)
explicitApi = 'warning'
sourceSets { sourceSets {
main.kotlin.srcDirs += 'build/generated/ksp/main/kotlin' main.kotlin.srcDirs += 'build/generated/ksp/main/kotlin'
} }
@ -53,7 +54,7 @@ afterEvaluate {
} }
dependencies { dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0-RC' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.12.0' implementation 'com.squareup.okhttp3:okhttp:4.12.0'
implementation 'com.squareup.okio:okio:3.9.0' implementation 'com.squareup.okio:okio:3.9.0'
api 'org.jsoup:jsoup:1.18.1' api 'org.jsoup:jsoup:1.18.1'

@ -1,5 +1,5 @@
plugins { plugins {
id 'org.jetbrains.kotlin.jvm' version '2.0.10-RC' id 'org.jetbrains.kotlin.jvm' version '2.0.20'
} }
repositories { repositories {
@ -14,5 +14,5 @@ dependencies {
implementation gradleApi() implementation gradleApi()
implementation 'org.simpleframework:simple-xml:2.7.1' implementation 'org.simpleframework:simple-xml:2.7.1'
implementation 'com.soywiz.korlibs.korte:korte-jvm:4.0.10' implementation 'com.soywiz.korlibs.korte:korte-jvm:4.0.10'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0-RC' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0'
} }

@ -7,5 +7,5 @@ kotlin {
} }
dependencies { dependencies {
implementation 'com.google.devtools.ksp:symbol-processing-api:2.0.10-RC-1.0.23' implementation 'com.google.devtools.ksp:symbol-processing-api:2.0.20-1.0.25'
} }

@ -1,10 +1,9 @@
package org.koitharu.kotatsu.parsers package org.koitharu.kotatsu.parsers
import androidx.annotation.CallSuper import androidx.annotation.CallSuper
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import okhttp3.Headers import okhttp3.Headers
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.network.OkHttpWebClient import org.koitharu.kotatsu.parsers.network.OkHttpWebClient
import org.koitharu.kotatsu.parsers.network.WebClient import org.koitharu.kotatsu.parsers.network.WebClient
@ -14,9 +13,9 @@ import org.koitharu.kotatsu.parsers.util.domain
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
import java.util.* import java.util.*
abstract class MangaParser @InternalParsersApi constructor( public abstract class MangaParser @InternalParsersApi constructor(
@property:InternalParsersApi val context: MangaLoaderContext, @property:InternalParsersApi public val context: MangaLoaderContext,
val source: MangaParserSource, public val source: MangaParserSource,
) { ) {
/** /**
@ -24,43 +23,16 @@ abstract class MangaParser @InternalParsersApi constructor(
* *
* For better performance use [EnumSet] for more than one item. * For better performance use [EnumSet] for more than one item.
*/ */
abstract val availableSortOrders: Set<SortOrder> public abstract val availableSortOrders: Set<SortOrder>
/** public abstract val filterCapabilities: MangaListFilterCapabilities
* Supported [MangaState] variants for filtering. May be empty.
*
* For better performance use [EnumSet] for more than one item.
*/
@Deprecated("")
internal open val availableStates: Set<MangaState>
get() = emptySet()
open val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = isMultipleTagsSupported,
isTagsExclusionSupported = isTagsExclusionSupported,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
/** public val config: MangaSourceConfig by lazy { context.getConfig(source) }
* Whether parser supports filtering by more than one tag
*/
@Deprecated("Use getListFilterCapabilities instead")
internal open val isMultipleTagsSupported: Boolean = true
/** public open val sourceLocale: Locale
* Whether parser supports tagsExclude field in filter
*/
@Deprecated("Use getListFilterCapabilities instead")
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) get() = if (source.locale.isEmpty()) Locale.ROOT else Locale(source.locale)
protected val isNsfwSource = source.contentType == ContentType.HENTAI protected val isNsfwSource: Boolean = source.contentType == ContentType.HENTAI
/** /**
* Provide default domain and available alternatives, if any. * Provide default domain and available alternatives, if any.
@ -68,18 +40,18 @@ abstract class MangaParser @InternalParsersApi constructor(
* Never hardcode domain in requests, use [domain] instead. * Never hardcode domain in requests, use [domain] instead.
*/ */
@InternalParsersApi @InternalParsersApi
abstract val configKeyDomain: ConfigKey.Domain public abstract val configKeyDomain: ConfigKey.Domain
protected open val userAgentKey = ConfigKey.UserAgent(context.getDefaultUserAgent()) protected open val userAgentKey: ConfigKey.UserAgent = ConfigKey.UserAgent(context.getDefaultUserAgent())
open fun getRequestHeaders(): Headers = Headers.Builder() public open fun getRequestHeaders(): Headers = Headers.Builder()
.add("User-Agent", config[userAgentKey]) .add("User-Agent", config[userAgentKey])
.build() .build()
/** /**
* Used as fallback if value of `order` passed to [getList] is null * Used as fallback if value of `order` passed to [getList] is null
*/ */
open val defaultSortOrder: SortOrder public open val defaultSortOrder: SortOrder
get() { get() {
val supported = availableSortOrders val supported = availableSortOrders
return SortOrder.entries.first { it in supported } return SortOrder.entries.first { it in supported }
@ -96,55 +68,41 @@ abstract class MangaParser @InternalParsersApi constructor(
* @param order one of [availableSortOrders] or [defaultSortOrder] for default value * @param order one of [availableSortOrders] or [defaultSortOrder] for default value
* @param filter is a set of filter rules * @param filter is a set of filter rules
*/ */
abstract suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> public abstract suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga>
/** /**
* Parse details for [Manga]: chapters list, description, large cover, etc. * Parse details for [Manga]: chapters list, description, large cover, etc.
* Must return the same manga, may change any fields excepts id, url and source * Must return the same manga, may change any fields excepts id, url and source
* @see Manga.copy * @see Manga.copy
*/ */
abstract suspend fun getDetails(manga: Manga): Manga public abstract suspend fun getDetails(manga: Manga): Manga
/** /**
* Parse pages list for specified chapter. * Parse pages list for specified chapter.
* @see MangaPage for details * @see MangaPage for details
*/ */
abstract suspend fun getPages(chapter: MangaChapter): List<MangaPage> public abstract suspend fun getPages(chapter: MangaChapter): List<MangaPage>
/** /**
* Fetch direct link to the page image. * Fetch direct link to the page image.
*/ */
internal open suspend fun getPageUrl(page: MangaPage): String = page.url.toAbsoluteUrl(domain) internal open suspend fun getPageUrl(page: MangaPage): String = page.url.toAbsoluteUrl(domain)
/** public abstract suspend fun getFilterOptions(): MangaListFilterOptions
* Fetch available tags (genres) for source
*/
@Deprecated("Use getListFilterDatasets instead")
internal open suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
open suspend fun getFilterOptions(): MangaListFilterOptions = coroutineScope {
val tagsDeferred = async { getAvailableTags() }
MangaListFilterOptions(
availableTags = tagsDeferred.await(),
availableStates = availableStates,
availableContentRating = emptySet(),
availableLocales = emptySet(),
)
}
/** /**
* Parse favicons from the main page of the source`s website * Parse favicons from the main page of the source`s website
*/ */
open suspend fun getFavicons(): Favicons { public open suspend fun getFavicons(): Favicons {
return FaviconParser(webClient, domain).parseFavicons() return FaviconParser(webClient, domain).parseFavicons()
} }
@CallSuper @CallSuper
open fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { public open fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
keys.add(configKeyDomain) keys.add(configKeyDomain)
} }
open suspend fun getRelatedManga(seed: Manga): List<Manga> { public open suspend fun getRelatedManga(seed: Manga): List<Manga> {
return RelatedMangaFinder(listOf(this)).invoke(seed) return RelatedMangaFinder(listOf(this)).invoke(seed)
} }
} }

@ -8,7 +8,7 @@ import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.Paginator import org.koitharu.kotatsu.parsers.util.Paginator
@InternalParsersApi @InternalParsersApi
abstract class PagedMangaParser( public abstract class PagedMangaParser(
context: MangaLoaderContext, context: MangaLoaderContext,
source: MangaParserSource, source: MangaParserSource,
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) @JvmField internal val pageSize: Int, @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) @JvmField internal val pageSize: Int,
@ -16,10 +16,10 @@ abstract class PagedMangaParser(
) : MangaParser(context, source) { ) : MangaParser(context, source) {
@JvmField @JvmField
protected val paginator = Paginator(pageSize) protected val paginator: Paginator = Paginator(pageSize)
@JvmField @JvmField
protected val searchPaginator = Paginator(searchPageSize) protected val searchPaginator: Paginator = Paginator(searchPageSize)
final override suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { final override suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
return getList( return getList(
@ -34,7 +34,7 @@ abstract class PagedMangaParser(
) )
} }
abstract suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> public abstract suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga>
private suspend fun getList( private suspend fun getList(
paginator: Paginator, paginator: Paginator,

@ -23,7 +23,19 @@ internal abstract class LineWebtoonsParser(
source: MangaParserSource, source: MangaParserSource,
) : MangaParser(context, source) { ) : MangaParser(context, source) {
override val isMultipleTagsSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = emptySet(),
availableContentRating = emptySet(),
)
private val signer by lazy { private val signer by lazy {
WebtoonsUrlSigner("gUtPzJFZch4ZyAGviiyH94P99lQ3pFdRTwpJWDlSGFfwgpr6ses5ALOxWHOIT7R1") WebtoonsUrlSigner("gUtPzJFZch4ZyAGviiyH94P99lQ3pFdRTwpJWDlSGFfwgpr6ses5ALOxWHOIT7R1")
@ -237,7 +249,7 @@ internal abstract class LineWebtoonsParser(
) )
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
return makeRequest("/lineWebtoon/webtoon/challengeGenreList.json") return makeRequest("/lineWebtoon/webtoon/challengeGenreList.json")
.getJSONObject("genreList") .getJSONObject("genreList")
.getJSONArray("challengeGenres") .getJSONArray("challengeGenres")

@ -40,10 +40,21 @@ internal abstract class MangaPlusParser(
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
) )
private val extraHeaders = Headers.headersOf("Session-Token", UUID.randomUUID().toString()) override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
// no tags or tag search available override suspend fun getFilterOptions() = MangaListFilterOptions(
override suspend fun getAvailableTags(): Set<MangaTag> = emptySet() availableTags = emptySet(),
availableStates = emptySet(),
availableContentRating = emptySet(),
)
private val extraHeaders = Headers.headersOf("Session-Token", UUID.randomUUID().toString())
override suspend fun getList(order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getList(order: SortOrder, filter: MangaListFilterV2): List<Manga> {
return when { return when {

@ -16,7 +16,20 @@ internal class MangaStorm(context: MangaLoaderContext) : PagedMangaParser(contex
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.POPULARITY, SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.POPULARITY, SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain("mangastorm.org") override val configKeyDomain = ConfigKey.Domain("mangastorm.org")
override val isMultipleTagsSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = emptySet(),
availableStates = emptySet(),
availableContentRating = emptySet(),
)
override val userAgentKey = ConfigKey.UserAgent(UserAgents.CHROME_DESKTOP) override val userAgentKey = ConfigKey.UserAgent(UserAgents.CHROME_DESKTOP)
@ -78,8 +91,6 @@ internal class MangaStorm(context: MangaLoaderContext) : PagedMangaParser(contex
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
override suspend fun getDetails(manga: Manga): Manga { override suspend fun getDetails(manga: Manga): Manga {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val root = doc.selectFirstOrThrow(".card-body .col-lg-9") val root = doc.selectFirstOrThrow(".card-body .col-lg-9")

@ -25,6 +25,20 @@ internal class AnibelParser(context: MangaLoaderContext) : MangaParser(context,
override val configKeyDomain = ConfigKey.Domain("anibel.net") override val configKeyDomain = ConfigKey.Domain("anibel.net")
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(),
)
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
keys.add(userAgentKey) keys.add(userAgentKey)
@ -186,7 +200,7 @@ internal class AnibelParser(context: MangaLoaderContext) : MangaParser(context,
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val json = apiCall( val json = apiCall(
""" """
getFilters(mediaType: manga) { getFilters(mediaType: manga) {

@ -18,6 +18,20 @@ internal class CloneMangaParser(context: MangaLoaderContext) :
override val configKeyDomain = ConfigKey.Domain("manga.clone-army.org") override val configKeyDomain = ConfigKey.Domain("manga.clone-army.org")
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = emptySet(),
availableStates = emptySet(),
availableContentRating = emptySet(),
)
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
keys.add(userAgentKey) keys.add(userAgentKey)
@ -92,6 +106,4 @@ internal class CloneMangaParser(context: MangaLoaderContext) :
), ),
) )
} }
override suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
} }

@ -17,19 +17,29 @@ internal class ComicExtra(context: MangaLoaderContext) : PagedMangaParser(contex
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.POPULARITY, SortOrder.UPDATED, SortOrder.NEWEST) EnumSet.of(SortOrder.POPULARITY, SortOrder.UPDATED, SortOrder.NEWEST)
override val availableStates: Set<MangaState> = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED)
override val configKeyDomain = ConfigKey.Domain("comixextra.com") override val configKeyDomain = ConfigKey.Domain("comixextra.com")
override val userAgentKey = ConfigKey.UserAgent(UserAgents.CHROME_DESKTOP) override val userAgentKey = ConfigKey.UserAgent(UserAgents.CHROME_DESKTOP)
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED),
availableContentRating = emptySet(),
)
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
keys.add(userAgentKey) keys.add(userAgentKey)
} }
override val isMultipleTagsSupported = false
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")
@ -103,7 +113,7 @@ internal class ComicExtra(context: MangaLoaderContext) : PagedMangaParser(contex
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/popular-comic").parseHtml() val doc = webClient.httpGet("https://$domain/popular-comic").parseHtml()
return doc.select("li.tag-item a").mapNotNullToSet { a -> return doc.select("li.tag-item a").mapNotNullToSet { a ->
MangaTag( MangaTag(

@ -25,13 +25,25 @@ internal class DynastyScans(context: MangaLoaderContext) :
override val userAgentKey = ConfigKey.UserAgent(UserAgents.CHROME_DESKTOP) override val userAgentKey = ConfigKey.UserAgent(UserAgents.CHROME_DESKTOP)
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = emptySet(),
availableContentRating = emptySet(),
)
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
keys.add(userAgentKey) keys.add(userAgentKey)
} }
override val isMultipleTagsSupported = false
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
when { when {
!filter.query.isNullOrEmpty() -> { !filter.query.isNullOrEmpty() -> {
@ -120,7 +132,7 @@ internal class DynastyScans(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
return coroutineScope { return coroutineScope {
(1..3).map { page -> (1..3).map { page ->
async { getTags(page) } async { getTags(page) }

@ -19,7 +19,19 @@ internal class MangaGeko(context: MangaLoaderContext) : PagedMangaParser(context
override val configKeyDomain = ConfigKey.Domain("www.mgeko.cc", "www.mgeko.com", "www.mangageko.com") override val configKeyDomain = ConfigKey.Domain("www.mgeko.cc", "www.mgeko.com", "www.mangageko.com")
override val isMultipleTagsSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = emptySet(),
availableContentRating = emptySet(),
)
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
@ -81,7 +93,7 @@ internal class MangaGeko(context: MangaLoaderContext) : PagedMangaParser(context
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/browse-comics/").parseHtml() val doc = webClient.httpGet("https://$domain/browse-comics/").parseHtml()
return doc.select("label.checkbox-inline").mapNotNullToSet { label -> return doc.select("label.checkbox-inline").mapNotNullToSet { label ->
MangaTag( MangaTag(

@ -20,6 +20,20 @@ internal class MangaKawaiiEn(context: MangaLoaderContext) :
override val configKeyDomain = ConfigKey.Domain("www.mangakawaii.io") override val configKeyDomain = ConfigKey.Domain("www.mangakawaii.io")
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = emptySet(),
availableContentRating = emptySet(),
)
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
keys.add(userAgentKey) keys.add(userAgentKey)
@ -29,8 +43,6 @@ internal class MangaKawaiiEn(context: MangaLoaderContext) :
.add("Accept-Language", "en") .add("Accept-Language", "en")
.build() .build()
override val isMultipleTagsSupported = false
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")
@ -155,7 +167,7 @@ internal class MangaKawaiiEn(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/manga-list/").parseHtml() val doc = webClient.httpGet("https://$domain/manga-list/").parseHtml()
return doc.select("ul li a.category").mapNotNullToSet { a -> return doc.select("ul li a.category").mapNotNullToSet { a ->
val name = a.text() val name = a.text()

@ -28,12 +28,22 @@ internal class MangaTownParser(context: MangaLoaderContext) :
SortOrder.UPDATED, SortOrder.UPDATED,
) )
override val availableStates: Set<MangaState> = EnumSet.of( override val filterCapabilities: MangaListFilterCapabilities
MangaState.ONGOING, get() = MangaListFilterCapabilities(
MangaState.FINISHED, isMultipleTagsSupported = false,
) isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override val isMultipleTagsSupported = false override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = EnumSet.of(
MangaState.ONGOING,
MangaState.FINISHED,
),
availableContentRating = emptySet(),
)
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val url = buildString { val url = buildString {
@ -220,7 +230,7 @@ internal class MangaTownParser(context: MangaLoaderContext) :
return doc.requireElementById("image").attrAsAbsoluteUrl("src") return doc.requireElementById("image").attrAsAbsoluteUrl("src")
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("/directory/".toAbsoluteUrl(domain)).parseHtml() val doc = webClient.httpGet("/directory/".toAbsoluteUrl(domain)).parseHtml()
val root = doc.body().selectFirst("aside.right") val root = doc.body().selectFirst("aside.right")
?.getElementsContainingOwnText("Genres") ?.getElementsContainingOwnText("Genres")

@ -10,7 +10,7 @@ import org.koitharu.kotatsu.parsers.util.*
import java.util.* import java.util.*
@MangaSourceParser("MANHWA18", "Manhwa18.net", "en", type = ContentType.HENTAI) @MangaSourceParser("MANHWA18", "Manhwa18.net", "en", type = ContentType.HENTAI)
class Manhwa18Parser(context: MangaLoaderContext) : internal class Manhwa18Parser(context: MangaLoaderContext) :
PagedMangaParser(context, MangaParserSource.MANHWA18, pageSize = 18, searchPageSize = 18) { PagedMangaParser(context, MangaParserSource.MANHWA18, pageSize = 18, searchPageSize = 18) {
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("manhwa18.net") override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("manhwa18.net")
@ -29,15 +29,25 @@ class Manhwa18Parser(context: MangaLoaderContext) :
SortOrder.RATING, SortOrder.RATING,
) )
override val availableStates: Set<MangaState> = EnumSet.of( private val tagsMap = SuspendLazy(::parseTags)
MangaState.ONGOING,
MangaState.FINISHED,
MangaState.PAUSED,
)
override val isTagsExclusionSupported = true override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = true,
isTagsExclusionSupported = true,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
private val tagsMap = SuspendLazy(::parseTags) override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = tagsMap.get().values.toSet(),
availableStates = EnumSet.of(
MangaState.ONGOING,
MangaState.FINISHED,
MangaState.PAUSED,
),
availableContentRating = emptySet(),
)
override suspend fun getFavicons(): Favicons { override suspend fun getFavicons(): Favicons {
return Favicons( return Favicons(
@ -218,10 +228,6 @@ class Manhwa18Parser(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> {
return tagsMap.get().values.toSet()
}
private suspend fun parseTags(): Map<String, MangaTag> { private suspend fun parseTags(): Map<String, MangaTag> {
val doc = webClient.httpGet("https://$domain/tim-kiem?q=").parseHtml() val doc = webClient.httpGet("https://$domain/tim-kiem?q=").parseHtml()
val list = doc.getElementsByAttribute("data-genre-id") val list = doc.getElementsByAttribute("data-genre-id")

@ -11,7 +11,7 @@ import java.text.SimpleDateFormat
import java.util.* import java.util.*
@MangaSourceParser("MANHWASMEN", "ManhwasMen", "en", type = ContentType.HENTAI) @MangaSourceParser("MANHWASMEN", "ManhwasMen", "en", type = ContentType.HENTAI)
class ManhwasMen(context: MangaLoaderContext) : internal class ManhwasMen(context: MangaLoaderContext) :
PagedMangaParser(context, MangaParserSource.MANHWASMEN, pageSize = 30, searchPageSize = 30) { PagedMangaParser(context, MangaParserSource.MANHWASMEN, pageSize = 30, searchPageSize = 30) {
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("manhwas.men") override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("manhwas.men")
@ -21,12 +21,22 @@ class ManhwasMen(context: MangaLoaderContext) :
keys.add(userAgentKey) keys.add(userAgentKey)
} }
override val isMultipleTagsSupported = false
override val availableSortOrders: Set<SortOrder> override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.POPULARITY) get() = EnumSet.of(SortOrder.POPULARITY)
override val availableStates: Set<MangaState> = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED) override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED),
availableContentRating = emptySet(),
)
override suspend fun getListPage( override suspend fun getListPage(
page: Int, page: Int,
@ -85,7 +95,7 @@ class ManhwasMen(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val tags = webClient.httpGet("https://$domain/manga-list").parseHtml() val tags = webClient.httpGet("https://$domain/manga-list").parseHtml()
.selectLastOrThrow(".filter-bx .form-group select.custom-select").select("option").drop(1) .selectLastOrThrow(".filter-bx .form-group select.custom-select").select("option").drop(1)
return tags.mapNotNullToSet { option -> return tags.mapNotNullToSet { option ->

@ -1,7 +1,6 @@
package org.koitharu.kotatsu.parsers.site.en package org.koitharu.kotatsu.parsers.site.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaParser
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.SinglePageMangaParser import org.koitharu.kotatsu.parsers.SinglePageMangaParser
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.config.ConfigKey
@ -16,6 +15,20 @@ internal class Po2Scans(context: MangaLoaderContext) : SinglePageMangaParser(con
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL)
override val configKeyDomain = ConfigKey.Domain("po2scans.com") override val configKeyDomain = ConfigKey.Domain("po2scans.com")
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = emptySet(),
availableStates = emptySet(),
availableContentRating = emptySet(),
)
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
keys.add(userAgentKey) keys.add(userAgentKey)
@ -51,8 +64,6 @@ internal class Po2Scans(context: MangaLoaderContext) : SinglePageMangaParser(con
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
override suspend fun getDetails(manga: Manga): Manga { override suspend fun getDetails(manga: Manga): Manga {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val dateFormat = SimpleDateFormat("dd MMM, yy", Locale.ENGLISH) val dateFormat = SimpleDateFormat("dd MMM, yy", Locale.ENGLISH)

@ -22,13 +22,25 @@ internal class Pururin(context: MangaLoaderContext) :
override val configKeyDomain = ConfigKey.Domain("pururin.to") override val configKeyDomain = ConfigKey.Domain("pururin.to")
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = emptySet(),
availableContentRating = emptySet(),
)
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
keys.add(userAgentKey) keys.add(userAgentKey)
} }
override val isMultipleTagsSupported = false
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")
@ -84,7 +96,7 @@ internal class Pururin(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
return coroutineScope { return coroutineScope {
(1..4).map { page -> (1..4).map { page ->
async { getTags(page) } async { getTags(page) }

@ -11,7 +11,7 @@ import java.text.SimpleDateFormat
import java.util.* import java.util.*
@MangaSourceParser("VYMANGA", "VyManga", "en") @MangaSourceParser("VYMANGA", "VyManga", "en")
class VyManga(context: MangaLoaderContext) : internal class VyManga(context: MangaLoaderContext) :
PagedMangaParser(context, MangaParserSource.VYMANGA, pageSize = 36) { PagedMangaParser(context, MangaParserSource.VYMANGA, pageSize = 36) {
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("vymanga.net") override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("vymanga.net")
@ -21,8 +21,6 @@ class VyManga(context: MangaLoaderContext) :
keys.add(userAgentKey) keys.add(userAgentKey)
} }
override val isMultipleTagsSupported = false
override val availableSortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.POPULARITY_ASC, SortOrder.POPULARITY_ASC,
@ -34,7 +32,19 @@ class VyManga(context: MangaLoaderContext) :
SortOrder.UPDATED_ASC, SortOrder.UPDATED_ASC,
) )
override val availableStates: Set<MangaState> = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED) override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED),
availableContentRating = emptySet(),
)
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val url = buildString { val url = buildString {
@ -120,7 +130,7 @@ class VyManga(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/").parseHtml() val doc = webClient.httpGet("https://$domain/").parseHtml()
return doc.select("div.dropdown-menu.custom-menu ul li a[href*=genre]").mapNotNullToSet { return doc.select("div.dropdown-menu.custom-menu ul li a[href*=genre]").mapNotNullToSet {
MangaTag( MangaTag(

@ -73,7 +73,7 @@ internal class Manhwa18Com(context: MangaLoaderContext) :
return parseMangaList(webClient.httpGet(url).parseHtml()) return parseMangaList(webClient.httpGet(url).parseHtml())
} }
override suspend fun getAvailableTags(): Set<MangaTag> { override suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml() val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml()
return doc.select(selectBodyTag).mapNotNullToSet { label -> return doc.select(selectBodyTag).mapNotNullToSet { label ->
val key = label.attr("data-genre-id") val key = label.attr("data-genre-id")

@ -14,8 +14,12 @@ internal class OlimpoScans(context: MangaLoaderContext) :
override val selectAlt = "ul.manga-info li:contains(Otros nombres)" override val selectAlt = "ul.manga-info li:contains(Otros nombres)"
override val selectTag = "ul.manga-info li:contains(Género) a" override val selectTag = "ul.manga-info li:contains(Género) a"
override val tagPrefix = "lista-de-comics-genero-" override val tagPrefix = "lista-de-comics-genero-"
override val isMultipleTagsSupported = false
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
)
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val url = buildString { val url = buildString {

@ -37,16 +37,25 @@ internal class BentomangaParser(context: MangaLoaderContext) :
keys.add(userAgentKey) keys.add(userAgentKey)
} }
override val availableStates: Set<MangaState> =
EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED)
override val isTagsExclusionSupported: Boolean = true
init { init {
paginator.firstPage = 0 paginator.firstPage = 0
searchPaginator.firstPage = 0 searchPaginator.firstPage = 0
} }
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = true,
isTagsExclusionSupported = true,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED),
availableContentRating = emptySet(),
)
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val url = urlBuilder() val url = urlBuilder()
.host(domain) .host(domain)
@ -206,7 +215,7 @@ internal class BentomangaParser(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val root = webClient.httpGet(urlBuilder().addPathSegment("manga_list").build()) val root = webClient.httpGet(urlBuilder().addPathSegment("manga_list").build())
.parseHtml() .parseHtml()
.requireElementById("search_options-form") .requireElementById("search_options-form")

@ -17,11 +17,22 @@ internal class LegacyScansParser(context: MangaLoaderContext) :
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.POPULARITY) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.POPULARITY)
override val availableStates: Set<MangaState> =
EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.ABANDONED, MangaState.PAUSED)
override val configKeyDomain = ConfigKey.Domain("legacy-scans.com") override val configKeyDomain = ConfigKey.Domain("legacy-scans.com")
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = true,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.ABANDONED, MangaState.PAUSED),
availableContentRating = emptySet(),
)
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
keys.add(userAgentKey) keys.add(userAgentKey)
@ -163,7 +174,7 @@ internal class LegacyScansParser(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/comics").parseHtml() val doc = webClient.httpGet("https://$domain/comics").parseHtml()
val script = doc.requireElementById("__NUXT_DATA__").data() val script = doc.requireElementById("__NUXT_DATA__").data()
.substringAfterLast("\"genres\"").substringBeforeLast("\"comics\"") .substringAfterLast("\"genres\"").substringBeforeLast("\"comics\"")

@ -18,13 +18,25 @@ internal class LireScan(context: MangaLoaderContext) : PagedMangaParser(context,
override val configKeyDomain = ConfigKey.Domain("lire-scan.me") override val configKeyDomain = ConfigKey.Domain("lire-scan.me")
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = emptySet(),
availableContentRating = emptySet(),
)
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
keys.add(userAgentKey) keys.add(userAgentKey)
} }
override val isMultipleTagsSupported = false
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val doc = when { val doc = when {
!filter.query.isNullOrEmpty() -> { !filter.query.isNullOrEmpty() -> {
@ -133,7 +145,7 @@ internal class LireScan(context: MangaLoaderContext) : PagedMangaParser(context,
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/").parseHtml() val doc = webClient.httpGet("https://$domain/").parseHtml()
return doc.select(".nav-menu li a").mapNotNullToSet { a -> return doc.select(".nav-menu li a").mapNotNullToSet { a ->
val key = a.attr("href").removeSuffix('/').substringAfterLast("manga/", "") val key = a.attr("href").removeSuffix('/').substringAfterLast("manga/", "")

@ -19,6 +19,20 @@ internal class MangaKawaii(context: MangaLoaderContext) : PagedMangaParser(conte
override val configKeyDomain = ConfigKey.Domain("www.mangakawaii.io") override val configKeyDomain = ConfigKey.Domain("www.mangakawaii.io")
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = emptySet(),
availableContentRating = emptySet(),
)
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
keys.add(userAgentKey) keys.add(userAgentKey)
@ -28,8 +42,6 @@ internal class MangaKawaii(context: MangaLoaderContext) : PagedMangaParser(conte
.add("Accept-Language", "fr") .add("Accept-Language", "fr")
.build() .build()
override val isMultipleTagsSupported = false
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")
@ -154,7 +166,7 @@ internal class MangaKawaii(context: MangaLoaderContext) : PagedMangaParser(conte
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/manga-list/").parseHtml() val doc = webClient.httpGet("https://$domain/manga-list/").parseHtml()
return doc.select("ul li a.category").mapNotNullToSet { a -> return doc.select("ul li a.category").mapNotNullToSet { a ->
val name = a.text() val name = a.text()

@ -32,18 +32,27 @@ internal class MangaMana(context: MangaLoaderContext) : PagedMangaParser(context
SortOrder.NEWEST, SortOrder.NEWEST,
) )
override val availableStates: Set<MangaState> =
EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.ABANDONED)
override val configKeyDomain = ConfigKey.Domain("www.manga-mana.com") override val configKeyDomain = ConfigKey.Domain("www.manga-mana.com")
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.ABANDONED),
availableContentRating = emptySet(),
)
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
keys.add(userAgentKey) keys.add(userAgentKey)
} }
override val isMultipleTagsSupported = false
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val postData = buildString { val postData = buildString {
append("page=") append("page=")
@ -98,7 +107,7 @@ internal class MangaMana(context: MangaLoaderContext) : PagedMangaParser(context
val doc = webClient.httpGet("https://$domain/?page=$page").parseHtml() val doc = webClient.httpGet("https://$domain/?page=$page").parseHtml()
return doc.select("div.row div.col_home").map { div -> return doc.select("div.row div.col_home").map { div ->
val href = div.selectFirstOrThrow("h4 a").attrAsRelativeUrl("href") val href = div.selectFirstOrThrow("h4 a").attrAsRelativeUrl("href")
val isNsfw = div.selectFirst("img[data-adult]")?.attr("data-adult")?.isNotEmpty() ?: false val isNsfw = div.selectFirst("img[data-adult]")?.attr("data-adult")?.isNotEmpty() == true
val img = if (isNsfw) { val img = if (isNsfw) {
div.selectFirst("img")?.attr("data-adult") div.selectFirst("img")?.attr("data-adult")
} else { } else {
@ -159,7 +168,7 @@ internal class MangaMana(context: MangaLoaderContext) : PagedMangaParser(context
return doc.select("div.p-2 div.col").map { div -> return doc.select("div.p-2 div.col").map { div ->
val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href") val href = div.selectFirstOrThrow("a").attrAsRelativeUrl("href")
val isNsfw = div.selectFirst("img[data-adult]")?.attr("data-adult")?.isNotEmpty() ?: false val isNsfw = div.selectFirst("img[data-adult]")?.attr("data-adult")?.isNotEmpty() == true
val img = if (isNsfw) { val img = if (isNsfw) {
div.selectFirst("img")?.attr("data-adult") div.selectFirst("img")?.attr("data-adult")
} else { } else {
@ -320,7 +329,7 @@ internal class MangaMana(context: MangaLoaderContext) : PagedMangaParser(context
return pages return pages
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/liste-mangas").parseHtml() val doc = webClient.httpGet("https://$domain/liste-mangas").parseHtml()
return doc.select("select.selectpicker option").drop(1).mapNotNullToSet { return doc.select("select.selectpicker option").drop(1).mapNotNullToSet {
MangaTag( MangaTag(

@ -31,12 +31,6 @@ internal abstract class FuzzyDoodleParser(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.NEWEST) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.NEWEST)
override val availableStates: Set<MangaState> =
EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED)
override val isMultipleTagsSupported = true
@JvmField @JvmField
protected val ongoing = scatterSetOf( protected val ongoing = scatterSetOf(
"en cours", "en cours",
@ -73,7 +67,21 @@ internal abstract class FuzzyDoodleParser(
protected open val pausedValue = "haitus" protected open val pausedValue = "haitus"
protected open val abandonedValue = "dropped" protected open val abandonedValue = "dropped"
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = true,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED, MangaState.ABANDONED),
availableContentRating = emptySet(),
)
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")
append(domain) append(domain)
@ -250,7 +258,7 @@ internal abstract class FuzzyDoodleParser(
protected open val selectTagsList = "div.mt-1 div.items-center:has(label)" protected open val selectTagsList = "div.mt-1 div.items-center:has(label)"
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/manga").parseHtml() val doc = webClient.httpGet("https://$domain/manga").parseHtml()
return doc.select(selectTagsList).mapNotNullToSet { return doc.select(selectTagsList).mapNotNullToSet {
val key = it.selectFirst("input")?.attr("value") ?: return@mapNotNullToSet null val key = it.selectFirst("input")?.attr("value") ?: return@mapNotNullToSet null

@ -6,14 +6,17 @@ import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.MangaState import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.site.fuzzydoodle.FuzzyDoodleParser import org.koitharu.kotatsu.parsers.site.fuzzydoodle.FuzzyDoodleParser
import java.util.EnumSet import java.util.*
@MangaSourceParser("HENTAISLAYER", "HentaiSlayer", "ar", ContentType.HENTAI) @MangaSourceParser("HENTAISLAYER", "HentaiSlayer", "ar", ContentType.HENTAI)
internal class HentaiSlayer(context: MangaLoaderContext) : internal class HentaiSlayer(context: MangaLoaderContext) :
FuzzyDoodleParser(context, MangaParserSource.HENTAISLAYER, "hentaislayer.net") { FuzzyDoodleParser(context, MangaParserSource.HENTAISLAYER, "hentaislayer.net") {
override val availableStates: Set<MangaState> =
EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.ABANDONED)
override val ongoingValue = "مستمر" override val ongoingValue = "مستمر"
override val finishedValue = "مكتمل" override val finishedValue = "مكتمل"
override val abandonedValue = "متوقف" override val abandonedValue = "متوقف"
override suspend fun getFilterOptions() = super.getFilterOptions().copy(
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.ABANDONED),
)
} }

@ -5,12 +5,16 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.MangaState import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.site.fuzzydoodle.FuzzyDoodleParser import org.koitharu.kotatsu.parsers.site.fuzzydoodle.FuzzyDoodleParser
import java.util.EnumSet import java.util.*
@MangaSourceParser("LELSCANVF", "LelScanFr", "fr") @MangaSourceParser("LELSCANVF", "LelScanFr", "fr")
internal class LelScanVf(context: MangaLoaderContext) : internal class LelScanVf(context: MangaLoaderContext) :
FuzzyDoodleParser(context, MangaParserSource.LELSCANVF, "lelscanfr.com") { FuzzyDoodleParser(context, MangaParserSource.LELSCANVF, "lelscanfr.com") {
override val availableStates: Set<MangaState> = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED)
override val ongoingValue = "en-cours" override val ongoingValue = "en-cours"
override val finishedValue = "termin" override val finishedValue = "termin"
override suspend fun getFilterOptions() = super.getFilterOptions().copy(
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED),
)
} }

@ -18,7 +18,10 @@ internal class HentaiFox(context: MangaLoaderContext) :
override val selectTag = "ul.tags" override val selectTag = "ul.tags"
override val selectLanguageChapter = "ul.languages a.tag_btn" override val selectLanguageChapter = "ul.languages a.tag_btn"
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 val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)

@ -25,7 +25,19 @@ internal abstract class GattsuParser(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val isMultipleTagsSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = emptySet(),
availableContentRating = emptySet(),
)
protected open val tagPrefix = "tag" protected open val tagPrefix = "tag"
@ -86,7 +98,7 @@ internal abstract class GattsuParser(
protected open val tagUrl = "generos" protected open val tagUrl = "generos"
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$tagUrl/").parseHtml() val doc = webClient.httpGet("https://$domain/$tagUrl/").parseHtml()
return doc.selectLastOrThrow(".meio-conteudo p, div.lista-tags ul").parseTags() return doc.selectLastOrThrow(".meio-conteudo p, div.lista-tags ul").parseTags()
} }

@ -13,7 +13,21 @@ internal class UniversoHentai(context: MangaLoaderContext) :
override val tagPrefix = "category" override val tagPrefix = "category"
override suspend fun getAvailableTags(): Set<MangaTag> { 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(),
)
private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/tags/").parseHtml() val doc = webClient.httpGet("https://$domain/tags/").parseHtml()
return doc.requireElementById("menu-topo").parseTags() return doc.requireElementById("menu-topo").parseTags()
} }

@ -25,8 +25,19 @@ class DoujinDesuParser(context: MangaLoaderContext) :
override val availableSortOrders: Set<SortOrder> override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.UPDATED, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.POPULARITY) get() = EnumSet.of(SortOrder.UPDATED, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.POPULARITY)
override val availableStates: Set<MangaState> = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED) override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = true,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED),
availableContentRating = emptySet(),
)
override fun getRequestHeaders(): Headers = Headers.Builder() override fun getRequestHeaders(): Headers = Headers.Builder()
.add("X-Requested-With", "XMLHttpRequest") .add("X-Requested-With", "XMLHttpRequest")
@ -158,7 +169,7 @@ class DoujinDesuParser(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
return webClient.httpGet("/genre/".toAbsoluteUrl(domain)).parseHtml() return webClient.httpGet("/genre/".toAbsoluteUrl(domain)).parseHtml()
.requireElementById("taxonomy") .requireElementById("taxonomy")
.selectFirstOrThrow(".entries") .selectFirstOrThrow(".entries")

@ -17,13 +17,25 @@ internal class HentaiCrot(context: MangaLoaderContext) :
) )
override val configKeyDomain = ConfigKey.Domain("hentaicrot.com") override val configKeyDomain = ConfigKey.Domain("hentaicrot.com")
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = emptySet(),
availableContentRating = emptySet(),
)
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
keys.add(userAgentKey) keys.add(userAgentKey)
} }
override val isMultipleTagsSupported = false
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")
@ -71,7 +83,7 @@ internal class HentaiCrot(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain").parseHtml() val doc = webClient.httpGet("https://$domain").parseHtml()
return doc.select("ul.megamenu li").mapNotNullToSet { li -> return doc.select("ul.megamenu li").mapNotNullToSet { li ->
val key = li.selectFirstOrThrow("a").attr("href").removeSuffix('/').substringAfterLast('/') val key = li.selectFirstOrThrow("a").attr("href").removeSuffix('/').substringAfterLast('/')

@ -17,13 +17,25 @@ internal class PixHentai(context: MangaLoaderContext) :
) )
override val configKeyDomain = ConfigKey.Domain("pixhentai.com") override val configKeyDomain = ConfigKey.Domain("pixhentai.com")
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = emptySet(),
availableContentRating = emptySet(),
)
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
keys.add(userAgentKey) keys.add(userAgentKey)
} }
override val isMultipleTagsSupported = false
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")
@ -71,7 +83,7 @@ internal class PixHentai(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain").parseHtml() val doc = webClient.httpGet("https://$domain").parseHtml()
return doc.select("ul.megamenu li").mapNotNullToSet { li -> return doc.select("ul.megamenu li").mapNotNullToSet { li ->
val key = li.selectFirstOrThrow("a").attr("href").removeSuffix('/').substringAfterLast('/') val key = li.selectFirstOrThrow("a").attr("href").removeSuffix('/').substringAfterLast('/')

@ -1,6 +1,9 @@
package org.koitharu.kotatsu.parsers.site.ja package org.koitharu.kotatsu.parsers.site.ja
import org.koitharu.kotatsu.parsers.* import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaParser
import org.koitharu.kotatsu.parsers.MangaParserAuthProvider
import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.model.*
@ -12,12 +15,26 @@ private const val STATUS_ONGOING = "連載"
private const val STATUS_FINISHED = "完結" private const val STATUS_FINISHED = "完結"
@MangaSourceParser("NICOVIDEO_SEIGA", "NicoVideo Seiga", "ja") @MangaSourceParser("NICOVIDEO_SEIGA", "NicoVideo Seiga", "ja")
class NicovideoSeigaParser(context: MangaLoaderContext) : internal class NicovideoSeigaParser(context: MangaLoaderContext) :
MangaParser(context, MangaParserSource.NICOVIDEO_SEIGA), MangaParser(context, MangaParserSource.NICOVIDEO_SEIGA),
MangaParserAuthProvider { MangaParserAuthProvider {
override val userAgentKey = ConfigKey.UserAgent(UserAgents.CHROME_DESKTOP) override val userAgentKey = ConfigKey.UserAgent(UserAgents.CHROME_DESKTOP)
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = emptySet(),
availableContentRating = emptySet(),
)
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) { override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
super.onCreateConfig(keys) super.onCreateConfig(keys)
keys.add(userAgentKey) keys.add(userAgentKey)
@ -41,8 +58,6 @@ class NicovideoSeigaParser(context: MangaLoaderContext) :
SortOrder.POPULARITY, SortOrder.POPULARITY,
) )
override val isMultipleTagsSupported = false
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("nicovideo.jp") override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("nicovideo.jp")
override suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
@ -139,7 +154,7 @@ class NicovideoSeigaParser(context: MangaLoaderContext) :
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> { override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val fullUrl = chapter.url.toAbsoluteUrl(getDomain("seiga")) val fullUrl = chapter.url.toAbsoluteUrl(getDomain("seiga"))
val doc = webClient.httpGet(fullUrl).parseHtml() val doc = webClient.httpGet(fullUrl).parseHtml()
if (!doc.select("#login_manga").isEmpty()) if (!doc.select("#login_manga").isEmpty)
throw AuthRequiredException(source) throw AuthRequiredException(source)
val root = doc.body().select("#page_contents > li") val root = doc.body().select("#page_contents > li")
return root.map { li -> return root.map { li ->
@ -153,7 +168,7 @@ class NicovideoSeigaParser(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://${getDomain("seiga")}/manga/list").parseHtml() val doc = webClient.httpGet("https://${getDomain("seiga")}/manga/list").parseHtml()
val root = doc.body().selectOrThrow("#mg_category_list > ul > li").drop(1) val root = doc.body().selectOrThrow("#mg_category_list > ul > li").drop(1)
return root.mapToSet { li -> return root.mapToSet { li ->

@ -26,8 +26,6 @@ internal abstract class KeyoappParser(
keys.add(userAgentKey) keys.add(userAgentKey)
} }
override val isMultipleTagsSupported = false
override val availableSortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.NEWEST, SortOrder.NEWEST,
@ -57,6 +55,19 @@ internal abstract class KeyoappParser(
"dropped", "dropped",
) )
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = emptySet(),
availableContentRating = emptySet(),
)
override suspend fun getList(order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getList(order: SortOrder, filter: MangaListFilterV2): List<Manga> {
var query = "" var query = ""
@ -160,7 +171,7 @@ internal abstract class KeyoappParser(
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml() val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml()
return doc.requireElementById("series_tags_page").select("button").mapNotNullToSet { button -> return doc.requireElementById("series_tags_page").select("button").mapNotNullToSet { button ->
val key = button.attr("tag") ?: return@mapNotNullToSet null val key = button.attr("tag") ?: return@mapNotNullToSet null

@ -32,10 +32,19 @@ internal abstract class LikeMangaParser(
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST)
override val availableStates: Set<MangaState> = override val filterCapabilities: MangaListFilterCapabilities
EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED) get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override val isMultipleTagsSupported = false override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.PAUSED),
availableContentRating = emptySet(),
)
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val url = buildString { val url = buildString {
@ -113,7 +122,7 @@ internal abstract class LikeMangaParser(
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/genres/").parseHtml() val doc = webClient.httpGet("https://$domain/genres/").parseHtml()
return doc.select("ul.nav-genres li:not(.text-center) a").mapNotNullToSet { a -> return doc.select("ul.nav-genres li:not(.text-center) a").mapNotNullToSet { a ->
MangaTag( MangaTag(

@ -82,7 +82,7 @@ internal class Manga18Fx(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { override suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml() val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml()
val list = doc.body().selectFirstOrThrow("div.genre-menu").select("ul li").orEmpty() val list = doc.body().selectFirstOrThrow("div.genre-menu").select("ul li").orEmpty()
val keySet = HashSet<String>(list.size) val keySet = HashSet<String>(list.size)

@ -15,7 +15,6 @@ internal class Manhwa18Cc(context: MangaLoaderContext) :
override val listUrl = "webtoons/" override val listUrl = "webtoons/"
override val tagPrefix = "webtoon-genre/" override val tagPrefix = "webtoon-genre/"
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
override val selectTestAsync = "ul.row-content-chapter" override val selectTestAsync = "ul.row-content-chapter"
@ -23,6 +22,11 @@ internal class Manhwa18Cc(context: MangaLoaderContext) :
override val selectChapter = "li.a-h" override val selectChapter = "li.a-h"
override val selectBodyPage = "div.read-content" override val selectBodyPage = "div.read-content"
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
init { init {
paginator.firstPage = 1 paginator.firstPage = 1
searchPaginator.firstPage = 1 searchPaginator.firstPage = 1
@ -91,7 +95,7 @@ internal class Manhwa18Cc(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { override suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml() val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml()
val list = doc.body().selectFirstOrThrow("div.sub-menu").select("ul li").orEmpty() val list = doc.body().selectFirstOrThrow("div.sub-menu").select("ul li").orEmpty()
val keySet = HashSet<String>(list.size) val keySet = HashSet<String>(list.size)

@ -2,10 +2,11 @@ package org.koitharu.kotatsu.parsers.site.madara.ar
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@MangaSourceParser("GATEMANGA", "GateManga", "ar") @MangaSourceParser("GATEMANGA", "GateManga", "ar")
internal class GateManga(context: MangaLoaderContext) : internal class GateManga(context: MangaLoaderContext) :
@ -14,7 +15,11 @@ internal class GateManga(context: MangaLoaderContext) :
override val datePattern = "d MMMM، yyyy" override val datePattern = "d MMMM، yyyy"
override val listUrl = "ar/" override val listUrl = "ar/"
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)

@ -2,17 +2,21 @@ package org.koitharu.kotatsu.parsers.site.madara.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@MangaSourceParser("BESTMANHUACOM", "BestManhua.com", "en") @MangaSourceParser("BESTMANHUACOM", "BestManhua.com", "en")
internal class BestManhuaCom(context: MangaLoaderContext) : internal class BestManhuaCom(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.BESTMANHUACOM, "bestmanhua.com", 10) { MadaraParser(context, MangaParserSource.BESTMANHUACOM, "bestmanhua.com", 10) {
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -3,7 +3,10 @@ package org.koitharu.kotatsu.parsers.site.madara.en
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.* import org.koitharu.kotatsu.parsers.util.*
@ -52,7 +55,7 @@ internal class FireScans(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { override suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/?s=&post_type=wp-manga").parseHtml() val doc = webClient.httpGet("https://$domain/?s=&post_type=wp-manga").parseHtml()
return doc.select("form.search-advanced-form div.form-group div.checkbox ").mapNotNullToSet { div -> return doc.select("form.search-advanced-form div.form-group div.checkbox ").mapNotNullToSet { div ->
val key = div.selectFirst("input")?.attr("value") ?: return@mapNotNullToSet null val key = div.selectFirst("input")?.attr("value") ?: return@mapNotNullToSet null

@ -4,17 +4,22 @@ import org.koitharu.kotatsu.parsers.Broken
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.ContentType import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@Broken // Redirect to @hentai20 @Broken // Redirect to @hentai20
@MangaSourceParser("HENTAI3Z", "Hentai3z", "en", ContentType.HENTAI) @MangaSourceParser("HENTAI3Z", "Hentai3z", "en", ContentType.HENTAI)
internal class Hentai3z(context: MangaLoaderContext) : internal class Hentai3z(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.HENTAI3Z, "manga18h.xyz", pageSize = 20) { MadaraParser(context, MangaParserSource.HENTAI3Z, "manga18h.xyz", pageSize = 20) {
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)

@ -6,7 +6,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.* import org.koitharu.kotatsu.parsers.util.*
import java.util.EnumSet import java.util.*
@MangaSourceParser("HENTAI_4FREE", "Hentai4Free", "en", ContentType.HENTAI) @MangaSourceParser("HENTAI_4FREE", "Hentai4Free", "en", ContentType.HENTAI)
internal class Hentai4Free(context: MangaLoaderContext) : internal class Hentai4Free(context: MangaLoaderContext) :
@ -15,7 +15,11 @@ internal class Hentai4Free(context: MangaLoaderContext) :
override val tagPrefix = "hentai-tag/" override val tagPrefix = "hentai-tag/"
override val listUrl = "" override val listUrl = ""
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
override val datePattern = "MMMM dd, yyyy" override val datePattern = "MMMM dd, yyyy"

@ -5,7 +5,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.* import org.koitharu.kotatsu.parsers.util.*
import java.util.EnumSet import java.util.*
@MangaSourceParser("ISEKAISCAN_EU", "ParagonScans", "en") @MangaSourceParser("ISEKAISCAN_EU", "ParagonScans", "en")
internal class IsekaiScanEuParser(context: MangaLoaderContext) : internal class IsekaiScanEuParser(context: MangaLoaderContext) :
@ -13,7 +13,11 @@ internal class IsekaiScanEuParser(context: MangaLoaderContext) :
override val datePattern = "MM/dd/yyyy" override val datePattern = "MM/dd/yyyy"
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
override val listUrl = "mangax/" override val listUrl = "mangax/"

@ -4,17 +4,22 @@ import org.koitharu.kotatsu.parsers.Broken
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.ContentType import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@Broken @Broken
@MangaSourceParser("MANGA1K", "Manga1k", "en", ContentType.HENTAI) @MangaSourceParser("MANGA1K", "Manga1k", "en", ContentType.HENTAI)
internal class Manga1k(context: MangaLoaderContext) : internal class Manga1k(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.MANGA1K, "manga1k.com", 20) { MadaraParser(context, MangaParserSource.MANGA1K, "manga1k.com", 20) {
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
} }

@ -3,17 +3,22 @@ package org.koitharu.kotatsu.parsers.site.madara.en
import org.koitharu.kotatsu.parsers.Broken import org.koitharu.kotatsu.parsers.Broken
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@Broken @Broken
@MangaSourceParser("MANGA68", "Manga68", "en") @MangaSourceParser("MANGA68", "Manga68", "en")
internal class Manga68(context: MangaLoaderContext) : internal class Manga68(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.MANGA68, "manga68.com") { MadaraParser(context, MangaParserSource.MANGA68, "manga68.com") {
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -9,7 +9,7 @@ import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.* import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.EnumSet import java.util.*
@MangaSourceParser("MANGADASS", "MangaDass", "en", ContentType.HENTAI) @MangaSourceParser("MANGADASS", "MangaDass", "en", ContentType.HENTAI)
internal class MangaDass(context: MangaLoaderContext) : internal class MangaDass(context: MangaLoaderContext) :
@ -17,12 +17,16 @@ internal class MangaDass(context: MangaLoaderContext) :
override val datePattern = "dd MMM yyyy" override val datePattern = "dd MMM yyyy"
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
override val selectChapter = "li.a-h" override val selectChapter = "li.a-h"
override val selectDesc = "div.ss-manga" override val selectDesc = "div.ss-manga"
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
init { init {
paginator.firstPage = 1 paginator.firstPage = 1
searchPaginator.firstPage = 1 searchPaginator.firstPage = 1

@ -3,10 +3,11 @@ package org.koitharu.kotatsu.parsers.site.madara.en
import org.koitharu.kotatsu.parsers.Broken import org.koitharu.kotatsu.parsers.Broken
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@Broken @Broken
@MangaSourceParser("MANGAEFFECT", "MangaEffect", "en") @MangaSourceParser("MANGAEFFECT", "MangaEffect", "en")
@ -14,7 +15,10 @@ internal class MangaEffect(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.MANGAEFFECT, "mangaeffect.com") { MadaraParser(context, MangaParserSource.MANGAEFFECT, "mangaeffect.com") {
override val datePattern = "dd.MM.yyyy" override val datePattern = "dd.MM.yyyy"
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
} }

@ -2,16 +2,20 @@ package org.koitharu.kotatsu.parsers.site.madara.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@MangaSourceParser("MANGAFASTNET", "MangaFast.net", "en") @MangaSourceParser("MANGAFASTNET", "MangaFast.net", "en")
internal class MangaFastNet(context: MangaLoaderContext) : internal class MangaFastNet(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.MANGAFASTNET, "manhuafast.net") { MadaraParser(context, MangaParserSource.MANGAFASTNET, "manhuafast.net") {
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
} }

@ -3,17 +3,21 @@ package org.koitharu.kotatsu.parsers.site.madara.en
import org.koitharu.kotatsu.parsers.Broken import org.koitharu.kotatsu.parsers.Broken
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@Broken @Broken
@MangaSourceParser("MANGAUS", "Mangaus", "en") @MangaSourceParser("MANGAUS", "Mangaus", "en")
internal class Mangaus(context: MangaLoaderContext) : internal class Mangaus(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.MANGAUS, "mangaus.xyz") { MadaraParser(context, MangaParserSource.MANGAUS, "mangaus.xyz") {
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
} }

@ -3,20 +3,20 @@ package org.koitharu.kotatsu.parsers.site.madara.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.exception.ParseException import org.koitharu.kotatsu.parsers.exception.ParseException
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.* import org.koitharu.kotatsu.parsers.util.*
import java.util.EnumSet import java.util.*
@MangaSourceParser("MANHUAPLUS", "ManhuaPlus", "en") @MangaSourceParser("MANHUAPLUS", "ManhuaPlus", "en")
internal class Manhuaplus(context: MangaLoaderContext) : internal class Manhuaplus(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.MANHUAPLUS, "manhuaplus.com") { MadaraParser(context, MangaParserSource.MANHUAPLUS, "manhuaplus.com") {
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)

@ -2,16 +2,21 @@ package org.koitharu.kotatsu.parsers.site.madara.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@MangaSourceParser("MANHUAUSS", "Manhuauss", "en") @MangaSourceParser("MANHUAUSS", "Manhuauss", "en")
internal class Manhuauss(context: MangaLoaderContext) : internal class Manhuauss(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.MANHUAUSS, "manhuauss.com") { MadaraParser(context, MangaParserSource.MANHUAUSS, "manhuauss.com") {
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -5,17 +5,11 @@ import kotlinx.coroutines.coroutineScope
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
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.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.* import org.koitharu.kotatsu.parsers.util.*
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.EnumSet import java.util.*
@MangaSourceParser("MANHWAHENTAI", "ManhwaHentai", "en", ContentType.HENTAI) @MangaSourceParser("MANHWAHENTAI", "ManhwaHentai", "en", ContentType.HENTAI)
internal class ManhwaHentai(context: MangaLoaderContext) : internal class ManhwaHentai(context: MangaLoaderContext) :
@ -23,7 +17,11 @@ internal class ManhwaHentai(context: MangaLoaderContext) :
override val tagPrefix = "webtoon-genre/" override val tagPrefix = "webtoon-genre/"
override val listUrl = "webtoon/" override val listUrl = "webtoon/"
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
override val postReq = true override val postReq = true

@ -3,10 +3,11 @@ package org.koitharu.kotatsu.parsers.site.madara.en
import org.koitharu.kotatsu.parsers.Broken import org.koitharu.kotatsu.parsers.Broken
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@Broken @Broken
@MangaSourceParser("MMSCANS", "MmScans", "en") @MangaSourceParser("MMSCANS", "MmScans", "en")
@ -15,7 +16,11 @@ internal class MmScans(context: MangaLoaderContext) :
override val selectChapter = "li.chapter-li" override val selectChapter = "li.chapter-li"
override val selectDesc = "div.summary-text" override val selectDesc = "div.summary-text"
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
} }

@ -3,10 +3,11 @@ package org.koitharu.kotatsu.parsers.site.madara.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.ContentType import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@MangaSourceParser("TOONGOD", "ToonGod", "en", ContentType.HENTAI) @MangaSourceParser("TOONGOD", "ToonGod", "en", ContentType.HENTAI)
internal class ToonGod(context: MangaLoaderContext) : internal class ToonGod(context: MangaLoaderContext) :
@ -15,7 +16,10 @@ internal class ToonGod(context: MangaLoaderContext) :
override val tagPrefix = "webtoon-genre/" override val tagPrefix = "webtoon-genre/"
override val datePattern = "d MMM yyyy" override val datePattern = "d MMM yyyy"
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
} }

@ -2,17 +2,22 @@ package org.koitharu.kotatsu.parsers.site.madara.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@MangaSourceParser("ZINMANGA", "ZinManga.net", "en") @MangaSourceParser("ZINMANGA", "ZinManga.net", "en")
internal class Zinmanga(context: MangaLoaderContext) : internal class Zinmanga(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.ZINMANGA, "zinmanga.net") { MadaraParser(context, MangaParserSource.ZINMANGA, "zinmanga.net") {
override val datePattern = "MM/dd/yyyy" override val datePattern = "MM/dd/yyyy"
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
} }

@ -4,17 +4,22 @@ import org.koitharu.kotatsu.parsers.Broken
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.ContentType import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@Broken @Broken
@MangaSourceParser("INDO18H", "Indo18h", "id", ContentType.HENTAI) @MangaSourceParser("INDO18H", "Indo18h", "id", ContentType.HENTAI)
internal class Indo18h(context: MangaLoaderContext) : internal class Indo18h(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.INDO18H, "indo18h.com", 24) { MadaraParser(context, MangaParserSource.INDO18H, "indo18h.com", 24) {
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
} }

@ -3,10 +3,11 @@ package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.Broken import org.koitharu.kotatsu.parsers.Broken
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@Broken @Broken
@MangaSourceParser("ANCIENTCOMICS", "AncientComics", "pt") @MangaSourceParser("ANCIENTCOMICS", "AncientComics", "pt")
@ -14,7 +15,11 @@ internal class AncientComics(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.ANCIENTCOMICS, "ancientcomics.com.br") { MadaraParser(context, MangaParserSource.ANCIENTCOMICS, "ancientcomics.com.br") {
override val datePattern: String = "dd/MM/yyyy" override val datePattern: String = "dd/MM/yyyy"
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,17 +2,22 @@ package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@MangaSourceParser("ATEMPORAL", "Atemporal", "pt") @MangaSourceParser("ATEMPORAL", "Atemporal", "pt")
internal class Atemporal(context: MangaLoaderContext) : internal class Atemporal(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.ATEMPORAL, "atemporal.cloud") { MadaraParser(context, MangaParserSource.ATEMPORAL, "atemporal.cloud") {
override val datePattern: String = "d 'de' MMMM 'de' yyyy" override val datePattern: String = "d 'de' MMMM 'de' yyyy"
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,17 +2,22 @@ package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@MangaSourceParser("GALINHASAMURAI", "GalinhaSamurai", "pt") @MangaSourceParser("GALINHASAMURAI", "GalinhaSamurai", "pt")
internal class GalinhaSamurai(context: MangaLoaderContext) : internal class GalinhaSamurai(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.GALINHASAMURAI, "galinhasamurai.com") { MadaraParser(context, MangaParserSource.GALINHASAMURAI, "galinhasamurai.com") {
override val datePattern = "dd/MM/yyyy" override val datePattern = "dd/MM/yyyy"
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
} }

@ -2,17 +2,21 @@ package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@MangaSourceParser("IMPERIODABRITANNIA", "ImperioDaBritannia", "pt") @MangaSourceParser("IMPERIODABRITANNIA", "ImperioDaBritannia", "pt")
internal class ImperiodaBritannia(context: MangaLoaderContext) : internal class ImperiodaBritannia(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.IMPERIODABRITANNIA, "imperiodabritannia.com", 10) { MadaraParser(context, MangaParserSource.IMPERIODABRITANNIA, "imperiodabritannia.com", 10) {
override val datePattern: String = "dd 'de' MMMMM 'de' yyyy" override val datePattern: String = "dd 'de' MMMMM 'de' yyyy"
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
} }

@ -16,7 +16,7 @@ internal class MrBenne(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.MRBENNE, "mrbenne.com", 10) { MadaraParser(context, MangaParserSource.MRBENNE, "mrbenne.com", 10) {
override val datePattern: String = "dd/MM/yyyy" override val datePattern: String = "dd/MM/yyyy"
override suspend fun getAvailableTags(): Set<MangaTag> { override suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/?s=&post_type=wp-manga").parseHtml() val doc = webClient.httpGet("https://$domain/?s=&post_type=wp-manga").parseHtml()
val body = doc.body() val body = doc.body()
val root = body.selectFirst("div.form-group.checkbox-group") val root = body.selectFirst("div.form-group.checkbox-group")

@ -2,17 +2,21 @@ package org.koitharu.kotatsu.parsers.site.madara.pt
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@MangaSourceParser("NORTEROSE", "Norterose", "pt") @MangaSourceParser("NORTEROSE", "Norterose", "pt")
internal class Norterose(context: MangaLoaderContext) : internal class Norterose(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.NORTEROSE, "norterose.com.br", 10) { MadaraParser(context, MangaParserSource.NORTEROSE, "norterose.com.br", 10) {
override val datePattern: String = "dd/MM/yyyy" override val datePattern: String = "dd/MM/yyyy"
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
} }

@ -3,16 +3,21 @@ package org.koitharu.kotatsu.parsers.site.madara.th
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.ContentType import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import java.util.EnumSet import java.util.*
@MangaSourceParser("DOUJINZA", "Doujinza", "th", ContentType.HENTAI) @MangaSourceParser("DOUJINZA", "Doujinza", "th", ContentType.HENTAI)
internal class Doujinza(context: MangaLoaderContext) : internal class Doujinza(context: MangaLoaderContext) :
MadaraParser(context, MangaParserSource.DOUJINZA, "doujinza.com", 24) { MadaraParser(context, MangaParserSource.DOUJINZA, "doujinza.com", 24) {
override val withoutAjax = true override val withoutAjax = true
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val availableSortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
override val datePattern = "MMMM dd, yyyy" override val datePattern = "MMMM dd, yyyy"

@ -31,8 +31,6 @@ internal abstract class Manga18Parser(
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
) )
override val isMultipleTagsSupported = false
protected open val listUrl = "list-manga/" protected open val listUrl = "list-manga/"
protected open val tagUrl = "manga-list/" protected open val tagUrl = "manga-list/"
protected open val datePattern = "dd-MM-yyyy" protected open val datePattern = "dd-MM-yyyy"
@ -54,6 +52,20 @@ internal abstract class Manga18Parser(
"Completed", "Completed",
) )
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = false,
isTagsExclusionSupported = false,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = emptySet(),
availableContentRating = emptySet(),
)
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")
@ -114,7 +126,7 @@ internal abstract class Manga18Parser(
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listUrl/").parseHtml() val doc = webClient.httpGet("https://$domain/$listUrl/").parseHtml()
return doc.select("div.grid_cate li").mapNotNullToSet { li -> return doc.select("div.grid_cate li").mapNotNullToSet { li ->
val a = li.selectFirst("a") ?: return@mapNotNullToSet null val a = li.selectFirst("a") ?: return@mapNotNullToSet null

@ -35,5 +35,5 @@ internal class Hanman18(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> = emptySet() // search by tag does not work private suspend fun fetchAvailableTags(): Set<MangaTag> = emptySet() // search by tag does not work
} }

@ -30,10 +30,6 @@ internal abstract class MangaboxParser(
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
) )
override val availableStates: Set<MangaState> = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED)
override val isTagsExclusionSupported = true
protected open val listUrl = "/advanced_search" protected open val listUrl = "/advanced_search"
protected open val searchUrl = "/search/story/" protected open val searchUrl = "/search/story/"
protected open val datePattern = "MMM dd,yy" protected open val datePattern = "MMM dd,yy"
@ -44,7 +40,6 @@ internal abstract class MangaboxParser(
searchPaginator.firstPage = 1 searchPaginator.firstPage = 1
} }
@JvmField @JvmField
protected val ongoing: Set<String> = setOf( protected val ongoing: Set<String> = setOf(
"ongoing", "ongoing",
@ -55,6 +50,20 @@ internal abstract class MangaboxParser(
"completed", "completed",
) )
override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities(
isMultipleTagsSupported = true,
isTagsExclusionSupported = true,
isSearchSupported = true,
isSearchWithFiltersSupported = false,
)
override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(),
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED),
availableContentRating = emptySet(),
)
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")
@ -139,7 +148,7 @@ internal abstract class MangaboxParser(
protected open val selectTagMap = "div.panel-genres-list a:not(.genres-select)" protected open val selectTagMap = "div.panel-genres-list a:not(.genres-select)"
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml() val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml()
val tags = doc.select(selectTagMap).drop(1) // remove all tags val tags = doc.select(selectTagMap).drop(1) // remove all tags
return tags.mapNotNullToSet { a -> return tags.mapNotNullToSet { a ->

@ -31,8 +31,11 @@ internal class Mangairo(context: MangaLoaderContext) :
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.NEWEST, SortOrder.NEWEST,
) )
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
override val isMultipleTagsSupported = false get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
isMultipleTagsSupported = false,
)
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val url = buildString { val url = buildString {
@ -105,7 +108,7 @@ internal class Mangairo(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listUrl/type-latest/ctg-all/state-all/page-1").parseHtml() val doc = webClient.httpGet("https://$domain/$listUrl/type-latest/ctg-all/state-all/page-1").parseHtml()
return doc.select("div.panel_category a:not(.ctg_select)").mapNotNullToSet { a -> return doc.select("div.panel_category a:not(.ctg_select)").mapNotNullToSet { a ->
val key = a.attr("href").substringAfterLast("ctg-").substringBefore("/") val key = a.attr("href").substringAfterLast("ctg-").substringBefore("/")

@ -19,8 +19,11 @@ internal class Mangakakalot(context: MangaLoaderContext) :
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.NEWEST, SortOrder.NEWEST,
) )
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
override val isMultipleTagsSupported = false get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
isMultipleTagsSupported = false,
)
override val otherDomain = "chapmanganato.com" override val otherDomain = "chapmanganato.com"
override val listUrl = "/manga_list" override val listUrl = "/manga_list"
@ -94,7 +97,7 @@ internal class Mangakakalot(context: MangaLoaderContext) :
} }
} }
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml() val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml()
val tags = doc.select("ul.tag li a").drop(1) val tags = doc.select("ul.tag li a").drop(1)
return tags.mapNotNullToSet { a -> return tags.mapNotNullToSet { a ->

@ -22,8 +22,11 @@ internal class MangakakalotTv(context: MangaLoaderContext) :
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.NEWEST, SortOrder.NEWEST,
) )
override val isMultipleTagsSupported = false override val filterCapabilities: MangaListFilterCapabilities
override val isTagsExclusionSupported = false get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
isMultipleTagsSupported = false,
)
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val url = buildString { val url = buildString {
@ -125,7 +128,7 @@ internal class MangakakalotTv(context: MangaLoaderContext) :
override val selectTagMap = "ul.tag li a" override val selectTagMap = "ul.tag li a"
override suspend fun getAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml() val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml()
return doc.select(selectTagMap).mapNotNullToSet { a -> return doc.select(selectTagMap).mapNotNullToSet { a ->
MangaTag( MangaTag(

@ -3,8 +3,8 @@ package org.koitharu.kotatsu.parsers.site.mangadventure.en
import androidx.collection.ArraySet import androidx.collection.ArraySet
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterOptions
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.site.mangadventure.MangAdventureParser import org.koitharu.kotatsu.parsers.site.mangadventure.MangAdventureParser
@MangaSourceParser("ASSORTEDSCANS", "AssortedScans", "en") @MangaSourceParser("ASSORTEDSCANS", "AssortedScans", "en")
@ -16,8 +16,10 @@ internal class AssortedScans(context: MangaLoaderContext) :
"Shoujo Ai", "Shounen Ai", "Smut", "Yaoi", "Shoujo Ai", "Shounen Ai", "Smut", "Yaoi",
) )
override suspend fun getAvailableTags(): Set<MangaTag> { override suspend fun getFilterOptions(): MangaListFilterOptions {
val tags = super.getAvailableTags() val options = super.getFilterOptions()
return tags.filterNotTo(ArraySet(tags.size)) { it.key in emptyTags } return options.copy(
availableTags = options.availableTags.filterNotTo(ArraySet(options.availableTags.size)) { it.key in emptyTags },
)
} }
} }

@ -2,11 +2,16 @@ package org.koitharu.kotatsu.parsers.site.mangareader.ar
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("ARAREASCANS", "ArAreaScans", "ar") @MangaSourceParser("ARAREASCANS", "ArAreaScans", "ar")
internal class ArAreaScans(context: MangaLoaderContext) : internal class ArAreaScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.ARAREASCANS, "ar.areascans.org", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.ARAREASCANS, "ar.areascans.org", pageSize = 20, searchPageSize = 10) {
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,11 +2,16 @@ package org.koitharu.kotatsu.parsers.site.mangareader.ar
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("AREASCANS", "AreaScans", "ar") @MangaSourceParser("AREASCANS", "AreaScans", "ar")
internal class AreaScans(context: MangaLoaderContext) : internal class AreaScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.AREASCANS, "www.areascans.net", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.AREASCANS, "www.areascans.net", pageSize = 20, searchPageSize = 10) {
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,6 +2,7 @@ package org.koitharu.kotatsu.parsers.site.mangareader.ar
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@ -10,5 +11,8 @@ internal class FlAres(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.FLARES, "fl-ares.com", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.FLARES, "fl-ares.com", pageSize = 20, searchPageSize = 10) {
override val listUrl = "/series" override val listUrl = "/series"
override val encodedSrc = true override val encodedSrc = true
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,11 +2,15 @@ package org.koitharu.kotatsu.parsers.site.mangareader.ar
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("MANGAPRO", "MangaPro", "ar") @MangaSourceParser("MANGAPRO", "MangaPro", "ar")
internal class MangaPro(context: MangaLoaderContext) : internal class MangaPro(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.MANGAPRO, "promanga.pro", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.MANGAPRO, "promanga.pro", pageSize = 20, searchPageSize = 10) {
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -16,7 +16,10 @@ internal class Normoyun(context: MangaLoaderContext) :
override val selectMangaList = ".listupd .bs .bsx" override val selectMangaList = ".listupd .bs .bsx"
override val selectMangaListImg = "img" override val selectMangaListImg = "img"
override val isNetShieldProtected = true override val isNetShieldProtected = true
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilterV2): List<Manga> {
val url = buildString { val url = buildString {

@ -5,6 +5,7 @@ import org.koitharu.kotatsu.parsers.Broken
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@ -15,7 +16,10 @@ import org.koitharu.kotatsu.parsers.util.*
internal class PotatoManga(context: MangaLoaderContext) : internal class PotatoManga(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.POTATOMANGA, "potatomanga.xyz", pageSize = 30, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.POTATOMANGA, "potatomanga.xyz", pageSize = 30, searchPageSize = 10) {
override val listUrl = "/series" override val listUrl = "/series"
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> { override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val chapterUrl = chapter.url.toAbsoluteUrl(domain) val chapterUrl = chapter.url.toAbsoluteUrl(domain)

@ -2,6 +2,7 @@ package org.koitharu.kotatsu.parsers.site.mangareader.ar
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@ -9,5 +10,8 @@ import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
internal class ScarManga(context: MangaLoaderContext) : internal class ScarManga(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.SCARMANGA, "scarmanga.com", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.SCARMANGA, "scarmanga.com", pageSize = 20, searchPageSize = 10) {
override val listUrl = "/series" override val listUrl = "/series"
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,6 +2,7 @@ package org.koitharu.kotatsu.parsers.site.mangareader.ar
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@ -14,6 +15,9 @@ internal class ThunderScans(context: MangaLoaderContext) :
pageSize = 32, pageSize = 32,
searchPageSize = 10, searchPageSize = 10,
) { ) {
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val selectChapter = ".eplister > ul > li" override val selectChapter = ".eplister > ul > li"
} }

@ -2,11 +2,15 @@ package org.koitharu.kotatsu.parsers.site.mangareader.ar
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("UMIMANGA", "UmiManga", "ar") @MangaSourceParser("UMIMANGA", "UmiManga", "ar")
internal class UmiManga(context: MangaLoaderContext) : internal class UmiManga(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.UMIMANGA, "www.umimanga.com", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.UMIMANGA, "www.umimanga.com", pageSize = 20, searchPageSize = 10) {
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -3,10 +3,7 @@ package org.koitharu.kotatsu.parsers.site.mangareader.ar
import org.koitharu.kotatsu.parsers.Broken import org.koitharu.kotatsu.parsers.Broken
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.WordSet
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import org.koitharu.kotatsu.parsers.util.* import org.koitharu.kotatsu.parsers.util.*
import java.text.DateFormat import java.text.DateFormat
@ -19,7 +16,10 @@ internal class VexManga(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.VEXMANGA, "vexmanga.com", pageSize = 10, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.VEXMANGA, "vexmanga.com", pageSize = 10, searchPageSize = 10) {
override val selectMangaList = ".listarchives .latest-recom" override val selectMangaList = ".listarchives .latest-recom"
override val selectChapter = ".ulChapterList > a" override val selectChapter = ".ulChapterList > a"
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override suspend fun getDetails(manga: Manga): Manga { override suspend fun getDetails(manga: Manga): Manga {
val docs = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val docs = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()

@ -2,6 +2,7 @@ package org.koitharu.kotatsu.parsers.site.mangareader.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@ -9,5 +10,9 @@ import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
internal class AgsComics(context: MangaLoaderContext) : internal class AgsComics(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.AGSCOMICS, "agscomics.com", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.AGSCOMICS, "agscomics.com", pageSize = 20, searchPageSize = 10) {
override val listUrl = "/series" override val listUrl = "/series"
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,11 +2,16 @@ package org.koitharu.kotatsu.parsers.site.mangareader.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("ALTAYSCANS", "AltayScans", "en") @MangaSourceParser("ALTAYSCANS", "AltayScans", "en")
internal class AltayScans(context: MangaLoaderContext) : internal class AltayScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.ALTAYSCANS, "altayscans.com", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.ALTAYSCANS, "altayscans.com", pageSize = 20, searchPageSize = 10) {
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,6 +2,7 @@ package org.koitharu.kotatsu.parsers.site.mangareader.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@ -9,5 +10,9 @@ import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
internal class AnigliScans(context: MangaLoaderContext) : internal class AnigliScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.ANIGLISCANS, "anigliscans.xyz", pageSize = 47, searchPageSize = 47) { MangaReaderParser(context, MangaParserSource.ANIGLISCANS, "anigliscans.xyz", pageSize = 47, searchPageSize = 47) {
override val listUrl = "/series" override val listUrl = "/series"
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,11 +2,16 @@ package org.koitharu.kotatsu.parsers.site.mangareader.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("ASCALONSCANS", "AscalonScans", "en") @MangaSourceParser("ASCALONSCANS", "AscalonScans", "en")
internal class AscalonScans(context: MangaLoaderContext) : internal class AscalonScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.ASCALONSCANS, "ascalonscans.com", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.ASCALONSCANS, "ascalonscans.com", pageSize = 20, searchPageSize = 10) {
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,12 +2,18 @@ package org.koitharu.kotatsu.parsers.site.mangareader.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("ASTRASCANS", "AstraScans", "en") @MangaSourceParser("ASTRASCANS", "AstraScans", "en")
internal class AstraScans(context: MangaLoaderContext) : internal class AstraScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.ASTRASCANS, "astrascans.org", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.ASTRASCANS, "astrascans.org", pageSize = 20, searchPageSize = 10) {
override val isTagsExclusionSupported = false
override val listUrl = "/series" override val listUrl = "/series"
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,6 +2,7 @@ package org.koitharu.kotatsu.parsers.site.mangareader.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@ -9,5 +10,9 @@ import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
internal class BirdManga(context: MangaLoaderContext) : internal class BirdManga(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.BIRDMANGA, "birdmanga.com", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.BIRDMANGA, "birdmanga.com", pageSize = 20, searchPageSize = 10) {
override val encodedSrc = true override val encodedSrc = true
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,10 +2,7 @@ package org.koitharu.kotatsu.parsers.site.mangareader.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
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.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
import org.koitharu.kotatsu.parsers.util.* import org.koitharu.kotatsu.parsers.util.*
@ -19,7 +16,11 @@ internal class Constellarcomic(context: MangaLoaderContext) :
searchPageSize = 18, searchPageSize = 18,
) { ) {
override val selectTestScript = "script:containsData(ts_rea_der_._run)" override val selectTestScript = "script:containsData(ts_rea_der_._run)"
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override suspend fun getDetails(manga: Manga): Manga { override suspend fun getDetails(manga: Manga): Manga {
val docs = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val docs = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()

@ -3,6 +3,7 @@ package org.koitharu.kotatsu.parsers.site.mangareader.en
import org.koitharu.kotatsu.parsers.Broken import org.koitharu.kotatsu.parsers.Broken
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@ -11,5 +12,8 @@ import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
internal class CosmicScansParser(context: MangaLoaderContext) : internal class CosmicScansParser(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.COSMICSCANS, "cosmic-scans.com", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.COSMICSCANS, "cosmic-scans.com", pageSize = 20, searchPageSize = 10) {
override val datePattern = "MMM d, yyyy" override val datePattern = "MMM d, yyyy"
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,6 +2,7 @@ package org.koitharu.kotatsu.parsers.site.mangareader.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@ -15,5 +16,9 @@ internal class EnThunderScans(context: MangaLoaderContext) :
searchPageSize = 10, searchPageSize = 10,
) { ) {
override val listUrl = "/comics" override val listUrl = "/comics"
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,11 +2,16 @@ package org.koitharu.kotatsu.parsers.site.mangareader.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("ENRYUMANGA", "EnryuManga", "en") @MangaSourceParser("ENRYUMANGA", "EnryuManga", "en")
internal class EnryuManga(context: MangaLoaderContext) : internal class EnryuManga(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.ENRYUMANGA, "enryumanga.net", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.ENRYUMANGA, "enryumanga.net", pageSize = 20, searchPageSize = 10) {
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -6,6 +6,7 @@ import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.koitharu.kotatsu.parsers.Broken import org.koitharu.kotatsu.parsers.Broken
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@ -18,7 +19,11 @@ import org.koitharu.kotatsu.parsers.util.toTitleCase
@MangaSourceParser("FREAKCOMIC", "FreakComic", "en") @MangaSourceParser("FREAKCOMIC", "FreakComic", "en")
internal class FreakComic(context: MangaLoaderContext) : internal class FreakComic(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.FREAKCOMIC, "freakcomic.com", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.FREAKCOMIC, "freakcomic.com", pageSize = 20, searchPageSize = 10) {
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
override val selectMangaList = ".listupd .lastest-serie" override val selectMangaList = ".listupd .lastest-serie"
override val selectMangaListImg = "img" override val selectMangaListImg = "img"
override val selectChapter = ".chapter-li a:not(:has(svg))" override val selectChapter = ".chapter-li a:not(:has(svg))"

@ -3,6 +3,7 @@ package org.koitharu.kotatsu.parsers.site.mangareader.en
import org.koitharu.kotatsu.parsers.Broken import org.koitharu.kotatsu.parsers.Broken
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@ -11,5 +12,9 @@ import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
internal class FreakScans(context: MangaLoaderContext) : internal class FreakScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.FREAKSCANS, "freakscans.com", pageSize = 20, searchPageSize = 20) { MangaReaderParser(context, MangaParserSource.FREAKSCANS, "freakscans.com", pageSize = 20, searchPageSize = 20) {
override val datePattern = "MMM d, yyyy" override val datePattern = "MMM d, yyyy"
override val isTagsExclusionSupported = false
override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,6 +2,7 @@ package org.koitharu.kotatsu.parsers.site.mangareader.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@ -9,5 +10,8 @@ import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("KAISCANS", "KaiScans", "en") @MangaSourceParser("KAISCANS", "KaiScans", "en")
internal class KaiScans(context: MangaLoaderContext) : internal class KaiScans(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.KAISCANS, "ponvi.online", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.KAISCANS, "ponvi.online", pageSize = 20, searchPageSize = 10) {
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,6 +2,7 @@ package org.koitharu.kotatsu.parsers.site.mangareader.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@ -9,5 +10,8 @@ import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
internal class KomikLabParser(context: MangaLoaderContext) : internal class KomikLabParser(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.KOMIKLAB, "komiklab.com", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.KOMIKLAB, "komiklab.com", pageSize = 20, searchPageSize = 10) {
override val datePattern = "MMM d, yyyy" override val datePattern = "MMM d, yyyy"
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,11 +2,15 @@ package org.koitharu.kotatsu.parsers.site.mangareader.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@MangaSourceParser("LUACOMIC_COM", "luaComic.com", "en") @MangaSourceParser("LUACOMIC_COM", "luaComic.com", "en")
internal class LuaComicCom(context: MangaLoaderContext) : internal class LuaComicCom(context: MangaLoaderContext) :
MangaReaderParser(context, MangaParserSource.LUACOMIC_COM, "ponvi.online", pageSize = 20, searchPageSize = 10) { MangaReaderParser(context, MangaParserSource.LUACOMIC_COM, "ponvi.online", pageSize = 20, searchPageSize = 10) {
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

@ -2,6 +2,7 @@ package org.koitharu.kotatsu.parsers.site.mangareader.en
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.MangaListFilterCapabilities
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser import org.koitharu.kotatsu.parsers.site.mangareader.MangaReaderParser
@ -16,5 +17,8 @@ internal class LuminousScans(context: MangaLoaderContext) :
) { ) {
override val listUrl = "/series" override val listUrl = "/series"
override val isTagsExclusionSupported = false override val filterCapabilities: MangaListFilterCapabilities
get() = super.filterCapabilities.copy(
isTagsExclusionSupported = false,
)
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save