fix(opds): cannot retrieve full size poster for epub books

Closes: #1312
This commit is contained in:
Gauthier Roebroeck 2023-11-29 16:43:00 +08:00
parent 86f0fcd706
commit 5a71cf757b
7 changed files with 42 additions and 23 deletions

View file

@ -136,13 +136,8 @@ class BookAnalyzer(
}
val thumbnail = try {
when (book.media.profile) {
MediaProfile.DIVINA -> divinaExtractors[book.media.mediaType]?.getEntryStream(book.book.path, book.media.pages.first().fileName)
MediaProfile.PDF -> pdfExtractor.getPageContentAsImage(book.book.path, 1).content
MediaProfile.EPUB -> epubExtractor.getCover(book.book.path)?.content
null -> null
}?.let { cover ->
imageConverter.resizeImageToByteArray(cover, thumbnailType, komgaSettingsProvider.thumbnailSize.maxEdge)
getPoster(book)?.let { cover ->
imageConverter.resizeImageToByteArray(cover.content, thumbnailType, komgaSettingsProvider.thumbnailSize.maxEdge)
}
} catch (ex: Exception) {
logger.warn(ex) { "Could not generate thumbnail for book: $book" }
@ -159,6 +154,19 @@ class BookAnalyzer(
)
}
fun getPoster(book: BookWithMedia): BookPageContent? = when (book.media.profile) {
MediaProfile.DIVINA -> divinaExtractors[book.media.mediaType]?.getEntryStream(book.book.path, book.media.pages.first().fileName)?.let {
BookPageContent(
it,
book.media.pages.first().mediaType,
)
}
MediaProfile.PDF -> pdfExtractor.getPageContentAsImage(book.book.path, 1)
MediaProfile.EPUB -> epubExtractor.getCover(book.book.path)
null -> null
}
@Throws(
MediaNotReadyException::class,
IndexOutOfBoundsException::class,

View file

@ -181,7 +181,7 @@ class BookLifecycle(
return selected
}
fun getThumbnailBytes(bookId: String, resizeTo: Int? = null): ByteArray? {
fun getThumbnailBytes(bookId: String, resizeTo: Int? = null): BookPageContent? {
getThumbnail(bookId)?.let {
val thumbnailBytes = when {
it.thumbnail != null -> it.thumbnail
@ -190,19 +190,32 @@ class BookLifecycle(
}
if (resizeTo != null) {
return try {
imageConverter.resizeImageToByteArray(thumbnailBytes, resizeTargetFormat, resizeTo)
try {
return BookPageContent(
imageConverter.resizeImageToByteArray(thumbnailBytes, resizeTargetFormat, resizeTo),
resizeTargetFormat.mediaType,
)
} catch (e: Exception) {
logger.error(e) { "Resize thumbnail of book $bookId to $resizeTo: failed" }
thumbnailBytes
}
}
return thumbnailBytes
return BookPageContent(thumbnailBytes, it.mediaType)
}
return null
}
fun getThumbnailBytesOriginal(bookId: String): BookPageContent? {
val thumbnail = getThumbnail(bookId) ?: return null
return if (thumbnail.type == ThumbnailBook.Type.GENERATED) {
val book = bookRepository.findByIdOrNull(bookId) ?: return null
val media = mediaRepository.findById(book.id)
bookAnalyzer.getPoster(BookWithMedia(book, media))
} else {
getThumbnailBytes(bookId)
}
}
fun getThumbnailBytesByThumbnailId(thumbnailId: String): ByteArray? =
thumbnailBookRepository.findByIdOrNull(thumbnailId)?.let {
getBytesFromThumbnailBook(it)

View file

@ -117,7 +117,7 @@ class ReadListLifecycle(
this.take(4)
}
val images = ids.mapNotNull { bookLifecycle.getThumbnailBytes(it) }
val images = ids.mapNotNull { bookLifecycle.getThumbnailBytes(it)?.content }
return mosaicGenerator.createMosaic(images)
}

View file

@ -257,7 +257,7 @@ class SeriesLifecycle(
?: bookRepository.findLastIdInSeriesOrNull(seriesId)
Library.SeriesCover.LAST -> bookRepository.findLastIdInSeriesOrNull(seriesId)
}
if (bookId != null) return bookLifecycle.getThumbnailBytes(bookId)
if (bookId != null) return bookLifecycle.getThumbnailBytes(bookId)?.content
}
return null

View file

@ -3,10 +3,10 @@ package org.gotson.komga.interfaces.api.opds
import io.swagger.v3.oas.annotations.media.Content
import io.swagger.v3.oas.annotations.media.Schema
import io.swagger.v3.oas.annotations.responses.ApiResponse
import org.gotson.komga.domain.model.ThumbnailBook
import org.gotson.komga.domain.persistence.BookRepository
import org.gotson.komga.domain.persistence.SeriesMetadataRepository
import org.gotson.komga.domain.service.BookLifecycle
import org.gotson.komga.infrastructure.image.ImageConverter
import org.gotson.komga.infrastructure.image.ImageType
import org.gotson.komga.infrastructure.security.KomgaPrincipal
import org.gotson.komga.interfaces.api.checkContentRestriction
@ -23,6 +23,7 @@ class OpdsCommonController(
private val seriesMetadataRepository: SeriesMetadataRepository,
private val bookRepository: BookRepository,
private val bookLifecycle: BookLifecycle,
private val imageConverter: ImageConverter,
) {
@ApiResponse(content = [Content(schema = Schema(type = "string", format = "binary"))])
@ -38,11 +39,8 @@ class OpdsCommonController(
@PathVariable bookId: String,
): ByteArray {
principal.user.checkContentRestriction(bookId, bookRepository, seriesMetadataRepository)
val thumbnail = bookLifecycle.getThumbnail(bookId) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
return if (thumbnail.type == ThumbnailBook.Type.GENERATED) {
bookLifecycle.getBookPage(bookRepository.findByIdOrNull(bookId)!!, 1, ImageType.JPEG).content
} else {
bookLifecycle.getThumbnailBytes(bookId) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
}
val poster = bookLifecycle.getThumbnailBytesOriginal(bookId) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
return if (poster.mediaType != ImageType.JPEG.mediaType) imageConverter.convertImage(poster.content, ImageType.JPEG.imageIOFormat)
else poster.content
}
}

View file

@ -670,7 +670,7 @@ class OpdsController(
principal.user.checkContentRestriction(bookId, bookRepository, seriesMetadataRepository)
val thumbnail = bookLifecycle.getThumbnail(bookId) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
return bookLifecycle.getThumbnailBytes(bookId, if (thumbnail.type == ThumbnailBook.Type.GENERATED) null else komgaSettingsProvider.thumbnailSize.maxEdge)
return bookLifecycle.getThumbnailBytes(bookId, if (thumbnail.type == ThumbnailBook.Type.GENERATED) null else komgaSettingsProvider.thumbnailSize.maxEdge)?.content
?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
}

View file

@ -298,7 +298,7 @@ class BookController(
): ByteArray {
principal.user.checkContentRestriction(bookId, bookRepository, seriesMetadataRepository)
return bookLifecycle.getThumbnailBytes(bookId) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
return bookLifecycle.getThumbnailBytes(bookId)?.content ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
}
@ApiResponse(content = [Content(schema = Schema(type = "string", format = "binary"))])