[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
devi 2 years ago
parent f2354957e6
commit d1f9b0d829

@ -49,10 +49,10 @@ internal class BatoToParser(context: MangaLoaderContext) : PagedMangaParser(
} }
override val availableSortOrders: Set<SortOrder> = EnumSet.of( override val availableSortOrders: Set<SortOrder> = EnumSet.of(
SortOrder.NEWEST, SortOrder.ALPHABETICAL,
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.NEWEST,
SortOrder.POPULARITY, SortOrder.POPULARITY,
SortOrder.ALPHABETICAL,
SortOrder.POPULARITY_YEAR, SortOrder.POPULARITY_YEAR,
SortOrder.POPULARITY_MONTH, SortOrder.POPULARITY_MONTH,
SortOrder.POPULARITY_WEEK, SortOrder.POPULARITY_WEEK,
@ -65,6 +65,7 @@ internal class BatoToParser(context: MangaLoaderContext) : PagedMangaParser(
isMultipleTagsSupported = true, isMultipleTagsSupported = true,
isTagsExclusionSupported = true, isTagsExclusionSupported = true,
isSearchSupported = true, isSearchSupported = true,
isOriginalLocaleSupported = true,
) )
override suspend fun getFilterOptions() = MangaListFilterOptions( 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=") append("&genres=")
if (filter.tags.isNotEmpty()) { if (filter.tags.isNotEmpty()) {
appendAll(filter.tags, ",") { it.key } appendAll(filter.tags, ",") { it.key }

@ -34,13 +34,12 @@ internal class ComickFunParser(context: MangaLoaderContext) :
SortOrder.NEWEST, SortOrder.NEWEST,
) )
private val tagsArray = SuspendLazy(::loadTags)
override val filterCapabilities: MangaListFilterCapabilities override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
isMultipleTagsSupported = true, isMultipleTagsSupported = true,
isTagsExclusionSupported = true, isTagsExclusionSupported = true,
isSearchSupported = true, isSearchSupported = true,
isSearchWithFiltersSupported = true,
isYearRangeSupported = true, isYearRangeSupported = true,
) )
@ -66,13 +65,11 @@ internal class ComickFunParser(context: MangaLoaderContext) :
.addQueryParameter("tachiyomi", "true") .addQueryParameter("tachiyomi", "true")
.addQueryParameter("limit", pageSize.toString()) .addQueryParameter("limit", pageSize.toString())
.addQueryParameter("page", page.toString()) .addQueryParameter("page", page.toString())
when {
!filter.query.isNullOrEmpty() -> { filter.query?.let {
url.addQueryParameter("q", filter.query) url.addQueryParameter("q", filter.query)
} }
else -> {
filter.tags.forEach { filter.tags.forEach {
url.addQueryParameter("genres", it.key) url.addQueryParameter("genres", it.key)
} }
@ -84,10 +81,10 @@ internal class ComickFunParser(context: MangaLoaderContext) :
url.addQueryParameter( url.addQueryParameter(
"sort", "sort",
when (order) { when (order) {
SortOrder.POPULARITY -> "view"
SortOrder.UPDATED -> "uploaded"
SortOrder.NEWEST -> "created_at" SortOrder.NEWEST -> "created_at"
SortOrder.POPULARITY -> "view"
SortOrder.RATING -> "rating" SortOrder.RATING -> "rating"
SortOrder.UPDATED -> "uploaded"
else -> "uploaded" else -> "uploaded"
}, },
) )
@ -138,8 +135,7 @@ internal class ComickFunParser(context: MangaLoaderContext) :
}, },
) )
} }
}
}
val ja = webClient.httpGet(url.build()).parseJsonArray() val ja = webClient.httpGet(url.build()).parseJsonArray()
val tagsMap = tagsArray.get() val tagsMap = tagsArray.get()
return ja.mapJSON { jo -> return ja.mapJSON { jo ->
@ -193,6 +189,45 @@ internal class ComickFunParser(context: MangaLoaderContext) :
) )
} }
private suspend fun getChapters(hid: String): List<MangaChapter> {
val ja = webClient.httpGet(
url = "https://api.${domain}/comic/$hid/chapters?limit=$CHAPTERS_LIMIT",
).parseJson().getJSONArray("chapters")
val dateFormat = SimpleDateFormat("yyyy-MM-dd")
return ja.toJSONList().reversed().mapChapters { _, jo ->
val vol = jo.getIntOrDefault("vol", 0)
val chap = jo.getFloatOrDefault("chap", 0f)
val locale = Locale.forLanguageTag(jo.getString("lang"))
val group = jo.optJSONArray("group_name")?.joinToString(", ")
val branch = buildString {
append(locale.getDisplayName(locale).toTitleCase(locale))
if (!group.isNullOrEmpty()) {
append(" (")
append(group)
append(')')
}
}
MangaChapter(
id = generateUid(jo.getLong("id")),
name = buildString {
if (vol > 0) {
append("Vol ").append(vol).append(' ')
}
append("Chap ").append(chap)
jo.getStringOrNull("title")?.let { append(": ").append(it) }
},
number = chap,
volume = vol,
url = jo.getString("hid"),
scanlator = jo.optJSONArray("group_name")?.asIterable<String>()?.joinToString()
?.takeUnless { it.isBlank() },
uploadDate = dateFormat.tryParse(jo.getString("created_at").substringBefore('T')),
branch = branch,
source = source,
)
}
}
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> { override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val jo = webClient.httpGet( val jo = webClient.httpGet(
"https://api.${domain}/chapter/${chapter.url}?tachiyomi=true", "https://api.${domain}/chapter/${chapter.url}?tachiyomi=true",
@ -208,6 +243,8 @@ internal class ComickFunParser(context: MangaLoaderContext) :
} }
} }
private val tagsArray = SuspendLazy(::loadTags)
private suspend fun fetchAvailableTags(): Set<MangaTag> { private suspend fun fetchAvailableTags(): Set<MangaTag> {
val sparseArray = tagsArray.get() val sparseArray = tagsArray.get()
val set = ArraySet<MangaTag>(sparseArray.size()) val set = ArraySet<MangaTag>(sparseArray.size())
@ -233,45 +270,6 @@ internal class ComickFunParser(context: MangaLoaderContext) :
return tags return tags
} }
private suspend fun getChapters(hid: String): List<MangaChapter> {
val ja = webClient.httpGet(
url = "https://api.${domain}/comic/$hid/chapters?limit=$CHAPTERS_LIMIT",
).parseJson().getJSONArray("chapters")
val dateFormat = SimpleDateFormat("yyyy-MM-dd")
return ja.toJSONList().reversed().mapChapters { _, jo ->
val vol = jo.getIntOrDefault("vol", 0)
val chap = jo.getFloatOrDefault("chap", 0f)
val locale = Locale.forLanguageTag(jo.getString("lang"))
val group = jo.optJSONArray("group_name")?.joinToString(", ")
val branch = buildString {
append(locale.getDisplayName(locale).toTitleCase(locale))
if (!group.isNullOrEmpty()) {
append(" (")
append(group)
append(')')
}
}
MangaChapter(
id = generateUid(jo.getLong("id")),
name = buildString {
if (vol > 0) {
append("Vol ").append(vol).append(' ')
}
append("Chap ").append(chap)
jo.getStringOrNull("title")?.let { append(": ").append(it) }
},
number = chap,
volume = vol,
url = jo.getString("hid"),
scanlator = jo.optJSONArray("group_name")?.asIterable<String>()?.joinToString()
?.takeUnless { it.isBlank() },
uploadDate = dateFormat.tryParse(jo.getString("created_at").substringBefore('T')),
branch = branch,
source = source,
)
}
}
private fun JSONObject.selectGenres(tags: SparseArrayCompat<MangaTag>): Set<MangaTag> { private fun JSONObject.selectGenres(tags: SparseArrayCompat<MangaTag>): Set<MangaTag> {
val array = optJSONArray("genres") ?: return emptySet() val array = optJSONArray("genres") ?: return emptySet()
val res = ArraySet<MangaTag>(array.length()) val res = ArraySet<MangaTag>(array.length())

@ -44,6 +44,22 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context
keys.add(preferredServerKey) 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 override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
isMultipleTagsSupported = true, isMultipleTagsSupported = true,
@ -54,8 +70,6 @@ internal class MangaDexParser(context: MangaLoaderContext) : MangaParser(context
isOriginalLocaleSupported = true, isOriginalLocaleSupported = true,
) )
override val availableSortOrders: EnumSet<SortOrder> = EnumSet.allOf(SortOrder::class.java)
override suspend fun getFilterOptions(): MangaListFilterOptions = coroutineScope { override suspend fun getFilterOptions(): MangaListFilterOptions = coroutineScope {
val localesDeferred = async { fetchAvailableLocales() } val localesDeferred = async { fetchAvailableLocales() }
val tagsDeferred = async { fetchAvailableTags() } val tagsDeferred = async { fetchAvailableTags() }

@ -16,16 +16,23 @@ import java.util.*
internal class MangaPark(context: MangaLoaderContext) : internal class MangaPark(context: MangaLoaderContext) :
PagedMangaParser(context, MangaParserSource.MANGAPARK, pageSize = 36) { 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> = override val availableSortOrders: Set<SortOrder> =
EnumSet.of(SortOrder.POPULARITY, SortOrder.UPDATED, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING) EnumSet.of(SortOrder.POPULARITY, SortOrder.UPDATED, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.RATING)
override val configKeyDomain = ConfigKey.Domain("mangapark.net")
override val filterCapabilities: MangaListFilterCapabilities override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
isMultipleTagsSupported = true, isMultipleTagsSupported = true,
isTagsExclusionSupported = true, isTagsExclusionSupported = true,
isSearchSupported = true, isSearchSupported = true,
isSearchWithFiltersSupported = true,
isOriginalLocaleSupported = true,
) )
override suspend fun getFilterOptions() = MangaListFilterOptions( 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 { init {
context.cookieJar.insertCookies(domain, "nsfw", "2") context.cookieJar.insertCookies(domain, "nsfw", "2")
} }
@ -73,14 +73,11 @@ internal class MangaPark(context: MangaLoaderContext) :
append(domain) append(domain)
append("/search?page=") append("/search?page=")
append(page.toString()) append(page.toString())
when { filter.query?.let {
!filter.query.isNullOrEmpty() -> {
append("&word=") append("&word=")
append(filter.query.urlEncoded()) append(filter.query.urlEncoded())
} }
else -> {
append("&genres=") append("&genres=")
if (filter.tags.isNotEmpty()) { if (filter.tags.isNotEmpty()) {
appendAll(filter.tags, ",") { it.key } appendAll(filter.tags, ",") { it.key }
@ -132,7 +129,10 @@ internal class MangaPark(context: MangaLoaderContext) :
append("&lang=") append("&lang=")
append(it.language) 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> { private suspend fun parseTags(): Map<String, MangaTag> {
val tagElements = webClient.httpGet("https://$domain/search").parseHtml() val tagElements = webClient.httpGet("https://$domain/search").parseHtml()
.select("div.flex-col:contains(Genres) div.whitespace-nowrap") .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 { private fun parseChapterDate(dateFormat: DateFormat, date: String?): Long {
val d = date?.lowercase() ?: return 0 val d = date?.lowercase() ?: return 0
return when { return when {
d.endsWith(" ago") -> parseRelativeDate(date) WordSet(" ago").endsWith(d) -> {
d.startsWith("just now") -> Calendar.getInstance().apply { parseRelativeDate(d)
}
WordSet("just now").startsWith(d) -> {
Calendar.getInstance().apply {
set(Calendar.HOUR_OF_DAY, 0) set(Calendar.HOUR_OF_DAY, 0)
set(Calendar.MINUTE, 0) set(Calendar.MINUTE, 0)
set(Calendar.SECOND, 0) set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0) set(Calendar.MILLISECOND, 0)
}.timeInMillis }.timeInMillis
}
else -> dateFormat.tryParse(date) else -> dateFormat.tryParse(date)
} }

@ -44,6 +44,7 @@ internal abstract class NineMangaParser(
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
isMultipleTagsSupported = true, isMultipleTagsSupported = true,
isTagsExclusionSupported = true, isTagsExclusionSupported = true,
isSearchWithFiltersSupported = true,
isSearchSupported = true, isSearchSupported = true,
) )
@ -69,19 +70,18 @@ internal abstract class NineMangaParser(
val url = buildString { val url = buildString {
append("https://") append("https://")
append(domain) append(domain)
when {
!filter.query.isNullOrEmpty() -> { if (filter.tags.isNotEmpty() || filter.tagsExclude.isNotEmpty() || filter.states.isNotEmpty() || !filter.query.isNullOrEmpty()) {
append("/search/?name_sel=&wd=") append("/search/")
append("?page=")
append(page.toString())
filter.query?.let {
append("&name_sel=contain&wd=")
append(filter.query.urlEncoded()) append(filter.query.urlEncoded())
append("&page=")
append(page)
append(".html")
} }
else -> { append("&category_id=")
if (filter.tags.isNotEmpty() || filter.tagsExclude.isNotEmpty() || filter.states.isNotEmpty()) {
append("/search/?category_id=")
append(filter.tags.joinToString(separator = ",") { it.key }) append(filter.tags.joinToString(separator = ",") { it.key })
append("&out_category_id=") append("&out_category_id=")
@ -95,13 +95,10 @@ internal abstract class NineMangaParser(
else -> append("either") else -> append("either")
} }
} }
append("&page=")
} else { } else {
append("/category/index_") append("/category/index_")
}
append(page.toString()) append(page.toString())
append(".html")
}
} }
} }
val doc = webClient.httpGet(url).parseHtml() val doc = webClient.httpGet(url).parseHtml()

@ -43,10 +43,16 @@ internal abstract class AnimeBootstrapParser(
override val filterCapabilities: MangaListFilterCapabilities override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
isSearchSupported = true, isSearchSupported = true,
isSearchWithFiltersSupported = true,
) )
override suspend fun getFilterOptions() = MangaListFilterOptions( override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(), availableTags = fetchAvailableTags(),
availableContentTypes = EnumSet.of(
ContentType.MANGA,
ContentType.MANHWA,
ContentType.MANHUA,
),
) )
override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
@ -58,19 +64,28 @@ internal abstract class AnimeBootstrapParser(
append(page.toString()) append(page.toString())
append("&type=all") append("&type=all")
when { filter.query?.let {
!filter.query.isNullOrEmpty() -> {
append("&search=") append("&search=")
append(filter.query.urlEncoded()) append(filter.query.urlEncoded())
} }
else -> {
filter.tags.oneOrThrowIfMany()?.let { filter.tags.oneOrThrowIfMany()?.let {
append("&categorie=") append("&categorie=")
append(it.key) 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=") append("&sort=")
when (order) { when (order) {
SortOrder.POPULARITY -> append("view") SortOrder.POPULARITY -> append("view")
@ -81,8 +96,6 @@ internal abstract class AnimeBootstrapParser(
} }
} }
}
}
val doc = webClient.httpGet(url).parseHtml() val doc = webClient.httpGet(url).parseHtml()
return doc.select("div.col-6 div.product__item").map { div -> return doc.select("div.col-6 div.product__item").map { div ->

@ -4,6 +4,7 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import org.koitharu.kotatsu.parsers.Broken
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.MangaSourceParser
import org.koitharu.kotatsu.parsers.PagedMangaParser import org.koitharu.kotatsu.parsers.PagedMangaParser
@ -15,6 +16,7 @@ import org.koitharu.kotatsu.parsers.util.json.mapJSONIndexed
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@Broken
@MangaSourceParser("FLIXSCANS", "FlixScans.net", "ar") @MangaSourceParser("FLIXSCANS", "FlixScans.net", "ar")
internal class FlixScans(context: MangaLoaderContext) : PagedMangaParser(context, MangaParserSource.FLIXSCANS, 18) { 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 override val filterCapabilities: MangaListFilterCapabilities
get() = MangaListFilterCapabilities( get() = MangaListFilterCapabilities(
isSearchSupported = true, isSearchSupported = true,
isSearchWithFiltersSupported = true,
) )
override suspend fun getFilterOptions() = MangaListFilterOptions( override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = fetchAvailableTags(), availableTags = fetchAvailableTags(),
availableStates = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED, MangaState.ABANDONED), 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> { override suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
val url = buildString { val url = buildString {
append("https://") append("https://")
append(domain) append(domain)
when {
!filter.query.isNullOrEmpty() -> { if (order == SortOrder.UPDATED) {
append("/?search=") if (filter.tags.isNotEmpty() || filter.demographics.isNotEmpty()) {
append(filter.query.urlEncoded()) throw IllegalArgumentException("Updated sorting does not support other sorting filters")
if (page > 1) {
append("&page=")
append(page.toString())
}
} }
append("/?page=")
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()) append(page.toString())
}
append("&")
} else { } else {
when (order) { append("/series?page=")
SortOrder.POPULARITY -> append("/series")
SortOrder.UPDATED -> append("/")
else -> append("/")
}
if (page > 1) {
append("?page=")
append(page.toString()) append(page.toString())
append("&")
} else { filter.query?.let {
append("?") append("&search=")
append(filter.query.urlEncoded())
} }
filter.tags.oneOrThrowIfMany()?.let {
append("&genre=")
append(it.key)
}
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 { filter.states.oneOrThrowIfMany()?.let {
append("status=") append("status=")
append( append(
@ -89,8 +91,6 @@ internal class TeamXNovel(context: MangaLoaderContext) : PagedMangaParser(contex
} }
} }
} }
}
}
val doc = webClient.httpGet(url).parseHtml() val doc = webClient.httpGet(url).parseHtml()
return doc.select("div.listupd .bs .bsx").ifEmpty { return doc.select("div.listupd .bs .bsx").ifEmpty {
doc.select("div.post-body .box") doc.select("div.post-body .box")

@ -252,7 +252,9 @@ internal abstract class FmreaderParser(
val d = date?.lowercase() ?: return 0 val d = date?.lowercase() ?: return 0
return when { 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) -> { WordSet("today").startsWith(d) -> {
Calendar.getInstance().apply { Calendar.getInstance().apply {
@ -281,18 +283,25 @@ internal abstract class FmreaderParser(
return when { return when {
WordSet("second") WordSet("second")
.anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
WordSet("min", "minute", "minutes", "minuto", "minutos") WordSet("min", "minute", "minutes", "minuto", "minutos")
.anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
WordSet("hour", "hours", "hora", "horas", "h") WordSet("hour", "hours", "hora", "horas", "h")
.anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
WordSet("day", "days", "día", "dia") WordSet("day", "days", "día", "dia")
.anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
WordSet("week", "weeks", "semana", "semanas") WordSet("week", "weeks", "semana", "semanas")
.anyWordIn(date) -> cal.apply { add(Calendar.WEEK_OF_YEAR, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.WEEK_OF_YEAR, -number) }.timeInMillis
WordSet("month", "months", "mes", "meses") WordSet("month", "months", "mes", "meses")
.anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
WordSet("year", "año", "años") WordSet("year", "año", "años")
.anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
else -> 0 else -> 0
} }
} }

@ -267,7 +267,9 @@ internal abstract class KeyoappParser(
val d = date?.lowercase() ?: return 0 val d = date?.lowercase() ?: return 0
return when { return when {
WordSet(" ago").endsWith(d) -> { parseRelativeDate(d) } WordSet(" ago").endsWith(d) -> {
parseRelativeDate(d)
}
WordSet("today").startsWith(d) -> { WordSet("today").startsWith(d) -> {
Calendar.getInstance().apply { Calendar.getInstance().apply {
@ -296,16 +298,22 @@ internal abstract class KeyoappParser(
return when { return when {
WordSet("second") WordSet("second")
.anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
WordSet("minute", "minutes") WordSet("minute", "minutes")
.anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
WordSet("hour", "hours") WordSet("hour", "hours")
.anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
WordSet("day", "days") WordSet("day", "days")
.anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
WordSet("month", "months") WordSet("month", "months")
.anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
WordSet("year") WordSet("year")
.anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
else -> 0 else -> 0
} }
} }

@ -40,6 +40,8 @@ internal abstract class MadaraParser(
isMultipleTagsSupported = true, isMultipleTagsSupported = true,
isTagsExclusionSupported = !withoutAjax, isTagsExclusionSupported = !withoutAjax,
isSearchSupported = true, isSearchSupported = true,
isSearchWithFiltersSupported = true,
isYearSupported = true,
) )
override suspend fun getFilterOptions() = MangaListFilterOptions( override suspend fun getFilterOptions() = MangaListFilterOptions(
@ -51,8 +53,7 @@ internal abstract class MadaraParser(
override val availableSortOrders: Set<SortOrder> = setupAvailableSortOrders() override val availableSortOrders: Set<SortOrder> = setupAvailableSortOrders()
private fun setupAvailableSortOrders(): Set<SortOrder> { private fun setupAvailableSortOrders(): Set<SortOrder> {
return if(!withoutAjax) return if (!withoutAjax) {
{
EnumSet.of( EnumSet.of(
SortOrder.UPDATED, SortOrder.UPDATED,
SortOrder.UPDATED_ASC, SortOrder.UPDATED_ASC,
@ -64,10 +65,17 @@ internal abstract class MadaraParser(
SortOrder.ALPHABETICAL_DESC, SortOrder.ALPHABETICAL_DESC,
SortOrder.RATING, SortOrder.RATING,
SortOrder.RATING_ASC, 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("https://")
append(domain) append(domain)
when {
!filter.query.isNullOrEmpty() -> {
if (pages > 1) { if (pages > 1) {
append("/page/") append("/page/")
append(pages.toString()) append(pages.toString())
} }
append("/?s=") append("/?s=")
append(filter.query.urlEncoded())
append("&post_type=wp-manga")
}
else -> { append(filter.query?.urlEncoded())
if (pages > 1) {
append("/page/")
append(pages.toString())
}
append("/?s=")
//Support query
//append(filter.query.urlEncoded())
append("&post_type=wp-manga") append("&post_type=wp-manga")
@ -273,11 +267,10 @@ internal abstract class MadaraParser(
) )
} }
// Support year if (filter.year != 0) {
//filter.year?.let { append("&release=")
// append("&release=") append(filter.year.toString())
// append(filter.year) }
//}
// Support author // Support author
//filter.author?.let { //filter.author?.let {
@ -299,10 +292,8 @@ internal abstract class MadaraParser(
SortOrder.NEWEST -> append("new-manga") SortOrder.NEWEST -> append("new-manga")
SortOrder.ALPHABETICAL -> append("alphabet") SortOrder.ALPHABETICAL -> append("alphabet")
SortOrder.RATING -> append("rating") SortOrder.RATING -> append("rating")
// SortOrder.RELEVANCE -> {} SortOrder.RELEVANCE -> {}
else -> append("latest") else -> {}
}
}
} }
} }
return parseMangaList(webClient.httpGet(url).parseHtml()) return parseMangaList(webClient.httpGet(url).parseHtml())
@ -312,20 +303,10 @@ internal abstract class MadaraParser(
payload["page"] = page.toString() payload["page"] = page.toString()
when { filter.query?.let {
!filter.query.isNullOrEmpty() -> {
payload["vars[s]"] = filter.query.urlEncoded() payload["vars[s]"] = filter.query.urlEncoded()
} }
else -> {
// Support query
// filter.query.let {
// payload["vars[s]"] = filter.query.urlEncoded()
// }
if (filter.tags.isNotEmpty()) { if (filter.tags.isNotEmpty()) {
payload["vars[tax_query][0][taxonomy]"] = "wp-manga-genre" payload["vars[tax_query][0][taxonomy]"] = "wp-manga-genre"
payload["vars[tax_query][0][field]"] = "slug" payload["vars[tax_query][0][field]"] = "slug"
@ -344,12 +325,11 @@ internal abstract class MadaraParser(
payload["vars[tax_query][1][operator]"] = "NOT IN" payload["vars[tax_query][1][operator]"] = "NOT IN"
} }
// Support year if (filter.year != 0) {
//filter.year?.let { payload["vars[tax_query][2][taxonomy]"] = "wp-manga-release"
// payload["vars[tax_query][2][taxonomy]"] = wp-manga-release payload["vars[tax_query][2][field]"] = "slug"
// payload["vars[tax_query][2][field]"] = slug payload["vars[tax_query][2][terms][]"] = filter.year.toString()
// payload["vars[tax_query][2][terms][]"] = filter.year }
//}
// Support author // Support author
// filter.author.let { // filter.author.let {
@ -368,8 +348,7 @@ internal abstract class MadaraParser(
// payload["vars[tax_query][4][operator]"] = "IN" // payload["vars[tax_query][4][operator]"] = "IN"
//} //}
/// for add filter.year need to add || filter.year if (filter.tags.isNotEmpty() || filter.tagsExclude.isNotEmpty() || filter.year != 0) {
if (filter.tags.isNotEmpty() || filter.tagsExclude.isNotEmpty()) {
payload["vars[tax_query][relation]"] = "AND" payload["vars[tax_query][relation]"] = "AND"
} }
@ -434,11 +413,11 @@ internal abstract class MadaraParser(
payload["vars[orderby][query_total_reviews]"] = "ASC" payload["vars[orderby][query_total_reviews]"] = "ASC"
} }
// SortOrder.RELEVANCE -> { SortOrder.RELEVANCE -> {
// payload["vars[orderby]"] = "" payload["vars[orderby]"] = ""
// } }
else -> payload["vars[meta_key]"] = "_latest_update" else -> payload["vars[orderby]"] = ""
} }
filter.states.forEach { filter.states.forEach {
@ -463,8 +442,6 @@ internal abstract class MadaraParser(
else -> "" else -> ""
} }
} }
}
}
return parseMangaList( return parseMangaList(
webClient.httpPost( webClient.httpPost(
@ -749,12 +726,14 @@ internal abstract class MadaraParser(
val d = date?.lowercase() ?: return 0 val d = date?.lowercase() ?: return 0
return when { return when {
WordSet(" ago", "atrás", " hace", " publicado"," назад", " önce", " trước", "مضت", WordSet(
" h", " d", " días", " jour", " horas", " heure", " mins", " minutos", " minute", " mois").endsWith(d) -> { " ago", "atrás", " hace", " publicado", " назад", " önce", " trước", "مضت",
" h", " d", " días", " jour", " horas", " heure", " mins", " minutos", " minute", " mois",
).endsWith(d) -> {
parseRelativeDate(d) parseRelativeDate(d)
} }
WordSet("", "منذ", "il y a" ).startsWith(d) -> { WordSet("", "منذ", "il y a").startsWith(d) -> {
parseRelativeDate(d) parseRelativeDate(d)
} }
@ -805,16 +784,22 @@ internal abstract class MadaraParser(
return when { return when {
WordSet("detik", "segundo", "second", "ثوان") WordSet("detik", "segundo", "second", "ثوان")
.anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
WordSet("menit", "dakika", "min", "minute", "minutes", "minuto", "mins", "phút", "минут", "دقيقة") WordSet("menit", "dakika", "min", "minute", "minutes", "minuto", "mins", "phút", "минут", "دقيقة")
.anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
WordSet("jam", "saat", "heure", "hora", "horas", "hour", "hours", "h", "ساعات", "ساعة") WordSet("jam", "saat", "heure", "hora", "horas", "hour", "hours", "h", "ساعات", "ساعة")
.anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
WordSet("hari", "gün", "jour", "día", "dia", "day", "days", "d", "день") WordSet("hari", "gün", "jour", "día", "dia", "day", "days", "d", "день")
.anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
WordSet("month", "months", "أشهر", "mois") WordSet("month", "months", "أشهر", "mois")
.anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
WordSet("year") WordSet("year")
.anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
else -> 0 else -> 0
} }
} }

@ -274,7 +274,9 @@ internal abstract class MadthemeParser(
val d = date?.lowercase() ?: return 0 val d = date?.lowercase() ?: return 0
return when { return when {
WordSet(" ago", " h", " d").endsWith(d) -> { parseRelativeDate(d) } WordSet(" ago", " h", " d").endsWith(d) -> {
parseRelativeDate(d)
}
WordSet("today").startsWith(d) -> { WordSet("today").startsWith(d) -> {
Calendar.getInstance().apply { Calendar.getInstance().apply {
@ -303,16 +305,22 @@ internal abstract class MadthemeParser(
return when { return when {
WordSet("second") WordSet("second")
.anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
WordSet("min", "minute", "minutes") WordSet("min", "minute", "minutes")
.anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
WordSet("hour", "hours", "h") WordSet("hour", "hours", "h")
.anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
WordSet("day", "days") WordSet("day", "days")
.anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
WordSet("month", "months") WordSet("month", "months")
.anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
WordSet("year") WordSet("year")
.anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
else -> 0 else -> 0
} }
} }

@ -18,7 +18,7 @@ internal class Hanman18(context: MangaLoaderContext) :
Manga18Parser(context, MangaParserSource.HANMAN18, "hanman18.com") { Manga18Parser(context, MangaParserSource.HANMAN18, "hanman18.com") {
override suspend fun getFilterOptions() = MangaListFilterOptions( override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = emptySet() availableTags = emptySet(),
) )
override suspend fun getChapters(doc: Document): List<MangaChapter> { override suspend fun getChapters(doc: Document): List<MangaChapter> {

@ -265,7 +265,9 @@ internal abstract class MangaboxParser(
protected fun parseChapterDate(dateFormat: DateFormat, date: String?): Long { protected fun parseChapterDate(dateFormat: DateFormat, date: String?): Long {
val d = date?.lowercase() ?: return 0 val d = date?.lowercase() ?: return 0
return when { return when {
WordSet(" ago", " h", " d").endsWith(d) -> { parseRelativeDate(d) } WordSet(" ago", " h", " d").endsWith(d) -> {
parseRelativeDate(d)
}
WordSet("today").startsWith(d) -> { WordSet("today").startsWith(d) -> {
Calendar.getInstance().apply { Calendar.getInstance().apply {
@ -294,16 +296,22 @@ internal abstract class MangaboxParser(
return when { return when {
WordSet("second") WordSet("second")
.anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
WordSet("min", "minute", "minutes") WordSet("min", "minute", "minutes")
.anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
WordSet("hour", "hours", "h") WordSet("hour", "hours", "h")
.anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
WordSet("day", "days") WordSet("day", "days")
.anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
WordSet("month", "months") WordSet("month", "months")
.anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
WordSet("year") WordSet("year")
.anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
else -> 0 else -> 0
} }
} }

@ -243,8 +243,14 @@ internal abstract class OtakuSanctuaryParser(
protected fun parseChapterDate(dateFormat: DateFormat, date: String?): Long { protected fun parseChapterDate(dateFormat: DateFormat, date: String?): Long {
val d = date?.lowercase() ?: return 0 val d = date?.lowercase() ?: return 0
return when { return when {
WordSet(" ago", " atrás").endsWith(d) -> { parseRelativeDate(d) } WordSet(" ago", " atrás").endsWith(d) -> {
WordSet("cách đây ").startsWith(d) -> { parseRelativeDate(d) } parseRelativeDate(d)
}
WordSet("cách đây ").startsWith(d) -> {
parseRelativeDate(d)
}
else -> dateFormat.tryParse(date) else -> dateFormat.tryParse(date)
} }
} }
@ -255,16 +261,22 @@ internal abstract class OtakuSanctuaryParser(
return when { return when {
WordSet("second", "giây") WordSet("second", "giây")
.anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
WordSet("min", "minute", "minutes", "phút") WordSet("min", "minute", "minutes", "phút")
.anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
WordSet("tiếng", "hour", "hours") WordSet("tiếng", "hour", "hours")
.anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
WordSet("day", "days", "d", "ngày") WordSet("day", "days", "d", "ngày")
.anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
WordSet("month", "months") WordSet("month", "months")
.anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
WordSet("year") WordSet("year")
.anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
else -> 0 else -> 0
} }
} }

@ -13,8 +13,9 @@ internal class MangaFr(context: MangaLoaderContext) :
override val listUrl = "/series" override val listUrl = "/series"
override suspend fun getFilterOptions() = MangaListFilterOptions( override suspend fun getFilterOptions() = MangaListFilterOptions(
availableTags = emptySet() availableTags = emptySet(),
) )
override suspend fun getDetails(manga: Manga): Manga { override suspend fun getDetails(manga: Manga): Manga {
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
val dateFormat = SimpleDateFormat("MM-dd-yyyy", sourceLocale) val dateFormat = SimpleDateFormat("MM-dd-yyyy", sourceLocale)

@ -280,7 +280,9 @@ internal abstract class WpComicsParser(
val d = date?.lowercase() ?: return 0 val d = date?.lowercase() ?: return 0
return when { return when {
WordSet(" ago", " trước").endsWith(d) -> { parseRelativeDate(d) } WordSet(" ago", " trước").endsWith(d) -> {
parseRelativeDate(d)
}
WordSet("today").startsWith(d) -> { WordSet("today").startsWith(d) -> {
Calendar.getInstance().apply { Calendar.getInstance().apply {
@ -309,14 +311,19 @@ internal abstract class WpComicsParser(
return when { return when {
WordSet("second", "giây") WordSet("second", "giây")
.anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
WordSet("min", "minute", "minutes", "mins", "phút") WordSet("min", "minute", "minutes", "mins", "phút")
.anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
WordSet("jam", "saat", "heure", "hora", "horas", "hour", "hours", "h", "giờ") WordSet("jam", "saat", "heure", "hora", "horas", "hour", "hours", "h", "giờ")
.anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
WordSet("day", "days", "d", "ngày") WordSet("day", "days", "d", "ngày")
.anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
WordSet("month", "months", "tháng") WordSet("month", "months", "tháng")
.anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
WordSet("year", "năm").anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis WordSet("year", "năm").anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
else -> 0 else -> 0
} }

@ -252,7 +252,9 @@ internal abstract class ZMangaParser(
protected fun parseChapterDate(dateFormat: DateFormat, date: String?): Long { protected fun parseChapterDate(dateFormat: DateFormat, date: String?): Long {
val d = date?.lowercase() ?: return 0 val d = date?.lowercase() ?: return 0
return when { return when {
WordSet(" ago", " h", " d").endsWith(d) -> { parseRelativeDate(d) } WordSet(" ago", " h", " d").endsWith(d) -> {
parseRelativeDate(d)
}
WordSet("today").startsWith(d) -> { WordSet("today").startsWith(d) -> {
Calendar.getInstance().apply { Calendar.getInstance().apply {
@ -282,15 +284,20 @@ internal abstract class ZMangaParser(
return when { return when {
WordSet("second") WordSet("second")
.anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
WordSet("min", "minute", "minutes") WordSet("min", "minute", "minutes")
.anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
WordSet("hour", "hours", "h") WordSet("hour", "hours", "h")
.anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
WordSet("day", "days").anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis WordSet("day", "days").anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
WordSet("month", "months") WordSet("month", "months")
.anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
WordSet("year") WordSet("year")
.anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis .anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
else -> 0 else -> 0
} }
} }

Loading…
Cancel
Save