// requirements const path = require('path'); const async = require('async'); const fse = require('fs-extra'); const recursive = require('recursive-readdir'); const progress = require('progress'); const cli = require('./cli'); const audio = require('./audio'); // move all files from input to output directory function batchSort(config, callback) { async.waterfall([ // get files function (waterfallCallback) { readDirRecursive(config.input, config.format, waterfallCallback); }, // display info, prompt user and create progressbar function (files, waterfallCallback) { cli.askForConfirmation(files.length + ' files found.\nstart sorting now?', ['yes', 'y'], function (err) { if (err) { return waterfallCallback(err); } waterfallCallback(null, files, cli.createProgressBar(files.length)); }); }, // process each file function (files, bar, waterfallCallback) { async.eachLimit(files, config.concurrency, function (file, eachCallback) { moveFile(file, config, function (err) { bar.tick(); if (err) { return eachCallback(err); } eachCallback(); }) }, waterfallCallback); } ], callback); } // create target directory and move the file function moveFile(source, config, callback) { async.waterfall([ // get metadata function (waterfallCallback) { audio.extractMetadata(source, waterfallCallback); }, // create path from metadata function (metadata, waterfallCallback) { getPathByMetadata(source, config.output, metadata, waterfallCallback); }, // create target directory function (target, waterfallCallback) { fse.mkdirs(path.dirname(target), function (err) { if (err) { return waterfallCallback(err); } waterfallCallback(null, target); }); }, // move file function (target, waterfallCallback) { fse.move(source, target, waterfallCallback); } ], callback); } // create path for target file function getPathByMetadata(source, output, metadata, callback) { // define directory let filePath = path.normalize(output); if (metadata.albumartist && metadata.albumartist.length > 0) { let tmp; const artistCount = metadata.albumartist.length; for (let counter = 0; counter < artistCount; counter++) { if (counter > 0) { tmp += ' - ' + metadata.albumartist[counter]; } else { tmp = metadata.albumartist[counter]; } } filePath = path.join(filePath, tmp); } else { filePath = path.join(filePath, metadata.artist[0]); } if (metadata.album) { filePath = path.join(filePath, metadata.album); } // define filename let fileName = ''; if (metadata.disk.no) { fileName += frontFill(metadata.disk.no, '0', 2); } if (metadata.track.no) { if (fileName) { fileName += '-' + frontFill(metadata.track.no, '0', 2) + ' '; } else { fileName += frontFill(metadata.track.no, '0', 2) + ' '; } } if (metadata.artist) { fileName += metadata.artist[0] + ' - '; } if (metadata.title) { fileName += metadata.title; } // append extension fileName += path.extname(source); // join directory and name callback(null, path.join(filePath, fileName)); } // fill a string beginning from the front function frontFill(string, fill, length) { while (string.toString().length < length) { string = fill + string; } return string; } // list files in directory function readDirRecursive(where, extension, callback) { if (extension.indexOf('.') !== 0) { extension = '.' + extension; } recursive(where, [ignoreFilter], callback); function ignoreFilter(file, stats) { return !stats.isDirectory() && extension.indexOf(path.extname(file)) === -1; } } // api exports.batchSort = batchSort; exports.moveFile = moveFile; exports.getPathByMetadata = getPathByMetadata; exports.frontFill = frontFill; exports.readDirRecursive = readDirRecursive;