Skip to content

Commit

Permalink
Update watcher files changed function to use the same grouping functi…
Browse files Browse the repository at this point in the history
…on as other scans
  • Loading branch information
advplyr committed Dec 4, 2024
1 parent 5fa0897 commit 344890f
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 105 deletions.
4 changes: 2 additions & 2 deletions server/scanner/LibraryScanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -424,8 +424,8 @@ class LibraryScanner {
}
const folder = library.libraryFolders[0]

const relFilePaths = folderGroups[folderId].fileUpdates.map((fileUpdate) => fileUpdate.relPath)
const fileUpdateGroup = scanUtils.groupFilesIntoLibraryItemPaths(library.mediaType, relFilePaths)
const filePathItems = folderGroups[folderId].fileUpdates.map((fileUpdate) => fileUtils.getFilePathItemFromFileUpdate(fileUpdate))
const fileUpdateGroup = scanUtils.groupFileItemsIntoLibraryItemDirs(library.mediaType, filePathItems, !!library.settings?.audiobooksOnly)

if (!Object.keys(fileUpdateGroup).length) {
Logger.info(`[LibraryScanner] No important changes to scan for in folder "${folderId}"`)
Expand Down
33 changes: 31 additions & 2 deletions server/utils/fileUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,21 @@ async function readTextFile(path) {
}
module.exports.readTextFile = readTextFile

/**
* @typedef FilePathItem
* @property {string} name - file name e.g. "audiofile.m4b"
* @property {string} path - fullpath excluding folder e.g. "Author/Book/audiofile.m4b"
* @property {string} reldirpath - path excluding file name e.g. "Author/Book"
* @property {string} fullpath - full path e.g. "/audiobooks/Author/Book/audiofile.m4b"
* @property {string} extension - file extension e.g. ".m4b"
* @property {number} deep - depth of file in directory (0 is file in folder root)
*/

/**
* Get array of files inside dir
* @param {string} path
* @param {string} [relPathToReplace]
* @returns {{name:string, path:string, dirpath:string, reldirpath:string, fullpath:string, extension:string, deep:number}[]}
* @returns {FilePathItem[]}
*/
async function recurseFiles(path, relPathToReplace = null) {
path = filePathToPOSIX(path)
Expand Down Expand Up @@ -213,7 +223,6 @@ async function recurseFiles(path, relPathToReplace = null) {
return {
name: item.name,
path: item.fullname.replace(relPathToReplace, ''),
dirpath: item.path,
reldirpath: isInRoot ? '' : item.path.replace(relPathToReplace, ''),
fullpath: item.fullname,
extension: item.extension,
Expand All @@ -228,6 +237,26 @@ async function recurseFiles(path, relPathToReplace = null) {
}
module.exports.recurseFiles = recurseFiles

/**
*
* @param {import('../Watcher').PendingFileUpdate} fileUpdate
* @returns {FilePathItem}
*/
module.exports.getFilePathItemFromFileUpdate = (fileUpdate) => {
let relPath = fileUpdate.relPath
if (relPath.startsWith('/')) relPath = relPath.slice(1)

const dirname = Path.dirname(relPath)
return {
name: Path.basename(relPath),
path: relPath,
reldirpath: dirname === '.' ? '' : dirname,
fullpath: fileUpdate.path,
extension: Path.extname(relPath),
deep: relPath.split('/').length - 1
}
}

/**
* Download file from web to local file system
* Uses SSRF filter to prevent internal URLs
Expand Down
101 changes: 0 additions & 101 deletions server/utils/scandir.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,107 +32,6 @@ function checkFilepathIsAudioFile(filepath) {
}
module.exports.checkFilepathIsAudioFile = checkFilepathIsAudioFile

/**
* TODO: Function needs to be re-done
* @param {string} mediaType
* @param {string[]} paths array of relative file paths
* @returns {Record<string,string[]>} map of files grouped into potential libarary item dirs
*/
function groupFilesIntoLibraryItemPaths(mediaType, paths) {
// Step 1: Clean path, Remove leading "/", Filter out non-media files in root dir
var nonMediaFilePaths = []
var pathsFiltered = paths
.map((path) => {
return path.startsWith('/') ? path.slice(1) : path
})
.filter((path) => {
let parsedPath = Path.parse(path)
// Is not in root dir OR is a book media file
if (parsedPath.dir) {
if (!isMediaFile(mediaType, parsedPath.ext, false)) {
// Seperate out non-media files
nonMediaFilePaths.push(path)
return false
}
return true
} else if (mediaType === 'book' && isMediaFile(mediaType, parsedPath.ext, false)) {
// (book media type supports single file audiobooks/ebooks in root dir)
return true
}
return false
})

// Step 2: Sort by least number of directories
pathsFiltered.sort((a, b) => {
var pathsA = Path.dirname(a).split('/').length
var pathsB = Path.dirname(b).split('/').length
return pathsA - pathsB
})

// Step 3: Group files in dirs
var itemGroup = {}
pathsFiltered.forEach((path) => {
var dirparts = Path.dirname(path)
.split('/')
.filter((p) => !!p && p !== '.') // dirname returns . if no directory
var numparts = dirparts.length
var _path = ''

if (!numparts) {
// Media file in root
itemGroup[path] = path
} else {
// Iterate over directories in path
for (let i = 0; i < numparts; i++) {
var dirpart = dirparts.shift()
_path = Path.posix.join(_path, dirpart)

if (itemGroup[_path]) {
// Directory already has files, add file
var relpath = Path.posix.join(dirparts.join('/'), Path.basename(path))
itemGroup[_path].push(relpath)
return
} else if (!dirparts.length) {
// This is the last directory, create group
itemGroup[_path] = [Path.basename(path)]
return
} else if (dirparts.length === 1 && /^(cd|dis[ck])\s*\d{1,3}$/i.test(dirparts[0])) {
// Next directory is the last and is a CD dir, create group
itemGroup[_path] = [Path.posix.join(dirparts[0], Path.basename(path))]
return
}
}
}
})

// Step 4: Add in non-media files if they fit into item group
if (nonMediaFilePaths.length) {
for (const nonMediaFilePath of nonMediaFilePaths) {
const pathDir = Path.dirname(nonMediaFilePath)
const filename = Path.basename(nonMediaFilePath)
const dirparts = pathDir.split('/')
const numparts = dirparts.length
let _path = ''

// Iterate over directories in path
for (let i = 0; i < numparts; i++) {
const dirpart = dirparts.shift()
_path = Path.posix.join(_path, dirpart)
if (itemGroup[_path]) {
// Directory is a group
const relpath = Path.posix.join(dirparts.join('/'), filename)
itemGroup[_path].push(relpath)
} else if (!dirparts.length) {
itemGroup[_path] = [filename]
}
}
}
}

return itemGroup
}
module.exports.groupFilesIntoLibraryItemPaths = groupFilesIntoLibraryItemPaths

/**
* @param {string} mediaType
* @param {{name:string, path:string, dirpath:string, reldirpath:string, fullpath:string, extension:string, deep:number}[]} fileItems (see recurseFiles)
Expand Down

0 comments on commit 344890f

Please sign in to comment.