From c06e206cda0008108892ca8ee6c86f1c13d9cb5c Mon Sep 17 00:00:00 2001 From: Vetle Ledaal Date: Sun, 4 May 2025 15:31:57 +0200 Subject: [PATCH] AComics: replicate filters 1:1 from site (#8730) --- src/ru/acomics/build.gradle | 2 +- .../tachiyomi/extension/ru/acomics/AComics.kt | 187 +++++++++++++----- 2 files changed, 135 insertions(+), 54 deletions(-) diff --git a/src/ru/acomics/build.gradle b/src/ru/acomics/build.gradle index 9eb0ef671..f8e4f5cbf 100644 --- a/src/ru/acomics/build.gradle +++ b/src/ru/acomics/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'AComics' extClass = '.AComics' - extVersionCode = 6 + extVersionCode = 7 isNsfw = true } diff --git a/src/ru/acomics/src/eu/kanade/tachiyomi/extension/ru/acomics/AComics.kt b/src/ru/acomics/src/eu/kanade/tachiyomi/extension/ru/acomics/AComics.kt index 5c3136724..769f095ee 100644 --- a/src/ru/acomics/src/eu/kanade/tachiyomi/extension/ru/acomics/AComics.kt +++ b/src/ru/acomics/src/eu/kanade/tachiyomi/extension/ru/acomics/AComics.kt @@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.util.asJsoup +import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.Request import okhttp3.Response @@ -36,8 +37,7 @@ class AComics : ParsedHttpSource() { override val supportsLatest = true // ============================== Popular =============================== - override fun popularMangaRequest(page: Int): Request = - GET("$baseUrl/comics?$DEFAULT_COMIC_QUERIES&sort=subscr_count&skip=${10 * (page - 1)}", headers) + override fun popularMangaRequest(page: Int): Request = searchMangaRequest(page, "", Sort.POPULAR) override fun popularMangaSelector() = "section.serial-card" @@ -52,8 +52,7 @@ class AComics : ParsedHttpSource() { override fun popularMangaNextPageSelector() = "a.infinite-scroll" // =============================== Latest =============================== - override fun latestUpdatesRequest(page: Int): Request = - GET("$baseUrl/comics?$DEFAULT_COMIC_QUERIES&sort=last_update&skip=${10 * (page - 1)}", headers) + override fun latestUpdatesRequest(page: Int): Request = searchMangaRequest(page, "", Sort.LATEST) override fun latestUpdatesSelector() = popularMangaSelector() @@ -62,40 +61,107 @@ class AComics : ParsedHttpSource() { // =============================== Search =============================== override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val url = if (query.isNotEmpty()) { - "$baseUrl/search?keyword=$query" + val urlBuilder = if (query.isNotEmpty()) { + "$baseUrl/search".toHttpUrl().newBuilder() + .addQueryParameter("keyword", query) } else { - val urlBuilder = "$baseUrl/comics?type=0&subscribe=0&issue_count=2&sort=subscr_count" - .toHttpUrl() - .newBuilder() - .addQueryParameter("skip", "${10 * (page - 1)}") + val categories = mutableListOf() + val ratings = mutableListOf() + var comicType = "0" + var publication = "0" + var subscription = "0" + var minPages = "2" + var sort = "subscr_count" + for (filter in if (filters.isEmpty()) getFilterList() else filters) { when (filter) { - is GenreList -> { - val categories = filter.state.filter { it.state }.joinToString(",") { it.id } - urlBuilder.addQueryParameter("categories", categories) + is Categories -> { + val selected = filter + .state + .filter { it.state } + .map { it.id } + .sorted() + .map { it.toString() } + categories.addAll(selected) } - is Status -> { - val status = when (filter.state) { + is Ratings -> { + val selected = filter + .state + .filter { it.state } + .map { it.id } + .sorted() + .map { it.toString() } + ratings.addAll(selected) + } + + // --- + + is ComicType -> { + comicType = when (filter.state) { + 1 -> "orig" + 2 -> "trans" + else -> comicType + } + } + is Publication -> { + publication = when (filter.state) { 1 -> "no" 2 -> "yes" - else -> "0" + else -> publication } - urlBuilder.addQueryParameter("updatable", status) } - is RatingList -> { - filter.state.forEach { - if (it.state) { - urlBuilder.addQueryParameter("ratings[]", it.id) - } + is Subscription -> { + subscription = when (filter.state) { + 1 -> "yes" + 2 -> "no" + else -> subscription + } + } + is MinPages -> { + minPages = filter.state + .toIntOrNull() + ?.toString() + ?: minPages + } + is Sort -> { + sort = when (filter.state) { + 0 -> "last_update" + 1 -> "subscr_count" + 2 -> "issue_count" + 3 -> "serial_name" + else -> sort } } else -> {} } } - urlBuilder.build().toString() + + "$baseUrl/comics".toHttpUrl().newBuilder() + .addIndexedQueryParameters("categories", categories, page == 1) + .addIndexedQueryParameters("ratings", ratings, page == 1) + .addQueryParameter("type", comicType) + .addQueryParameter("updatable", publication) + .addQueryParameter("subscribe", subscription) + .addQueryParameter("issue_count", minPages) + .addQueryParameter("sort", sort) + } + + if (page > 1) { + urlBuilder.addQueryParameter("skip", ((page - 1) * 10).toString()) + } + + return GET(urlBuilder.build(), headers) + } + + fun HttpUrl.Builder.addIndexedQueryParameters( + name: String, + values: Iterable, + collapse: Boolean, + ): HttpUrl.Builder = apply { + values.forEachIndexed { i, value -> + val key = if (collapse) "$name[]" else "$name[$i]" + addQueryParameter(key, value) } - return GET(url, headers) } override fun searchMangaSelector() = popularMangaSelector() @@ -147,46 +213,61 @@ class AComics : ParsedHttpSource() { override fun imageUrlParse(document: Document) = throw UnsupportedOperationException() // ============================== Filters =============================== - private class Genre(name: String, val id: String) : Filter.CheckBox(name) - private class Rating(name: String, val id: String) : Filter.CheckBox(name, state = true) - private class Status : Filter.Select("Статус", arrayOf("Все", "Завершенный", "Продолжающийся")) + private class Genre(name: String, val id: Int) : Filter.CheckBox(name) + private class Rating(name: String, val id: Int) : Filter.CheckBox(name, state = true) - private class GenreList : Filter.Group( + private class Categories : Filter.Group( "Категории", listOf( - Genre("Животные", "1"), - Genre("Драма", "2"), - Genre("Фэнтези", "3"), - Genre("Игры", "4"), - Genre("Юмор", "5"), - Genre("Журнал", "6"), - Genre("Паранормальное", "7"), - Genre("Конец света", "8"), - Genre("Романтика", "9"), - Genre("Фантастика", "10"), - Genre("Бытовое", "11"), - Genre("Стимпанк", "12"), - Genre("Супергерои", "13"), + Genre("Животные", 1), + Genre("Драма", 2), + Genre("Фентези", 3), + Genre("Игры", 4), + Genre("Юмор", 5), + Genre("Журнал", 6), + Genre("Паранормальное", 7), + Genre("Конец света", 8), + Genre("Романтика", 9), + Genre("Фантастика", 10), + Genre("Бытовое", 11), + Genre("Стимпанк", 12), + Genre("Супергерои", 13), + Genre("Детектив", 14), + Genre("Историческое", 15), ), ) - private class RatingList : Filter.Group( + private class Ratings : Filter.Group( "Возрастная категория", listOf( - Rating("???", "1"), - Rating("0+", "2"), - Rating("6+", "3"), - Rating("12+", "4"), - Rating("16+", "5"), - Rating("18+", "6"), + Rating("NR", 1), + Rating("G", 2), + Rating("PG", 3), + Rating("PG-13", 4), + Rating("R", 5), + Rating("NC-17", 6), ), ) + private class ComicType : Filter.Select("Тип комикса", arrayOf("Все", "Оригинальный", "Перевод")) // "0", "orig", "trans" + private class Publication : Filter.Select("Публикация", arrayOf("Все", "Завершенный", "Продолжающийся")) // "0", "no", "yes" + private class Subscription : Filter.Select("Подписка", arrayOf("Все", "В моей ленте", "Кроме моей ленты")) // "0", "yes", "no" + private class MinPages : Filter.Text("Минимум страниц", state = "2") + private class Sort(state: Int = 1) : Filter.Select("Сортировка", arrayOf("по дате обновления", "по количеству подписчиков", "по количеству выпусков", "по алфавиту"), state = state) { // "last_update", "subscr_count", "issue_count", "serial_name" + companion object { + val LATEST = FilterList(Ratings(), Sort(0)) + val POPULAR = FilterList(Ratings(), Sort(1)) + } + } + override fun getFilterList() = FilterList( - Status(), - RatingList(), - GenreList(), + Categories(), + Ratings(), + Filter.Separator(), + ComicType(), + Publication(), + Subscription(), + MinPages(), + Sort(), ) } - -private const val DEFAULT_COMIC_QUERIES = "categories=&ratings[]=1&ratings[]=2&ratings[]=3&ratings[]=4&ratings[]=5&ratings[]=6&type=0&updatable=0&issue_count=2"