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 {