[Comick] Various updates (#19118)

* Add setting for Score positioning
Localization support for settings

* Simplify score position evaluation
Reformat code

* Include backup domain in Manifest

* Refine logic for picking the first volume cover

* Officially moved their main TLD

* Fallback to default value instead of empty string
This commit is contained in:
BrutuZ 2023-12-07 10:07:43 -03:00 committed by GitHub
parent 76d9997262
commit 67c4e30577
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 118 additions and 24 deletions

View File

@ -14,7 +14,9 @@
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
<data android:host="comick.ink" />
<data android:host="comick.app" />
<data android:host="comick.fun" />
<data android:pathPattern="/comic/.*/..*" />
<data android:pathPattern="/comic/..*" />
</intent-filter>

View File

@ -0,0 +1,13 @@
ignored_groups_title=Ignored Groups
ignored_groups_summary=Chapters from these groups won't be shown.\nOne group name per line (case-insensitive)
include_tags_title=Include Tags
include_tags_on=More specific, but might contain spoilers!
include_tags_off=Only the broader genres
update_cover_title=Update Covers
update_cover_on=Keep cover updated
update_cover_off=Prefer first cover
score_position_title=Score Position in the Description
score_position_top=Top
score_position_middle=Middle
score_position_bottom=Bottom
score_position_none=Hide Score

View File

@ -0,0 +1,13 @@
ignored_groups_title=Grupos Ignorados
ignored_groups_summary=Capítulos desses grupos não aparecerão.\nUm grupo por linha
include_tags_title=Incluir Tags
include_tags_on=Mais detalhadas, mas podem conter spoilers
include_tags_off=Apenas os gêneros básicos
update_cover_title=Atualizar Capas
update_cover_on=Manter capas atualizadas
update_cover_off=Usar apenas a primeira capa
score_position_title=Posição da Nota na Descrição
score_position_top=Topo
score_position_middle=Meio
score_position_bottom=Final
score_position_none=Sem Nota

View File

@ -6,8 +6,12 @@ ext {
extName = 'Comick'
pkgNameSuffix = 'all.comickfun'
extClass = '.ComickFunFactory'
extVersionCode = 39
extVersionCode = 40
isNsfw = true
}
dependencies {
implementation(project(":lib-i18n"))
}
apply from: "$rootDir/common.gradle"

View File

@ -3,8 +3,10 @@ package eu.kanade.tachiyomi.extension.all.comickfun
import android.app.Application
import android.content.SharedPreferences
import androidx.preference.EditTextPreference
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreferenceCompat
import eu.kanade.tachiyomi.lib.i18n.Intl
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.network.interceptor.rateLimit
@ -36,7 +38,7 @@ abstract class ComickFun(
override val name = "Comick"
override val baseUrl = "https://comick.app"
override val baseUrl = "https://comick.ink"
private val apiUrl = "https://api.comick.fun"
@ -51,6 +53,15 @@ abstract class ComickFun(
private lateinit var searchResponse: List<SearchManga>
private val intl by lazy {
Intl(
language = lang,
baseLanguage = "en",
availableLanguages = setOf("en", "pt-BR"),
classLoader = this::class.java.classLoader!!,
)
}
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
@ -58,9 +69,8 @@ abstract class ComickFun(
override fun setupPreferenceScreen(screen: PreferenceScreen) {
EditTextPreference(screen.context).apply {
key = IGNORED_GROUPS_PREF
title = "Ignored Groups"
summary =
"Chapters from these groups won't be shown.\nOne group name per line (case-insensitive)"
title = intl["ignored_groups_title"]
summary = intl["ignored_groups_summary"]
setOnPreferenceChangeListener { _, newValue ->
preferences.edit()
@ -71,9 +81,9 @@ abstract class ComickFun(
SwitchPreferenceCompat(screen.context).apply {
key = INCLUDE_MU_TAGS_PREF
title = "Include Tags"
summaryOn = "More specific, but might contain spoilers!"
summaryOff = "Only the broader genres"
title = intl["include_tags_title"]
summaryOn = intl["include_tags_on"]
summaryOff = intl["include_tags_off"]
setDefaultValue(INCLUDE_MU_TAGS_DEFAULT)
setOnPreferenceChangeListener { _, newValue ->
@ -85,9 +95,9 @@ abstract class ComickFun(
SwitchPreferenceCompat(screen.context).apply {
key = FIRST_COVER_PREF
title = "Update Covers"
summaryOff = "Prefer first cover"
summaryOn = "Keep cover updated"
title = intl["update_cover_title"]
summaryOff = intl["update_cover_off"]
summaryOn = intl["update_cover_on"]
setDefaultValue(FIRST_COVER_DEFAULT)
setOnPreferenceChangeListener { _, newValue ->
@ -96,6 +106,30 @@ abstract class ComickFun(
.commit()
}
}.also(screen::addPreference)
ListPreference(screen.context).apply {
key = SCORE_POSITION_PREF
title = intl["score_position_title"]
summary = "%s"
entries = arrayOf(
intl["score_position_top"],
intl["score_position_middle"],
intl["score_position_bottom"],
intl["score_position_none"],
)
entryValues = arrayOf(SCORE_POSITION_DEFAULT, "middle", "bottom", "none")
setDefaultValue(SCORE_POSITION_DEFAULT)
setOnPreferenceChangeListener { _, newValue ->
val selected = newValue as String
val index = findIndexOfValue(selected)
val entry = entryValues[index] as String
preferences.edit()
.putString(SCORE_POSITION_PREF, entry)
.commit()
}
}.also(screen::addPreference)
}
private val SharedPreferences.ignoredGroups: Set<String>
@ -114,6 +148,9 @@ abstract class ComickFun(
private val SharedPreferences.updateCover: Boolean
get() = getBoolean(FIRST_COVER_PREF, FIRST_COVER_DEFAULT)
private val SharedPreferences.scorePosition: String
get() = getString(SCORE_POSITION_PREF, SCORE_POSITION_DEFAULT) ?: SCORE_POSITION_DEFAULT
init {
preferences.newLineIgnoredGroups()
}
@ -314,13 +351,15 @@ abstract class ComickFun(
private fun mangaDetailsParse(response: Response, manga: SManga): SManga {
val mangaData = response.parseAs<Manga>()
if (!preferences.updateCover && manga.thumbnail_url != mangaData.comic.cover) {
if (manga.thumbnail_url.toString().endsWith("#")) {
if (manga.thumbnail_url.toString().endsWith("#1")) {
return mangaData.toSManga(
includeMuTags = preferences.includeMuTags,
scorePosition = preferences.scorePosition,
covers = listOf(
MDcovers(
b2key = manga.thumbnail_url?.removeSuffix("#")
b2key = manga.thumbnail_url?.substringBeforeLast("#")
?.substringAfterLast("/"),
vol = "1",
),
),
)
@ -329,7 +368,10 @@ abstract class ComickFun(
"$apiUrl/comic/${mangaData.comic.slug ?: mangaData.comic.hid}/covers?tachiyomi=true"
val covers = client.newCall(GET(coversUrl)).execute()
.parseAs<Covers>().md_covers.reversed()
return mangaData.toSManga(includeMuTags = preferences.includeMuTags, covers = covers)
return mangaData.toSManga(
includeMuTags = preferences.includeMuTags,
covers = if (covers.any { it.vol == "1" }) covers.filter { it.vol == "1" } else covers,
)
}
return mangaData.toSManga(includeMuTags = preferences.includeMuTags)
}
@ -440,6 +482,8 @@ abstract class ComickFun(
private const val MIGRATED_IGNORED_GROUPS = "MigratedIgnoredGroups"
private const val FIRST_COVER_PREF = "DefaultCover"
private const val FIRST_COVER_DEFAULT = true
private const val SCORE_POSITION_PREF = "ScorePosition"
private const val SCORE_POSITION_DEFAULT = "top"
private const val limit = 20
val dateFormat by lazy {
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH).apply {

View File

@ -13,7 +13,6 @@ data class SearchManga(
val title: String,
@SerialName("md_covers") val mdCovers: List<MDcovers> = emptyList(),
@SerialName("cover_url") val cover: String? = null,
) {
fun toSManga() = SManga.create().apply {
// appending # at end as part of migration from slug to hid
@ -31,24 +30,26 @@ data class Manga(
val genres: List<Name> = emptyList(),
val demographic: String? = null,
) {
fun toSManga(includeMuTags: Boolean = false, covers: List<MDcovers>? = null) =
fun toSManga(
includeMuTags: Boolean = false,
scorePosition: String = "",
covers: List<MDcovers>? = null,
) =
SManga.create().apply {
// appennding # at end as part of migration from slug to hid
url = "/comic/${comic.hid}#"
title = comic.title
description = buildString {
if (!comic.score.isNullOrEmpty()) {
val stars = comic.score.toBigDecimal().div(BigDecimal(2))
.setScale(0, RoundingMode.HALF_UP).toInt()
append("".repeat(stars))
if (stars < 5) append("".repeat(5 - stars))
append(" ${comic.score} ")
}
if (scorePosition == "top") append(comic.fancyScore)
val desc = comic.desc?.beautifyDescription()
if (!desc.isNullOrEmpty()) {
if (this.isNotEmpty()) append("\n\n")
append(desc)
}
if (scorePosition == "middle") {
if (this.isNotEmpty()) append("\n\n")
append(comic.fancyScore)
}
if (comic.altTitles.isNotEmpty()) {
if (this.isNotEmpty()) append("\n\n")
append("Alternative Titles:\n")
@ -58,6 +59,10 @@ data class Manga(
}.joinToString("\n"),
)
}
if (scorePosition == "bottom") {
if (this.isNotEmpty()) append("\n\n")
append(comic.fancyScore)
}
}
status = comic.status.parseStatus(comic.translationComplete)
@ -106,6 +111,17 @@ data class Comic(
"cn" -> Name("Manhua")
else -> null
}
val fancyScore: String = if (score.isNullOrEmpty()) {
""
} else {
val stars = score.toBigDecimal().div(BigDecimal(2))
.setScale(0, RoundingMode.HALF_UP).toInt()
buildString {
append("".repeat(stars))
if (stars < 5) append("".repeat(5 - stars))
append(" $score")
}
}
}
@Serializable
@ -131,6 +147,7 @@ data class Covers(
@Serializable
data class MDcovers(
val b2key: String?,
val vol: String? = null,
)
@Serializable

View File

@ -37,8 +37,9 @@ internal fun Int?.parseStatus(translationComplete: Boolean?): Int {
internal fun parseCover(thumbnailUrl: String?, mdCovers: List<MDcovers>): String? {
val b2key = mdCovers.firstOrNull()?.b2key
?: return thumbnailUrl
val vol = mdCovers.firstOrNull()?.vol.orEmpty()
return thumbnailUrl?.replaceAfterLast("/", "$b2key#")
return thumbnailUrl?.replaceAfterLast("/", "$b2key#$vol")
}
internal fun thumbnailIntercept(chain: Interceptor.Chain): Response {