From f6d2fd3c65f953b8a8739d81057f8c7622cd5c77 Mon Sep 17 00:00:00 2001 From: Luqman <16263232+Riztard@users.noreply.github.com> Date: Thu, 14 Aug 2025 21:34:04 +0700 Subject: [PATCH] Comick: Option cover quality (#10085) * Comick: Option cover quality i think need some text suggestion use cover quality served by the site by default on browse. this can save lot of bandwidth compared to original 2x-100x smaller. thats why i think can increase rate limit a little bit. add option to choose cover quality when opening the manga closes #9088 closes #2550 * update version * fix first vol cover, renaming * cleaning, already default value * applied to first vol cover as well * change default value * rename * Update messages_en.properties --- .../assets/i18n/messages_en.properties | 4 +++ src/all/comickfun/build.gradle | 2 +- .../extension/all/comickfun/Comick.kt | 34 ++++++++++++++++++- .../tachiyomi/extension/all/comickfun/Dto.kt | 2 ++ .../extension/all/comickfun/Helpers.kt | 27 ++++++++++++--- 5 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/all/comickfun/assets/i18n/messages_en.properties b/src/all/comickfun/assets/i18n/messages_en.properties index 5a559b779..527622966 100644 --- a/src/all/comickfun/assets/i18n/messages_en.properties +++ b/src/all/comickfun/assets/i18n/messages_en.properties @@ -22,6 +22,10 @@ score_position_top=Top score_position_middle=Middle score_position_bottom=Bottom score_position_none=Hide Score +cover_quality_title=Cover Quality +cover_quality_original=Original +cover_quality_compressed=Compressed +cover_quality_web_default=Small (Web Default) chapter_score_filtering_title=Automatically de-duplicate chapters chapter_score_filtering_on=For each chapter, only displays the scanlator with the highest score chapter_score_filtering_off=Does not filterout any chapters based on score (any other scanlator filtering will still apply) diff --git a/src/all/comickfun/build.gradle b/src/all/comickfun/build.gradle index 8ab9df226..f866d828b 100644 --- a/src/all/comickfun/build.gradle +++ b/src/all/comickfun/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'Comick' extClass = '.ComickFactory' - extVersionCode = 58 + extVersionCode = 59 isNsfw = true } diff --git a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Comick.kt b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Comick.kt index 9f15a95b2..004ac37a2 100644 --- a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Comick.kt +++ b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Comick.kt @@ -141,6 +141,29 @@ abstract class Comick( } }.also(screen::addPreference) + ListPreference(screen.context).apply { + key = COVER_QUALITY_PREF + title = intl["cover_quality_title"] + entries = arrayOf( + intl["cover_quality_original"], + intl["cover_quality_compressed"], + intl["cover_quality_web_default"], + ) + entryValues = arrayOf( + "Original", + "Compressed", + COVER_QUALITY_DEFAULT, + ) + setDefaultValue(COVER_QUALITY_DEFAULT) + summary = "%s" + + setOnPreferenceChangeListener { _, newValue -> + preferences.edit() + .putString(COVER_QUALITY_PREF, newValue as String) + .commit() + } + }.also(screen::addPreference) + SwitchPreferenceCompat(screen.context).apply { key = LOCAL_TITLE_PREF title = intl["local_title_title"] @@ -224,6 +247,11 @@ abstract class Comick( private val SharedPreferences.updateCover: Boolean get() = getBoolean(FIRST_COVER_PREF, FIRST_COVER_DEFAULT) + private val coverQuality: CoverQuality + get() = CoverQuality.valueOf( + preferences.getString(COVER_QUALITY_PREF, COVER_QUALITY_DEFAULT) ?: COVER_QUALITY_DEFAULT, + ) + private val SharedPreferences.localTitle: String get() = if (getBoolean( LOCAL_TITLE_PREF, @@ -253,7 +281,7 @@ abstract class Comick( .build() private val imageClient = network.cloudflareClient.newBuilder() - .rateLimit(12, 8, TimeUnit.SECONDS) // == 1.5req/1sec == 3req/2sec == 90req/60sec + .rateLimit(14, 8, TimeUnit.SECONDS) // == 1.75req/1sec == 7req/4sec == 105req/60sec .build() private fun imageInterceptor(chain: Interceptor.Chain): Response { @@ -519,6 +547,7 @@ abstract class Comick( covers = localCovers.ifEmpty { originalCovers }.ifEmpty { firstVol }, groupTags = preferences.groupTags, titleLang = preferences.localTitle, + coverQuality = coverQuality, ) } return mangaData.toSManga( @@ -527,6 +556,7 @@ abstract class Comick( showAlternativeTitles = preferences.showAlternativeTitles, groupTags = preferences.groupTags, titleLang = preferences.localTitle, + coverQuality = coverQuality, ) } @@ -663,6 +693,8 @@ abstract class Comick( private const val MIGRATED_IGNORED_GROUPS = "MigratedIgnoredGroups" private const val FIRST_COVER_PREF = "DefaultCover" private const val FIRST_COVER_DEFAULT = true + private const val COVER_QUALITY_PREF = "CoverQuality" + const val COVER_QUALITY_DEFAULT = "WebDefault" private const val SCORE_POSITION_PREF = "ScorePosition" const val SCORE_POSITION_DEFAULT = "top" private const val LOCAL_TITLE_PREF = "LocalTitle" diff --git a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Dto.kt b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Dto.kt index cfad0da0a..01ab8946e 100644 --- a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Dto.kt +++ b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Dto.kt @@ -41,6 +41,7 @@ class Manga( covers: List? = null, groupTags: Boolean = GROUP_TAGS_DEFAULT, titleLang: String, + coverQuality: CoverQuality = CoverQuality.Compressed, ): SManga { val entryTitle = comic.altTitles.firstOrNull { titleLang != "all" && !it.lang.isNullOrBlank() && titleLang.startsWith(it.lang) @@ -82,6 +83,7 @@ class Manga( thumbnail_url = parseCover( comic.cover, covers ?: comic.mdCovers, + coverQuality, ) artist = artists.joinToString { it.name.trim() } author = authors.joinToString { it.name.trim() } diff --git a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Helpers.kt b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Helpers.kt index 57cdcd46f..a2587e98e 100644 --- a/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Helpers.kt +++ b/src/all/comickfun/src/eu/kanade/tachiyomi/extension/all/comickfun/Helpers.kt @@ -39,13 +39,30 @@ internal fun Int?.parseStatus(translationComplete: Boolean?): Int { else -> SManga.UNKNOWN } } +enum class CoverQuality { + Original, // HQ original + Compressed, // HQ but compressed + WebDefault, // what comick serves in browser, usually compressed + downscaled +} -internal fun parseCover(thumbnailUrl: String?, mdCovers: List): String? { - val b2key = mdCovers.firstOrNull()?.b2key - ?: return thumbnailUrl - val vol = mdCovers.firstOrNull()?.vol.orEmpty() +internal fun parseCover(thumbnailUrl: String?, mdCovers: List, coverQuality: CoverQuality = CoverQuality.WebDefault): String? { + fun addOrReplaceCoverQualitySuffix(url: String, qualitySuffix: String): String { + return url.substringBeforeLast('.').replace(Regex("-(m|s)$"), "") + + "$qualitySuffix.jpg#${url.substringAfter('#', "")}" + } - return thumbnailUrl?.replaceAfterLast("/", "$b2key#$vol") + val mdCover = mdCovers.firstOrNull() + val coverUrl = if (mdCover != null) { + thumbnailUrl?.replaceAfterLast("/", "${mdCover.b2key}#${mdCover.vol.orEmpty()}") + } else { + thumbnailUrl + } ?: return null + + return when (coverQuality) { + CoverQuality.Original -> coverUrl + CoverQuality.Compressed -> addOrReplaceCoverQualitySuffix(coverUrl, "-m") + CoverQuality.WebDefault -> addOrReplaceCoverQualitySuffix(coverUrl, "-s") + } } internal fun beautifyChapterName(vol: String, chap: String, title: String): String {