From acf080be9dce58a6f2140fd98d1dde4addc51eff Mon Sep 17 00:00:00 2001 From: Gauthier Roebroeck Date: Thu, 30 Nov 2023 10:41:30 +0800 Subject: [PATCH] fix(komga): mark broken EPUB files as ERROR instead of falling back to CBZ --- ERRORCODES.md | 1 + komga-webui/src/locales/en.json | 3 ++- .../gotson/komga/domain/service/BookAnalyzer.kt | 6 ++++++ .../komga/domain/service/BookAnalyzerTest.kt | 12 ++++++++++++ .../src/test/resources/archives/zip-as-epub.epub | Bin 0 -> 3260 bytes 5 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 komga/src/test/resources/archives/zip-as-epub.epub diff --git a/ERRORCODES.md b/ERRORCODES.md index d6c8ceb13..5d0e14071 100644 --- a/ERRORCODES.md +++ b/ERRORCODES.md @@ -35,3 +35,4 @@ | ERR_1029 | ComicRack CBL does not contain any Book element | | ERR_1030 | ComicRack CBL has no Name element | | ERR_1031 | ComicRack CBL Book is missing series or number | +| ERR_1032 | EPUB file has wrong media type | diff --git a/komga-webui/src/locales/en.json b/komga-webui/src/locales/en.json index 428bc739e..20de97e9a 100644 --- a/komga-webui/src/locales/en.json +++ b/komga-webui/src/locales/en.json @@ -750,7 +750,8 @@ "ERR_1028": "OpenID Connect login error: no email attribute", "ERR_1029": "ComicRack CBL does not contain any Book element", "ERR_1030": "ComicRack CBL has no Name element", - "ERR_1031": "ComicRack CBL Book is missing series or number" + "ERR_1031": "ComicRack CBL Book is missing series or number", + "ERR_1032": "EPUB file has wrong media type" }, "filter": { "age_rating": "age rating", diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookAnalyzer.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookAnalyzer.kt index 392abe3ba..f429f4b39 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookAnalyzer.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookAnalyzer.kt @@ -30,6 +30,7 @@ import java.io.ByteArrayOutputStream import java.nio.file.AccessDeniedException import java.nio.file.NoSuchFileException import javax.imageio.ImageIO +import kotlin.io.path.extension private val logger = KotlinLogging.logger {} @@ -62,6 +63,11 @@ class BookAnalyzer( MediaType.fromMediaType(it) ?: return Media(mediaType = it, status = Media.Status.UNSUPPORTED, comment = "ERR_1001", bookId = book.id) } + if (book.path.extension.lowercase() == "epub" && mediaType != MediaType.EPUB) { + logger.warn { "Epub file detected as zip, file is probably broken: ${book.path}" } + return Media(mediaType = mediaType.type, status = Media.Status.ERROR, comment = "ERR_1032", bookId = book.id) + } + when (mediaType.profile) { MediaProfile.DIVINA -> analyzeDivina(book, mediaType, analyzeDimensions) MediaProfile.PDF -> analyzePdf(book, analyzeDimensions) diff --git a/komga/src/test/kotlin/org/gotson/komga/domain/service/BookAnalyzerTest.kt b/komga/src/test/kotlin/org/gotson/komga/domain/service/BookAnalyzerTest.kt index cf05d9575..ed82840ff 100644 --- a/komga/src/test/kotlin/org/gotson/komga/domain/service/BookAnalyzerTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/domain/service/BookAnalyzerTest.kt @@ -133,6 +133,18 @@ class BookAnalyzerTest( assertThat(media.pages).hasSize(0) } + @Test + fun `given broken epub archive when analyzing then media status is ERROR`() { + val file = ClassPathResource("archives/zip-as-epub.epub") + val book = Book("book", file.url, LocalDateTime.now()) + + val media = bookAnalyzer.analyze(book, false) + + assertThat(media.mediaType).isEqualTo("application/zip") + assertThat(media.status).isEqualTo(Media.Status.ERROR) + assertThat(media.pages).hasSize(0) + } + @Test fun `given book with a single page when hashing then all pages are hashed`() { val book = makeBook("book1") diff --git a/komga/src/test/resources/archives/zip-as-epub.epub b/komga/src/test/resources/archives/zip-as-epub.epub new file mode 100644 index 0000000000000000000000000000000000000000..bc224d48719dd91a9acb3ed63fab21aa38c98f57 GIT binary patch literal 3260 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 literal 0 HcmV?d00001