feat(comix): Add rating score, NSFW toggle, and filter fix (#11682)
* bump * refactor: fix **type** filter param to match api * add configurable rating score display * rearrange filter * add preference to hide NSFW content
This commit is contained in:
parent
f59060dc92
commit
6eae846dc8
@ -1,7 +1,7 @@
|
||||
ext {
|
||||
extName = 'Comix'
|
||||
extClass = '.Comix'
|
||||
extVersionCode = 1
|
||||
extVersionCode = 2
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
|
||||
@ -39,12 +39,18 @@ class Comix : HttpSource(), ConfigurableSource {
|
||||
|
||||
/******************************* POPULAR MANGA ************************************/
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
val url = apiUrl.toHttpUrl().newBuilder()
|
||||
.addPathSegment("manga")
|
||||
.addQueryParameter("order[views_30d]", "desc")
|
||||
.addQueryParameter("limit", "50")
|
||||
.addQueryParameter("page", page.toString())
|
||||
.build()
|
||||
val url = apiUrl.toHttpUrl().newBuilder().apply {
|
||||
addPathSegment("manga")
|
||||
addQueryParameter("order[views_30d]", "desc")
|
||||
addQueryParameter("limit", "50")
|
||||
addQueryParameter("page", page.toString())
|
||||
|
||||
if (preferences.hideNsfw()) {
|
||||
NSFW_GENRE_IDS.forEach {
|
||||
addQueryParameter("genres[]", "-$it")
|
||||
}
|
||||
}
|
||||
}.build()
|
||||
|
||||
return GET(url, headers)
|
||||
}
|
||||
@ -54,12 +60,18 @@ class Comix : HttpSource(), ConfigurableSource {
|
||||
|
||||
/******************************* LATEST MANGA ************************************/
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
val url = apiUrl.toHttpUrl().newBuilder()
|
||||
.addPathSegment("manga")
|
||||
.addQueryParameter("order[chapter_updated_at]", "desc")
|
||||
.addQueryParameter("limit", "50")
|
||||
.addQueryParameter("page", page.toString())
|
||||
.build()
|
||||
val url = apiUrl.toHttpUrl().newBuilder().apply {
|
||||
addPathSegment("manga")
|
||||
addQueryParameter("order[chapter_updated_at]", "desc")
|
||||
addQueryParameter("limit", "50")
|
||||
addQueryParameter("page", page.toString())
|
||||
|
||||
if (preferences.hideNsfw()) {
|
||||
NSFW_GENRE_IDS.forEach {
|
||||
addQueryParameter("genres[]", "-$it")
|
||||
}
|
||||
}
|
||||
}.build()
|
||||
|
||||
return GET(url, headers)
|
||||
}
|
||||
@ -71,23 +83,30 @@ class Comix : HttpSource(), ConfigurableSource {
|
||||
override fun getFilterList() = ComixFilters().getFilterList()
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val url = apiUrl.toHttpUrl().newBuilder()
|
||||
.addPathSegment("manga")
|
||||
val url = apiUrl.toHttpUrl().newBuilder().apply {
|
||||
addPathSegment("manga")
|
||||
|
||||
filters.filterIsInstance<ComixFilters.UriFilter>()
|
||||
.forEach { it.addToUri(url) }
|
||||
filters.filterIsInstance<ComixFilters.UriFilter>()
|
||||
.forEach { it.addToUri(this) }
|
||||
|
||||
// Make searches accurate
|
||||
if (query.isNotBlank()) {
|
||||
url.addQueryParameter("keyword", query)
|
||||
url.removeAllQueryParameters("order[views_30d]")
|
||||
url.setQueryParameter("order[relevance]", "desc")
|
||||
}
|
||||
// Make searches accurate
|
||||
if (query.isNotBlank()) {
|
||||
addQueryParameter("keyword", query)
|
||||
removeAllQueryParameters("order[views_30d]")
|
||||
setQueryParameter("order[relevance]", "desc")
|
||||
}
|
||||
|
||||
url.addQueryParameter("limit", "50")
|
||||
.addQueryParameter("page", page.toString())
|
||||
if (preferences.hideNsfw()) {
|
||||
NSFW_GENRE_IDS.forEach {
|
||||
addQueryParameter("genres[]", "-$it")
|
||||
}
|
||||
}
|
||||
|
||||
return GET(url.build(), headers)
|
||||
addQueryParameter("limit", "50")
|
||||
addQueryParameter("page", page.toString())
|
||||
}.build()
|
||||
|
||||
return GET(url, headers)
|
||||
}
|
||||
|
||||
override fun searchMangaParse(response: Response): MangasPage {
|
||||
@ -121,6 +140,7 @@ class Comix : HttpSource(), ConfigurableSource {
|
||||
return mangaResponse.result.toSManga(
|
||||
preferences.posterQuality(),
|
||||
preferences.alternativeNamesInDescription(),
|
||||
preferences.scorePosition(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -253,6 +273,13 @@ class Comix : HttpSource(), ConfigurableSource {
|
||||
setDefaultValue("large")
|
||||
}.let(screen::addPreference)
|
||||
|
||||
SwitchPreferenceCompat(screen.context).apply {
|
||||
key = NSFW_PREF
|
||||
title = "Hide NSFW content"
|
||||
summary = "Hides NSFW content from popular, latest, and search lists."
|
||||
setDefaultValue(false)
|
||||
}.let(screen::addPreference)
|
||||
|
||||
SwitchPreferenceCompat(screen.context).apply {
|
||||
key = DEDUPLICATE_CHAPTERS
|
||||
title = "Deduplicate Chapters"
|
||||
@ -269,6 +296,15 @@ class Comix : HttpSource(), ConfigurableSource {
|
||||
|
||||
setDefaultValue(false)
|
||||
}.let(screen::addPreference)
|
||||
|
||||
ListPreference(screen.context).apply {
|
||||
key = PREF_SCORE_POSITION
|
||||
title = "Score display position"
|
||||
summary = "%s"
|
||||
entries = arrayOf("Top of description", "Bottom of description", "Don't show")
|
||||
entryValues = arrayOf("top", "bottom", "none")
|
||||
setDefaultValue("top")
|
||||
}.let(screen::addPreference)
|
||||
}
|
||||
|
||||
private fun SharedPreferences.posterQuality() =
|
||||
@ -280,9 +316,19 @@ class Comix : HttpSource(), ConfigurableSource {
|
||||
private fun SharedPreferences.alternativeNamesInDescription() =
|
||||
getBoolean(ALTERNATIVE_NAMES_IN_DESCRIPTION, false)
|
||||
|
||||
private fun SharedPreferences.scorePosition() =
|
||||
getString(PREF_SCORE_POSITION, "top") ?: "top"
|
||||
|
||||
private fun SharedPreferences.hideNsfw() =
|
||||
getBoolean(NSFW_PREF, false)
|
||||
|
||||
companion object {
|
||||
private const val PREF_POSTER_QUALITY = "pref_poster_quality"
|
||||
private const val NSFW_PREF = "nsfw_pref"
|
||||
private const val DEDUPLICATE_CHAPTERS = "pref_deduplicate_chapters"
|
||||
private const val ALTERNATIVE_NAMES_IN_DESCRIPTION = "pref_alt_names_in_description"
|
||||
private const val PREF_SCORE_POSITION = "pref_score_position"
|
||||
|
||||
private val NSFW_GENRE_IDS = listOf("87264", "8", "87265", "13", "87266", "87268")
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,8 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
|
||||
@Serializable
|
||||
data class Term(
|
||||
@ -33,6 +35,8 @@ class Manga(
|
||||
private val genre: List<Term>?,
|
||||
private val theme: List<Term>?,
|
||||
private val demographic: List<Term>?,
|
||||
@SerialName("rated_avg")
|
||||
private val ratedAvg: Double = 0.0,
|
||||
) {
|
||||
@Serializable
|
||||
class Poster(
|
||||
@ -47,15 +51,44 @@ class Manga(
|
||||
}
|
||||
}
|
||||
|
||||
private val fancyScore: String
|
||||
get() {
|
||||
if (ratedAvg == 0.0) return ""
|
||||
|
||||
val score = ratedAvg.toBigDecimal()
|
||||
val stars = score.div(BigDecimal(2))
|
||||
.setScale(0, RoundingMode.HALF_UP).toInt()
|
||||
|
||||
val scoreString = if (score.scale() == 0) {
|
||||
score.toPlainString()
|
||||
} else {
|
||||
score.stripTrailingZeros().toPlainString()
|
||||
}
|
||||
|
||||
return buildString {
|
||||
append("★".repeat(stars))
|
||||
if (stars < 5) append("☆".repeat(5 - stars))
|
||||
append(" $scoreString")
|
||||
}
|
||||
}
|
||||
|
||||
fun toSManga(
|
||||
posterQuality: String?,
|
||||
altTitlesInDesc: Boolean = false,
|
||||
scorePosition: String,
|
||||
) = SManga.create().apply {
|
||||
url = "/$hashId"
|
||||
title = this@Manga.title
|
||||
author = this@Manga.author.takeUnless { it.isNullOrEmpty() }?.joinToString { it.title }
|
||||
artist = this@Manga.artist.takeUnless { it.isNullOrEmpty() }?.joinToString { it.title }
|
||||
description = buildString {
|
||||
if (scorePosition == "top") {
|
||||
fancyScore.takeIf { it.isNotEmpty() }?.let {
|
||||
append(it)
|
||||
append("\n\n")
|
||||
}
|
||||
}
|
||||
|
||||
synopsis.takeUnless { it.isNullOrEmpty() }
|
||||
?.let { append(it) }
|
||||
altTitles.takeIf { altTitlesInDesc && it.isNotEmpty() }
|
||||
@ -64,6 +97,13 @@ class Manga(
|
||||
append("Alternative Names:\n")
|
||||
append(altName.joinToString("\n"))
|
||||
}
|
||||
|
||||
if (scorePosition == "bottom") {
|
||||
fancyScore.takeIf { it.isNotEmpty() }?.let {
|
||||
if (isNotEmpty()) append("\n\n")
|
||||
append(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
initialized = true
|
||||
status = when (this@Manga.status) {
|
||||
|
||||
@ -105,10 +105,10 @@ class ComixFilters {
|
||||
fun getFilterList() = FilterList(
|
||||
SortFilter(getSortables()),
|
||||
StatusFilter(),
|
||||
MinChapterFilter(),
|
||||
GenreFilter(getGenres()),
|
||||
TypeFilter(),
|
||||
DemographicFilter(getDemographics()),
|
||||
MinChapterFilter(),
|
||||
Filter.Separator(),
|
||||
Filter.Header("Release Year"),
|
||||
YearFromFilter(),
|
||||
@ -180,7 +180,7 @@ class ComixFilters {
|
||||
|
||||
private class TypeFilter : UriMultiSelectFilter(
|
||||
"Type",
|
||||
"type",
|
||||
"types[]",
|
||||
arrayOf(
|
||||
Pair("Manga", "manga"),
|
||||
Pair("Manhwa", "manhwa"),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user