From 67c4e30577be1a48bb1a37a77a8330f0f437ba3a Mon Sep 17 00:00:00 2001 From: BrutuZ Date: Thu, 7 Dec 2023 10:07:43 -0300 Subject: [PATCH] [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 --- src/all/comickfun/AndroidManifest.xml | 2 + .../assets/i18n/messages_en.properties | 13 ++++ .../assets/i18n/messages_pt_br.properties | 13 ++++ src/all/comickfun/build.gradle | 6 +- .../extension/all/comickfun/ComickFun.kt | 70 +++++++++++++++---- .../extension/all/comickfun/ComickFunDto.kt | 35 +++++++--- .../all/comickfun/ComickFunHelper.kt | 3 +- 7 files changed, 118 insertions(+), 24 deletions(-) create mode 100644 src/all/comickfun/assets/i18n/messages_en.properties create mode 100644 src/all/comickfun/assets/i18n/messages_pt_br.properties diff --git a/src/all/comickfun/AndroidManifest.xml b/src/all/comickfun/AndroidManifest.xml index 8d693cfe8..ab949d68e 100644 --- a/src/all/comickfun/AndroidManifest.xml +++ b/src/all/comickfun/AndroidManifest.xml @@ -14,7 +14,9 @@ + + diff --git a/src/all/comickfun/assets/i18n/messages_en.properties b/src/all/comickfun/assets/i18n/messages_en.properties new file mode 100644 index 000000000..55487eaac --- /dev/null +++ b/src/all/comickfun/assets/i18n/messages_en.properties @@ -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 diff --git a/src/all/comickfun/assets/i18n/messages_pt_br.properties b/src/all/comickfun/assets/i18n/messages_pt_br.properties new file mode 100644 index 000000000..745ed5b15 --- /dev/null +++ b/src/all/comickfun/assets/i18n/messages_pt_br.properties @@ -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 diff --git a/src/all/comickfun/build.gradle b/src/all/comickfun/build.gradle index fb93c9f7a..f07d39284 100644 --- a/src/all/comickfun/build.gradle +++ b/src/all/comickfun/build.gradle @@ -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" diff --git a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFun.kt b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFun.kt index 79cc11123..07fb8dcf3 100644 --- a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFun.kt +++ b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFun.kt @@ -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 + 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().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 @@ -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() 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().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 { diff --git a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunDto.kt b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunDto.kt index 91d9ab1f1..405a6e37e 100644 --- a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunDto.kt +++ b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunDto.kt @@ -13,7 +13,6 @@ data class SearchManga( val title: String, @SerialName("md_covers") val mdCovers: List = 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 = emptyList(), val demographic: String? = null, ) { - fun toSManga(includeMuTags: Boolean = false, covers: List? = null) = + fun toSManga( + includeMuTags: Boolean = false, + scorePosition: String = "", + covers: List? = 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 diff --git a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunHelper.kt b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunHelper.kt index 29ed1eb15..1d9f365a4 100644 --- a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunHelper.kt +++ b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/ComickFunHelper.kt @@ -37,8 +37,9 @@ internal fun Int?.parseStatus(translationComplete: Boolean?): Int { internal fun parseCover(thumbnailUrl: String?, mdCovers: List): 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 {