Kagane: Add excluded genres & Fix chapter number (#11537)
* Don't use DTO chapter number as it is , not actual chapter number * Add Exclude Genres preference * pump version * Move 'Show scanlations' to preferences * Add source to tags so it can be searched with filter by clicking on it * Don't sort by relevant if filtering without query string * Some sources prefer 'number_sort' * catching error * optimize
This commit is contained in:
parent
9194e31208
commit
b8154e7698
@ -1,7 +1,7 @@
|
||||
ext {
|
||||
extName = 'Kagane'
|
||||
extClass = '.Kagane'
|
||||
extVersionCode = 9
|
||||
extVersionCode = 10
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ class DetailsDto(
|
||||
|
||||
author = authors.joinToString()
|
||||
description = desc.toString()
|
||||
genre = genres.joinToString()
|
||||
genre = (listOf(source) + genres).joinToString()
|
||||
status = this@DetailsDto.status.toStatus()
|
||||
}
|
||||
|
||||
@ -86,11 +86,13 @@ class ChapterDto(
|
||||
@SerialName("number_sort")
|
||||
val number: Float,
|
||||
) {
|
||||
fun toSChapter(): SChapter = SChapter.create().apply {
|
||||
fun toSChapter(useSourceChapterNumber: Boolean = false): SChapter = SChapter.create().apply {
|
||||
url = "$seriesId;$id;$pagesCount"
|
||||
name = title
|
||||
date_upload = dateFormat.tryParse(releaseDate)
|
||||
chapter_number = number
|
||||
if (useSourceChapterNumber) {
|
||||
chapter_number = number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -102,8 +102,6 @@ internal class SourcesFilter(
|
||||
},
|
||||
)
|
||||
|
||||
internal class ScanlationsFilter() : Filter.CheckBox("Show scanlations", true)
|
||||
|
||||
class FilterData(
|
||||
val id: String,
|
||||
val name: String,
|
||||
@ -116,7 +114,7 @@ internal open class JsonMultiSelectFilter(
|
||||
private val param: String,
|
||||
genres: List<MultiSelectOption>,
|
||||
) : Filter.Group<MultiSelectOption>(name, genres), JsonFilter {
|
||||
override fun addToJsonObject(builder: JsonObjectBuilder) {
|
||||
override fun addToJsonObject(builder: JsonObjectBuilder, additionExcludeList: List<String>) {
|
||||
val whatToInclude = state.filter { it.state }.map { it.id }
|
||||
|
||||
if (whatToInclude.isNotEmpty()) {
|
||||
@ -134,9 +132,9 @@ internal open class JsonMultiSelectTriFilter(
|
||||
private val param: String,
|
||||
genres: List<MultiSelectTriOption>,
|
||||
) : Filter.Group<MultiSelectTriOption>(name, genres), JsonFilter {
|
||||
override fun addToJsonObject(builder: JsonObjectBuilder) {
|
||||
override fun addToJsonObject(builder: JsonObjectBuilder, additionExcludeList: List<String>) {
|
||||
val whatToInclude = state.filter { it.state == TriState.STATE_INCLUDE }.map { it.id }
|
||||
val whatToExclude = state.filter { it.state == TriState.STATE_EXCLUDE }.map { it.id }
|
||||
val whatToExclude = state.filter { it.state == TriState.STATE_EXCLUDE }.map { it.id } + additionExcludeList
|
||||
|
||||
with(builder) {
|
||||
if (whatToInclude.isNotEmpty()) {
|
||||
@ -160,5 +158,74 @@ internal open class JsonMultiSelectTriFilter(
|
||||
}
|
||||
|
||||
internal interface JsonFilter {
|
||||
fun addToJsonObject(builder: JsonObjectBuilder)
|
||||
fun addToJsonObject(builder: JsonObjectBuilder, additionExcludeList: List<String> = emptyList())
|
||||
}
|
||||
|
||||
internal val GenresList = arrayOf(
|
||||
"Romance",
|
||||
"Drama",
|
||||
"Manhwa",
|
||||
"Fantasy",
|
||||
"Manga",
|
||||
"Comedy",
|
||||
"Action",
|
||||
"Mature",
|
||||
"LGBTQIA+",
|
||||
"Shoujo",
|
||||
"Josei",
|
||||
"Shounen",
|
||||
"Supernatural",
|
||||
"Boys' Love",
|
||||
"Slice of Life",
|
||||
"Seinen",
|
||||
"Adventure",
|
||||
"Manhua",
|
||||
"School Life",
|
||||
"Smut",
|
||||
"Yaoi",
|
||||
"Hentai",
|
||||
"Historical",
|
||||
"Isekai",
|
||||
"Mystery",
|
||||
"Psychological",
|
||||
"Tragedy",
|
||||
"Harem",
|
||||
"Martial Arts",
|
||||
"Science Fiction",
|
||||
"Shounen Ai",
|
||||
"Ecchi",
|
||||
"Horror",
|
||||
"Girls' Love",
|
||||
"Anime",
|
||||
"Thriller",
|
||||
"Yuri",
|
||||
"Coming of Age",
|
||||
"Sports",
|
||||
"OEL",
|
||||
"Gender Bender",
|
||||
"Suspense",
|
||||
"Music",
|
||||
"Shoujo Ai",
|
||||
"Award Winning",
|
||||
"Cooking",
|
||||
"Crime",
|
||||
"Doujinshi",
|
||||
"Mecha",
|
||||
"Oneshot",
|
||||
"Philosophical",
|
||||
"Magical Girls",
|
||||
"Anthology",
|
||||
"Wuxia",
|
||||
"Medical",
|
||||
"official colored",
|
||||
"family life",
|
||||
"parody",
|
||||
"Superhero",
|
||||
"4-Koma",
|
||||
"educational",
|
||||
"self-published",
|
||||
"Animals",
|
||||
"Magic",
|
||||
"fan colored",
|
||||
"monsters",
|
||||
)
|
||||
|
||||
@ -13,6 +13,7 @@ import android.webkit.PermissionRequest
|
||||
import android.webkit.WebChromeClient
|
||||
import android.webkit.WebView
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.MultiSelectListPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
@ -125,7 +126,7 @@ class Kagane : HttpSource(), ConfigurableSource {
|
||||
ContentRatingFilter(
|
||||
preferences.contentRating.toSet(),
|
||||
),
|
||||
ScanlationsFilter(),
|
||||
GenresFilter(emptyList()),
|
||||
),
|
||||
)
|
||||
|
||||
@ -142,7 +143,7 @@ class Kagane : HttpSource(), ConfigurableSource {
|
||||
ContentRatingFilter(
|
||||
preferences.contentRating.toSet(),
|
||||
),
|
||||
ScanlationsFilter(),
|
||||
GenresFilter(emptyList()),
|
||||
),
|
||||
)
|
||||
|
||||
@ -154,6 +155,9 @@ class Kagane : HttpSource(), ConfigurableSource {
|
||||
val body = buildJsonObject {
|
||||
filters.forEach { filter ->
|
||||
when (filter) {
|
||||
is GenresFilter -> {
|
||||
filter.addToJsonObject(this, preferences.excludedGenres.toList())
|
||||
}
|
||||
is JsonFilter -> {
|
||||
filter.addToJsonObject(this)
|
||||
}
|
||||
@ -175,15 +179,17 @@ class Kagane : HttpSource(), ConfigurableSource {
|
||||
is SortFilter -> {
|
||||
filter.toUriPart().takeIf { it.isNotEmpty() }
|
||||
?.let { uriPart -> addQueryParameter("sort", uriPart) }
|
||||
}
|
||||
|
||||
is ScanlationsFilter -> {
|
||||
addQueryParameter("scanlations", filter.state.toString())
|
||||
?: run {
|
||||
if (query.isBlank()) {
|
||||
addQueryParameter("sort", "updated_at,desc")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
addQueryParameter("scanlations", preferences.showScanlations.toString())
|
||||
}
|
||||
|
||||
return POST(url.toString(), headers, body)
|
||||
@ -203,7 +209,11 @@ class Kagane : HttpSource(), ConfigurableSource {
|
||||
}
|
||||
|
||||
override fun mangaDetailsRequest(manga: SManga): Request {
|
||||
return GET("$apiUrl/api/v1/series/${manga.url}", apiHeaders)
|
||||
return mangaDetailsRequest(manga.url)
|
||||
}
|
||||
|
||||
private fun mangaDetailsRequest(seriesId: String): Request {
|
||||
return GET("$apiUrl/api/v1/series/$seriesId", apiHeaders)
|
||||
}
|
||||
|
||||
override fun getMangaUrl(manga: SManga): String {
|
||||
@ -213,8 +223,25 @@ class Kagane : HttpSource(), ConfigurableSource {
|
||||
// ============================== Chapters ==============================
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
val seriesId = response.request.url.toString()
|
||||
.substringAfterLast("/")
|
||||
|
||||
val dto = response.parseAs<ChapterDto>()
|
||||
return dto.content.map { it -> it.toSChapter() }.reversed()
|
||||
|
||||
val source = runCatching {
|
||||
client.newCall(mangaDetailsRequest(seriesId))
|
||||
.execute()
|
||||
.parseAs<DetailsDto>()
|
||||
.source
|
||||
}.getOrDefault("")
|
||||
val useSourceChapterNumber = source in setOf(
|
||||
"Dark Horse Comics",
|
||||
"Flame Comics",
|
||||
"MangaDex",
|
||||
"Square Enix Manga",
|
||||
)
|
||||
|
||||
return dto.content.map { it -> it.toSChapter(useSourceChapterNumber) }.reversed()
|
||||
}
|
||||
|
||||
override fun chapterListRequest(manga: SManga): Request {
|
||||
@ -430,6 +457,12 @@ class Kagane : HttpSource(), ConfigurableSource {
|
||||
return CONTENT_RATINGS.slice(0..index.coerceAtLeast(0))
|
||||
}
|
||||
|
||||
private val SharedPreferences.excludedGenres: Set<String>
|
||||
get() = this.getStringSet(GENRES_PREF, emptySet()) ?: emptySet()
|
||||
|
||||
private val SharedPreferences.showScanlations: Boolean
|
||||
get() = this.getBoolean(SHOW_SCANLATIONS, SHOW_SCANLATIONS_DEFAULT)
|
||||
|
||||
private val SharedPreferences.dataSaver
|
||||
get() = this.getBoolean(DATA_SAVER, false)
|
||||
|
||||
@ -443,6 +476,27 @@ class Kagane : HttpSource(), ConfigurableSource {
|
||||
setDefaultValue(CONTENT_RATING_DEFAULT)
|
||||
}.let(screen::addPreference)
|
||||
|
||||
MultiSelectListPreference(screen.context).apply {
|
||||
key = GENRES_PREF
|
||||
title = "Exclude Genres"
|
||||
entries = GenresList.map { it.replaceFirstChar { c -> c.uppercase() } }.toTypedArray()
|
||||
entryValues = GenresList
|
||||
summary = preferences.excludedGenres.joinToString { it.replaceFirstChar { c -> c.uppercase() } }
|
||||
setDefaultValue(emptySet<String>())
|
||||
|
||||
setOnPreferenceChangeListener { _, values ->
|
||||
val selected = values as Set<String>
|
||||
this.summary = selected.joinToString { it.replaceFirstChar { c -> c.uppercase() } }
|
||||
true
|
||||
}
|
||||
}.let(screen::addPreference)
|
||||
|
||||
SwitchPreferenceCompat(screen.context).apply {
|
||||
key = SHOW_SCANLATIONS
|
||||
title = "Show scanlations"
|
||||
setDefaultValue(SHOW_SCANLATIONS_DEFAULT)
|
||||
}.let(screen::addPreference)
|
||||
|
||||
SwitchPreferenceCompat(screen.context).apply {
|
||||
key = DATA_SAVER
|
||||
title = "Data saver"
|
||||
@ -462,6 +516,10 @@ class Kagane : HttpSource(), ConfigurableSource {
|
||||
"pornographic",
|
||||
)
|
||||
|
||||
private const val GENRES_PREF = "pref_genres_exclude"
|
||||
private const val SHOW_SCANLATIONS = "pref_show_scanlations"
|
||||
private const val SHOW_SCANLATIONS_DEFAULT = true
|
||||
|
||||
private const val DATA_SAVER = "data_saver_default"
|
||||
}
|
||||
|
||||
@ -486,7 +544,6 @@ class Kagane : HttpSource(), ConfigurableSource {
|
||||
// TagsFilter(),
|
||||
// SourcesFilter(),
|
||||
Filter.Separator(),
|
||||
ScanlationsFilter(),
|
||||
)
|
||||
|
||||
val response = metadataClient.newCall(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user