AComics: replicate filters 1:1 from site (#8730)

This commit is contained in:
Vetle Ledaal 2025-05-04 15:31:57 +02:00 committed by Draff
parent d3d573fe77
commit c06e206cda
No known key found for this signature in database
GPG Key ID: E8A89F3211677653
2 changed files with 135 additions and 54 deletions

View File

@ -1,7 +1,7 @@
ext { ext {
extName = 'AComics' extName = 'AComics'
extClass = '.AComics' extClass = '.AComics'
extVersionCode = 6 extVersionCode = 7
isNsfw = true isNsfw = true
} }

View File

@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
@ -36,8 +37,7 @@ class AComics : ParsedHttpSource() {
override val supportsLatest = true override val supportsLatest = true
// ============================== Popular =============================== // ============================== Popular ===============================
override fun popularMangaRequest(page: Int): Request = override fun popularMangaRequest(page: Int): Request = searchMangaRequest(page, "", Sort.POPULAR)
GET("$baseUrl/comics?$DEFAULT_COMIC_QUERIES&sort=subscr_count&skip=${10 * (page - 1)}", headers)
override fun popularMangaSelector() = "section.serial-card" override fun popularMangaSelector() = "section.serial-card"
@ -52,8 +52,7 @@ class AComics : ParsedHttpSource() {
override fun popularMangaNextPageSelector() = "a.infinite-scroll" override fun popularMangaNextPageSelector() = "a.infinite-scroll"
// =============================== Latest =============================== // =============================== Latest ===============================
override fun latestUpdatesRequest(page: Int): Request = override fun latestUpdatesRequest(page: Int): Request = searchMangaRequest(page, "", Sort.LATEST)
GET("$baseUrl/comics?$DEFAULT_COMIC_QUERIES&sort=last_update&skip=${10 * (page - 1)}", headers)
override fun latestUpdatesSelector() = popularMangaSelector() override fun latestUpdatesSelector() = popularMangaSelector()
@ -62,40 +61,107 @@ class AComics : ParsedHttpSource() {
// =============================== Search =============================== // =============================== Search ===============================
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = if (query.isNotEmpty()) { val urlBuilder = if (query.isNotEmpty()) {
"$baseUrl/search?keyword=$query" "$baseUrl/search".toHttpUrl().newBuilder()
.addQueryParameter("keyword", query)
} else { } else {
val urlBuilder = "$baseUrl/comics?type=0&subscribe=0&issue_count=2&sort=subscr_count" val categories = mutableListOf<String>()
.toHttpUrl() val ratings = mutableListOf<String>()
.newBuilder() var comicType = "0"
.addQueryParameter("skip", "${10 * (page - 1)}") var publication = "0"
var subscription = "0"
var minPages = "2"
var sort = "subscr_count"
for (filter in if (filters.isEmpty()) getFilterList() else filters) { for (filter in if (filters.isEmpty()) getFilterList() else filters) {
when (filter) { when (filter) {
is GenreList -> { is Categories -> {
val categories = filter.state.filter { it.state }.joinToString(",") { it.id } val selected = filter
urlBuilder.addQueryParameter("categories", categories) .state
.filter { it.state }
.map { it.id }
.sorted()
.map { it.toString() }
categories.addAll(selected)
} }
is Status -> { is Ratings -> {
val status = when (filter.state) { 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" 1 -> "no"
2 -> "yes" 2 -> "yes"
else -> "0" else -> publication
} }
urlBuilder.addQueryParameter("updatable", status)
} }
is RatingList -> { is Subscription -> {
filter.state.forEach { subscription = when (filter.state) {
if (it.state) { 1 -> "yes"
urlBuilder.addQueryParameter("ratings[]", it.id) 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 -> {} 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<String?>,
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() override fun searchMangaSelector() = popularMangaSelector()
@ -147,46 +213,61 @@ class AComics : ParsedHttpSource() {
override fun imageUrlParse(document: Document) = throw UnsupportedOperationException() override fun imageUrlParse(document: Document) = throw UnsupportedOperationException()
// ============================== Filters =============================== // ============================== Filters ===============================
private class Genre(name: String, val id: String) : Filter.CheckBox(name) private class Genre(name: String, val id: Int) : Filter.CheckBox(name)
private class Rating(name: String, val id: String) : Filter.CheckBox(name, state = true) private class Rating(name: String, val id: Int) : Filter.CheckBox(name, state = true)
private class Status : Filter.Select<String>("Статус", arrayOf("Все", "Завершенный", "Продолжающийся"))
private class GenreList : Filter.Group<Genre>( private class Categories : Filter.Group<Genre>(
"Категории", "Категории",
listOf( listOf(
Genre("Животные", "1"), Genre("Животные", 1),
Genre("Драма", "2"), Genre("Драма", 2),
Genre("Фэнтези", "3"), Genre("Фентези", 3),
Genre("Игры", "4"), Genre("Игры", 4),
Genre("Юмор", "5"), Genre("Юмор", 5),
Genre("Журнал", "6"), Genre("Журнал", 6),
Genre("Паранормальное", "7"), Genre("Паранормальное", 7),
Genre("Конец света", "8"), Genre("Конец света", 8),
Genre("Романтика", "9"), Genre("Романтика", 9),
Genre("Фантастика", "10"), Genre("Фантастика", 10),
Genre("Бытовое", "11"), Genre("Бытовое", 11),
Genre("Стимпанк", "12"), Genre("Стимпанк", 12),
Genre("Супергерои", "13"), Genre("Супергерои", 13),
Genre("Детектив", 14),
Genre("Историческое", 15),
), ),
) )
private class RatingList : Filter.Group<Rating>( private class Ratings : Filter.Group<Rating>(
"Возрастная категория", "Возрастная категория",
listOf( listOf(
Rating("???", "1"), Rating("NR", 1),
Rating("0+", "2"), Rating("G", 2),
Rating("6+", "3"), Rating("PG", 3),
Rating("12+", "4"), Rating("PG-13", 4),
Rating("16+", "5"), Rating("R", 5),
Rating("18+", "6"), Rating("NC-17", 6),
), ),
) )
private class ComicType : Filter.Select<String>("Тип комикса", arrayOf("Все", "Оригинальный", "Перевод")) // "0", "orig", "trans"
private class Publication : Filter.Select<String>("Публикация", arrayOf("Все", "Завершенный", "Продолжающийся")) // "0", "no", "yes"
private class Subscription : Filter.Select<String>("Подписка", arrayOf("Все", "В моей ленте", "Кроме моей ленты")) // "0", "yes", "no"
private class MinPages : Filter.Text("Минимум страниц", state = "2")
private class Sort(state: Int = 1) : Filter.Select<String>("Сортировка", 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( override fun getFilterList() = FilterList(
Status(), Categories(),
RatingList(), Ratings(),
GenreList(), 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"