badger-am/badger-am.js

160 lines
4.9 KiB
JavaScript
Raw Normal View History

2017-03-24 17:05:14 +01:00
#!/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');
2017-03-24 22:05:51 +01:00
const audio = require('./lib/audio');
const util = require('./lib/util');
2017-03-27 22:28:35 +02:00
const cli = require('./lib/cli');
2017-03-24 17:05:14 +01:00
2017-03-24 21:23:29 +01:00
// generate timestamp
const start = process.hrtime();
2017-03-27 22:28:35 +02:00
badger();
2017-03-24 21:46:09 +01:00
2017-03-24 22:18:22 +01:00
// "main"
2017-03-27 22:28:35 +02:00
function badger() {
cli.printLogo();
run();
2017-03-24 22:18:22 +01:00
}
2017-03-24 17:05:14 +01:00
2017-03-27 22:28:35 +02:00
// start from command lines
function run() {
2017-03-24 22:18:22 +01:00
// general options
commander
.version(app.version)
.usage('[options] <command>')
.option('-c, --concurrency <n>', 'specify concurrency level', os.cpus().length);
2017-03-24 23:36:41 +01:00
// conversion
2017-03-24 22:18:22 +01:00
commander
.command('convert <input> <output>')
.description('convert .flac to .mp3 files')
.option('-b, --bitrate <n>', 'specify conversion bitrate', 320)
2017-03-24 22:56:05 +01:00
.action(convert);
2017-03-24 23:36:41 +01:00
// sort
2017-03-24 22:18:22 +01:00
commander
.command('sort <input> <output>')
.description('sort audio files by tags')
2017-03-27 22:28:35 +02:00
.option('-f, --format <type>', 'specify audio format (\'flac\', \'mp3\')', '.flac')
2017-03-24 22:18:22 +01:00
.action(sort);
2017-03-24 23:36:41 +01:00
// artwork
commander
.command('artwork <input>')
.description('extract cover artwork')
2017-03-27 22:28:35 +02:00
.option('-f, --format <type>', 'specify audio format (\'flac\', \'mp3\')', '.flac')
2017-03-24 23:36:41 +01:00
.action(artwork);
2017-03-24 22:18:22 +01:00
// parse command line arguments
commander.parse(process.argv);
}
2017-03-24 17:05:14 +01:00
2017-03-27 22:28:35 +02:00
// create config object
function getConfig(input, output, options, commander) {
return {
input: path.normalize(input),
output: path.normalize(output),
concurrency: commander.concurrency || os.cpus().length,
bitrate: options.bitrate || 320,
format: options.format || '.flac'
2017-03-24 22:56:05 +01:00
}
}
2017-03-27 22:28:35 +02:00
// convert files
function convert(input, output, options) {
audio.batchConvert(getConfig(input, output, options, commander), function (err) {
cli.exit(err);
2017-03-24 23:36:41 +01:00
});
}
2017-03-24 21:23:29 +01:00
// sort files
2017-03-24 17:05:14 +01:00
function sort(input, output, options) {
2017-03-24 21:23:29 +01:00
async.waterfall([
function (asyncCallback) {
recursive(input, [ignoreFilter], asyncCallback);
},
function (files, asyncCallback) {
console.log(files.length + ' \'' + options.format + '\' files found');
// display progressbar
2017-03-24 22:05:51 +01:00
const bar = util.createProgressBar(files.length);
2017-03-24 21:23:29 +01:00
// handle each file
2017-03-24 22:56:05 +01:00
async.eachLimit(files, commander.concurrency, function (file, eachCallback) {
processFileSort(output, file, options, function (err) {
2017-03-24 21:23:29 +01:00
bar.tick();
if (err) {
return eachCallback(err);
}
eachCallback();
});
}, function (err) {
2017-03-24 17:05:14 +01:00
if (err) {
2017-03-24 21:23:29 +01:00
return asyncCallback(err);
2017-03-24 17:05:14 +01:00
}
2017-03-24 21:23:29 +01:00
asyncCallback();
2017-03-24 17:05:14 +01:00
});
2017-03-24 21:23:29 +01:00
}
], function (err, result) {
2017-03-24 22:05:51 +01:00
util.exit(err, start);
2017-03-24 17:05:14 +01:00
});
function ignoreFilter(file, stats) {
return !stats.isDirectory() && path.extname(file).indexOf(options.format) == -1;
}
}
2017-03-24 22:56:05 +01:00
// move file to location defined by its metadata
2017-03-24 23:36:41 +01:00
function processFileSort(output, sourceFile, callback) {
2017-03-24 22:56:05 +01:00
async.waterfall([
function (asyncCallback) {
audio.extractMetadata(sourceFile, asyncCallback)
},
function (sourceFile, metadata, asyncCallback) {
util.pathFromMetadata(sourceFile, output, metadata, asyncCallback);
},
function (targetFile, asyncCallback) {
2017-03-24 23:36:41 +01:00
util.moveFile(sourceFile, targetFile, asyncCallback);
2017-03-24 22:56:05 +01:00
}
], function (err, results) {
if (err) {
return callback(err);
}
callback(null, results);
});
}
2017-03-24 23:36:41 +01:00
// extract artwork
function artwork(input, options) {
2017-03-24 17:05:14 +01:00
async.waterfall([
function (asyncCallback) {
2017-03-24 23:36:41 +01:00
recursive(input, [ignoreFilter], asyncCallback);
2017-03-24 17:05:14 +01:00
},
2017-03-24 23:36:41 +01:00
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, commander.concurrency, function (file, eachCallback) {
audio.extractArtwork(file, function (err) {
bar.tick();
if (err) {
return eachCallback(err);
}
eachCallback();
});
}, function (err) {
if (err) {
return asyncCallback(err);
}
asyncCallback();
});
2017-03-24 17:05:14 +01:00
}
2017-03-24 23:36:41 +01:00
], function (err, result) {
util.exit(err, start);
2017-03-24 17:05:14 +01:00
});
2017-03-24 23:36:41 +01:00
function ignoreFilter(file, stats) {
return !stats.isDirectory() && path.extname(file).indexOf(options.format) == -1;
}
2017-03-24 22:18:57 +01:00
}