From 00a1d381676bb3a446f0cf3e25b4c414a546a6ab Mon Sep 17 00:00:00 2001 From: IrosTheBeggar Date: Tue, 9 Mar 2021 18:45:13 -0500 Subject: [PATCH] new scanner --- src/db/scanner-alpha.js | 80 +++++++++++++++++++++++++++++++++++++++-- src/db/task-queue.js | 26 +++++++------- 2 files changed, 90 insertions(+), 16 deletions(-) diff --git a/src/db/scanner-alpha.js b/src/db/scanner-alpha.js index 809e572..b78593d 100644 --- a/src/db/scanner-alpha.js +++ b/src/db/scanner-alpha.js @@ -160,8 +160,8 @@ async function recursiveScan(dir) { // put in new entry await insertEntries(songInfo); - // update users db - + // TODO: update users db + } catch(err) { console.error(`Warning: failed to add file ${thisSong} to database: ${err.message}`); } @@ -216,6 +216,7 @@ function calculateHash(filepath) { async function getAlbumArt(songInfo) { if (loadJson.skipImg === true) { return; } + // picture is stored in song metadata if (songInfo.picture && songInfo.picture[0]) { // Generate unique name based off hash of album art and metadata const picHashString = crypto.createHash('md5').update(songInfo.picture[0].data.toString('utf-8')).digest('hex'); @@ -225,9 +226,84 @@ async function getAlbumArt(songInfo) { // Save file sync fs.writeFileSync(path.join(loadJson.albumArtDirectory, songInfo.aaFile), songInfo.picture[0].data); } + } else { + await checkDirectoryForAlbumArt(songInfo); } } +const mapOfDirectoryAlbumArt = {}; +async function checkDirectoryForAlbumArt(songInfo) { + const directory = path.join(loadJson.directory, path.dirname(songInfo.filePath)); + + // album art has already been found + if (mapOfDirectoryAlbumArt[directory]) { + return songInfo.aaFile = mapOfDirectoryAlbumArt[directory]; + } + + // directory was already scanned and nothing was found + if (mapOfDirectoryAlbumArt[directory] === false) { return; } + + const imageArray = []; + try { + var files = fs.readdirSync(directory); + } catch (err) { + return; + } + + for (const file of files) { + const filepath = path.join(directory, file); + try { + var stat = fs.statSync(filepath); + } catch (error) { + // Bad file, ignore and continue + continue; + } + + if (!stat.isFile()) { + continue; + } + + if (["png", "jpg"].indexOf(getFileType(file)) === -1) { + continue; + } + + imageArray.push(file); + } + + if (imageArray.length === 0) { + return mapOfDirectoryAlbumArt[directory] = false; + } + + let imageBuffer; + let picFormat; + + // Search for a named file + for (var i = 0; i < imageArray.length; i++) { + const imgMod = imageArray[i].toLowerCase(); + if (imgMod === 'folder.jpg' || imgMod === 'cover.jpg' || imgMod === 'album.jpg' || imgMod === 'folder.png' || imgMod === 'cover.png' || imgMod === 'album.png') { + imageBuffer = fs.readFileSync(path.join(directory, imageArray[i])); + picFormat = getFileType(imageArray[i]); + break; + } + } + + // default to first file if none are named + if (!imageBuffer) { + imageBuffer = fs.readFileSync(path.join(directory, imageArray[0])); + picFormat = getFileType(imageArray[0]); + } + + const picHashString = crypto.createHash('md5').update(imageBuffer.toString('utf8')).digest('hex'); + songInfo.aaFile = picHashString + '.' + picFormat; + // Check image-cache folder for filename and save if doesn't exist + if (!fs.existsSync(path.join(loadJson.albumArtDirectory, songInfo.aaFile))) { + // Save file sync + fs.writeFileSync(path.join(loadJson.albumArtDirectory, songInfo.aaFile), imageBuffer); + } + + mapOfDirectoryAlbumArt[directory] = songInfo.aaFile; +} + function getFileType(filename) { return filename.split(".").pop(); } \ No newline at end of file diff --git a/src/db/task-queue.js b/src/db/task-queue.js index bb56abe..bdfd55b 100644 --- a/src/db/task-queue.js +++ b/src/db/task-queue.js @@ -11,10 +11,11 @@ const vpathLimiter = new Set(); let scanIntervalTimer = null; // This gets set after the server boots function addScanTask(vpath) { + const scanObj = { task: 'scan', vpath: vpath, id: nanoid.nanoid(8) }; if (runningTasks.size < config.program.scanOptions.maxConcurrentTasks) { - runScan(vpath); + runScan(scanObj); } else { - taskQueue.push({ task: 'scan', vpath: vpath, id: nanoid.nanoid(8) }); + taskQueue.push(scanObj); } } @@ -34,28 +35,29 @@ function nextTask() { && runningTasks.size < config.program.scanOptions.maxConcurrentTasks && !vpathLimiter.has(taskQueue[taskQueue.length - 1].vpath)) { - runScan(taskQueue.pop().vpath); + runScan(taskQueue.pop()); } } -function runScan(vpath) { +function runScan(scanObj) { let parseFlag = false; const jsonLoad = { - directory: config.program.folders[vpath].root, - vpath: vpath, + directory: config.program.folders[scanObj.vpath].root, + vpath: scanObj.vpath, dbPath: path.join(config.program.storage.dbDirectory, db.getFileDbName()), albumArtDirectory: config.program.storage.albumArtDirectory, skipImg: config.program.scanOptions.skipImg, saveInterval: config.program.scanOptions.saveInterval, pause: config.program.scanOptions.pause, - supportedFiles: config.program.supportedAudioFiles + supportedFiles: config.program.supportedAudioFiles, + scanId: scanObj.id }; - const forkedScan = child.fork(path.join(__dirname, './scanner.js'), [JSON.stringify(jsonLoad)], { silent: true }); + const forkedScan = child.fork(path.join(__dirname, './scanner-alpha.js'), [JSON.stringify(jsonLoad)], { silent: true }); winston.info(`File scan started on ${jsonLoad.directory}`); runningTasks.add(forkedScan); - vpathLimiter.add(vpath); + vpathLimiter.add(scanObj.vpath); forkedScan.stdout.on('data', (data) => { try { @@ -80,7 +82,7 @@ function runScan(vpath) { db.loadDB(); } runningTasks.delete(forkedScan); - vpathLimiter.delete(vpath); + vpathLimiter.delete(scanObj.vpath); nextTask(); winston.info(`File scan completed with code ${code}`); }); @@ -99,10 +101,6 @@ exports.isScanning = () => { } exports.getAdminStats = () => { - console.log(taskQueue); - console.log(vpathLimiter); - console.log(runningTasks); - return { taskQueue, vpaths: [...vpathLimiter]