Adding inode to files and audiobooks to support renaming, setting up watcher and removing chokidar

This commit is contained in:
advplyr 2021-08-25 17:36:54 -05:00
parent 0c1a29adbf
commit cb40e063da
17 changed files with 558 additions and 234 deletions

View file

@ -1,15 +1,20 @@
const Path = require('path')
const { bytesPretty, elapsedPretty } = require('./utils/fileUtils')
const { comparePaths } = require('./utils/index')
const { comparePaths, getIno } = require('./utils/index')
const Logger = require('./Logger')
const Book = require('./Book')
const AudioTrack = require('./AudioTrack')
const AudioFile = require('./AudioFile')
const AudiobookFile = require('./AudiobookFile')
class Audiobook {
constructor(audiobook = null) {
this.id = null
this.ino = null // Inode
this.path = null
this.fullPath = null
this.addedAt = null
this.lastUpdate = null
@ -30,19 +35,18 @@ class Audiobook {
construct(audiobook) {
this.id = audiobook.id
this.ino = audiobook.ino || null
this.path = audiobook.path
this.fullPath = audiobook.fullPath
this.addedAt = audiobook.addedAt
this.lastUpdate = audiobook.lastUpdate || this.addedAt
this.tracks = audiobook.tracks.map(track => {
return new AudioTrack(track)
})
this.tracks = audiobook.tracks.map(track => new AudioTrack(track))
this.missingParts = audiobook.missingParts
this.invalidParts = audiobook.invalidParts
this.audioFiles = audiobook.audioFiles
this.otherFiles = audiobook.otherFiles
this.audioFiles = audiobook.audioFiles.map(file => new AudioFile(file))
this.otherFiles = audiobook.otherFiles.map(file => new AudiobookFile(file))
this.tags = audiobook.tags
if (audiobook.book) {
@ -102,6 +106,7 @@ class Audiobook {
toJSON() {
return {
id: this.id,
ino: this.ino,
title: this.title,
author: this.author,
cover: this.cover,
@ -114,14 +119,15 @@ class Audiobook {
tags: this.tags,
book: this.bookToJSON(),
tracks: this.tracksToJSON(),
audioFiles: this.audioFiles,
otherFiles: this.otherFiles
audioFiles: (this.audioFiles || []).map(audioFile => audioFile.toJSON()),
otherFiles: (this.otherFiles || []).map(otherFile => otherFile.toJSON())
}
}
toJSONMinified() {
return {
id: this.id,
ino: this.ino,
book: this.bookToJSON(),
tags: this.tags,
path: this.path,
@ -140,9 +146,6 @@ class Audiobook {
toJSONExpanded() {
return {
id: this.id,
// title: this.title,
// author: this.author,
// cover: this.cover,
path: this.path,
fullPath: this.fullPath,
addedAt: this.addedAt,
@ -153,8 +156,8 @@ class Audiobook {
sizePretty: this.sizePretty,
missingParts: this.missingParts,
invalidParts: this.invalidParts,
audioFiles: this.audioFiles,
otherFiles: this.otherFiles,
audioFiles: (this.audioFiles || []).map(audioFile => audioFile.toJSON()),
otherFiles: (this.otherFiles || []).map(otherFile => otherFile.toJSON()),
tags: this.tags,
book: this.bookToJSON(),
tracks: this.tracksToJSON()
@ -175,14 +178,46 @@ class Audiobook {
return false
}
// Update was made to add ino values, ensure they are set
async checkUpdateInos() {
var hasUpdates = false
if (!this.ino) {
this.ino = await getIno(this.fullPath)
hasUpdates = true
}
for (let i = 0; i < this.audioFiles.length; i++) {
var af = this.audioFiles[i]
if (!af.ino || af.ino === this.ino) {
af.ino = await getIno(af.fullPath)
if (!af.ino) {
Logger.error('[Audiobook] checkUpdateInos: Failed to set ino for audio file', af.fullPath)
} else {
var track = this.tracks.find(t => comparePaths(t.path, af.path))
if (track) {
track.ino = af.ino
}
}
hasUpdates = true
}
}
return hasUpdates
}
setData(data) {
this.id = (Math.trunc(Math.random() * 1000) + Date.now()).toString(36)
this.ino = data.ino || null
this.path = data.path
this.fullPath = data.fullPath
this.addedAt = Date.now()
this.lastUpdate = this.addedAt
this.otherFiles = data.otherFiles || []
if (data.otherFiles) {
data.otherFiles.forEach((file) => {
this.addOtherFile(file)
})
}
this.setBook(data)
}
@ -198,6 +233,20 @@ class Audiobook {
return track
}
addAudioFile(audioFileData) {
var audioFile = new AudioFile()
audioFile.setData(audioFileData)
this.audioFiles.push(audioFile)
return audioFile
}
addOtherFile(fileData) {
var file = new AudiobookFile()
file.setData(fileData)
this.otherFiles.push(file)
return file
}
update(payload) {
var hasUpdates = false
@ -241,17 +290,12 @@ class Audiobook {
}
removeAudioFile(audioFile) {
this.tracks = this.tracks.filter(t => t.path !== audioFile.path)
this.audioFiles = this.audioFiles.filter(f => f.path !== audioFile.path)
}
audioPartExists(part) {
var path = Path.join(this.path, part)
return this.audioFiles.find(file => file.path === path)
this.tracks = this.tracks.filter(t => t.ino !== audioFile.ino)
this.audioFiles = this.audioFiles.filter(f => f.ino !== audioFile.ino)
}
checkUpdateMissingParts() {
var currMissingParts = this.missingParts.join(',')
var currMissingParts = (this.missingParts || []).join(',') || ''
var current_index = 1
var missingParts = []
@ -268,7 +312,8 @@ class Audiobook {
this.missingParts = missingParts
var wasUpdated = this.missingParts.join(',') !== currMissingParts
var newMissingParts = (this.missingParts || []).join(',') || ''
var wasUpdated = newMissingParts !== currMissingParts
if (wasUpdated && this.missingParts.length) {
Logger.info(`[Audiobook] "${this.title}" has ${missingParts.length} missing parts`)
}
@ -282,16 +327,18 @@ class Audiobook {
var newOtherFilePaths = newOtherFiles.map(f => f.path)
this.otherFiles = this.otherFiles.filter(f => newOtherFilePaths.includes(f.path))
newOtherFiles.forEach((file) => {
var existingOtherFile = this.otherFiles.find(f => f.path === file.path)
if (!existingOtherFile) {
Logger.info(`[Audiobook] New other file found on sync ${file.filename}/${file.filetype} | "${this.title}"`)
this.otherFiles.push(file)
Logger.debug(`[Audiobook] New other file found on sync ${file.filename}/${file.filetype} | "${this.title}"`)
this.addOtherFile(file)
}
})
var hasUpdates = currOtherFileNum !== this.otherFiles.length
// Check if cover was a local image and that it still exists
var imageFiles = this.otherFiles.filter(f => f.filetype === 'image')
if (this.book.cover && this.book.cover.substr(1).startsWith('local')) {
var coverStillExists = imageFiles.find(f => comparePaths(f.path, this.book.cover.substr('/local/'.length)))
@ -302,6 +349,7 @@ class Audiobook {
}
}
// If no cover set and image file exists then use it
if (!this.book.cover && imageFiles.length) {
this.book.cover = Path.join('/local', imageFiles[0].path)
Logger.info(`[Audiobook] Local cover was set | "${this.title}"`)
@ -310,8 +358,38 @@ class Audiobook {
return hasUpdates
}
syncAudioFile(audioFile, fileScanData) {
var hasUpdates = audioFile.syncFile(fileScanData)
if (hasUpdates) {
var track = this.tracks.find(t => t.ino === audioFile.ino)
if (track) {
track.syncFile(fileScanData)
}
}
return hasUpdates
}
syncPaths(audiobookData) {
var hasUpdates = false
var keysToSync = ['path', 'fullPath']
keysToSync.forEach((key) => {
if (audiobookData[key] !== undefined && audiobookData[key] !== this[key]) {
hasUpdates = true
this[key] = audiobookData[key]
}
})
if (hasUpdates) {
this.book.syncPathsUpdated(audiobookData)
}
return hasUpdates
}
isSearchMatch(search) {
return this.book.isSearchMatch(search.toLowerCase().trim())
}
getAudioFileByIno(ino) {
return this.audioFiles.find(af => af.ino === ino)
}
}
module.exports = Audiobook