Scanner update check for mismatched inode and update

This commit is contained in:
advplyr 2021-10-01 14:52:10 -05:00
parent d753683090
commit 4e45ff83c6
4 changed files with 64 additions and 10 deletions

View File

@ -1,6 +1,6 @@
{
"name": "audiobookshelf-client",
"version": "1.3.1",
"version": "1.3.2",
"description": "Audiobook manager and player",
"main": "index.js",
"scripts": {

View File

@ -1,6 +1,6 @@
{
"name": "audiobookshelf",
"version": "1.3.1",
"version": "1.3.2",
"description": "Self-hosted audiobook server for managing and playing audiobooks",
"main": "index.js",
"scripts": {

View File

@ -60,10 +60,59 @@ class Scanner {
return audiobookDataAudioFiles.filter(abdFile => !!abdFile.ino)
}
// Only updates audio files with matching paths
syncAudiobookInodeValues(audiobook, { audioFiles, otherFiles }) {
var filesUpdated = 0
// Sync audio files & audio tracks with updated inodes
audiobook._audioFiles.forEach((audioFile) => {
var matchingAudioFile = audioFiles.find(af => af.ino !== audioFile.ino && af.path === audioFile.path)
if (matchingAudioFile) {
// Audio Track should always have the same ino as the equivalent audio file (not all audio files have a track)
var audioTrack = audiobook.tracks.find(t => t.ino === audioFile.ino)
if (audioTrack) {
Logger.debug(`[Scanner] Found audio file & track with mismatched inode "${audioFile.filename}" - updating it`)
audioTrack.ino = matchingAudioFile.ino
filesUpdated++
} else {
Logger.debug(`[Scanner] Found audio file with mismatched inode "${audioFile.filename}" - updating it`)
}
audioFile.ino = matchingAudioFile.ino
filesUpdated++
}
})
// Sync other files with updated inodes
audiobook._otherFiles.forEach((otherFile) => {
var matchingOtherFile = otherFiles.find(of => of.ino !== otherFile.ino && of.path === otherFile.path)
if (matchingOtherFile) {
Logger.debug(`[Scanner] Found other file with mismatched inode "${otherFile.filename}" - updating it`)
otherFile.ino = matchingOtherFile.ino
filesUpdated++
}
})
return filesUpdated
}
async scanAudiobookData(audiobookData, forceAudioFileScan = false) {
var existingAudiobook = this.audiobooks.find(a => a.ino === audiobookData.ino)
// Logger.debug(`[Scanner] Scanning "${audiobookData.title}" (${audiobookData.ino}) - ${!!existingAudiobook ? 'Exists' : 'New'}`)
// inode value may change when using shared drives, update inode if matching path is found
// Note: inode will not change on rename
var hasUpdatedIno = false
if (!existingAudiobook) {
// check an audiobook exists with matching path, then update inodes
existingAudiobook = this.audiobooks.find(a => a.path === audiobookData.path)
if (existingAudiobook) {
hasUpdatedIno = true
var filesUpdated = this.syncAudiobookInodeValues(existingAudiobook, audiobookData)
Logger.info(`[Scanner] Updating inode value for "${existingAudiobook.title}" - ${filesUpdated} files updated`)
}
}
// Logger.debug(`[Scanner] Scanning "${audiobookData.title}" (${audiobookData.ino}) - ${!!existingAudiobook ? 'Exists' : 'New'}`)
if (existingAudiobook) {
// TEMP: Check if is older audiobook and needs force rescan
@ -158,7 +207,7 @@ class Scanner {
return ScanResult.REMOVED
}
var hasUpdates = removedAudioFiles.length || removedAudioTracks.length || newAudioFiles.length || hasUpdatedAudioFiles
var hasUpdates = hasUpdatedIno || removedAudioFiles.length || removedAudioTracks.length || newAudioFiles.length || hasUpdatedAudioFiles
// Check that audio tracks are in sequential order with no gaps
if (existingAudiobook.checkUpdateMissingParts()) {
@ -177,12 +226,14 @@ class Scanner {
hasUpdates = true
}
// If audiobook was missing before, it is now found
if (existingAudiobook.isMissing) {
existingAudiobook.isMissing = false
hasUpdates = true
Logger.info(`[Scanner] "${existingAudiobook.title}" was missing but now it is found`)
}
// Save changes and notify users
if (hasUpdates) {
existingAudiobook.setChapters()

View File

@ -105,23 +105,26 @@ class Audiobook {
}
get invalidParts() {
return (this.audioFiles || []).filter(af => af.invalid).map(af => ({ filename: af.filename, error: af.error || 'Unknown Error' }))
return this._audioFiles.filter(af => af.invalid).map(af => ({ filename: af.filename, error: af.error || 'Unknown Error' }))
}
get _audioFiles() { return this.audioFiles || [] }
get _otherFiles() { return this.otherFiles || [] }
get ebooks() {
return this.otherFiles.filter(file => file.filetype === 'ebook')
}
get hasMissingIno() {
return !this.ino || (this.audioFiles || []).find(abf => !abf.ino) || (this.otherFiles || []).find(f => !f.ino) || (this.tracks || []).find(t => !t.ino)
return !this.ino || this._audioFiles.find(abf => !abf.ino) || this._otherFiles.find(f => !f.ino) || (this.tracks || []).find(t => !t.ino)
}
get hasEmbeddedCoverArt() {
return !!(this.audioFiles || []).find(af => af.embeddedCoverArt)
return !!this._audioFiles.find(af => af.embeddedCoverArt)
}
get hasDescriptionTextFile() {
return !!(this.otherFiles || []).find(of => of.filename === 'desc.txt')
return !!this._otherFiles.find(of => of.filename === 'desc.txt')
}
bookToJSON() {
@ -148,8 +151,8 @@ class Audiobook {
tags: this.tags,
book: this.bookToJSON(),
tracks: this.tracksToJSON(),
audioFiles: (this.audioFiles || []).map(audioFile => audioFile.toJSON()),
otherFiles: (this.otherFiles || []).map(otherFile => otherFile.toJSON()),
audioFiles: this._audioFiles.map(audioFile => audioFile.toJSON()),
otherFiles: this._otherFiles.map(otherFile => otherFile.toJSON()),
chapters: this.chapters || [],
isMissing: !!this.isMissing
}