implemented basic functionality
This commit is contained in:
parent
76bbe545be
commit
5f220204b3
1 changed files with 169 additions and 1 deletions
168
badger-am.js
168
badger-am.js
|
@ -1 +1,169 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
// requirements
|
||||||
|
const os = require('os');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const fse = require('fs-extra');
|
||||||
|
const async = require('async');
|
||||||
|
const commander = require('commander');
|
||||||
|
const recursive = require('recursive-readdir');
|
||||||
|
const metadata = require('musicmetadata');
|
||||||
|
const progress = require('progress');
|
||||||
|
const app = require('./package.json');
|
||||||
|
|
||||||
|
// general options
|
||||||
|
commander
|
||||||
|
.version(app.version)
|
||||||
|
.usage('[options] <command>')
|
||||||
|
.option('-c, --concurrency <n>', 'specify concurrency level', os.cpus().length);
|
||||||
|
|
||||||
|
// conversion mode
|
||||||
|
commander
|
||||||
|
.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);
|
||||||
|
});
|
||||||
|
|
||||||
|
// sort mode
|
||||||
|
commander
|
||||||
|
.command('sort <input> <output>')
|
||||||
|
.description('sort audio files by tags')
|
||||||
|
.option('-f, --format <type>', 'specify audio format (\'flac\', \'mp3\')', 'flac')
|
||||||
|
.action(sort);
|
||||||
|
|
||||||
|
// parse command line arguments
|
||||||
|
commander.parse(process.argv);
|
||||||
|
|
||||||
|
// functions
|
||||||
|
function sort(input, output, options) {
|
||||||
|
const start = process.hrtime();
|
||||||
|
const concurrency = commander.concurrency;
|
||||||
|
console.log('--- SORT MODE ---');
|
||||||
|
console.log('concurrency: ' + concurrency);
|
||||||
|
// get files in input directory
|
||||||
|
recursive(input, [ignoreFilter], function (err, files) {
|
||||||
|
if (err) {
|
||||||
|
exit(err);
|
||||||
|
}
|
||||||
|
// display progressbar
|
||||||
|
const bar = createProgressBar(files.length);
|
||||||
|
// handle each file
|
||||||
|
async.eachLimit(files, concurrency, function (file, eachCallback) {
|
||||||
|
handleSource(output, file, function (err) {
|
||||||
|
bar.tick();
|
||||||
|
if (err) {
|
||||||
|
return eachCallback(err);
|
||||||
|
}
|
||||||
|
eachCallback();
|
||||||
|
});
|
||||||
|
}, function (err) {
|
||||||
|
const diff = process.hrtime(start);
|
||||||
|
console.log('done after ' + (diff[0] * 1000 + diff[1] / 1000000) + ' milliseconds');
|
||||||
|
exit(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function ignoreFilter(file, stats) {
|
||||||
|
return !stats.isDirectory() && path.extname(file).indexOf(options.format) == -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function exit(err) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
console.log('DONE');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSource(output, file, callback) {
|
||||||
|
async.waterfall([
|
||||||
|
function (asyncCallback) {
|
||||||
|
extractMetadata(file, asyncCallback)
|
||||||
|
},
|
||||||
|
function (metadata, asyncCallback) {
|
||||||
|
pathFromMetadata(output, metadata, asyncCallback);
|
||||||
|
}
|
||||||
|
// TODO: create output directory, append file extension and move file
|
||||||
|
], function (err, results) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
callback(null, results);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractMetadata(file, callback) {
|
||||||
|
const stream = fs.createReadStream(file);
|
||||||
|
metadata(stream, function (err, metadata) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
stream.close();
|
||||||
|
callback(null, metadata)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function pathFromMetadata(output, metadata, callback) {
|
||||||
|
// define directory
|
||||||
|
let directory = path.normalize(path.join(output));
|
||||||
|
if (metadata.albumartist && metadata.albumartist.length > 0) {
|
||||||
|
let tmp;
|
||||||
|
const artistCount = metadata.albumartist.length;
|
||||||
|
for (let counter = 0; counter < artistCount; counter++) {
|
||||||
|
if (counter > 0) {
|
||||||
|
tmp += ' - ' + metadata.albumartist[counter];
|
||||||
|
} else {
|
||||||
|
tmp = metadata.albumartist[counter];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
directory = path.join(directory, tmp);
|
||||||
|
} else {
|
||||||
|
directory = path.join(directory, metadata.artist[0]);
|
||||||
|
}
|
||||||
|
if (metadata.album) {
|
||||||
|
directory = path.join(directory, metadata.album);
|
||||||
|
}
|
||||||
|
// define filename
|
||||||
|
let file = '';
|
||||||
|
if (metadata.disk.no) {
|
||||||
|
file += frontFill(metadata.disk.no, '0', 2);
|
||||||
|
}
|
||||||
|
if (metadata.track.no) {
|
||||||
|
if (file) {
|
||||||
|
file += '-' + frontFill(metadata.track.no, '0', 2) + ' ';
|
||||||
|
} else {
|
||||||
|
file += frontFill(metadata.track.no, '0', 2) + ' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (metadata.artist && metadata.albumartist.length > 0) {
|
||||||
|
file += metadata.artist[0] + ' - ';
|
||||||
|
}
|
||||||
|
if (metadata.title) {
|
||||||
|
file += metadata.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null, directory, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
function frontFill(string, fill, length) {
|
||||||
|
while (string.length > length) {
|
||||||
|
string = fill + string;
|
||||||
|
}
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createProgressBar(total) {
|
||||||
|
return new progress(':bar | progress: :current/:total (:percent) | elapsed: :elapseds | eta: :etas', {
|
||||||
|
total: total,
|
||||||
|
width: 32
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in a new issue