#!/usr/bin/env node // requirements const os = require('os'); const path = require('path'); const async = require('async'); const commander = require('commander'); const recursive = require('recursive-readdir'); const app = require('./package.json'); const audio = require('./lib/audio'); const util = require('./lib/util'); // generate timestamp const start = process.hrtime(); util.printLogo(); // general options commander .version(app.version) .usage('[options] ') .option('-c, --concurrency ', 'specify concurrency level', os.cpus().length); // conversion mode commander .command('convert ') .description('convert .flac to .mp3 files') .option('-b, --bitrate ', 'specify conversion bitrate', 320) .action(function (input, output, options) { console.log('--- CONVERT MODE ---'); console.log('input: ' + input); console.log('output: ' + output); console.log('bitrate: ' + commander.options.bitrate); console.log('conc: ' + commander.concurrency); }); // sort mode commander .command('sort ') .description('sort audio files by tags') .option('-f, --format ', 'specify audio format (\'flac\', \'mp3\')', 'flac') .action(sort); // parse command line arguments commander.parse(process.argv); // sort files function sort(input, output, options) { const concurrency = commander.concurrency; async.waterfall([ function (asyncCallback) { recursive(input, [ignoreFilter], asyncCallback); }, function (files, asyncCallback) { console.log(files.length + ' \'' + options.format + '\' files found'); // display progressbar const bar = util.createProgressBar(files.length); // handle each file async.eachLimit(files, concurrency, function (file, eachCallback) { processFileSort(output, file, function (err) { bar.tick(); if (err) { return eachCallback(err); } eachCallback(); }); }, function (err) { if (err) { return asyncCallback(err); } asyncCallback(); }); } ], function (err, result) { util.exit(err, start); }); function ignoreFilter(file, stats) { return !stats.isDirectory() && path.extname(file).indexOf(options.format) == -1; } } // move file to location defined by its metadata function processFileSort(output, sourceFile, callback) { async.waterfall([ function (asyncCallback) { audio.extractMetadata(sourceFile, asyncCallback) }, function (sourceFile, metadata, asyncCallback) { util.pathFromMetadata(sourceFile, output, metadata, asyncCallback); }, function (targetFile, asyncCallback) { util.moveFile(sourceFile, targetFile, asyncCallback); } ], function (err, results) { if (err) { return callback(err); } callback(null, results); }); }