[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,80 +65,77 @@ internal class ComickFunParser(context: MangaLoaderContext) :
|
||||
.addQueryParameter("tachiyomi", "true")
|
||||
.addQueryParameter("limit", pageSize.toString())
|
||||
.addQueryParameter("page", page.toString())
|
||||
when {
|
||||
!filter.query.isNullOrEmpty() -> {
|
||||
url.addQueryParameter("q", filter.query)
|
||||
}
|
||||
|
||||
else -> {
|
||||
|
||||
filter.tags.forEach {
|
||||
url.addQueryParameter("genres", it.key)
|
||||
}
|
||||
|
||||
filter.tagsExclude.forEach {
|
||||
url.addQueryParameter("excludes", it.key)
|
||||
}
|
||||
|
||||
url.addQueryParameter(
|
||||
"sort",
|
||||
when (order) {
|
||||
SortOrder.POPULARITY -> "view"
|
||||
SortOrder.UPDATED -> "uploaded"
|
||||
SortOrder.NEWEST -> "created_at"
|
||||
SortOrder.RATING -> "rating"
|
||||
else -> "uploaded"
|
||||
},
|
||||
)
|
||||
|
||||
filter.states.oneOrThrowIfMany()?.let {
|
||||
url.addQueryParameter(
|
||||
"status",
|
||||
when (it) {
|
||||
MangaState.ONGOING -> "1"
|
||||
MangaState.FINISHED -> "2"
|
||||
MangaState.ABANDONED -> "3"
|
||||
MangaState.PAUSED -> "4"
|
||||
else -> ""
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if (filter.yearFrom != YEAR_UNKNOWN) {
|
||||
url.addQueryParameter("from", filter.yearFrom.toString())
|
||||
}
|
||||
|
||||
if (filter.yearTo != YEAR_UNKNOWN) {
|
||||
url.addQueryParameter("to", filter.yearTo.toString())
|
||||
}
|
||||
|
||||
filter.types.forEach {
|
||||
url.addQueryParameter(
|
||||
"country",
|
||||
when (it) {
|
||||
ContentType.MANGA -> "jp"
|
||||
ContentType.MANHWA -> "kr"
|
||||
ContentType.MANHUA -> "cn"
|
||||
ContentType.OTHER -> "others"
|
||||
else -> ""
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
filter.demographics.forEach {
|
||||
url.addQueryParameter(
|
||||
"demographic",
|
||||
when (it) {
|
||||
Demographic.SHOUNEN -> "1"
|
||||
Demographic.SHOUJO -> "2"
|
||||
Demographic.SEINEN -> "3"
|
||||
Demographic.JOSEI -> "4"
|
||||
Demographic.NONE -> "5"
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
filter.query?.let {
|
||||
url.addQueryParameter("q", filter.query)
|
||||
}
|
||||
|
||||
filter.tags.forEach {
|
||||
url.addQueryParameter("genres", it.key)
|
||||
}
|
||||
|
||||
filter.tagsExclude.forEach {
|
||||
url.addQueryParameter("excludes", it.key)
|
||||
}
|
||||
|
||||
url.addQueryParameter(
|
||||
"sort",
|
||||
when (order) {
|
||||
SortOrder.NEWEST -> "created_at"
|
||||
SortOrder.POPULARITY -> "view"
|
||||
SortOrder.RATING -> "rating"
|
||||
SortOrder.UPDATED -> "uploaded"
|
||||
else -> "uploaded"
|
||||
},
|
||||
)
|
||||
|
||||
filter.states.oneOrThrowIfMany()?.let {
|
||||
url.addQueryParameter(
|
||||
"status",
|
||||
when (it) {
|
||||
MangaState.ONGOING -> "1"
|
||||
MangaState.FINISHED -> "2"
|
||||
MangaState.ABANDONED -> "3"
|
||||
MangaState.PAUSED -> "4"
|
||||
else -> ""
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if (filter.yearFrom != YEAR_UNKNOWN) {
|
||||
url.addQueryParameter("from", filter.yearFrom.toString())
|
||||
}
|
||||
|
||||
if (filter.yearTo != YEAR_UNKNOWN) {
|
||||
url.addQueryParameter("to", filter.yearTo.toString())
|
||||
}
|
||||
|
||||
filter.types.forEach {
|
||||
url.addQueryParameter(
|
||||
"country",
|
||||
when (it) {
|
||||
ContentType.MANGA -> "jp"
|
||||
ContentType.MANHWA -> "kr"
|
||||
ContentType.MANHUA -> "cn"
|
||||
ContentType.OTHER -> "others"
|
||||
else -> ""
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
filter.demographics.forEach {
|
||||
url.addQueryParameter(
|
||||
"demographic",
|
||||
when (it) {
|
||||
Demographic.SHOUNEN -> "1"
|
||||
Demographic.SHOUJO -> "2"
|
||||
Demographic.SEINEN -> "3"
|
||||
Demographic.JOSEI -> "4"
|
||||
Demographic.NONE -> "5"
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
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,67 +73,67 @@ internal class MangaPark(context: MangaLoaderContext) :
|
||||
append(domain)
|
||||
append("/search?page=")
|
||||
append(page.toString())
|
||||
when {
|
||||
!filter.query.isNullOrEmpty() -> {
|
||||
append("&word=")
|
||||
append(filter.query.urlEncoded())
|
||||
}
|
||||
filter.query?.let {
|
||||
append("&word=")
|
||||
append(filter.query.urlEncoded())
|
||||
}
|
||||
|
||||
else -> {
|
||||
append("&genres=")
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
appendAll(filter.tags, ",") { it.key }
|
||||
}
|
||||
|
||||
append("&genres=")
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
appendAll(filter.tags, ",") { it.key }
|
||||
}
|
||||
append("|")
|
||||
if (filter.tagsExclude.isNotEmpty()) {
|
||||
appendAll(filter.tagsExclude, ",") { it.key }
|
||||
}
|
||||
|
||||
append("|")
|
||||
if (filter.tagsExclude.isNotEmpty()) {
|
||||
appendAll(filter.tagsExclude, ",") { it.key }
|
||||
}
|
||||
|
||||
if (filter.contentRating.isNotEmpty()) {
|
||||
filter.contentRating.oneOrThrowIfMany()?.let {
|
||||
append(
|
||||
when (it) {
|
||||
ContentRating.SAFE -> append(",gore,bloody,violence,ecchi,adult,mature,smut,hentai")
|
||||
else -> append("")
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
filter.states.oneOrThrowIfMany()?.let {
|
||||
append("&status=")
|
||||
append(
|
||||
when (it) {
|
||||
MangaState.ONGOING -> "ongoing"
|
||||
MangaState.FINISHED -> "completed"
|
||||
MangaState.PAUSED -> "hiatus"
|
||||
MangaState.ABANDONED -> "cancelled"
|
||||
MangaState.UPCOMING -> "pending"
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
append("&sortby=")
|
||||
if (filter.contentRating.isNotEmpty()) {
|
||||
filter.contentRating.oneOrThrowIfMany()?.let {
|
||||
append(
|
||||
when (order) {
|
||||
SortOrder.POPULARITY -> "views_d000"
|
||||
SortOrder.UPDATED -> "field_update"
|
||||
SortOrder.NEWEST -> "field_create"
|
||||
SortOrder.ALPHABETICAL -> "field_name"
|
||||
SortOrder.RATING -> "field_score"
|
||||
else -> ""
|
||||
|
||||
when (it) {
|
||||
ContentRating.SAFE -> append(",gore,bloody,violence,ecchi,adult,mature,smut,hentai")
|
||||
else -> append("")
|
||||
},
|
||||
)
|
||||
|
||||
filter.locale?.let {
|
||||
append("&lang=")
|
||||
append(it.language)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filter.states.oneOrThrowIfMany()?.let {
|
||||
append("&status=")
|
||||
append(
|
||||
when (it) {
|
||||
MangaState.ONGOING -> "ongoing"
|
||||
MangaState.FINISHED -> "completed"
|
||||
MangaState.PAUSED -> "hiatus"
|
||||
MangaState.ABANDONED -> "cancelled"
|
||||
MangaState.UPCOMING -> "pending"
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
append("&sortby=")
|
||||
append(
|
||||
when (order) {
|
||||
SortOrder.POPULARITY -> "views_d000"
|
||||
SortOrder.UPDATED -> "field_update"
|
||||
SortOrder.NEWEST -> "field_create"
|
||||
SortOrder.ALPHABETICAL -> "field_name"
|
||||
SortOrder.RATING -> "field_score"
|
||||
else -> ""
|
||||
|
||||
},
|
||||
)
|
||||
|
||||
filter.locale?.let {
|
||||
append("&lang=")
|
||||
append(it.language)
|
||||
}
|
||||
|
||||
filter.originalLocale?.let {
|
||||
append("&orig=")
|
||||
append(it.language)
|
||||
}
|
||||
}
|
||||
|
||||
val doc = webClient.httpGet(url).parseHtml()
|
||||
@@ -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 {
|
||||
set(Calendar.HOUR_OF_DAY, 0)
|
||||
set(Calendar.MINUTE, 0)
|
||||
set(Calendar.SECOND, 0)
|
||||
set(Calendar.MILLISECOND, 0)
|
||||
}.timeInMillis
|
||||
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,39 +70,35 @@ 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 -> {
|
||||
append("&category_id=")
|
||||
append(filter.tags.joinToString(separator = ",") { it.key })
|
||||
|
||||
if (filter.tags.isNotEmpty() || filter.tagsExclude.isNotEmpty() || filter.states.isNotEmpty()) {
|
||||
append("/search/?category_id=")
|
||||
append(filter.tags.joinToString(separator = ",") { it.key })
|
||||
append("&out_category_id=")
|
||||
append(filter.tagsExclude.joinToString(separator = ",") { it.key })
|
||||
|
||||
append("&out_category_id=")
|
||||
append(filter.tagsExclude.joinToString(separator = ",") { it.key })
|
||||
|
||||
filter.states.oneOrThrowIfMany()?.let {
|
||||
append("&completed_series=")
|
||||
when (it) {
|
||||
MangaState.ONGOING -> append("no")
|
||||
MangaState.FINISHED -> append("yes")
|
||||
else -> append("either")
|
||||
}
|
||||
}
|
||||
append("&page=")
|
||||
} else {
|
||||
append("/category/index_")
|
||||
filter.states.oneOrThrowIfMany()?.let {
|
||||
append("&completed_series=")
|
||||
when (it) {
|
||||
MangaState.ONGOING -> append("no")
|
||||
MangaState.FINISHED -> append("yes")
|
||||
else -> append("either")
|
||||
}
|
||||
append(page.toString())
|
||||
append(".html")
|
||||
}
|
||||
|
||||
} else {
|
||||
append("/category/index_")
|
||||
append(page.toString())
|
||||
}
|
||||
}
|
||||
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,30 +64,37 @@ internal abstract class AnimeBootstrapParser(
|
||||
append(page.toString())
|
||||
append("&type=all")
|
||||
|
||||
when {
|
||||
!filter.query.isNullOrEmpty() -> {
|
||||
append("&search=")
|
||||
append(filter.query.urlEncoded())
|
||||
}
|
||||
|
||||
else -> {
|
||||
|
||||
filter.tags.oneOrThrowIfMany()?.let {
|
||||
append("&categorie=")
|
||||
append(it.key)
|
||||
}
|
||||
|
||||
append("&sort=")
|
||||
when (order) {
|
||||
SortOrder.POPULARITY -> append("view")
|
||||
SortOrder.UPDATED -> append("updated")
|
||||
SortOrder.ALPHABETICAL -> append("default")
|
||||
SortOrder.NEWEST -> append("published")
|
||||
else -> append("updated")
|
||||
}
|
||||
|
||||
}
|
||||
filter.query?.let {
|
||||
append("&search=")
|
||||
append(filter.query.urlEncoded())
|
||||
}
|
||||
|
||||
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")
|
||||
SortOrder.UPDATED -> append("updated")
|
||||
SortOrder.ALPHABETICAL -> append("default")
|
||||
SortOrder.NEWEST -> append("published")
|
||||
else -> append("updated")
|
||||
}
|
||||
|
||||
}
|
||||
val doc = webClient.httpGet(url).parseHtml()
|
||||
|
||||
|
||||
@@ -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,66 +28,66 @@ 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())
|
||||
}
|
||||
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.tags.oneOrThrowIfMany()?.let {
|
||||
append("&genre=")
|
||||
append(it.key)
|
||||
}
|
||||
|
||||
if (order == SortOrder.POPULARITY || filter.tags.isNotEmpty()) {
|
||||
filter.states.oneOrThrowIfMany()?.let {
|
||||
append("status=")
|
||||
append(
|
||||
when (it) {
|
||||
MangaState.ONGOING -> "مستمرة"
|
||||
MangaState.FINISHED -> "مكتمل"
|
||||
MangaState.ABANDONED -> "متوقف"
|
||||
else -> "مستمرة"
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
filter.types.forEach {
|
||||
append("&type=")
|
||||
append(
|
||||
when (it) {
|
||||
ContentType.MANGA -> "مانجا ياباني"
|
||||
ContentType.MANHWA -> "مانهوا كورية"
|
||||
ContentType.MANHUA -> "مانها صيني"
|
||||
else -> ""
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
filter.states.oneOrThrowIfMany()?.let {
|
||||
append("status=")
|
||||
append(
|
||||
when (it) {
|
||||
MangaState.ONGOING -> "مستمرة"
|
||||
MangaState.FINISHED -> "مكتمل"
|
||||
MangaState.ABANDONED -> "متوقف"
|
||||
else -> "مستمرة"
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,91 +227,74 @@ internal abstract class MadaraParser(
|
||||
append("https://")
|
||||
append(domain)
|
||||
|
||||
when {
|
||||
if (pages > 1) {
|
||||
append("/page/")
|
||||
append(pages.toString())
|
||||
}
|
||||
append("/?s=")
|
||||
|
||||
!filter.query.isNullOrEmpty() -> {
|
||||
if (pages > 1) {
|
||||
append("/page/")
|
||||
append(pages.toString())
|
||||
}
|
||||
append("/?s=")
|
||||
append(filter.query.urlEncoded())
|
||||
append("&post_type=wp-manga")
|
||||
append(filter.query?.urlEncoded())
|
||||
|
||||
append("&post_type=wp-manga")
|
||||
|
||||
// Known bug: in some cases, if there are no manga with the associated tags, the source returns the full list of manga
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
filter.tags.forEach {
|
||||
append("&genre[]=")
|
||||
append(it.key)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
if (pages > 1) {
|
||||
append("/page/")
|
||||
append(pages.toString())
|
||||
}
|
||||
append("/?s=")
|
||||
|
||||
//Support query
|
||||
//append(filter.query.urlEncoded())
|
||||
|
||||
append("&post_type=wp-manga")
|
||||
|
||||
// Known bug: in some cases, if there are no manga with the associated tags, the source returns the full list of manga
|
||||
if (filter.tags.isNotEmpty()) {
|
||||
filter.tags.forEach {
|
||||
append("&genre[]=")
|
||||
append(it.key)
|
||||
}
|
||||
}
|
||||
|
||||
filter.states.forEach {
|
||||
append("&status[]=")
|
||||
when (it) {
|
||||
MangaState.ONGOING -> append("on-going")
|
||||
MangaState.FINISHED -> append("end")
|
||||
MangaState.ABANDONED -> append("canceled")
|
||||
MangaState.PAUSED -> append("on-hold")
|
||||
MangaState.UPCOMING -> append("upcoming")
|
||||
}
|
||||
}
|
||||
|
||||
filter.contentRating.oneOrThrowIfMany()?.let {
|
||||
append("&adult=")
|
||||
append(
|
||||
when (it) {
|
||||
ContentRating.SAFE -> "0"
|
||||
ContentRating.ADULT -> "1"
|
||||
else -> ""
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// Support year
|
||||
//filter.year?.let {
|
||||
// append("&release=")
|
||||
// append(filter.year)
|
||||
//}
|
||||
|
||||
// Support author
|
||||
//filter.author?.let {
|
||||
// append("&author=")
|
||||
// append(filter.author)
|
||||
//}
|
||||
|
||||
// Support artist
|
||||
//filter.artist?.let {
|
||||
// append("&artist=")
|
||||
// append(filter.artist)
|
||||
//}
|
||||
|
||||
|
||||
append("&m_orderby=")
|
||||
when (order) {
|
||||
SortOrder.POPULARITY -> append("views")
|
||||
SortOrder.UPDATED -> append("latest")
|
||||
SortOrder.NEWEST -> append("new-manga")
|
||||
SortOrder.ALPHABETICAL -> append("alphabet")
|
||||
SortOrder.RATING -> append("rating")
|
||||
// SortOrder.RELEVANCE -> {}
|
||||
else -> append("latest")
|
||||
}
|
||||
filter.states.forEach {
|
||||
append("&status[]=")
|
||||
when (it) {
|
||||
MangaState.ONGOING -> append("on-going")
|
||||
MangaState.FINISHED -> append("end")
|
||||
MangaState.ABANDONED -> append("canceled")
|
||||
MangaState.PAUSED -> append("on-hold")
|
||||
MangaState.UPCOMING -> append("upcoming")
|
||||
}
|
||||
}
|
||||
|
||||
filter.contentRating.oneOrThrowIfMany()?.let {
|
||||
append("&adult=")
|
||||
append(
|
||||
when (it) {
|
||||
ContentRating.SAFE -> "0"
|
||||
ContentRating.ADULT -> "1"
|
||||
else -> ""
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if (filter.year != 0) {
|
||||
append("&release=")
|
||||
append(filter.year.toString())
|
||||
}
|
||||
|
||||
// Support author
|
||||
//filter.author?.let {
|
||||
// append("&author=")
|
||||
// append(filter.author)
|
||||
//}
|
||||
|
||||
// Support artist
|
||||
//filter.artist?.let {
|
||||
// append("&artist=")
|
||||
// append(filter.artist)
|
||||
//}
|
||||
|
||||
|
||||
append("&m_orderby=")
|
||||
when (order) {
|
||||
SortOrder.POPULARITY -> append("views")
|
||||
SortOrder.UPDATED -> append("latest")
|
||||
SortOrder.NEWEST -> append("new-manga")
|
||||
SortOrder.ALPHABETICAL -> append("alphabet")
|
||||
SortOrder.RATING -> append("rating")
|
||||
SortOrder.RELEVANCE -> {}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
return parseMangaList(webClient.httpGet(url).parseHtml())
|
||||
} else {
|
||||
@@ -312,158 +303,144 @@ internal abstract class MadaraParser(
|
||||
|
||||
payload["page"] = page.toString()
|
||||
|
||||
when {
|
||||
filter.query?.let {
|
||||
payload["vars[s]"] = filter.query.urlEncoded()
|
||||
}
|
||||
|
||||
!filter.query.isNullOrEmpty() -> {
|
||||
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"
|
||||
filter.tags.forEachIndexed { i, it ->
|
||||
payload["vars[tax_query][0][terms][$i]"] = it.key
|
||||
}
|
||||
payload["vars[tax_query][0][operator]"] = "IN"
|
||||
}
|
||||
|
||||
if (filter.tagsExclude.isNotEmpty()) {
|
||||
payload["vars[tax_query][1][taxonomy]"] = "wp-manga-genre"
|
||||
payload["vars[tax_query][1][field]"] = "slug"
|
||||
filter.tagsExclude.forEachIndexed { i, it ->
|
||||
payload["vars[tax_query][1][terms][$i]"] = it.key
|
||||
}
|
||||
payload["vars[tax_query][1][operator]"] = "NOT IN"
|
||||
}
|
||||
|
||||
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 {
|
||||
// payload["vars[tax_query][3][taxonomy]"] = "wp-manga-author"
|
||||
// payload["vars[tax_query][3][field]"] = "name"
|
||||
// payload["vars[tax_query][3][terms][0]"] = filter.author
|
||||
// payload["vars[tax_query][3][operator]"] = "IN"
|
||||
//}
|
||||
|
||||
|
||||
// Support artist
|
||||
// filter.artist.let {
|
||||
// payload["vars[tax_query][4][taxonomy]"] = "wp-manga-artist"
|
||||
// payload["vars[tax_query][4][field]"] = "name"
|
||||
// payload["vars[tax_query][4][terms][0]"] = filter.artist
|
||||
// payload["vars[tax_query][4][operator]"] = "IN"
|
||||
//}
|
||||
|
||||
if (filter.tags.isNotEmpty() || filter.tagsExclude.isNotEmpty() || filter.year != 0) {
|
||||
payload["vars[tax_query][relation]"] = "AND"
|
||||
}
|
||||
|
||||
when (order) {
|
||||
SortOrder.POPULARITY -> {
|
||||
payload["vars[meta_key]"] = "_wp_manga_views"
|
||||
payload["vars[orderby]"] = "meta_value_num"
|
||||
payload["vars[order]"] = "desc"
|
||||
}
|
||||
|
||||
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"
|
||||
filter.tags.forEachIndexed { i, it ->
|
||||
payload["vars[tax_query][0][terms][$i]"] = it.key
|
||||
}
|
||||
payload["vars[tax_query][0][operator]"] = "IN"
|
||||
}
|
||||
|
||||
if (filter.tagsExclude.isNotEmpty()) {
|
||||
payload["vars[tax_query][1][taxonomy]"] = "wp-manga-genre"
|
||||
payload["vars[tax_query][1][field]"] = "slug"
|
||||
filter.tagsExclude.forEachIndexed { i, it ->
|
||||
payload["vars[tax_query][1][terms][$i]"] = it.key
|
||||
}
|
||||
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
|
||||
//}
|
||||
|
||||
// Support author
|
||||
// filter.author.let {
|
||||
// payload["vars[tax_query][3][taxonomy]"] = "wp-manga-author"
|
||||
// payload["vars[tax_query][3][field]"] = "name"
|
||||
// payload["vars[tax_query][3][terms][0]"] = filter.author
|
||||
// payload["vars[tax_query][3][operator]"] = "IN"
|
||||
//}
|
||||
|
||||
|
||||
// Support artist
|
||||
// filter.artist.let {
|
||||
// payload["vars[tax_query][4][taxonomy]"] = "wp-manga-artist"
|
||||
// payload["vars[tax_query][4][field]"] = "name"
|
||||
// payload["vars[tax_query][4][terms][0]"] = filter.artist
|
||||
// payload["vars[tax_query][4][operator]"] = "IN"
|
||||
//}
|
||||
|
||||
/// for add filter.year need to add || filter.year
|
||||
if (filter.tags.isNotEmpty() || filter.tagsExclude.isNotEmpty()) {
|
||||
payload["vars[tax_query][relation]"] = "AND"
|
||||
}
|
||||
|
||||
when (order) {
|
||||
SortOrder.POPULARITY -> {
|
||||
payload["vars[meta_key]"] = "_wp_manga_views"
|
||||
payload["vars[orderby]"] = "meta_value_num"
|
||||
payload["vars[order]"] = "desc"
|
||||
}
|
||||
|
||||
SortOrder.POPULARITY_ASC -> {
|
||||
payload["vars[meta_key]"] = "_wp_manga_views"
|
||||
payload["vars[orderby]"] = "meta_value_num"
|
||||
payload["vars[order]"] = "asc"
|
||||
}
|
||||
|
||||
SortOrder.UPDATED -> {
|
||||
payload["vars[meta_key]"] = "_latest_update"
|
||||
payload["vars[orderby]"] = "meta_value_num"
|
||||
payload["vars[order]"] = "desc"
|
||||
}
|
||||
|
||||
SortOrder.UPDATED_ASC -> {
|
||||
payload["vars[meta_key]"] = "_latest_update"
|
||||
payload["vars[orderby]"] = "meta_value_num"
|
||||
payload["vars[order]"] = "asc"
|
||||
}
|
||||
|
||||
SortOrder.NEWEST -> {
|
||||
payload["vars[orderby]"] = "date"
|
||||
payload["vars[order]"] = "desc"
|
||||
}
|
||||
|
||||
SortOrder.NEWEST_ASC -> {
|
||||
payload["vars[orderby]"] = "date"
|
||||
payload["vars[order]"] = "asc"
|
||||
}
|
||||
|
||||
SortOrder.ALPHABETICAL -> {
|
||||
payload["vars[orderby]"] = "post_title"
|
||||
payload["vars[order]"] = "asc"
|
||||
}
|
||||
|
||||
SortOrder.ALPHABETICAL_DESC -> {
|
||||
payload["vars[orderby]"] = "post_title"
|
||||
payload["vars[order]"] = "desc"
|
||||
}
|
||||
|
||||
SortOrder.RATING -> {
|
||||
payload["vars[meta_query][0][query_avarage_reviews][key]"] = "_manga_avarage_reviews"
|
||||
payload["vars[meta_query][0][query_total_reviews][key]"] = "_manga_total_votes"
|
||||
|
||||
payload["vars[orderby][query_avarage_reviews]"] = "DESC"
|
||||
payload["vars[orderby][query_total_reviews]"] = "DESC"
|
||||
}
|
||||
|
||||
SortOrder.RATING_ASC -> {
|
||||
payload["vars[meta_query][0][query_avarage_reviews][key]"] = "_manga_avarage_reviews"
|
||||
payload["vars[meta_query][0][query_total_reviews][key]"] = "_manga_total_votes"
|
||||
|
||||
payload["vars[orderby][query_avarage_reviews]"] = "ASC"
|
||||
payload["vars[orderby][query_total_reviews]"] = "ASC"
|
||||
}
|
||||
|
||||
// SortOrder.RELEVANCE -> {
|
||||
// payload["vars[orderby]"] = ""
|
||||
// }
|
||||
|
||||
else -> payload["vars[meta_key]"] = "_latest_update"
|
||||
}
|
||||
|
||||
filter.states.forEach {
|
||||
payload["vars[meta_query][0][0][key]"] = "_wp_manga_status"
|
||||
payload["vars[meta_query][0][0][compare]"] = "IN"
|
||||
payload["vars[meta_query][0][0][value][]"] =
|
||||
when (it) {
|
||||
MangaState.ONGOING -> "on-going"
|
||||
MangaState.FINISHED -> "end"
|
||||
MangaState.ABANDONED -> "canceled"
|
||||
MangaState.PAUSED -> "on-hold"
|
||||
MangaState.UPCOMING -> "upcoming"
|
||||
}
|
||||
}
|
||||
|
||||
filter.contentRating.oneOrThrowIfMany()?.let {
|
||||
payload["vars[meta_query][0][1][key]"] = "manga_adult_content"
|
||||
payload["vars[meta_query][0][1][value]"] =
|
||||
when (it) {
|
||||
ContentRating.SAFE -> ""
|
||||
ContentRating.ADULT -> "a%3A1%3A%7Bi%3A0%3Bs%3A3%3A%22yes%22%3B%7D"
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
SortOrder.POPULARITY_ASC -> {
|
||||
payload["vars[meta_key]"] = "_wp_manga_views"
|
||||
payload["vars[orderby]"] = "meta_value_num"
|
||||
payload["vars[order]"] = "asc"
|
||||
}
|
||||
|
||||
SortOrder.UPDATED -> {
|
||||
payload["vars[meta_key]"] = "_latest_update"
|
||||
payload["vars[orderby]"] = "meta_value_num"
|
||||
payload["vars[order]"] = "desc"
|
||||
}
|
||||
|
||||
SortOrder.UPDATED_ASC -> {
|
||||
payload["vars[meta_key]"] = "_latest_update"
|
||||
payload["vars[orderby]"] = "meta_value_num"
|
||||
payload["vars[order]"] = "asc"
|
||||
}
|
||||
|
||||
SortOrder.NEWEST -> {
|
||||
payload["vars[orderby]"] = "date"
|
||||
payload["vars[order]"] = "desc"
|
||||
}
|
||||
|
||||
SortOrder.NEWEST_ASC -> {
|
||||
payload["vars[orderby]"] = "date"
|
||||
payload["vars[order]"] = "asc"
|
||||
}
|
||||
|
||||
SortOrder.ALPHABETICAL -> {
|
||||
payload["vars[orderby]"] = "post_title"
|
||||
payload["vars[order]"] = "asc"
|
||||
}
|
||||
|
||||
SortOrder.ALPHABETICAL_DESC -> {
|
||||
payload["vars[orderby]"] = "post_title"
|
||||
payload["vars[order]"] = "desc"
|
||||
}
|
||||
|
||||
SortOrder.RATING -> {
|
||||
payload["vars[meta_query][0][query_avarage_reviews][key]"] = "_manga_avarage_reviews"
|
||||
payload["vars[meta_query][0][query_total_reviews][key]"] = "_manga_total_votes"
|
||||
|
||||
payload["vars[orderby][query_avarage_reviews]"] = "DESC"
|
||||
payload["vars[orderby][query_total_reviews]"] = "DESC"
|
||||
}
|
||||
|
||||
SortOrder.RATING_ASC -> {
|
||||
payload["vars[meta_query][0][query_avarage_reviews][key]"] = "_manga_avarage_reviews"
|
||||
payload["vars[meta_query][0][query_total_reviews][key]"] = "_manga_total_votes"
|
||||
|
||||
payload["vars[orderby][query_avarage_reviews]"] = "ASC"
|
||||
payload["vars[orderby][query_total_reviews]"] = "ASC"
|
||||
}
|
||||
|
||||
SortOrder.RELEVANCE -> {
|
||||
payload["vars[orderby]"] = ""
|
||||
}
|
||||
|
||||
else -> payload["vars[orderby]"] = ""
|
||||
}
|
||||
|
||||
filter.states.forEach {
|
||||
payload["vars[meta_query][0][0][key]"] = "_wp_manga_status"
|
||||
payload["vars[meta_query][0][0][compare]"] = "IN"
|
||||
payload["vars[meta_query][0][0][value][]"] =
|
||||
when (it) {
|
||||
MangaState.ONGOING -> "on-going"
|
||||
MangaState.FINISHED -> "end"
|
||||
MangaState.ABANDONED -> "canceled"
|
||||
MangaState.PAUSED -> "on-hold"
|
||||
MangaState.UPCOMING -> "upcoming"
|
||||
}
|
||||
}
|
||||
|
||||
filter.contentRating.oneOrThrowIfMany()?.let {
|
||||
payload["vars[meta_query][0][1][key]"] = "manga_adult_content"
|
||||
payload["vars[meta_query][0][1][value]"] =
|
||||
when (it) {
|
||||
ContentRating.SAFE -> ""
|
||||
ContentRating.ADULT -> "a%3A1%3A%7Bi%3A0%3Bs%3A3%3A%22yes%22%3B%7D"
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
return parseMangaList(
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,18 +245,18 @@ internal abstract class MangaReaderParser(
|
||||
"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
|
||||
-> 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ş",
|
||||
-> MangaState.FINISHED
|
||||
-> MangaState.FINISHED
|
||||
|
||||
"Canceled", "Cancelled", "Cancelado", "cancellato", "Cancelados", "Dropped", "Discontinued", "abandonné", "Abandonné",
|
||||
-> MangaState.ABANDONED
|
||||
-> MangaState.ABANDONED
|
||||
|
||||
"Hiatus", "On Hold", "Pausado", "En espera", "En pause", "En Pause", "En attente",
|
||||
-> MangaState.PAUSED
|
||||
-> MangaState.PAUSED
|
||||
|
||||
else -> null
|
||||
}
|
||||
|
||||
@@ -9,12 +9,12 @@ import java.util.*
|
||||
|
||||
@MangaSourceParser("ADUMANGA", "AduManga", "tr")
|
||||
internal class AduManga(context: MangaLoaderContext) :
|
||||
MangaReaderParser(context, MangaParserSource.ADUMANGA, "adumanga.com", pageSize = 20, searchPageSize = 10) {
|
||||
MangaReaderParser(context, MangaParserSource.ADUMANGA, "adumanga.com", pageSize = 20, searchPageSize = 10) {
|
||||
|
||||
override val sourceLocale: Locale = Locale.ENGLISH
|
||||
override val sourceLocale: Locale = Locale.ENGLISH
|
||||
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = super.filterCapabilities.copy(
|
||||
isTagsExclusionSupported = false,
|
||||
)
|
||||
override val filterCapabilities: MangaListFilterCapabilities
|
||||
get() = super.filterCapabilities.copy(
|
||||
isTagsExclusionSupported = false,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -104,13 +104,13 @@ internal abstract class MangaWorldParser(
|
||||
tags = tags,
|
||||
author = div.selectFirst(".author a")?.text(),
|
||||
state =
|
||||
when (div.selectFirst(".status a")?.text()) {
|
||||
"In corso" -> MangaState.ONGOING
|
||||
"Finito" -> MangaState.FINISHED
|
||||
"Droppato" -> MangaState.ABANDONED
|
||||
"In pausa" -> MangaState.PAUSED
|
||||
else -> null
|
||||
},
|
||||
when (div.selectFirst(".status a")?.text()) {
|
||||
"In corso" -> MangaState.ONGOING
|
||||
"Finito" -> MangaState.FINISHED
|
||||
"Droppato" -> MangaState.ABANDONED
|
||||
"In pausa" -> MangaState.PAUSED
|
||||
else -> null
|
||||
},
|
||||
source = source,
|
||||
isNsfw = isNsfwSource,
|
||||
)
|
||||
@@ -143,30 +143,30 @@ internal abstract class MangaWorldParser(
|
||||
val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()
|
||||
return manga.copy(
|
||||
altTitle =
|
||||
doc.selectFirst(".meta-data .font-weight-bold:contains(Titoli alternativi:)")
|
||||
?.parent()
|
||||
?.ownText()
|
||||
?.substringAfter(": ")
|
||||
?.trim(),
|
||||
doc.selectFirst(".meta-data .font-weight-bold:contains(Titoli alternativi:)")
|
||||
?.parent()
|
||||
?.ownText()
|
||||
?.substringAfter(": ")
|
||||
?.trim(),
|
||||
description = doc.getElementById("noidungm")?.text().orEmpty(),
|
||||
chapters =
|
||||
doc.select(".chapters-wrapper .chapter a").mapChapters(reversed = true) { i, a ->
|
||||
val url = a.attrAsRelativeUrl("href").toAbsoluteUrl(domain)
|
||||
MangaChapter(
|
||||
id = generateUid(url),
|
||||
name = a.selectFirstOrThrow("span.d-inline-block").text(),
|
||||
number = i + 1f,
|
||||
volume = 0,
|
||||
url = "$url?style=list",
|
||||
scanlator = null,
|
||||
uploadDate =
|
||||
SimpleDateFormat("dd MMMM yyyy", Locale.ITALIAN).tryParse(
|
||||
a.selectFirst(".chap-date")?.text(),
|
||||
),
|
||||
branch = null,
|
||||
source = source,
|
||||
)
|
||||
},
|
||||
doc.select(".chapters-wrapper .chapter a").mapChapters(reversed = true) { i, a ->
|
||||
val url = a.attrAsRelativeUrl("href").toAbsoluteUrl(domain)
|
||||
MangaChapter(
|
||||
id = generateUid(url),
|
||||
name = a.selectFirstOrThrow("span.d-inline-block").text(),
|
||||
number = i + 1f,
|
||||
volume = 0,
|
||||
url = "$url?style=list",
|
||||
scanlator = null,
|
||||
uploadDate =
|
||||
SimpleDateFormat("dd MMMM yyyy", Locale.ITALIAN).tryParse(
|
||||
a.selectFirst(".chap-date")?.text(),
|
||||
),
|
||||
branch = null,
|
||||
source = source,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -186,17 +186,17 @@ internal abstract class NepnepParser(
|
||||
altTitle = null,
|
||||
state = when (doc.selectFirstOrThrow(".list-group-item:contains(Status:) a").text()) {
|
||||
"Ongoing (Scan)", "Ongoing (Publish)",
|
||||
-> MangaState.ONGOING
|
||||
-> MangaState.ONGOING
|
||||
|
||||
"Complete (Scan)", "Complete (Publish)",
|
||||
-> MangaState.FINISHED
|
||||
-> MangaState.FINISHED
|
||||
|
||||
"Cancelled (Scan)", "Cancelled (Publish)",
|
||||
"Discontinued (Scan)", "Discontinued (Publish)",
|
||||
-> MangaState.ABANDONED
|
||||
-> MangaState.ABANDONED
|
||||
|
||||
"Hiatus (Scan)", "Hiatus (Publish)",
|
||||
-> MangaState.PAUSED
|
||||
-> MangaState.PAUSED
|
||||
|
||||
else -> null
|
||||
},
|
||||
|
||||
@@ -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