implemented conversion functionality

This commit is contained in:
Daniel Sommer 2017-03-24 22:56:05 +01:00
parent 1b3f19e92d
commit e1e6d8edeb
4 changed files with 107 additions and 24 deletions

View file

@ -33,13 +33,7 @@ function parseCLI() {
.command('convert <input> <output>')
.description('convert .flac to .mp3 files')
.option('-b, --bitrate <n>', '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);
});
.action(convert);
// sort mode
commander
.command('sort <input> <output>')
@ -50,9 +44,43 @@ function parseCLI() {
commander.parse(process.argv);
}
// convert files
function convert(input, output, options) {
async.waterfall([
function (asyncCallback) {
recursive(input, [ignoreFilter], asyncCallback);
},
function (files, asyncCallback) {
console.log(files.length + ' \'flac\' files found');
// 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;
}
}
// sort files
function sort(input, output, options) {
const concurrency = commander.concurrency;
async.waterfall([
function (asyncCallback) {
recursive(input, [ignoreFilter], asyncCallback);
@ -62,8 +90,8 @@ function sort(input, output, options) {
// display progressbar
const bar = util.createProgressBar(files.length);
// handle each file
async.eachLimit(files, concurrency, function (file, eachCallback) {
processFileSort(output, file, function (err) {
async.eachLimit(files, commander.concurrency, function (file, eachCallback) {
processFileSort(output, file, options, function (err) {
bar.tick();
if (err) {
return eachCallback(err);
@ -86,6 +114,26 @@ function sort(input, output, options) {
}
}
// move file to location defined by its metadata
function processFileConvert(output, sourceFile, options, callback) {
async.waterfall([
function (asyncCallback) {
audio.extractMetadata(sourceFile, asyncCallback)
},
function (sourceFile, 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);
});
}
// move file to location defined by its metadata
function processFileSort(output, sourceFile, callback) {
async.waterfall([

View file

@ -1,6 +1,34 @@
// requirements
const fs = require('fs');
const path = require('path');
const async = require('async');
const metadata = require('musicmetadata');
const ffmpeg = require('fluent-ffmpeg');
const fse = require('fs-extra');
// convert file to mp3 at specified bitrate
exports.convert = function convert(input, output, bitrate, callback) {
output = path.join(path.dirname(output), path.basename(output, path.extname(output)) + '.mp3');
async.series([
function (asyncCallback) {
fse.mkdirs(path.dirname(output), asyncCallback);
},
function (asyncCallback) {
ffmpeg(path.normalize(input)).audioCodec('libmp3lame').audioBitrate(bitrate).save(output)
.on('error', function (err) {
return asyncCallback(err);
})
.on('end', function () {
asyncCallback();
});
}
], function (err, results) {
if (err) {
return callback(err);
}
callback();
});
};
// extract metadata for further processing
exports.extractMetadata = function extractMetadata(sourceFile, callback) {

View file

@ -4,17 +4,16 @@ const async = require('async');
const fse = require('fs-extra');
const progress = require('progress');
// print logo
exports.printLogo = function printLogo() {
function printLogo() {
console.log(' _ _ _ __ __ ');
console.log(' | |__ __ _ __| |__ _ ___ _ _ /_\\ | \\/ |');
console.log(' | \'_ \\\/ _` \/ _` \/ _` / -_) \'_\/ _ \\| |\\/| |');
console.log(' |_.__\/\\__,_\\__,_\\__, \\___|_|\/_\/ \\_\\_| |_|');
console.log(' |___/ ');
};
}
// create path for target file
exports.pathFromMetadata = function pathFromMetadata(file, output, metadata, callback) {
function pathFromMetadata(file, output, metadata, callback) {
// define directory
let filePath = path.normalize(output);
if (metadata.albumartist && metadata.albumartist.length > 0) {
@ -56,10 +55,10 @@ exports.pathFromMetadata = function pathFromMetadata(file, output, metadata, cal
fileName += path.extname(file);
// join directory and name
callback(null, path.join(filePath, fileName));
};
}
// create target directory and move the file
exports.moveFile = function moveFile(source, target, callback) {
function moveFile(source, target, callback) {
async.series([
function (asyncCallback) {
fse.mkdirs(path.dirname(target), asyncCallback);
@ -73,26 +72,26 @@ exports.moveFile = function moveFile(source, target, callback) {
}
callback();
});
};
}
// fill a string beginning from the front
exports.frontfill = function frontFill(string, fill, length) {
function frontFill(string, fill, length) {
while (string.toString().length < length) {
string = fill + string;
}
return string;
};
}
// create a ascii progressbar
exports.createProgressBar = function createProgressBar(total) {
function createProgressBar(total) {
return new progress(':bar | progress: :current/:total (:percent) | elapsed: :elapseds | eta: :etas', {
total: total,
width: 32
});
};
}
// shutdown
exports.exit = function exit(err, start) {
function exit(err, start) {
if (err) {
console.error(err);
process.exit(1);
@ -100,4 +99,12 @@ exports.exit = function exit(err, start) {
const diff = process.hrtime(start);
console.log('exiting after ' + ((diff[0] + (diff[1] / 1000000)) / 1000).toFixed(2) + ' seconds');
process.exit(0);
};
}
// api
exports.printLogo = printLogo;
exports.pathFromMetadata = pathFromMetadata;
exports.moveFile = moveFile;
exports.frontFill = frontFill;
exports.createProgressBar = createProgressBar;
exports.exit = exit;

View file

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