Skip to content

Commit 3e6a32e

Browse files
committed
Merge branch 'PaulKinlan-fix-parser'
2 parents 92df53a + 13b8c90 commit 3e6a32e

File tree

5 files changed

+95
-1
lines changed

5 files changed

+95
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
node_modules
22
dist
33
/.nyc_output
4+
.DS_Store

src/createFFmpeg.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const { setLogging, log } = require('./utils/log');
33
const resolvePaths = require('./utils/resolvePaths');
44
const parseProgress = require('./utils/parseProgress');
55
const stringList2pointer = require('./utils/stringList2pointer');
6+
const parseArgs = require('./utils/parseArgs');
67
const {
78
defaultOptions,
89
getModule,
@@ -92,7 +93,7 @@ module.exports = (_options = {}) => {
9293
} else {
9394
running = true;
9495
return new Promise((resolve) => {
95-
const args = [...defaultArgs, ..._args.trim().split(' ')].filter((s) => s.length !== 0);
96+
const args = [...defaultArgs, ...parseArgs(_args)].filter((s) => s.length !== 0);
9697
log('info', `ffmpeg command: ${args.join(' ')}`);
9798
runResolve = resolve;
9899
ffmpeg(args.length, stringList2pointer(Module, args));

src/utils/parseArgs.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
module.exports = (cmd) => {
2+
const args = [];
3+
let nextDelimiter = 0;
4+
let prevDelimiter = 0;
5+
// eslint-disable-next-line no-cond-assign
6+
while ((nextDelimiter = cmd.indexOf(' ', prevDelimiter)) >= 0) {
7+
let arg = cmd.substring(prevDelimiter, nextDelimiter);
8+
let quoteIdx = arg.indexOf('\'');
9+
let dblQuoteIdx = arg.indexOf('"');
10+
11+
if (quoteIdx === 0 || dblQuoteIdx === 0) {
12+
/* The argument has a quote at the start i.e, 'id=0,streams=0 id=1,streams=1' */
13+
const delimiter = arg[0];
14+
const endDelimiter = cmd.indexOf(delimiter, prevDelimiter + 1);
15+
16+
if (endDelimiter < 0) {
17+
throw new Error(`Bad command escape sequence ${delimiter} near ${nextDelimiter}`);
18+
}
19+
20+
arg = cmd.substring(prevDelimiter + 1, endDelimiter);
21+
prevDelimiter = endDelimiter + 2;
22+
args.push(arg);
23+
} else if (quoteIdx > 0 || dblQuoteIdx > 0) {
24+
/* The argument has a quote in it, it must be ended correctly i,e. title='test' */
25+
if (quoteIdx === -1) quoteIdx = Infinity;
26+
if (dblQuoteIdx === -1) dblQuoteIdx = Infinity;
27+
const delimiter = (quoteIdx < dblQuoteIdx) ? '\'' : '"';
28+
const quoteOffset = Math.min(quoteIdx, dblQuoteIdx);
29+
const endDelimiter = cmd.indexOf(delimiter, prevDelimiter + quoteOffset + 1);
30+
31+
if (endDelimiter < 0) {
32+
throw new Error(`Bad command escape sequence ${delimiter} near ${nextDelimiter}`);
33+
}
34+
35+
arg = cmd.substring(prevDelimiter, endDelimiter + 1);
36+
prevDelimiter = endDelimiter + 2;
37+
args.push(arg);
38+
} else if (arg !== '') {
39+
args.push(arg);
40+
prevDelimiter = nextDelimiter + 1;
41+
} else {
42+
prevDelimiter = nextDelimiter + 1;
43+
}
44+
}
45+
46+
if (prevDelimiter !== cmd.length) {
47+
args.push(cmd.substring(prevDelimiter));
48+
}
49+
50+
return args;
51+
};

tests/constants.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,18 @@ const IS_BROWSER = typeof window !== 'undefined' && typeof window.document !== '
44
const OPTIONS = {
55
corePath: 'http://localhost:3000/node_modules/@ffmpeg/core/ffmpeg-core.js',
66
};
7+
const FLAME_MP4_LENGTH = 100374;
8+
const META_FLAME_MP4_LENGTH = 100408;
9+
const META_FLAME_MP4_LENGTH_NO_SPACE = 100404;
710

811
if (typeof module !== 'undefined') {
912
module.exports = {
1013
TIMEOUT,
1114
BASE_URL,
1215
IS_BROWSER,
1316
OPTIONS,
17+
FLAME_MP4_LENGTH,
18+
META_FLAME_MP4_LENGTH,
19+
META_FLAME_MP4_LENGTH_NO_SPACE,
1420
};
1521
}

tests/ffmpeg.test.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,38 @@ describe('transcode()', () => {
2525
});
2626
});
2727
});
28+
29+
describe('run()', () => {
30+
describe('should run a command with quoted parameters at start no spaces', () => {
31+
['flame.avi'].forEach((name) => (
32+
it(`run ${name}`, async () => {
33+
await ffmpeg.write(name, `${BASE_URL}/${name}`);
34+
await ffmpeg.run(`-y -i ${name} -metadata 'title="test"' output.mp4`);
35+
const data = ffmpeg.read('output.mp4');
36+
expect(data.length).to.be(META_FLAME_MP4_LENGTH_NO_SPACE);
37+
}).timeout(TIMEOUT)
38+
));
39+
});
40+
41+
describe('should run a command with quoted parameters at start and a space in between', () => {
42+
['flame.avi'].forEach((name) => (
43+
it(`run ${name}`, async () => {
44+
await ffmpeg.write(name, `${BASE_URL}/${name}`);
45+
await ffmpeg.run(`-y -i ${name} -metadata 'title="my title"' output.mp4`);
46+
const data = ffmpeg.read('output.mp4');
47+
expect(data.length).to.be(META_FLAME_MP4_LENGTH);
48+
}).timeout(TIMEOUT)
49+
));
50+
});
51+
52+
describe('should run a command with name quoted parameters and a space in between', () => {
53+
['flame.avi'].forEach((name) => (
54+
it(`run ${name}`, async () => {
55+
await ffmpeg.write(name, `${BASE_URL}/${name}`);
56+
await ffmpeg.run(`-y -i ${name} -metadata title="my title" output.mp4`);
57+
const data = ffmpeg.read('output.mp4');
58+
expect(data.length).to.be(META_FLAME_MP4_LENGTH);
59+
}).timeout(TIMEOUT)
60+
));
61+
});
62+
});

0 commit comments

Comments
 (0)