mirror of
https://github.com/gotson/komga.git
synced 2025-12-06 08:32:25 +01:00
feat: localize server side errors
This commit is contained in:
parent
07cec50417
commit
cbe47ea593
10 changed files with 74 additions and 20 deletions
13
ERRORCODES.md
Normal file
13
ERRORCODES.md
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Error codes
|
||||||
|
|
||||||
|
Code | Description
|
||||||
|
---|---
|
||||||
|
ERR_1000 | File could not be accessed during analysis
|
||||||
|
ERR_1001 | Media type is not supported during analysis
|
||||||
|
ERR_1002 | Encrypted RAR archives are not supported
|
||||||
|
ERR_1003 | Solid RAR archives are not supported
|
||||||
|
ERR_1004 | Multi-Volume RAR archives are not supported
|
||||||
|
ERR_1005 | Unknown error while analyzing book
|
||||||
|
ERR_1006 | Book does not contain any page
|
||||||
|
ERR_1007 | Some entries could not be analyzed
|
||||||
|
ERR_1008 | Unknown error while getting book's entries
|
||||||
|
|
@ -11,7 +11,9 @@ export function getBookFormatFromMediaType (mediaType: string): BookFormat {
|
||||||
return { type: 'PDF', color: '#FF5722' }
|
return { type: 'PDF', color: '#FF5722' }
|
||||||
case 'application/epub+zip':
|
case 'application/epub+zip':
|
||||||
return { type: 'EPUB', color: '#ff5ab1' }
|
return { type: 'EPUB', color: '#ff5ab1' }
|
||||||
|
case 'application/x-rar-compressed; version=5':
|
||||||
|
return { type: 'RAR5', color: '#000000' }
|
||||||
default:
|
default:
|
||||||
return { type: '?', color: '#000000' }
|
return { type: mediaType, color: '#000000' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
komga-webui/src/functions/error-codes.ts
Normal file
10
komga-webui/src/functions/error-codes.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import i18n from "@/i18n";
|
||||||
|
|
||||||
|
export function convertErrorCodes(message: string): string {
|
||||||
|
const match = message.match(/ERR_\d{4}/g)
|
||||||
|
let r = message
|
||||||
|
if(match){
|
||||||
|
match.forEach(x => r = r.replace(x, i18n.t(`error_codes.${x}`).toString()))
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
@ -243,6 +243,7 @@
|
||||||
"button_confirm_edit": "Edit",
|
"button_confirm_edit": "Edit",
|
||||||
"dialog_title_add": "Add Library",
|
"dialog_title_add": "Add Library",
|
||||||
"dialot_title_edit": "Edit Library",
|
"dialot_title_edit": "Edit Library",
|
||||||
|
"field_import_barcode_isbn": "ISBN barcode",
|
||||||
"field_import_comicinfo_book": "Book metadata",
|
"field_import_comicinfo_book": "Book metadata",
|
||||||
"field_import_comicinfo_collections": "Collections",
|
"field_import_comicinfo_collections": "Collections",
|
||||||
"field_import_comicinfo_readlists": "Read lists",
|
"field_import_comicinfo_readlists": "Read lists",
|
||||||
|
|
@ -256,14 +257,13 @@
|
||||||
"field_scanner_force_directory_modified_time": "Force directory modified time",
|
"field_scanner_force_directory_modified_time": "Force directory modified time",
|
||||||
"file_browser_dialog_button_confirm": "Choose",
|
"file_browser_dialog_button_confirm": "Choose",
|
||||||
"file_browser_dialog_title": "Library's root folder",
|
"file_browser_dialog_title": "Library's root folder",
|
||||||
|
"label_import_barcode_isbn": "Import ISBN within barcode",
|
||||||
"label_import_comicinfo": "Import metadata for CBR/CBZ containing a ComicInfo.xml file",
|
"label_import_comicinfo": "Import metadata for CBR/CBZ containing a ComicInfo.xml file",
|
||||||
"label_import_epub": "Import metadata from EPUB files",
|
"label_import_epub": "Import metadata from EPUB files",
|
||||||
"label_import_local": "Import local media assets",
|
"label_import_local": "Import local media assets",
|
||||||
"label_scanner": "Scanner",
|
"label_scanner": "Scanner",
|
||||||
"tab_general": "General",
|
"tab_general": "General",
|
||||||
"tab_options": "Options",
|
"tab_options": "Options"
|
||||||
"field_import_barcode_isbn": "ISBN barcode",
|
|
||||||
"label_import_barcode_isbn": "Import ISBN within barcode"
|
|
||||||
},
|
},
|
||||||
"edit_readlist": {
|
"edit_readlist": {
|
||||||
"button_cancel": "Cancel",
|
"button_cancel": "Cancel",
|
||||||
|
|
@ -352,6 +352,17 @@
|
||||||
"ONGOING": "Ongoing"
|
"ONGOING": "Ongoing"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"error_codes": {
|
||||||
|
"ERR_1000": "File could not be accessed during analysis",
|
||||||
|
"ERR_1001": "Media type is not supported",
|
||||||
|
"ERR_1002": "Encrypted RAR archives are not supported",
|
||||||
|
"ERR_1003": "Solid RAR archives are not supported",
|
||||||
|
"ERR_1004": "Multi-Volume RAR archives are not supported",
|
||||||
|
"ERR_1005": "Unknown error while analyzing book",
|
||||||
|
"ERR_1006": "Book does not contain any page",
|
||||||
|
"ERR_1007": "Some entries could not be analyzed",
|
||||||
|
"ERR_1008": "Unknown error while getting book's entries"
|
||||||
|
},
|
||||||
"filter": {
|
"filter": {
|
||||||
"age_rating": "age rating",
|
"age_rating": "age rating",
|
||||||
"age_rating_none": "None",
|
"age_rating_none": "None",
|
||||||
|
|
|
||||||
|
|
@ -347,6 +347,17 @@
|
||||||
"ONGOING": "En cours"
|
"ONGOING": "En cours"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"error_codes": {
|
||||||
|
"ERR_1000": "Le fichier n'etait pas accessible pendant l'analyse",
|
||||||
|
"ERR_1001": "Le type de média n'est pas supporté",
|
||||||
|
"ERR_1002": "Les archives RAR encryptées ne sont pas supportées",
|
||||||
|
"ERR_1003": "Les archives RAR solides ne sont pas supportées",
|
||||||
|
"ERR_1004": "Les archives RAR multi-volumes ne sont pas supportées",
|
||||||
|
"ERR_1005": "Erreur inconnue pendant l'analyse",
|
||||||
|
"ERR_1006": "Le livre ne contient aucune page",
|
||||||
|
"ERR_1007": "Certaines entrées n'ont pas pu être analysées",
|
||||||
|
"ERR_1008": "Erreur inconnue pendant la recuperation des entrées"
|
||||||
|
},
|
||||||
"filter": {
|
"filter": {
|
||||||
"age_rating": "Âge minimal",
|
"age_rating": "Âge minimal",
|
||||||
"age_rating_none": "Aucun",
|
"age_rating_none": "Aucun",
|
||||||
|
|
|
||||||
|
|
@ -252,7 +252,7 @@
|
||||||
|
|
||||||
<v-row v-if="book.media.comment" class="align-center text-caption">
|
<v-row v-if="book.media.comment" class="align-center text-caption">
|
||||||
<v-col class="py-1" cols="4" sm="3" md="2" xl="1">{{ $t('browse_book.comment') }}</v-col>
|
<v-col class="py-1" cols="4" sm="3" md="2" xl="1">{{ $t('browse_book.comment') }}</v-col>
|
||||||
<v-col class="py-1 error--text font-weight-bold" cols="8" sm="9" md="10" xl="11">{{ book.media.comment }}</v-col>
|
<v-col class="py-1 error--text font-weight-bold" cols="8" sm="9" md="10" xl="11">{{ mediaComment }}</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
<v-row class="align-center text-caption">
|
<v-row class="align-center text-caption">
|
||||||
|
|
@ -294,6 +294,7 @@ import {SeriesDto} from "@/types/komga-series";
|
||||||
import ReadMore from "@/components/ReadMore.vue";
|
import ReadMore from "@/components/ReadMore.vue";
|
||||||
import VueHorizontal from "vue-horizontal";
|
import VueHorizontal from "vue-horizontal";
|
||||||
import {authorRoles} from "@/types/author-roles";
|
import {authorRoles} from "@/types/author-roles";
|
||||||
|
import {convertErrorCodes} from "@/functions/error-codes";
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'BrowseBook',
|
name: 'BrowseBook',
|
||||||
|
|
@ -376,6 +377,9 @@ export default Vue.extend({
|
||||||
contextReadList(): boolean {
|
contextReadList(): boolean {
|
||||||
return this.context.origin === ContextOrigin.READLIST
|
return this.context.origin === ContextOrigin.READLIST
|
||||||
},
|
},
|
||||||
|
mediaComment(): string {
|
||||||
|
return convertErrorCodes(this.book.media.comment)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
libraryDeleted(event: EventLibraryDeleted) {
|
libraryDeleted(event: EventLibraryDeleted) {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import {MediaStatus} from '@/types/enum-books'
|
import {MediaStatus} from '@/types/enum-books'
|
||||||
import {BookDto} from '@/types/komga-books'
|
import {BookDto} from '@/types/komga-books'
|
||||||
|
import {convertErrorCodes} from "@/functions/error-codes";
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'SettingsMediaAnalysis',
|
name: 'SettingsMediaAnalysis',
|
||||||
|
|
@ -59,6 +60,7 @@ export default Vue.extend({
|
||||||
...b,
|
...b,
|
||||||
media: {
|
media: {
|
||||||
...b.media,
|
...b.media,
|
||||||
|
comment: convertErrorCodes(b.media.comment),
|
||||||
status: this.$t(`enums.media_status.${b.media.status}`).toString()},
|
status: this.$t(`enums.media_status.${b.media.status}`).toString()},
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
package org.gotson.komga.domain.model
|
package org.gotson.komga.domain.model
|
||||||
|
|
||||||
|
open class CodedException(message: String, val code: String) : Exception(message)
|
||||||
class MediaNotReadyException : Exception()
|
class MediaNotReadyException : Exception()
|
||||||
class MediaUnsupportedException(message: String) : Exception(message)
|
class MediaUnsupportedException(message: String, code: String = "") : CodedException(message, code)
|
||||||
class ImageConversionException(message: String) : Exception(message)
|
class ImageConversionException(message: String, code: String = "") : CodedException(message, code)
|
||||||
class DirectoryNotFoundException(message: String) : Exception(message)
|
class DirectoryNotFoundException(message: String, code: String = "") : CodedException(message, code)
|
||||||
class DuplicateNameException(message: String) : Exception(message)
|
class DuplicateNameException(message: String, code: String = "") : CodedException(message, code)
|
||||||
class PathContainedInPath(message: String) : Exception(message)
|
class PathContainedInPath(message: String, code: String = "") : CodedException(message, code)
|
||||||
class UserEmailAlreadyExistsException(message: String) : Exception(message)
|
class UserEmailAlreadyExistsException(message: String, code: String = "") : CodedException(message, code)
|
||||||
|
|
|
||||||
|
|
@ -36,15 +36,15 @@ class BookAnalyzer(
|
||||||
val mediaType = contentDetector.detectMediaType(book.path())
|
val mediaType = contentDetector.detectMediaType(book.path())
|
||||||
logger.info { "Detected media type: $mediaType" }
|
logger.info { "Detected media type: $mediaType" }
|
||||||
if (!supportedMediaTypes.containsKey(mediaType))
|
if (!supportedMediaTypes.containsKey(mediaType))
|
||||||
return Media(mediaType = mediaType, status = Media.Status.UNSUPPORTED, comment = "Media type $mediaType is not supported")
|
return Media(mediaType = mediaType, status = Media.Status.UNSUPPORTED, comment = "ERR_1001")
|
||||||
|
|
||||||
val entries = try {
|
val entries = try {
|
||||||
supportedMediaTypes.getValue(mediaType).getEntries(book.path())
|
supportedMediaTypes.getValue(mediaType).getEntries(book.path())
|
||||||
} catch (ex: MediaUnsupportedException) {
|
} catch (ex: MediaUnsupportedException) {
|
||||||
return Media(mediaType = mediaType, status = Media.Status.UNSUPPORTED, comment = ex.message)
|
return Media(mediaType = mediaType, status = Media.Status.UNSUPPORTED, comment = ex.code)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
logger.error(ex) { "Error while analyzing book: $book" }
|
logger.error(ex) { "Error while analyzing book: $book" }
|
||||||
return Media(mediaType = mediaType, status = Media.Status.ERROR, comment = ex.message)
|
return Media(mediaType = mediaType, status = Media.Status.ERROR, comment = "ERR_1008")
|
||||||
}
|
}
|
||||||
|
|
||||||
val (pages, others) = entries
|
val (pages, others) = entries
|
||||||
|
|
@ -61,11 +61,11 @@ class BookAnalyzer(
|
||||||
.filter { it.mediaType.isNullOrBlank() }
|
.filter { it.mediaType.isNullOrBlank() }
|
||||||
.map { it.name }
|
.map { it.name }
|
||||||
.ifEmpty { null }
|
.ifEmpty { null }
|
||||||
?.joinToString(prefix = "Some entries could not be analyzed: [", postfix = "]") { it }
|
?.joinToString(prefix = "ERR_1007 [", postfix = "]") { it }
|
||||||
|
|
||||||
if (pages.isEmpty()) {
|
if (pages.isEmpty()) {
|
||||||
logger.warn { "Book $book does not contain any pages" }
|
logger.warn { "Book $book does not contain any pages" }
|
||||||
return Media(mediaType = mediaType, status = Media.Status.ERROR, comment = "Book does not contain any pages")
|
return Media(mediaType = mediaType, status = Media.Status.ERROR, comment = "ERR_1006")
|
||||||
}
|
}
|
||||||
logger.info { "Book has ${pages.size} pages" }
|
logger.info { "Book has ${pages.size} pages" }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,9 @@ class RarExtractor(
|
||||||
|
|
||||||
override fun getEntries(path: Path): List<MediaContainerEntry> =
|
override fun getEntries(path: Path): List<MediaContainerEntry> =
|
||||||
Archive(path.toFile()).use { rar ->
|
Archive(path.toFile()).use { rar ->
|
||||||
if (rar.isPasswordProtected) throw MediaUnsupportedException("Encrypted RAR archives are not supported")
|
if (rar.isPasswordProtected) throw MediaUnsupportedException("Encrypted RAR archives are not supported", "ERR_1002")
|
||||||
if (rar.mainHeader.isSolid) throw MediaUnsupportedException("Solid RAR archives are not supported")
|
if (rar.mainHeader.isSolid) throw MediaUnsupportedException("Solid RAR archives are not supported", "ERR_1003")
|
||||||
if (rar.mainHeader.isMultiVolume) throw MediaUnsupportedException("Multi-Volume RAR archives are not supported")
|
if (rar.mainHeader.isMultiVolume) throw MediaUnsupportedException("Multi-Volume RAR archives are not supported", "ERR_1004")
|
||||||
rar.fileHeaders
|
rar.fileHeaders
|
||||||
.filter { !it.isDirectory }
|
.filter { !it.isDirectory }
|
||||||
.map { hd ->
|
.map { hd ->
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue