diff --git a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookImporter.kt b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookImporter.kt index b4bcabe97..59ecc150e 100644 --- a/komga/src/main/kotlin/org/gotson/komga/domain/service/BookImporter.kt +++ b/komga/src/main/kotlin/org/gotson/komga/domain/service/BookImporter.kt @@ -77,31 +77,34 @@ class BookImporter( ) } - val upgradedBook = + val bookToUpgrade = if (upgradeBookId != null) { - bookRepository.findByIdOrNull(upgradeBookId)?.let { + bookRepository.findByIdOrNull(upgradeBookId)?.also { if (it.seriesId != series.id) throw IllegalArgumentException("Book to upgrade ($upgradeBookId) does not belong to series: $series").withCode("ERR_1020") - it } } else null - val upgradedBookPath = - if (upgradedBook != null) - bookRepository.findByIdOrNull(upgradedBook.id)?.path - else null var deletedUpgradedFile = false when { - upgradedBookPath != null && destFile == upgradedBookPath -> { - logger.info { "Deleting existing file: $upgradedBookPath" } + bookToUpgrade?.path != null && destFile == bookToUpgrade.path -> { + logger.info { "Deleting existing file: ${bookToUpgrade.path}" } try { - upgradedBookPath.deleteExisting() + bookToUpgrade.path.deleteExisting() deletedUpgradedFile = true } catch (e: NoSuchFileException) { - logger.warn { "Could not delete upgraded book: $upgradedBookPath" } + logger.warn { "Could not delete upgraded book: ${bookToUpgrade.path}" } } } destFile.exists() -> throw FileAlreadyExistsException("Destination file already exists: $destFile").withCode("ERR_1021") } + // delete existing sidecars + if (bookToUpgrade?.path != null) { + fileSystemScanner.scanBookSidecars(bookToUpgrade.path).forEach { sidecar -> + val sidecarPath = sidecar.url.toURI().toPath() + logger.info { "Deleting existing file: $sidecarPath" } + sidecarPath.deleteIfExists() + } + } when (copyMode) { CopyMode.MOVE -> { @@ -149,9 +152,9 @@ class BookImporter( seriesLifecycle.addBooks(series, listOf(importedBook)) - if (upgradedBook != null) { + if (bookToUpgrade != null) { // copy media and mark it as outdated - mediaRepository.findById(upgradedBook.id).let { + mediaRepository.findById(bookToUpgrade.id).let { mediaRepository.update( it.copy( bookId = importedBook.id, @@ -161,31 +164,31 @@ class BookImporter( } // copy metadata - metadataRepository.findById(upgradedBook.id).let { + metadataRepository.findById(bookToUpgrade.id).let { metadataRepository.update(it.copy(bookId = importedBook.id)) } // copy read progress - readProgressRepository.findAllByBookId(upgradedBook.id) + readProgressRepository.findAllByBookId(bookToUpgrade.id) .map { it.copy(bookId = importedBook.id) } .forEach { readProgressRepository.save(it) } // replace upgraded book by imported book in read lists - readListRepository.findAllContainingBookId(upgradedBook.id, filterOnLibraryIds = null) + readListRepository.findAllContainingBookId(bookToUpgrade.id, filterOnLibraryIds = null) .forEach { rl -> readListRepository.update( rl.copy( - bookIds = rl.bookIds.values.map { if (it == upgradedBook.id) importedBook.id else it }.toIndexedMap() + bookIds = rl.bookIds.values.map { if (it == bookToUpgrade.id) importedBook.id else it }.toIndexedMap() ) ) } // delete upgraded book file on disk if it has not been replaced earlier - if (upgradedBookPath != null && !deletedUpgradedFile && upgradedBookPath.deleteIfExists()) - logger.info { "Deleted existing file: $upgradedBookPath" } + if (!deletedUpgradedFile && bookToUpgrade.path.deleteIfExists()) + logger.info { "Deleted existing file: ${bookToUpgrade.path}" } // delete upgraded book - bookLifecycle.deleteOne(upgradedBook) + bookLifecycle.deleteOne(bookToUpgrade) } seriesLifecycle.sortBooks(series) diff --git a/komga/src/test/kotlin/org/gotson/komga/domain/service/BookImporterTest.kt b/komga/src/test/kotlin/org/gotson/komga/domain/service/BookImporterTest.kt index 44df97a9a..aee817183 100644 --- a/komga/src/test/kotlin/org/gotson/komga/domain/service/BookImporterTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/domain/service/BookImporterTest.kt @@ -39,7 +39,6 @@ import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.context.junit.jupiter.SpringExtension import java.io.FileNotFoundException import java.nio.file.FileAlreadyExistsException -import java.nio.file.Files import java.nio.file.Paths import kotlin.io.path.createDirectories import kotlin.io.path.createDirectory @@ -284,13 +283,15 @@ class BookImporterTest( } @Test - fun `given existing book when importing with upgrade then existing book is deleted`() { + fun `given existing book when importing with upgrade then existing book and sidecars are deleted`() { Jimfs.newFileSystem(Configuration.unix()).use { fs -> // given val sourceDir = fs.getPath("/source").createDirectory() val sourceFile = sourceDir.resolve("source.cbz").createFile() val destDir = fs.getPath("/library/series").createDirectories() val existingFile = destDir.resolve("4.cbz").createFile() + val existingSidecar = destDir.resolve("4.jpg").createFile() + val existingSidecar2 = destDir.resolve("4-1.jpg").createFile() val bookToUpgrade = makeBook("2", libraryId = library.id, url = existingFile.toUri().toURL()) val otherBooks = listOf( @@ -319,7 +320,11 @@ class BookImporterTest( val upgradedMedia = mediaRepository.findById(books[2].id) assertThat(upgradedMedia.status).isEqualTo(Media.Status.OUTDATED) - assertThat(Files.notExists(sourceFile)).isTrue + assertThat(sourceFile).doesNotExist() + + assertThat(existingFile).doesNotExist() + assertThat(existingSidecar).doesNotExist() + assertThat(existingSidecar2).doesNotExist() } } @@ -379,7 +384,7 @@ class BookImporterTest( assertThat(numberSortLock).isTrue } - assertThat(Files.notExists(sourceFile)).isTrue + assertThat(sourceFile).doesNotExist() } } @@ -419,7 +424,7 @@ class BookImporterTest( val upgradedMedia = mediaRepository.findById(books[1].id) assertThat(upgradedMedia.status).isEqualTo(Media.Status.OUTDATED) - assertThat(Files.exists(sourceFile)).isTrue + assertThat(sourceFile).exists() } }