[mangaDex] Fix SortOrder and remove YearRange
[Bato] add OriginalLocale [MangaPark] add OriginalLocale, SearchWithFilters [Comick] add SearchWithFilters [NineMangaParser] add SearchWithFilters [AnimeBootstrap] add SearchWithFilters , ContentTypes [madara] add Year, SearchWithFilters, SortOrder.RELEVANCE [TeamXNovel] add ContentTypes , SearchWithFilters
This commit is contained in:
@@ -49,10 +49,10 @@ internal class BatoToParser(context: MangaLoaderContext) : PagedMangaParser(
|
||||
}
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> = EnumSet.of(
|
||||
SortOrder.NEWEST,
|
||||
SortOrder.UPDATED,
|
||||
SortOrder.POPULARITY,
|
||||
SortOrder.ALPHABETICAL,
|
||||
SortOrder.UPDATED,
|
||||
SortOrder.NEWEST,
|
||||
SortOrder.POPULARITY,
|
||||
SortOrder.POPULARITY_YEAR,
|
||||
SortOrder.POPULARITY_MONTH,
|
||||
SortOrder.POPULARITY_WEEK,
|
||||
@@ -65,6 +65,7 @@ internal class BatoToParser(context: MangaLoaderContext) : PagedMangaParser(
|
||||
isMultipleTagsSupported = true,
|
||||
isTagsExclusionSupported = true,
|
||||
isSearchSupported = true,
|
||||
isOriginalLocaleSupported = true,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
@@ -165,6 +166,15 @@ internal class BatoToParser(context: MangaLoaderContext) : PagedMangaParser(
|
||||
|
||||
}
|
||||
|
||||
filter.originalLocale?.let {
|
||||
append("&origs=")
|
||||
if (it.language == "in") {
|
||||
append("id")
|
||||
} else {
|
||||
append(it.language)
|
||||
}
|
||||
}
|
||||
|
||||
append("&genres=")
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
appendAll(filter.tags, ",") { it.key }
|
||||
|
||||
@@ -34,13 +34,12 @@ internal class ComickFunParser(context: MangaLoaderContext) :
|
||||
SortOrder.NEWEST,
|
||||
)
|
||||
|
||||
private val tagsArray = SuspendLazy(::loadTags)
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isMultipleTagsSupported = true,
|
||||
isTagsExclusionSupported = true,
|
||||
isSearchSupported = true,
|
||||
isSearchWithFiltersSupported = true,
|
||||
isYearRangeSupported = true,
|
||||
)
|
||||
|
||||
@@ -66,13 +65,11 @@ internal class ComickFunParser(context: MangaLoaderContext) :
|
||||
.addQueryParameter("tachiyomi", "true")
|
||||
.addQueryParameter("limit", pageSize.toString())
|
||||
.addQueryParameter("page", page.toString())
|
||||
when {
|
||||
!filter.query.isNullOrEmpty() -> {
|
||||
|
||||
filter.query?.let {
|
||||
url.addQueryParameter("q", filter.query)
|
||||
}
|
||||
|
||||
else -> {
|
||||
|
||||
filter.tags.forEach {
|
||||
url.addQueryParameter("genres", it.key)
|
||||
}
|
||||
@@ -84,10 +81,10 @@ internal class ComickFunParser(context: MangaLoaderContext) :
|
||||
url.addQueryParameter(
|
||||
"sort",
|
||||
when (order) {
|
||||
SortOrder.POPULARITY -> "view"
|
||||
SortOrder.UPDATED -> "uploaded"
|
||||
SortOrder.NEWEST -> "created_at"
|
||||
SortOrder.POPULARITY -> "view"
|
||||
SortOrder.RATING -> "rating"
|
||||
SortOrder.UPDATED -> "uploaded"
|
||||
else -> "uploaded"
|
||||
},
|
||||
)
|
||||
@@ -138,8 +135,7 @@ internal class ComickFunParser(context: MangaLoaderContext) :
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val ja = webClient.httpGet(url.build()).parseJsonArray()
|
||||
val tagsMap = tagsArray.get()
|
||||
return ja.mapJSON { jo ->
|
||||
@@ -193,46 +189,6 @@ internal class ComickFunParser(context: MangaLoaderContext) :
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
|
||||
val jo = webClient.httpGet(
|
||||
"https://api.${domain}/chapter/${chapter.url}?tachiyomi=true",
|
||||
).parseJson().getJSONObject("chapter")
|
||||
return jo.getJSONArray("images").mapJSON {
|
||||
val url = it.getString("url")
|
||||
MangaPage(
|
||||
id = generateUid(url),
|
||||
url = url,
|
||||
preview = null,
|
||||
source = source,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchAvailableTags(): Set<MangaTag> {
|
||||
val sparseArray = tagsArray.get()
|
||||
val set = ArraySet<MangaTag>(sparseArray.size())
|
||||
for (i in 0 until sparseArray.size()) {
|
||||
set.add(sparseArray.valueAt(i))
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
private suspend fun loadTags(): SparseArrayCompat<MangaTag> {
|
||||
val ja = webClient.httpGet("https://api.${domain}/genre").parseJsonArray()
|
||||
val tags = SparseArrayCompat<MangaTag>(ja.length())
|
||||
for (jo in ja.JSONIterator()) {
|
||||
tags.append(
|
||||
jo.getInt("id"),
|
||||
MangaTag(
|
||||
title = jo.getString("name").toTitleCase(Locale.ENGLISH),
|
||||
key = jo.getString("slug"),
|
||||
source = source,
|
||||
),
|
||||
)
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
private suspend fun getChapters(hid: String): List<MangaChapter> {
|
||||
val ja = webClient.httpGet(
|
||||
url = "https://api.${domain}/comic/$hid/chapters?limit=$CHAPTERS_LIMIT",
|
||||
@@ -272,6 +228,48 @@ internal class ComickFunParser(context: MangaLoaderContext) :
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
|
||||
val jo = webClient.httpGet(
|
||||
"https://api.${domain}/chapter/${chapter.url}?tachiyomi=true",
|
||||
).parseJson().getJSONObject("chapter")
|
||||
return jo.getJSONArray("images").mapJSON {
|
||||
val url = it.getString("url")
|
||||
MangaPage(
|
||||
id = generateUid(url),
|
||||
url = url,
|
||||
preview = null,
|
||||
source = source,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val tagsArray = SuspendLazy(::loadTags)
|
||||
|
||||
private suspend fun fetchAvailableTags(): Set<MangaTag> {
|
||||
val sparseArray = tagsArray.get()
|
||||
val set = ArraySet<MangaTag>(sparseArray.size())
|
||||
for (i in 0 until sparseArray.size()) {
|
||||
set.add(sparseArray.valueAt(i))
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
private suspend fun loadTags(): SparseArrayCompat<MangaTag> {
|
||||
val ja = webClient.httpGet("https://api.${domain}/genre").parseJsonArray()
|
||||
val tags = SparseArrayCompat<MangaTag>(ja.length())
|
||||
for (jo in ja.JSONIterator()) {
|
||||
tags.append(
|
||||
jo.getInt("id"),
|
||||
MangaTag(
|
||||
title = jo.getString("name").toTitleCase(Locale.ENGLISH),
|
||||
key = jo.getString("slug"),
|
||||
source = source,
|
||||
),
|
||||
)
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
private fun JSONObject.selectGenres(tags: SparseArrayCompat<MangaTag>): Set<MangaTag> {
|
||||
val array = optJSONArray("genres") ?: return emptySet()
|
||||
val res = ArraySet<MangaTag>(array.length())
|
||||
|
||||
@@ -44,6 +44,22 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context
|
||||
keys.add(preferredServerKey)
|
||||
}
|
||||
|
||||
override val availableSortOrders: EnumSet<SortOrder> = EnumSet.of(
|
||||
SortOrder.UPDATED,
|
||||
SortOrder.UPDATED_ASC,
|
||||
SortOrder.POPULARITY,
|
||||
SortOrder.POPULARITY_ASC,
|
||||
SortOrder.RATING,
|
||||
SortOrder.RATING_ASC,
|
||||
SortOrder.NEWEST,
|
||||
SortOrder.NEWEST_ASC,
|
||||
SortOrder.ALPHABETICAL,
|
||||
SortOrder.ALPHABETICAL_DESC,
|
||||
SortOrder.ADDED,
|
||||
SortOrder.ADDED_ASC,
|
||||
SortOrder.RELEVANCE,
|
||||
)
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isMultipleTagsSupported = true,
|
||||
@@ -54,8 +70,6 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context
|
||||
isOriginalLocaleSupported = true,
|
||||
)
|
||||
|
||||
override val availableSortOrders: EnumSet<SortOrder> = EnumSet.allOf(SortOrder::class.java)
|
||||
|
||||
override suspend fun getFilterOptions(): MangaListFilterOptions = coroutineScope {
|
||||
val localesDeferred = async { fetchAvailableLocales() }
|
||||
val tagsDeferred = async { fetchAvailableTags() }
|
||||
|
||||
@@ -16,16 +16,23 @@ import java.util.*
|
||||
internal class MangaPark(context: MangaLoaderContext) :
|
||||
PagedMangaParser(context, MangaParserSource.MANGAPARK, pageSize = 36) {
|
||||
|
||||
override val configKeyDomain = ConfigKey.Domain("mangapark.net")
|
||||
|
||||
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
|
||||
super.onCreateConfig(keys)
|
||||
keys.add(userAgentKey)
|
||||
}
|
||||
|
||||
override val availableSortOrders: Set<SortOrder> =
|
||||
EnumSet.of(SortOrder.POPULARITY, SortOrder.UPDATED, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
|
||||
|
||||
override val configKeyDomain = ConfigKey.Domain("mangapark.net")
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isMultipleTagsSupported = true,
|
||||
isTagsExclusionSupported = true,
|
||||
isSearchSupported = true,
|
||||
isSearchWithFiltersSupported = true,
|
||||
isOriginalLocaleSupported = true,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
@@ -56,13 +63,6 @@ internal class MangaPark(context: MangaLoaderContext) :
|
||||
),
|
||||
)
|
||||
|
||||
override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
|
||||
super.onCreateConfig(keys)
|
||||
keys.add(userAgentKey)
|
||||
}
|
||||
|
||||
private val tagsMap = SuspendLazy(::parseTags)
|
||||
|
||||
init {
|
||||
context.cookieJar.insertCookies(domain, "nsfw", "2")
|
||||
}
|
||||
@@ -73,14 +73,11 @@ internal class MangaPark(context: MangaLoaderContext) :
|
||||
append(domain)
|
||||
append("/search?page=")
|
||||
append(page.toString())
|
||||
when {
|
||||
!filter.query.isNullOrEmpty() -> {
|
||||
filter.query?.let {
|
||||
append("&word=")
|
||||
append(filter.query.urlEncoded())
|
||||
}
|
||||
|
||||
else -> {
|
||||
|
||||
append("&genres=")
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
appendAll(filter.tags, ",") { it.key }
|
||||
@@ -132,7 +129,10 @@ internal class MangaPark(context: MangaLoaderContext) :
|
||||
append("&lang=")
|
||||
append(it.language)
|
||||
}
|
||||
}
|
||||
|
||||
filter.originalLocale?.let {
|
||||
append("&orig=")
|
||||
append(it.language)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +156,8 @@ internal class MangaPark(context: MangaLoaderContext) :
|
||||
}
|
||||
}
|
||||
|
||||
private val tagsMap = SuspendLazy(::parseTags)
|
||||
|
||||
private suspend fun parseTags(): Map<String, MangaTag> {
|
||||
val tagElements = webClient.httpGet("https://$domain/search").parseHtml()
|
||||
.select("div.flex-col:contains(Genres) div.whitespace-nowrap")
|
||||
@@ -217,13 +219,18 @@ internal class MangaPark(context: MangaLoaderContext) :
|
||||
private fun parseChapterDate(dateFormat: DateFormat, date: String?): Long {
|
||||
val d = date?.lowercase() ?: return 0
|
||||
return when {
|
||||
d.endsWith(" ago") -> parseRelativeDate(date)
|
||||
d.startsWith("just now") -> Calendar.getInstance().apply {
|
||||
WordSet(" ago").endsWith(d) -> {
|
||||
parseRelativeDate(d)
|
||||
}
|
||||
|
||||
WordSet("just now").startsWith(d) -> {
|
||||
Calendar.getInstance().apply {
|
||||
set(Calendar.HOUR_OF_DAY, 0)
|
||||
set(Calendar.MINUTE, 0)
|
||||
set(Calendar.SECOND, 0)
|
||||
set(Calendar.MILLISECOND, 0)
|
||||
}.timeInMillis
|
||||
}
|
||||
|
||||
else -> dateFormat.tryParse(date)
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ internal abstract class NineMangaParser(
|
||||
get() = MangaListFilterCapabilities(
|
||||
isMultipleTagsSupported = true,
|
||||
isTagsExclusionSupported = true,
|
||||
isSearchWithFiltersSupported = true,
|
||||
isSearchSupported = true,
|
||||
)
|
||||
|
||||
@@ -69,19 +70,18 @@ internal abstract class NineMangaParser(
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
append(domain)
|
||||
when {
|
||||
!filter.query.isNullOrEmpty() -> {
|
||||
append("/search/?name_sel=&wd=")
|
||||
|
||||
if (filter.tags.isNotEmpty() || filter.tagsExclude.isNotEmpty() || filter.states.isNotEmpty() || !filter.query.isNullOrEmpty()) {
|
||||
append("/search/")
|
||||
append("?page=")
|
||||
append(page.toString())
|
||||
|
||||
filter.query?.let {
|
||||
append("&name_sel=contain&wd=")
|
||||
append(filter.query.urlEncoded())
|
||||
append("&page=")
|
||||
append(page)
|
||||
append(".html")
|
||||
}
|
||||
|
||||
else -> {
|
||||
|
||||
if (filter.tags.isNotEmpty() || filter.tagsExclude.isNotEmpty() || filter.states.isNotEmpty()) {
|
||||
append("/search/?category_id=")
|
||||
append("&category_id=")
|
||||
append(filter.tags.joinToString(separator = ",") { it.key })
|
||||
|
||||
append("&out_category_id=")
|
||||
@@ -95,13 +95,10 @@ internal abstract class NineMangaParser(
|
||||
else -> append("either")
|
||||
}
|
||||
}
|
||||
append("&page=")
|
||||
|
||||
} else {
|
||||
append("/category/index_")
|
||||
}
|
||||
append(page.toString())
|
||||
append(".html")
|
||||
}
|
||||
}
|
||||
}
|
||||
val doc = webClient.httpGet(url).parseHtml()
|
||||
|
||||
@@ -43,10 +43,16 @@ internal abstract class AnimeBootstrapParser(
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isSearchSupported = true,
|
||||
isSearchWithFiltersSupported = true,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
availableTags = fetchAvailableTags(),
|
||||
availableContentTypes = EnumSet.of(
|
||||
ContentType.MANGA,
|
||||
ContentType.MANHWA,
|
||||
ContentType.MANHUA,
|
||||
),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
|
||||
@@ -58,19 +64,28 @@ internal abstract class AnimeBootstrapParser(
|
||||
append(page.toString())
|
||||
append("&type=all")
|
||||
|
||||
when {
|
||||
!filter.query.isNullOrEmpty() -> {
|
||||
filter.query?.let {
|
||||
append("&search=")
|
||||
append(filter.query.urlEncoded())
|
||||
}
|
||||
|
||||
else -> {
|
||||
|
||||
filter.tags.oneOrThrowIfMany()?.let {
|
||||
append("&categorie=")
|
||||
append(it.key)
|
||||
}
|
||||
|
||||
filter.types.oneOrThrowIfMany()?.let {
|
||||
append("&type=")
|
||||
append(
|
||||
when (it) {
|
||||
ContentType.MANGA -> "manga"
|
||||
ContentType.MANHWA -> "manhwa"
|
||||
ContentType.MANHUA -> "manhua"
|
||||
else -> "all"
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
append("&sort=")
|
||||
when (order) {
|
||||
SortOrder.POPULARITY -> append("view")
|
||||
@@ -81,8 +96,6 @@ internal abstract class AnimeBootstrapParser(
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
val doc = webClient.httpGet(url).parseHtml()
|
||||
|
||||
return doc.select("div.col-6 div.product__item").map { div ->
|
||||
|
||||
@@ -4,6 +4,7 @@ import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.parsers.Broken
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||
import org.koitharu.kotatsu.parsers.PagedMangaParser
|
||||
@@ -15,6 +16,7 @@ import org.koitharu.kotatsu.parsers.util.json.mapJSONIndexed
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
@Broken
|
||||
@MangaSourceParser("FLIXSCANS", "FlixScans.net", "ar")
|
||||
internal class FlixScans(context: MangaLoaderContext) : PagedMangaParser(context, MangaParserSource.FLIXSCANS, 18) {
|
||||
|
||||
|
||||
@@ -28,54 +28,56 @@ internal class TeamXNovel(context: MangaLoaderContext) : PagedMangaParser(contex
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = MangaListFilterCapabilities(
|
||||
isSearchSupported = true,
|
||||
isSearchWithFiltersSupported = true,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
availableTags = fetchAvailableTags(),
|
||||
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.ABANDONED),
|
||||
availableContentTypes = EnumSet.of(
|
||||
ContentType.MANGA,
|
||||
ContentType.MANHWA,
|
||||
ContentType.MANHUA,
|
||||
),
|
||||
)
|
||||
|
||||
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
|
||||
val url = buildString {
|
||||
append("https://")
|
||||
append(domain)
|
||||
when {
|
||||
|
||||
!filter.query.isNullOrEmpty() -> {
|
||||
append("/?search=")
|
||||
if (order == SortOrder.UPDATED) {
|
||||
if (filter.tags.isNotEmpty() || filter.demographics.isNotEmpty()) {
|
||||
throw IllegalArgumentException("Updated sorting does not support other sorting filters")
|
||||
}
|
||||
append("/?page=")
|
||||
append(page.toString())
|
||||
} else {
|
||||
append("/series?page=")
|
||||
append(page.toString())
|
||||
|
||||
filter.query?.let {
|
||||
append("&search=")
|
||||
append(filter.query.urlEncoded())
|
||||
if (page > 1) {
|
||||
append("&page=")
|
||||
append(page.toString())
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
val tag = filter.tags.oneOrThrowIfMany()
|
||||
append("/series?genre=")
|
||||
append(tag?.key.orEmpty())
|
||||
if (page > 1) {
|
||||
append("&page=")
|
||||
append(page.toString())
|
||||
filter.tags.oneOrThrowIfMany()?.let {
|
||||
append("&genre=")
|
||||
append(it.key)
|
||||
}
|
||||
append("&")
|
||||
} else {
|
||||
when (order) {
|
||||
SortOrder.POPULARITY -> append("/series")
|
||||
SortOrder.UPDATED -> append("/")
|
||||
else -> append("/")
|
||||
}
|
||||
if (page > 1) {
|
||||
append("?page=")
|
||||
append(page.toString())
|
||||
append("&")
|
||||
} else {
|
||||
append("?")
|
||||
}
|
||||
|
||||
filter.types.forEach {
|
||||
append("&type=")
|
||||
append(
|
||||
when (it) {
|
||||
ContentType.MANGA -> "مانجا ياباني"
|
||||
ContentType.MANHWA -> "مانهوا كورية"
|
||||
ContentType.MANHUA -> "مانها صيني"
|
||||
else -> ""
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if (order == SortOrder.POPULARITY || filter.tags.isNotEmpty()) {
|
||||
filter.states.oneOrThrowIfMany()?.let {
|
||||
append("status=")
|
||||
append(
|
||||
@@ -89,8 +91,6 @@ internal class TeamXNovel(context: MangaLoaderContext) : PagedMangaParser(contex
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val doc = webClient.httpGet(url).parseHtml()
|
||||
return doc.select("div.listupd .bs .bsx").ifEmpty {
|
||||
doc.select("div.post-body .box")
|
||||
|
||||
@@ -252,7 +252,9 @@ internal abstract class FmreaderParser(
|
||||
val d = date?.lowercase() ?: return 0
|
||||
return when {
|
||||
|
||||
WordSet(" ago", " atrás", " h", " d").endsWith(d) -> { parseRelativeDate(d) }
|
||||
WordSet(" ago", " atrás", " h", " d").endsWith(d) -> {
|
||||
parseRelativeDate(d)
|
||||
}
|
||||
|
||||
WordSet("today").startsWith(d) -> {
|
||||
Calendar.getInstance().apply {
|
||||
@@ -281,18 +283,25 @@ internal abstract class FmreaderParser(
|
||||
return when {
|
||||
WordSet("second")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
|
||||
|
||||
WordSet("min", "minute", "minutes", "minuto", "minutos")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
|
||||
|
||||
WordSet("hour", "hours", "hora", "horas", "h")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
|
||||
|
||||
WordSet("day", "days", "día", "dia")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
|
||||
|
||||
WordSet("week", "weeks", "semana", "semanas")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.WEEK_OF_YEAR, -number) }.timeInMillis
|
||||
|
||||
WordSet("month", "months", "mes", "meses")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
|
||||
|
||||
WordSet("year", "año", "años")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
|
||||
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +267,9 @@ internal abstract class KeyoappParser(
|
||||
val d = date?.lowercase() ?: return 0
|
||||
return when {
|
||||
|
||||
WordSet(" ago").endsWith(d) -> { parseRelativeDate(d) }
|
||||
WordSet(" ago").endsWith(d) -> {
|
||||
parseRelativeDate(d)
|
||||
}
|
||||
|
||||
WordSet("today").startsWith(d) -> {
|
||||
Calendar.getInstance().apply {
|
||||
@@ -296,16 +298,22 @@ internal abstract class KeyoappParser(
|
||||
return when {
|
||||
WordSet("second")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
|
||||
|
||||
WordSet("minute", "minutes")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
|
||||
|
||||
WordSet("hour", "hours")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
|
||||
|
||||
WordSet("day", "days")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
|
||||
|
||||
WordSet("month", "months")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
|
||||
|
||||
WordSet("year")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
|
||||
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ internal abstract class MadaraParser(
|
||||
isMultipleTagsSupported = true,
|
||||
isTagsExclusionSupported = !withoutAjax,
|
||||
isSearchSupported = true,
|
||||
isSearchWithFiltersSupported = true,
|
||||
isYearSupported = true,
|
||||
)
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
@@ -51,8 +53,7 @@ internal abstract class MadaraParser(
|
||||
override val availableSortOrders: Set<SortOrder> = setupAvailableSortOrders()
|
||||
|
||||
private fun setupAvailableSortOrders(): Set<SortOrder> {
|
||||
return if(!withoutAjax)
|
||||
{
|
||||
return if (!withoutAjax) {
|
||||
EnumSet.of(
|
||||
SortOrder.UPDATED,
|
||||
SortOrder.UPDATED_ASC,
|
||||
@@ -64,10 +65,17 @@ internal abstract class MadaraParser(
|
||||
SortOrder.ALPHABETICAL_DESC,
|
||||
SortOrder.RATING,
|
||||
SortOrder.RATING_ASC,
|
||||
SortOrder.RELEVANCE,
|
||||
)
|
||||
} else {
|
||||
EnumSet.of(
|
||||
SortOrder.UPDATED,
|
||||
SortOrder.POPULARITY,
|
||||
SortOrder.NEWEST,
|
||||
SortOrder.ALPHABETICAL,
|
||||
SortOrder.RATING,
|
||||
SortOrder.RELEVANCE,
|
||||
)
|
||||
}else
|
||||
{
|
||||
EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,27 +227,13 @@ internal abstract class MadaraParser(
|
||||
append("https://")
|
||||
append(domain)
|
||||
|
||||
when {
|
||||
|
||||
!filter.query.isNullOrEmpty() -> {
|
||||
if (pages > 1) {
|
||||
append("/page/")
|
||||
append(pages.toString())
|
||||
}
|
||||
append("/?s=")
|
||||
append(filter.query.urlEncoded())
|
||||
append("&post_type=wp-manga")
|
||||
}
|
||||
|
||||
else -> {
|
||||
if (pages > 1) {
|
||||
append("/page/")
|
||||
append(pages.toString())
|
||||
}
|
||||
append("/?s=")
|
||||
|
||||
//Support query
|
||||
//append(filter.query.urlEncoded())
|
||||
append(filter.query?.urlEncoded())
|
||||
|
||||
append("&post_type=wp-manga")
|
||||
|
||||
@@ -273,11 +267,10 @@ internal abstract class MadaraParser(
|
||||
)
|
||||
}
|
||||
|
||||
// Support year
|
||||
//filter.year?.let {
|
||||
// append("&release=")
|
||||
// append(filter.year)
|
||||
//}
|
||||
if (filter.year != 0) {
|
||||
append("&release=")
|
||||
append(filter.year.toString())
|
||||
}
|
||||
|
||||
// Support author
|
||||
//filter.author?.let {
|
||||
@@ -299,10 +292,8 @@ internal abstract class MadaraParser(
|
||||
SortOrder.NEWEST -> append("new-manga")
|
||||
SortOrder.ALPHABETICAL -> append("alphabet")
|
||||
SortOrder.RATING -> append("rating")
|
||||
// SortOrder.RELEVANCE -> {}
|
||||
else -> append("latest")
|
||||
}
|
||||
}
|
||||
SortOrder.RELEVANCE -> {}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
return parseMangaList(webClient.httpGet(url).parseHtml())
|
||||
@@ -312,20 +303,10 @@ internal abstract class MadaraParser(
|
||||
|
||||
payload["page"] = page.toString()
|
||||
|
||||
when {
|
||||
|
||||
!filter.query.isNullOrEmpty() -> {
|
||||
filter.query?.let {
|
||||
payload["vars[s]"] = filter.query.urlEncoded()
|
||||
}
|
||||
|
||||
else -> {
|
||||
|
||||
|
||||
// Support query
|
||||
// filter.query.let {
|
||||
// payload["vars[s]"] = filter.query.urlEncoded()
|
||||
// }
|
||||
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
payload["vars[tax_query][0][taxonomy]"] = "wp-manga-genre"
|
||||
payload["vars[tax_query][0][field]"] = "slug"
|
||||
@@ -344,12 +325,11 @@ internal abstract class MadaraParser(
|
||||
payload["vars[tax_query][1][operator]"] = "NOT IN"
|
||||
}
|
||||
|
||||
// Support year
|
||||
//filter.year?.let {
|
||||
// payload["vars[tax_query][2][taxonomy]"] = wp-manga-release
|
||||
// payload["vars[tax_query][2][field]"] = slug
|
||||
// payload["vars[tax_query][2][terms][]"] = filter.year
|
||||
//}
|
||||
if (filter.year != 0) {
|
||||
payload["vars[tax_query][2][taxonomy]"] = "wp-manga-release"
|
||||
payload["vars[tax_query][2][field]"] = "slug"
|
||||
payload["vars[tax_query][2][terms][]"] = filter.year.toString()
|
||||
}
|
||||
|
||||
// Support author
|
||||
// filter.author.let {
|
||||
@@ -368,8 +348,7 @@ internal abstract class MadaraParser(
|
||||
// payload["vars[tax_query][4][operator]"] = "IN"
|
||||
//}
|
||||
|
||||
/// for add filter.year need to add || filter.year
|
||||
if (filter.tags.isNotEmpty() || filter.tagsExclude.isNotEmpty()) {
|
||||
if (filter.tags.isNotEmpty() || filter.tagsExclude.isNotEmpty() || filter.year != 0) {
|
||||
payload["vars[tax_query][relation]"] = "AND"
|
||||
}
|
||||
|
||||
@@ -434,11 +413,11 @@ internal abstract class MadaraParser(
|
||||
payload["vars[orderby][query_total_reviews]"] = "ASC"
|
||||
}
|
||||
|
||||
// SortOrder.RELEVANCE -> {
|
||||
// payload["vars[orderby]"] = ""
|
||||
// }
|
||||
SortOrder.RELEVANCE -> {
|
||||
payload["vars[orderby]"] = ""
|
||||
}
|
||||
|
||||
else -> payload["vars[meta_key]"] = "_latest_update"
|
||||
else -> payload["vars[orderby]"] = ""
|
||||
}
|
||||
|
||||
filter.states.forEach {
|
||||
@@ -463,8 +442,6 @@ internal abstract class MadaraParser(
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parseMangaList(
|
||||
webClient.httpPost(
|
||||
@@ -749,12 +726,14 @@ internal abstract class MadaraParser(
|
||||
val d = date?.lowercase() ?: return 0
|
||||
return when {
|
||||
|
||||
WordSet(" ago", "atrás", " hace", " publicado"," назад", " önce", " trước", "مضت",
|
||||
" h", " d", " días", " jour", " horas", " heure", " mins", " minutos", " minute", " mois").endsWith(d) -> {
|
||||
WordSet(
|
||||
" ago", "atrás", " hace", " publicado", " назад", " önce", " trước", "مضت",
|
||||
" h", " d", " días", " jour", " horas", " heure", " mins", " minutos", " minute", " mois",
|
||||
).endsWith(d) -> {
|
||||
parseRelativeDate(d)
|
||||
}
|
||||
|
||||
WordSet("há ", "منذ", "il y a" ).startsWith(d) -> {
|
||||
WordSet("há ", "منذ", "il y a").startsWith(d) -> {
|
||||
parseRelativeDate(d)
|
||||
}
|
||||
|
||||
@@ -805,16 +784,22 @@ internal abstract class MadaraParser(
|
||||
return when {
|
||||
WordSet("detik", "segundo", "second", "ثوان")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
|
||||
|
||||
WordSet("menit", "dakika", "min", "minute", "minutes", "minuto", "mins", "phút", "минут", "دقيقة")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
|
||||
|
||||
WordSet("jam", "saat", "heure", "hora", "horas", "hour", "hours", "h", "ساعات", "ساعة")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
|
||||
|
||||
WordSet("hari", "gün", "jour", "día", "dia", "day", "days", "d", "день")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
|
||||
|
||||
WordSet("month", "months", "أشهر", "mois")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
|
||||
|
||||
WordSet("year")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
|
||||
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,7 +274,9 @@ internal abstract class MadthemeParser(
|
||||
val d = date?.lowercase() ?: return 0
|
||||
return when {
|
||||
|
||||
WordSet(" ago", " h", " d").endsWith(d) -> { parseRelativeDate(d) }
|
||||
WordSet(" ago", " h", " d").endsWith(d) -> {
|
||||
parseRelativeDate(d)
|
||||
}
|
||||
|
||||
WordSet("today").startsWith(d) -> {
|
||||
Calendar.getInstance().apply {
|
||||
@@ -303,16 +305,22 @@ internal abstract class MadthemeParser(
|
||||
return when {
|
||||
WordSet("second")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
|
||||
|
||||
WordSet("min", "minute", "minutes")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
|
||||
|
||||
WordSet("hour", "hours", "h")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
|
||||
|
||||
WordSet("day", "days")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
|
||||
|
||||
WordSet("month", "months")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
|
||||
|
||||
WordSet("year")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
|
||||
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ internal class Hanman18(context: MangaLoaderContext) :
|
||||
Manga18Parser(context, MangaParserSource.HANMAN18, "hanman18.com") {
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
availableTags = emptySet()
|
||||
availableTags = emptySet(),
|
||||
)
|
||||
|
||||
override suspend fun getChapters(doc: Document): List<MangaChapter> {
|
||||
|
||||
@@ -265,7 +265,9 @@ internal abstract class MangaboxParser(
|
||||
protected fun parseChapterDate(dateFormat: DateFormat, date: String?): Long {
|
||||
val d = date?.lowercase() ?: return 0
|
||||
return when {
|
||||
WordSet(" ago", " h", " d").endsWith(d) -> { parseRelativeDate(d) }
|
||||
WordSet(" ago", " h", " d").endsWith(d) -> {
|
||||
parseRelativeDate(d)
|
||||
}
|
||||
|
||||
WordSet("today").startsWith(d) -> {
|
||||
Calendar.getInstance().apply {
|
||||
@@ -294,16 +296,22 @@ internal abstract class MangaboxParser(
|
||||
return when {
|
||||
WordSet("second")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
|
||||
|
||||
WordSet("min", "minute", "minutes")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
|
||||
|
||||
WordSet("hour", "hours", "h")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
|
||||
|
||||
WordSet("day", "days")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
|
||||
|
||||
WordSet("month", "months")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
|
||||
|
||||
WordSet("year")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
|
||||
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,8 +243,14 @@ internal abstract class OtakuSanctuaryParser(
|
||||
protected fun parseChapterDate(dateFormat: DateFormat, date: String?): Long {
|
||||
val d = date?.lowercase() ?: return 0
|
||||
return when {
|
||||
WordSet(" ago", " atrás").endsWith(d) -> { parseRelativeDate(d) }
|
||||
WordSet("cách đây ").startsWith(d) -> { parseRelativeDate(d) }
|
||||
WordSet(" ago", " atrás").endsWith(d) -> {
|
||||
parseRelativeDate(d)
|
||||
}
|
||||
|
||||
WordSet("cách đây ").startsWith(d) -> {
|
||||
parseRelativeDate(d)
|
||||
}
|
||||
|
||||
else -> dateFormat.tryParse(date)
|
||||
}
|
||||
}
|
||||
@@ -255,16 +261,22 @@ internal abstract class OtakuSanctuaryParser(
|
||||
return when {
|
||||
WordSet("second", "giây")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
|
||||
|
||||
WordSet("min", "minute", "minutes", "phút")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
|
||||
|
||||
WordSet("tiếng", "hour", "hours")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
|
||||
|
||||
WordSet("day", "days", "d", "ngày")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
|
||||
|
||||
WordSet("month", "months")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
|
||||
|
||||
WordSet("year")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
|
||||
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,9 @@ internal class MangaFr(context: MangaLoaderContext) :
|
||||
override val listUrl = "/series"
|
||||
|
||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||
availableTags = emptySet()
|
||||
availableTags = emptySet(),
|
||||
)
|
||||
|
||||
override suspend fun getDetails(manga: Manga): Manga {
|
||||
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
|
||||
val dateFormat = SimpleDateFormat("MM-dd-yyyy", sourceLocale)
|
||||
|
||||
@@ -280,7 +280,9 @@ internal abstract class WpComicsParser(
|
||||
val d = date?.lowercase() ?: return 0
|
||||
return when {
|
||||
|
||||
WordSet(" ago", " trước").endsWith(d) -> { parseRelativeDate(d) }
|
||||
WordSet(" ago", " trước").endsWith(d) -> {
|
||||
parseRelativeDate(d)
|
||||
}
|
||||
|
||||
WordSet("today").startsWith(d) -> {
|
||||
Calendar.getInstance().apply {
|
||||
@@ -309,14 +311,19 @@ internal abstract class WpComicsParser(
|
||||
return when {
|
||||
WordSet("second", "giây")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
|
||||
|
||||
WordSet("min", "minute", "minutes", "mins", "phút")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
|
||||
|
||||
WordSet("jam", "saat", "heure", "hora", "horas", "hour", "hours", "h", "giờ")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
|
||||
|
||||
WordSet("day", "days", "d", "ngày")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
|
||||
|
||||
WordSet("month", "months", "tháng")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
|
||||
|
||||
WordSet("year", "năm").anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
|
||||
else -> 0
|
||||
}
|
||||
|
||||
@@ -252,7 +252,9 @@ internal abstract class ZMangaParser(
|
||||
protected fun parseChapterDate(dateFormat: DateFormat, date: String?): Long {
|
||||
val d = date?.lowercase() ?: return 0
|
||||
return when {
|
||||
WordSet(" ago", " h", " d").endsWith(d) -> { parseRelativeDate(d) }
|
||||
WordSet(" ago", " h", " d").endsWith(d) -> {
|
||||
parseRelativeDate(d)
|
||||
}
|
||||
|
||||
WordSet("today").startsWith(d) -> {
|
||||
Calendar.getInstance().apply {
|
||||
@@ -282,15 +284,20 @@ internal abstract class ZMangaParser(
|
||||
return when {
|
||||
WordSet("second")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
|
||||
|
||||
WordSet("min", "minute", "minutes")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
|
||||
|
||||
WordSet("hour", "hours", "h")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
|
||||
|
||||
WordSet("day", "days").anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
|
||||
WordSet("month", "months")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
|
||||
|
||||
WordSet("year")
|
||||
.anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
|
||||
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user