From b68c181631c79ee00184334591080f69386571b4 Mon Sep 17 00:00:00 2001 From: Igor Kaldowski Date: Sat, 4 Dec 2021 23:57:47 +0000 Subject: [PATCH 1/4] Add: Force re-scan library --- client/components/modals/libraries/LibraryItem.vue | 4 ++++ server/Server.js | 4 ++-- server/scanner/Scanner.js | 6 +++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/client/components/modals/libraries/LibraryItem.vue b/client/components/modals/libraries/LibraryItem.vue index a6fa5118..60839c3b 100644 --- a/client/components/modals/libraries/LibraryItem.vue +++ b/client/components/modals/libraries/LibraryItem.vue @@ -10,6 +10,7 @@

{{ library.name }}

Scan + Force Re-Scan edit delete
@@ -67,6 +68,9 @@ export default { scan() { this.$root.socket.emit('scan', this.library.id) }, + forceScan() { + this.$root.socket.emit('scan', this.library.id, {forceRescan: true}) + }, deleteClick() { if (this.isMain) return if (confirm(`Are you sure you want to permanently delete library "${this.library.name}"?`)) { diff --git a/server/Server.js b/server/Server.js index 5fd1638f..09dd4b63 100644 --- a/server/Server.js +++ b/server/Server.js @@ -316,9 +316,9 @@ class Server { await this.scanner2.scanFilesChanged(fileUpdates) } - async scan(libraryId) { + async scan(libraryId, options = {}) { Logger.info('[Server] Starting Scan') - await this.scanner2.scan(libraryId) + await this.scanner2.scan(libraryId, options) // await this.scanner.scan(libraryId) Logger.info('[Server] Scan complete') } diff --git a/server/scanner/Scanner.js b/server/scanner/Scanner.js index 40df4eb2..d5bd38d0 100644 --- a/server/scanner/Scanner.js +++ b/server/scanner/Scanner.js @@ -221,7 +221,7 @@ class Scanner { } } else { var checkRes = audiobook.checkScanData(dataFound, version) - if (checkRes.newAudioFileData.length || checkRes.newOtherFileData.length) { // Audiobook has new files + if (checkRes.newAudioFileData.length || checkRes.newOtherFileData.length || libraryScan.scanOptions.forceRescan) { // Audiobook has new files checkRes.audiobook = audiobook checkRes.bookScanData = dataFound audiobookDataToRescan.push(checkRes) @@ -325,13 +325,13 @@ class Scanner { libraryScan.addLog(LogLevel.DEBUG, `Library "${libraryScan.libraryName}" Re-scanning "${audiobook.path}"`) // Sync other files first to use local images as cover before extracting audio file cover - if (newOtherFileData.length) { + if (newOtherFileData.length || libraryScan.scanOptions.forceRescan) { // TODO: Cleanup other file sync var allOtherFiles = newOtherFileData.concat(audiobook._otherFiles) await audiobook.syncOtherFiles(allOtherFiles, this.MetadataPath, libraryScan.preferOpfMetadata) } - if (newAudioFileData.length) { + if (newAudioFileData.length || libraryScan.scanOptions.forceRescan) { await AudioFileScanner.scanAudioFiles(newAudioFileData, bookScanData, audiobook, libraryScan.preferAudioMetadata, libraryScan) // Extract embedded cover art if cover is not already in directory From 040548c6db413efdb09b5da4afe7693d99bd0dd3 Mon Sep 17 00:00:00 2001 From: advplyr Date: Sun, 5 Dec 2021 09:52:23 -0600 Subject: [PATCH 2/4] Fix:Reorder libraries route and draggable table,Fix:Update filter daata --- .../components/modals/libraries/LibraryItem.vue | 5 +---- client/components/tables/LibrariesTable.vue | 16 +++++++++------- client/store/libraries.js | 2 +- server/ApiController.js | 3 ++- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/client/components/modals/libraries/LibraryItem.vue b/client/components/modals/libraries/LibraryItem.vue index 60839c3b..37c1d692 100644 --- a/client/components/modals/libraries/LibraryItem.vue +++ b/client/components/modals/libraries/LibraryItem.vue @@ -59,9 +59,6 @@ export default { } }, methods: { - itemClicked() { - // this.$emit('click', this.library) - }, editClick() { this.$emit('edit', this.library) }, @@ -69,7 +66,7 @@ export default { this.$root.socket.emit('scan', this.library.id) }, forceScan() { - this.$root.socket.emit('scan', this.library.id, {forceRescan: true}) + this.$root.socket.emit('scan', this.library.id, { forceRescan: true }) }, deleteClick() { if (this.isMain) return diff --git a/client/components/tables/LibrariesTable.vue b/client/components/tables/LibrariesTable.vue index f9911398..9df5e66c 100644 --- a/client/components/tables/LibrariesTable.vue +++ b/client/components/tables/LibrariesTable.vue @@ -6,12 +6,12 @@ add
- - + - @@ -48,6 +48,9 @@ export default { }, libraries() { return this.$store.getters['libraries/getSortedLibraries']() + }, + libraryScans() { + return this.$store.state.scanners.libraryScans } }, methods: { @@ -55,10 +58,9 @@ export default { this.drag = true clearTimeout(this.orderTimeout) }, - endDrag() { + endDrag(e) { this.drag = false this.checkOrder() - console.log('DRAG END') }, checkOrder() { clearTimeout(this.orderTimeout) @@ -78,7 +80,7 @@ export default { }) var newOrder = libraryOrderData.map((lib) => lib.id).join(',') if (currOrder !== newOrder) { - this.$axios.$patch('/api/libraries/order', libraryOrderData).then((libraries) => { + this.$axios.$post('/api/libraries/order', libraryOrderData).then((libraries) => { if (libraries && libraries.length) { this.$toast.success('Library order saved', { timeout: 1500 }) this.$store.commit('libraries/set', libraries) diff --git a/client/store/libraries.js b/client/store/libraries.js index 48793985..c4a51a2e 100644 --- a/client/store/libraries.js +++ b/client/store/libraries.js @@ -210,7 +210,7 @@ export const mutations = { } if (audiobook.book.genres && audiobook.book.genres.length) { audiobook.book.genres.forEach((genre) => { - if (tag && !state.filterData.genres.includes(genre)) state.filterData.genres.push(genre) + if (genre && !state.filterData.genres.includes(genre)) state.filterData.genres.push(genre) }) } } diff --git a/server/ApiController.js b/server/ApiController.js index c23a787e..1ce4f188 100644 --- a/server/ApiController.js +++ b/server/ApiController.js @@ -63,7 +63,8 @@ class ApiController { this.router.get('/libraries/:id/search', LibraryController.middleware.bind(this), LibraryController.search.bind(this)) this.router.get('/libraries/:id/stats', LibraryController.middleware.bind(this), LibraryController.stats.bind(this)) this.router.get('/libraries/:id/authors', LibraryController.middleware.bind(this), LibraryController.getAuthors.bind(this)) - this.router.patch('/libraries/order', LibraryController.reorder.bind(this)) + this.router.post('/libraries/order', LibraryController.reorder.bind(this)) + // TEMP: Support old syntax for mobile app this.router.get('/library/:id/audiobooks', LibraryController.middleware.bind(this), LibraryController.getBooksForLibrary.bind(this)) From 975984e8d1b05d4c084e385b50159e0b1016bb9e Mon Sep 17 00:00:00 2001 From: advplyr Date: Sun, 5 Dec 2021 11:29:42 -0600 Subject: [PATCH 3/4] Add:forceRescan rescans existing audio files,Fix:False positives for if an audio file was updated --- server/objects/AudioFile.js | 14 +++++----- server/objects/Audiobook.js | 15 ++++++++--- server/scanner/AudioFileScanner.js | 2 -- server/scanner/AudioProbeData.js | 2 +- server/scanner/Scanner.js | 41 ++++++++++++++++++++++-------- 5 files changed, 50 insertions(+), 24 deletions(-) diff --git a/server/objects/AudioFile.js b/server/objects/AudioFile.js index 6c2c0333..99edac14 100644 --- a/server/objects/AudioFile.js +++ b/server/objects/AudioFile.js @@ -96,9 +96,9 @@ class AudioFile { this.exclude = !!data.exclude this.error = data.error || null - this.trackNumFromMeta = data.trackNumFromMeta || null - this.trackNumFromFilename = data.trackNumFromFilename || null - this.cdNumFromFilename = data.cdNumFromFilename || null + this.trackNumFromMeta = data.trackNumFromMeta + this.trackNumFromFilename = data.trackNumFromFilename + this.cdNumFromFilename = data.cdNumFromFilename this.format = data.format this.duration = data.duration @@ -130,9 +130,9 @@ class AudioFile { this.fullPath = data.fullPath this.addedAt = Date.now() - this.trackNumFromMeta = data.trackNumFromMeta || null - this.trackNumFromFilename = data.trackNumFromFilename || null - this.cdNumFromFilename = data.cdNumFromFilename || null + this.trackNumFromMeta = data.trackNumFromMeta + this.trackNumFromFilename = data.trackNumFromFilename + this.cdNumFromFilename = data.cdNumFromFilename this.manuallyVerified = !!data.manuallyVerified this.invalid = !!data.invalid @@ -302,9 +302,9 @@ class AudioFile { hasUpdated = true } } else if (this[key] !== newjson[key]) { + // console.log(this.filename, 'key', key, 'updated', this[key], newjson[key]) this[key] = newjson[key] hasUpdated = true - // console.log('key', key, 'updated', this[key], newjson[key]) } } return hasUpdated diff --git a/server/objects/Audiobook.js b/server/objects/Audiobook.js index 5fbfa8ab..419efc79 100644 --- a/server/objects/Audiobook.js +++ b/server/objects/Audiobook.js @@ -542,10 +542,9 @@ class Audiobook { var alreadyHasDescTxt = otherFilenamesAlreadyInBook.includes('desc.txt') var alreadyHasReaderTxt = otherFilenamesAlreadyInBook.includes('reader.txt') + // Filter out other files no longer in directory var newOtherFilePaths = newOtherFiles.map(f => f.path) this.otherFiles = this.otherFiles.filter(f => newOtherFilePaths.includes(f.path)) - - // Some files are not there anymore and filtered out if (currOtherFileNum !== this.otherFiles.length) { Logger.debug(`[Audiobook] ${currOtherFileNum - this.otherFiles.length} other files were removed for "${this.title}"`) hasUpdates = true @@ -937,6 +936,8 @@ class Audiobook { var newAudioFileData = [] var newOtherFileData = [] + var existingAudioFileData = [] + var existingOtherFileData = [] dataFound.audioFiles.forEach((af) => { var audioFileFoundCheck = this.checkFileFound(af, true) @@ -944,6 +945,9 @@ class Audiobook { newAudioFileData.push(af) } else if (audioFileFoundCheck) { hasUpdated = true + existingAudioFileData.push(af) + } else { + existingAudioFileData.push(af) } }) @@ -953,6 +957,9 @@ class Audiobook { newOtherFileData.push(otherFileData) } else if (fileFoundCheck) { hasUpdated = true + existingOtherFileData.push(otherFileData) + } else { + existingOtherFileData.push(otherFileData) } }) @@ -1010,7 +1017,9 @@ class Audiobook { newAudioFileData, newOtherFileData, audioFilesRemoved, - otherFilesRemoved + otherFilesRemoved, + existingAudioFileData, // Existing file data may get re-scanned if forceRescan is set + existingOtherFileData } } } diff --git a/server/scanner/AudioFileScanner.js b/server/scanner/AudioFileScanner.js index 718dcb65..c217f661 100644 --- a/server/scanner/AudioFileScanner.js +++ b/server/scanner/AudioFileScanner.js @@ -139,12 +139,10 @@ class AudioFileScanner { } if (existingAF) { if (audiobook.updateAudioFile(newAF)) { - // console.log('update dauido file') hasUpdated = true } } else { audiobook.addAudioFile(newAF) - // console.log('added auido file') hasUpdated = true } } diff --git a/server/scanner/AudioProbeData.js b/server/scanner/AudioProbeData.js index c6513ace..82efa6fa 100644 --- a/server/scanner/AudioProbeData.js +++ b/server/scanner/AudioProbeData.js @@ -35,7 +35,7 @@ class AudioProbeData { setData(data) { var audioStream = this.getDefaultAudioStream(data.audio_streams) - this.embeddedCoverArt = data.video_stream ? this.getEmbeddedCoverArt(data.video_stream) : false + this.embeddedCoverArt = data.video_stream ? this.getEmbeddedCoverArt(data.video_stream) : null this.format = data.format this.duration = data.duration this.size = data.size diff --git a/server/scanner/Scanner.js b/server/scanner/Scanner.js index d5bd38d0..63eb6c27 100644 --- a/server/scanner/Scanner.js +++ b/server/scanner/Scanner.js @@ -305,9 +305,11 @@ class Scanner { return this.rescanAudiobook(abd, libraryScan) })) audiobooksUpdated = audiobooksUpdated.filter(ab => ab) // Filter out nulls - libraryScan.resultsUpdated += audiobooksUpdated.length - await this.db.updateEntities('audiobook', audiobooksUpdated) - this.emitter('audiobooks_updated', audiobooksUpdated.map(ab => ab.toJSONExpanded())) + if (audiobooksUpdated.length) { + libraryScan.resultsUpdated += audiobooksUpdated.length + await this.db.updateEntities('audiobook', audiobooksUpdated) + this.emitter('audiobooks_updated', audiobooksUpdated.map(ab => ab.toJSONExpanded())) + } } async scanNewAudiobookDataChunk(newAudiobookDataToScan, libraryScan) { @@ -321,24 +323,38 @@ class Scanner { } async rescanAudiobook(audiobookCheckData, libraryScan) { - const { newAudioFileData, newOtherFileData, audiobook, bookScanData } = audiobookCheckData + const { newAudioFileData, newOtherFileData, audiobook, bookScanData, updated, existingAudioFileData, existingOtherFileData } = audiobookCheckData libraryScan.addLog(LogLevel.DEBUG, `Library "${libraryScan.libraryName}" Re-scanning "${audiobook.path}"`) + var hasUpdated = updated // Sync other files first to use local images as cover before extracting audio file cover if (newOtherFileData.length || libraryScan.scanOptions.forceRescan) { // TODO: Cleanup other file sync - var allOtherFiles = newOtherFileData.concat(audiobook._otherFiles) - await audiobook.syncOtherFiles(allOtherFiles, this.MetadataPath, libraryScan.preferOpfMetadata) + var allOtherFiles = newOtherFileData.concat(existingOtherFileData) + if (await audiobook.syncOtherFiles(allOtherFiles, this.MetadataPath, libraryScan.preferOpfMetadata)) { + hasUpdated = true + } } + // forceRescan all existing audio files - will probe and update ID3 tag metadata + if (libraryScan.scanOptions.forceRescan && existingAudioFileData.length) { + if (await AudioFileScanner.scanAudioFiles(existingAudioFileData, bookScanData, audiobook, libraryScan.preferAudioMetadata, libraryScan)) { + hasUpdated = true + } + } + // Scan new audio files + if (newAudioFileData.length) { + if (await AudioFileScanner.scanAudioFiles(newAudioFileData, bookScanData, audiobook, libraryScan.preferAudioMetadata, libraryScan)) { + hasUpdated = true + } + } + // If an audio file has embedded cover art and no cover is set yet, extract & use it if (newAudioFileData.length || libraryScan.scanOptions.forceRescan) { - await AudioFileScanner.scanAudioFiles(newAudioFileData, bookScanData, audiobook, libraryScan.preferAudioMetadata, libraryScan) - - // Extract embedded cover art if cover is not already in directory if (audiobook.hasEmbeddedCoverArt && !audiobook.cover) { var outputCoverDirs = this.getCoverDirectory(audiobook) var relativeDir = await audiobook.saveEmbeddedCoverArt(outputCoverDirs.fullPath, outputCoverDirs.relPath) if (relativeDir) { + hasUpdated = true libraryScan.addLog(LogLevel.DEBUG, `Saved embedded cover art "${relativeDir}"`) } } @@ -346,17 +362,20 @@ class Scanner { if (!audiobook.audioFilesToInclude.length && !audiobook.ebooks.length) { // Audiobook is invalid audiobook.setInvalid() + hasUpdated = true } else if (audiobook.isInvalid) { audiobook.isInvalid = false + hasUpdated = true } - // Scan for cover if enabled and has no cover + // Scan for cover if enabled and has no cover (and author or title has changed OR has been 7 days since last lookup) if (audiobook && libraryScan.findCovers && !audiobook.cover && audiobook.book.shouldSearchForCover) { var updatedCover = await this.searchForCover(audiobook, libraryScan) audiobook.book.updateLastCoverSearch(updatedCover) + hasUpdated = true } - return audiobook + return hasUpdated ? audiobook : null } async scanNewAudiobook(audiobookData, preferAudioMetadata, preferOpfMetadata, findCovers, libraryScan = null) { From 609c1d0cd2322d690cc179d51ddbbc93e4430143 Mon Sep 17 00:00:00 2001 From: advplyr Date: Sun, 5 Dec 2021 19:21:06 -0600 Subject: [PATCH 4/4] Add:Force re-scan note, Fix:Z-index issue with toolbar menus --- client/components/app/Appbar.vue | 2 +- client/components/app/BookShelfToolbar.vue | 2 +- client/components/app/SideRail.vue | 2 +- client/components/controls/OrderSelect.vue | 2 +- client/components/tables/LibrariesTable.vue | 2 ++ 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/client/components/app/Appbar.vue b/client/components/app/Appbar.vue index 9ad3c500..711ea2ae 100644 --- a/client/components/app/Appbar.vue +++ b/client/components/app/Appbar.vue @@ -1,6 +1,6 @@