[Kavita] Filters update, smart filters and localization (#19329)
* Finish migration to filters v2 * Implementation for smart filters * Subtle cleanup * Localization tests * Fix 404 for latest update * Filter out epubs * Fixed Filter out epubs and optimization of 20 results per page * Changelog and bump version * Localization implementation * Add localization keys * Fix pub status not displaying. Closes #16318 Co-authored-by: FYannK <fanch.kerguelen@gmail.com> * Hande exceptions and add version requirements * Make fetch implementation with error handler. Added/improved some comments Added some more translation * Update changelog * Updated localization --------- Co-authored-by: FYannK <fanch.kerguelen@gmail.com>
This commit is contained in:
parent
cae83bf094
commit
5a05fd18c6
@ -1,3 +1,14 @@
|
|||||||
|
## 1.3.12
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* Migrate filters to v2
|
||||||
|
* Implemented smartFilters
|
||||||
|
* Added localization support
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
* Fixed publication status not showing
|
||||||
|
|
||||||
## 1.3.10
|
## 1.3.10
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
18
src/all/kavita/assets/i18n/messages_en.properties
Normal file
18
src/all/kavita/assets/i18n/messages_en.properties
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
login_errors_failed_login=Login failed. Something went wrong
|
||||||
|
login_errors_header_token_empty="Error: The JSON Web Token is empty.\nTry opening the extension first."
|
||||||
|
login_errors_invalid_url=Invalid URL:
|
||||||
|
login_errors_parse_tokendto=There was an error parsing the auth token
|
||||||
|
pref_customsource_title=Displayed name for source
|
||||||
|
pref_edit_customsource_summary=Here you can change this source name.\nYou can write a descriptive name to identify this OPDS URL.
|
||||||
|
pref_filters_summary=Show these filters in the filter list
|
||||||
|
pref_filters_title=Default filters shown
|
||||||
|
pref_opds_badformed_url=Incorrect OPDS address. Please copy it from User settings \u2192 3rd party apps \u2192 OPDS URL
|
||||||
|
pref_opds_duplicated_source_url=The URL is configured in a different source ->
|
||||||
|
pref_opds_must_setup_address=You must set up the address to communicate with Kavita
|
||||||
|
pref_opds_summary=The OPDS URL copied from User Settings. This should include address and end with the API key.
|
||||||
|
restartapp_settings=Restart Tachiyomi to apply new setting.
|
||||||
|
version_exceptions_chapters_parse=Unhandled exception parsing chapters. Send your logs to the Kavita devs.
|
||||||
|
check_version=Ensure you have the newest version of the extension and Kavita. (0.7.8 or newer.)\nIf the issue persists, report it to the Kavita developers with the accompanying logs.
|
||||||
|
version_exceptions_smart_filter=Could not decode SmartFilter. Ensure you are using Kavita version 0.7.11 or later.
|
||||||
|
http_errors_500=Something went wrong
|
||||||
|
http_errors_401=There was an error logging in. Try again or reload the app
|
18
src/all/kavita/assets/i18n/messages_es_es.properties
Normal file
18
src/all/kavita/assets/i18n/messages_es_es.properties
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
pref_customsource_title=Nombre de la instancia
|
||||||
|
pref_edit_customsource_summary=Aqui puedes cambiar el nombre de la instancia.\nPuedes escribir un nombre descriptivo que identifique esta url/instancia
|
||||||
|
restartapp_settings=Reinicia la aplicación para aplicar los cambios
|
||||||
|
version_exceptions_chapters_parse=Algo ha ido mal al procesar los capitulos. Envia los registros de fallo a los desarrolladores de Kavita
|
||||||
|
check_version=Comprueba que tienes tanto Kavita como la extension actualizada. (Version minima: 0.7.8)\nSi el problema persiste, reportalo a los desarrolladores de Kavita aportando los registros de fallo.
|
||||||
|
version_exceptions_smart_filter=Fallo al decodificar los filtros inteligentes. Aseg\u00FArate que estas al menos en la version 0.7.11 de Kavita
|
||||||
|
http_errors_500=Algo ha ido mal
|
||||||
|
http_errors_401=Ha habido un error al iniciar sesi\u00F3n. Prueba otra vez o reinicia la aplicaci\u00F3n
|
||||||
|
pref_opds_summary=La url del OPDS copiada de la configuraci\u00F3n del usuario. Debe incluir la direcci\u00F3n y la clave api al final.
|
||||||
|
pref_filters_summary=Mostrar estos filtros en la lista de filtros
|
||||||
|
pref_filters_title=Filtros por defecto
|
||||||
|
pref_opds_badformed_url=La direcci\u00F3n OPDS no es correcta. Por favor, c\u00F3piela desde la Configuraci\u00F3n de usuario-> aplicaciones de terceros -> url de OPDS
|
||||||
|
login_errors_parse_tokendto=Se ha producido un error al procesar el token de autenticaci\u00F3n
|
||||||
|
pref_opds_duplicated_source_url=Url est\u00E1 configurado en una fuente diferente ->
|
||||||
|
pref_opds_must_setup_address=Debe configurar la direcci\u00F3n para comunicarse con Kavita
|
||||||
|
login_errors_failed_login=Error en el inicio de sesi\u00F3n. Algo ha ido mal
|
||||||
|
login_errors_header_token_empty="Error: el token jwt est\u00E1 vac\u00EDo.\nIntente abrir primero la extensi\u00F3n"
|
||||||
|
login_errors_invalid_url=URL no v\u00E1lida:
|
20
src/all/kavita/assets/i18n/messages_fr_fr.properties
Normal file
20
src/all/kavita/assets/i18n/messages_fr_fr.properties
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
|
||||||
|
version_exceptions_chapters_parse=Exception non trait\u00E9e durant l'analyse des chapitres. Envoyez les journaux aux d\u00E9velopeurs de Kavita
|
||||||
|
pref_customsource_title=Nom d'affichage pour la source
|
||||||
|
version_exceptions_smart_filter=\u00C9chec du d\u00E9codage de SmartFilter. Assurez-vous que vous utilisez au moins Kavita version 0.7.11
|
||||||
|
pref_opds_summary=L'URL OPDS a \u00E9t\u00E9 copi\u00E9e \u00E0 partir des param\u00E8tres de l'utilisateur. Ceci devrait inclure l'adresse et la cl\u00E9 API.
|
||||||
|
pref_filters_summary=Afficher ces filtres dans la liste des filtres
|
||||||
|
check_version=Assurez-vous que vous avez l'extension et Kavita mises \u00E0 jour. (version Mini\u202F: 0.7.8)\nSi le probl\u00E8me persiste, signalez-le aux d\u00E9veloppeurs de Kavita en fournissant des journaux
|
||||||
|
pref_filters_title=Filtres par d\u00E9faut affich\u00E9s
|
||||||
|
pref_edit_customsource_summary=Ici vous pouvez changer ce nom source.\nVous pouvez \u00E9crire un nom descriptif pour identifier cette URL opds
|
||||||
|
pref_opds_badformed_url=L'adresse OPDS n'est pas correcte. Veuillez la copiez \u00E0 partir des param\u00E8tres de l'utilisateur - > Applis tierces -> URL OPDS
|
||||||
|
login_errors_parse_tokendto=Il y a eu une erreur pendant l'analyse du jeton d'authentification
|
||||||
|
restartapp_settings=Red\u00E9marrez Tachiyomi pour appliquer le nouveau r\u00E9glage.
|
||||||
|
pref_opds_duplicated_source_url=L'URL est configur\u00E9e dans une autre source ->
|
||||||
|
pref_opds_must_setup_address=Vous devez configurer l'adresse pour communiquer avec Kavita
|
||||||
|
login_errors_failed_login=\u00C9chec de la connexion. Quelque chose s'est mal pass\u00E9
|
||||||
|
http_errors_500=Quelque chose s'est mal pass\u00E9
|
||||||
|
login_errors_header_token_empty=\u00AB\u00A0Erreur\u202F: le jeton jwt est vide.\nEssayez d'abord d'ouvrir l'extension\u00A0\u00BB
|
||||||
|
login_errors_invalid_url=URL invalide\u202F:
|
||||||
|
http_errors_401=Il y a eu une erreur. Essayez de nouveau ou rechargez l'application
|
21
src/all/kavita/assets/i18n/messages_nb_no.properties
Normal file
21
src/all/kavita/assets/i18n/messages_nb_no.properties
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
|
||||||
|
pref_customsource_title=Vist kildenavn
|
||||||
|
pref_edit_customsource_summary=Her kan du endre dette kildenavnet.\nDu kan skrive et beskrivende navn for \u00E5 identifisere denne OPDS-nettadressen.
|
||||||
|
restartapp_settings=Ny innstilling trer i kraft n\u00E5r du starter Tachiyomi p\u00E5 ny.
|
||||||
|
duplicated_source_url=Nettadressen er satt opp i en annen Kavita-instans
|
||||||
|
pref_filters_summary=Vis disse filterne i filterlisten
|
||||||
|
pref_filters_title=Forvalgte filtre valgt
|
||||||
|
login_errors_parse_tokendto=Kunne ikke tolke identifiseringssymbolet
|
||||||
|
login_errors_failed_login=Innlogging mislyktes. Noe gikk galt.
|
||||||
|
http_errors_500=Noe gikk galt
|
||||||
|
login_errors_header_token_empty="Feil: JSON-nettsymbol er tomt.\nPr\u00F8v \u00E5 \u00E5pne utvidelsen f\u00F8rst."
|
||||||
|
login_errors_invalid_url=Ugyldig nettadresse:
|
||||||
|
version_exceptions_chapters_parse=Uh\u00E5ndtert unntak i tolking av kapitler. Send loggene dine til Kavita-utviklerne.
|
||||||
|
version_exceptions_smart_filter=Kunne ikke dekode smartfilter. Forsikre deg om at du bruker Kavita versjon 0.7.11 eller nyere.
|
||||||
|
pref_opds_summary=OPDS-nettadressen kopiert fra brukerinnstillingene. Denne skal inkludere med adressen og slutte med API-n\u00F8kkelen.
|
||||||
|
check_version=Forsikre deg om at b\u00E5de utvidelsen og Kavita er av nyeste versjon. (Ihvertfall 0.7.8)\nHvis problemet vedvarer kan du rapportere det til Kavita-utviklerne med tilh\u00F8rende loggf\u00F8ring.
|
||||||
|
pref_opds_badformed_url=OPDS-adressen er ikke riktig. Kopier den fra brukerinnstillinger -> tredjepartsprogrammer -> OPDS-nettadresse
|
||||||
|
pref_opds_duplicated_source_url=Nettadressen er satt opp i en annen instans ->
|
||||||
|
pref_opds_must_setup_address=Du m\u00E5 sette opp adressen som skal kommunisere med Kavita
|
||||||
|
http_errors_401=Feil med innlogging. Pr\u00F8v \u00E5 laste inn p\u00E5 ny, eller start programmet p\u00E5 ny.
|
@ -6,11 +6,12 @@ ext {
|
|||||||
extName = 'Kavita'
|
extName = 'Kavita'
|
||||||
pkgNameSuffix = 'all.kavita'
|
pkgNameSuffix = 'all.kavita'
|
||||||
extClass = '.KavitaFactory'
|
extClass = '.KavitaFactory'
|
||||||
extVersionCode = 11
|
extVersionCode = 12
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'info.debatty:java-string-similarity:2.0.0'
|
implementation 'info.debatty:java-string-similarity:2.0.0'
|
||||||
|
implementation(project(':lib-i18n'))
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -0,0 +1,112 @@
|
|||||||
|
package eu.kanade.tachiyomi.extension.all.kavita
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.extension.all.kavita.KavitaConstants.noSmartFilterSelected
|
||||||
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
|
|
||||||
|
class UserRating :
|
||||||
|
Filter.Select<String>(
|
||||||
|
"Minimum Rating",
|
||||||
|
arrayOf(
|
||||||
|
"Any",
|
||||||
|
"1 star",
|
||||||
|
"2 stars",
|
||||||
|
"3 stars",
|
||||||
|
"4 stars",
|
||||||
|
"5 stars",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
class SmartFiltersFilter(smartFilters: Array<String>) :
|
||||||
|
Filter.Select<String>("Smart Filters", arrayOf(noSmartFilterSelected) + smartFilters)
|
||||||
|
class SortFilter(sortables: Array<String>) : Filter.Sort("Sort by", sortables, Selection(0, true))
|
||||||
|
|
||||||
|
val sortableList = listOf(
|
||||||
|
Pair("Sort name", 1),
|
||||||
|
Pair("Created", 2),
|
||||||
|
Pair("Last modified", 3),
|
||||||
|
Pair("Item added", 4),
|
||||||
|
Pair("Time to Read", 5),
|
||||||
|
Pair("Release year", 6),
|
||||||
|
)
|
||||||
|
|
||||||
|
class StatusFilter(name: String) : Filter.CheckBox(name, false)
|
||||||
|
class StatusFilterGroup(filters: List<StatusFilter>) :
|
||||||
|
Filter.Group<StatusFilter>("Status", filters)
|
||||||
|
|
||||||
|
class ReleaseYearRange(name: String) : Filter.Text(name)
|
||||||
|
class ReleaseYearRangeGroup(filters: List<ReleaseYearRange>) :
|
||||||
|
Filter.Group<ReleaseYearRange>("Release Year", filters)
|
||||||
|
class GenreFilter(name: String) : Filter.TriState(name)
|
||||||
|
class GenreFilterGroup(genres: List<GenreFilter>) :
|
||||||
|
Filter.Group<GenreFilter>("Genres", genres)
|
||||||
|
|
||||||
|
class TagFilter(name: String) : Filter.TriState(name)
|
||||||
|
class TagFilterGroup(tags: List<TagFilter>) : Filter.Group<TagFilter>("Tags", tags)
|
||||||
|
|
||||||
|
class AgeRatingFilter(name: String) : Filter.TriState(name)
|
||||||
|
class AgeRatingFilterGroup(ageRatings: List<AgeRatingFilter>) :
|
||||||
|
Filter.Group<AgeRatingFilter>("Age Rating", ageRatings)
|
||||||
|
|
||||||
|
class FormatFilter(name: String) : Filter.CheckBox(name, false)
|
||||||
|
class FormatsFilterGroup(formats: List<FormatFilter>) :
|
||||||
|
Filter.Group<FormatFilter>("Formats", formats)
|
||||||
|
|
||||||
|
class CollectionFilter(name: String) : Filter.TriState(name)
|
||||||
|
class CollectionFilterGroup(collections: List<CollectionFilter>) :
|
||||||
|
Filter.Group<CollectionFilter>("Collection", collections)
|
||||||
|
|
||||||
|
class LanguageFilter(name: String) : Filter.TriState(name)
|
||||||
|
class LanguageFilterGroup(languages: List<LanguageFilter>) :
|
||||||
|
Filter.Group<LanguageFilter>("Language", languages)
|
||||||
|
|
||||||
|
class LibraryFilter(library: String) : Filter.TriState(library)
|
||||||
|
class LibrariesFilterGroup(libraries: List<LibraryFilter>) :
|
||||||
|
Filter.Group<LibraryFilter>("Libraries", libraries)
|
||||||
|
|
||||||
|
class PubStatusFilter(name: String) : Filter.CheckBox(name, false)
|
||||||
|
class PubStatusFilterGroup(status: List<PubStatusFilter>) :
|
||||||
|
Filter.Group<PubStatusFilter>("Publication Status", status)
|
||||||
|
|
||||||
|
class PeopleHeaderFilter(name: String) :
|
||||||
|
Filter.Header(name)
|
||||||
|
class PeopleSeparatorFilter :
|
||||||
|
Filter.Separator()
|
||||||
|
|
||||||
|
class WriterPeopleFilter(name: String) : Filter.CheckBox(name, false)
|
||||||
|
class WriterPeopleFilterGroup(peoples: List<WriterPeopleFilter>) :
|
||||||
|
Filter.Group<WriterPeopleFilter>("Writer", peoples)
|
||||||
|
|
||||||
|
class PencillerPeopleFilter(name: String) : Filter.CheckBox(name, false)
|
||||||
|
class PencillerPeopleFilterGroup(peoples: List<PencillerPeopleFilter>) :
|
||||||
|
Filter.Group<PencillerPeopleFilter>("Penciller", peoples)
|
||||||
|
|
||||||
|
class InkerPeopleFilter(name: String) : Filter.CheckBox(name, false)
|
||||||
|
class InkerPeopleFilterGroup(peoples: List<InkerPeopleFilter>) :
|
||||||
|
Filter.Group<InkerPeopleFilter>("Inker", peoples)
|
||||||
|
|
||||||
|
class ColoristPeopleFilter(name: String) : Filter.CheckBox(name, false)
|
||||||
|
class ColoristPeopleFilterGroup(peoples: List<ColoristPeopleFilter>) :
|
||||||
|
Filter.Group<ColoristPeopleFilter>("Colorist", peoples)
|
||||||
|
|
||||||
|
class LettererPeopleFilter(name: String) : Filter.CheckBox(name, false)
|
||||||
|
class LettererPeopleFilterGroup(peoples: List<LettererPeopleFilter>) :
|
||||||
|
Filter.Group<LettererPeopleFilter>("Letterer", peoples)
|
||||||
|
|
||||||
|
class CoverArtistPeopleFilter(name: String) : Filter.CheckBox(name, false)
|
||||||
|
class CoverArtistPeopleFilterGroup(peoples: List<CoverArtistPeopleFilter>) :
|
||||||
|
Filter.Group<CoverArtistPeopleFilter>("Cover Artist", peoples)
|
||||||
|
|
||||||
|
class EditorPeopleFilter(name: String) : Filter.CheckBox(name, false)
|
||||||
|
class EditorPeopleFilterGroup(peoples: List<EditorPeopleFilter>) :
|
||||||
|
Filter.Group<EditorPeopleFilter>("Editor", peoples)
|
||||||
|
|
||||||
|
class PublisherPeopleFilter(name: String) : Filter.CheckBox(name, false)
|
||||||
|
class PublisherPeopleFilterGroup(peoples: List<PublisherPeopleFilter>) :
|
||||||
|
Filter.Group<PublisherPeopleFilter>("Publisher", peoples)
|
||||||
|
|
||||||
|
class CharacterPeopleFilter(name: String) : Filter.CheckBox(name, false)
|
||||||
|
class CharacterPeopleFilterGroup(peoples: List<CharacterPeopleFilter>) :
|
||||||
|
Filter.Group<CharacterPeopleFilter>("Character", peoples)
|
||||||
|
|
||||||
|
class TranslatorPeopleFilter(name: String) : Filter.CheckBox(name, false)
|
||||||
|
class TranslatorPeopleFilterGroup(peoples: List<TranslatorPeopleFilter>) :
|
||||||
|
Filter.Group<TranslatorPeopleFilter>("Translator", peoples)
|
File diff suppressed because it is too large
Load Diff
@ -77,4 +77,5 @@ object KavitaConstants {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const val customSourceNamePref = "customSourceName"
|
const val customSourceNamePref = "customSourceName"
|
||||||
|
const val noSmartFilterSelected = "No smart filter loaded"
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
package eu.kanade.tachiyomi.extension.all.kavita
|
package eu.kanade.tachiyomi.extension.all.kavita
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.extension.all.kavita.dto.ChapterDto
|
||||||
import eu.kanade.tachiyomi.extension.all.kavita.dto.PaginationInfo
|
import eu.kanade.tachiyomi.extension.all.kavita.dto.PaginationInfo
|
||||||
import eu.kanade.tachiyomi.extension.all.kavita.dto.SeriesDto
|
import eu.kanade.tachiyomi.extension.all.kavita.dto.SeriesDto
|
||||||
|
import eu.kanade.tachiyomi.extension.all.kavita.dto.VolumeDto
|
||||||
|
import eu.kanade.tachiyomi.lib.i18n.Intl
|
||||||
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@ -18,7 +22,9 @@ class KavitaHelper {
|
|||||||
useArrayPolymorphism = true
|
useArrayPolymorphism = true
|
||||||
prettyPrint = true
|
prettyPrint = true
|
||||||
}
|
}
|
||||||
|
inline fun <reified T : Enum<T>> safeValueOf(type: String): T {
|
||||||
|
return java.lang.Enum.valueOf(T::class.java, type)
|
||||||
|
}
|
||||||
val dateFormatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSS", Locale.US)
|
val dateFormatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSS", Locale.US)
|
||||||
.apply { timeZone = TimeZone.getTimeZone("UTC") }
|
.apply { timeZone = TimeZone.getTimeZone("UTC") }
|
||||||
fun parseDate(dateAsString: String): Long =
|
fun parseDate(dateAsString: String): Long =
|
||||||
@ -45,4 +51,91 @@ class KavitaHelper {
|
|||||||
// Deprecated: description = obj.summary
|
// Deprecated: description = obj.summary
|
||||||
thumbnail_url = "$baseUrl/image/series-cover?seriesId=${obj.id}&apiKey=$apiKey"
|
thumbnail_url = "$baseUrl/image/series-cover?seriesId=${obj.id}&apiKey=$apiKey"
|
||||||
}
|
}
|
||||||
|
class CompareChapters {
|
||||||
|
companion object : Comparator<SChapter> {
|
||||||
|
override fun compare(a: SChapter, b: SChapter): Int {
|
||||||
|
if (a.chapter_number < 1.0 && b.chapter_number < 1.0) {
|
||||||
|
// Both are volumes, multiply by 100 and do normal sort
|
||||||
|
return if ((a.chapter_number * 100) < (b.chapter_number * 100)) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (a.chapter_number < 1.0 && b.chapter_number >= 1.0) {
|
||||||
|
// A is volume, b is not. A should sort first
|
||||||
|
return 1
|
||||||
|
} else if (a.chapter_number >= 1.0 && b.chapter_number < 1.0) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (a.chapter_number < b.chapter_number) return 1
|
||||||
|
if (a.chapter_number > b.chapter_number) return -1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun chapterFromObject(obj: ChapterDto): SChapter = SChapter.create().apply {
|
||||||
|
url = obj.id.toString()
|
||||||
|
name = if (obj.number == "0" && obj.isSpecial) {
|
||||||
|
// This is a special. Chapter name is special name
|
||||||
|
obj.range
|
||||||
|
} else {
|
||||||
|
val cleanedName = obj.title.replaceFirst("^0+(?!$)".toRegex(), "")
|
||||||
|
"Chapter $cleanedName"
|
||||||
|
}
|
||||||
|
date_upload = parseDate(obj.created)
|
||||||
|
chapter_number = obj.number.toFloat()
|
||||||
|
scanlator = "${obj.pages} pages"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun chapterFromVolume(obj: ChapterDto, volume: VolumeDto): SChapter =
|
||||||
|
SChapter.create().apply {
|
||||||
|
// If there are multiple chapters to this volume, then prefix with Volume number
|
||||||
|
if (volume.chapters.isNotEmpty() && obj.number != "0") {
|
||||||
|
// This volume is not volume 0, hence they are not loose chapters
|
||||||
|
// We just add a nice Volume X to the chapter title
|
||||||
|
// Chapter-based Volume
|
||||||
|
name = "Volume ${volume.number} Chapter ${obj.number}"
|
||||||
|
chapter_number = obj.number.toFloat()
|
||||||
|
} else if (obj.number == "0") {
|
||||||
|
// Both specials and volume has chapter number 0
|
||||||
|
if (volume.number == 0) {
|
||||||
|
// Treat as special
|
||||||
|
// Special is not in a volume
|
||||||
|
if (obj.range == "") {
|
||||||
|
// Special does not have any Title
|
||||||
|
name = "Chapter 0"
|
||||||
|
chapter_number = obj.number.toFloat()
|
||||||
|
} else {
|
||||||
|
// We use it's own special tile
|
||||||
|
name = obj.range
|
||||||
|
chapter_number = obj.number.toFloat()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Is a single-file volume
|
||||||
|
// We encode the chapter number to support tracking
|
||||||
|
name = "Volume ${volume.number}"
|
||||||
|
chapter_number = volume.number.toFloat() / 10000
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
name = "Unhandled Else Volume ${volume.number}"
|
||||||
|
}
|
||||||
|
url = obj.id.toString()
|
||||||
|
date_upload = parseDate(obj.created)
|
||||||
|
|
||||||
|
scanlator = "${obj.pages} pages"
|
||||||
|
}
|
||||||
|
val intl = Intl(
|
||||||
|
language = Locale.getDefault().toString(),
|
||||||
|
baseLanguage = "en",
|
||||||
|
availableLanguages = KavitaInt.AVAILABLE_LANGS,
|
||||||
|
classLoader = this::class.java.classLoader!!,
|
||||||
|
createMessageFileName = { lang ->
|
||||||
|
when (lang) {
|
||||||
|
KavitaInt.SPANISH_LATAM -> Intl.createDefaultMessageFileName(KavitaInt.SPANISH)
|
||||||
|
else -> Intl.createDefaultMessageFileName(lang)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
package eu.kanade.tachiyomi.extension.all.kavita
|
||||||
|
|
||||||
|
object KavitaInt {
|
||||||
|
const val ENGLISH = "en"
|
||||||
|
const val SPANISH = "es_ES"
|
||||||
|
const val SPANISH_LATAM = "es-419"
|
||||||
|
const val FRENCH = "fr_FR"
|
||||||
|
const val NORWEGIAN = "nb_NO"
|
||||||
|
val AVAILABLE_LANGS = setOf(
|
||||||
|
ENGLISH,
|
||||||
|
SPANISH,
|
||||||
|
SPANISH_LATAM,
|
||||||
|
NORWEGIAN,
|
||||||
|
FRENCH
|
||||||
|
)
|
||||||
|
const val KAVITA_NAME = "Kavita"
|
||||||
|
}
|
@ -0,0 +1,124 @@
|
|||||||
|
package eu.kanade.tachiyomi.extension.all.kavita.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlin.Triple
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class FilterV2Dto(
|
||||||
|
val id: Int? = null,
|
||||||
|
val name: String? = null,
|
||||||
|
val statements: MutableList<FilterStatementDto> = mutableListOf(),
|
||||||
|
val combination: Int = 0, // FilterCombination = FilterCombination.And,
|
||||||
|
val sortOptions: SortOptions = SortOptions(),
|
||||||
|
val limitTo: Int = 0,
|
||||||
|
) {
|
||||||
|
fun addStatement(comparison: FilterComparison, field: FilterField, value: String) {
|
||||||
|
if (value.isNotBlank()) {
|
||||||
|
statements.add(FilterStatementDto(comparison.type, field.type, value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun addStatement(comparison: FilterComparison, field: FilterField, values: java.util.ArrayList<out Any>) {
|
||||||
|
if (values.isNotEmpty()) {
|
||||||
|
statements.add(FilterStatementDto(comparison.type, field.type, values.joinToString(",")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addContainsNotTriple(list: List<Triple<FilterField, java.util.ArrayList<out Any>, ArrayList<Int>>>) {
|
||||||
|
list.map {
|
||||||
|
addStatement(FilterComparison.Contains, it.first, it.second)
|
||||||
|
addStatement(FilterComparison.NotContains, it.first, it.third)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun addPeople(list: List<Pair<FilterField, ArrayList<Int>>>) {
|
||||||
|
list.map {
|
||||||
|
addStatement(FilterComparison.MustContains, it.first, it.second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class FilterStatementDto(
|
||||||
|
// todo: Create custom serializator for comparison and field and remove .type extension in Kavita.kt
|
||||||
|
val comparison: Int,
|
||||||
|
val field: Int,
|
||||||
|
val value: String,
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class SortFieldEnum(val type: Int) {
|
||||||
|
SortName(1),
|
||||||
|
CreatedDate(2),
|
||||||
|
LastModifiedDate(3),
|
||||||
|
LastChapterAdded(4),
|
||||||
|
TimeToRead(5),
|
||||||
|
ReleaseYear(6),
|
||||||
|
;
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val map = SortFieldEnum.values().associateBy(SortFieldEnum::type)
|
||||||
|
fun fromInt(type: Int) = map[type]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SortOptions(
|
||||||
|
var sortField: Int = SortFieldEnum.SortName.type,
|
||||||
|
var isAscending: Boolean = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class FilterCombination {
|
||||||
|
Or,
|
||||||
|
And,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class FilterField(val type: Int) {
|
||||||
|
Summary(0),
|
||||||
|
SeriesName(1),
|
||||||
|
PublicationStatus(2),
|
||||||
|
Languages(3),
|
||||||
|
AgeRating(4),
|
||||||
|
UserRating(5),
|
||||||
|
Tags(6),
|
||||||
|
CollectionTags(7),
|
||||||
|
Translators(8),
|
||||||
|
Characters(9),
|
||||||
|
Publisher(10),
|
||||||
|
Editor(11),
|
||||||
|
CoverArtist(12),
|
||||||
|
Letterer(13),
|
||||||
|
Colorist(14),
|
||||||
|
Inker(15),
|
||||||
|
Penciller(16),
|
||||||
|
Writers(17),
|
||||||
|
Genres(18),
|
||||||
|
Libraries(19),
|
||||||
|
ReadProgress(20),
|
||||||
|
Formats(21),
|
||||||
|
ReleaseYear(22),
|
||||||
|
ReadTime(23),
|
||||||
|
Path(24),
|
||||||
|
FilePath(25),
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class FilterComparison(val type: Int) {
|
||||||
|
Equal(0),
|
||||||
|
GreaterThan(1),
|
||||||
|
GreaterThanEqual(2),
|
||||||
|
LessThan(3),
|
||||||
|
LessThanEqual(4),
|
||||||
|
Contains(5),
|
||||||
|
MustContains(6),
|
||||||
|
Matches(7),
|
||||||
|
NotContains(8),
|
||||||
|
NotEqual(9),
|
||||||
|
BeginsWith(10),
|
||||||
|
EndsWith(11),
|
||||||
|
IsBefore(12),
|
||||||
|
IsAfter(13),
|
||||||
|
IsInLast(14),
|
||||||
|
IsNotInLast(15),
|
||||||
|
}
|
@ -62,7 +62,7 @@ data class SeriesMetadataDto(
|
|||||||
val genres: List<Genres> = emptyList(),
|
val genres: List<Genres> = emptyList(),
|
||||||
val seriesId: Int,
|
val seriesId: Int,
|
||||||
val ageRating: Int,
|
val ageRating: Int,
|
||||||
|
val publicationStatus: Int,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@ -60,15 +60,25 @@ data class MetadataPayload(
|
|||||||
var sorting_asc: Boolean = true,
|
var sorting_asc: Boolean = true,
|
||||||
var readStatus: ArrayList<String> = arrayListOf<String>(),
|
var readStatus: ArrayList<String> = arrayListOf<String>(),
|
||||||
val readStatusList: List<String> = listOf("notRead", "inProgress", "read"),
|
val readStatusList: List<String> = listOf("notRead", "inProgress", "read"),
|
||||||
var genres: ArrayList<Int> = arrayListOf<Int>(),
|
// _i = included, _e = excluded
|
||||||
var tags: ArrayList<Int> = arrayListOf<Int>(),
|
var genres_i: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
var ageRating: ArrayList<Int> = arrayListOf<Int>(),
|
var genres_e: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var tags_i: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var tags_e: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var ageRating_i: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var ageRating_e: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
|
||||||
var formats: ArrayList<Int> = arrayListOf<Int>(),
|
var formats: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
var collections: ArrayList<Int> = arrayListOf<Int>(),
|
var collections_i: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var collections_e: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
var userRating: Int = 0,
|
var userRating: Int = 0,
|
||||||
var people: ArrayList<Int> = arrayListOf<Int>(),
|
var people: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
var language: ArrayList<String> = arrayListOf<String>(),
|
// _i = included, _e = excluded
|
||||||
var libraries: ArrayList<Int> = arrayListOf<Int>(),
|
var language_i: ArrayList<String> = arrayListOf<String>(),
|
||||||
|
var language_e: ArrayList<String> = arrayListOf<String>(),
|
||||||
|
|
||||||
|
var libraries_i: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
|
var libraries_e: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
var pubStatus: ArrayList<Int> = arrayListOf<Int>(),
|
var pubStatus: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
var seriesNameQuery: String = "",
|
var seriesNameQuery: String = "",
|
||||||
var releaseYearRangeMin: Int = 0,
|
var releaseYearRangeMin: Int = 0,
|
||||||
@ -85,3 +95,10 @@ data class MetadataPayload(
|
|||||||
var peopleCharacter: ArrayList<Int> = arrayListOf<Int>(),
|
var peopleCharacter: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
var peopleTranslator: ArrayList<Int> = arrayListOf<Int>(),
|
var peopleTranslator: ArrayList<Int> = arrayListOf<Int>(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SmartFilter(
|
||||||
|
val id: Int,
|
||||||
|
val name: String,
|
||||||
|
val filter: String,
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user