Skip to content

Commit

Permalink
fix: use Epub cover for thumbnail
Browse files Browse the repository at this point in the history
  • Loading branch information
gotson committed Aug 17, 2023
1 parent 099276c commit 8bdc4d8
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import org.gotson.komga.infrastructure.hash.Hasher
import org.gotson.komga.infrastructure.image.ImageConverter
import org.gotson.komga.infrastructure.image.ImageType
import org.gotson.komga.infrastructure.mediacontainer.ContentDetector
import org.gotson.komga.infrastructure.mediacontainer.CoverExtractor
import org.gotson.komga.infrastructure.mediacontainer.MediaContainerExtractor
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
Expand Down Expand Up @@ -102,7 +103,20 @@ class BookAnalyzer(
}

val thumbnail = try {
supportedMediaTypes.getValue(book.media.mediaType!!).getEntryStream(book.book.path, book.media.pages.first().fileName).let { cover ->
val extractor = supportedMediaTypes.getValue(book.media.mediaType!!)
// try to get the cover from a CoverExtractor first
var coverBytes: ByteArray? = if (extractor is CoverExtractor) {
try {
extractor.getCoverStream(book.book.path)
} catch (e: Exception) {
logger.warn(e) { "Error while extracting cover. Falling back to first page. Book: $book" }
null
}
} else null
// if no cover could be found, get the first page
if (coverBytes == null) coverBytes = extractor.getEntryStream(book.book.path, book.media.pages.first().fileName)

coverBytes.let { cover ->
imageConverter.resizeImage(cover, thumbnailFormat, thumbnailSize)
}
} catch (ex: Exception) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.gotson.komga.infrastructure.mediacontainer

import java.nio.file.Path

interface CoverExtractor {
fun getCoverStream(path: Path): ByteArray?
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.gotson.komga.domain.model.MediaType
import org.gotson.komga.domain.model.MediaUnsupportedException
import org.gotson.komga.infrastructure.image.ImageAnalyzer
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.springframework.stereotype.Service
import java.nio.file.Path
import java.nio.file.Paths
Expand All @@ -20,7 +21,7 @@ class EpubExtractor(
private val zipExtractor: ZipExtractor,
private val contentDetector: ContentDetector,
private val imageAnalyzer: ImageAnalyzer,
) : MediaContainerExtractor {
) : MediaContainerExtractor, CoverExtractor {

override fun mediaTypes(): List<String> = listOf(MediaType.EPUB.value)

Expand All @@ -32,8 +33,7 @@ class EpubExtractor(
val opfDoc = zip.getInputStream(zip.getEntry(opfFile)).use { Jsoup.parse(it, null, "") }
val opfDir = Paths.get(opfFile).parent

val manifest = opfDoc.select("manifest > item")
.associate { it.attr("id") to ManifestItem(it.attr("id"), it.attr("href"), it.attr("media-type")) }
val manifest = opfDoc.getManifest()

val pages = opfDoc.select("spine > itemref").map { it.attr("idref") }
.mapNotNull { manifest[it] }
Expand Down Expand Up @@ -84,6 +84,17 @@ class EpubExtractor(
?: throw MediaUnsupportedException("META-INF/container.xml does not contain rootfile tag")
}

private fun Document.getManifest() =
select("manifest > item")
.associate {
it.attr("id") to ManifestItem(
it.attr("id"),
it.attr("href"),
it.attr("media-type"),
it.attr("properties").split(" ").toSet(),
)
}

fun getPackageFile(path: Path): String? =
ZipFile(path.toFile()).use { zip ->
try {
Expand All @@ -99,5 +110,28 @@ class EpubExtractor(
val id: String,
val href: String,
val mediaType: String,
val properties: Set<String> = emptySet(),
)

override fun getCoverStream(path: Path): ByteArray? {
ZipFile(path.toFile()).use { zip ->
val opfFile = getPackagePath(zip)

val opfDoc = zip.getInputStream(zip.getEntry(opfFile)).use { Jsoup.parse(it, null, "") }
val opfDir = Paths.get(opfFile).parent
val manifest = opfDoc.getManifest()

val coverManifestItem =
// EPUB 3 - try to get cover from manifest properties 'cover-image'
manifest.values.firstOrNull { it.properties.contains("cover-image") }
?: // EPUB 2 - get cover from meta element with name="cover"
opfDoc.selectFirst("metadata > meta[name=cover]")?.attr("content")?.ifBlank { null }?.let { manifest[it] }

if (coverManifestItem != null) {
val href = coverManifestItem.href
val coverPath = opfDir?.resolve(href)?.normalize() ?: Paths.get(href)
return zip.getInputStream(zip.getEntry(coverPath.invariantSeparatorsPathString)).readAllBytes()
} else return null
}
}
}

0 comments on commit 8bdc4d8

Please sign in to comment.