feat: scanner option per library

Library can now have scanner options:
- scanForceModifiedTime replaces filesystemScannerForceDirectoryModifiedTime
- scanDeep will bypass the modified date comparison for series, and check all books

The configuration key komga.filesystem-scanner-force-directory-modified-time is deprecated
This commit is contained in:
Gauthier Roebroeck 2020-08-14 14:55:26 +08:00
parent fe22cb5ce6
commit 4da6ff9fd4
8 changed files with 39 additions and 16 deletions

View File

@ -0,0 +1,4 @@
alter table library
add column SCAN_FORCE_MODIFIED_TIME boolean NOT NULL DEFAULT 0;
alter table library
add column SCAN_DEEP boolean NOT NULL DEFAULT 0;

View File

@ -14,6 +14,8 @@ data class Library(
val importComicInfoCollection: Boolean = true,
val importEpubBook: Boolean = true,
val importEpubSeries: Boolean = true,
val scanForceModifiedTime: Boolean = false,
val scanDeep: Boolean = false,
val id: String = TsidCreator.getTsidString256(),

View File

@ -25,12 +25,11 @@ class FileSystemScanner(
val supportedExtensions = listOf("cbz", "zip", "cbr", "rar", "pdf", "epub")
fun scanRootFolder(root: Path): Map<Series, List<Book>> {
fun scanRootFolder(root: Path, forceDirectoryModifiedTime: Boolean = false): Map<Series, List<Book>> {
logger.info { "Scanning folder: $root" }
logger.info { "Supported extensions: $supportedExtensions" }
logger.info { "Excluded patterns: ${komgaProperties.librariesScanDirectoryExclusions}" }
if (komgaProperties.filesystemScannerForceDirectoryModifiedTime)
logger.info { "Force directory modified time: active" }
logger.info { "Force directory modified time: $forceDirectoryModifiedTime" }
lateinit var scannedSeries: Map<Series, List<Book>>
@ -70,7 +69,7 @@ class FileSystemScanner(
name = dir.fileName.toString(),
url = dir.toUri().toURL(),
fileLastModified =
if (komgaProperties.filesystemScannerForceDirectoryModifiedTime)
if (forceDirectoryModifiedTime)
maxOf(dir.getUpdatedTime(), books.map { it.fileLastModified }.max()!!)
else dir.getUpdatedTime()
) to books

View File

@ -27,7 +27,7 @@ class LibraryScanner(
logger.info { "Updating library: $library" }
measureTime {
val scannedSeries =
fileSystemScanner.scanRootFolder(Paths.get(library.root.toURI()))
fileSystemScanner.scanRootFolder(Paths.get(library.root.toURI()), library.scanForceModifiedTime)
.map { (series, books) ->
series.copy(libraryId = library.id) to books.map { it.copy(libraryId = library.id) }
}.toMap()
@ -59,15 +59,15 @@ class LibraryScanner(
} else {
// if series already exists, update it
logger.debug { "Scanned series already exists. Scanned: $newSeries, Existing: $existingSeries" }
if (newSeries.fileLastModified.truncatedTo(ChronoUnit.MILLIS) != existingSeries.fileLastModified.truncatedTo(ChronoUnit.MILLIS)) {
val seriesChanged = newSeries.fileLastModified.truncatedTo(ChronoUnit.MILLIS) != existingSeries.fileLastModified.truncatedTo(ChronoUnit.MILLIS)
if (seriesChanged) {
logger.info { "Series changed on disk, updating: $existingSeries" }
seriesRepository.update(existingSeries.copy(fileLastModified = newSeries.fileLastModified))
}
if (library.scanDeep || seriesChanged) {
// update list of books with existing entities if they exist
val existingBooks = bookRepository.findBySeriesId(existingSeries.id)
logger.debug { "Existing books: $existingBooks" }
// update existing books
newBooks.forEach { newBook ->
logger.debug { "Trying to match scanned book by url: $newBook" }

View File

@ -16,6 +16,7 @@ class KomgaProperties {
var librariesScanDirectoryExclusions: List<String> = emptyList()
@Deprecated("Deprecated since 0.56.0. Use per-library option instead")
var filesystemScannerForceDirectoryModifiedTime: Boolean = false
var rememberMe = RememberMe()

View File

@ -72,6 +72,8 @@ class LibraryDao(
.set(l.IMPORT_COMICINFO_COLLECTION, library.importComicInfoCollection)
.set(l.IMPORT_EPUB_BOOK, library.importEpubBook)
.set(l.IMPORT_EPUB_SERIES, library.importEpubSeries)
.set(l.SCAN_FORCE_MODIFIED_TIME, library.scanForceModifiedTime)
.set(l.SCAN_DEEP, library.scanDeep)
.execute()
}
@ -84,6 +86,8 @@ class LibraryDao(
.set(l.IMPORT_COMICINFO_COLLECTION, library.importComicInfoCollection)
.set(l.IMPORT_EPUB_BOOK, library.importEpubBook)
.set(l.IMPORT_EPUB_SERIES, library.importEpubSeries)
.set(l.SCAN_FORCE_MODIFIED_TIME, library.scanForceModifiedTime)
.set(l.SCAN_DEEP, library.scanDeep)
.set(l.LAST_MODIFIED_DATE, LocalDateTime.now(ZoneId.of("Z")))
.where(l.ID.eq(library.id))
.execute()
@ -101,6 +105,8 @@ class LibraryDao(
importComicInfoCollection = importComicinfoCollection,
importEpubBook = importEpubBook,
importEpubSeries = importEpubSeries,
scanForceModifiedTime = scanForceModifiedTime,
scanDeep = scanDeep,
id = id,
createdDate = createdDate.toCurrentTimeZone(),
lastModifiedDate = lastModifiedDate.toCurrentTimeZone()

View File

@ -77,7 +77,9 @@ class LibraryController(
importComicInfoSeries = library.importComicInfoSeries,
importComicInfoCollection = library.importComicInfoCollection,
importEpubBook = library.importEpubBook,
importEpubSeries = library.importEpubSeries
importEpubSeries = library.importEpubSeries,
scanForceModifiedTime = library.scanForceModifiedTime,
scanDeep = library.scanDeep
)
).toDto(includeRoot = principal.user.roleAdmin)
} catch (e: Exception) {
@ -107,7 +109,9 @@ class LibraryController(
importComicInfoSeries = library.importComicInfoSeries,
importComicInfoCollection = library.importComicInfoCollection,
importEpubBook = library.importEpubBook,
importEpubSeries = library.importEpubSeries
importEpubSeries = library.importEpubSeries,
scanForceModifiedTime = library.scanForceModifiedTime,
scanDeep = library.scanDeep
)
libraryLifecycle.updateLibrary(toUpdate)
} ?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
@ -157,7 +161,9 @@ data class LibraryCreationDto(
val importComicInfoSeries: Boolean = true,
val importComicInfoCollection: Boolean = true,
val importEpubBook: Boolean = true,
val importEpubSeries: Boolean = true
val importEpubSeries: Boolean = true,
val scanForceModifiedTime: Boolean = false,
val scanDeep: Boolean = false
)
data class LibraryDto(
@ -168,7 +174,9 @@ data class LibraryDto(
val importComicInfoSeries: Boolean,
val importComicInfoCollection: Boolean,
val importEpubBook: Boolean,
val importEpubSeries: Boolean
val importEpubSeries: Boolean,
val scanForceModifiedTime: Boolean,
val scanDeep: Boolean
)
data class LibraryUpdateDto(
@ -178,7 +186,9 @@ data class LibraryUpdateDto(
val importComicInfoSeries: Boolean,
val importComicInfoCollection: Boolean,
val importEpubBook: Boolean,
val importEpubSeries: Boolean
val importEpubSeries: Boolean,
val scanForceModifiedTime: Boolean,
val scanDeep: Boolean
)
fun Library.toDto(includeRoot: Boolean) = LibraryDto(
@ -189,5 +199,7 @@ fun Library.toDto(includeRoot: Boolean) = LibraryDto(
importComicInfoSeries = importComicInfoSeries,
importComicInfoCollection = importComicInfoCollection,
importEpubBook = importEpubBook,
importEpubSeries = importEpubSeries
importEpubSeries = importEpubSeries,
scanForceModifiedTime = scanForceModifiedTime,
scanDeep = scanDeep
)

View File

@ -1,5 +1,4 @@
komga:
filesystem-scanner-force-directory-modified-time: false
remember-me:
key: changeMe!
validity: 2592000 # 1 month