From 0fd783c9cdb5093ea6d197c7dad6ae4ec2d451cd Mon Sep 17 00:00:00 2001 From: Gauthier Roebroeck Date: Thu, 19 Sep 2024 15:42:55 +0800 Subject: [PATCH] feat: detect if epub is a kepub --- .../sqlite/V20240911175419__kepub.sql | 2 ++ .../org/gotson/komga/domain/model/Media.kt | 1 + .../komga/domain/service/BookAnalyzer.kt | 1 + .../infrastructure/jooq/main/BookDtoDao.kt | 1 + .../infrastructure/jooq/main/KoboDtoDao.kt | 2 ++ .../komga/infrastructure/jooq/main/MediaDao.kt | 7 ++++++- .../mediacontainer/epub/EpubExtractor.kt | 18 ++++++++++++++++++ .../mediacontainer/epub/EpubManifest.kt | 1 + .../komga/interfaces/api/rest/dto/BookDto.kt | 1 + 9 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 komga/src/flyway/resources/db/migration/sqlite/V20240911175419__kepub.sql diff --git a/komga/src/flyway/resources/db/migration/sqlite/V20240911175419__kepub.sql b/komga/src/flyway/resources/db/migration/sqlite/V20240911175419__kepub.sql new file mode 100644 index 00000000..98971ecf --- /dev/null +++ b/komga/src/flyway/resources/db/migration/sqlite/V20240911175419__kepub.sql @@ -0,0 +1,2 @@ +alter table MEDIA + add column EPUB_IS_KEPUB boolean NOT NULL DEFAULT 0; diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/model/Media.kt b/komga/src/main/kotlin/org/gotson/komga/domain/model/Media.kt index 9ff2b65b..26383090 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/model/Media.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/model/Media.kt @@ -12,6 +12,7 @@ data class Media( val extension: MediaExtension? = null, val bookId: String = "", val epubDivinaCompatible: Boolean = false, + val epubIsKepub: Boolean = false, override val createdDate: LocalDateTime = LocalDateTime.now(), override val lastModifiedDate: LocalDateTime = createdDate, ) : Auditable { 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 dcb17bdc..28fedfe4 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 @@ -155,6 +155,7 @@ class BookAnalyzer( files = manifest.resources, pageCount = manifest.pageCount, epubDivinaCompatible = manifest.divinaPages.isNotEmpty(), + epubIsKepub = manifest.isKepub, extension = MediaExtensionEpub( toc = manifest.toc, diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDao.kt index 863ac58b..bc07c20c 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDao.kt @@ -486,6 +486,7 @@ class BookDtoDao( pagesCount = pageCount.toInt(), comment = comment ?: "", epubDivinaCompatible = epubDivinaCompatible, + epubIsKepub = epubIsKepub, ) private fun BookMetadataRecord.toDto( diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KoboDtoDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KoboDtoDao.kt index 33c9a7cb..06c96585 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KoboDtoDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KoboDtoDao.kt @@ -47,6 +47,7 @@ class KoboDtoDao( sd.LANGUAGE, b.FILE_SIZE, b.ONESHOT, + m.EPUB_IS_KEPUB, m.EXTENSION_CLASS, m.EXTENSION_VALUE_BLOB, ).from(b) @@ -107,6 +108,7 @@ class KoboDtoDao( null, title = dr.title, workId = dr.bookId, + isKepub = mr.epubIsKepub, ) } } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/MediaDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/MediaDao.kt index 16abbbca..89e93da4 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/MediaDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/MediaDao.kt @@ -50,6 +50,7 @@ class MediaDao( m.PAGE_COUNT, m.EXTENSION_CLASS, m.EPUB_DIVINA_COMPATIBLE, + m.EPUB_IS_KEPUB, *p.fields(), ) @@ -136,9 +137,10 @@ class MediaDao( m.COMMENT, m.PAGE_COUNT, m.EPUB_DIVINA_COMPATIBLE, + m.EPUB_IS_KEPUB, m.EXTENSION_CLASS, m.EXTENSION_VALUE_BLOB, - ).values(null as String?, null, null, null, null, null, null, null), + ).values(null as String?, null, null, null, null, null, null, null, null), ).also { step -> chunk.forEach { media -> step.bind( @@ -148,6 +150,7 @@ class MediaDao( media.comment, media.pageCount, media.epubDivinaCompatible, + media.epubIsKepub, media.extension?.let { if (it is ProxyExtension) null else it::class.qualifiedName }, media.extension?.let { if (it is ProxyExtension) null else mapper.serializeJsonGz(it) }, ) @@ -232,6 +235,7 @@ class MediaDao( .set(m.COMMENT, media.comment) .set(m.PAGE_COUNT, media.pageCount) .set(m.EPUB_DIVINA_COMPATIBLE, media.epubDivinaCompatible) + .set(m.EPUB_IS_KEPUB, media.epubIsKepub) .apply { if (media.extension != null && media.extension !is ProxyExtension) { set(m.EXTENSION_CLASS, media.extension::class.qualifiedName) @@ -286,6 +290,7 @@ class MediaDao( comment = comment, bookId = bookId, epubDivinaCompatible = epubDivinaCompatible, + epubIsKepub = epubIsKepub, createdDate = createdDate.toCurrentTimeZone(), lastModifiedDate = lastModifiedDate.toCurrentTimeZone(), ) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/EpubExtractor.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/EpubExtractor.kt index 14427760..4aae8fd2 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/EpubExtractor.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/EpubExtractor.kt @@ -87,6 +87,7 @@ class EpubExtractor( isFixedLayout = isFixedLayout, positions = computePositions(resources, isFixedLayout), divinaPages = getDivinaPages(epub, isFixedLayout, pageCount, analyzeDimensions), + isKepub = isKepub(epub, resources) ) } @@ -174,6 +175,23 @@ class EpubExtractor( } } + private fun isKepub( + epub: EpubPackage, + resources: List + ): Boolean { + try { + val readingOrder = resources.filter { it.subType == MediaFile.SubType.EPUB_PAGE } + + readingOrder.forEach { mediaFile -> + val doc = epub.zip.getEntryInputStream(mediaFile.fileName).use { Jsoup.parse(it, null, "") } + if(!doc.getElementsByClass("koboSpan").isNullOrEmpty()) return true + } + } catch (e: Exception) { + logger.warn(e) { "Error while checking if EPUB is KEPUB" } + } + return false + } + private fun computePageCount(epub: EpubPackage): Int { val spine = epub.opfDoc.select("spine > itemref") diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/EpubManifest.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/EpubManifest.kt index ab64f01c..862e1c79 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/EpubManifest.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/epub/EpubManifest.kt @@ -15,4 +15,5 @@ data class EpubManifest( val isFixedLayout: Boolean, val positions: List, val divinaPages: List, + val isKepub: Boolean, ) diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/dto/BookDto.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/dto/BookDto.kt index 1b496803..4bec50e1 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/dto/BookDto.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/rest/dto/BookDto.kt @@ -40,6 +40,7 @@ data class MediaDto( val pagesCount: Int, val comment: String, val epubDivinaCompatible: Boolean, + val epubIsKepub: Boolean, ) { val mediaProfile: String by lazy { MediaType.fromMediaType(mediaType)?.profile?.name ?: "" } }