Comparing version 1.0.1 to 1.0.2
119
index.js
@@ -0,8 +1,4 @@ | ||
/* jshint node:true */ | ||
"use strict"; | ||
var COMMAND = "fpcalc", | ||
run = require("comandante"), | ||
fpcalc = run.bind(null, COMMAND), | ||
split = require("split"); | ||
module.exports = function(file, options, callback) { | ||
@@ -15,7 +11,4 @@ // Handle `options` parameter being optional | ||
var | ||
// Result object to build as data is returned by fpcalc | ||
result = {}, | ||
// Command-line arguments to pass to fpcalc | ||
args = []; | ||
// Command-line arguments to pass to fpcalc | ||
var args = []; | ||
@@ -29,23 +22,91 @@ // `-length` command-line argument | ||
function onData(data) { | ||
// Data is given as lines like `FILE=path/to/file`, so we split the | ||
// parts out and build the `results` object | ||
var parts = data.split("=", 2), | ||
name = parts[0].toLowerCase(), | ||
value = parts[1]; | ||
run(args) | ||
.on("error", callback) | ||
.pipe(parse(callback.bind(null, null))); | ||
}; | ||
if (name) { | ||
result[name.toLowerCase()] = value; | ||
// -- Run fpcalc command | ||
var spawn = require("child_process").spawn, | ||
fpcalc = spawn.bind(null, "fpcalc"), | ||
es = require("event-stream"), | ||
concat = require("concat-stream"); | ||
// Runs the fpcalc tool and returns a readable stream that will emit stdout | ||
// or an error event if an error occurs | ||
function run(args) { | ||
var | ||
// Create fpcalc child process | ||
cp = fpcalc(args), | ||
// Create a through stream that passes through data but does not end | ||
// when the source stream ends. We will manually end the stream once | ||
// the child processes closes. | ||
stream = es.through(null, function() {}); | ||
// Pass fpcalc stdout through the stream | ||
cp.stdout.pipe(stream); | ||
// Catch fpcalc stderr errors even when exit code is 0 | ||
// See https://bitbucket.org/acoustid/chromaprint/issue/2/fpcalc-return-non-zero-exit-code-if | ||
cp.stderr.pipe(concat(function(data) { | ||
data = data.toString(); | ||
if (data && data.slice(0, 6) === "ERROR:") { | ||
stream.emit("error", new Error(data)); | ||
} | ||
} | ||
})); | ||
fpcalc(args) | ||
// parse one complete line at a time | ||
.pipe(split()) | ||
// parse data into result object | ||
.on("data", onData) | ||
// return result object | ||
.on("end", callback.bind(null, null, result)) | ||
// return error | ||
.on("error", callback); | ||
}; | ||
// End the stream when the child processes closes | ||
cp.on("close", function() { | ||
stream.queue(null); | ||
}); | ||
return stream; | ||
} | ||
// -- fpcalc stdout stream parsing | ||
function parse(callback) { | ||
return es.pipeline( | ||
// Parse one complete line at a time | ||
es.split(), | ||
// Only use non-empty lines | ||
filter(Boolean), | ||
// Parse each line into name/value pair | ||
es.mapSync(parseData), | ||
// Reduce data into single result object to pass to callback | ||
reduce(function(result, data) { | ||
result[data.name] = data.value; | ||
return result; | ||
}, {}, callback) | ||
); | ||
} | ||
// Create a through stream that only passes data that passes the given test | ||
// @TODO Extract this to own module | ||
function filter(test) { | ||
return es.mapSync(function(data) { | ||
if (test(data)) { | ||
return data; | ||
} | ||
}); | ||
} | ||
// Reduce stream data into a single value | ||
// @TODO Extract this to own module | ||
function reduce(fn, acc, callback) { | ||
return es.through(function(data) { | ||
acc = fn(acc, data); | ||
}, function() { | ||
callback(acc); | ||
}); | ||
} | ||
// Data is given as lines like `FILE=path/to/file`, so we split the | ||
// parts out to a name/value pair | ||
function parseData(data) { | ||
var parts = data.split("=", 2); | ||
return { | ||
name: parts[0].toLowerCase(), | ||
value: parts[1], | ||
}; | ||
} |
{ | ||
"name": "fpcalc", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"description": "Light wrapper around the AcoustID Chromaprint fpcalc tool", | ||
@@ -28,8 +28,8 @@ "main": "index.js", | ||
"dependencies": { | ||
"comandante": "0.0.1", | ||
"split": "~0.2.6" | ||
"event-stream": "~3", | ||
"concat-stream": "~1" | ||
}, | ||
"devDependencies": { | ||
"tape": "~1.0.4" | ||
"tape": "~1" | ||
} | ||
} |
@@ -9,4 +9,3 @@ "use strict"; | ||
test("test audio fingerprint", function(t) { | ||
t.plan(4); | ||
test("get audio fingerprint", function(t) { | ||
fpcalc(TEST_FILE, function(err, result) { | ||
@@ -17,3 +16,11 @@ t.ifError(err); | ||
t.ok(result.fingerprint); | ||
t.end(); | ||
}); | ||
}); | ||
test("bad file path", function(t) { | ||
fpcalc("bad/path", function(err, result) { | ||
t.ok(err); | ||
t.end(); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
203789
118
2
+ Addedconcat-stream@~1
+ Addedevent-stream@~3
+ Addedbuffer-from@1.1.2(transitive)
+ Addedconcat-stream@1.6.2(transitive)
+ Addedcore-util-is@1.0.3(transitive)
+ Addedduplexer@0.1.2(transitive)
+ Addedevent-stream@3.3.5(transitive)
+ Addedfrom@0.1.7(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedisarray@1.0.0(transitive)
+ Addedmap-stream@0.0.7(transitive)
+ Addedpause-stream@0.0.11(transitive)
+ Addedprocess-nextick-args@2.0.1(transitive)
+ Addedreadable-stream@2.3.8(transitive)
+ Addedsafe-buffer@5.1.2(transitive)
+ Addedsplit@1.0.1(transitive)
+ Addedstream-combiner@0.2.2(transitive)
+ Addedstring_decoder@1.1.1(transitive)
+ Addedtypedarray@0.0.6(transitive)
+ Addedutil-deprecate@1.0.2(transitive)
- Removedcomandante@0.0.1
- Removedsplit@~0.2.6
- Removedcomandante@0.0.1(transitive)
- Removedduplexer@0.0.4(transitive)
- Removedsplit@0.2.10(transitive)