diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/PdfExtractor.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/PdfExtractor.kt index 70e4ffcab..d541d4aeb 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/PdfExtractor.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/PdfExtractor.kt @@ -1,5 +1,6 @@ package org.gotson.komga.infrastructure.mediacontainer +import com.github.benmanes.caffeine.cache.Caffeine import mu.KotlinLogging import org.apache.pdfbox.pdmodel.PDDocument import org.apache.pdfbox.pdmodel.PDPage @@ -11,6 +12,7 @@ import org.gotson.komga.infrastructure.image.ImageAnalyzer import org.springframework.stereotype.Service import java.io.ByteArrayOutputStream import java.nio.file.Path +import java.util.concurrent.TimeUnit import javax.imageio.ImageIO import kotlin.math.roundToInt @@ -25,6 +27,12 @@ class PdfExtractor( private val imageIOFormat = "jpeg" private val resolution = 1536F + private val cache = Caffeine.newBuilder() + .maximumSize(20) + .expireAfterAccess(1, TimeUnit.MINUTES) + .removalListener { _: Path?, pdf: PDDocument?, _ -> pdf?.close() } + .build() + override fun mediaTypes(): List = listOf("application/pdf") override fun getEntries(path: Path): List = @@ -37,16 +45,16 @@ class PdfExtractor( } } - override fun getEntryStream(path: Path, entryName: String): ByteArray = - PDDocument.load(path.toFile()).use { pdf -> - val pageNumber = entryName.toInt() - val page = pdf.getPage(pageNumber) - val image = PDFRenderer(pdf).renderImage(pageNumber, page.getScale(), ImageType.RGB) - ByteArrayOutputStream().use { out -> - ImageIO.write(image, imageIOFormat, out) - out.toByteArray() - } + override fun getEntryStream(path: Path, entryName: String): ByteArray { + val pdf = cache.get(path) { PDDocument.load(path.toFile()) }!! + val pageNumber = entryName.toInt() + val page = pdf.getPage(pageNumber) + val image = PDFRenderer(pdf).renderImage(pageNumber, page.getScale(), ImageType.RGB) + return ByteArrayOutputStream().use { out -> + ImageIO.write(image, imageIOFormat, out) + out.toByteArray() } + } private fun PDPage.getScale() = resolution / minOf(cropBox.width, cropBox.height) } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/ZipExtractor.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/ZipExtractor.kt index 5b97b5439..8e080e2e9 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/ZipExtractor.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/mediacontainer/ZipExtractor.kt @@ -1,5 +1,6 @@ package org.gotson.komga.infrastructure.mediacontainer +import com.github.benmanes.caffeine.cache.Caffeine import mu.KotlinLogging import net.greypanther.natsort.CaseInsensitiveSimpleNaturalComparator import org.apache.commons.compress.archivers.zip.ZipFile @@ -7,6 +8,7 @@ import org.gotson.komga.domain.model.MediaContainerEntry import org.gotson.komga.infrastructure.image.ImageAnalyzer import org.springframework.stereotype.Service import java.nio.file.Path +import java.util.concurrent.TimeUnit private val logger = KotlinLogging.logger {} @@ -16,6 +18,12 @@ class ZipExtractor( private val imageAnalyzer: ImageAnalyzer ) : MediaContainerExtractor { + private val cache = Caffeine.newBuilder() + .maximumSize(20) + .expireAfterAccess(1, TimeUnit.MINUTES) + .removalListener { _: Path?, zip: ZipFile?, _ -> zip?.close() } + .build() + private val natSortComparator: Comparator = CaseInsensitiveSimpleNaturalComparator.getInstance() override fun mediaTypes(): List = listOf("application/zip") @@ -42,8 +50,8 @@ class ZipExtractor( .sortedWith(compareBy(natSortComparator) { it.name }) } - override fun getEntryStream(path: Path, entryName: String): ByteArray = - ZipFile(path.toFile()).use { zip -> - zip.getInputStream(zip.getEntry(entryName)).use { it.readBytes() } - } + override fun getEntryStream(path: Path, entryName: String): ByteArray { + val zip = cache.get(path) { ZipFile(path.toFile()) }!! + return zip.getInputStream(zip.getEntry(entryName)).use { it.readBytes() } + } }