mirror of
https://github.com/gotson/komga.git
synced 2026-05-08 04:22:28 +02:00
fix: book conversion will conserve page hashes
This commit is contained in:
parent
d9aa33d7d7
commit
83a59b8bd3
1 changed files with 19 additions and 5 deletions
|
|
@ -4,17 +4,21 @@ import mu.KotlinLogging
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry
|
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream
|
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream
|
||||||
import org.apache.commons.io.FilenameUtils
|
import org.apache.commons.io.FilenameUtils
|
||||||
|
import org.gotson.komga.application.events.EventPublisher
|
||||||
import org.gotson.komga.domain.model.Book
|
import org.gotson.komga.domain.model.Book
|
||||||
import org.gotson.komga.domain.model.BookConversionException
|
import org.gotson.komga.domain.model.BookConversionException
|
||||||
import org.gotson.komga.domain.model.BookWithMedia
|
import org.gotson.komga.domain.model.BookWithMedia
|
||||||
|
import org.gotson.komga.domain.model.DomainEvent
|
||||||
import org.gotson.komga.domain.model.Library
|
import org.gotson.komga.domain.model.Library
|
||||||
import org.gotson.komga.domain.model.Media
|
import org.gotson.komga.domain.model.Media
|
||||||
import org.gotson.komga.domain.model.MediaNotReadyException
|
import org.gotson.komga.domain.model.MediaNotReadyException
|
||||||
import org.gotson.komga.domain.model.MediaType
|
import org.gotson.komga.domain.model.MediaType
|
||||||
import org.gotson.komga.domain.model.MediaUnsupportedException
|
import org.gotson.komga.domain.model.MediaUnsupportedException
|
||||||
|
import org.gotson.komga.domain.model.restoreHashFrom
|
||||||
import org.gotson.komga.domain.persistence.BookRepository
|
import org.gotson.komga.domain.persistence.BookRepository
|
||||||
import org.gotson.komga.domain.persistence.LibraryRepository
|
import org.gotson.komga.domain.persistence.LibraryRepository
|
||||||
import org.gotson.komga.domain.persistence.MediaRepository
|
import org.gotson.komga.domain.persistence.MediaRepository
|
||||||
|
import org.gotson.komga.infrastructure.language.notEquals
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import org.springframework.transaction.support.TransactionTemplate
|
import org.springframework.transaction.support.TransactionTemplate
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
|
|
@ -40,6 +44,7 @@ class BookConverter(
|
||||||
private val mediaRepository: MediaRepository,
|
private val mediaRepository: MediaRepository,
|
||||||
private val libraryRepository: LibraryRepository,
|
private val libraryRepository: LibraryRepository,
|
||||||
private val transactionTemplate: TransactionTemplate,
|
private val transactionTemplate: TransactionTemplate,
|
||||||
|
private val eventPublisher: EventPublisher,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val convertibleTypes = listOf(MediaType.RAR_4.value)
|
private val convertibleTypes = listOf(MediaType.RAR_4.value)
|
||||||
|
|
@ -55,22 +60,27 @@ class BookConverter(
|
||||||
bookRepository.findAllByLibraryIdAndMediaTypes(library.id, convertibleTypes)
|
bookRepository.findAllByLibraryIdAndMediaTypes(library.id, convertibleTypes)
|
||||||
|
|
||||||
fun convertToCbz(book: Book) {
|
fun convertToCbz(book: Book) {
|
||||||
// TODO: check if file has changed on disk before doing conversion
|
// perform various checks
|
||||||
if (!libraryRepository.findById(book.libraryId).convertToCbz)
|
if (!libraryRepository.findById(book.libraryId).convertToCbz)
|
||||||
return logger.info { "Book conversion is disabled for the library, it may have changed since the task was submitted, skipping" }
|
return logger.info { "Book conversion is disabled for the library, it may have changed since the task was submitted, skipping" }
|
||||||
|
|
||||||
if (failedConversions.contains(book.id))
|
if (failedConversions.contains(book.id))
|
||||||
return logger.info { "Book conversion already failed before, skipping" }
|
return logger.info { "Book conversion already failed before, skipping" }
|
||||||
|
|
||||||
if (book.path.notExists()) throw FileNotFoundException("File not found: ${book.path}")
|
fileSystemScanner.scanFile(book.path)?.let { scannedBook ->
|
||||||
|
if (scannedBook.fileLastModified.notEquals(book.fileLastModified))
|
||||||
|
return logger.info { "Book has changed on disk, skipping" }
|
||||||
|
} ?: throw FileNotFoundException("File not found: ${book.path}")
|
||||||
|
|
||||||
val media = mediaRepository.findById(book.id)
|
val media = mediaRepository.findById(book.id)
|
||||||
|
|
||||||
if (!convertibleTypes.contains(media.mediaType))
|
if (!convertibleTypes.contains(media.mediaType))
|
||||||
throw MediaUnsupportedException("${media.mediaType} cannot be converted. Must be one of $convertibleTypes")
|
throw MediaUnsupportedException("${media.mediaType} cannot be converted. Must be one of $convertibleTypes")
|
||||||
|
|
||||||
if (media.status != Media.Status.READY)
|
if (media.status != Media.Status.READY)
|
||||||
throw MediaNotReadyException()
|
throw MediaNotReadyException()
|
||||||
|
|
||||||
|
// perform conversion
|
||||||
val destinationFilename = "${book.path.nameWithoutExtension}.$CBZ_EXTENSION"
|
val destinationFilename = "${book.path.nameWithoutExtension}.$CBZ_EXTENSION"
|
||||||
val destinationPath = book.path.parent.resolve(destinationFilename)
|
val destinationPath = book.path.parent.resolve(destinationFilename)
|
||||||
if (destinationPath.exists())
|
if (destinationPath.exists())
|
||||||
|
|
@ -91,6 +101,7 @@ class BookConverter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// perform checks on new file
|
||||||
val convertedBook = fileSystemScanner.scanFile(destinationPath)
|
val convertedBook = fileSystemScanner.scanFile(destinationPath)
|
||||||
?.copy(
|
?.copy(
|
||||||
id = book.id,
|
id = book.id,
|
||||||
|
|
@ -124,13 +135,16 @@ class BookConverter(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (book.path.deleteIfExists())
|
if (book.path.deleteIfExists())
|
||||||
logger.info { "Deleted converted file: ${book.path}" }
|
logger.info { "Deleted old file: ${book.path}" }
|
||||||
|
|
||||||
|
val mediaWithHashes = convertedMedia.copy(pages = convertedMedia.pages.restoreHashFrom(media.pages))
|
||||||
|
|
||||||
transactionTemplate.executeWithoutResult {
|
transactionTemplate.executeWithoutResult {
|
||||||
bookRepository.update(convertedBook)
|
bookRepository.update(convertedBook)
|
||||||
// TODO: restore page hash from existing media
|
mediaRepository.update(mediaWithHashes)
|
||||||
mediaRepository.update(convertedMedia)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eventPublisher.publishEvent(DomainEvent.BookUpdated(convertedBook))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMismatchedExtensionBooks(library: Library): Collection<Book> =
|
fun getMismatchedExtensionBooks(library: Library): Collection<Book> =
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue