forked from mertdogar/node-fpcalc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
109 lines (90 loc) · 2.78 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/* jshint node:true */
"use strict";
var once = require("once");
var path = require("path");
module.exports = function(file, options, callback) {
// Handle `options` parameter being optional
if ( ! callback) {
callback = options;
options = {};
}
// Make sure the callback is called only once
callback = once(callback);
// Command-line arguments to pass to fpcalc
var args = [];
// `-length` command-line argument
if (options.length) {
args.push("-length", options.length);
}
args.push(file);
run(args)
.on("error", callback)
.pipe(parse())
.on("data", callback.bind(null, null));
};
// -- Run fpcalc command
var exeP = 'fpcalc';
if(process.platform == 'darwin')
exeP = path.normalize(process.execPath.split('/').slice(0, -1).join('/')+'/../../../../MacOS/fpcalc');
else if(process.platform == 'win32')
exeP = path.normalize(process.execPath.split('\\').slice(0, -1).join('\\')+'\\fpcalc.exe');
var fpcalc = require("child_process").spawn.bind(null, exeP),
es = require("event-stream"),
concat = require("concat-stream"),
filter = require("stream-filter"),
reduce = require("stream-reduce");
// 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
// Start the fpcalc child process
cp = fpcalc(args),
// Create the stream that we will eventually return. This stream
// passes through any data (cp's stdout) but does not emit an end
// event so that we can make sure the process exited without error.
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) {
if (data &&
(data = data.toString()) &&
data.slice(0, 6) === "ERROR:") {
stream.emit("error", new Error(data));
}
}));
// Check process exit code and end the stream
cp.on("close", function(code) {
if (code !== 0) {
stream.emit("error", new Error("fpcalc failed"));
}
stream.queue(null);
});
return stream;
}
// -- fpcalc stdout stream parsing
function parse() {
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;
}, {})
);
}
// 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 index = data.indexOf("=");
return {
name: data.slice(0, index).toLowerCase(),
value: data.slice(index + 1),
};
}