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.
*/
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) }
@ -49,7 +69,7 @@ abstract class MangaParser @InternalParsersApi constructor(
*/
protected open val defaultSortOrder: SortOrder
get() {
val supported = sortOrders
val supported = availableSortOrders
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.
* 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 tags genres for filtering, values from [getTags] and [Manga.tags]. May be null or empty
* @param sortOrder one of [sortOrders] or null for default value
* @param tags genres for filtering, values from [getAvailableTags] and [Manga.tags]. May be null or empty
* @param sortOrder one of [availableSortOrders] or null for default value
*/
@JvmSynthetic
@InternalParsersApi
@Deprecated(
"Use getList with filter instead",
replaceWith = ReplaceWith("getList(offset, filter)"),
)
abstract suspend fun getList(
offset: Int,
query: String?,
@ -80,8 +104,15 @@ abstract class MangaParser @InternalParsersApi constructor(
* @param offset starting from 0 and used for pagination.
* @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> {
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.
* 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 sortOrder one of [sortOrders] or null for default value
* @param tags genres for filtering, values from [getAvailableTags] and [Manga.tags]. May be null or empty
* @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> {
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
*/
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

@ -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
enum class MangaState {
ONGOING, FINISHED, ABANDONED
ONGOING, FINISHED, ABANDONED, PAUSED
}

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

@ -25,7 +25,7 @@ internal class ComickFunParser(context: MangaLoaderContext) : MangaParser(contex
override val configKeyDomain = ConfigKey.Domain("comick.app")
override val sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY,
SortOrder.UPDATED,
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 set = ArraySet<MangaTag>(sparseArray.size())
for (i in 0 until sparseArray.size()) {

@ -23,7 +23,7 @@ internal class ExHentaiParser(
context: MangaLoaderContext,
) : PagedMangaParser(context, MangaSource.EXHENTAI, pageSize = 25), MangaParserAuthProvider {
override val sortOrders: Set<SortOrder> = Collections.singleton(
override val availableSortOrders: Set<SortOrder> = Collections.singleton(
SortOrder.NEWEST,
)
@ -213,7 +213,7 @@ internal class ExHentaiParser(
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 root = doc.body().requireElementById("searchbox").selectFirstOrThrow("table")
return root.select("div.cs").mapNotNullToSet { div ->

@ -17,11 +17,13 @@ import java.util.*
internal class ImHentai(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.IMHENTAI, pageSize = 20) {
override val sortOrders: Set<SortOrder> =
override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.RATING)
override val configKeyDomain = ConfigKey.Domain("imhentai.xxx")
override val isMultipleTagsSupported = false
override suspend fun getListPage(
page: Int,
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.
//only the most popular ones are taken.
override suspend fun getTags(): Set<MangaTag> {
override suspend fun getAvailableTags(): Set<MangaTag> {
return coroutineScope {
(1..3).map { page ->
async { getTags(page) }

@ -24,6 +24,8 @@ internal abstract class LineWebtoonsParser(
source: MangaSource,
) : MangaParser(context, source) {
override val isMultipleTagsSupported = false
private val signer by lazy {
WebtoonsUrlSigner("gUtPzJFZch4ZyAGviiyH94P99lQ3pFdRTwpJWDlSGFfwgpr6ses5ALOxWHOIT7R1")
}
@ -39,7 +41,7 @@ internal abstract class LineWebtoonsParser(
private val apiDomain = "global.apis.naver.com"
private val staticDomain = "webtoon-phinf.pstatic.net"
override val sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY,
// doesn't actually sort by rating, but by likes
// 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")
.getJSONObject("genreList")
.getJSONArray("challengeGenres")

@ -30,7 +30,7 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context
override val configKeyDomain = ConfigKey.Domain("mangadex.org")
override val sortOrders: EnumSet<SortOrder> = EnumSet.of(
override val availableSortOrders: EnumSet<SortOrder> = EnumSet.of(
SortOrder.UPDATED,
SortOrder.ALPHABETICAL,
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()
.getJSONArray("data")
return tags.mapJSONToSet { jo ->

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

@ -22,7 +22,9 @@ internal abstract class AnimeBootstrapParser(
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.POPULARITY,
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()
return doc.select("div.product__page__filter div:contains(Genre:) option ").mapNotNullToSet { option ->
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 isMultipleTagsSupported = false
override val listUrl = "/liste-manga"
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 sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY,
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()
return doc.select("a.category ").mapNotNullToSet { a ->
val key = a.attr("href").substringAfterLast('=')

@ -18,7 +18,7 @@ import java.util.*
@MangaSourceParser("FLIXSCANS", "FlixScans", "ar")
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 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 json = JSONArray(doc.requireElementById("__NUXT_DATA__").data())
val tagsList = json.getJSONArray(3).toString().replace("[", "").replace("]", "").split(",")

@ -13,8 +13,9 @@ import java.util.*
@MangaSourceParser("MANGASTORM", "MangaStorm", "ar")
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 isMultipleTagsSupported = false
override val headers: Headers = Headers.Builder()
.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 {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()

@ -16,8 +16,9 @@ import java.util.*
@MangaSourceParser("TEAMXNOVEL", "TeamXNovel", "ar")
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 isMultipleTagsSupported = false
override suspend fun getListPage(
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()
return doc.requireElementById("select_genre").select("option").mapNotNullToSet {
MangaTag(

@ -23,7 +23,7 @@ internal class AnibelParser(context: MangaLoaderContext) : MangaParser(context,
override val configKeyDomain = ConfigKey.Domain("anibel.net")
override val sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
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(
"""
getFilters(mediaType: manga) {

@ -13,10 +13,12 @@ import java.util.*
internal class BeeToon(context: MangaLoaderContext) :
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 isMultipleTagsSupported = false
override suspend fun getListPage(
page: Int,
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()
return doc.requireElementById("menu-item-3").select("ul.sub-menu li a").mapNotNullToSet {
MangaTag(

@ -12,7 +12,7 @@ import java.util.*
@MangaSourceParser("CLONEMANGA", "CloneManga", "en")
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,
)
@ -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")
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 isMultipleTagsSupported = false
override val headers: Headers = Headers.Builder()
.add("User-Agent", UserAgents.CHROME_DESKTOP)
.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()
return doc.select("li.tag-item a").mapNotNullToSet { a ->
MangaTag(

@ -15,7 +15,7 @@ import java.util.*
@MangaSourceParser("DYNASTYSCANS", "DynastyScans", "en")
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 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 {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()

@ -15,11 +15,13 @@ import java.util.*
internal class Fakku(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.FAKKU, pageSize = 25) {
override val sortOrders: Set<SortOrder> =
override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.ALPHABETICAL, SortOrder.NEWEST, SortOrder.UPDATED)
override val configKeyDomain = ConfigKey.Domain("fakku.cc")
override val isMultipleTagsSupported = false
override suspend fun getListPage(
page: Int,
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()
return root.select("div.entries .entry a").mapToSet {
MangaTag(

@ -20,9 +20,10 @@ import java.util.*
@MangaSourceParser("KSKMOE", "Ksk.moe", "en", ContentType.HENTAI)
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)
override val configKeyDomain = ConfigKey.Domain("ksk.moe")
override val isMultipleTagsSupported = false
override suspend fun getListPage(
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 {
(1..2).map { page ->
async { getTags(page) }

@ -14,10 +14,13 @@ import java.util.*
@MangaSourceParser("MANGAGEKO", "MangaGeko", "en")
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 isMultipleTagsSupported = false
override val headers: Headers = Headers.Builder()
.add("User-Agent", UserAgents.CHROME_DESKTOP)
.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()
return doc.select("label.checkbox-inline").mapNotNullToSet { label ->
MangaTag(

@ -15,7 +15,7 @@ internal class MangaTownParser(context: MangaLoaderContext) : MangaParser(contex
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.RATING,
SortOrder.POPULARITY,
@ -157,7 +157,7 @@ internal class MangaTownParser(context: MangaLoaderContext) : MangaParser(contex
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 root = doc.body().selectFirst("aside.right")
?.getElementsContainingOwnText("Genres")

@ -18,7 +18,7 @@ import java.util.*
internal class Mangaowl(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.MANGAOWL, pageSize = 24) {
override val sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY,
SortOrder.NEWEST,
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()
return doc.select("div.genres-container span.genre-item a").mapNotNullToSet { a ->
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 sortOrders: Set<SortOrder>
override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.ALPHABETICAL, SortOrder.NEWEST)
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()
}

@ -16,7 +16,9 @@ class ManhwasMen(context: MangaLoaderContext) :
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)
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()
.selectLastOrThrow(".filter-bx .form-group select.custom-select").select("option").drop(1)
return tags.mapNotNullToSet { option ->

@ -12,7 +12,7 @@ import java.util.*
@MangaSourceParser("PO2SCANS", "Po2Scans", "en")
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 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 {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()

@ -17,11 +17,13 @@ import java.util.*
internal class Pururin(context: MangaLoaderContext) :
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)
override val configKeyDomain = ConfigKey.Domain("pururin.to")
override val isMultipleTagsSupported = false
override suspend fun getListPage(
page: Int,
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 {
(1..4).map { page ->
async { getTags(page) }

@ -16,7 +16,7 @@ import java.util.*
internal class TempleScanEsp(context: MangaLoaderContext) :
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")
@ -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 {
val fullUrl = manga.url.toAbsoluteUrl(domain)

@ -24,7 +24,7 @@ class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaParser(
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.UPDATED,
SortOrder.NEWEST,
@ -207,7 +207,7 @@ class TuMangaOnlineParser(context: MangaLoaderContext) : PagedMangaParser(
return document
}
override suspend fun getTags(): Set<MangaTag> {
override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/library", headers).parseHtml()
val elements = doc.body().select("div#books-genders > div > div")
return elements.mapNotNullToSet { element ->

@ -21,12 +21,14 @@ internal abstract class FmreaderParser(
override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED,
SortOrder.POPULARITY,
SortOrder.ALPHABETICAL,
)
override val isMultipleTagsSupported = false
protected open val listUrl = "/manga-list.html"
protected open val datePattern = "MMMM d, yyyy"
protected open val tagPrefix = "manga-list-genre-"
@ -113,7 +115,7 @@ internal abstract class FmreaderParser(
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()
return doc.select(selectBodyTag).mapNotNullToSet { a ->
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()
return doc.select(selectBodyTag).mapNotNullToSet { a ->
val href = a.attr("href").substringAfterLast("/")

@ -20,7 +20,7 @@ internal abstract class FoolSlideParser(
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 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"

@ -18,7 +18,7 @@ import java.util.*
@MangaSourceParser("BENTOMANGA", "BentoManga", "fr")
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.POPULARITY,
SortOrder.RATING,
@ -99,11 +99,14 @@ internal class BentomangaParser(context: MangaLoaderContext) : PagedMangaParser(
val root = webClient.httpGet(mangaUrl).parseHtml()
.requireElementById("container_manga_show")
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")
?: manga.description,
state = when (root.selectFirst(".datas_more-status-data")?.textOrNull().assertNotNull("status")) {
"En cours" -> MangaState.ONGOING
"Terminé" -> MangaState.FINISHED
"Abandonné" -> MangaState.ABANDONED
"En pause" -> MangaState.PAUSED
else -> null
},
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())
.parseHtml()
.requireElementById("search_options-form")

@ -17,7 +17,7 @@ import java.util.*
internal class FmTeam(context: MangaLoaderContext) :
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 suspend fun getListPage(
@ -29,11 +29,9 @@ internal class FmTeam(context: MangaLoaderContext) :
if (page > 1) {
return emptyList()
}
val jsonManga = if (!query.isNullOrEmpty()) {
//3 letters minimum
webClient.httpGet("https://$domain/api/search/${query.urlEncoded()}").parseJson().getJSONArray("comics")
} else {
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 {
val fullUrl = manga.url.toAbsoluteUrl(domain)

@ -18,7 +18,7 @@ import java.util.*
internal class FuryoSociety(context: MangaLoaderContext) :
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")
@ -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 {

@ -16,7 +16,7 @@ import java.util.*
internal class LegacyScansParser(context: MangaLoaderContext) :
PagedMangaParser(context, MangaSource.LEGACY_SCANS, 18) {
override val sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
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 script = doc.requireElementById("__NUXT_DATA__").data()
.substringAfterLast("\"genres\"").substringBeforeLast("\"comics\"")

@ -14,10 +14,12 @@ import java.util.*
@MangaSourceParser("LIRESCAN", "LireScan", "fr")
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 isMultipleTagsSupported = false
override val headers: Headers = Headers.Builder()
.add("User-Agent", UserAgents.CHROME_MOBILE)
.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()
return doc.select(".nav-menu li a").mapNotNullToSet { a ->
val key = a.attr("href").removeSuffix('/').substringAfterLast("manga/", "")

@ -16,7 +16,7 @@ import java.util.*
@MangaSourceParser("LUGNICASCANS", "LugnicaScans", "fr")
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.UPDATED,
)
@ -176,6 +176,6 @@ internal class LugnicaScans(context: MangaLoaderContext) : PagedMangaParser(cont
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) :
PagedMangaParser(context, MangaSource.SCANS_MANGAS_ME, 0) {
override val sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.ALPHABETICAL,
SortOrder.UPDATED,
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()
return doc.select("ul.genre li").mapNotNullToSet { li ->
val key = li.selectFirstOrThrow("a").attr("href").removeSuffix('/').substringAfterLast('/')

@ -15,7 +15,7 @@ import java.util.*
@MangaSourceParser("SCANTRADUNION", "ScantradUnion", "fr")
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.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 body = doc.body()
val root = body.select(".asp_gochosen")[1]

@ -20,8 +20,9 @@ internal abstract class GalleryAdultsParser(
pageSize: Int = 20,
) : 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 isMultipleTagsSupported = false
override suspend fun getListPage(
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.
//only the most popular ones are taken.
override suspend fun getTags(): Set<MangaTag> {
override suspend fun getAvailableTags(): Set<MangaTag> {
return coroutineScope {
(1..3).map { page ->
async { getTags(page) }

@ -20,7 +20,7 @@ internal abstract class HeanCms(
override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.ALPHABETICAL,
SortOrder.UPDATED,
SortOrder.NEWEST,
@ -100,6 +100,7 @@ internal abstract class HeanCms(
"Ongoing" -> MangaState.ONGOING
"Completed" -> MangaState.FINISHED
"Dropped" -> MangaState.ABANDONED
"Hiatus" -> MangaState.PAUSED
else -> 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 tags = doc.selectFirstOrThrow("script:containsData(Genres)").data()

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

@ -20,7 +20,7 @@ internal abstract class HeanCmsAlt(
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 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 selectAlt = "div.series-alternative-names"

@ -15,7 +15,7 @@ class DoujinDesuParser(context: MangaLoaderContext) : PagedMangaParser(context,
override val configKeyDomain: ConfigKey.Domain
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)
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()
.requireElementById("taxonomy")
.selectFirstOrThrow(".entries")

@ -34,7 +34,7 @@ class NicovideoSeigaParser(context: MangaLoaderContext) :
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.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 root = doc.body().selectOrThrow("#mg_category_list > ul > li")
return root.mapToSet { li ->

@ -21,8 +21,10 @@ internal abstract class LikeMangaParser(
pageSize: Int = 36,
) : 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 isMultipleTagsSupported = false
override suspend fun getListPage(
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()
return doc.select("ul.nav-genres li:not(.text-center) a").mapNotNullToSet { a ->
MangaTag(

@ -23,7 +23,9 @@ internal abstract class MadaraParser(
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.POPULARITY,
SortOrder.NEWEST,
@ -137,6 +139,16 @@ internal abstract class MadaraParser(
"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
protected open val withoutAjax = false
@ -232,11 +244,11 @@ internal abstract class MadaraParser(
)
}.orEmpty(),
author = summary?.selectFirst(".mg_author")?.selectFirst("a")?.ownText(),
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText()
?.lowercase()) {
state = when (summary?.selectFirst(".mg_status")?.selectFirst(".summary-content")?.ownText()) {
in ongoing -> MangaState.ONGOING
in finished -> MangaState.FINISHED
in abandoned -> MangaState.ABANDONED
in paused -> MangaState.PAUSED
else -> null
},
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 body = doc.body()
val root1 = body.selectFirst("header")?.selectFirst("ul.second-menu")
@ -314,6 +326,7 @@ internal abstract class MadaraParser(
in ongoing -> MangaState.ONGOING
in finished -> MangaState.FINISHED
in abandoned -> MangaState.ABANDONED
in paused -> MangaState.PAUSED
else -> null
}
}

@ -5,9 +5,7 @@ import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.model.*
import org.koitharu.kotatsu.parsers.site.madara.MadaraParser
import org.koitharu.kotatsu.parsers.util.*
import java.util.EnumSet
import java.util.HashSet
import java.util.Locale
import java.util.*
@MangaSourceParser("MANGA18FX", "Manga18Fx", "", ContentType.HENTAI)
internal class Manga18Fx(context: MangaLoaderContext) :
@ -15,7 +13,7 @@ internal class Manga18Fx(context: MangaLoaderContext) :
override val sourceLocale: Locale = Locale.ENGLISH
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 selectTestAsync = "ul.row-content-chapter"
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 list = doc.body().selectFirstOrThrow("div.genre-menu").select("ul li").orEmpty()
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 list = doc.body().selectFirstOrThrow("div.sub-menu").select("ul li").orEmpty()
val keySet = HashSet<String>(list.size)

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

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

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

@ -14,7 +14,7 @@ import java.util.*
internal class DragonTranslationParser(context: MangaLoaderContext) :
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"

@ -22,7 +22,7 @@ internal class TmoManga(context: MangaLoaderContext) :
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(
page: Int,
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()
return doc.select("div.genres li").mapNotNullToSet { li ->
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")
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"
}

@ -21,7 +21,7 @@ internal abstract class MadthemeParser(
override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED,
SortOrder.POPULARITY,
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()
return doc.select("div.genres label.checkbox").mapNotNullToSet { checkbox ->
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 sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED,
SortOrder.POPULARITY,
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()
return doc.select("div.grid_cate li").mapNotNullToSet { li ->
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,
) : PagedMangaParser(context, source, pageSize) {
override val sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED,
SortOrder.POPULARITY,
SortOrder.NEWEST,
@ -107,7 +107,7 @@ internal abstract class MangaboxParser(
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()
return doc.select(selectTagMap).mapNotNullToSet { a ->
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()
return doc.select("div.panel_category a:not(.ctg_select)").mapNotNullToSet { a ->
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 suspend fun getTags(): Set<MangaTag> {
override suspend fun getAvailableTags(): Set<MangaTag> {
val doc = webClient.httpGet("https://$domain/$listUrl").parseHtml()
return doc.select(selectTagMap).mapNotNullToSet { a ->
MangaTag(

@ -29,7 +29,7 @@ internal abstract class MangaReaderParser(
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)
protected open val listUrl = "/manga"
@ -181,20 +181,24 @@ internal abstract class MangaReaderParser(
val mangaState = state?.let {
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",
"Онгоінг", "Publishing", "Devam Ediyor", "Em Andamento", "In Corso", "Güncel", "Berjalan", "Продолжается", "Updating",
"Lançando", "In Arrivo", "Emision", "En emision", "مستمر", "Curso", "En marcha", "Publicandose", "Publicando", "连载中",
"Devam ediyor", "Devam Etmekte",
"مستمرة", "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", "Онгоінг", "Publishing",
"Devam Ediyor", "Em Andamento", "In Corso", "Güncel", "Berjalan", "Продолжается", "Updating", "Lançando", "In Arrivo", "Emision",
"En emision", "مستمر", "Curso", "En marcha", "Publicandose", "Publicando", "连载中", "Devam ediyor", "Devam Etmekte",
-> MangaState.ONGOING
"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ş",
"Completed", "Completo", "Complété", "Fini", "Achevé", "Terminé", "Terminé ⚫", "Tamamlandı", "Đã hoàn thành", "Hoàn Thành",
"مكتملة", "Завершено", "Finished", "Finalizado", "Completata", "One-Shot", "Bitti", "Tamat", "Completado", "Concluído",
"Concluido", "已完结", "Bitmiş",
-> MangaState.FINISHED
"Canceled", "Cancelled", "Cancelado", "cancellato", "Cancelados", "Dropped", "Discontinued", "abandonné", "Abandonné",
-> MangaState.ABANDONED
"Hiatus", "On Hold", "Pausado", "En espera", "En pause", "En Pause", "En attente",
-> MangaState.PAUSED
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()
}

@ -75,7 +75,7 @@ internal class ManhwaFreak(context: MangaLoaderContext) :
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()
return doc.select("ul.genre-list li a").mapNotNullToSet { a ->
val href = a.attr("href").substringAfterLast("=")

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

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

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

@ -77,7 +77,7 @@ internal class ManhwaFreakFr(context: MangaLoaderContext) :
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()
return doc.select("ul.genre-list li a").mapNotNullToSet { a ->
val href = a.attr("href").substringAfterLast("=")

@ -18,7 +18,7 @@ internal class Komikcast(context: MangaLoaderContext) :
override val listUrl = "/daftar-komik"
override val datePattern = "MMM d, yyyy"
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)
override suspend fun getListPage(

@ -20,7 +20,7 @@ internal abstract class MmrcmsParser(
override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.POPULARITY,
SortOrder.UPDATED,
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()
return doc.select("ul.list-category li").mapNotNullToSet { li ->
val a = li.selectFirst("a") ?: return@mapNotNullToSet null

@ -23,7 +23,7 @@ internal abstract class NepnepParser(
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()
.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 tags = doc.selectFirstOrThrow("script:containsData(vm.AvailableFilters)").data()
.substringAfter("\"Genre\"")
@ -138,12 +138,18 @@ internal abstract class NepnepParser(
return manga.copy(
altTitle = null,
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)",
-> MangaState.FINISHED
"Cancelled (Scan)", "Cancelled (Publish)",
"Discontinued (Scan)", "Discontinued (Publish)",
-> MangaState.ABANDONED
"Hiatus (Scan)", "Hiatus (Publish)",
-> MangaState.FINISHED
-> MangaState.PAUSED
else -> null
},

@ -20,7 +20,7 @@ internal abstract class OtakuSanctuaryParser(
override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED,
SortOrder.NEWEST,
)
@ -114,7 +114,7 @@ internal abstract class OtakuSanctuaryParser(
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()
return doc.select(selectBodyTag).mapNotNullToSet { a ->
val href = a.attr("href").substringAfterLast("/").substringBefore("?")

@ -13,7 +13,7 @@ import java.util.*
@MangaSourceParser("BAKAI", "Bakai", "pt", ContentType.HENTAI)
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 headers: Headers = Headers.Builder()
.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()
return doc.requireElementById("elNavigation_17_menu").select("li.ipsMenu_item a").mapNotNullToSet { a ->

@ -13,7 +13,7 @@ import java.util.*
@MangaSourceParser("BRMANGAS", "BrMangas", "pt")
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")
@ -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()
return doc.select(".genres_page a").mapNotNullToSet { a ->
MangaTag(

@ -14,7 +14,7 @@ import java.util.*
@MangaSourceParser("LERMANGAONLINE", "LerMangaOnline", "pt")
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")
@ -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")
return doc.select("ul.container li a").mapNotNullToSet { a ->
MangaTag(

@ -12,7 +12,7 @@ import java.util.*
@MangaSourceParser("MANGAONLINE", "MangaOnline.biz", "pt")
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")
@ -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()
return doc.select(".wp-content p a").mapNotNullToSet { a ->
MangaTag(

@ -16,7 +16,7 @@ import java.util.*
@MangaSourceParser("YUGENMANGAS", "YugenMangas.net.br", "pt")
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 suspend fun getListPage(
@ -86,7 +86,7 @@ class YugenMangas(context: MangaLoaderContext) : PagedMangaParser(context, Manga
when (it) {
"ongoing" -> MangaState.ONGOING
"completed" -> MangaState.FINISHED
//"hiatus" -> MangaState.PAUSED
"hiatus" -> MangaState.PAUSED
else -> null
}
},
@ -145,5 +145,5 @@ class YugenMangas(context: MangaLoaderContext) : PagedMangaParser(context, Manga
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 sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED,
SortOrder.POPULARITY,
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()
}

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

@ -47,7 +47,7 @@ internal class RemangaParser(
override val authUrl: String
get() = "https://${domain}/user/login"
override val sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED,
SortOrder.POPULARITY,
SortOrder.RATING,
@ -221,7 +221,7 @@ internal class RemangaParser(
return result
}
override suspend fun getTags(): Set<MangaTag> {
override suspend fun getAvailableTags(): Set<MangaTag> {
val domain = domain
val content = webClient.httpGet("https://api.$domain/api/forms/titles/?get=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 sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED,
SortOrder.POPULARITY,
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 root = doc.body().getElementById("mangaBox")?.selectFirst("div.leftContent")?.selectFirst("table.table")
?: doc.parseFailed("Cannot find root")

@ -15,7 +15,7 @@ internal abstract class ChanParser(
source: MangaSource,
) : MangaParser(context, source), MangaParserAuthProvider {
override val sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.NEWEST,
SortOrder.POPULARITY,
SortOrder.ALPHABETICAL,
@ -126,7 +126,7 @@ internal abstract class ChanParser(
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 doc = webClient.httpGet("https://$domain/mostfavorites&sort=manga").parseHtml()
val root = doc.body().selectFirst("div.main_fon")?.getElementById("side")

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

@ -17,7 +17,7 @@ internal class YaoiChanParser(context: MangaLoaderContext) : ChanParser(context,
"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 {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()

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

@ -18,7 +18,7 @@ internal abstract class SinmhParser(
override val configKeyDomain = ConfigKey.Domain(domain)
override val sortOrders: Set<SortOrder> = EnumSet.of(
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.UPDATED,
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()
return doc.select(".filter-item:contains(按剧情) li a:not(.active)").mapNotNullToSet { a ->
val href = a.attr("href").removeSuffix('/').substringAfterLast('/')

@ -15,7 +15,7 @@ import java.util.*
@MangaSourceParser("MANGAAY", "MangaAy", "tr")
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")
@ -93,7 +93,7 @@ class MangaAy(context: MangaLoaderContext) : PagedMangaParser(context, MangaSour
private var tagCache: ArrayMap<String, MangaTag>? = null
private val mutex = Mutex()
override suspend fun getTags(): Set<MangaTag> {
override suspend fun getAvailableTags(): Set<MangaTag> {
return getOrCreateTagMap().values.toSet()
}

@ -12,7 +12,7 @@ import java.util.*
@MangaSourceParser("SADSCANS", "SadScans", "tr")
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 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 {
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 sortOrders: Set<SortOrder>
override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.POPULARITY, SortOrder.ALPHABETICAL, SortOrder.UPDATED)
override suspend fun getListPage(
@ -112,7 +112,7 @@ class TrWebtoon(context: MangaLoaderContext) :
return mangas
}
override suspend fun getTags(): Set<MangaTag> {
override suspend fun getAvailableTags(): Set<MangaTag> {
val tags =
webClient.httpGet("https://$domain/webtoon-listesi").parseHtml().requireElementById("collapseExample")
.select(".pt-12 a").drop(1)

@ -12,7 +12,7 @@ import java.util.*
@MangaSourceParser("YAOIFLIX", "YaoiFlix", "tr", ContentType.HENTAI)
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")
@ -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()
return doc.select(".tags .cat-item a").mapNotNullToSet { a ->
MangaTag(

@ -33,7 +33,7 @@ class HentaiUkrParser(context: MangaLoaderContext) : MangaParser(context, MangaS
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,
)
@ -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 ->
x.getJSONArray("tags").mapJSON { t ->
MangaTag(

@ -37,7 +37,7 @@ class HoneyMangaParser(context: MangaLoaderContext) : PagedMangaParser(context,
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.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
val content = webClient.httpGet(genresListApi).parseJsonArray()
val tagsSet = ArraySet<MangaTag>(content.length())

@ -19,7 +19,7 @@ class MangaInUaParser(context: MangaLoaderContext) : PagedMangaParser(
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")
@ -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 doc = webClient.httpGet("https://$domain/mangas").parseHtml()
val root = doc.body().requireElementById("menu_1").selectFirstOrThrow("div.menu__wrapper")

@ -22,7 +22,7 @@ class BlogTruyenParser(context: MangaLoaderContext) :
override val configKeyDomain: ConfigKey.Domain
get() = ConfigKey.Domain("blogtruyenmoi.com")
override val sortOrders: Set<SortOrder>
override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.UPDATED)
override val headers: Headers = Headers.Builder()
@ -219,7 +219,7 @@ class BlogTruyenParser(context: MangaLoaderContext) :
return pages
}
override suspend fun getTags(): Set<MangaTag> {
override suspend fun getAvailableTags(): Set<MangaTag> {
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.
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.POPULARITY,
SortOrder.RATING,
@ -137,7 +137,7 @@ class HentaiVNParser(context: MangaLoaderContext) : MangaParser(context, MangaSo
private var tagCache: ArrayMap<String, MangaTag>? = null
private val mutex = Mutex()
override suspend fun getTags(): Set<MangaTag> {
override suspend fun getAvailableTags(): Set<MangaTag> {
return getOrCreateTagMap().values.toSet()
}

@ -14,7 +14,7 @@ import java.util.*
@MangaSourceParser("LXMANGA", "LxManga", "vi")
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.UPDATED,
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 body = doc.body()
return body.select("ul.absolute.w-full a").mapToSet { a ->

@ -26,7 +26,7 @@ class NetTruyenParser(context: MangaLoaderContext) :
"nettruyenin.com",
)
override val sortOrders: Set<SortOrder>
override val availableSortOrders: Set<SortOrder>
get() = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.RATING)
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 tagSet = ArraySet<MangaTag>(map.size)
for (entry in map) {

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

Loading…
Cancel
Save