badger-am/lib/audio.js

146 lines
5.1 KiB
JavaScript
Raw Normal View History

2017-03-24 22:05:51 +01:00
// requirements
2017-03-24 22:11:22 +01:00
const fs = require('fs');
2017-03-24 22:56:05 +01:00
const path = require('path');
const async = require('async');
2017-03-24 22:05:51 +01:00
const metadata = require('musicmetadata');
2017-03-24 22:56:05 +01:00
const ffmpeg = require('fluent-ffmpeg');
const fse = require('fs-extra');
2017-03-24 23:36:41 +01:00
const util = require('./util');
2017-03-27 22:28:35 +02:00
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);
}
2017-03-24 22:56:05 +01:00
// convert file to mp3 at specified bitrate
2017-03-27 22:28:35 +02:00
function convert(source, config, callback) {
async.waterfall([
// get metadata
function (waterfallCallback) {
extractMetadata(source, waterfallCallback);
2017-03-24 22:56:05 +01:00
},
2017-03-27 22:28:35 +02:00
// create path from metadata
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)
2017-03-24 22:56:05 +01:00
.on('error', function (err) {
2017-03-27 22:28:35 +02:00
return waterfallCallback(err);
2017-03-24 22:56:05 +01:00
})
.on('end', function () {
2017-03-27 22:28:35 +02:00
waterfallCallback();
2017-03-24 22:56:05 +01:00
});
}
2017-03-27 22:28:35 +02:00
], callback);
2017-03-24 23:36:41 +01:00
}
2017-03-27 23:27:33 +02:00
//
function batchArtwork(config, callback) {
2017-03-24 23:36:41 +01:00
async.waterfall([
2017-03-27 23:27:33 +02:00
// get files
function (waterfallCallback) {
util.readDirRecursive(config.input, config.format, waterfallCallback);
2017-03-24 23:36:41 +01:00
},
2017-03-27 23:27:33 +02:00
// display info, prompt user and create progressbar
function (files, waterfallCallback) {
cli.askForConfirmation(files.length + ' files found.\nstart artwork extraction now?', ['yes', 'y'], function (err) {
if (err) {
return waterfallCallback(err);
}
waterfallCallback(null, files, cli.createProgressBar(files.length));
2017-03-24 23:36:41 +01:00
});
2017-03-27 23:27:33 +02:00
},
// process each file
function (files, bar, waterfallCallback) {
async.eachLimit(files, config.concurrency, function (file, eachCallback) {
extractArtwork(file, function (err) {
bar.tick();
if (err) {
return eachCallback(err);
}
eachCallback();
});
}, waterfallCallback);
2017-03-24 23:36:41 +01:00
}
2017-03-27 23:27:33 +02:00
], callback);
}
// extract cover artwork
function extractArtwork(source, callback) {
async.waterfall([
// get metadata
function (waterfallCallback) {
extractMetadata(source, waterfallCallback);
},
// write image to disk
function (metadata, waterfallCallback) {
if (!metadata.picture) {
waterfallCallback();
}
for (let counter = 0, length = metadata.picture.length; counter < length; counter++) {
const stream = fs.createWriteStream(path.join(path.dirname(source), path.basename(source, path.extname(source)) + '.' + metadata.picture[counter].format));
stream.write(metadata.picture[counter].data);
stream.end();
}
waterfallCallback();
2017-03-24 23:36:41 +01:00
}
2017-03-27 23:27:33 +02:00
], callback);
2017-03-24 23:36:41 +01:00
}
2017-03-24 22:05:51 +01:00
// extract metadata for further processing
2017-03-24 23:36:41 +01:00
function extractMetadata(sourceFile, callback) {
2017-03-24 22:05:51 +01:00
const stream = fs.createReadStream(sourceFile);
metadata(stream, function (err, metadata) {
if (err) {
return callback(err);
}
stream.close();
2017-03-24 23:36:41 +01:00
callback(null, metadata);
2017-03-24 22:05:51 +01:00
});
2017-03-24 23:36:41 +01:00
}
// api
2017-03-27 22:28:35 +02:00
exports.batchConvert = batchConvert;
2017-03-27 23:27:33 +02:00
exports.convert = convert;
exports.batchArtwork = batchArtwork;
2017-03-24 23:36:41 +01:00
exports.extractArtwork = extractArtwork;
exports.extractMetadata = extractMetadata;