MangaGeko: Fix Filters (#4221)
* Fix Filters * Apply suggestion1 Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com> * Apply suggestion2 * Apply Suggetions - Apply AwkwardPeak7's suggestions --------- Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
This commit is contained in:
parent
ac57f5e3dd
commit
2f9ebadb08
|
@ -1,7 +1,7 @@
|
|||
ext {
|
||||
extName = 'MangaGeko'
|
||||
extClass = '.MangaRawClub'
|
||||
extVersionCode = 24
|
||||
extVersionCode = 25
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
package eu.kanade.tachiyomi.extension.en.mangarawclub
|
||||
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
|
@ -36,74 +34,121 @@ class MangaRawClub : ParsedHttpSource() {
|
|||
private val DATE_FORMATTER_2 by lazy { SimpleDateFormat("MMMMM dd, yyyy, h a", Locale.ENGLISH) }
|
||||
}
|
||||
|
||||
// Popular
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
return GET("$baseUrl/browse-comics/?results=$page&filter=views", headers)
|
||||
}
|
||||
|
||||
// Latest
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
return GET("$baseUrl/jumbo/manga/?results=$page", headers)
|
||||
}
|
||||
|
||||
// Search
|
||||
override fun getFilterList(): FilterList = getFilters()
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
if (query.isNotEmpty()) {
|
||||
// Query search
|
||||
val url = "$baseUrl/search/".toHttpUrl().newBuilder()
|
||||
.addQueryParameter("search", query)
|
||||
.build()
|
||||
return GET(url, headers)
|
||||
}
|
||||
|
||||
// Filter search
|
||||
val url = "$baseUrl/browse-comics/".toHttpUrl().newBuilder().apply {
|
||||
val tagsIncl: MutableList<String> = mutableListOf()
|
||||
val tagsExcl: MutableList<String> = mutableListOf()
|
||||
val genreIncl: MutableList<String> = mutableListOf()
|
||||
val genreExcl: MutableList<String> = mutableListOf()
|
||||
filters.forEach { filter ->
|
||||
when (filter) {
|
||||
is SelectFilter -> addQueryParameter("filter", filter.vals[filter.state])
|
||||
is GenreFilter -> {
|
||||
filter.state.forEach {
|
||||
when {
|
||||
it.isIncluded() -> genreIncl.add(it.name)
|
||||
it.isExcluded() -> genreExcl.add(it.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
is ChapterFilter -> addQueryParameter("minchap", filter.state)
|
||||
is TextFilter -> {
|
||||
if (filter.state.isNotEmpty()) {
|
||||
filter.state.split(",").filter(String::isNotBlank).map { tag ->
|
||||
val trimmed = tag.trim()
|
||||
when {
|
||||
trimmed.startsWith('-') -> tagsExcl.add(trimmed.removePrefix("-"))
|
||||
else -> tagsIncl.add(trimmed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
addQueryParameter("results", page.toString())
|
||||
addQueryParameter("genre_included", genreIncl.joinToString(","))
|
||||
addQueryParameter("genre_excluded", genreExcl.joinToString(","))
|
||||
addQueryParameter("tags_include", tagsIncl.joinToString(","))
|
||||
addQueryParameter("tags_exclude", tagsExcl.joinToString(","))
|
||||
}.build()
|
||||
|
||||
return GET(url, headers)
|
||||
}
|
||||
|
||||
// Selectors
|
||||
override fun searchMangaSelector() = "ul.novel-list > li.novel-item"
|
||||
override fun popularMangaSelector() = searchMangaSelector()
|
||||
override fun latestUpdatesSelector() = "ul.novel-list.chapters > li.novel-item"
|
||||
|
||||
override fun searchMangaFromElement(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
manga.title = element.select(".novel-title").first()?.text() ?: ""
|
||||
manga.thumbnail_url = element.select(".novel-cover img").attr("abs:data-src")
|
||||
manga.setUrlWithoutDomain(element.select("a").first()!!.attr("href"))
|
||||
return manga
|
||||
}
|
||||
override fun popularMangaFromElement(element: Element): SManga = searchMangaFromElement(element)
|
||||
override fun latestUpdatesFromElement(element: Element): SManga = searchMangaFromElement(element)
|
||||
|
||||
override fun searchMangaNextPageSelector() = ".paging .mg-pagination-chev:last-child:not(.chev-disabled)"
|
||||
override fun popularMangaNextPageSelector() = searchMangaNextPageSelector()
|
||||
override fun latestUpdatesNextPageSelector() = searchMangaNextPageSelector()
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
if (document.select(".novel-header").first() == null) {
|
||||
throw Exception("Page not found")
|
||||
// Manga from Element
|
||||
override fun searchMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
title = element.selectFirst(".novel-title")!!.ownText()
|
||||
thumbnail_url = element.select(".novel-cover img").attr("abs:data-src")
|
||||
setUrlWithoutDomain(element.selectFirst("a")!!.attr("href"))
|
||||
}
|
||||
override fun popularMangaFromElement(element: Element): SManga = searchMangaFromElement(element)
|
||||
override fun latestUpdatesFromElement(element: Element): SManga = searchMangaFromElement(element)
|
||||
|
||||
val manga = SManga.create()
|
||||
val author = document.select(".author a").first()?.attr("title")?.trim() ?: ""
|
||||
if (author.lowercase(Locale.ROOT) != "updating") {
|
||||
manga.author = author
|
||||
// Details
|
||||
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
||||
document.selectFirst(".novel-header") ?: throw Exception("Page not found")
|
||||
|
||||
author = document.selectFirst(".author a")?.attr("title")?.trim()?.takeIf { it.lowercase() != "updating" }
|
||||
|
||||
description = buildString {
|
||||
document.selectFirst(".description")?.ownText()?.substringAfter("Summary is")?.trim()?.let {
|
||||
append(it)
|
||||
}
|
||||
|
||||
var description = document.select(".description").first()?.text() ?: ""
|
||||
description = description.substringAfter("Summary is").trim()
|
||||
|
||||
val otherTitle = document.select(".alternative-title").first()?.text()?.trim() ?: ""
|
||||
if (otherTitle.isNotEmpty() && otherTitle.lowercase(Locale.ROOT) != "updating") {
|
||||
description += "\n\n$altName $otherTitle"
|
||||
}
|
||||
manga.description = description.trim()
|
||||
|
||||
manga.genre = document.select(".categories a[href*=genre]").joinToString(", ") {
|
||||
it.attr("title").removeSuffix("Genre").trim()
|
||||
.split(" ").joinToString(" ") { char ->
|
||||
char.lowercase().replaceFirstChar { c -> c.uppercase() }
|
||||
document.selectFirst(".alternative-title")?.ownText()?.trim()?.takeIf { it.isNotEmpty() && it.lowercase() != "updating" }?.let {
|
||||
append("\n\n$altName ${it.trim()}")
|
||||
}
|
||||
}
|
||||
|
||||
val statusElement = document.select("div.header-stats")
|
||||
manga.status = when {
|
||||
statusElement.select("strong.completed").isNotEmpty() -> SManga.COMPLETED
|
||||
statusElement.select("strong.ongoing").isNotEmpty() -> SManga.ONGOING
|
||||
genre = document.select(".categories a[href*=genre]").joinToString(", ") {
|
||||
it.ownText().trim()
|
||||
.split(" ").joinToString(" ") { word ->
|
||||
word.lowercase().replaceFirstChar { c -> c.uppercase() }
|
||||
}
|
||||
}
|
||||
|
||||
status = when {
|
||||
document.select("div.header-stats strong.completed").isNotEmpty() -> SManga.COMPLETED
|
||||
document.select("div.header-stats strong.ongoing").isNotEmpty() -> SManga.ONGOING
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
|
||||
val coverElement = document.select(".cover img")
|
||||
manga.thumbnail_url = when {
|
||||
coverElement.attr("data-src").isNotEmpty() -> coverElement.attr("data-src")
|
||||
else -> coverElement.attr("src")
|
||||
}
|
||||
return manga
|
||||
thumbnail_url = document.selectFirst(".cover img")?.let { img ->
|
||||
img.attr("data-src").takeIf { it.isNotEmpty() } ?: img.attr("src")
|
||||
} ?: thumbnail_url
|
||||
}
|
||||
|
||||
// Chapters
|
||||
override fun chapterListSelector() = "ul.chapter-list > li"
|
||||
|
||||
override fun chapterListRequest(manga: SManga): Request {
|
||||
|
@ -111,19 +156,13 @@ class MangaRawClub : ParsedHttpSource() {
|
|||
return GET(url, headers)
|
||||
}
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter {
|
||||
val chapter = SChapter.create()
|
||||
chapter.setUrlWithoutDomain(element.select("a").attr("href"))
|
||||
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||
setUrlWithoutDomain(element.select("a").attr("href"))
|
||||
|
||||
val name = element.select(".chapter-title").text().removeSuffix("-eng-li")
|
||||
chapter.name = "Chapter $name"
|
||||
val number = parseChapterNumber(name)
|
||||
if (number != null) {
|
||||
chapter.chapter_number = number
|
||||
}
|
||||
val date = parseChapterDate(element.select(".chapter-update").attr("datetime"))
|
||||
chapter.date_upload = date
|
||||
return chapter
|
||||
this.name = "Chapter $name"
|
||||
|
||||
date_upload = parseChapterDate(element.select(".chapter-update").attr("datetime"))
|
||||
}
|
||||
|
||||
private fun parseChapterDate(string: String): Long {
|
||||
|
@ -133,140 +172,12 @@ class MangaRawClub : ParsedHttpSource() {
|
|||
?: runCatching { DATE_FORMATTER_2.parse(date)?.time }.getOrNull() ?: 0L
|
||||
}
|
||||
|
||||
private fun parseChapterNumber(string: String): Float? {
|
||||
if (string.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
return string.split("-")[0].toFloatOrNull()
|
||||
?: string.split(".")[0].toFloatOrNull()
|
||||
}
|
||||
|
||||
// Pages
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val pages = mutableListOf<Page>()
|
||||
document.select(".page-in img[onerror]").forEachIndexed { i, it ->
|
||||
pages.add(Page(i, imageUrl = it.attr("src")))
|
||||
return document.select(".page-in img[onerror]").mapIndexed { i, it ->
|
||||
Page(i, imageUrl = it.attr("src"))
|
||||
}
|
||||
return pages
|
||||
}
|
||||
|
||||
override fun imageUrlParse(document: Document) = throw UnsupportedOperationException()
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
if (query.isNotEmpty()) {
|
||||
// Query search
|
||||
return GET("$baseUrl/search/?search=$query", headers)
|
||||
}
|
||||
|
||||
// Filter search
|
||||
val url = "$baseUrl/browse-comics/".toHttpUrl().newBuilder()
|
||||
val requestBody = FormBody.Builder()
|
||||
url.addQueryParameter("results", page.toString())
|
||||
|
||||
filters.forEach { filter ->
|
||||
when (filter) {
|
||||
is GenrePairList -> url.addQueryParameter("genre", filter.toUriPart()) // GET
|
||||
is Order -> url.addQueryParameter("filter", filter.toUriPart()) // GET
|
||||
is Status -> requestBody.add("status", filter.toUriPart()) // POST
|
||||
is Action -> requestBody.add("action", filter.toUriPart()) // POST
|
||||
is GenreList -> { // POST
|
||||
filter.state.filter { it.state == 1 }.forEach {
|
||||
requestBody.add("options[]", it.name)
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
return GET(url.build(), headers)
|
||||
// return POST("$baseUrl/search", headers, requestBody.build()) // csrfmiddlewaretoken required
|
||||
}
|
||||
|
||||
override fun getFilterList() = FilterList(
|
||||
Filter.Header("NOTE: Ignored if using text search!"),
|
||||
Filter.Separator(),
|
||||
Order(),
|
||||
GenrePairList(),
|
||||
// Action(),
|
||||
// Status(),
|
||||
// GenreList(getGenreList())
|
||||
)
|
||||
|
||||
private class Action : UriPartFilter(
|
||||
"Action",
|
||||
arrayOf(
|
||||
Pair("All", ""),
|
||||
Pair("Include", "include"),
|
||||
Pair("Exclude", "exclude"),
|
||||
),
|
||||
)
|
||||
|
||||
private class Order : UriPartFilter(
|
||||
"Order",
|
||||
arrayOf(
|
||||
Pair("Random", "Random"),
|
||||
Pair("Updated", "Updated"),
|
||||
Pair("New", "New"),
|
||||
Pair("Views", "views"),
|
||||
),
|
||||
)
|
||||
|
||||
private class Status : UriPartFilter(
|
||||
"Status",
|
||||
arrayOf(
|
||||
Pair("All", ""),
|
||||
Pair("Completed", "Completed"),
|
||||
Pair("Ongoing", "Ongoing"),
|
||||
),
|
||||
)
|
||||
|
||||
private class GenrePairList : UriPartFilter(
|
||||
"Genres",
|
||||
arrayOf(
|
||||
Pair("All", ""),
|
||||
Pair("R-18", "R-18"),
|
||||
Pair("Action", "Action"),
|
||||
Pair("Adult", "Adult"),
|
||||
Pair("Adventure", "Adventure"),
|
||||
Pair("Comedy", "Comedy"),
|
||||
Pair("Cooking", "Cooking"),
|
||||
Pair("Doujinshi", "Doujinshi"),
|
||||
Pair("Drama", "Drama"),
|
||||
Pair("Ecchi", "Ecchi"),
|
||||
Pair("Fantasy", "Fantasy"),
|
||||
Pair("Gender bender", "Gender bender"),
|
||||
Pair("Harem", "Harem"),
|
||||
Pair("Historical", "Historical"),
|
||||
Pair("Horror", "Horror"),
|
||||
Pair("Isekai", "Isekai"),
|
||||
Pair("Josei", "Josei"),
|
||||
Pair("Ladies", "ladies"),
|
||||
Pair("Manhua", "Manhua"),
|
||||
Pair("Manhwa", "Manhwa"),
|
||||
Pair("Martial arts", "Martial arts"),
|
||||
Pair("Mature", "Mature"),
|
||||
Pair("Mecha", "Mecha"),
|
||||
Pair("Medical", "Medical"),
|
||||
Pair("Mystery", "Mystery"),
|
||||
Pair("One shot", "One shot"),
|
||||
Pair("Psychological", "Psychological"),
|
||||
Pair("Romance", "Romance"),
|
||||
Pair("School life", "School life"),
|
||||
Pair("Sci fi", "Sci fi"),
|
||||
Pair("Seinen", "Seinen"),
|
||||
Pair("Shoujo", "Shoujo"),
|
||||
Pair("Shounen", "Shounen"),
|
||||
Pair("Slice of life", "Slice of life"),
|
||||
Pair("Sports", "Sports"),
|
||||
Pair("Supernatural", "Supernatural"),
|
||||
Pair("Tragedy", "Tragedy"),
|
||||
Pair("Webtoons", "Webtoons"),
|
||||
),
|
||||
)
|
||||
|
||||
private class Genre(name: String) : Filter.TriState(name)
|
||||
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres+", genres)
|
||||
|
||||
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
|
||||
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
|
||||
fun toUriPart() = vals[state].second
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
package eu.kanade.tachiyomi.extension.en.mangarawclub
|
||||
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
|
||||
fun getFilters(): FilterList {
|
||||
return FilterList(
|
||||
Filter.Header("NOTE: Ignored if using text search!"),
|
||||
Filter.Separator(),
|
||||
SelectFilter("Sort by", getSortsList),
|
||||
GenreFilter("Genre", getGenres),
|
||||
Filter.Separator(),
|
||||
Filter.Header("Separate tags with commas (,)"),
|
||||
Filter.Header("Prepend with dash (-) to exclude"),
|
||||
TextFilter("Tags"),
|
||||
Filter.Separator(),
|
||||
ChapterFilter("Minimum Chapter"),
|
||||
)
|
||||
}
|
||||
|
||||
internal class GenreFilter(name: String, genreList: List<String>) :
|
||||
Filter.Group<TriFilter>(name, genreList.map { TriFilter(it) })
|
||||
|
||||
internal open class TriFilter(name: String) : Filter.TriState(name)
|
||||
|
||||
internal open class ChapterFilter(name: String) : Filter.Text(name)
|
||||
|
||||
internal open class TextFilter(name: String) : Filter.Text(name)
|
||||
|
||||
internal open class SelectFilter(name: String, val vals: List<String>, state: Int = 0) :
|
||||
Filter.Select<String>(name, vals.map { it }.toTypedArray(), state)
|
||||
|
||||
private val getGenres = listOf(
|
||||
"R-18",
|
||||
"Action",
|
||||
"Adult",
|
||||
"Adventure",
|
||||
"Comedy",
|
||||
"Cooking",
|
||||
"Doujinshi",
|
||||
"Drama",
|
||||
"Ecchi",
|
||||
"Fantasy",
|
||||
"Gender bender",
|
||||
"Harem",
|
||||
"Historical",
|
||||
"Horror",
|
||||
"Isekai",
|
||||
"Josei",
|
||||
"Ladies",
|
||||
"Manhua",
|
||||
"Manhwa",
|
||||
"Martial arts",
|
||||
"Mature",
|
||||
"Mecha",
|
||||
"Medical",
|
||||
"Mystery",
|
||||
"One shot",
|
||||
"Psychological",
|
||||
"Romance",
|
||||
"School life",
|
||||
"Sci fi",
|
||||
"Seinen",
|
||||
"Shoujo",
|
||||
"Shounen",
|
||||
"Slice of life",
|
||||
"Sports",
|
||||
"Supernatural",
|
||||
"Tragedy",
|
||||
"Webtoons",
|
||||
)
|
||||
|
||||
private val getSortsList = listOf(
|
||||
"Random",
|
||||
"New",
|
||||
"Updated",
|
||||
"Views",
|
||||
)
|
Loading…
Reference in New Issue