[Comick] Cover setting and Score on Description (#18984)

* 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
This commit is contained in:
BrutuZ 2023-11-20 13:52:10 -03:00 committed by GitHub
parent fb7c211c36
commit bdc0ea4d06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 108 additions and 35 deletions

View File

@ -6,7 +6,7 @@ ext {
extName = 'Comick'
pkgNameSuffix = 'all.comickfun'
extClass = '.ComickFunFactory'
extVersionCode = 38
extVersionCode = 39
isNsfw = true
}

View File

@ -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 {

View File

@ -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?,

View File

@ -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 {