From 7c2ac033d7598a8dcacbe4151feaccb970745819 Mon Sep 17 00:00:00 2001 From: devi Date: Wed, 29 Nov 2023 18:31:26 +0100 Subject: [PATCH] add filter on HeanCms , DoujinDesu.tv Fix GetList GalleryAdultsParser --- .../site/galleryadults/GalleryAdultsParser.kt | 50 +++---- .../parsers/site/galleryadults/all/Hentai3.kt | 77 ++++++----- .../site/galleryadults/all/HentaiEnvy.kt | 55 ++++---- .../site/galleryadults/all/HentaiEra.kt | 76 ++++++----- .../site/galleryadults/all/HentaiForce.kt | 72 ++++++----- .../site/galleryadults/all/HentaiFox.kt | 112 +++++++++------- .../site/galleryadults/all/NHentaiParser.kt | 82 ++++++------ .../site/galleryadults/all/NHentaiUk.kt | 48 ++++--- .../kotatsu/parsers/site/heancms/HeanCms.kt | 72 ++++++----- .../parsers/site/heancms/es/YugenMangasEs.kt | 84 ++++++------ .../parsers/site/heancmsalt/HeanCmsAlt.kt | 24 ++-- .../parsers/site/id/DoujinDesuParser.kt | 122 +++++++++++------- 12 files changed, 495 insertions(+), 379 deletions(-) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/GalleryAdultsParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/GalleryAdultsParser.kt index 9def242d..5b69fd57 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/GalleryAdultsParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/GalleryAdultsParser.kt @@ -24,36 +24,42 @@ internal abstract class GalleryAdultsParser( override val configKeyDomain = ConfigKey.Domain(domain) override val isMultipleTagsSupported = false - override suspend fun getListPage( - page: Int, - query: String?, - tags: Set?, - sortOrder: SortOrder, - ): List { - val tag = tags.oneOrThrowIfMany() + override suspend fun getListPage(page: Int, filter: MangaListFilter?): List { + val url = buildString { append("https://") append(domain) - if (!tags.isNullOrEmpty()) { - if (tag?.key == "languageKey") { - append("/language") - append(tag.title) - append("/?") - } else { - append("/tag/") - append(tag?.key.orEmpty()) - append("/?") + when (filter) { + is MangaListFilter.Search -> { + append("/search/?q=") + append(filter.query.urlEncoded()) + append("&") + } + + is MangaListFilter.Advanced -> { + if (filter.tags.isNotEmpty()) { + filter.tags.oneOrThrowIfMany()?.let { + if (it.key == "languageKey") { + append("/language") + append(it.title) + append("/?") + } else { + append("/tag/") + append(it.key) + append("/?") + } + } + } else { + append("/?") + } } - } else if (!query.isNullOrEmpty()) { - append("/search/?q=") - append(query.urlEncoded()) - append("&") - } else { - append("/?") + + null -> append("/?") } append("page=") append(page) } + return parseMangaList(webClient.httpGet(url).parseHtml()) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/Hentai3.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/Hentai3.kt index 65b653b5..ed39facf 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/Hentai3.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/Hentai3.kt @@ -31,45 +31,58 @@ internal class Hentai3(context: MangaLoaderContext) : "/japanese", ) - override val sortOrders: Set = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY) + override val isMultipleTagsSupported = true - override suspend fun getListPage( - page: Int, - query: String?, - tags: Set?, - sortOrder: SortOrder, - ): List { - if (query.isNullOrEmpty() && tags != null && tags.size > 1) { - return getListPage(page, buildQuery(tags), emptySet(), sortOrder) - } + override val availableSortOrders: Set = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY) + + override suspend fun getListPage(page: Int, filter: MangaListFilter?): List { val url = buildString { append("https://") append(domain) - if (!tags.isNullOrEmpty()) { - val tag = tags.single() - if (tag.key == "languageKey") { - append("/language") - append(tag.title) - } else { - append("/tags/") - append(tag.key) + when (filter) { + + is MangaListFilter.Search -> { + append("/search?q=") + append(filter.query.urlEncoded()) + append("&page=") + append(page.toString()) } - append("/") - append(page) - if (sortOrder == SortOrder.POPULARITY) { - append("?sort=popular") + + is MangaListFilter.Advanced -> { + + if (filter.tags.isNotEmpty() && filter.tags.size > 1) { + append("/search?q=") + append(buildQuery(filter.tags)) + if (filter.sortOrder == SortOrder.POPULARITY) { + append("&sort=popular") + } + append("&page=") + append(page.toString()) + } else if (filter.tags.isNotEmpty()) { + filter.tags.oneOrThrowIfMany()?.let { + if (it.key == "languageKey") { + append("/language") + append(it.title) + } else { + append("/tags/") + append(it.key) + } + } + append("/") + append(page.toString()) + if (filter.sortOrder == SortOrder.POPULARITY) { + append("?sort=popular") + } + } else { + append("/") + append(page) + } } - } else if (!query.isNullOrEmpty()) { - append("/search?q=") - append(query.urlEncoded()) - if (sortOrder == SortOrder.POPULARITY) { - append("&sort=popular") + + null -> { + append("/") + append(page) } - append("&page=") - append(page) - } else { - append("/") - append(page) } } return parseMangaList(webClient.httpGet(url).parseHtml()) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/HentaiEnvy.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/HentaiEnvy.kt index cb8a199a..95407f77 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/HentaiEnvy.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/HentaiEnvy.kt @@ -32,40 +32,45 @@ internal class HentaiEnvy(context: MangaLoaderContext) : "/portuguese", ) - override val sortOrders: Set = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY) + override val availableSortOrders: Set = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY) - override suspend fun getListPage( - page: Int, - query: String?, - tags: Set?, - sortOrder: SortOrder, - ): List { - val tag = tags.oneOrThrowIfMany() + override suspend fun getListPage(page: Int, filter: MangaListFilter?): List { val url = buildString { append("https://") append(domain) - if (!tags.isNullOrEmpty()) { - if (tag?.key == "languageKey") { - append("/language") - append(tag.title) - append("/?") - } else { - append("/tag/") - append(tag?.key.orEmpty()) - if (sortOrder == SortOrder.POPULARITY) { - append("/popular") + when (filter) { + is MangaListFilter.Search -> { + append("/search/?s_key=") + append(filter.query.urlEncoded()) + append("&") + } + + is MangaListFilter.Advanced -> { + if (filter.tags.isNotEmpty()) { + filter.tags.oneOrThrowIfMany()?.let { + if (it.key == "languageKey") { + append("/language") + append(it.title) + append("/?") + } else { + append("/tag/") + append(it.key) + if (filter.sortOrder == SortOrder.POPULARITY) { + append("/popular") + } + append("/?") + } + } + } else { + append("/?") } - append("/?") } - } else if (!query.isNullOrEmpty()) { - append("/search/?s_key=") - append(query.urlEncoded()) - append("&") - } else { - append("/?") + + null -> append("/?") } append("page=") append(page) + } return parseMangaList(webClient.httpGet(url).parseHtml()) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/HentaiEra.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/HentaiEra.kt index 8d4628eb..0b83be26 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/HentaiEra.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/HentaiEra.kt @@ -25,7 +25,9 @@ internal class HentaiEra(context: MangaLoaderContext) : "/russian", ) - override val sortOrders: Set = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY) + override val availableSortOrders: Set = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY) + + override val isMultipleTagsSupported = true override fun Element.parseTags() = select("a.tag, .gallery_title a").mapToSet { val key = it.attr("href").removeSuffix('/').substringAfterLast('/') @@ -37,46 +39,54 @@ internal class HentaiEra(context: MangaLoaderContext) : ) } - override suspend fun getListPage( - page: Int, - query: String?, - tags: Set?, - sortOrder: SortOrder, - ): List { - if (query.isNullOrEmpty() && tags != null && tags.size > 1) { - return getListPage(page, buildQuery(tags), emptySet(), sortOrder) - } + override suspend fun getListPage(page: Int, filter: MangaListFilter?): List { val url = buildString { append("https://") append(domain) - if (!tags.isNullOrEmpty()) { - val tag = tags.single() - if (tag.key == "languageKey") { - append("/language") - append(tag.title) - } else { - append("/tag/") - append(tag.key) - } - append("/") - if (sortOrder == SortOrder.POPULARITY) { - append("popular/") + when (filter) { + + is MangaListFilter.Search -> { + append("/search/?key=") + append(filter.query.urlEncoded()) + append("&") } - append("?") - } else if (!query.isNullOrEmpty()) { - append("/search/?key=") - if (sortOrder == SortOrder.POPULARITY) { - append(query.replace("<=1&dl=0&pp=0&tr=0", "<=0&dl=0&pp=1&tr=0")) - } else { - append(query) + + is MangaListFilter.Advanced -> { + if (filter.tags.isNotEmpty() && filter.tags.size > 1) { + append("/search/?key=") + if (filter.sortOrder == SortOrder.POPULARITY) { + append(buildQuery(filter.tags).replace("<=1&dl=0&pp=0&tr=0", "<=0&dl=0&pp=1&tr=0")) + } else { + append(buildQuery(filter.tags)) + } + append("&") + } else if (filter.tags.isNotEmpty()) { + filter.tags.oneOrThrowIfMany()?.let { + if (it.key == "languageKey") { + append("/language") + append(it.title) + } else { + append("/tag/") + append(it.key) + } + } + append("/") + + if (filter.sortOrder == SortOrder.POPULARITY) { + append("popular/") + } + append("?") + } else { + append("/?") + } } - append("&") - } else { - append("/?") + + null -> append("/?") } append("page=") - append(page) + append(page.toString()) } + return parseMangaList(webClient.httpGet(url).parseHtml()) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/HentaiForce.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/HentaiForce.kt index dc5a76c7..ed97854f 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/HentaiForce.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/HentaiForce.kt @@ -35,50 +35,60 @@ internal class HentaiForce(context: MangaLoaderContext) : "/vietnamese", ) - override val sortOrders: Set = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY) + override val isMultipleTagsSupported = true + + override val availableSortOrders: Set = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY) override suspend fun getPageUrl(page: MangaPage): String { val doc = webClient.httpGet(page.url.toAbsoluteUrl(domain)).parseHtml() return doc.selectFirstOrThrow(idImg).src() ?: doc.parseFailed("Image src not found") } - override suspend fun getListPage( - page: Int, - query: String?, - tags: Set?, - sortOrder: SortOrder, - ): List { - if (query.isNullOrEmpty() && tags != null && tags.size > 1) { - return getListPage(page, buildQuery(tags), emptySet(), sortOrder) - } + override suspend fun getListPage(page: Int, filter: MangaListFilter?): List { val url = buildString { append("https://") append(domain) - if (!tags.isNullOrEmpty()) { - val tag = tags.single() - if (tag.key == "languageKey") { - append("/language") - append(tag.title) - } else { - append("/tag/") - append(tag.key) + when (filter) { + is MangaListFilter.Search -> { + append("/search?q=") + append(filter.query.urlEncoded()) + append("&page=") } - if (sortOrder == SortOrder.POPULARITY) { - append("/popular") - } - append("/") - } else if (!query.isNullOrEmpty()) { - append("/search?q=") - append(query.urlEncoded()) - if (sortOrder == SortOrder.POPULARITY) { - append("&sort=popular") + + is MangaListFilter.Advanced -> { + if (filter.tags.isNotEmpty() && filter.tags.size > 1) { + append("/search?q=") + append(buildQuery(filter.tags)) + if (filter.sortOrder == SortOrder.POPULARITY) { + append("&sort=popular") + } + append("&page=") + } else if (filter.tags.isNotEmpty()) { + filter.tags.oneOrThrowIfMany()?.let { + if (it.key == "languageKey") { + append("/language") + append(it.title) + } else { + append("/tag/") + append(it.key) + } + } + append("/") + + if (filter.sortOrder == SortOrder.POPULARITY) { + append("popular/") + } + append("?") + } else { + append("/page/") + } } - append("&page=") - } else { - append("/page/") + + null -> append("/page/") } - append(page) + append(page.toString()) } + return parseMangaList(webClient.httpGet(url).parseHtml()) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/HentaiFox.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/HentaiFox.kt index 8bcde87c..02c108c0 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/HentaiFox.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/HentaiFox.kt @@ -32,59 +32,83 @@ internal class HentaiFox(context: MangaLoaderContext) : "/vietnamese", ) - override val sortOrders: Set = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY) + override val isMultipleTagsSupported = true - override suspend fun getListPage( - page: Int, - query: String?, - tags: Set?, - sortOrder: SortOrder, - ): List { - if (query.isNullOrEmpty() && tags != null && tags.size > 1) { - return getListPage(page, buildQuery(tags), emptySet(), sortOrder) - } + override val availableSortOrders: Set = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY) + + override suspend fun getListPage(page: Int, filter: MangaListFilter?): List { val url = buildString { append("https://") append(domain) - if (!tags.isNullOrEmpty()) { - val tag = tags.single() - if (tag.key == "languageKey") { - append("/language") - append(tag.title) - } else { - append("/tag/") - append(tag.key) - } - if (sortOrder == SortOrder.POPULARITY) { - append("/popular") + when (filter) { + is MangaListFilter.Search -> { + append("/search/?q=") + append(filter.query.urlEncoded()) + if (page > 1) { + append("&page=") + append(page.toString()) + } } - if (page > 1) { - append("/pag/") - append(page) - append("/") - } - } else if (!query.isNullOrEmpty()) { - append("/search/?q=") - append(query.urlEncoded()) - if (sortOrder == SortOrder.POPULARITY) { - append("&sort=popular") - } - if (page > 1) { - append("&page=") - append(page) + + is MangaListFilter.Advanced -> { + if (filter.tags.isNotEmpty() && filter.tags.size > 1) { + append("/search/?q=") + append(buildQuery(filter.tags)) + if (page > 1) { + append("&page=") + append(page.toString()) + } + + if (filter.sortOrder == SortOrder.POPULARITY) { + append("&sort=popular") + } + } else if (filter.tags.isNotEmpty()) { + filter.tags.oneOrThrowIfMany()?.let { + if (it.key == "languageKey") { + append("/language") + append(it.title) + } else { + append("/tag/") + append(it.key) + } + } + append("/") + if (filter.sortOrder == SortOrder.POPULARITY) { + append("popular/") + } + + if (page > 1) { + append("/pag/") + append(page.toString()) + append("/") + } + } else { + if (page > 2) { + append("/pag/") + append(page.toString()) + append("/") + } else if (page > 1) { + append("/page/") + append(page.toString()) + append("/") + } + } } - } else { - if (page > 2) { - append("/pag/") - append(page) - append("/") - } else if (page > 1) { - append("/page/") - append(page) - append("/") + + null -> { + if (page > 2) { + append("/pag/") + append(page.toString()) + append("/") + } else if (page > 1) { + append("/page/") + append(page.toString()) + append("/") + } } } } + return parseMangaList(webClient.httpGet(url).parseHtml()) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/NHentaiParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/NHentaiParser.kt index 078d5eaf..b6cac6b5 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/NHentaiParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/NHentaiParser.kt @@ -27,50 +27,60 @@ internal class NHentaiParser(context: MangaLoaderContext) : "/chinese", ) - override val sortOrders: Set = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY) + override val availableSortOrders: Set = EnumSet.of(SortOrder.UPDATED, SortOrder.POPULARITY) + + override val isMultipleTagsSupported = true + + override suspend fun getListPage(page: Int, filter: MangaListFilter?): List { - override suspend fun getListPage( - page: Int, - query: String?, - tags: Set?, - sortOrder: SortOrder, - ): List { - if (query.isNullOrEmpty() && tags != null && tags.size > 1) { - return getListPage(page, buildQuery(tags), emptySet(), sortOrder) - } val url = buildString { append("https://") append(domain) - if (!tags.isNullOrEmpty()) { - val tag = tags.single() - if (tag.key == "languageKey") { - append("/language") - append(tag.title) - } else { - append("/tag/") - append(tag.key) - } - append("/") - if (sortOrder == SortOrder.POPULARITY) { - append("popular") - } - append("?") - } else if (!query.isNullOrEmpty()) { - append("/search/?q=") - append(query.urlEncoded()) - if (sortOrder == SortOrder.POPULARITY) { - append("&sort=popular") + when (filter) { + + is MangaListFilter.Search -> { + append("/search/?q=") + append(filter.query.urlEncoded()) + append("&") } - append("&") - } else { - if (sortOrder == SortOrder.POPULARITY) { - append("/?sort=popular&") - } else { - append("/?") + + is MangaListFilter.Advanced -> { + if (filter.tags.isNotEmpty() && filter.tags.size > 1) { + append("/search/?q=") + append(buildQuery(filter.tags)) + if (filter.sortOrder == SortOrder.POPULARITY) { + append("&sort=popular") + } + append("&") + } else if (filter.tags.isNotEmpty()) { + filter.tags.oneOrThrowIfMany()?.let { + if (it.key == "languageKey") { + append("/language") + append(it.title) + } else { + append("/tag/") + append(it.key) + } + } + append("/") + if (filter.sortOrder == SortOrder.POPULARITY) { + append("popular/") + } + + append("?") + } else { + if (filter.sortOrder == SortOrder.POPULARITY) { + append("/?sort=popular&") + } else { + append("/?") + } + } } + + null -> append("/?") } append("page=") - append(page) + append(page.toString()) } return parseMangaList(webClient.httpGet(url).parseHtml()) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/NHentaiUk.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/NHentaiUk.kt index 0a8b8403..cc434d16 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/NHentaiUk.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/galleryadults/all/NHentaiUk.kt @@ -33,33 +33,39 @@ internal class NHentaiUk(context: MangaLoaderContext) : "/turkish", ) - override suspend fun getListPage( - page: Int, - query: String?, - tags: Set?, - sortOrder: SortOrder, - ): List { - val tag = tags.oneOrThrowIfMany() + override suspend fun getListPage(page: Int, filter: MangaListFilter?): List { + val url = buildString { append("https://") append(domain) - if (!tags.isNullOrEmpty()) { - if (tag?.key == "languageKey") { - append("/language") - append(tag.title) - append("/?p=") - } else { - append("/tag/") - append(tag?.key) - append("/?p=") + when (filter) { + + is MangaListFilter.Search -> { + throw IllegalArgumentException("Search is not supported by this source") + } + + is MangaListFilter.Advanced -> { + if (filter.tags.isNotEmpty()) { + filter.tags.oneOrThrowIfMany()?.let { + if (it.key == "languageKey") { + append("/language") + append(it.title) + } else { + append("/tag/") + append(it.key) + } + } + append("/?p=") + } else { + append("/home?p=") + } } - } else if (!query.isNullOrEmpty()) { - throw IllegalArgumentException("Search is not supported by this source") - } else { - append("/home?p=") + + null -> append("/?") } - append(page) + append(page.toString()) } + return parseMangaList(webClient.httpGet(url).parseHtml()) } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancms/HeanCms.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancms/HeanCms.kt index e196f8d9..70bea32a 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancms/HeanCms.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancms/HeanCms.kt @@ -27,6 +27,8 @@ internal abstract class HeanCms( SortOrder.POPULARITY, ) + override val availableStates: Set = EnumSet.allOf(MangaState::class.java) + override val headers: Headers = Headers.Builder() .add("User-Agent", UserAgents.CHROME_DESKTOP) .build() @@ -34,50 +36,54 @@ internal abstract class HeanCms( protected open val pathManga = "series" //For some sources, you need to send a json. For the moment, this part only works in Get. ( ex source need json gloriousscan.com , omegascans.org ) - override suspend fun getListPage( - page: Int, - query: String?, - tags: Set?, - sortOrder: SortOrder, - ): List { - - var firstTag = false + override suspend fun getListPage(page: Int, filter: MangaListFilter?): List { val url = buildString { append("https://api.") append(domain) append("/query?query_string=") + when (filter) { + is MangaListFilter.Search -> { + append(filter.query.urlEncoded()) + } - if (!query.isNullOrEmpty()) { - append(query.urlEncoded()) - } + is MangaListFilter.Advanced -> { - append("&series_status=All&order=desc&orderBy=") - when (sortOrder) { - SortOrder.POPULARITY -> append("total_views") - SortOrder.UPDATED -> append("latest") - SortOrder.NEWEST -> append("created_at") - SortOrder.ALPHABETICAL -> append("title") - else -> append("latest") - } + filter.states.oneOrThrowIfMany()?.let { + append("&series_status=") + append( + when (it) { + MangaState.ONGOING -> "Ongoing" + MangaState.FINISHED -> "Completed" + MangaState.ABANDONED -> "Dropped" + MangaState.PAUSED -> "Hiatus" + }, + ) - append("&series_type=Comic&page=") - append(page) - append("&perPage=12&tags_ids=") - append("[".urlEncoded()) - if (!tags.isNullOrEmpty()) { - for (tag in tags) { - // Just to make it fit [1,2,44] ect - if (!firstTag) { - firstTag = true - } else { - append(",") } - append(tag.key) + append("&order=desc") + append("&orderBy=") + when (filter.sortOrder) { + SortOrder.POPULARITY -> append("total_views") + SortOrder.UPDATED -> append("latest") + SortOrder.NEWEST -> append("created_at") + SortOrder.ALPHABETICAL -> append("title") + else -> append("latest") + } + append("&series_type=Comic&perPage=12") + append("&tags_ids=") + append("[".urlEncoded()) + append(filter.tags.joinToString(",") { it.key }) + append("]".urlEncoded()) + } + + null -> {} } - append("]".urlEncoded()) + append("&page=") + append(page.toString()) } val json = webClient.httpGet(url).parseJson() + return json.getJSONArray("data").mapJSON { j -> val slug = j.getString("series_slug") val urlManga = "https://$domain/$pathManga/$slug" @@ -107,8 +113,10 @@ internal abstract class HeanCms( source = source, ) } + } + protected open val datePattern = "yyyy-MM-dd" override suspend fun getDetails(manga: Manga): Manga { val root = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancms/es/YugenMangasEs.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancms/es/YugenMangasEs.kt index e1700bbb..64b7349a 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancms/es/YugenMangasEs.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancms/es/YugenMangasEs.kt @@ -2,19 +2,10 @@ package org.koitharu.kotatsu.parsers.site.heancms.es import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaSourceParser -import org.koitharu.kotatsu.parsers.model.ContentType -import org.koitharu.kotatsu.parsers.model.Manga -import org.koitharu.kotatsu.parsers.model.MangaSource -import org.koitharu.kotatsu.parsers.model.MangaState -import org.koitharu.kotatsu.parsers.model.MangaTag -import org.koitharu.kotatsu.parsers.model.RATING_UNKNOWN -import org.koitharu.kotatsu.parsers.model.SortOrder +import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.site.heancms.HeanCms -import org.koitharu.kotatsu.parsers.util.domain -import org.koitharu.kotatsu.parsers.util.generateUid import org.koitharu.kotatsu.parsers.util.json.mapJSON -import org.koitharu.kotatsu.parsers.util.parseJson -import org.koitharu.kotatsu.parsers.util.urlEncoded +import org.koitharu.kotatsu.parsers.util.* @MangaSourceParser("YUGEN_MANGAS_ES", "YugenMangas.lat", "es", ContentType.HENTAI) internal class YugenMangasEs(context: MangaLoaderContext) : @@ -22,46 +13,55 @@ internal class YugenMangasEs(context: MangaLoaderContext) : private val domainAlt = "yugenmangas.net" - override suspend fun getListPage( - page: Int, - query: String?, - tags: Set?, - sortOrder: SortOrder, - ): List { - var firstTag = false + override suspend fun getListPage(page: Int, filter: MangaListFilter?): List { val url = buildString { append("https://api.") append(domainAlt) append("/query?query_string=") - if (!query.isNullOrEmpty()) { - append(query.urlEncoded()) - } - append("&series_status=All&order=desc&orderBy=") - when (sortOrder) { - SortOrder.POPULARITY -> append("total_views") - SortOrder.UPDATED -> append("latest") - SortOrder.NEWEST -> append("created_at") - SortOrder.ALPHABETICAL -> append("title") - else -> append("latest") - } - append("&series_type=Comic&page=") - append(page) - append("&perPage=12&tags_ids=") - append("[".urlEncoded()) - if (!tags.isNullOrEmpty()) { - for (tag in tags) { - // Just to make it fit [1,2,44] ect - if (!firstTag) { - firstTag = true - } else { - append(",") + when (filter) { + is MangaListFilter.Search -> { + append(filter.query.urlEncoded()) + } + + is MangaListFilter.Advanced -> { + + filter.states.oneOrThrowIfMany()?.let { + append("&series_status=") + append( + when (it) { + MangaState.ONGOING -> "Ongoing" + MangaState.FINISHED -> "Completed" + MangaState.ABANDONED -> "Dropped" + MangaState.PAUSED -> "Hiatus" + }, + ) + } - append(tag.key) + append("&order=desc") + append("&orderBy=") + when (filter.sortOrder) { + SortOrder.POPULARITY -> append("total_views") + SortOrder.UPDATED -> append("latest") + SortOrder.NEWEST -> append("created_at") + SortOrder.ALPHABETICAL -> append("title") + else -> append("latest") + } + append("&series_type=Comic&perPage=12") + append("&tags_ids=") + append("[".urlEncoded()) + append(filter.tags.joinToString(",") { it.key }) + append("]".urlEncoded()) } + + null -> {} } - append("]".urlEncoded()) + + append("&page=") + append(page.toString()) } + val json = webClient.httpGet(url).parseJson() + return json.getJSONArray("data").mapJSON { j -> val slug = j.getString("series_slug") val urlManga = "https://$domain/series/$slug" diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancmsalt/HeanCmsAlt.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancmsalt/HeanCmsAlt.kt index a6768be4..588e23f3 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancmsalt/HeanCmsAlt.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/heancmsalt/HeanCmsAlt.kt @@ -5,6 +5,7 @@ import org.koitharu.kotatsu.parsers.PagedMangaParser import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.util.* +import java.lang.IllegalArgumentException import java.text.DateFormat import java.text.SimpleDateFormat import java.util.* @@ -33,23 +34,24 @@ internal abstract class HeanCmsAlt( protected open val selectManga = "div.grid.grid-cols-2 div:not([class]):contains(M)" protected open val selectMangaTitle = "h5" - override suspend fun getListPage( - page: Int, - query: String?, - tags: Set?, - sortOrder: SortOrder, - ): List { - // No search or tag - if (!query.isNullOrEmpty()) { - return emptyList() - } + override suspend fun getListPage(page: Int, filter: MangaListFilter?): List { val url = buildString { append("https://") append(domain) append(listUrl) + when (filter) { + is MangaListFilter.Search -> { + throw IllegalArgumentException("Search is not supported by this source") + } + + is MangaListFilter.Advanced -> { + } + + null -> {} + } if (page > 1) { append("?page=") - append(page) + append(page.toString()) } } val doc = webClient.httpGet(url).parseHtml() diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/DoujinDesuParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/DoujinDesuParser.kt index babd84fc..69ef6220 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/DoujinDesuParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/id/DoujinDesuParser.kt @@ -18,6 +18,78 @@ class DoujinDesuParser(context: MangaLoaderContext) : PagedMangaParser(context, override val availableSortOrders: Set get() = EnumSet.of(SortOrder.UPDATED, SortOrder.NEWEST, SortOrder.ALPHABETICAL, SortOrder.POPULARITY) + override val availableStates: Set = EnumSet.of(MangaState.ONGOING, MangaState.FINISHED) + + override suspend fun getListPage(page: Int, filter: MangaListFilter?): List { + val url = urlBuilder().apply { + addPathSegment("manga") + addPathSegment("page") + addPathSegment("$page/") + + when (filter) { + is MangaListFilter.Search -> { + addQueryParameter("title", filter.query) + } + + is MangaListFilter.Advanced -> { + addQueryParameter("title", "") + addQueryParameter( + "order", + when (filter.sortOrder) { + SortOrder.UPDATED -> "update" + SortOrder.POPULARITY -> "popular" + SortOrder.ALPHABETICAL -> "title" + SortOrder.NEWEST -> "latest" + else -> "latest" + }, + ) + + filter.tags.forEach { + addEncodedQueryParameter("genre[]".urlEncoded(), it.key.urlEncoded()) + } + + filter.states.oneOrThrowIfMany()?.let { + addEncodedQueryParameter( + "statusx", + when (it) { + MangaState.ONGOING -> "Publishing" + MangaState.FINISHED -> "Finished" + else -> "" + }, + ) + } + } + + null -> addQueryParameter("order", "update") + } + }.build() + + return webClient.httpGet(url).parseHtml() + .requireElementById("archives") + .selectFirstOrThrow("div.entries") + .select(".entry") + .map { + val titleTag = it.selectFirstOrThrow(".metadata > a") + val relativeUrl = titleTag.attrAsRelativeUrl("href") + Manga( + id = generateUid(relativeUrl), + title = titleTag.attr("title"), + altTitle = null, + url = relativeUrl, + publicUrl = relativeUrl.toAbsoluteUrl(domain), + rating = RATING_UNKNOWN, + isNsfw = true, + coverUrl = it.selectFirst(".thumbnail > img")?.src().orEmpty(), + tags = emptySet(), + state = null, + author = null, + largeCoverUrl = null, + description = null, + source = source, + ) + } + } + override suspend fun getDetails(manga: Manga): Manga { val docs = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml().selectFirstOrThrow("#archive") val chapterDateFormat = SimpleDateFormat("EEEE, dd MMMM yyyy", sourceLocale) @@ -58,56 +130,6 @@ class DoujinDesuParser(context: MangaLoaderContext) : PagedMangaParser(context, ) } - override suspend fun getListPage( - page: Int, - query: String?, - tags: Set?, - sortOrder: SortOrder, - ): List { - val url = urlBuilder().apply { - addPathSegment("manga") - addPathSegment("page") - addPathSegment("$page/") - val order = when (sortOrder) { - SortOrder.UPDATED -> "update" - SortOrder.POPULARITY -> "popular" - SortOrder.ALPHABETICAL -> "title" - SortOrder.NEWEST -> "latest" - else -> throw IllegalArgumentException("Sort order not supported") - } - addQueryParameter("order", order) - addQueryParameter("title", query.orEmpty()) - tags?.forEach { - addEncodedQueryParameter("genre[]".urlEncoded(), it.key.urlEncoded()) - } - }.build() - - return webClient.httpGet(url).parseHtml() - .requireElementById("archives") - .selectFirstOrThrow("div.entries") - .select(".entry") - .map { - val titleTag = it.selectFirstOrThrow(".metadata > a") - val relativeUrl = titleTag.attrAsRelativeUrl("href") - Manga( - id = generateUid(relativeUrl), - title = titleTag.attr("title"), - altTitle = null, - url = relativeUrl, - publicUrl = relativeUrl.toAbsoluteUrl(domain), - rating = RATING_UNKNOWN, - isNsfw = true, - coverUrl = it.selectFirst(".thumbnail > img")?.src().orEmpty(), - tags = emptySet(), - state = null, - author = null, - largeCoverUrl = null, - description = null, - source = source, - ) - } - } - override suspend fun getPages(chapter: MangaChapter): List { val id = webClient.httpGet(chapter.url.toAbsoluteUrl(domain)).parseHtml() .requireElementById("reader")