From bdc0ea4d06d7d3f099a8edc64c08c51e2d71dd4c Mon Sep 17 00:00:00 2001
From: BrutuZ <BrutuZ@users.noreply.github.com>
Date: Mon, 20 Nov 2023 13:52:10 -0300
Subject: [PATCH] [Comick] Cover setting and Score on Description (#18984)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Add Score to the description
Add option to keep the first cover

* Check to prevent the extra call

* Swap from ★☆ to ●◐○ to make use of the half-symbol
Because the half-star character (⯪) is too new and doesn't show up properly

* Missing Override

* Back to the stars on rating.
No half-symbols but makes more sense and is consistent with the site's usage of the ⭐ star emoji
---
 src/all/comickfun/build.gradle                |  2 +-
 .../extension/all/comickfun/ComickFun.kt      | 50 ++++++++++-
 .../extension/all/comickfun/ComickFunDto.kt   | 89 ++++++++++++-------
 .../all/comickfun/ComickFunHelper.kt          |  2 +-
 4 files changed, 108 insertions(+), 35 deletions(-)

diff --git a/src/all/comickfun/build.gradle b/src/all/comickfun/build.gradle
index eeeadb960..fb93c9f7a 100644
--- a/src/all/comickfun/build.gradle
+++ b/src/all/comickfun/build.gradle
@@ -6,7 +6,7 @@ ext {
     extName = 'Comick'
     pkgNameSuffix = 'all.comickfun'
     extClass = '.ComickFunFactory'
-    extVersionCode = 38
+    extVersionCode = 39
     isNsfw = true
 }
 
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 d8f7db87e..79cc11123 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
@@ -82,6 +82,20 @@ abstract class ComickFun(
                     .commit()
             }
         }.also(screen::addPreference)
+
+        SwitchPreferenceCompat(screen.context).apply {
+            key = FIRST_COVER_PREF
+            title = "Update Covers"
+            summaryOff = "Prefer first cover"
+            summaryOn = "Keep cover updated"
+            setDefaultValue(FIRST_COVER_DEFAULT)
+
+            setOnPreferenceChangeListener { _, newValue ->
+                preferences.edit()
+                    .putBoolean(FIRST_COVER_PREF, newValue as Boolean)
+                    .commit()
+            }
+        }.also(screen::addPreference)
     }
 
     private val SharedPreferences.ignoredGroups: Set<String>
@@ -97,6 +111,9 @@ abstract class ComickFun(
     private val SharedPreferences.includeMuTags: Boolean
         get() = getBoolean(INCLUDE_MU_TAGS_PREF, INCLUDE_MU_TAGS_DEFAULT)
 
+    private val SharedPreferences.updateCover: Boolean
+        get() = getBoolean(FIRST_COVER_PREF, FIRST_COVER_DEFAULT)
+
     init {
         preferences.newLineIgnoredGroups()
     }
@@ -283,8 +300,37 @@ abstract class ComickFun(
         return GET("$apiUrl$mangaUrl?tachiyomi=true", headers)
     }
 
-    override fun mangaDetailsParse(response: Response): SManga {
+    override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
+        return client.newCall(mangaDetailsRequest(manga))
+            .asObservableSuccess()
+            .map { response ->
+                mangaDetailsParse(response, manga).apply { initialized = true }
+            }
+    }
+
+    override fun mangaDetailsParse(response: Response): SManga =
+        mangaDetailsParse(response, SManga.create())
+
+    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("#")) {
+                return mangaData.toSManga(
+                    includeMuTags = preferences.includeMuTags,
+                    covers = listOf(
+                        MDcovers(
+                            b2key = manga.thumbnail_url?.removeSuffix("#")
+                                ?.substringAfterLast("/"),
+                        ),
+                    ),
+                )
+            }
+            val coversUrl =
+                "$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)
     }
 
@@ -392,6 +438,8 @@ abstract class ComickFun(
         private const val INCLUDE_MU_TAGS_PREF = "IncludeMangaUpdatesTags"
         private const val INCLUDE_MU_TAGS_DEFAULT = false
         private const val MIGRATED_IGNORED_GROUPS = "MigratedIgnoredGroups"
+        private const val FIRST_COVER_PREF = "DefaultCover"
+        private const val FIRST_COVER_DEFAULT = true
         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 f915468f9..91d9ab1f1 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
@@ -4,6 +4,8 @@ import eu.kanade.tachiyomi.source.model.SChapter
 import eu.kanade.tachiyomi.source.model.SManga
 import kotlinx.serialization.SerialName
 import kotlinx.serialization.Serializable
+import java.math.BigDecimal
+import java.math.RoundingMode
 
 @Serializable
 data class SearchManga(
@@ -29,41 +31,57 @@ data class Manga(
     val genres: List<Name> = emptyList(),
     val demographic: String? = null,
 ) {
-    fun toSManga(includeMuTags: Boolean = false) = SManga.create().apply {
-        // appennding # at end as part of migration from slug to hid
-        url = "/comic/${comic.hid}#"
-        title = comic.title
-        description = comic.desc?.beautifyDescription()
-        if (comic.altTitles.isNotEmpty()) {
-            if (description.isNullOrEmpty()) {
-                description = "Alternative Titles:\n"
-            } else {
-                description += "\n\nAlternative Titles:\n"
-            }
-
-            description += comic.altTitles.mapNotNull { title ->
-                title.title?.let { "• $it" }
-            }.joinToString("\n")
-        }
-        status = comic.status.parseStatus(comic.translationComplete)
-        thumbnail_url = parseCover(comic.cover, comic.mdCovers)
-        artist = artists.joinToString { it.name.trim() }
-        author = authors.joinToString { it.name.trim() }
-        genre = buildList {
-            comic.origination?.let(::add)
-            demographic?.let { add(Name(it)) }
-            addAll(genres)
-            addAll(comic.mdGenres.mapNotNull { it.name })
-            if (includeMuTags) {
-                comic.muGenres.categories.forEach { category ->
-                    category?.category?.title?.let { add(Name(it)) }
+    fun toSManga(includeMuTags: Boolean = false, 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} ")
+                }
+                val desc = comic.desc?.beautifyDescription()
+                if (!desc.isNullOrEmpty()) {
+                    if (this.isNotEmpty()) append("\n\n")
+                    append(desc)
+                }
+                if (comic.altTitles.isNotEmpty()) {
+                    if (this.isNotEmpty()) append("\n\n")
+                    append("Alternative Titles:\n")
+                    append(
+                        comic.altTitles.mapNotNull { title ->
+                            title.title?.let { "• $it" }
+                        }.joinToString("\n"),
+                    )
                 }
             }
+
+            status = comic.status.parseStatus(comic.translationComplete)
+            thumbnail_url = parseCover(
+                comic.cover,
+                covers ?: comic.mdCovers,
+            )
+            artist = artists.joinToString { it.name.trim() }
+            author = authors.joinToString { it.name.trim() }
+            genre = buildList {
+                comic.origination?.let(::add)
+                demographic?.let { add(Name(it)) }
+                addAll(genres)
+                addAll(comic.mdGenres.mapNotNull { it.name })
+                if (includeMuTags) {
+                    comic.muGenres.categories.forEach { category ->
+                        category?.category?.title?.let { add(Name(it)) }
+                    }
+                }
+            }
+                .distinctBy { it.name }
+                .filter { it.name.isNotBlank() }
+                .joinToString { it.name.trim() }
         }
-            .distinctBy { it.name }
-            .filter { it.name.isNotBlank() }
-            .joinToString { it.name.trim() }
-    }
 }
 
 @Serializable
@@ -71,6 +89,7 @@ data class Comic(
     val hid: String,
     val title: String,
     val country: String? = null,
+    val slug: String? = null,
     @SerialName("md_titles") val altTitles: List<Title> = emptyList(),
     val desc: String? = null,
     val status: Int? = 0,
@@ -79,6 +98,7 @@ data class Comic(
     @SerialName("cover_url") val cover: String? = null,
     @SerialName("md_comic_md_genres") val mdGenres: List<MdGenres>,
     @SerialName("mu_comics") val muGenres: MuComicCategories = MuComicCategories(emptyList()),
+    @SerialName("bayesian_rating") val score: String? = null,
 ) {
     val origination = when (country) {
         "jp" -> Name("Manga")
@@ -103,6 +123,11 @@ data class MuCategories(
     @SerialName("mu_categories") val category: Title? = null,
 )
 
+@Serializable
+data class Covers(
+    val md_covers: List<MDcovers> = emptyList(),
+)
+
 @Serializable
 data class MDcovers(
     val b2key: String?,
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 ea8c05946..29ed1eb15 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
@@ -38,7 +38,7 @@ internal fun parseCover(thumbnailUrl: String?, mdCovers: List<MDcovers>): String
     val b2key = mdCovers.firstOrNull()?.b2key
         ?: return thumbnailUrl
 
-    return thumbnailUrl?.let { "$it#$b2key" }
+    return thumbnailUrl?.replaceAfterLast("/", "$b2key#")
 }
 
 internal fun thumbnailIntercept(chain: Interceptor.Chain): Response {