Comick: Add preferred groups filter and it's localization (#10159)

* Add preferred groups filter and it's localization

* stevenyomi changes

* lint error

* remove migrated preferred groups

* ignoredGroups -> ignoredGroupsLowercase
This commit is contained in:
David 2025-08-17 09:20:55 +02:00 committed by Draff
parent 3642771ba0
commit 8a3758959b
Signed by: Draff
GPG Key ID: E8A89F3211677653
4 changed files with 83 additions and 11 deletions

View File

@ -1,5 +1,7 @@
ignored_groups_title=Ignored Groups
ignored_groups_summary=Chapters from these groups won't be shown.\nOne group name per line (case-insensitive)
preferred_groups_title=Preferred Groups
preferred_groups_summary=Chapters from these groups will have priority over others (Even if lower score).\nOne group name per line (case-insensitive)
ignored_tags_title=Ignored Tags
ignored_tags_summary=Manga with these tags won't show up when browsing.\nOne tag per line (case-insensitive)
show_alternative_titles_title=Show Alternative Titles

View File

@ -1,17 +1,21 @@
ignored_groups_title=Grupos Ignorados
ignored_groups_summary=Capítulos desses grupos não aparecerão.\nUm grupo por linha
ignored_groups_summary=Capítulos desses grupos não serão mostrados.\nUm nome de grupo por linha (não diferencia maiúsculas de minúsculas)
preferred_groups_title=Grupos Preferidos
preferred_groups_summary=Capítulos desses grupos terão prioridade sobre os outros (Mesmo que com nota mais baixa).\nUm nome de grupo por linha (não diferencia maiúsculas de minúsculas)
ignored_tags_title=Tags Ignoradas
ignored_tags_summary=Mangás com essas tags não aparecerão ao navegar.\nUma tag por linha (não diferencia maiúsculas de minúsculas)
show_alternative_titles_title=Mostrar Títulos Alternativos
show_alternative_titles_on=Adiciona títulos alternativos à descrição
show_alternative_titles_off=Não mostra títulos alternativos na descrição
include_tags_title=Incluir Tags
include_tags_on=Mais detalhadas, mas podem conter spoilers
include_tags_on=Mais específicas, mas podem conter spoilers!
include_tags_off=Apenas os gêneros básicos
group_tags_title=Agrupar Tags (necessário fork compatível)
group_tags_on=Prefixar tags com o respectivo tipo
group_tags_on=Irá prefixar tags com o respectivo tipo
group_tags_off=Listar todas as tags juntas
update_cover_title=Atualizar Capas
update_cover_on=Manter capas atualizadas
update_cover_off=Usar apenas a primeira capa
update_cover_on=Manter capa atualizada
update_cover_off=Preferir a primeira capa
local_title_title=Título Traduzido
local_title_on=se disponível
local_title_off=Usar o título padrão do site
@ -19,4 +23,11 @@ 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
score_position_none=Esconder Nota
cover_quality_title=Qualidade da Capa
cover_quality_original=Original
cover_quality_compressed=Comprimida
cover_quality_web_default=Pequena (Padrão Web)
chapter_score_filtering_title=Desduplicar capítulos automaticamente
chapter_score_filtering_on=Para cada capítulo, exibe apenas o scanlator com a maior nota
chapter_score_filtering_off=Não filtra nenhum capítulo com base na nota (outros filtros de scanlator ainda se aplicarão)

View File

@ -1,7 +1,7 @@
ext {
extName = 'Comick'
extClass = '.ComickFactory'
extVersionCode = 60
extVersionCode = 61
isNsfw = true
}

View File

@ -79,6 +79,18 @@ abstract class Comick(
}
}.also(screen::addPreference)
EditTextPreference(screen.context).apply {
key = PREFERRED_GROUPS_PREF
title = intl["preferred_groups_title"]
summary = intl["preferred_groups_summary"]
setOnPreferenceChangeListener { _, newValue ->
preferences.edit()
.putString(PREFERRED_GROUPS_PREF, newValue.toString())
.commit()
}
}.also(screen::addPreference)
EditTextPreference(screen.context).apply {
key = IGNORED_TAGS_PREF
title = intl["ignored_tags_title"]
@ -227,6 +239,16 @@ abstract class Comick(
.orEmpty()
.toSet()
private val SharedPreferences.preferredGroups: Set<String>
get() = getString(PREFERRED_GROUPS_PREF, "")
?.lowercase()
?.split("\n")
?.map(String::trim)
?.filter(String::isNotEmpty)
?.sorted()
.orEmpty()
.toSet()
private val SharedPreferences.ignoredTags: String
get() = getString(IGNORED_TAGS_PREF, "")
?.split("\n")
@ -593,13 +615,17 @@ abstract class Comick(
override fun chapterListParse(response: Response): List<SChapter> {
val chapterListResponse = response.parseAs<ChapterList>()
val preferredGroups = preferences.preferredGroups
val ignoredGroupsLowercase = preferences.ignoredGroups.map { it.lowercase() }
val mangaUrl = response.request.url.toString()
.substringBefore("/chapters")
.substringAfter(apiUrl)
val currentTimestamp = System.currentTimeMillis()
return chapterListResponse.chapters
// First, apply the ignored groups filter to remove chapters from blocked groups
val filteredChapters = chapterListResponse.chapters
.filter {
val publishTime = try {
publishedDateFormat.parse(it.publishedAt)!!.time
@ -610,13 +636,45 @@ abstract class Comick(
val publishedChapter = publishTime <= currentTimestamp
val noGroupBlock = it.groups.map { g -> g.lowercase() }
.intersect(preferences.ignoredGroups)
.intersect(ignoredGroupsLowercase)
.isEmpty()
publishedChapter && noGroupBlock
}
.filterOnScore(preferences.chapterScoreFiltering)
.map { it.toSChapter(mangaUrl) }
// Now apply the primary filtering logic based on user preferences
val finalChapters = if (preferredGroups.isEmpty()) {
// If preferredGroups is empty, fall back to the existing score filter
filteredChapters.filterOnScore(preferences.chapterScoreFiltering)
} else {
// If preferredGroups is not empty, use the list to grab chapters from those groups in order of preference
val chaptersByNumber = filteredChapters.groupBy { it.chap }
val preferredFilteredChapters = mutableListOf<Chapter>()
// Iterate through each chapter number's group of chapters
chaptersByNumber.forEach { (_, chaptersForNumber) ->
// Find the chapter from the most preferred group
val preferredChapter = preferredGroups.firstNotNullOfOrNull { preferredGroup ->
chaptersForNumber.find { chapter ->
chapter.groups.any { group ->
group.lowercase() == preferredGroup.lowercase()
}
}
}
if (preferredChapter != null) {
preferredFilteredChapters.add(preferredChapter)
} else {
// If no preferred group chapter was found, fall back to the score filter
val fallbackChapter = chaptersForNumber.filterOnScore(preferences.chapterScoreFiltering)
preferredFilteredChapters.addAll(fallbackChapter)
}
}
preferredFilteredChapters
}
// Finally, map the filtered chapters to the SChapter model
return finalChapters.map { it.toSChapter(mangaUrl) }
}
private fun List<Chapter>.filterOnScore(shouldFilter: Boolean): Collection<Chapter> {
@ -691,6 +749,7 @@ abstract class Comick(
const val SLUG_SEARCH_PREFIX = "id:"
private val SPACE_AND_SLASH_REGEX = Regex("[ /]")
private const val IGNORED_GROUPS_PREF = "IgnoredGroups"
private const val PREFERRED_GROUPS_PREF = "PreferredGroups"
private const val IGNORED_TAGS_PREF = "IgnoredTags"
private const val SHOW_ALTERNATIVE_TITLES_PREF = "ShowAlternativeTitles"
const val SHOW_ALTERNATIVE_TITLES_DEFAULT = false