Skip to content

Commit

Permalink
Merge pull request #176 from aclap-dev/node10
Browse files Browse the repository at this point in the history
Node10
  • Loading branch information
paulrouget committed Oct 16, 2023
2 parents bc8ca15 + f251ec0 commit aa204c6
Show file tree
Hide file tree
Showing 8 changed files with 350 additions and 261 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ jobs:
- run: eslint app tests/*.mjs
- run: sudo snap install yq
- run: ./build.sh
- run: sudo dpkg -i ./dist/linux/x86_64/vdhcoapp-2.0.2-linux-x86_64.deb
- run: sudo dpkg -i ./dist/linux/x86_64/vdhcoapp-2.0.3-linux-x86_64.deb
- run: ./tests/test.mjs /opt/vdhcoapp/vdhcoapp --with-network
345 changes: 174 additions & 171 deletions app/src/converter.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,204 +33,207 @@ function ExecConverter(args) {
});
}

const convertChildren = new Map();
exports.star_listening = () => {

rpc.listen({
const convertChildren = new Map();

"abortConvert": (pid) => {
let child = convertChildren.get(pid);
if (child && child.exitCode == null) {
child.kill();
}
},

// FIXME: Partly in test suite. But just for hls retrieval.
"convert": async (args = ["-h"], options = {}) => {
// `-progress pipe:1` send program-friendly progress information to stdin every 500ms.
// `-hide_banner -loglevel error`: make the output less noisy.
rpc.listen({

// This should never happen, but just in case a third party does a convert request
// with the old version of ffmpeg arguments, let's rewrite the arguments to fit
// the new syntax.
let fixed = false;
for (let i = 0; i < args.length; i++) {
if (args[i].startsWith("[1:v][2:v] overlay=") && !args[i].endsWith("[m]")) {
args[i] += " [m]";
fixed = true;
"abortConvert": (pid) => {
let child = convertChildren.get(pid);
if (child && child.exitCode == null) {
child.kill();
}
if (fixed && args[i] == "1:v") {
args[i] = "[m]";
},

// FIXME: Partly in test suite. But just for hls retrieval.
"convert": async (args = ["-h"], options = {}) => {
// `-progress pipe:1` send program-friendly progress information to stdin every 500ms.
// `-hide_banner -loglevel error`: make the output less noisy.

// This should never happen, but just in case a third party does a convert request
// with the old version of ffmpeg arguments, let's rewrite the arguments to fit
// the new syntax.
let fixed = false;
for (let i = 0; i < args.length; i++) {
if (args[i].startsWith("[1:v][2:v] overlay=") && !args[i].endsWith("[m]")) {
args[i] += " [m]";
fixed = true;
}
if (fixed && args[i] == "1:v") {
args[i] = "[m]";
}
}
}

const ffmpeg_base_args = "-progress pipe:1 -hide_banner -loglevel error";
args = [...ffmpeg_base_args.split(" "), ...args];
const ffmpeg_base_args = "-progress pipe:1 -hide_banner -loglevel error";
args = [...ffmpeg_base_args.split(" "), ...args];

const child = spawn(ffmpeg, args);
const child = spawn(ffmpeg, args);

if (!child.pid) {
throw new Error("Process creation failed");
}
if (!child.pid) {
throw new Error("Process creation failed");
}

convertChildren.set(child.pid, child);
convertChildren.set(child.pid, child);

let stderr = "";
let stderr = "";

let on_exit = new Promise((resolve) => {
child.on("exit", (code) => {
convertChildren.delete(child.pid);
resolve({exitCode: code, pid: child.pid, stderr});
let on_exit = new Promise((resolve) => {
child.on("exit", (code) => {
convertChildren.delete(child.pid);
resolve({exitCode: code, pid: child.pid, stderr});
});
});
});

child.stderr.on("data", (data) => stderr += data);
child.stderr.on("data", (data) => stderr += data);

if (options.startHandler) {
rpc.call("convertStartNotification", options.startHandler, child.pid);
}
if (options.startHandler) {
rpc.call("convertStartNotification", options.startHandler, child.pid);
}

const PROPS_RE = new RegExp("\\S+=\\s*\\S+");
const NAMEVAL_RE = new RegExp("(\\S+)=\\s*(\\S+)");
let progressInfo = {};
const PROPS_RE = new RegExp("\\S+=\\s*\\S+");
const NAMEVAL_RE = new RegExp("(\\S+)=\\s*(\\S+)");
let progressInfo = {};

const on_line = async (line) => {
let props = line.match(PROPS_RE) || [];
props.forEach((prop) => {
let m = NAMEVAL_RE.exec(prop);
if (m) {
progressInfo[m[1]] = m[2];
}
});
// last line of block is "progress"
if (progressInfo["progress"]) {
let info = progressInfo;
progressInfo = {};
if (typeof info["out_time_ms"] !== "undefined") {
// out_time_ms is in ns, not ms.
const seconds = parseInt(info["out_time_ms"]) / 1_000_000;
try {
await rpc.call("convertOutput", options.progressTime, seconds, info);
} catch (_) {
// Extension stopped caring
child.kill();
const on_line = async (line) => {
let props = line.match(PROPS_RE) || [];
props.forEach((prop) => {
let m = NAMEVAL_RE.exec(prop);
if (m) {
progressInfo[m[1]] = m[2];
}
});
// last line of block is "progress"
if (progressInfo["progress"]) {
let info = progressInfo;
progressInfo = {};
if (typeof info["out_time_ms"] !== "undefined") {
// out_time_ms is in ns, not ms.
const seconds = parseInt(info["out_time_ms"]) / 1_000_000;
try {
await rpc.call("convertOutput", options.progressTime, seconds, info);
} catch (_) {
// Extension stopped caring
child.kill();
}
}
}
}
};

if (options.progressTime) {
child.stdout.on("data", (lines) => {
lines.toString("utf-8").split("\n").forEach(on_line);
});
}
};

return on_exit;
},
// FIXME: Partly in test suite. But just for hls retrieval.
"probe": (input, json = false) => {
return new Promise((resolve, reject) => {
let args = [];
if (json) {
args = ["-v", "quiet", "-print_format", "json", "-show_format", "-show_streams"];
if (options.progressTime) {
child.stdout.on("data", (lines) => {
lines.toString("utf-8").split("\n").forEach(on_line);
});
}
args.push(input);
let probeProcess = spawn(ffprobe, args);
let stdout = "";
let stderr = "";
probeProcess.stdout.on("data", (data) => stdout += data);
probeProcess.stderr.on("data", (data) => stderr += data);
probeProcess.on("exit", (exitCode) => {
if (exitCode !== 0) {
return reject(new Error("Exit code: " + exitCode + "\n" + stderr));
}

return on_exit;
},
// FIXME: Partly in test suite. But just for hls retrieval.
"probe": (input, json = false) => {
return new Promise((resolve, reject) => {
let args = [];
if (json) {
// FIXME: not parsed?
resolve(stdout);
} else {
let info = {};
let m = /([0-9]{2,})x([0-9]{2,})/g.exec(stderr);
if (m) {
info.width = parseInt(m[1]);
info.height = parseInt(m[2]);
}
m = /Duration: ([0-9]{2}):([0-9]{2}):([0-9]{2})\.([0-9]{2})/g.exec(stderr);
if (m) {
info.duration = parseInt(m[1]) * 3600 + parseInt(m[2]) * 60 + parseInt(m[3]);
}
m = /Video:\s+([^\s\(,]+)/g.exec(stderr);
if (m) {
info.videoCodec = m[1];
}
m = /Audio:\s+([^\s\(,]+)/g.exec(stderr);
if (m) {
info.audioCodec = m[1];
}
m = /([0-9]+(?:\.[0-9]+)?)\s+fps\b/g.exec(stderr);
if (m) {
info.fps = parseFloat(m[1]);
}
resolve(info);
args = ["-v", "quiet", "-print_format", "json", "-show_format", "-show_streams"];
}
});
});
},
// FIXME: test (partly because open result is untested)
"play": (filePath) => {
return new Promise((resolve, _reject) => {
open(filePath);
resolve();
});
},
// In test suite
"codecs": () => {
return ExecConverter(["-codecs"])
.then((out) => {
let lines = out.split("\n");
let result = {};
lines.forEach((line) => {
let m = /^\s*(\.|D)(\.|E)(\.|V|A|S)(\.|I)(\.|L)(\.|S)\s+([^\s]+)\s+(.*?)\s*$/.exec(line);
if (!m || m[7] === '=') {
return;
args.push(input);
let probeProcess = spawn(ffprobe, args);
let stdout = "";
let stderr = "";
probeProcess.stdout.on("data", (data) => stdout += data);
probeProcess.stderr.on("data", (data) => stderr += data);
probeProcess.on("exit", (exitCode) => {
if (exitCode !== 0) {
return reject(new Error("Exit code: " + exitCode + "\n" + stderr));
}
result[m[7]] = {
d: m[1] != ".",
e: m[2] != ".",
t: m[3] == "." && null || m[3],
i: m[4] != ".",
l: m[5] != ".",
s: m[6] != ".",
_: m[8]
};
});
return result;
});
},
// In test suite
"formats": () => {
return ExecConverter(["-formats"])
.then((out) => {
let lines = out.split("\n");
let result = {};
lines.forEach((line) => {
let m = /^\s*(\.| |D)(\.| |E)\s+([^\s]+)\s+(.*?)\s*$/.exec(line);
if (!m || m[3] === '=') {
return;
if (json) {
// FIXME: not parsed?
resolve(stdout);
} else {
let info = {};
let m = /([0-9]{2,})x([0-9]{2,})/g.exec(stderr);
if (m) {
info.width = parseInt(m[1]);
info.height = parseInt(m[2]);
}
m = /Duration: ([0-9]{2}):([0-9]{2}):([0-9]{2})\.([0-9]{2})/g.exec(stderr);
if (m) {
info.duration = parseInt(m[1]) * 3600 + parseInt(m[2]) * 60 + parseInt(m[3]);
}
m = /Video:\s+([^\s\(,]+)/g.exec(stderr);
if (m) {
info.videoCodec = m[1];
}
m = /Audio:\s+([^\s\(,]+)/g.exec(stderr);
if (m) {
info.audioCodec = m[1];
}
m = /([0-9]+(?:\.[0-9]+)?)\s+fps\b/g.exec(stderr);
if (m) {
info.fps = parseFloat(m[1]);
}
resolve(info);
}
result[m[3]] = {
d: m[1] == "D",
e: m[2] == "E",
_: m[4]
};
});
return result;
});
},
// In test suite, but just to check if not throwing.
"open": (filePath, options = {}) => {
return open(filePath, options);
},
},
// FIXME: test (partly because open result is untested)
"play": (filePath) => {
return new Promise((resolve, _reject) => {
open(filePath);
resolve();
});
},
// In test suite
"codecs": () => {
return ExecConverter(["-codecs"])
.then((out) => {
let lines = out.split("\n");
let result = {};
lines.forEach((line) => {
let m = /^\s*(\.|D)(\.|E)(\.|V|A|S)(\.|I)(\.|L)(\.|S)\s+([^\s]+)\s+(.*?)\s*$/.exec(line);
if (!m || m[7] === '=') {
return;
}
result[m[7]] = {
d: m[1] != ".",
e: m[2] != ".",
t: m[3] == "." && null || m[3],
i: m[4] != ".",
l: m[5] != ".",
s: m[6] != ".",
_: m[8]
};
});
return result;
});
},
// In test suite
"formats": () => {
return ExecConverter(["-formats"])
.then((out) => {
let lines = out.split("\n");
let result = {};
lines.forEach((line) => {
let m = /^\s*(\.| |D)(\.| |E)\s+([^\s]+)\s+(.*?)\s*$/.exec(line);
if (!m || m[3] === '=') {
return;
}
result[m[3]] = {
d: m[1] == "D",
e: m[2] == "E",
_: m[4]
};
});
return result;
});
},
// In test suite, but just to check if not throwing.
"open": (filePath, options = {}) => {
return open(filePath, options);
},

});
});
};

exports.info = () => {
return new Promise((resolve, reject) => {
Expand Down
Loading

0 comments on commit aa204c6

Please sign in to comment.