refactored conversion

This commit is contained in:
Daniel Sommer 2017-03-27 22:28:35 +02:00
parent cbe726c4fc
commit e8f7c33a46
3 changed files with 80 additions and 73 deletions

View file

@ -9,20 +9,21 @@ const recursive = require('recursive-readdir');
const app = require('./package.json'); const app = require('./package.json');
const audio = require('./lib/audio'); const audio = require('./lib/audio');
const util = require('./lib/util'); const util = require('./lib/util');
const cli = require('./lib/cli');
// generate timestamp // generate timestamp
const start = process.hrtime(); const start = process.hrtime();
main(); badger();
// "main" // "main"
function main() { function badger() {
util.printLogo(); cli.printLogo();
parseCLI(); run();
} }
// process command line arguments // start from command lines
function parseCLI() { function run() {
// general options // general options
commander commander
.version(app.version) .version(app.version)
@ -38,70 +39,33 @@ function parseCLI() {
commander commander
.command('sort <input> <output>') .command('sort <input> <output>')
.description('sort audio files by tags') .description('sort audio files by tags')
.option('-f, --format <type>', 'specify audio format (\'flac\', \'mp3\')', 'flac') .option('-f, --format <type>', 'specify audio format (\'flac\', \'mp3\')', '.flac')
.action(sort); .action(sort);
// artwork // artwork
commander commander
.command('artwork <input>') .command('artwork <input>')
.description('extract cover artwork') .description('extract cover artwork')
.option('-f, --format <type>', 'specify audio format (\'flac\', \'mp3\')', 'flac') .option('-f, --format <type>', 'specify audio format (\'flac\', \'mp3\')', '.flac')
.action(artwork); .action(artwork);
// parse command line arguments // parse command line arguments
commander.parse(process.argv); commander.parse(process.argv);
} }
// convert files // create config object
function convert(input, output, options) { function getConfig(input, output, options, commander) {
async.waterfall([ return {
function (asyncCallback) { input: path.normalize(input),
recursive(input, [ignoreFilter], asyncCallback); output: path.normalize(output),
}, concurrency: commander.concurrency || os.cpus().length,
function (files, asyncCallback) { bitrate: options.bitrate || 320,
console.log(files.length + ' \'flac\' files found'); format: options.format || '.flac'
// display progressbar
const bar = util.createProgressBar(files.length);
// handle each file
async.eachLimit(files, commander.concurrency, function (file, eachCallback) {
processFileConvert(output, file, options, 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('flac') == -1;
} }
} }
// move file to location defined by its metadata // convert files
function processFileConvert(output, sourceFile, options, callback) { function convert(input, output, options) {
async.waterfall([ audio.batchConvert(getConfig(input, output, options, commander), function (err) {
function (asyncCallback) { cli.exit(err);
audio.extractMetadata(sourceFile, asyncCallback)
},
function (metadata, asyncCallback) {
util.pathFromMetadata(sourceFile, output, metadata, asyncCallback);
},
function (targetFile, asyncCallback) {
audio.convert(sourceFile, targetFile, options.bitrate, asyncCallback);
}
], function (err, results) {
if (err) {
return callback(err);
}
callback(null, results);
}); });
} }

View file

@ -6,29 +6,71 @@ const metadata = require('musicmetadata');
const ffmpeg = require('fluent-ffmpeg'); const ffmpeg = require('fluent-ffmpeg');
const fse = require('fs-extra'); const fse = require('fs-extra');
const util = require('./util'); const util = require('./util');
const cli = require('./cli');
// convert all files in input directory
function batchConvert(config, callback) {
async.waterfall([
// get files
function (waterfallCallback) {
util.readDirRecursive(config.input, config.format, waterfallCallback);
},
// display info, prompt user and create progressbar
function (files, waterfallCallback) {
cli.askForConfirmation(files.length + ' files found.\nstart conversion 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) {
convert(file, config, function (err) {
bar.tick();
if (err) {
return eachCallback(err);
}
eachCallback();
});
}, waterfallCallback);
}
], callback);
}
// convert file to mp3 at specified bitrate // convert file to mp3 at specified bitrate
function convert(input, output, bitrate, callback) { function convert(source, config, callback) {
output = path.join(path.dirname(output), path.basename(output, path.extname(output)) + '.mp3'); async.waterfall([
async.series([ // get metadata
function (asyncCallback) { function (waterfallCallback) {
fse.mkdirs(path.dirname(output), asyncCallback); extractMetadata(source, waterfallCallback);
}, },
function (asyncCallback) { // create path from metadata
ffmpeg(path.normalize(input)).audioCodec('libmp3lame').audioBitrate(bitrate).save(output) function (metadata, waterfallCallback) {
util.getPathByMetadata(source, config.output, metadata, waterfallCallback);
},
// create target directory
function (target, waterfallCallback) {
target = path.join(path.dirname(target), path.basename(target, path.extname(target)) + '.mp3');
fse.mkdirs(path.dirname(target), function (err) {
if (err) {
return waterfallCallback(err);
}
waterfallCallback(null, target, config);
});
},
// convert file to mp3
function (target, config, waterfallCallback) {
ffmpeg(path.normalize(source)).audioCodec('libmp3lame').audioBitrate(config.bitrate).save(target)
.on('error', function (err) { .on('error', function (err) {
return asyncCallback(err); return waterfallCallback(err);
}) })
.on('end', function () { .on('end', function () {
asyncCallback(); waterfallCallback();
}); });
} }
], function (err, results) { ], callback);
if (err) {
return callback(err);
}
callback();
});
} }
// extract cover artwork // extract cover artwork
@ -68,5 +110,6 @@ function extractMetadata(sourceFile, callback) {
// api // api
exports.convert = convert; exports.convert = convert;
exports.batchConvert = batchConvert;
exports.extractArtwork = extractArtwork; exports.extractArtwork = extractArtwork;
exports.extractMetadata = extractMetadata; exports.extractMetadata = extractMetadata;

View file

@ -1,6 +1,6 @@
{ {
"name": "badger-am", "name": "badger-am",
"version": "0.4.0", "version": "0.4.1",
"license": "MIT", "license": "MIT",
"description": "audio manager", "description": "audio manager",
"author": "Daniel Sommer <daniel.sommer@velvettear.de>", "author": "Daniel Sommer <daniel.sommer@velvettear.de>",