From 6bf0ae92e4309983430c1405f539e7c1bf63def2 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Wed, 25 Oct 2023 13:36:42 +0300 Subject: [PATCH] [*chan] Fix sort orders --- .../parsers/site/ru/multichan/ChanParser.kt | 79 ++++++++++++------- .../site/ru/multichan/HenChanParser.kt | 34 ++++++++ .../site/ru/multichan/YaoiChanParser.kt | 8 +- 3 files changed, 90 insertions(+), 31 deletions(-) diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/multichan/ChanParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/multichan/ChanParser.kt index 39fd9297..58848ec8 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/multichan/ChanParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/multichan/ChanParser.kt @@ -1,5 +1,6 @@ package org.koitharu.kotatsu.parsers.site.ru.multichan +import okhttp3.HttpUrl import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaParser import org.koitharu.kotatsu.parsers.MangaParserAuthProvider @@ -18,6 +19,7 @@ internal abstract class ChanParser( SortOrder.NEWEST, SortOrder.POPULARITY, SortOrder.ALPHABETICAL, + SortOrder.RATING, ) override val authUrl: String @@ -33,23 +35,7 @@ internal abstract class ChanParser( sortOrder: SortOrder, ): List { val domain = domain - val url = when { - !query.isNullOrEmpty() -> { - if (offset != 0) { - return emptyList() - } - "https://$domain/?do=search&subaction=search&story=${query.urlEncoded()}" - } - - !tags.isNullOrEmpty() -> tags.joinToString( - prefix = "https://$domain/tags/", - postfix = "&n=${getSortKey2(sortOrder)}?offset=$offset", - separator = "+", - ) { tag -> tag.key } - - else -> "https://$domain/${getSortKey(sortOrder)}?offset=$offset" - } - val doc = webClient.httpGet(url).parseHtml() + val doc = webClient.httpGet(buildUrl(offset, query, tags, sortOrder)).parseHtml() val root = doc.body().selectFirst("div.main_fon")?.getElementById("content") ?: doc.parseFailed("Cannot find root") return root.select("div.content_row").mapNotNull { row -> @@ -191,21 +177,54 @@ internal abstract class ChanParser( } } - private fun getSortKey(sortOrder: SortOrder) = - when (sortOrder) { - SortOrder.ALPHABETICAL -> "catalog" - SortOrder.POPULARITY -> "mostfavorites" - SortOrder.NEWEST -> "manga/new" - else -> "mostfavorites" - } + protected open fun buildUrl( + offset: Int, + query: String?, + tags: Set?, + sortOrder: SortOrder, + ): HttpUrl { + val builder = urlBuilder() + builder.addQueryParameter("offset", offset.toString()) + when { + !query.isNullOrEmpty() -> { + builder.addQueryParameter("do", "search") + builder.addQueryParameter("subaction", "search") + builder.addQueryParameter("search_start", ((offset / 40) + 1).toString()) + builder.addQueryParameter("full_search", "0") + builder.addQueryParameter("result_from", (offset + 1).toString()) + builder.addQueryParameter("result_num", "40") + builder.addQueryParameter("story", query) + builder.addQueryParameter("need_sort_date", "false") + } - private fun getSortKey2(sortOrder: SortOrder) = - when (sortOrder) { - SortOrder.ALPHABETICAL -> "abcasc" - SortOrder.POPULARITY -> "favdesc" - SortOrder.NEWEST -> "datedesc" - else -> "favdesc" + !tags.isNullOrEmpty() -> { + builder.addPathSegment("tags") + builder.addPathSegment(tags.joinToString("+") { it.key }) + builder.addQueryParameter( + "n", + when (sortOrder) { + SortOrder.RATING, + SortOrder.POPULARITY, + -> "favdesc" + + SortOrder.ALPHABETICAL -> "abcasc" + else -> "" // SortOrder.NEWEST + }, + ) + } + + else -> when (sortOrder) { + SortOrder.POPULARITY -> builder.addPathSegment("mostviews") + SortOrder.ALPHABETICAL -> builder.addPathSegment("catalog") + SortOrder.RATING -> builder.addPathSegment("mostfavorites") + else -> { // SortOrder.NEWEST + builder.addPathSegment("manga") + builder.addPathSegment("new") + } + } } + return builder.build() + } private fun String.toTagName() = replace('_', ' ').toTitleCase() diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/multichan/HenChanParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/multichan/HenChanParser.kt index b6a6fc72..f3644236 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/multichan/HenChanParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/multichan/HenChanParser.kt @@ -1,15 +1,19 @@ package org.koitharu.kotatsu.parsers.site.ru.multichan +import okhttp3.HttpUrl import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaSourceParser import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.* import org.koitharu.kotatsu.parsers.util.* +import java.util.* @MangaSourceParser("HENCHAN", "Хентай-тян", "ru", type = ContentType.HENTAI) internal class HenChanParser(context: MangaLoaderContext) : ChanParser(context, MangaSource.HENCHAN) { override val configKeyDomain = ConfigKey.Domain( + "x.henchan.pro", + "xxx.henchan.pro", "y.hentaichan.live", "xxx.hentaichan.live", "xx.hentaichan.live", @@ -17,6 +21,12 @@ internal class HenChanParser(context: MangaLoaderContext) : ChanParser(context, "hentaichan.pro", ) + override val sortOrders: Set = EnumSet.of( + SortOrder.NEWEST, + SortOrder.POPULARITY, + SortOrder.RATING, + ) + override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml() val root = doc.body().requireElementById("dle-content") @@ -46,4 +56,28 @@ internal class HenChanParser(context: MangaLoaderContext) : ChanParser(context, ), ) } + + override fun buildUrl(offset: Int, query: String?, tags: Set?, sortOrder: SortOrder): HttpUrl { + if (query.isNullOrEmpty() && tags.isNullOrEmpty()) { + val builder = urlBuilder().addQueryParameter("offset", offset.toString()) + when (sortOrder) { + SortOrder.POPULARITY -> { + builder.addPathSegment("mostviews") + builder.addQueryParameter("sort", "manga") + } + + SortOrder.RATING -> { + builder.addPathSegment("mostfavorites") + builder.addQueryParameter("sort", "manga") + } + + else -> { // SortOrder.NEWEST + builder.addPathSegment("manga") + builder.addPathSegment("newest") + } + } + return builder.build() + } + return super.buildUrl(offset, query, tags, sortOrder) + } } diff --git a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/multichan/YaoiChanParser.kt b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/multichan/YaoiChanParser.kt index 020824a7..f2fd2683 100644 --- a/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/multichan/YaoiChanParser.kt +++ b/src/main/kotlin/org/koitharu/kotatsu/parsers/site/ru/multichan/YaoiChanParser.kt @@ -6,12 +6,18 @@ import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaSource +import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.util.* @MangaSourceParser("YAOICHAN", "Яой-тян", "ru") internal class YaoiChanParser(context: MangaLoaderContext) : ChanParser(context, MangaSource.YAOICHAN) { - override val configKeyDomain = ConfigKey.Domain("yaoi-chan.me") + override val configKeyDomain = ConfigKey.Domain( + "v1.yaoi-chan.me", + "yaoi-chan.me", + ) + + override val sortOrders: Set = setOf(SortOrder.NEWEST) override suspend fun getDetails(manga: Manga): Manga { val doc = webClient.httpGet(manga.url.toAbsoluteUrl(domain)).parseHtml()