Merge branch 'feature/filter-ex'

pull/397/head
Koitharu 2 years ago
commit 9d2f633e14
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -23,7 +23,27 @@ 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 sortOrders: Set<SortOrder> abstract val availableSortOrders: Set<SortOrder>
/**
* Supported [MangaState] variants for filtering. May be empty.
*
* For better performance use [EnumSet] for more than one item.
*/
open val availableStates: Set<MangaState>
get() = emptySet()
/**
* Whether parser supports filtering by more than one tag
*/
open val isMultipleTagsSupported: Boolean = true
@Deprecated(
message = "Use availableSortOrders instead",
replaceWith = ReplaceWith("availableSortOrders"),
)
val sortOrders: Set<SortOrder>
get() = availableSortOrders
val config by lazy { context.getConfig(source) } val config by lazy { context.getConfig(source) }
@ -49,7 +69,7 @@ abstract class MangaParser @InternalParsersApi constructor(
*/ */
protected open val defaultSortOrder: SortOrder protected open val defaultSortOrder: SortOrder
get() { get() {
val supported = sortOrders val supported = availableSortOrders
return SortOrder.entries.first { it in supported } return SortOrder.entries.first { it in supported }
} }
@ -62,11 +82,15 @@ abstract class MangaParser @InternalParsersApi constructor(
* @param offset starting from 0 and used for pagination. * @param offset starting from 0 and used for pagination.
* Note than passed value may not be divisible by internal page size, so you should adjust it manually. * Note than passed value may not be divisible by internal page size, so you should adjust it manually.
* @param query search query, may be null or empty if no search needed * @param query search query, may be null or empty if no search needed
* @param tags genres for filtering, values from [getTags] and [Manga.tags]. May be null or empty * @param tags genres for filtering, values from [getAvailableTags] and [Manga.tags]. May be null or empty
* @param sortOrder one of [sortOrders] or null for default value * @param sortOrder one of [availableSortOrders] or null for default value
*/ */
@JvmSynthetic @JvmSynthetic
@InternalParsersApi @InternalParsersApi
@Deprecated(
"Use getList with filter instead",
replaceWith = ReplaceWith("getList(offset, filter)"),
)
abstract suspend fun getList( abstract suspend fun getList(
offset: Int, offset: Int,
query: String?, query: String?,
@ -80,8 +104,15 @@ abstract class MangaParser @InternalParsersApi constructor(
* @param offset starting from 0 and used for pagination. * @param offset starting from 0 and used for pagination.
* @param query search query * @param query search query
*/ */
@Deprecated(
"Use getList with filter instead",
ReplaceWith(
"getList(offset, MangaListFilter.Search(query))",
"org.koitharu.kotatsu.parsers.model.MangaListFilter",
),
)
open suspend fun getList(offset: Int, query: String): List<Manga> { open suspend fun getList(offset: Int, query: String): List<Manga> {
return getList(offset, query, null, defaultSortOrder) return getList(offset, MangaListFilter.Search(query))
} }
/** /**
@ -89,11 +120,29 @@ abstract class MangaParser @InternalParsersApi constructor(
* *
* @param offset starting from 0 and used for pagination. * @param offset starting from 0 and used for pagination.
* Note than passed value may not be divisible by internal page size, so you should adjust it manually. * Note than passed value may not be divisible by internal page size, so you should adjust it manually.
* @param tags genres for filtering, values from [getTags] and [Manga.tags]. May be null or empty * @param tags genres for filtering, values from [getAvailableTags] and [Manga.tags]. May be null or empty
* @param sortOrder one of [sortOrders] or null for default value * @param sortOrder one of [availableSortOrders] or null for default value
*/ */
@Deprecated(
"Use getList with filter instead",
ReplaceWith(
"getList(offset, MangaListFilter.Advanced(sortOrder, tags, null, emptySet()))",
"org.koitharu.kotatsu.parsers.model.MangaListFilter",
),
)
open suspend fun getList(offset: Int, tags: Set<MangaTag>?, sortOrder: SortOrder?): List<Manga> { open suspend fun getList(offset: Int, tags: Set<MangaTag>?, sortOrder: SortOrder?): List<Manga> {
return getList(offset, null, tags, sortOrder ?: defaultSortOrder) return getList(
offset,
MangaListFilter.Advanced(sortOrder ?: defaultSortOrder, tags.orEmpty(), null, emptySet()),
)
}
open suspend fun getList(offset: Int, filter: MangaListFilter?): List<Manga> {
return when (filter) {
is MangaListFilter.Advanced -> getList(offset, null, filter.tags, filter.sortOrder)
is MangaListFilter.Search -> getList(offset, filter.query, null, defaultSortOrder)
null -> getList(offset, null, null, defaultSortOrder)
}
} }
/** /**
@ -117,7 +166,18 @@ abstract class MangaParser @InternalParsersApi constructor(
/** /**
* Fetch available tags (genres) for source * Fetch available tags (genres) for source
*/ */
abstract suspend fun getTags(): Set<MangaTag> abstract suspend fun getAvailableTags(): Set<MangaTag>
/**
* Fetch available locales for multilingual sources
*/
open suspend fun getAvailableLocales(): Set<Locale> = emptySet()
@Deprecated(
message = "Use getAvailableTags instead",
replaceWith = ReplaceWith("getAvailableTags()"),
)
suspend fun getTags(): Set<MangaTag> = getAvailableTags()
/** /**
* Parse favicons from the main page of the source`s website * Parse favicons from the main page of the source`s website

@ -0,0 +1,29 @@
package org.koitharu.kotatsu.parsers.model
import java.util.*
sealed interface MangaListFilter {
fun isEmpty(): Boolean
val sortOrder: SortOrder?
data class Search(
@JvmField val query: String,
) : MangaListFilter {
override val sortOrder: SortOrder? = null
override fun isEmpty() = query.isBlank()
}
data class Advanced(
override val sortOrder: SortOrder,
@JvmField val tags: Set<MangaTag>,
@JvmField val locale: Locale?,
@JvmField val states: Set<MangaState>,
) : MangaListFilter {
override fun isEmpty(): Boolean = tags.isEmpty() && locale == null && states.isEmpty()
}
}

@ -1,5 +1,5 @@
package org.koitharu.kotatsu.parsers.model package org.koitharu.kotatsu.parsers.model
enum class MangaState { enum class MangaState {
ONGOING, FINISHED, ABANDONED ONGOING, FINISHED, ABANDONED, PAUSED
} }

@ -26,7 +26,7 @@ internal class BatoToParser(context: MangaLoaderContext) : PagedMangaParser(
searchPageSize = 20, searchPageSize = 20,
) { ) {
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.NEWEST, SortOrder.NEWEST,
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.POPULARITY, SortOrder.POPULARITY,
@ -159,7 +159,7 @@ internal class BatoToParser(context: MangaLoaderContext) : PagedMangaParser(
throw ParseException("Cannot find images list", fullUrl) throw ParseException("Cannot find images list", fullUrl)
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val scripts = webClient.httpGet( val scripts = webClient.httpGet(
"https://${domain}/browse", "https://${domain}/browse",
).parseHtml().selectOrThrow("script") ).parseHtml().selectOrThrow("script")

@ -25,7 +25,7 @@ internal class ComickFunParser(context: MangaLoaderContext) : MangaParser(contex
override val configKeyDomain = ConfigKey.Domain("comick.app") override val configKeyDomain = ConfigKey.Domain("comick.app")
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.RATING, SortOrder.RATING,
@ -137,7 +137,7 @@ internal class ComickFunParser(context: MangaLoaderContext) : MangaParser(contex
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val sparseArray = cachedTags ?: loadTags() val sparseArray = cachedTags ?: loadTags()
val set = ArraySet<MangaTag>(sparseArray.size()) val set = ArraySet<MangaTag>(sparseArray.size())
for (i in 0 until sparseArray.size()) { for (i in 0 until sparseArray.size()) {

@ -23,7 +23,7 @@ internal class ExHentaiParser(
context: MangaLoaderContext, context: MangaLoaderContext,
) : PagedMangaParser(context, MangaSource.EXHENTAI, pageSize = 25), MangaParserAuthProvider { ) : PagedMangaParser(context, MangaSource.EXHENTAI, pageSize = 25), MangaParserAuthProvider {
override val sortOrders: Set<SortOrder> = Collections.singleton( override val availableSortOrders: Set<SortOrder> = Collections.singleton(
SortOrder.NEWEST, SortOrder.NEWEST,
) )
@ -213,7 +213,7 @@ internal class ExHentaiParser(
return doc.body().requireElementById("img").attrAsAbsoluteUrl("src") return doc.body().requireElementById("img").attrAsAbsoluteUrl("src")
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://${domain}").parseHtml() val doc = webClient.httpGet("https://${domain}").parseHtml()
val root = doc.body().requireElementById("searchbox").selectFirstOrThrow("table") val root = doc.body().requireElementById("searchbox").selectFirstOrThrow("table")
return root.select("div.cs").mapNotNullToSet { div -> return root.select("div.cs").mapNotNullToSet { div ->

@ -17,11 +17,13 @@ import java.util.*
internal class ImHentai(context: MangaLoaderContext) : internal class ImHentai(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.IMHENTAI, pageSize = 20) { PagedMangaParser(context, MangaSource.IMHENTAI, pageSize = 20) {
override val sortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.RATING) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.RATING)
override val configKeyDomain = ConfigKey.Domain("imhentai.xxx") override val configKeyDomain = ConfigKey.Domain("imhentai.xxx")
override val isMultipleTagsSupported = false
override suspend fun getListPage( override suspend fun getListPage(
page: Int, page: Int,
query: String?, query: String?,
@ -83,7 +85,7 @@ internal class ImHentai(context: MangaLoaderContext) :
//Tags are deliberately reduced because there are too many and this slows down the application. //Tags are deliberately reduced because there are too many and this slows down the application.
//only the most popular ones are taken. //only the most popular ones are taken.
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
return coroutineScope { return coroutineScope {
(1..3).map { page -> (1..3).map { page ->
async { getTags(page) } async { getTags(page) }

@ -24,6 +24,8 @@ internal abstract class LineWebtoonsParser(
source: MangaSource, source: MangaSource,
) : MangaParser(context, source) { ) : MangaParser(context, source) {
override val isMultipleTagsSupported = false
private val signer by lazy { private val signer by lazy {
WebtoonsUrlSigner("gUtPzJFZch4ZyAGviiyH94P99lQ3pFdRTwpJWDlSGFfwgpr6ses5ALOxWHOIT7R1") WebtoonsUrlSigner("gUtPzJFZch4ZyAGviiyH94P99lQ3pFdRTwpJWDlSGFfwgpr6ses5ALOxWHOIT7R1")
} }
@ -39,7 +41,7 @@ internal abstract class LineWebtoonsParser(
private val apiDomain = "global.apis.naver.com" private val apiDomain = "global.apis.naver.com"
private val staticDomain = "webtoon-phinf.pstatic.net" private val staticDomain = "webtoon-phinf.pstatic.net"
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY, SortOrder.POPULARITY,
// doesn't actually sort by rating, but by likes // doesn't actually sort by rating, but by likes
// this should be fine though // this should be fine though
@ -235,7 +237,7 @@ internal abstract class LineWebtoonsParser(
) )
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
return makeRequest("/lineWebtoon/webtoon/challengeGenreList.json") return makeRequest("/lineWebtoon/webtoon/challengeGenreList.json")
.getJSONObject("genreList") .getJSONObject("genreList")
.getJSONArray("challengeGenres") .getJSONArray("challengeGenres")

@ -30,7 +30,7 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context
override val configKeyDomain = ConfigKey.Domain("mangadex.org") override val configKeyDomain = ConfigKey.Domain("mangadex.org")
override val sortOrders: EnumSet<SortOrder> = EnumSet.of( override val availableSortOrders: EnumSet<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
SortOrder.NEWEST, SortOrder.NEWEST,
@ -159,7 +159,7 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val tags = webClient.httpGet("https://api.${domain}/manga/tag").parseJson() val tags = webClient.httpGet("https://api.${domain}/manga/tag").parseJson()
.getJSONArray("data") .getJSONArray("data")
return tags.mapJSONToSet { jo -> return tags.mapJSONToSet { jo ->

@ -31,7 +31,7 @@ internal abstract class NineMangaParser(
.add("Accept-Language", "en-US;q=0.7,en;q=0.3") .add("Accept-Language", "en-US;q=0.7,en;q=0.3")
.build() .build()
override val sortOrders: Set<SortOrder> = Collections.singleton( override val availableSortOrders: Set<SortOrder> = Collections.singleton(
SortOrder.POPULARITY, SortOrder.POPULARITY,
) )
@ -158,7 +158,7 @@ internal abstract class NineMangaParser(
private var tagCache: ArrayMap<String, MangaTag>? = null private var tagCache: ArrayMap<String, MangaTag>? = null
private val mutex = Mutex() private val mutex = Mutex()
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
return getOrCreateTagMap().values.toSet() return getOrCreateTagMap().values.toSet()
} }

@ -22,7 +22,9 @@ internal abstract class AnimeBootstrapParser(
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of( override val isMultipleTagsSupported = false
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
@ -93,7 +95,7 @@ internal abstract class AnimeBootstrapParser(
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain$listUrl").parseHtml() val doc = webClient.httpGet("https://$domain$listUrl").parseHtml()
return doc.select("div.product__page__filter div:contains(Genre:) option ").mapNotNullToSet { option -> return doc.select("div.product__page__filter div:contains(Genre:) option ").mapNotNullToSet { option ->
val key = option.attr("value") ?: return@mapNotNullToSet null val key = option.attr("value") ?: return@mapNotNullToSet null

@ -20,6 +20,8 @@ internal class PapScan(context: MangaLoaderContext) :
override val sourceLocale: Locale = Locale.ENGLISH override val sourceLocale: Locale = Locale.ENGLISH
override val isMultipleTagsSupported = false
override val listUrl = "/liste-manga" override val listUrl = "/liste-manga"
override val selectState = "div.anime__details__widget li:contains(En cours)" override val selectState = "div.anime__details__widget li:contains(En cours)"
@ -27,7 +29,7 @@ internal class PapScan(context: MangaLoaderContext) :
override val selectChapter = "ul.chapters li" override val selectChapter = "ul.chapters li"
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
) )
@ -85,7 +87,7 @@ internal class PapScan(context: MangaLoaderContext) :
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain$listUrl").parseHtml() val doc = webClient.httpGet("https://$domain$listUrl").parseHtml()
return doc.select("a.category ").mapNotNullToSet { a -> return doc.select("a.category ").mapNotNullToSet { a ->
val key = a.attr("href").substringAfterLast('=') val key = a.attr("href").substringAfterLast('=')

@ -18,7 +18,7 @@ import java.util.*
@MangaSourceParser("FLIXSCANS", "FlixScans", "ar") @MangaSourceParser("FLIXSCANS", "FlixScans", "ar")
internal class FlixScans(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.FLIXSCANS, 18) { internal class FlixScans(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.FLIXSCANS, 18) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain("flixscans.com") override val configKeyDomain = ConfigKey.Domain("flixscans.com")
override suspend fun getListPage( override suspend fun getListPage(
@ -70,7 +70,7 @@ internal class FlixScans(context: MangaLoaderContext) : PagedMangaParser(context
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/search/advance").parseHtml() val doc = webClient.httpGet("https://$domain/search/advance").parseHtml()
val json = JSONArray(doc.requireElementById("__NUXT_DATA__").data()) val json = JSONArray(doc.requireElementById("__NUXT_DATA__").data())
val tagsList = json.getJSONArray(3).toString().replace("[", "").replace("]", "").split(",") val tagsList = json.getJSONArray(3).toString().replace("[", "").replace("]", "").split(",")

@ -13,8 +13,9 @@ import java.util.*
@MangaSourceParser("MANGASTORM", "MangaStorm", "ar") @MangaSourceParser("MANGASTORM", "MangaStorm", "ar")
internal class MangaStorm(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.MANGASTORM, 30) { internal class MangaStorm(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.MANGASTORM, 30) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.POPULARITY) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.POPULARITY)
override val configKeyDomain = ConfigKey.Domain("mangastorm.org") override val configKeyDomain = ConfigKey.Domain("mangastorm.org")
override val isMultipleTagsSupported = false
override val headers: Headers = Headers.Builder() override val headers: Headers = Headers.Builder()
.add("User-Agent", UserAgents.CHROME_DESKTOP) .add("User-Agent", UserAgents.CHROME_DESKTOP)
@ -69,7 +70,7 @@ internal class MangaStorm(context: MangaLoaderContext) : PagedMangaParser(contex
} }
} }
override suspend fun getTags(): Set<MangaTag> = emptySet() 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()

@ -16,8 +16,9 @@ import java.util.*
@MangaSourceParser("TEAMXNOVEL", "TeamXNovel", "ar") @MangaSourceParser("TEAMXNOVEL", "TeamXNovel", "ar")
internal class TeamXNovel(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.TEAMXNOVEL, 10) { internal class TeamXNovel(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.TEAMXNOVEL, 10) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)
override val configKeyDomain = ConfigKey.Domain("team11x11.com") override val configKeyDomain = ConfigKey.Domain("team11x11.com")
override val isMultipleTagsSupported = false
override suspend fun getListPage( override suspend fun getListPage(
page: Int, page: Int,
@ -82,7 +83,7 @@ internal class TeamXNovel(context: MangaLoaderContext) : PagedMangaParser(contex
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/series").parseHtml() val doc = webClient.httpGet("https://$domain/series").parseHtml()
return doc.requireElementById("select_genre").select("option").mapNotNullToSet { return doc.requireElementById("select_genre").select("option").mapNotNullToSet {
MangaTag( MangaTag(

@ -23,7 +23,7 @@ internal class AnibelParser(context: MangaLoaderContext) : MangaParser(context,
override val configKeyDomain = ConfigKey.Domain("anibel.net") override val configKeyDomain = ConfigKey.Domain("anibel.net")
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.NEWEST, SortOrder.NEWEST,
) )
@ -176,7 +176,7 @@ internal class AnibelParser(context: MangaLoaderContext) : MangaParser(context,
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val json = apiCall( val json = apiCall(
""" """
getFilters(mediaType: manga) { getFilters(mediaType: manga) {

@ -13,10 +13,12 @@ import java.util.*
internal class BeeToon(context: MangaLoaderContext) : internal class BeeToon(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.BEETOON, pageSize = 30) { PagedMangaParser(context, MangaSource.BEETOON, pageSize = 30) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY)
override val configKeyDomain = ConfigKey.Domain("ww7.beetoon.net") override val configKeyDomain = ConfigKey.Domain("ww7.beetoon.net")
override val isMultipleTagsSupported = false
override suspend fun getListPage( override suspend fun getListPage(
page: Int, page: Int,
query: String?, query: String?,
@ -80,7 +82,7 @@ internal class BeeToon(context: MangaLoaderContext) :
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/").parseHtml() val doc = webClient.httpGet("https://$domain/").parseHtml()
return doc.requireElementById("menu-item-3").select("ul.sub-menu li a").mapNotNullToSet { return doc.requireElementById("menu-item-3").select("ul.sub-menu li a").mapNotNullToSet {
MangaTag( MangaTag(

@ -12,7 +12,7 @@ import java.util.*
@MangaSourceParser("CLONEMANGA", "CloneManga", "en") @MangaSourceParser("CLONEMANGA", "CloneManga", "en")
internal class CloneMangaParser(context: MangaLoaderContext) : MangaParser(context, MangaSource.CLONEMANGA) { internal class CloneMangaParser(context: MangaLoaderContext) : MangaParser(context, MangaSource.CLONEMANGA) {
override val sortOrders: Set<SortOrder> = Collections.singleton( override val availableSortOrders: Set<SortOrder> = Collections.singleton(
SortOrder.POPULARITY, SortOrder.POPULARITY,
) )
@ -89,5 +89,5 @@ internal class CloneMangaParser(context: MangaLoaderContext) : MangaParser(conte
) )
} }
override suspend fun getTags(): Set<MangaTag> = emptySet() override suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
} }

@ -14,10 +14,13 @@ import java.util.*
@MangaSourceParser("COMICEXTRA", "ComicExtra", "en") @MangaSourceParser("COMICEXTRA", "ComicExtra", "en")
internal class ComicExtra(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.COMICEXTRA, 25) { internal class ComicExtra(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.COMICEXTRA, 25) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.POPULARITY, SortOrder.UPDATED, SortOrder.NEWEST) override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.POPULARITY, SortOrder.UPDATED, SortOrder.NEWEST)
override val configKeyDomain = ConfigKey.Domain("comicextra.me") override val configKeyDomain = ConfigKey.Domain("comicextra.me")
override val isMultipleTagsSupported = false
override val headers: Headers = Headers.Builder() override val headers: Headers = Headers.Builder()
.add("User-Agent", UserAgents.CHROME_DESKTOP) .add("User-Agent", UserAgents.CHROME_DESKTOP)
.build() .build()
@ -80,7 +83,7 @@ internal class ComicExtra(context: MangaLoaderContext) : PagedMangaParser(contex
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): 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(

@ -15,7 +15,7 @@ import java.util.*
@MangaSourceParser("DYNASTYSCANS", "DynastyScans", "en") @MangaSourceParser("DYNASTYSCANS", "DynastyScans", "en")
internal class DynastyScans(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.DYNASTYSCANS, 117) { internal class DynastyScans(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.DYNASTYSCANS, 117) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL)
override val configKeyDomain = ConfigKey.Domain("dynasty-scans.com") override val configKeyDomain = ConfigKey.Domain("dynasty-scans.com")
override val headers: Headers = Headers.Builder() override val headers: Headers = Headers.Builder()
@ -100,7 +100,7 @@ internal class DynastyScans(context: MangaLoaderContext) : PagedMangaParser(cont
} }
} }
override suspend fun getTags(): Set<MangaTag> = emptySet() 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()

@ -15,11 +15,13 @@ import java.util.*
internal class Fakku(context: MangaLoaderContext) : internal class Fakku(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.FAKKU, pageSize = 25) { PagedMangaParser(context, MangaSource.FAKKU, pageSize = 25) {
override val sortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.ALPHABETICAL, SortOrder.NEWEST, SortOrder.UPDATED) EnumSet.of(SortOrder.ALPHABETICAL, SortOrder.NEWEST, SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain("fakku.cc") override val configKeyDomain = ConfigKey.Domain("fakku.cc")
override val isMultipleTagsSupported = false
override suspend fun getListPage( override suspend fun getListPage(
page: Int, page: Int,
query: String?, query: String?,
@ -77,7 +79,7 @@ internal class Fakku(context: MangaLoaderContext) :
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val root = webClient.httpGet("https://$domain/tags").parseHtml() val root = webClient.httpGet("https://$domain/tags").parseHtml()
return root.select("div.entries .entry a").mapToSet { return root.select("div.entries .entry a").mapToSet {
MangaTag( MangaTag(

@ -20,9 +20,10 @@ import java.util.*
@MangaSourceParser("KSKMOE", "Ksk.moe", "en", ContentType.HENTAI) @MangaSourceParser("KSKMOE", "Ksk.moe", "en", ContentType.HENTAI)
internal class KskMoe(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.KSKMOE, 35) { internal class KskMoe(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.KSKMOE, 35) {
override val sortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL)
override val configKeyDomain = ConfigKey.Domain("ksk.moe") override val configKeyDomain = ConfigKey.Domain("ksk.moe")
override val isMultipleTagsSupported = false
override suspend fun getListPage( override suspend fun getListPage(
page: Int, page: Int,
@ -91,7 +92,7 @@ internal class KskMoe(context: MangaLoaderContext) : PagedMangaParser(context, M
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
return coroutineScope { return coroutineScope {
(1..2).map { page -> (1..2).map { page ->
async { getTags(page) } async { getTags(page) }

@ -14,10 +14,13 @@ import java.util.*
@MangaSourceParser("MANGAGEKO", "MangaGeko", "en") @MangaSourceParser("MANGAGEKO", "MangaGeko", "en")
internal class MangaGeko(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.MANGAGEKO, 30) { internal class MangaGeko(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.MANGAGEKO, 30) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.POPULARITY, SortOrder.UPDATED, SortOrder.NEWEST) override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.POPULARITY, SortOrder.UPDATED, SortOrder.NEWEST)
override val configKeyDomain = ConfigKey.Domain("www.mangageko.com") override val configKeyDomain = ConfigKey.Domain("www.mangageko.com")
override val isMultipleTagsSupported = false
override val headers: Headers = Headers.Builder() override val headers: Headers = Headers.Builder()
.add("User-Agent", UserAgents.CHROME_DESKTOP) .add("User-Agent", UserAgents.CHROME_DESKTOP)
.build() .build()
@ -77,7 +80,7 @@ internal class MangaGeko(context: MangaLoaderContext) : PagedMangaParser(context
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): 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(

@ -15,7 +15,7 @@ internal class MangaTownParser(context: MangaLoaderContext) : MangaParser(contex
override val configKeyDomain = ConfigKey.Domain("www.mangatown.com") override val configKeyDomain = ConfigKey.Domain("www.mangatown.com")
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
SortOrder.RATING, SortOrder.RATING,
SortOrder.POPULARITY, SortOrder.POPULARITY,
@ -157,7 +157,7 @@ internal class MangaTownParser(context: MangaLoaderContext) : MangaParser(contex
return doc.requireElementById("image").attrAsAbsoluteUrl("src") return doc.requireElementById("image").attrAsAbsoluteUrl("src")
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): 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")

@ -18,7 +18,7 @@ import java.util.*
internal class Mangaowl(context: MangaLoaderContext) : internal class Mangaowl(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.MANGAOWL, pageSize = 24) { PagedMangaParser(context, MangaSource.MANGAOWL, pageSize = 24) {
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.NEWEST, SortOrder.NEWEST,
SortOrder.UPDATED, SortOrder.UPDATED,
@ -94,7 +94,7 @@ internal class Mangaowl(context: MangaLoaderContext) :
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/8-genres").parseHtml() val doc = webClient.httpGet("https://$domain/8-genres").parseHtml()
return doc.select("div.genres-container span.genre-item a").mapNotNullToSet { a -> return doc.select("div.genres-container span.genre-item a").mapNotNullToSet { a ->
val key = a.attr("href").substringAfterLast("/") val key = a.attr("href").substringAfterLast("/")

@ -15,7 +15,7 @@ class Manhwa18Parser(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("manhwa18.net") override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("manhwa18.net")
override val sortOrders: Set<SortOrder> override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.ALPHABETICAL, SortOrder.NEWEST) get() = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.ALPHABETICAL, SortOrder.NEWEST)
private val tagsMap = SuspendLazy(::parseTags) private val tagsMap = SuspendLazy(::parseTags)
@ -169,7 +169,7 @@ class Manhwa18Parser(context: MangaLoaderContext) :
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
return tagsMap.get().values.toSet() return tagsMap.get().values.toSet()
} }

@ -16,7 +16,9 @@ class ManhwasMen(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("manhwas.men") override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("manhwas.men")
override val sortOrders: Set<SortOrder> override val isMultipleTagsSupported = false
override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.POPULARITY) get() = EnumSet.of(SortOrder.POPULARITY)
override suspend fun getListPage( override suspend fun getListPage(
@ -64,7 +66,7 @@ class ManhwasMen(context: MangaLoaderContext) :
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): 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 ->

@ -12,7 +12,7 @@ import java.util.*
@MangaSourceParser("PO2SCANS", "Po2Scans", "en") @MangaSourceParser("PO2SCANS", "Po2Scans", "en")
internal class Po2Scans(context: MangaLoaderContext) : MangaParser(context, MangaSource.PO2SCANS) { internal class Po2Scans(context: MangaLoaderContext) : MangaParser(context, MangaSource.PO2SCANS) {
override val sortOrders: 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 suspend fun getList(offset: Int, query: String?, tags: Set<MangaTag>?, sortOrder: SortOrder): List<Manga> { override suspend fun getList(offset: Int, query: String?, tags: Set<MangaTag>?, sortOrder: SortOrder): List<Manga> {
@ -46,7 +46,7 @@ internal class Po2Scans(context: MangaLoaderContext) : MangaParser(context, Mang
} }
} }
override suspend fun getTags(): Set<MangaTag> = emptySet() 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()

@ -17,11 +17,13 @@ import java.util.*
internal class Pururin(context: MangaLoaderContext) : internal class Pururin(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.PURURIN, pageSize = 20) { PagedMangaParser(context, MangaSource.PURURIN, pageSize = 20) {
override val sortOrders: Set<SortOrder> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.RATING, SortOrder.ALPHABETICAL) EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.RATING, SortOrder.ALPHABETICAL)
override val configKeyDomain = ConfigKey.Domain("pururin.to") override val configKeyDomain = ConfigKey.Domain("pururin.to")
override val isMultipleTagsSupported = false
override suspend fun getListPage( override suspend fun getListPage(
page: Int, page: Int,
query: String?, query: String?,
@ -76,7 +78,7 @@ internal class Pururin(context: MangaLoaderContext) :
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
return coroutineScope { return coroutineScope {
(1..4).map { page -> (1..4).map { page ->
async { getTags(page) } async { getTags(page) }

@ -16,7 +16,7 @@ import java.util.*
internal class TempleScanEsp(context: MangaLoaderContext) : internal class TempleScanEsp(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.TEMPLESCANESP, pageSize = 15) { PagedMangaParser(context, MangaSource.TEMPLESCANESP, pageSize = 15) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.NEWEST, SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.NEWEST, SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain("templescanesp.net") override val configKeyDomain = ConfigKey.Domain("templescanesp.net")
@ -66,7 +66,7 @@ internal class TempleScanEsp(context: MangaLoaderContext) :
} }
} }
override suspend fun getTags(): Set<MangaTag> = emptySet() override suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
override suspend fun getDetails(manga: Manga): Manga = coroutineScope { override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain) val fullUrl = manga.url.toAbsoluteUrl(domain)

@ -24,7 +24,7 @@ class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaParser(
private val chapterDateFormat = SimpleDateFormat("yyyy-MM-dd", sourceLocale) private val chapterDateFormat = SimpleDateFormat("yyyy-MM-dd", sourceLocale)
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.NEWEST, SortOrder.NEWEST,
@ -207,7 +207,7 @@ class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaParser(
return document return document
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/library", headers).parseHtml() val doc = webClient.httpGet("https://$domain/library", headers).parseHtml()
val elements = doc.body().select("div#books-genders > div > div") val elements = doc.body().select("div#books-genders > div > div")
return elements.mapNotNullToSet { element -> return elements.mapNotNullToSet { element ->

@ -21,12 +21,14 @@ internal abstract class FmreaderParser(
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
) )
override val isMultipleTagsSupported = false
protected open val listUrl = "/manga-list.html" protected open val listUrl = "/manga-list.html"
protected open val datePattern = "MMMM d, yyyy" protected open val datePattern = "MMMM d, yyyy"
protected open val tagPrefix = "manga-list-genre-" protected open val tagPrefix = "manga-list-genre-"
@ -113,7 +115,7 @@ internal abstract class FmreaderParser(
protected open val selectBodyTag = "ul.filter-type li a" protected open val selectBodyTag = "ul.filter-type li a"
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml() val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml()
return doc.select(selectBodyTag).mapNotNullToSet { a -> return doc.select(selectBodyTag).mapNotNullToSet { a ->
val href = a.attr("href").substringAfter(tagPrefix).substringBeforeLast(".html") val href = a.attr("href").substringAfter(tagPrefix).substringBeforeLast(".html")

@ -86,7 +86,7 @@ internal class Manhwa18Com(context: MangaLoaderContext) :
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml() val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml()
return doc.select(selectBodyTag).mapNotNullToSet { a -> return doc.select(selectBodyTag).mapNotNullToSet { a ->
val href = a.attr("href").substringAfterLast("/") val href = a.attr("href").substringAfterLast("/")

@ -20,7 +20,7 @@ internal abstract class FoolSlideParser(
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL)
protected open val listUrl = "directory/" protected open val listUrl = "directory/"
protected open val searchUrl = "search/" protected open val searchUrl = "search/"
@ -81,7 +81,7 @@ internal abstract class FoolSlideParser(
} }
override suspend fun getTags(): Set<MangaTag> = emptySet() override suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
protected open val selectInfo = "div.info" protected open val selectInfo = "div.info"

@ -18,7 +18,7 @@ import java.util.*
@MangaSourceParser("BENTOMANGA", "BentoManga", "fr") @MangaSourceParser("BENTOMANGA", "BentoManga", "fr")
internal class BentomangaParser(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.BENTOMANGA, 10) { internal class BentomangaParser(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.BENTOMANGA, 10) {
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.RATING, SortOrder.RATING,
@ -99,11 +99,14 @@ internal class BentomangaParser(context: MangaLoaderContext) : PagedMangaParser(
val root = webClient.httpGet(mangaUrl).parseHtml() val root = webClient.httpGet(mangaUrl).parseHtml()
.requireElementById("container_manga_show") .requireElementById("container_manga_show")
return manga.copy( return manga.copy(
altTitle = root.selectFirst(".component-manga-title_alt")?.textOrNull().assertNotNull("altTitle"), altTitle = root.selectFirst(".component-manga-title_alt")?.text(),
description = root.selectFirst(".datas_synopsis")?.html().assertNotNull("description") description = root.selectFirst(".datas_synopsis")?.html().assertNotNull("description")
?: manga.description, ?: manga.description,
state = when (root.selectFirst(".datas_more-status-data")?.textOrNull().assertNotNull("status")) { state = when (root.selectFirst(".datas_more-status-data")?.textOrNull().assertNotNull("status")) {
"En cours" -> MangaState.ONGOING "En cours" -> MangaState.ONGOING
"Terminé" -> MangaState.FINISHED
"Abandonné" -> MangaState.ABANDONED
"En pause" -> MangaState.PAUSED
else -> null else -> null
}, },
author = root.selectFirst(".datas_more-authors-people")?.textOrNull().assertNotNull("author"), author = root.selectFirst(".datas_more-authors-people")?.textOrNull().assertNotNull("author"),
@ -156,7 +159,7 @@ internal class BentomangaParser(context: MangaLoaderContext) : PagedMangaParser(
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): 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,7 +17,7 @@ import java.util.*
internal class FmTeam(context: MangaLoaderContext) : internal class FmTeam(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.FMTEAM, 0) { PagedMangaParser(context, MangaSource.FMTEAM, 0) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL)
override val configKeyDomain = ConfigKey.Domain("fmteam.fr") override val configKeyDomain = ConfigKey.Domain("fmteam.fr")
override suspend fun getListPage( override suspend fun getListPage(
@ -29,11 +29,9 @@ internal class FmTeam(context: MangaLoaderContext) :
if (page > 1) { if (page > 1) {
return emptyList() return emptyList()
} }
val jsonManga = if (!query.isNullOrEmpty()) { val jsonManga = if (!query.isNullOrEmpty()) {
//3 letters minimum //3 letters minimum
webClient.httpGet("https://$domain/api/search/${query.urlEncoded()}").parseJson().getJSONArray("comics") webClient.httpGet("https://$domain/api/search/${query.urlEncoded()}").parseJson().getJSONArray("comics")
} else { } else {
webClient.httpGet("https://$domain/api/comics").parseJson().getJSONArray("comics") webClient.httpGet("https://$domain/api/comics").parseJson().getJSONArray("comics")
} }
@ -99,7 +97,7 @@ internal class FmTeam(context: MangaLoaderContext) :
} }
override suspend fun getTags(): Set<MangaTag> = emptySet() override suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
override suspend fun getDetails(manga: Manga): Manga = coroutineScope { override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
val fullUrl = manga.url.toAbsoluteUrl(domain) val fullUrl = manga.url.toAbsoluteUrl(domain)

@ -18,7 +18,7 @@ import java.util.*
internal class FuryoSociety(context: MangaLoaderContext) : internal class FuryoSociety(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.FURYOSOCIETY, 0) { PagedMangaParser(context, MangaSource.FURYOSOCIETY, 0) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL, SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL, SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain("furyosociety.com") override val configKeyDomain = ConfigKey.Domain("furyosociety.com")
@ -76,7 +76,7 @@ internal class FuryoSociety(context: MangaLoaderContext) :
} }
override suspend fun getTags(): Set<MangaTag> = emptySet() override suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
override suspend fun getDetails(manga: Manga): Manga = coroutineScope { override suspend fun getDetails(manga: Manga): Manga = coroutineScope {

@ -16,7 +16,7 @@ import java.util.*
internal class LegacyScansParser(context: MangaLoaderContext) : internal class LegacyScansParser(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.LEGACY_SCANS, 18) { PagedMangaParser(context, MangaSource.LEGACY_SCANS, 18) {
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY, SortOrder.POPULARITY,
) )
@ -151,7 +151,7 @@ internal class LegacyScansParser(context: MangaLoaderContext) :
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): 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\"")

@ -14,10 +14,12 @@ import java.util.*
@MangaSourceParser("LIRESCAN", "LireScan", "fr") @MangaSourceParser("LIRESCAN", "LireScan", "fr")
internal class LireScan(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.LIRESCAN, 20) { internal class LireScan(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.LIRESCAN, 20) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain("lire-scan.me") override val configKeyDomain = ConfigKey.Domain("lire-scan.me")
override val isMultipleTagsSupported = false
override val headers: Headers = Headers.Builder() override val headers: Headers = Headers.Builder()
.add("User-Agent", UserAgents.CHROME_MOBILE) .add("User-Agent", UserAgents.CHROME_MOBILE)
.build() .build()
@ -130,7 +132,7 @@ internal class LireScan(context: MangaLoaderContext) : PagedMangaParser(context,
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): 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/", "")

@ -16,7 +16,7 @@ import java.util.*
@MangaSourceParser("LUGNICASCANS", "LugnicaScans", "fr") @MangaSourceParser("LUGNICASCANS", "LugnicaScans", "fr")
internal class LugnicaScans(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.LUGNICASCANS, 10) { internal class LugnicaScans(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.LUGNICASCANS, 10) {
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
SortOrder.UPDATED, SortOrder.UPDATED,
) )
@ -176,6 +176,6 @@ internal class LugnicaScans(context: MangaLoaderContext) : PagedMangaParser(cont
return pages return pages
} }
override suspend fun getTags(): Set<MangaTag> = emptySet() override suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
} }

@ -17,7 +17,7 @@ import java.util.*
internal class ScansMangasMe(context: MangaLoaderContext) : internal class ScansMangasMe(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.SCANS_MANGAS_ME, 0) { PagedMangaParser(context, MangaSource.SCANS_MANGAS_ME, 0) {
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.NEWEST, SortOrder.NEWEST,
@ -91,7 +91,7 @@ internal class ScansMangasMe(context: MangaLoaderContext) :
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/tous-nos-mangas/").parseHtml() val doc = webClient.httpGet("https://$domain/tous-nos-mangas/").parseHtml()
return doc.select("ul.genre li").mapNotNullToSet { li -> return doc.select("ul.genre li").mapNotNullToSet { li ->
val key = li.selectFirstOrThrow("a").attr("href").removeSuffix('/').substringAfterLast('/') val key = li.selectFirstOrThrow("a").attr("href").removeSuffix('/').substringAfterLast('/')

@ -15,7 +15,7 @@ import java.util.*
@MangaSourceParser("SCANTRADUNION", "ScantradUnion", "fr") @MangaSourceParser("SCANTRADUNION", "ScantradUnion", "fr")
internal class ScantradUnion(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.SCANTRADUNION, 10) { internal class ScantradUnion(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.SCANTRADUNION, 10) {
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
SortOrder.UPDATED, SortOrder.UPDATED,
) )
@ -174,7 +174,7 @@ internal class ScantradUnion(context: MangaLoaderContext) : PagedMangaParser(con
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/").parseHtml() val doc = webClient.httpGet("https://$domain/").parseHtml()
val body = doc.body() val body = doc.body()
val root = body.select(".asp_gochosen")[1] val root = body.select(".asp_gochosen")[1]

@ -20,8 +20,9 @@ internal abstract class GalleryAdultsParser(
pageSize: Int = 20, pageSize: Int = 20,
) : PagedMangaParser(context, source, pageSize) { ) : PagedMangaParser(context, source, pageSize) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override val isMultipleTagsSupported = false
override suspend fun getListPage( override suspend fun getListPage(
page: Int, page: Int,
@ -87,7 +88,7 @@ internal abstract class GalleryAdultsParser(
//Tags are deliberately reduced because there are too many and this slows down the application. //Tags are deliberately reduced because there are too many and this slows down the application.
//only the most popular ones are taken. //only the most popular ones are taken.
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
return coroutineScope { return coroutineScope {
(1..3).map { page -> (1..3).map { page ->
async { getTags(page) } async { getTags(page) }

@ -20,7 +20,7 @@ internal abstract class HeanCms(
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.NEWEST, SortOrder.NEWEST,
@ -100,6 +100,7 @@ internal abstract class HeanCms(
"Ongoing" -> MangaState.ONGOING "Ongoing" -> MangaState.ONGOING
"Completed" -> MangaState.FINISHED "Completed" -> MangaState.FINISHED
"Dropped" -> MangaState.ABANDONED "Dropped" -> MangaState.ABANDONED
"Hiatus" -> MangaState.PAUSED
else -> null else -> null
}, },
author = null, author = null,
@ -159,7 +160,7 @@ internal abstract class HeanCms(
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/comics").parseHtml() val doc = webClient.httpGet("https://$domain/comics").parseHtml()
val tags = doc.selectFirstOrThrow("script:containsData(Genres)").data() val tags = doc.selectFirstOrThrow("script:containsData(Genres)").data()

@ -84,6 +84,7 @@ internal class YugenMangasEs(context: MangaLoaderContext) :
"Ongoing" -> MangaState.ONGOING "Ongoing" -> MangaState.ONGOING
"Completed" -> MangaState.FINISHED "Completed" -> MangaState.FINISHED
"Dropped" -> MangaState.ABANDONED "Dropped" -> MangaState.ABANDONED
"Hiatus" -> MangaState.PAUSED
else -> null else -> null
}, },
author = null, author = null,

@ -20,7 +20,7 @@ internal abstract class HeanCmsAlt(
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
protected open val listUrl = "/comics" protected open val listUrl = "/comics"
protected open val datePattern = "MMMM d, yyyy" protected open val datePattern = "MMMM d, yyyy"
@ -73,7 +73,7 @@ internal abstract class HeanCmsAlt(
} }
} }
override suspend fun getTags(): Set<MangaTag> = emptySet() override suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
protected open val selectDesc = "div.description-container" protected open val selectDesc = "div.description-container"
protected open val selectAlt = "div.series-alternative-names" protected open val selectAlt = "div.series-alternative-names"

@ -15,7 +15,7 @@ class DoujinDesuParser(context: MangaLoaderContext) : PagedMangaParser(context,
override val configKeyDomain: ConfigKey.Domain override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("doujindesu.tv") get() = ConfigKey.Domain("doujindesu.tv")
override val sortOrders: 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 suspend fun getDetails(manga: Manga): Manga { override suspend fun getDetails(manga: Manga): Manga {
@ -125,7 +125,7 @@ class DoujinDesuParser(context: MangaLoaderContext) : PagedMangaParser(context,
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
return webClient.httpGet("/genre/".toAbsoluteUrl(domain)).parseHtml() return webClient.httpGet("/genre/".toAbsoluteUrl(domain)).parseHtml()
.requireElementById("taxonomy") .requireElementById("taxonomy")
.selectFirstOrThrow(".entries") .selectFirstOrThrow(".entries")

@ -34,7 +34,7 @@ class NicovideoSeigaParser(context: MangaLoaderContext) :
return body.selectFirst("#userinfo > div > div > strong")?.text() ?: throw AuthRequiredException(source) return body.selectFirst("#userinfo > div > div > strong")?.text() ?: throw AuthRequiredException(source)
} }
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.POPULARITY, SortOrder.POPULARITY,
) )
@ -143,7 +143,7 @@ class NicovideoSeigaParser(context: MangaLoaderContext) :
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): 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") val root = doc.body().selectOrThrow("#mg_category_list > ul > li")
return root.mapToSet { li -> return root.mapToSet { li ->

@ -21,8 +21,10 @@ internal abstract class LikeMangaParser(
pageSize: Int = 36, pageSize: Int = 36,
) : PagedMangaParser(context, source, pageSize) { ) : PagedMangaParser(context, source, pageSize) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST) override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST)
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override val isMultipleTagsSupported = false
override suspend fun getListPage( override suspend fun getListPage(
page: Int, page: Int,
@ -80,7 +82,7 @@ internal abstract class LikeMangaParser(
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): 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(

@ -23,7 +23,9 @@ internal abstract class MadaraParser(
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of( override val isMultipleTagsSupported = false
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.NEWEST, SortOrder.NEWEST,
@ -137,6 +139,16 @@ internal abstract class MadaraParser(
"Abandonné", "Abandonné",
) )
@JvmField
protected val paused: Set<String> = hashSetOf(
"Hiatus",
"On Hold",
"Pausado",
"En espera",
"En pause",
"En attente",
)
// Change these values only if the site does not support manga listings via ajax // Change these values only if the site does not support manga listings via ajax
protected open val withoutAjax = false protected open val withoutAjax = false
@ -232,11 +244,11 @@ internal abstract class MadaraParser(
) )
}.orEmpty(), }.orEmpty(),
author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(), author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(),
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText() state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText()) {
?.lowercase()) {
in ongoing -> MangaState.ONGOING in ongoing -> MangaState.ONGOING
in finished -> MangaState.FINISHED in finished -> MangaState.FINISHED
in abandoned -> MangaState.ABANDONED in abandoned -> MangaState.ABANDONED
in paused -> MangaState.PAUSED
else -> null else -> null
}, },
source = source, source = source,
@ -245,7 +257,7 @@ internal abstract class MadaraParser(
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml() val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml()
val body = doc.body() val body = doc.body()
val root1 = body.selectFirst("header")?.selectFirst("ul.second-menu") val root1 = body.selectFirst("header")?.selectFirst("ul.second-menu")
@ -314,6 +326,7 @@ internal abstract class MadaraParser(
in ongoing -> MangaState.ONGOING in ongoing -> MangaState.ONGOING
in finished -> MangaState.FINISHED in finished -> MangaState.FINISHED
in abandoned -> MangaState.ABANDONED in abandoned -> MangaState.ABANDONED
in paused -> MangaState.PAUSED
else -> null else -> null
} }
} }

@ -5,9 +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.*
import java.util.HashSet
import java.util.Locale
@MangaSourceParser("MANGA18FX", "Manga18Fx", "", ContentType.HENTAI) @MangaSourceParser("MANGA18FX", "Manga18Fx", "", ContentType.HENTAI)
internal class Manga18Fx(context: MangaLoaderContext) : internal class Manga18Fx(context: MangaLoaderContext) :
@ -15,7 +13,7 @@ internal class Manga18Fx(context: MangaLoaderContext) :
override val sourceLocale: Locale = Locale.ENGLISH override val sourceLocale: Locale = Locale.ENGLISH
override val datePattern = "dd MMM yy" override val datePattern = "dd MMM yy"
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val listUrl = "" override val listUrl = ""
override val selectTestAsync = "ul.row-content-chapter" override val selectTestAsync = "ul.row-content-chapter"
override val selectDate = "span.chapter-time" override val selectDate = "span.chapter-time"
@ -79,7 +77,7 @@ internal class Manga18Fx(context: MangaLoaderContext) :
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): 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)

@ -90,7 +90,7 @@ internal class Manhwa18Cc(context: MangaLoaderContext) :
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): 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)

@ -17,7 +17,7 @@ internal class InstaManhwa(context: MangaLoaderContext) :
override val postReq = true override val postReq = true
override val datePattern = "d MMMM, yyyy" override val datePattern = "d MMMM, yyyy"
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.NEWEST, SortOrder.NEWEST,

@ -17,7 +17,7 @@ internal class IsekaiScan(context: MangaLoaderContext) :
override val listUrl = "latest-manga/" override val listUrl = "latest-manga/"
override val datePattern = "MMMM d, HH:mm" override val datePattern = "MMMM d, HH:mm"
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.UPDATED, SortOrder.UPDATED,
) )

@ -16,7 +16,7 @@ internal class MangaPure(context: MangaLoaderContext) :
override val listUrl = "latest-manga/" override val listUrl = "latest-manga/"
override val datePattern = "MMMM d, HH:mm" override val datePattern = "MMMM d, HH:mm"
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.UPDATED, SortOrder.UPDATED,
) )

@ -14,7 +14,7 @@ import java.util.*
internal class DragonTranslationParser(context: MangaLoaderContext) : internal class DragonTranslationParser(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.DRAGONTRANSLATION, "dragontranslation.net", 30) { MadaraParser(context, MangaSource.DRAGONTRANSLATION, "dragontranslation.net", 30) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val selectPage = "div#chapter_imgs img" override val selectPage = "div#chapter_imgs img"

@ -22,7 +22,7 @@ internal class TmoManga(context: MangaLoaderContext) :
searchPaginator.firstPage = 1 searchPaginator.firstPage = 1
} }
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.POPULARITY) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.POPULARITY)
override suspend fun getListPage( override suspend fun getListPage(
page: Int, page: Int,
query: String?, query: String?,

@ -105,7 +105,7 @@ internal class ManhwaHub(context: MangaLoaderContext) :
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain").parseHtml() val doc = webClient.httpGet("https://$domain").parseHtml()
return doc.select("div.genres li").mapNotNullToSet { li -> return doc.select("div.genres li").mapNotNullToSet { li ->
val a = li.selectFirst("a") ?: return@mapNotNullToSet null val a = li.selectFirst("a") ?: return@mapNotNullToSet null

@ -7,6 +7,6 @@ import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
@MangaSourceParser("CERISE_SCANS", "CeriseScans", "pt") @MangaSourceParser("CERISE_SCANS", "CeriseScans", "pt")
internal class CeriseScans(context: MangaLoaderContext) : internal class CeriseScans(context: MangaLoaderContext) :
MadaraParser(context, MangaSource.CERISE_SCANS, "cerisescan.net/") { MadaraParser(context, MangaSource.CERISE_SCANS, "cerisescan.net") {
override val datePattern: String = "dd 'de' MMMMM 'de' yyyy" override val datePattern: String = "dd 'de' MMMMM 'de' yyyy"
} }

@ -21,7 +21,7 @@ internal abstract class MadthemeParser(
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
@ -115,7 +115,7 @@ internal abstract class MadthemeParser(
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml() val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml()
return doc.select("div.genres label.checkbox").mapNotNullToSet { checkbox -> return doc.select("div.genres label.checkbox").mapNotNullToSet { checkbox ->
val key = checkbox.selectFirstOrThrow("input").attr("value") ?: return@mapNotNullToSet null val key = checkbox.selectFirstOrThrow("input").attr("value") ?: return@mapNotNullToSet null

@ -20,7 +20,7 @@ internal abstract class Manga18Parser(
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
@ -109,7 +109,7 @@ internal abstract class Manga18Parser(
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): 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

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

@ -17,7 +17,7 @@ internal abstract class MangaboxParser(
pageSize: Int = 24, pageSize: Int = 24,
) : PagedMangaParser(context, source, pageSize) { ) : PagedMangaParser(context, source, pageSize) {
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.NEWEST, SortOrder.NEWEST,
@ -107,7 +107,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 getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): 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 ->
val key = a.attr("href").removeSuffix('/').substringAfterLast('/') val key = a.attr("href").removeSuffix('/').substringAfterLast('/')

@ -99,7 +99,7 @@ internal class Mangairo(context: MangaLoaderContext) :
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): 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("/")

@ -73,7 +73,7 @@ internal class MangakakalotTv(context: MangaLoaderContext) :
override val selectTagMap = "ul.tag li a" override val selectTagMap = "ul.tag li a"
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): 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(

@ -29,7 +29,7 @@ internal abstract class MangaReaderParser(
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.ALPHABETICAL, SortOrder.NEWEST) get() = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.ALPHABETICAL, SortOrder.NEWEST)
protected open val listUrl = "/manga" protected open val listUrl = "/manga"
@ -181,20 +181,24 @@ internal abstract class MangaReaderParser(
val mangaState = state?.let { val mangaState = state?.let {
when (it.text()) { when (it.text()) {
"مستمرة", "En curso", "En Curso", "Ongoing", "OnGoing", "On going", "Ativo", "En Cours", "En cours",
"En cours \uD83D\uDFE2", "En cours de publication", "Đang tiến hành", "Em lançamento", "em lançamento", "Em Lançamento", "مستمرة", "En curso", "En Curso", "Ongoing", "OnGoing", "On going", "Ativo", "En Cours", "En cours", "En cours \uD83D\uDFE2",
"Онгоінг", "Publishing", "Devam Ediyor", "Em Andamento", "In Corso", "Güncel", "Berjalan", "Продолжается", "Updating", "En cours de publication", "Đang tiến hành", "Em lançamento", "em lançamento", "Em Lançamento", "Онгоінг", "Publishing",
"Lançando", "In Arrivo", "Emision", "En emision", "مستمر", "Curso", "En marcha", "Publicandose", "Publicando", "连载中", "Devam Ediyor", "Em Andamento", "In Corso", "Güncel", "Berjalan", "Продолжается", "Updating", "Lançando", "In Arrivo", "Emision",
"Devam ediyor", "Devam Etmekte", "En emision", "مستمر", "Curso", "En marcha", "Publicandose", "Publicando", "连载中", "Devam ediyor", "Devam Etmekte",
-> MangaState.ONGOING -> MangaState.ONGOING
"Completed", "Completo", "Complété", "Fini", "Achevé", "Terminé", "Terminé ⚫", "Tamamlandı", "Đã hoàn thành", "Hoàn Thành", "مكتملة", "Completed", "Completo", "Complété", "Fini", "Achevé", "Terminé", "Terminé ⚫", "Tamamlandı", "Đã hoàn thành", "Hoàn Thành",
"Завершено", "Finished", "Finalizado", "Completata", "One-Shot", "Bitti", "Tamat", "Completado", "Concluído", "Concluido", "已完结", "Bitmiş", "مكتملة", "Завершено", "Finished", "Finalizado", "Completata", "One-Shot", "Bitti", "Tamat", "Completado", "Concluído",
"Concluido", "已完结", "Bitmiş",
-> MangaState.FINISHED -> MangaState.FINISHED
"Canceled", "Cancelled", "Cancelado", "cancellato", "Cancelados", "Dropped", "Discontinued", "abandonné", "Abandonné", "Canceled", "Cancelled", "Cancelado", "cancellato", "Cancelados", "Dropped", "Discontinued", "abandonné", "Abandonné",
-> MangaState.ABANDONED -> MangaState.ABANDONED
"Hiatus", "On Hold", "Pausado", "En espera", "En pause", "En Pause", "En attente",
-> MangaState.PAUSED
else -> null else -> null
} }
} }
@ -283,7 +287,7 @@ internal abstract class MangaReaderParser(
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
return getOrCreateTagMap().values.toSet() return getOrCreateTagMap().values.toSet()
} }

@ -75,7 +75,7 @@ internal class ManhwaFreak(context: MangaLoaderContext) :
return parseMangaList(webClient.httpGet(url).parseHtml()) return parseMangaList(webClient.httpGet(url).parseHtml())
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/genres/").parseHtml() val doc = webClient.httpGet("https://$domain/genres/").parseHtml()
return doc.select("ul.genre-list li a").mapNotNullToSet { a -> return doc.select("ul.genre-list li a").mapNotNullToSet { a ->
val href = a.attr("href").substringAfterLast("=") val href = a.attr("href").substringAfterLast("=")

@ -19,7 +19,7 @@ internal class RizzComic(context: MangaLoaderContext) :
override val datePattern = "dd MMM yyyy" override val datePattern = "dd MMM yyyy"
override val listUrl = "/series" override val listUrl = "/series"
override val sortOrders: Set<SortOrder> override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.ALPHABETICAL) get() = EnumSet.of(SortOrder.ALPHABETICAL)
override suspend fun getListPage( override suspend fun getListPage(

@ -21,7 +21,7 @@ internal class Zahard(context: MangaLoaderContext) :
override val selectPage = "div#chapter_imgs img" override val selectPage = "div#chapter_imgs img"
override val sortOrders: Set<SortOrder> override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.NEWEST) get() = EnumSet.of(SortOrder.NEWEST)

@ -19,10 +19,10 @@ internal class TuManhwas(context: MangaLoaderContext) :
override val selectPage = "div#readerarea img" override val selectPage = "div#readerarea img"
override val sortOrders: Set<SortOrder> override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.NEWEST) get() = EnumSet.of(SortOrder.NEWEST)
override suspend fun getTags(): Set<MangaTag> = emptySet() override suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
override suspend fun getListPage( override suspend fun getListPage(
page: Int, page: Int,
query: String?, query: String?,

@ -77,7 +77,7 @@ internal class ManhwaFreakFr(context: MangaLoaderContext) :
return parseMangaList(webClient.httpGet(url).parseHtml()) return parseMangaList(webClient.httpGet(url).parseHtml())
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/genres/").parseHtml() val doc = webClient.httpGet("https://$domain/genres/").parseHtml()
return doc.select("ul.genre-list li a").mapNotNullToSet { a -> return doc.select("ul.genre-list li a").mapNotNullToSet { a ->
val href = a.attr("href").substringAfterLast("=") val href = a.attr("href").substringAfterLast("=")

@ -18,7 +18,7 @@ internal class Komikcast(context: MangaLoaderContext) :
override val listUrl = "/daftar-komik" override val listUrl = "/daftar-komik"
override val datePattern = "MMM d, yyyy" override val datePattern = "MMM d, yyyy"
override val sourceLocale: Locale = Locale.ENGLISH override val sourceLocale: Locale = Locale.ENGLISH
override val sortOrders: Set<SortOrder> override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.ALPHABETICAL) get() = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.ALPHABETICAL)
override suspend fun getListPage( override suspend fun getListPage(

@ -20,7 +20,7 @@ internal abstract class MmrcmsParser(
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
@ -138,7 +138,7 @@ internal abstract class MmrcmsParser(
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$tagUrl/").parseHtml() val doc = webClient.httpGet("https://$domain/$tagUrl/").parseHtml()
return doc.select("ul.list-category li").mapNotNullToSet { li -> return doc.select("ul.list-category li").mapNotNullToSet { li ->
val a = li.selectFirst("a") ?: return@mapNotNullToSet null val a = li.selectFirst("a") ?: return@mapNotNullToSet null

@ -23,7 +23,7 @@ internal abstract class NepnepParser(
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL)
override val headers: Headers = Headers.Builder() override val headers: Headers = Headers.Builder()
.add("User-Agent", UserAgents.CHROME_DESKTOP) .add("User-Agent", UserAgents.CHROME_DESKTOP)
@ -104,7 +104,7 @@ internal abstract class NepnepParser(
) )
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/search/").parseHtml() val doc = webClient.httpGet("https://$domain/search/").parseHtml()
val tags = doc.selectFirstOrThrow("script:containsData(vm.AvailableFilters)").data() val tags = doc.selectFirstOrThrow("script:containsData(vm.AvailableFilters)").data()
.substringAfter("\"Genre\"") .substringAfter("\"Genre\"")
@ -138,12 +138,18 @@ internal abstract class NepnepParser(
return manga.copy( return manga.copy(
altTitle = null, altTitle = null,
state = when (doc.selectFirstOrThrow(".list-group-item:contains(Status:) a").text()) { state = when (doc.selectFirstOrThrow(".list-group-item:contains(Status:) a").text()) {
"Ongoing (Scan)", "Ongoing (Publish)" -> MangaState.ONGOING "Ongoing (Scan)", "Ongoing (Publish)",
-> MangaState.ONGOING
"Complete (Scan)", "Complete (Publish)", "Complete (Scan)", "Complete (Publish)",
-> MangaState.FINISHED
"Cancelled (Scan)", "Cancelled (Publish)", "Cancelled (Scan)", "Cancelled (Publish)",
"Discontinued (Scan)", "Discontinued (Publish)", "Discontinued (Scan)", "Discontinued (Publish)",
-> MangaState.ABANDONED
"Hiatus (Scan)", "Hiatus (Publish)", "Hiatus (Scan)", "Hiatus (Publish)",
-> MangaState.FINISHED -> MangaState.PAUSED
else -> null else -> null
}, },

@ -20,7 +20,7 @@ internal abstract class OtakuSanctuaryParser(
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.NEWEST, SortOrder.NEWEST,
) )
@ -114,7 +114,7 @@ internal abstract class OtakuSanctuaryParser(
protected open val selectBodyTag = "div#genre-table a" protected open val selectBodyTag = "div#genre-table a"
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/Home/LoadingGenresMenu").parseHtml() val doc = webClient.httpGet("https://$domain/Home/LoadingGenresMenu").parseHtml()
return doc.select(selectBodyTag).mapNotNullToSet { a -> return doc.select(selectBodyTag).mapNotNullToSet { a ->
val href = a.attr("href").substringAfterLast("/").substringBefore("?") val href = a.attr("href").substringAfterLast("/").substringBefore("?")

@ -13,7 +13,7 @@ import java.util.*
@MangaSourceParser("BAKAI", "Bakai", "pt", ContentType.HENTAI) @MangaSourceParser("BAKAI", "Bakai", "pt", ContentType.HENTAI)
internal class Bakai(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.BAKAI, 15) { internal class Bakai(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.BAKAI, 15) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain("bakai.org") override val configKeyDomain = ConfigKey.Domain("bakai.org")
override val headers: Headers = Headers.Builder() override val headers: Headers = Headers.Builder()
.add("User-Agent", UserAgents.CHROME_MOBILE) .add("User-Agent", UserAgents.CHROME_MOBILE)
@ -89,7 +89,7 @@ internal class Bakai(context: MangaLoaderContext) : PagedMangaParser(context, Ma
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain").parseHtml() val doc = webClient.httpGet("https://$domain").parseHtml()
return doc.requireElementById("elNavigation_17_menu").select("li.ipsMenu_item a").mapNotNullToSet { a -> return doc.requireElementById("elNavigation_17_menu").select("li.ipsMenu_item a").mapNotNullToSet { a ->

@ -13,7 +13,7 @@ import java.util.*
@MangaSourceParser("BRMANGAS", "BrMangas", "pt") @MangaSourceParser("BRMANGAS", "BrMangas", "pt")
internal class BrMangas(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.BRMANGAS, 25) { internal class BrMangas(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.BRMANGAS, 25) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.POPULARITY, SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.POPULARITY, SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain("www.brmangas.net") override val configKeyDomain = ConfigKey.Domain("www.brmangas.net")
@ -81,7 +81,7 @@ internal class BrMangas(context: MangaLoaderContext) : PagedMangaParser(context,
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/lista-de-generos-de-manga/").parseHtml() val doc = webClient.httpGet("https://$domain/lista-de-generos-de-manga/").parseHtml()
return doc.select(".genres_page a").mapNotNullToSet { a -> return doc.select(".genres_page a").mapNotNullToSet { a ->
MangaTag( MangaTag(

@ -14,7 +14,7 @@ import java.util.*
@MangaSourceParser("LERMANGAONLINE", "LerMangaOnline", "pt") @MangaSourceParser("LERMANGAONLINE", "LerMangaOnline", "pt")
class LerMangaOnline(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.LERMANGAONLINE, 20) { class LerMangaOnline(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.LERMANGAONLINE, 20) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain("lermangaonline.com.br") override val configKeyDomain = ConfigKey.Domain("lermangaonline.com.br")
@ -67,7 +67,7 @@ class LerMangaOnline(context: MangaLoaderContext) : PagedMangaParser(context, Ma
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/").parseHtml().requireElementById("sub-menu") val doc = webClient.httpGet("https://$domain/").parseHtml().requireElementById("sub-menu")
return doc.select("ul.container li a").mapNotNullToSet { a -> return doc.select("ul.container li a").mapNotNullToSet { a ->
MangaTag( MangaTag(

@ -12,7 +12,7 @@ import java.util.*
@MangaSourceParser("MANGAONLINE", "MangaOnline.biz", "pt") @MangaSourceParser("MANGAONLINE", "MangaOnline.biz", "pt")
class MangaOnline(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.MANGAONLINE, 20) { class MangaOnline(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.MANGAONLINE, 20) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain("mangaonline.biz") override val configKeyDomain = ConfigKey.Domain("mangaonline.biz")
@ -71,7 +71,7 @@ class MangaOnline(context: MangaLoaderContext) : PagedMangaParser(context, Manga
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/generos/").parseHtml() val doc = webClient.httpGet("https://$domain/generos/").parseHtml()
return doc.select(".wp-content p a").mapNotNullToSet { a -> return doc.select(".wp-content p a").mapNotNullToSet { a ->
MangaTag( MangaTag(

@ -16,7 +16,7 @@ import java.util.*
@MangaSourceParser("YUGENMANGAS", "YugenMangas.net.br", "pt") @MangaSourceParser("YUGENMANGAS", "YugenMangas.net.br", "pt")
class YugenMangas(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.YUGENMANGAS, 28) { class YugenMangas(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.YUGENMANGAS, 28) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL, SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain("yugenmangas.net.br") override val configKeyDomain = ConfigKey.Domain("yugenmangas.net.br")
override suspend fun getListPage( override suspend fun getListPage(
@ -86,7 +86,7 @@ class YugenMangas(context: MangaLoaderContext) : PagedMangaParser(context, Manga
when (it) { when (it) {
"ongoing" -> MangaState.ONGOING "ongoing" -> MangaState.ONGOING
"completed" -> MangaState.FINISHED "completed" -> MangaState.FINISHED
//"hiatus" -> MangaState.PAUSED "hiatus" -> MangaState.PAUSED
else -> null else -> null
} }
}, },
@ -145,5 +145,5 @@ class YugenMangas(context: MangaLoaderContext) : PagedMangaParser(context, Manga
return pages return pages
} }
override suspend fun getTags(): Set<MangaTag> = emptySet() override suspend fun getAvailableTags(): Set<MangaTag> = emptySet()
} }

@ -20,7 +20,7 @@ internal class DesuMeParser(context: MangaLoaderContext) : PagedMangaParser(cont
override val configKeyDomain = ConfigKey.Domain("desu.me", "desu.win") override val configKeyDomain = ConfigKey.Domain("desu.me", "desu.win")
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.NEWEST, SortOrder.NEWEST,
@ -148,7 +148,7 @@ internal class DesuMeParser(context: MangaLoaderContext) : PagedMangaParser(cont
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
return tagsCache.get().values.toSet() return tagsCache.get().values.toSet()
} }

@ -30,7 +30,7 @@ internal class NudeMoonParser(
} }
} }
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.NEWEST, SortOrder.NEWEST,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.RATING, SortOrder.RATING,
@ -144,7 +144,7 @@ internal class NudeMoonParser(
return page.url.toAbsoluteUrl("img.$domain") return page.url.toAbsoluteUrl("img.$domain")
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val domain = domain val domain = domain
val doc = webClient.httpGet("https://$domain/tags").parseHtml() val doc = webClient.httpGet("https://$domain/tags").parseHtml()
val root = doc.body().getElementsByAttributeValue("name", "multitags").first() val root = doc.body().getElementsByAttributeValue("name", "multitags").first()

@ -47,7 +47,7 @@ internal class RemangaParser(
override val authUrl: String override val authUrl: String
get() = "https://${domain}/user/login" get() = "https://${domain}/user/login"
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.RATING, SortOrder.RATING,
@ -221,7 +221,7 @@ internal class RemangaParser(
return result return result
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val domain = domain val domain = domain
val content = webClient.httpGet("https://api.$domain/api/forms/titles/?get=genres") val content = webClient.httpGet("https://api.$domain/api/forms/titles/?get=genres")
.parseJson().getJSONObject("content").getJSONArray("genres") .parseJson().getJSONObject("content").getJSONArray("genres")

@ -46,7 +46,7 @@ internal abstract class GroupleParser(
override val headers: Headers = Headers.Builder().add("User-Agent", config[userAgentKey]).build() override val headers: Headers = Headers.Builder().add("User-Agent", config[userAgentKey]).build()
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.NEWEST, SortOrder.NEWEST,
@ -218,7 +218,7 @@ internal abstract class GroupleParser(
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://${domain}/list/genres/sort_name").parseHtml() val doc = webClient.httpGet("https://${domain}/list/genres/sort_name").parseHtml()
val root = doc.body().getElementById("mangaBox")?.selectFirst("div.leftContent")?.selectFirst("table.table") val root = doc.body().getElementById("mangaBox")?.selectFirst("div.leftContent")?.selectFirst("table.table")
?: doc.parseFailed("Cannot find root") ?: doc.parseFailed("Cannot find root")

@ -15,7 +15,7 @@ internal abstract class ChanParser(
source: MangaSource, source: MangaSource,
) : MangaParser(context, source), MangaParserAuthProvider { ) : MangaParser(context, source), MangaParserAuthProvider {
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.NEWEST, SortOrder.NEWEST,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
@ -126,7 +126,7 @@ internal abstract class ChanParser(
doc.parseFailed("Pages list not found at ${chapter.url}") doc.parseFailed("Pages list not found at ${chapter.url}")
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val domain = domain val domain = domain
val doc = webClient.httpGet("https://$domain/mostfavorites&sort=manga").parseHtml() val doc = webClient.httpGet("https://$domain/mostfavorites&sort=manga").parseHtml()
val root = doc.body().selectFirst("div.main_fon")?.getElementById("side") val root = doc.body().selectFirst("div.main_fon")?.getElementById("side")

@ -21,7 +21,7 @@ internal class HenChanParser(context: MangaLoaderContext) : ChanParser(context,
"hentaichan.pro", "hentaichan.pro",
) )
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.NEWEST, SortOrder.NEWEST,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.RATING, SortOrder.RATING,

@ -17,7 +17,7 @@ internal class YaoiChanParser(context: MangaLoaderContext) : ChanParser(context,
"yaoi-chan.me", "yaoi-chan.me",
) )
override val sortOrders: Set<SortOrder> = setOf(SortOrder.NEWEST) override val availableSortOrders: Set<SortOrder> = setOf(SortOrder.NEWEST)
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()

@ -32,7 +32,7 @@ internal open class MangaLibParser(
override val authUrl: String override val authUrl: String
get() = "https://$domain/login" get() = "https://$domain/login"
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.RATING, SortOrder.RATING,
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
SortOrder.POPULARITY, SortOrder.POPULARITY,
@ -232,7 +232,7 @@ internal open class MangaLibParser(
} ?: concatUrl(defaultServer, pageUrl) } ?: concatUrl(defaultServer, pageUrl)
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val url = "https://$domain/manga-list" val url = "https://$domain/manga-list"
val doc = webClient.httpGet(url).parseHtml() val doc = webClient.httpGet(url).parseHtml()
val scripts = doc.body().select("script") val scripts = doc.body().select("script")

@ -18,7 +18,7 @@ internal abstract class SinmhParser(
override val configKeyDomain = ConfigKey.Domain(domain) override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.POPULARITY, SortOrder.POPULARITY,
) )
@ -101,7 +101,7 @@ internal abstract class SinmhParser(
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml() val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml()
return doc.select(".filter-item:contains(按剧情) li a:not(.active)").mapNotNullToSet { a -> return doc.select(".filter-item:contains(按剧情) li a:not(.active)").mapNotNullToSet { a ->
val href = a.attr("href").removeSuffix('/').substringAfterLast('/') val href = a.attr("href").removeSuffix('/').substringAfterLast('/')

@ -15,7 +15,7 @@ import java.util.*
@MangaSourceParser("MANGAAY", "MangaAy", "tr") @MangaSourceParser("MANGAAY", "MangaAy", "tr")
class MangaAy(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.MANGAAY, 45) { class MangaAy(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.MANGAAY, 45) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain("manga-ay.com") override val configKeyDomain = ConfigKey.Domain("manga-ay.com")
@ -93,7 +93,7 @@ class MangaAy(context: MangaLoaderContext) : PagedMangaParser(context, MangaSour
private var tagCache: ArrayMap<String, MangaTag>? = null private var tagCache: ArrayMap<String, MangaTag>? = null
private val mutex = Mutex() private val mutex = Mutex()
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
return getOrCreateTagMap().values.toSet() return getOrCreateTagMap().values.toSet()
} }

@ -12,7 +12,7 @@ import java.util.*
@MangaSourceParser("SADSCANS", "SadScans", "tr") @MangaSourceParser("SADSCANS", "SadScans", "tr")
internal class SadScans(context: MangaLoaderContext) : MangaParser(context, MangaSource.SADSCANS) { internal class SadScans(context: MangaLoaderContext) : MangaParser(context, MangaSource.SADSCANS) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.ALPHABETICAL)
override val configKeyDomain = ConfigKey.Domain("sadscans.com") override val configKeyDomain = ConfigKey.Domain("sadscans.com")
override suspend fun getList(offset: Int, query: String?, tags: Set<MangaTag>?, sortOrder: SortOrder): List<Manga> { override suspend fun getList(offset: Int, query: String?, tags: Set<MangaTag>?, sortOrder: SortOrder): List<Manga> {
@ -46,7 +46,7 @@ internal class SadScans(context: MangaLoaderContext) : MangaParser(context, Mang
} }
} }
override suspend fun getTags(): Set<MangaTag> = emptySet() 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()

@ -16,7 +16,7 @@ class TrWebtoon(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("trwebtoon.com") override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("trwebtoon.com")
override val sortOrders: Set<SortOrder> override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.POPULARITY, SortOrder.ALPHABETICAL, SortOrder.UPDATED) get() = EnumSet.of(SortOrder.POPULARITY, SortOrder.ALPHABETICAL, SortOrder.UPDATED)
override suspend fun getListPage( override suspend fun getListPage(
@ -112,7 +112,7 @@ class TrWebtoon(context: MangaLoaderContext) :
return mangas return mangas
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val tags = val tags =
webClient.httpGet("https://$domain/webtoon-listesi").parseHtml().requireElementById("collapseExample") webClient.httpGet("https://$domain/webtoon-listesi").parseHtml().requireElementById("collapseExample")
.select(".pt-12 a").drop(1) .select(".pt-12 a").drop(1)

@ -12,7 +12,7 @@ import java.util.*
@MangaSourceParser("YAOIFLIX", "YaoiFlix", "tr", ContentType.HENTAI) @MangaSourceParser("YAOIFLIX", "YaoiFlix", "tr", ContentType.HENTAI)
class YaoiFlix(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.YAOIFLIX, 8) { class YaoiFlix(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.YAOIFLIX, 8) {
override val sortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = EnumSet.of(SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain("www.yaoiflix.pro") override val configKeyDomain = ConfigKey.Domain("www.yaoiflix.pro")
@ -79,7 +79,7 @@ class YaoiFlix(context: MangaLoaderContext) : PagedMangaParser(context, MangaSou
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain").parseHtml() val doc = webClient.httpGet("https://$domain").parseHtml()
return doc.select(".tags .cat-item a").mapNotNullToSet { a -> return doc.select(".tags .cat-item a").mapNotNullToSet { a ->
MangaTag( MangaTag(

@ -33,7 +33,7 @@ class HentaiUkrParser(context: MangaLoaderContext) : MangaParser(context, MangaS
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("hentaiukr.com") override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("hentaiukr.com")
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.NEWEST, SortOrder.NEWEST,
) )
@ -119,7 +119,7 @@ class HentaiUkrParser(context: MangaLoaderContext) : MangaParser(context, MangaS
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
return allManga.get().flatMapTo(HashSet()) { x -> return allManga.get().flatMapTo(HashSet()) { x ->
x.getJSONArray("tags").mapJSON { t -> x.getJSONArray("tags").mapJSON { t ->
MangaTag( MangaTag(

@ -37,7 +37,7 @@ class HoneyMangaParser(context: MangaLoaderContext) : PagedMangaParser(context,
override val configKeyDomain = ConfigKey.Domain("honey-manga.com.ua") override val configKeyDomain = ConfigKey.Domain("honey-manga.com.ua")
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.NEWEST, SortOrder.NEWEST,
) )
@ -167,7 +167,7 @@ class HoneyMangaParser(context: MangaLoaderContext) : PagedMangaParser(context,
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
// https://data.api.honey-manga.com.ua/genres-tags/genres-list // https://data.api.honey-manga.com.ua/genres-tags/genres-list
val content = webClient.httpGet(genresListApi).parseJsonArray() val content = webClient.httpGet(genresListApi).parseJsonArray()
val tagsSet = ArraySet<MangaTag>(content.length()) val tagsSet = ArraySet<MangaTag>(content.length())

@ -19,7 +19,7 @@ class MangaInUaParser(context: MangaLoaderContext) : PagedMangaParser(
searchPageSize = 10, searchPageSize = 10,
) { ) {
override val sortOrders: Set<SortOrder> = setOf(SortOrder.UPDATED) override val availableSortOrders: Set<SortOrder> = setOf(SortOrder.UPDATED)
override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("manga.in.ua") override val configKeyDomain: ConfigKey.Domain = ConfigKey.Domain("manga.in.ua")
@ -151,7 +151,7 @@ class MangaInUaParser(context: MangaLoaderContext) : PagedMangaParser(
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val domain = domain val domain = domain
val doc = webClient.httpGet("https://$domain/mangas").parseHtml() val doc = webClient.httpGet("https://$domain/mangas").parseHtml()
val root = doc.body().requireElementById("menu_1").selectFirstOrThrow("div.menu__wrapper") val root = doc.body().requireElementById("menu_1").selectFirstOrThrow("div.menu__wrapper")

@ -22,7 +22,7 @@ class BlogTruyenParser(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("blogtruyenmoi.com") get() = ConfigKey.Domain("blogtruyenmoi.com")
override val sortOrders: Set<SortOrder> override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.UPDATED) get() = EnumSet.of(SortOrder.UPDATED)
override val headers: Headers = Headers.Builder() override val headers: Headers = Headers.Builder()
@ -219,7 +219,7 @@ class BlogTruyenParser(context: MangaLoaderContext) :
return pages return pages
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
return cacheTags.get().values.toSet() return cacheTags.get().values.toSet()
} }

@ -28,7 +28,7 @@ class HentaiVNParser(context: MangaLoaderContext) : MangaParser(context, MangaSo
// hentaivn has created 2 different interfaces for mobile and desktop, and Cloudflare detects whether it's mobile or not even with a desktop user agent. // hentaivn has created 2 different interfaces for mobile and desktop, and Cloudflare detects whether it's mobile or not even with a desktop user agent.
override val headers: Headers = Headers.Builder().add("User-Agent", UserAgents.CHROME_MOBILE).build() override val headers: Headers = Headers.Builder().add("User-Agent", UserAgents.CHROME_MOBILE).build()
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.RATING, SortOrder.RATING,
@ -137,7 +137,7 @@ class HentaiVNParser(context: MangaLoaderContext) : MangaParser(context, MangaSo
private var tagCache: ArrayMap<String, MangaTag>? = null private var tagCache: ArrayMap<String, MangaTag>? = null
private val mutex = Mutex() private val mutex = Mutex()
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
return getOrCreateTagMap().values.toSet() return getOrCreateTagMap().values.toSet()
} }

@ -14,7 +14,7 @@ import java.util.*
@MangaSourceParser("LXMANGA", "LxManga", "vi") @MangaSourceParser("LXMANGA", "LxManga", "vi")
internal class LxManga(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.LXMANGA, 60) { internal class LxManga(context: MangaLoaderContext) : PagedMangaParser(context, MangaSource.LXMANGA, 60) {
override val sortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.ALPHABETICAL, SortOrder.ALPHABETICAL,
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.NEWEST, SortOrder.NEWEST,
@ -150,7 +150,7 @@ internal class LxManga(context: MangaLoaderContext) : PagedMangaParser(context,
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/").parseHtml() val doc = webClient.httpGet("https://$domain/").parseHtml()
val body = doc.body() val body = doc.body()
return body.select("ul.absolute.w-full a").mapToSet { a -> return body.select("ul.absolute.w-full a").mapToSet { a ->

@ -26,7 +26,7 @@ class NetTruyenParser(context: MangaLoaderContext) :
"nettruyenin.com", "nettruyenin.com",
) )
override val sortOrders: Set<SortOrder> override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.RATING) get() = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.RATING)
private val mutex = Mutex() private val mutex = Mutex()
@ -194,7 +194,7 @@ class NetTruyenParser(context: MangaLoaderContext) :
} }
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getAvailableTags(): Set<MangaTag> {
val map = getOrCreateTagMap() val map = getOrCreateTagMap()
val tagSet = ArraySet<MangaTag>(map.size) val tagSet = ArraySet<MangaTag>(map.size)
for (entry in map) { for (entry in map) {

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

Loading…
Cancel
Save