refactored conversion
This commit is contained in:
parent
cbe726c4fc
commit
e8f7c33a46
78
badger-am.js
78
badger-am.js
|
@ -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);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
73
lib/audio.js
73
lib/audio.js
|
@ -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;
|
|
@ -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>",
|
||||||
|
|
Loading…
Reference in a new issue