mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-07-31 08:14:40 +02:00
Adding inode to files and audiobooks to support renaming, setting up watcher and removing chokidar
This commit is contained in:
parent
0c1a29adbf
commit
cb40e063da
17 changed files with 558 additions and 234 deletions
|
@ -1,6 +1,7 @@
|
|||
const Path = require('path')
|
||||
const Logger = require('../Logger')
|
||||
var prober = require('./prober')
|
||||
const prober = require('./prober')
|
||||
const AudioFile = require('../AudioFile')
|
||||
|
||||
|
||||
function getDefaultAudioStream(audioStreams) {
|
||||
|
@ -76,41 +77,42 @@ function getTrackNumberFromFilename(filename) {
|
|||
return number
|
||||
}
|
||||
|
||||
async function scanParts(audiobook, parts) {
|
||||
if (!parts || !parts.length) {
|
||||
Logger.error('[AudioFileScanner] Scan Parts', audiobook.title, 'No Parts', parts)
|
||||
async function scanAudioFiles(audiobook, newAudioFiles) {
|
||||
if (!newAudioFiles || !newAudioFiles.length) {
|
||||
Logger.error('[AudioFileScanner] Scan Audio Files no files', audiobook.title)
|
||||
return
|
||||
}
|
||||
var tracks = []
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
var fullPath = Path.join(audiobook.fullPath, parts[i])
|
||||
for (let i = 0; i < newAudioFiles.length; i++) {
|
||||
var audioFile = newAudioFiles[i]
|
||||
|
||||
var scanData = await scan(fullPath)
|
||||
var scanData = await scan(audioFile.fullPath)
|
||||
if (!scanData || scanData.error) {
|
||||
Logger.error('[AudioFileScanner] Scan failed for', parts[i])
|
||||
audiobook.invalidParts.push(parts[i])
|
||||
Logger.error('[AudioFileScanner] Scan failed for', audioFile.path)
|
||||
// audiobook.invalidAudioFiles.push(parts[i])
|
||||
continue;
|
||||
}
|
||||
|
||||
var trackNumFromMeta = getTrackNumberFromMeta(scanData)
|
||||
var trackNumFromFilename = getTrackNumberFromFilename(parts[i])
|
||||
var trackNumFromFilename = getTrackNumberFromFilename(audioFile.filename)
|
||||
|
||||
var audioFileObj = {
|
||||
path: Path.join(audiobook.path, parts[i]),
|
||||
ext: Path.extname(parts[i]),
|
||||
filename: parts[i],
|
||||
fullPath: fullPath,
|
||||
ino: audioFile.ino,
|
||||
filename: audioFile.filename,
|
||||
path: audioFile.path,
|
||||
fullPath: audioFile.fullPath,
|
||||
ext: audioFile.ext,
|
||||
...scanData,
|
||||
trackNumFromMeta,
|
||||
trackNumFromFilename
|
||||
}
|
||||
audiobook.audioFiles.push(audioFileObj)
|
||||
audiobook.addAudioFile(audioFileObj)
|
||||
|
||||
var trackNumber = 1
|
||||
if (parts.length > 1) {
|
||||
if (newAudioFiles.length > 1) {
|
||||
trackNumber = isNumber(trackNumFromMeta) ? trackNumFromMeta : trackNumFromFilename
|
||||
if (trackNumber === null) {
|
||||
Logger.error('[AudioFileScanner] Invalid track number for', parts[i])
|
||||
Logger.error('[AudioFileScanner] Invalid track number for', audioFile.filename)
|
||||
audioFileObj.invalid = true
|
||||
audioFileObj.error = 'Failed to get track number'
|
||||
continue;
|
||||
|
@ -118,7 +120,7 @@ async function scanParts(audiobook, parts) {
|
|||
}
|
||||
|
||||
if (tracks.find(t => t.index === trackNumber)) {
|
||||
Logger.error('[AudioFileScanner] Duplicate track number for', parts[i])
|
||||
Logger.error('[AudioFileScanner] Duplicate track number for', audioFile.filename)
|
||||
audioFileObj.invalid = true
|
||||
audioFileObj.error = 'Duplicate track number'
|
||||
continue;
|
||||
|
@ -156,4 +158,4 @@ async function scanParts(audiobook, parts) {
|
|||
audiobook.tracks.sort((a, b) => a.index - b.index)
|
||||
}
|
||||
}
|
||||
module.exports.scanParts = scanParts
|
||||
module.exports.scanAudioFiles = scanAudioFiles
|
|
@ -1,4 +1,6 @@
|
|||
const Path = require('path')
|
||||
const fs = require('fs')
|
||||
const Logger = require('../Logger')
|
||||
|
||||
const levenshteinDistance = (str1, str2, caseSensitive = false) => {
|
||||
if (!caseSensitive) {
|
||||
|
@ -48,24 +50,13 @@ module.exports.isObject = (val) => {
|
|||
return val !== null && typeof val === 'object'
|
||||
}
|
||||
|
||||
function normalizePath(path) {
|
||||
const replace = [
|
||||
[/\\/g, '/'],
|
||||
[/(\w):/, '/$1'],
|
||||
[/(\w+)\/\.\.\/?/g, ''],
|
||||
[/^\.\//, ''],
|
||||
[/\/\.\//, '/'],
|
||||
[/\/\.$/, ''],
|
||||
[/\/$/, ''],
|
||||
]
|
||||
replace.forEach(array => {
|
||||
while (array[0].test(path)) {
|
||||
path = path.replace(array[0], array[1])
|
||||
}
|
||||
})
|
||||
return path
|
||||
module.exports.comparePaths = (path1, path2) => {
|
||||
return path1 === path2 || Path.normalize(path1) === Path.normalize(path2)
|
||||
}
|
||||
|
||||
module.exports.comparePaths = (path1, path2) => {
|
||||
return (path1 === path2) || (normalizePath(path1) === normalizePath(path2))
|
||||
module.exports.getIno = (path) => {
|
||||
return fs.promises.stat(path, { bigint: true }).then((data => String(data.ino))).catch((err) => {
|
||||
Logger.error('[Utils] Failed to get ino for path', path, error)
|
||||
return null
|
||||
})
|
||||
}
|
|
@ -3,7 +3,7 @@ const dir = require('node-dir')
|
|||
const Logger = require('../Logger')
|
||||
const { cleanString } = require('./index')
|
||||
|
||||
const AUDIOBOOK_PARTS_FORMATS = ['m4b', 'mp3']
|
||||
const AUDIO_FORMATS = ['m4b', 'mp3']
|
||||
const INFO_FORMATS = ['nfo']
|
||||
const IMAGE_FORMATS = ['png', 'jpg', 'jpeg', 'webp']
|
||||
const EBOOK_FORMATS = ['epub', 'pdf']
|
||||
|
@ -23,7 +23,7 @@ function getPaths(path) {
|
|||
function getFileType(ext) {
|
||||
var ext_cleaned = ext.toLowerCase()
|
||||
if (ext_cleaned.startsWith('.')) ext_cleaned = ext_cleaned.slice(1)
|
||||
if (AUDIOBOOK_PARTS_FORMATS.includes(ext_cleaned)) return 'abpart'
|
||||
if (AUDIO_FORMATS.includes(ext_cleaned)) return 'audio'
|
||||
if (INFO_FORMATS.includes(ext_cleaned)) return 'info'
|
||||
if (IMAGE_FORMATS.includes(ext_cleaned)) return 'image'
|
||||
if (EBOOK_FORMATS.includes(ext_cleaned)) return 'ebook'
|
||||
|
@ -35,7 +35,7 @@ async function getAllAudiobookFiles(abRootPath) {
|
|||
var audiobooks = {}
|
||||
|
||||
paths.files.forEach((filepath) => {
|
||||
var relpath = filepath.replace(abRootPath, '').slice(1)
|
||||
var relpath = Path.normalize(filepath).replace(abRootPath, '').slice(1)
|
||||
var pathformat = Path.parse(relpath)
|
||||
var path = pathformat.dir
|
||||
|
||||
|
@ -71,22 +71,20 @@ async function getAllAudiobookFiles(abRootPath) {
|
|||
publishYear: publishYear,
|
||||
path: path,
|
||||
fullPath: Path.join(abRootPath, path),
|
||||
parts: [],
|
||||
audioFiles: [],
|
||||
otherFiles: []
|
||||
}
|
||||
}
|
||||
|
||||
var filetype = getFileType(pathformat.ext)
|
||||
if (filetype === 'abpart') {
|
||||
audiobooks[path].parts.push(pathformat.base)
|
||||
var fileObj = {
|
||||
filetype: getFileType(pathformat.ext),
|
||||
filename: pathformat.base,
|
||||
path: relpath,
|
||||
fullPath: filepath,
|
||||
ext: pathformat.ext
|
||||
}
|
||||
if (fileObj.filetype === 'audio') {
|
||||
audiobooks[path].audioFiles.push(fileObj)
|
||||
} else {
|
||||
var fileObj = {
|
||||
filetype: filetype,
|
||||
filename: pathformat.base,
|
||||
path: relpath,
|
||||
fullPath: filepath,
|
||||
ext: pathformat.ext
|
||||
}
|
||||
audiobooks[path].otherFiles.push(fileObj)
|
||||
}
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue