@remotion/renderer 3.2.24 → 3.2.26-crf.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/browser/BrowserRunner.d.ts +1 -4
  2. package/dist/browser/BrowserRunner.js +28 -71
  3. package/dist/browser/LaunchOptions.d.ts +0 -4
  4. package/dist/browser/Launcher.d.ts +1 -1
  5. package/dist/browser/Launcher.js +5 -363
  6. package/dist/browser/PuppeteerNode.js +1 -4
  7. package/dist/browser/create-browser-fetcher.js +2 -44
  8. package/dist/browser/revisions.d.ts +0 -1
  9. package/dist/browser/revisions.js +0 -1
  10. package/dist/check-apple-silicon.d.ts +1 -0
  11. package/dist/check-apple-silicon.js +51 -0
  12. package/dist/combine-videos.js +1 -1
  13. package/dist/convert-to-positive-frame-index.d.ts +4 -0
  14. package/dist/convert-to-positive-frame-index.js +8 -0
  15. package/dist/ffmpeg-args-hook.d.ts +4 -0
  16. package/dist/ffmpeg-args-hook.js +2 -0
  17. package/dist/ffmpeg-flags.d.ts +1 -2
  18. package/dist/ffmpeg-flags.js +1 -5
  19. package/dist/get-local-browser-executable.js +1 -3
  20. package/dist/index.d.ts +7 -4
  21. package/dist/index.js +8 -3
  22. package/dist/make-assets-download-dir.d.ts +1 -0
  23. package/dist/make-assets-download-dir.js +13 -0
  24. package/dist/open-browser.js +1 -11
  25. package/dist/render-media.d.ts +1 -0
  26. package/dist/render-media.js +10 -3
  27. package/dist/render-still.d.ts +1 -1
  28. package/dist/render-still.js +8 -3
  29. package/dist/set-props-and-env.js +1 -1
  30. package/dist/validate-ffmpeg-args-hook.d.ts +2 -0
  31. package/dist/validate-ffmpeg-args-hook.js +12 -0
  32. package/dist/validate-ffmpeg-override-fn.d.ts +2 -0
  33. package/dist/validate-ffmpeg-override-fn.js +12 -0
  34. package/dist/validate-frame.js +3 -3
  35. package/dist/validate-puppeteer-timeout.js +1 -1
  36. package/package.json +3 -3
@@ -17,17 +17,14 @@
17
17
  import * as childProcess from 'child_process';
18
18
  import { Connection } from './Connection';
19
19
  import type { LaunchOptions } from './LaunchOptions';
20
- import type { Product } from './Product';
21
20
  export declare class BrowserRunner {
22
21
  #private;
23
22
  proc?: childProcess.ChildProcess;
24
23
  connection?: Connection;
25
- constructor({ product, executablePath, processArguments, userDataDir, isTempUserDataDir, }: {
26
- product: Product;
24
+ constructor({ executablePath, processArguments, userDataDir, }: {
27
25
  executablePath: string;
28
26
  processArguments: string[];
29
27
  userDataDir: string;
30
- isTempUserDataDir?: boolean;
31
28
  });
32
29
  start(options: LaunchOptions): void;
33
30
  close(): Promise<void>;
@@ -48,45 +48,37 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
48
48
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
49
49
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
50
50
  };
51
- var _BrowserRunner_product, _BrowserRunner_executablePath, _BrowserRunner_processArguments, _BrowserRunner_userDataDir, _BrowserRunner_isTempUserDataDir, _BrowserRunner_closed, _BrowserRunner_listeners, _BrowserRunner_processClosing;
51
+ var _BrowserRunner_executablePath, _BrowserRunner_processArguments, _BrowserRunner_userDataDir, _BrowserRunner_closed, _BrowserRunner_listeners, _BrowserRunner_processClosing;
52
52
  Object.defineProperty(exports, "__esModule", { value: true });
53
53
  exports.BrowserRunner = void 0;
54
54
  const childProcess = __importStar(require("child_process"));
55
55
  const fs = __importStar(require("fs"));
56
- const path = __importStar(require("path"));
57
56
  const readline = __importStar(require("readline"));
58
- const util_1 = require("util");
59
57
  const delete_directory_1 = require("../delete-directory");
60
58
  const assert_1 = require("./assert");
61
59
  const Connection_1 = require("./Connection");
62
60
  const Errors_1 = require("./Errors");
63
61
  const NodeWebSocketTransport_1 = require("./NodeWebSocketTransport");
64
- const util_2 = require("./util");
65
- const renameAsync = (0, util_1.promisify)(fs.rename);
66
- const unlinkAsync = (0, util_1.promisify)(fs.unlink);
62
+ const util_1 = require("./util");
67
63
  const PROCESS_ERROR_EXPLANATION = `Puppeteer was unable to kill the process which ran the browser binary.
68
64
  This means that, on future Puppeteer launches, Puppeteer might not be able to launch the browser.
69
65
  Please check your open processes and ensure that the browser processes that Puppeteer launched have been killed.
70
66
  If you think this is a bug, please report it on the Puppeteer issue tracker.`;
71
67
  class BrowserRunner {
72
- constructor({ product, executablePath, processArguments, userDataDir, isTempUserDataDir, }) {
73
- _BrowserRunner_product.set(this, void 0);
68
+ constructor({ executablePath, processArguments, userDataDir, }) {
74
69
  _BrowserRunner_executablePath.set(this, void 0);
75
70
  _BrowserRunner_processArguments.set(this, void 0);
76
71
  _BrowserRunner_userDataDir.set(this, void 0);
77
- _BrowserRunner_isTempUserDataDir.set(this, void 0);
78
72
  _BrowserRunner_closed.set(this, true);
79
73
  _BrowserRunner_listeners.set(this, []);
80
74
  _BrowserRunner_processClosing.set(this, void 0);
81
- __classPrivateFieldSet(this, _BrowserRunner_product, product, "f");
82
75
  __classPrivateFieldSet(this, _BrowserRunner_executablePath, executablePath, "f");
83
76
  __classPrivateFieldSet(this, _BrowserRunner_processArguments, processArguments, "f");
84
77
  __classPrivateFieldSet(this, _BrowserRunner_userDataDir, userDataDir, "f");
85
- __classPrivateFieldSet(this, _BrowserRunner_isTempUserDataDir, isTempUserDataDir, "f");
86
78
  }
87
79
  start(options) {
88
80
  var _a, _b;
89
- const { handleSIGINT, handleSIGTERM, handleSIGHUP, dumpio, env, pipe } = options;
81
+ const { dumpio, env, pipe } = options;
90
82
  let stdio;
91
83
  if (pipe) {
92
84
  if (dumpio) {
@@ -121,66 +113,33 @@ class BrowserRunner {
121
113
  this.proc.once('exit', async () => {
122
114
  __classPrivateFieldSet(this, _BrowserRunner_closed, true, "f");
123
115
  // Cleanup as processes exit.
124
- if (__classPrivateFieldGet(this, _BrowserRunner_isTempUserDataDir, "f")) {
125
- try {
116
+ try {
117
+ if (fs.existsSync(__classPrivateFieldGet(this, _BrowserRunner_userDataDir, "f"))) {
126
118
  await (0, delete_directory_1.deleteDirectory)(__classPrivateFieldGet(this, _BrowserRunner_userDataDir, "f"));
127
- fulfill();
128
- }
129
- catch (error) {
130
- reject(error);
131
- }
132
- }
133
- else {
134
- if (__classPrivateFieldGet(this, _BrowserRunner_product, "f") === 'firefox') {
135
- try {
136
- // When an existing user profile has been used remove the user
137
- // preferences file and restore possibly backuped preferences.
138
- await unlinkAsync(path.join(__classPrivateFieldGet(this, _BrowserRunner_userDataDir, "f"), 'user.js'));
139
- const prefsBackupPath = path.join(__classPrivateFieldGet(this, _BrowserRunner_userDataDir, "f"), 'prefs.js.puppeteer');
140
- if (fs.existsSync(prefsBackupPath)) {
141
- const prefsPath = path.join(__classPrivateFieldGet(this, _BrowserRunner_userDataDir, "f"), 'prefs.js');
142
- await unlinkAsync(prefsPath);
143
- await renameAsync(prefsBackupPath, prefsPath);
144
- }
145
- }
146
- catch (error) {
147
- reject(error);
148
- }
149
119
  }
150
120
  fulfill();
151
121
  }
122
+ catch (error) {
123
+ reject(error);
124
+ }
152
125
  });
153
126
  }), "f");
154
- __classPrivateFieldSet(this, _BrowserRunner_listeners, [(0, util_2.addEventListener)(process, 'exit', this.kill.bind(this))], "f");
155
- if (handleSIGINT) {
156
- __classPrivateFieldGet(this, _BrowserRunner_listeners, "f").push((0, util_2.addEventListener)(process, 'SIGINT', () => {
157
- this.kill();
158
- process.exit(130);
159
- }));
160
- }
161
- if (handleSIGTERM) {
162
- __classPrivateFieldGet(this, _BrowserRunner_listeners, "f").push((0, util_2.addEventListener)(process, 'SIGTERM', this.close.bind(this)));
163
- }
164
- if (handleSIGHUP) {
165
- __classPrivateFieldGet(this, _BrowserRunner_listeners, "f").push((0, util_2.addEventListener)(process, 'SIGHUP', this.close.bind(this)));
166
- }
127
+ __classPrivateFieldSet(this, _BrowserRunner_listeners, [(0, util_1.addEventListener)(process, 'exit', this.kill.bind(this))], "f");
128
+ __classPrivateFieldGet(this, _BrowserRunner_listeners, "f").push((0, util_1.addEventListener)(process, 'SIGINT', () => {
129
+ this.kill();
130
+ process.exit(130);
131
+ }));
132
+ __classPrivateFieldGet(this, _BrowserRunner_listeners, "f").push((0, util_1.addEventListener)(process, 'SIGTERM', this.close.bind(this)));
133
+ __classPrivateFieldGet(this, _BrowserRunner_listeners, "f").push((0, util_1.addEventListener)(process, 'SIGHUP', this.close.bind(this)));
167
134
  }
168
135
  close() {
169
136
  if (__classPrivateFieldGet(this, _BrowserRunner_closed, "f")) {
170
137
  return Promise.resolve();
171
138
  }
172
- if (__classPrivateFieldGet(this, _BrowserRunner_isTempUserDataDir, "f")) {
173
- this.kill();
174
- }
175
- else if (this.connection) {
176
- // Attempt to close the browser gracefully
177
- this.connection.send('Browser.close').catch(() => {
178
- this.kill();
179
- });
180
- }
139
+ this.kill();
181
140
  // Cleanup this listener last, as that makes sure the full callback runs. If we
182
141
  // perform this earlier, then the previous function calls would not happen.
183
- (0, util_2.removeEventListeners)(__classPrivateFieldGet(this, _BrowserRunner_listeners, "f"));
142
+ (0, util_1.removeEventListeners)(__classPrivateFieldGet(this, _BrowserRunner_listeners, "f"));
184
143
  return __classPrivateFieldGet(this, _BrowserRunner_processClosing, "f");
185
144
  }
186
145
  kill() {
@@ -217,19 +176,17 @@ class BrowserRunner {
217
176
  }
218
177
  }
219
178
  catch (error) {
220
- throw new Error(`${PROCESS_ERROR_EXPLANATION}\nError cause: ${(0, util_2.isErrorLike)(error) ? error.stack : error}`);
179
+ throw new Error(`${PROCESS_ERROR_EXPLANATION}\nError cause: ${(0, util_1.isErrorLike)(error) ? error.stack : error}`);
221
180
  }
222
181
  }
223
182
  // Attempt to remove temporary profile directory to avoid littering.
224
183
  try {
225
- if (__classPrivateFieldGet(this, _BrowserRunner_isTempUserDataDir, "f")) {
226
- fs.rmSync(__classPrivateFieldGet(this, _BrowserRunner_userDataDir, "f"), { recursive: true, force: true });
227
- }
184
+ fs.rmSync(__classPrivateFieldGet(this, _BrowserRunner_userDataDir, "f"), { recursive: true, force: true });
228
185
  }
229
186
  catch (error) { }
230
187
  // Cleanup this listener last, as that makes sure the full callback runs. If we
231
188
  // perform this earlier, then the previous function calls would not happen.
232
- (0, util_2.removeEventListeners)(__classPrivateFieldGet(this, _BrowserRunner_listeners, "f"));
189
+ (0, util_1.removeEventListeners)(__classPrivateFieldGet(this, _BrowserRunner_listeners, "f"));
233
190
  }
234
191
  async setupConnection(options) {
235
192
  (0, assert_1.assert)(this.proc, 'BrowserRunner not started.');
@@ -241,21 +198,21 @@ class BrowserRunner {
241
198
  }
242
199
  }
243
200
  exports.BrowserRunner = BrowserRunner;
244
- _BrowserRunner_product = new WeakMap(), _BrowserRunner_executablePath = new WeakMap(), _BrowserRunner_processArguments = new WeakMap(), _BrowserRunner_userDataDir = new WeakMap(), _BrowserRunner_isTempUserDataDir = new WeakMap(), _BrowserRunner_closed = new WeakMap(), _BrowserRunner_listeners = new WeakMap(), _BrowserRunner_processClosing = new WeakMap();
201
+ _BrowserRunner_executablePath = new WeakMap(), _BrowserRunner_processArguments = new WeakMap(), _BrowserRunner_userDataDir = new WeakMap(), _BrowserRunner_closed = new WeakMap(), _BrowserRunner_listeners = new WeakMap(), _BrowserRunner_processClosing = new WeakMap();
245
202
  function waitForWSEndpoint(browserProcess, timeout, preferredRevision) {
246
203
  (0, assert_1.assert)(browserProcess.stderr, '`browserProcess` does not have stderr.');
247
204
  const rl = readline.createInterface(browserProcess.stderr);
248
205
  let stderr = '';
249
206
  return new Promise((resolve, reject) => {
250
207
  const listeners = [
251
- (0, util_2.addEventListener)(rl, 'line', onLine),
252
- (0, util_2.addEventListener)(rl, 'close', () => {
208
+ (0, util_1.addEventListener)(rl, 'line', onLine),
209
+ (0, util_1.addEventListener)(rl, 'close', () => {
253
210
  return onClose();
254
211
  }),
255
- (0, util_2.addEventListener)(browserProcess, 'exit', () => {
212
+ (0, util_1.addEventListener)(browserProcess, 'exit', () => {
256
213
  return onClose();
257
214
  }),
258
- (0, util_2.addEventListener)(browserProcess, 'error', (error) => {
215
+ (0, util_1.addEventListener)(browserProcess, 'error', (error) => {
259
216
  return onClose(error);
260
217
  }),
261
218
  ];
@@ -289,7 +246,7 @@ function waitForWSEndpoint(browserProcess, timeout, preferredRevision) {
289
246
  if (timeoutId) {
290
247
  clearTimeout(timeoutId);
291
248
  }
292
- (0, util_2.removeEventListeners)(listeners);
249
+ (0, util_1.removeEventListeners)(listeners);
293
250
  }
294
251
  });
295
252
  }
@@ -298,7 +255,7 @@ function pidExists(pid) {
298
255
  return process.kill(pid, 0);
299
256
  }
300
257
  catch (error) {
301
- if ((0, util_2.isErrnoException)(error)) {
258
+ if ((0, util_1.isErrnoException)(error)) {
302
259
  if (error.code && error.code === 'ESRCH') {
303
260
  return false;
304
261
  }
@@ -24,14 +24,10 @@ export interface BrowserLaunchArgumentOptions {
24
24
  }
25
25
  export interface LaunchOptions {
26
26
  executablePath?: string;
27
- handleSIGINT?: boolean;
28
- handleSIGTERM?: boolean;
29
- handleSIGHUP?: boolean;
30
27
  timeout?: number;
31
28
  dumpio?: boolean;
32
29
  env?: Record<string, string | undefined>;
33
30
  pipe?: boolean;
34
31
  product?: Product;
35
- extraPrefsFirefox?: Record<string, unknown>;
36
32
  }
37
33
  export declare type PuppeteerNodeLaunchOptions = BrowserLaunchArgumentOptions & LaunchOptions & BrowserConnectOptions;
@@ -6,4 +6,4 @@ export interface ProductLauncher {
6
6
  executablePath: (path?: any) => string;
7
7
  product: Product;
8
8
  }
9
- export default function Launcher(preferredRevision: string, product?: string): ProductLauncher;
9
+ export default function Launcher(preferredRevision: string): ProductLauncher;
@@ -45,9 +45,7 @@ const assert_1 = require("./assert");
45
45
  const Browser_1 = require("./Browser");
46
46
  const BrowserFetcher_1 = require("./BrowserFetcher");
47
47
  const BrowserRunner_1 = require("./BrowserRunner");
48
- const copyFileAsync = fs.promises.copyFile;
49
48
  const mkdtempAsync = fs.promises.mkdtemp;
50
- const writeFileAsync = fs.promises.writeFile;
51
49
  const tmpDir = () => {
52
50
  return process.env.PUPPETEER_TMP_DIR || os.tmpdir();
53
51
  };
@@ -56,7 +54,7 @@ class ChromeLauncher {
56
54
  this._preferredRevision = preferredRevision;
57
55
  }
58
56
  async launch(options) {
59
- const { args = [], dumpio = false, executablePath, pipe = false, env = process.env, handleSIGINT = true, handleSIGTERM = true, handleSIGHUP = true, defaultViewport, timeout = 60000, debuggingPort, } = options;
57
+ const { args = [], dumpio = false, executablePath, pipe = false, env = process.env, defaultViewport, timeout = 60000, debuggingPort, } = options;
60
58
  const chromeArguments = args;
61
59
  if (!chromeArguments.some((argument) => {
62
60
  return argument.startsWith('--remote-debugging-');
@@ -69,19 +67,10 @@ class ChromeLauncher {
69
67
  chromeArguments.push(`--remote-debugging-port=${debuggingPort || 0}`);
70
68
  }
71
69
  }
72
- let isTempUserDataDir = true;
73
70
  // Check for the user data dir argument, which will always be set even
74
71
  // with a custom directory specified via the userDataDir option.
75
- let userDataDirIndex = chromeArguments.findIndex((arg) => {
76
- return arg.startsWith('--user-data-dir');
77
- });
78
- if (userDataDirIndex < 0) {
79
- chromeArguments.push(`--user-data-dir=${await mkdtempAsync(path.join(tmpDir(), 'puppeteer_dev_chrome_profile-'))}`);
80
- userDataDirIndex = chromeArguments.length - 1;
81
- }
82
- const userDataDir = chromeArguments[userDataDirIndex].split('=', 2)[1];
83
- (0, assert_1.assert)(typeof userDataDir === 'string', '`--user-data-dir` is malformed');
84
- isTempUserDataDir = false;
72
+ const userDataDir = await mkdtempAsync(path.join(tmpDir(), 'puppeteer_dev_chrome_profile-'));
73
+ chromeArguments.push(`--user-data-dir=${userDataDir}`);
85
74
  let chromeExecutable = executablePath;
86
75
  if (!chromeExecutable) {
87
76
  const { missingText, executablePath: exPath } = resolveExecutablePath(this);
@@ -91,16 +80,11 @@ class ChromeLauncher {
91
80
  chromeExecutable = exPath;
92
81
  }
93
82
  const runner = new BrowserRunner_1.BrowserRunner({
94
- product: this.product,
95
83
  executablePath: chromeExecutable,
96
84
  processArguments: chromeArguments,
97
85
  userDataDir,
98
- isTempUserDataDir,
99
86
  });
100
87
  runner.start({
101
- handleSIGHUP,
102
- handleSIGTERM,
103
- handleSIGINT,
104
88
  dumpio,
105
89
  env,
106
90
  pipe: false,
@@ -141,335 +125,6 @@ class ChromeLauncher {
141
125
  return 'chrome';
142
126
  }
143
127
  }
144
- class FirefoxLauncher {
145
- constructor(preferredRevision) {
146
- this._preferredRevision = preferredRevision;
147
- }
148
- async launch(options) {
149
- const { dumpio = false, executablePath = null, env = process.env, handleSIGINT = true, handleSIGTERM = true, handleSIGHUP = true, defaultViewport, timeout = 30000, extraPrefsFirefox = {}, debuggingPort = null, } = options;
150
- const firefoxArguments = [];
151
- firefoxArguments.push(...this.defaultArgs(options));
152
- if (!firefoxArguments.some((argument) => {
153
- return argument.startsWith('--remote-debugging-');
154
- })) {
155
- firefoxArguments.push(`--remote-debugging-port=${debuggingPort || 0}`);
156
- }
157
- let userDataDir;
158
- let isTempUserDataDir = true;
159
- // Check for the profile argument, which will always be set even
160
- // with a custom directory specified via the userDataDir option.
161
- const profileArgIndex = firefoxArguments.findIndex((arg) => {
162
- return ['-profile', '--profile'].includes(arg);
163
- });
164
- if (profileArgIndex === -1) {
165
- userDataDir = await this._createProfile(extraPrefsFirefox);
166
- firefoxArguments.push('--profile');
167
- firefoxArguments.push(userDataDir);
168
- }
169
- else {
170
- userDataDir = firefoxArguments[profileArgIndex + 1];
171
- if (!userDataDir || !fs.existsSync(userDataDir)) {
172
- throw new Error(`Firefox profile not found at '${userDataDir}'`);
173
- }
174
- // When using a custom Firefox profile it needs to be populated
175
- // with required preferences.
176
- isTempUserDataDir = false;
177
- const prefs = this.defaultPreferences(extraPrefsFirefox);
178
- this.writePreferences(prefs, userDataDir);
179
- }
180
- await this._updateRevision();
181
- let firefoxExecutable = executablePath;
182
- if (!executablePath) {
183
- const { missingText, executablePath: exPath } = resolveExecutablePath(this);
184
- if (missingText) {
185
- throw new Error(missingText);
186
- }
187
- firefoxExecutable = exPath;
188
- }
189
- if (!firefoxExecutable) {
190
- throw new Error('firefoxExecutable is not found.');
191
- }
192
- const runner = new BrowserRunner_1.BrowserRunner({
193
- product: this.product,
194
- executablePath: firefoxExecutable,
195
- processArguments: firefoxArguments,
196
- userDataDir,
197
- isTempUserDataDir,
198
- });
199
- runner.start({
200
- handleSIGHUP,
201
- handleSIGTERM,
202
- handleSIGINT,
203
- dumpio,
204
- env,
205
- });
206
- let browser;
207
- try {
208
- const connection = await runner.setupConnection({
209
- timeout,
210
- preferredRevision: this._preferredRevision,
211
- });
212
- browser = await Browser_1.Browser._create({
213
- connection,
214
- contextIds: [],
215
- defaultViewport,
216
- closeCallback: runner.close.bind(runner),
217
- });
218
- }
219
- catch (error) {
220
- runner.kill();
221
- throw error;
222
- }
223
- try {
224
- await browser.waitForTarget((t) => {
225
- return t.type() === 'page';
226
- }, { timeout });
227
- }
228
- catch (error) {
229
- await browser.close();
230
- throw error;
231
- }
232
- return browser;
233
- }
234
- executablePath() {
235
- return resolveExecutablePath(this).executablePath;
236
- }
237
- async _updateRevision() {
238
- // replace 'latest' placeholder with actual downloaded revision
239
- if (this._preferredRevision === 'latest') {
240
- const browserFetcher = new BrowserFetcher_1.BrowserFetcher({
241
- product: this.product,
242
- path: null,
243
- platform: null,
244
- });
245
- const localRevisions = await browserFetcher.localRevisions();
246
- if (localRevisions[0]) {
247
- this._preferredRevision = localRevisions[0];
248
- }
249
- }
250
- }
251
- get product() {
252
- return 'firefox';
253
- }
254
- defaultArgs(options) {
255
- const { devtools = false, headless = !devtools, args = [], userDataDir = null, } = options;
256
- const firefoxArguments = ['--no-remote'];
257
- if (os.platform() === 'darwin') {
258
- firefoxArguments.push('--foreground');
259
- }
260
- else if (os.platform().startsWith('win')) {
261
- firefoxArguments.push('--wait-for-browser');
262
- }
263
- if (userDataDir) {
264
- firefoxArguments.push('--profile');
265
- firefoxArguments.push(userDataDir);
266
- }
267
- if (headless) {
268
- firefoxArguments.push('--headless');
269
- }
270
- if (devtools) {
271
- firefoxArguments.push('--devtools');
272
- }
273
- if (args.every((arg) => {
274
- return arg.startsWith('-');
275
- })) {
276
- firefoxArguments.push('about:blank');
277
- }
278
- firefoxArguments.push(...args);
279
- return firefoxArguments;
280
- }
281
- defaultPreferences(extraPrefs) {
282
- const server = 'dummy.test';
283
- const defaultPrefs = {
284
- // Make sure Shield doesn't hit the network.
285
- 'app.normandy.api_url': '',
286
- // Disable Firefox old build background check
287
- 'app.update.checkInstallTime': false,
288
- // Disable automatically upgrading Firefox
289
- 'app.update.disabledForTesting': true,
290
- // Increase the APZ content response timeout to 1 minute
291
- 'apz.content_response_timeout': 60000,
292
- // Prevent various error message on the console
293
- // jest-puppeteer asserts that no error message is emitted by the console
294
- 'browser.contentblocking.features.standard': '-tp,tpPrivate,cookieBehavior0,-cm,-fp',
295
- // Enable the dump function: which sends messages to the system
296
- // console
297
- // https://bugzilla.mozilla.org/show_bug.cgi?id=1543115
298
- 'browser.dom.window.dump.enabled': true,
299
- // Disable topstories
300
- 'browser.newtabpage.activity-stream.feeds.system.topstories': false,
301
- // Always display a blank page
302
- 'browser.newtabpage.enabled': false,
303
- // Background thumbnails in particular cause grief: and disabling
304
- // thumbnails in general cannot hurt
305
- 'browser.pagethumbnails.capturing_disabled': true,
306
- // Disable safebrowsing components.
307
- 'browser.safebrowsing.blockedURIs.enabled': false,
308
- 'browser.safebrowsing.downloads.enabled': false,
309
- 'browser.safebrowsing.malware.enabled': false,
310
- 'browser.safebrowsing.passwords.enabled': false,
311
- 'browser.safebrowsing.phishing.enabled': false,
312
- // Disable updates to search engines.
313
- 'browser.search.update': false,
314
- // Do not restore the last open set of tabs if the browser has crashed
315
- 'browser.sessionstore.resume_from_crash': false,
316
- // Skip check for default browser on startup
317
- 'browser.shell.checkDefaultBrowser': false,
318
- // Disable newtabpage
319
- 'browser.startup.homepage': 'about:blank',
320
- // Do not redirect user when a milstone upgrade of Firefox is detected
321
- 'browser.startup.homepage_override.mstone': 'ignore',
322
- // Start with a blank page about:blank
323
- 'browser.startup.page': 0,
324
- // Do not allow background tabs to be zombified on Android: otherwise for
325
- // tests that open additional tabs: the test harness tab itself might get
326
- // unloaded
327
- 'browser.tabs.disableBackgroundZombification': false,
328
- // Do not warn when closing all other open tabs
329
- 'browser.tabs.warnOnCloseOtherTabs': false,
330
- // Do not warn when multiple tabs will be opened
331
- 'browser.tabs.warnOnOpen': false,
332
- // Disable the UI tour.
333
- 'browser.uitour.enabled': false,
334
- // Turn off search suggestions in the location bar so as not to trigger
335
- // network connections.
336
- 'browser.urlbar.suggest.searches': false,
337
- // Disable first run splash page on Windows 10
338
- 'browser.usedOnWindows10.introURL': '',
339
- // Do not warn on quitting Firefox
340
- 'browser.warnOnQuit': false,
341
- // Defensively disable data reporting systems
342
- 'datareporting.healthreport.documentServerURI': `http://${server}/dummy/healthreport/`,
343
- 'datareporting.healthreport.logging.consoleEnabled': false,
344
- 'datareporting.healthreport.service.enabled': false,
345
- 'datareporting.healthreport.service.firstRun': false,
346
- 'datareporting.healthreport.uploadEnabled': false,
347
- // Do not show datareporting policy notifications which can interfere with tests
348
- 'datareporting.policy.dataSubmissionEnabled': false,
349
- 'datareporting.policy.dataSubmissionPolicyBypassNotification': true,
350
- // DevTools JSONViewer sometimes fails to load dependencies with its require.js.
351
- // This doesn't affect Puppeteer but spams console (Bug 1424372)
352
- 'devtools.jsonview.enabled': false,
353
- // Disable popup-blocker
354
- 'dom.disable_open_during_load': false,
355
- // Enable the support for File object creation in the content process
356
- // Required for |Page.setFileInputFiles| protocol method.
357
- 'dom.file.createInChild': true,
358
- // Disable the ProcessHangMonitor
359
- 'dom.ipc.reportProcessHangs': false,
360
- // Disable slow script dialogues
361
- 'dom.max_chrome_script_run_time': 0,
362
- 'dom.max_script_run_time': 0,
363
- // Only load extensions from the application and user profile
364
- // AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
365
- 'extensions.autoDisableScopes': 0,
366
- 'extensions.enabledScopes': 5,
367
- // Disable metadata caching for installed add-ons by default
368
- 'extensions.getAddons.cache.enabled': false,
369
- // Disable installing any distribution extensions or add-ons.
370
- 'extensions.installDistroAddons': false,
371
- // Disabled screenshots extension
372
- 'extensions.screenshots.disabled': true,
373
- // Turn off extension updates so they do not bother tests
374
- 'extensions.update.enabled': false,
375
- // Turn off extension updates so they do not bother tests
376
- 'extensions.update.notifyUser': false,
377
- // Make sure opening about:addons will not hit the network
378
- 'extensions.webservice.discoverURL': `http://${server}/dummy/discoveryURL`,
379
- // Temporarily force disable BFCache in parent (https://bit.ly/bug-1732263)
380
- 'fission.bfcacheInParent': false,
381
- // Force all web content to use a single content process
382
- 'fission.webContentIsolationStrategy': 0,
383
- // Allow the application to have focus even it runs in the background
384
- 'focusmanager.testmode': true,
385
- // Disable useragent updates
386
- 'general.useragent.updates.enabled': false,
387
- // Always use network provider for geolocation tests so we bypass the
388
- // macOS dialog raised by the corelocation provider
389
- 'geo.provider.testing': true,
390
- // Do not scan Wifi
391
- 'geo.wifi.scan': false,
392
- // No hang monitor
393
- 'hangmonitor.timeout': 0,
394
- // Show chrome errors and warnings in the error console
395
- 'javascript.options.showInConsole': true,
396
- // Disable download and usage of OpenH264: and Widevine plugins
397
- 'media.gmp-manager.updateEnabled': false,
398
- // Prevent various error message on the console
399
- // jest-puppeteer asserts that no error message is emitted by the console
400
- 'network.cookie.cookieBehavior': 0,
401
- // Disable experimental feature that is only available in Nightly
402
- 'network.cookie.sameSite.laxByDefault': false,
403
- // Do not prompt for temporary redirects
404
- 'network.http.prompt-temp-redirect': false,
405
- // Disable speculative connections so they are not reported as leaking
406
- // when they are hanging around
407
- 'network.http.speculative-parallel-limit': 0,
408
- // Do not automatically switch between offline and online
409
- 'network.manage-offline-status': false,
410
- // Make sure SNTP requests do not hit the network
411
- 'network.sntp.pools': server,
412
- // Disable Flash.
413
- 'plugin.state.flash': 0,
414
- 'privacy.trackingprotection.enabled': false,
415
- // Can be removed once Firefox 89 is no longer supported
416
- // https://bugzilla.mozilla.org/show_bug.cgi?id=1710839
417
- 'remote.enabled': true,
418
- // Don't do network connections for mitm priming
419
- 'security.certerrors.mitm.priming.enabled': false,
420
- // Local documents have access to all other local documents,
421
- // including directory listings
422
- 'security.fileuri.strict_origin_policy': false,
423
- // Do not wait for the notification button security delay
424
- 'security.notification_enable_delay': 0,
425
- // Ensure blocklist updates do not hit the network
426
- 'services.settings.server': `http://${server}/dummy/blocklist/`,
427
- // Do not automatically fill sign-in forms with known usernames and
428
- // passwords
429
- 'signon.autofillForms': false,
430
- // Disable password capture, so that tests that include forms are not
431
- // influenced by the presence of the persistent doorhanger notification
432
- 'signon.rememberSignons': false,
433
- // Disable first-run welcome page
434
- 'startup.homepage_welcome_url': 'about:blank',
435
- // Disable first-run welcome page
436
- 'startup.homepage_welcome_url.additional': '',
437
- // Disable browser animations (tabs, fullscreen, sliding alerts)
438
- 'toolkit.cosmeticAnimations.enabled': false,
439
- // Prevent starting into safe mode after application crashes
440
- 'toolkit.startup.max_resumed_crashes': -1,
441
- };
442
- return Object.assign(defaultPrefs, extraPrefs);
443
- }
444
- /**
445
- * Populates the user.js file with custom preferences as needed to allow
446
- * Firefox's CDP support to properly function. These preferences will be
447
- * automatically copied over to prefs.js during startup of Firefox. To be
448
- * able to restore the original values of preferences a backup of prefs.js
449
- * will be created.
450
- *
451
- * @param prefs - List of preferences to add.
452
- * @param profilePath - Firefox profile to write the preferences to.
453
- */
454
- async writePreferences(prefs, profilePath) {
455
- const lines = Object.entries(prefs).map(([key, value]) => {
456
- return `user_pref(${JSON.stringify(key)}, ${JSON.stringify(value)});`;
457
- });
458
- await writeFileAsync(path.join(profilePath, 'user.js'), lines.join('\n'));
459
- // Create a backup of the preferences file if it already exitsts.
460
- const prefsPath = path.join(profilePath, 'prefs.js');
461
- if (fs.existsSync(prefsPath)) {
462
- const prefsBackupPath = path.join(profilePath, 'prefs.js.puppeteer');
463
- await copyFileAsync(prefsPath, prefsBackupPath);
464
- }
465
- }
466
- async _createProfile(extraPrefs) {
467
- const temporaryProfilePath = await mkdtempAsync(path.join(tmpDir(), 'puppeteer_dev_firefox_profile-'));
468
- const prefs = this.defaultPreferences(extraPrefs);
469
- await this.writePreferences(prefs, temporaryProfilePath);
470
- return temporaryProfilePath;
471
- }
472
- }
473
128
  function resolveExecutablePath(launcher) {
474
129
  const { product, _preferredRevision } = launcher;
475
130
  const browserFetcher = new BrowserFetcher_1.BrowserFetcher({
@@ -485,20 +140,7 @@ function resolveExecutablePath(launcher) {
485
140
  : `Could not find expected browser (${product}) locally. ${product === 'chrome' ? chromeHelp : firefoxHelp}`;
486
141
  return { executablePath: revisionInfo.executablePath, missingText };
487
142
  }
488
- function Launcher(preferredRevision, product) {
489
- switch (product) {
490
- case 'firefox':
491
- return new FirefoxLauncher(preferredRevision);
492
- case 'chrome':
493
- default:
494
- if (typeof product !== 'undefined' && product !== 'chrome') {
495
- /* The user gave us an incorrect product name
496
- * we'll default to launching Chrome, but log to the console
497
- * to let the user know (they've probably typoed).
498
- */
499
- console.warn(`Warning: unknown product name ${product}. Falling back to chrome.`);
500
- }
501
- return new ChromeLauncher(preferredRevision);
502
- }
143
+ function Launcher(preferredRevision) {
144
+ return new ChromeLauncher(preferredRevision);
503
145
  }
504
146
  exports.default = Launcher;
@@ -58,15 +58,12 @@ class PuppeteerNode {
58
58
  if (!__classPrivateFieldGet(this, _PuppeteerNode_lazyLauncher, "f") ||
59
59
  __classPrivateFieldGet(this, _PuppeteerNode_lazyLauncher, "f").product !== __classPrivateFieldGet(this, _PuppeteerNode_productName, "f")) {
60
60
  switch (__classPrivateFieldGet(this, _PuppeteerNode_productName, "f")) {
61
- case 'firefox':
62
- this._preferredRevision = revisions_1.PUPPETEER_REVISIONS.firefox;
63
- break;
64
61
  case 'chrome':
65
62
  default:
66
63
  this._preferredRevision = revisions_1.PUPPETEER_REVISIONS.chromium;
67
64
  }
68
65
  // eslint-disable-next-line new-cap
69
- __classPrivateFieldSet(this, _PuppeteerNode_lazyLauncher, (0, Launcher_1.default)(this._preferredRevision, __classPrivateFieldGet(this, _PuppeteerNode_productName, "f")), "f");
66
+ __classPrivateFieldSet(this, _PuppeteerNode_lazyLauncher, (0, Launcher_1.default)(this._preferredRevision), "f");
70
67
  }
71
68
  return __classPrivateFieldGet(this, _PuppeteerNode_lazyLauncher, "f");
72
69
  }
@@ -14,12 +14,8 @@
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
16
  */
17
- var __importDefault = (this && this.__importDefault) || function (mod) {
18
- return (mod && mod.__esModule) ? mod : { "default": mod };
19
- };
20
17
  Object.defineProperty(exports, "__esModule", { value: true });
21
18
  exports.downloadBrowser = void 0;
22
- const https_1 = __importDefault(require("https"));
23
19
  const node_1 = require("./node");
24
20
  const revisions_1 = require("./revisions");
25
21
  const supportedProducts = {
@@ -34,19 +30,9 @@ async function downloadBrowser(product) {
34
30
  });
35
31
  const revision = await getRevision();
36
32
  await fetchBinary(revision);
37
- async function getRevision() {
33
+ function getRevision() {
38
34
  if (product === 'chrome') {
39
- return Promise.resolve(revisions_1.PUPPETEER_REVISIONS.chromium);
40
- }
41
- if (product === 'firefox') {
42
- node_1.puppeteer._preferredRevision = revisions_1.PUPPETEER_REVISIONS.firefox;
43
- try {
44
- return await getFirefoxNightlyVersion();
45
- }
46
- catch (error) {
47
- console.error(error);
48
- process.exit(1);
49
- }
35
+ return revisions_1.PUPPETEER_REVISIONS.chromium;
50
36
  }
51
37
  throw new Error(`Unsupported product ${product}`);
52
38
  }
@@ -87,33 +73,5 @@ async function downloadBrowser(product) {
87
73
  const mb = bytes / 1024 / 1024;
88
74
  return `${Math.round(mb * 10) / 10} Mb`;
89
75
  }
90
- function getFirefoxNightlyVersion() {
91
- const firefoxVersionsUrl = 'https://product-details.mozilla.org/1.0/firefox_versions.json';
92
- const requestOptions = {};
93
- const promise = new Promise((resolve, reject) => {
94
- let data = '';
95
- console.log(`Requesting latest Firefox Nightly version from ${firefoxVersionsUrl}`);
96
- https_1.default
97
- .get(firefoxVersionsUrl, requestOptions, (r) => {
98
- if (r.statusCode && r.statusCode >= 400) {
99
- return reject(new Error(`Got status code ${r.statusCode}`));
100
- }
101
- r.on('data', (chunk) => {
102
- data += chunk;
103
- });
104
- r.on('end', () => {
105
- try {
106
- const versions = JSON.parse(data);
107
- return resolve(versions.FIREFOX_NIGHTLY);
108
- }
109
- catch (_a) {
110
- return reject(new Error('Firefox version not found'));
111
- }
112
- });
113
- })
114
- .on('error', reject);
115
- });
116
- return promise;
117
- }
118
76
  }
119
77
  exports.downloadBrowser = downloadBrowser;
@@ -15,7 +15,6 @@
15
15
  */
16
16
  declare type Revisions = Readonly<{
17
17
  readonly chromium: string;
18
- readonly firefox: string;
19
18
  }>;
20
19
  export declare const PUPPETEER_REVISIONS: Revisions;
21
20
  export {};
@@ -18,5 +18,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.PUPPETEER_REVISIONS = void 0;
19
19
  exports.PUPPETEER_REVISIONS = {
20
20
  chromium: '1002410',
21
- firefox: 'latest',
22
21
  };
@@ -0,0 +1 @@
1
+ export declare const warnIfAppleSiliconIsNotUsingArm64Architecture: () => void;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.warnIfAppleSiliconIsNotUsingArm64Architecture = void 0;
27
+ const os = __importStar(require("os"));
28
+ const warnIfAppleSiliconIsNotUsingArm64Architecture = () => {
29
+ // see https://github.com/nodejs/node/issues/41900#issuecomment-1113511254
30
+ const cpus = os.cpus();
31
+ const isAppleSilicon = cpus[0].model.includes('Apple');
32
+ const isArm64 = os.arch() === 'arm64';
33
+ if (isAppleSilicon && !isArm64) {
34
+ const recommendedNodeVersion = 16;
35
+ const version = process.version.replace('v', '').split('.');
36
+ const majorVersion = Number(version[0]);
37
+ const recommendNodeUpgrade = majorVersion < recommendedNodeVersion;
38
+ console.warn([
39
+ `⚠️ Apple Silicon detected but Node.JS running under Rosetta. This will cause performance issues.\n`,
40
+ `Recommended actions:\n`,
41
+ recommendNodeUpgrade
42
+ ? ` - Upgrade to Node ${recommendedNodeVersion} or later\n`
43
+ : ' - Run Node using `arch -arm64` architecture\n',
44
+ 'See https://remotion.dev/docs/troubleshooting/rosetta for more information.',
45
+ '---',
46
+ ]
47
+ .filter(Boolean)
48
+ .join('\n'));
49
+ }
50
+ };
51
+ exports.warnIfAppleSiliconIsNotUsingArm64Architecture = warnIfAppleSiliconIsNotUsingArm64Architecture;
@@ -37,7 +37,7 @@ const combineVideos = async ({ files, filelistDir, output, onProgress, numberOfF
37
37
  (0, is_audio_codec_1.isAudioCodec)(codec) ? null : codec === 'gif' ? 'gif' : 'copy',
38
38
  '-c:a',
39
39
  (0, get_audio_codec_name_1.getAudioCodecName)(codec),
40
- // Set max bitrate up to 1024kbps, will choose lower if that's too much
40
+ // Set max bitrate up to 512kbps, will choose lower if that's too much
41
41
  '-b:a',
42
42
  '512K',
43
43
  codec === 'h264' ? '-movflags' : null,
@@ -0,0 +1,4 @@
1
+ export declare const convertToPositiveFrameIndex: ({ frame, durationInFrames, }: {
2
+ frame: number;
3
+ durationInFrames: number;
4
+ }) => number;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertToPositiveFrameIndex = void 0;
4
+ // Handle negative indices (e.g. -1 being the last frame)
5
+ const convertToPositiveFrameIndex = ({ frame, durationInFrames, }) => {
6
+ return frame < 0 ? durationInFrames - frame : frame;
7
+ };
8
+ exports.convertToPositiveFrameIndex = convertToPositiveFrameIndex;
@@ -0,0 +1,4 @@
1
+ export declare type FfmpegArgsHook = (info: {
2
+ type: 'pre-stitcher' | 'stitcher';
3
+ args: string[];
4
+ }) => string[];
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -2,10 +2,9 @@ export declare type FfmpegVersion = [number, number, number] | null;
2
2
  export declare const getFfmpegBuildInfo: (options: {
3
3
  ffmpegExecutable: string | null;
4
4
  }) => Promise<string>;
5
- export declare const ffmpegHasFeature: ({ ffmpegExecutable, feature, isLambda, }: {
5
+ export declare const ffmpegHasFeature: ({ ffmpegExecutable, feature, }: {
6
6
  ffmpegExecutable: string | null;
7
7
  feature: 'enable-gpl' | 'enable-libx265' | 'enable-libvpx';
8
- isLambda: boolean;
9
8
  }) => Promise<boolean>;
10
9
  export declare const parseFfmpegVersion: (buildconf: string) => FfmpegVersion;
11
10
  export declare const getFfmpegVersion: (options: {
@@ -19,11 +19,7 @@ const getFfmpegBuildInfo = async (options) => {
19
19
  return buildConfig;
20
20
  };
21
21
  exports.getFfmpegBuildInfo = getFfmpegBuildInfo;
22
- const ffmpegHasFeature = async ({ ffmpegExecutable, feature, isLambda, }) => {
23
- if (isLambda) {
24
- // When rendering in the cloud, we don't need a local binary
25
- return true;
26
- }
22
+ const ffmpegHasFeature = async ({ ffmpegExecutable, feature, }) => {
27
23
  if (!(await (0, validate_ffmpeg_1.binaryExists)('ffmpeg', ffmpegExecutable))) {
28
24
  return false;
29
25
  }
@@ -49,9 +49,7 @@ const getBrowserRevision = (product) => {
49
49
  path: null,
50
50
  platform: null,
51
51
  });
52
- const revisionInfo = browserFetcher.revisionInfo(product === 'firefox'
53
- ? revisions_1.PUPPETEER_REVISIONS.firefox
54
- : revisions_1.PUPPETEER_REVISIONS.chromium);
52
+ const revisionInfo = browserFetcher.revisionInfo(revisions_1.PUPPETEER_REVISIONS.chromium);
55
53
  return revisionInfo;
56
54
  };
57
55
  const getBrowserStatus = (product, browserExecutablePath) => {
package/dist/index.d.ts CHANGED
@@ -26,17 +26,17 @@ export { PixelFormat } from './pixel-format';
26
26
  export { ProResProfile } from './prores-profile';
27
27
  export { renderFrames } from './render-frames';
28
28
  export { renderMedia, RenderMediaOnProgress, RenderMediaOptions, StitchingState, } from './render-media';
29
- export { renderStill } from './render-still';
29
+ export { renderStill, RenderStillOptions } from './render-still';
30
30
  export { StitcherOptions, stitchFramesToVideo } from './stitch-frames-to-video';
31
31
  export { SymbolicatedStackFrame } from './symbolicate-stacktrace';
32
32
  export { OnStartData, RenderFramesOutput } from './types';
33
33
  export { OpenGlRenderer } from './validate-opengl-renderer';
34
+ export { validateOutputFilename } from './validate-output-filename';
34
35
  export declare const RenderInternals: {
35
36
  ensureLocalBrowser: (browser: import("./browser").Browser, preferredBrowserExecutable: import("./browser-executable").BrowserExecutable) => Promise<void>;
36
- ffmpegHasFeature: ({ ffmpegExecutable, feature, isLambda, }: {
37
+ ffmpegHasFeature: ({ ffmpegExecutable, feature, }: {
37
38
  ffmpegExecutable: string | null;
38
39
  feature: "enable-gpl" | "enable-libx265" | "enable-libvpx";
39
- isLambda: boolean;
40
40
  }) => Promise<boolean>;
41
41
  getActualConcurrency: (userPreference: number | null) => number;
42
42
  getFfmpegVersion: (options: {
@@ -130,7 +130,6 @@ export declare const RenderInternals: {
130
130
  validateSelectedCrfAndCodecCombination: (crf: unknown, codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif") => void;
131
131
  validImageFormats: readonly ["png", "jpeg", "none"];
132
132
  validCodecs: readonly ["h264", "h265", "vp8", "vp9", "mp3", "aac", "wav", "prores", "h264-mkv", "gif"];
133
- DEFAULT_OVERWRITE: boolean;
134
133
  DEFAULT_PIXEL_FORMAT: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le";
135
134
  validateQuality: (q: number | undefined) => void;
136
135
  validateFrame: (frame: number, durationInFrames: number) => void;
@@ -148,4 +147,8 @@ export declare const RenderInternals: {
148
147
  perf: typeof perf;
149
148
  makeDownloadMap: () => import("./assets/download-map").DownloadMap;
150
149
  cleanDownloadMap: (downloadMap: import("./assets/download-map").DownloadMap) => Promise<void>;
150
+ convertToPositiveFrameIndex: ({ frame, durationInFrames, }: {
151
+ frame: number;
152
+ durationInFrames: number;
153
+ }) => number;
151
154
  };
package/dist/index.js CHANGED
@@ -26,14 +26,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.RenderInternals = exports.stitchFramesToVideo = exports.renderStill = exports.renderMedia = exports.renderFrames = exports.openBrowser = exports.makeCancelSignal = exports.validImageFormats = exports.validateSelectedPixelFormatAndImageFormatCombination = exports.getCompositions = exports.ErrorWithStackFrame = exports.combineVideos = void 0;
29
+ exports.RenderInternals = exports.validateOutputFilename = exports.stitchFramesToVideo = exports.renderStill = exports.renderMedia = exports.renderFrames = exports.openBrowser = exports.makeCancelSignal = exports.validImageFormats = exports.validateSelectedPixelFormatAndImageFormatCombination = exports.getCompositions = exports.ErrorWithStackFrame = exports.combineVideos = void 0;
30
30
  const execa_1 = __importDefault(require("execa"));
31
31
  const download_file_1 = require("./assets/download-file");
32
32
  const download_map_1 = require("./assets/download-map");
33
33
  const browser_1 = require("./browser");
34
34
  const TimeoutSettings_1 = require("./browser/TimeoutSettings");
35
35
  const can_use_parallel_encoding_1 = require("./can-use-parallel-encoding");
36
+ const check_apple_silicon_1 = require("./check-apple-silicon");
36
37
  const codec_1 = require("./codec");
38
+ const convert_to_positive_frame_index_1 = require("./convert-to-positive-frame-index");
37
39
  const crf_1 = require("./crf");
38
40
  const delete_directory_1 = require("./delete-directory");
39
41
  const ensure_output_directory_1 = require("./ensure-output-directory");
@@ -55,7 +57,6 @@ const log_level_1 = require("./log-level");
55
57
  const mime_types_1 = require("./mime-types");
56
58
  const normalize_serve_url_1 = require("./normalize-serve-url");
57
59
  const open_browser_1 = require("./open-browser");
58
- const overwrite_1 = require("./overwrite");
59
60
  const parse_browser_error_stack_1 = require("./parse-browser-error-stack");
60
61
  const perf = __importStar(require("./perf"));
61
62
  const pixel_format_1 = require("./pixel-format");
@@ -95,6 +96,8 @@ var render_still_1 = require("./render-still");
95
96
  Object.defineProperty(exports, "renderStill", { enumerable: true, get: function () { return render_still_1.renderStill; } });
96
97
  var stitch_frames_to_video_2 = require("./stitch-frames-to-video");
97
98
  Object.defineProperty(exports, "stitchFramesToVideo", { enumerable: true, get: function () { return stitch_frames_to_video_2.stitchFramesToVideo; } });
99
+ var validate_output_filename_1 = require("./validate-output-filename");
100
+ Object.defineProperty(exports, "validateOutputFilename", { enumerable: true, get: function () { return validate_output_filename_1.validateOutputFilename; } });
98
101
  exports.RenderInternals = {
99
102
  ensureLocalBrowser: get_local_browser_executable_1.ensureLocalBrowser,
100
103
  ffmpegHasFeature: ffmpeg_flags_1.ffmpegHasFeature,
@@ -140,7 +143,6 @@ exports.RenderInternals = {
140
143
  validateSelectedCrfAndCodecCombination: crf_1.validateSelectedCrfAndCodecCombination,
141
144
  validImageFormats: image_format_1.validImageFormats,
142
145
  validCodecs: codec_1.validCodecs,
143
- DEFAULT_OVERWRITE: overwrite_1.DEFAULT_OVERWRITE,
144
146
  DEFAULT_PIXEL_FORMAT: pixel_format_1.DEFAULT_PIXEL_FORMAT,
145
147
  validateQuality: quality_1.validateQuality,
146
148
  validateFrame: validate_frame_1.validateFrame,
@@ -158,4 +160,7 @@ exports.RenderInternals = {
158
160
  perf,
159
161
  makeDownloadMap: download_map_1.makeDownloadMap,
160
162
  cleanDownloadMap: download_map_1.cleanDownloadMap,
163
+ convertToPositiveFrameIndex: convert_to_positive_frame_index_1.convertToPositiveFrameIndex,
161
164
  };
165
+ // Warn of potential performance issues with Apple Silicon (M1 chip under Rosetta)
166
+ (0, check_apple_silicon_1.warnIfAppleSiliconIsNotUsingArm64Architecture)();
@@ -0,0 +1 @@
1
+ export declare const makeAssetsDownloadTmpDir: () => string;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeAssetsDownloadTmpDir = void 0;
4
+ const tmp_dir_1 = require("./tmp-dir");
5
+ let dir = null;
6
+ const makeAssetsDownloadTmpDir = () => {
7
+ if (dir) {
8
+ return dir;
9
+ }
10
+ dir = (0, tmp_dir_1.tmpDir)('remotion-assets-dir');
11
+ return dir;
12
+ };
13
+ exports.makeAssetsDownloadTmpDir = makeAssetsDownloadTmpDir;
@@ -1,12 +1,6 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.openBrowser = exports.killAllBrowsers = void 0;
7
- const fs_1 = __importDefault(require("fs"));
8
- const os_1 = __importDefault(require("os"));
9
- const path_1 = __importDefault(require("path"));
10
4
  const node_1 = require("./browser/node");
11
5
  const get_local_browser_executable_1 = require("./get-local-browser-executable");
12
6
  const get_video_threads_flag_1 = require("./get-video-threads-flag");
@@ -102,11 +96,7 @@ const openBrowser = async (browser, options) => {
102
96
  ? '--ignore-certificate-errors'
103
97
  : null,
104
98
  ...(((_j = options === null || options === void 0 ? void 0 : options.chromiumOptions) === null || _j === void 0 ? void 0 : _j.disableWebSecurity)
105
- ? [
106
- '--disable-web-security',
107
- '--user-data-dir=' +
108
- (await fs_1.default.promises.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'chrome-user-dir'))),
109
- ]
99
+ ? ['--disable-web-security']
110
100
  : []),
111
101
  ].filter(Boolean),
112
102
  defaultViewport: (_k = options === null || options === void 0 ? void 0 : options.viewport) !== null && _k !== void 0 ? _k : {
@@ -61,6 +61,7 @@ export declare type RenderMediaOptions = {
61
61
  muted?: boolean;
62
62
  enforceAudioTrack?: boolean;
63
63
  ffmpegOverride?: FfmpegOverrideFn;
64
+ disallowParallelEncoding?: boolean;
64
65
  } & ServeUrlOrWebpackBundle & ConcurrencyOrParallelism;
65
66
  declare type ConcurrencyOrParallelism = {
66
67
  concurrency?: number | null;
@@ -79,12 +79,15 @@ const renderMedia = ({ proResProfile, crf, composition, ffmpegExecutable, ffprob
79
79
  height: composition.height,
80
80
  width: composition.width,
81
81
  });
82
- const parallelEncoding = hasEnoughMemory && (0, can_use_parallel_encoding_1.canUseParallelEncoding)(codec);
82
+ const parallelEncoding = !options.disallowParallelEncoding &&
83
+ hasEnoughMemory &&
84
+ (0, can_use_parallel_encoding_1.canUseParallelEncoding)(codec);
83
85
  if (options.verbose) {
84
86
  console.log('[PRESTITCHER] Free memory:', freeMemory, 'Estimated usage parallel encoding', estimatedUsage);
85
- console.log('[PRESTICHER]: Codec supports parallel rendering:', (0, can_use_parallel_encoding_1.canUseParallelEncoding)(codec));
87
+ console.log('[PRESTITCHER]: Codec supports parallel rendering:', (0, can_use_parallel_encoding_1.canUseParallelEncoding)(codec));
88
+ console.log('[PRESTITCHER]: User disallowed parallel encoding:', Boolean(options.disallowParallelEncoding));
86
89
  if (parallelEncoding) {
87
- console.log('[PRESTICHER] Parallel encoding is enabled.');
90
+ console.log('[PRESTITCHER] Parallel encoding is enabled.');
88
91
  }
89
92
  else {
90
93
  console.log('[PRESTITCHER] Parallel encoding is disabled.');
@@ -303,6 +306,10 @@ const renderMedia = ({ proResProfile, crf, composition, ffmpegExecutable, ffprob
303
306
  if (!(options === null || options === void 0 ? void 0 : options.downloadMap)) {
304
307
  (0, download_map_1.cleanDownloadMap)(downloadMap);
305
308
  }
309
+ // Clean temporary image frames when rendering ends or fails
310
+ if (outputDir && fs_1.default.existsSync(outputDir)) {
311
+ (0, delete_directory_1.deleteDirectory)(outputDir);
312
+ }
306
313
  });
307
314
  return Promise.race([
308
315
  happyPath,
@@ -32,7 +32,7 @@ declare type InnerStillOptions = {
32
32
  */
33
33
  downloadMap?: DownloadMap;
34
34
  };
35
- declare type RenderStillOptions = InnerStillOptions & ServeUrlOrWebpackBundle & {
35
+ export declare type RenderStillOptions = InnerStillOptions & ServeUrlOrWebpackBundle & {
36
36
  port?: number | null;
37
37
  };
38
38
  /**
@@ -32,6 +32,7 @@ const path_1 = __importDefault(require("path"));
32
32
  const remotion_1 = require("remotion");
33
33
  const download_map_1 = require("./assets/download-map");
34
34
  const browser_1 = require("./browser");
35
+ const convert_to_positive_frame_index_1 = require("./convert-to-positive-frame-index");
35
36
  const ensure_output_directory_1 = require("./ensure-output-directory");
36
37
  const handle_javascript_exception_1 = require("./error-handling/handle-javascript-exception");
37
38
  const image_format_1 = require("./image-format");
@@ -53,6 +54,10 @@ const innerRenderStill = async ({ composition, quality, imageFormat = 'png', ser
53
54
  remotion_1.Internals.validateDurationInFrames(composition.durationInFrames, 'in the `config` object passed to `renderStill()`');
54
55
  (0, image_format_1.validateNonNullImageFormat)(imageFormat);
55
56
  (0, validate_frame_1.validateFrame)(frame, composition.durationInFrames);
57
+ const stillFrame = (0, convert_to_positive_frame_index_1.convertToPositiveFrameIndex)({
58
+ durationInFrames: composition.durationInFrames,
59
+ frame,
60
+ });
56
61
  (0, validate_puppeteer_timeout_1.validatePuppeteerTimeout)(timeoutInMilliseconds);
57
62
  (0, validate_scale_1.validateScale)(scale);
58
63
  if (typeof output !== 'string') {
@@ -113,7 +118,7 @@ const innerRenderStill = async ({ composition, quality, imageFormat = 'png', ser
113
118
  envVariables,
114
119
  page,
115
120
  serveUrl,
116
- initialFrame: frame,
121
+ initialFrame: stillFrame,
117
122
  timeoutInMilliseconds,
118
123
  proxyPort,
119
124
  retriesRemaining: 2,
@@ -144,13 +149,13 @@ const innerRenderStill = async ({ composition, quality, imageFormat = 'png', ser
144
149
  frame: null,
145
150
  page,
146
151
  });
147
- await (0, seek_to_frame_1.seekToFrame)({ frame, page });
152
+ await (0, seek_to_frame_1.seekToFrame)({ frame: stillFrame, page });
148
153
  await (0, provide_screenshot_1.provideScreenshot)({
149
154
  page,
150
155
  imageFormat,
151
156
  quality,
152
157
  options: {
153
- frame,
158
+ frame: stillFrame,
154
159
  output,
155
160
  },
156
161
  });
@@ -103,7 +103,7 @@ const setPropsAndEnv = async ({ inputProps, envVariables, page, serveUrl, initia
103
103
  if (siteVersion !== requiredVersion) {
104
104
  throw new Error(`Incompatible site: When visiting ${urlToVisit}, a bundle was found, but one that is not compatible with this version of Remotion. Found version: ${siteVersion} - Required version: ${requiredVersion}. To resolve this error, please bundle and deploy again.`);
105
105
  }
106
- if (remotionVersion !== version_1.VERSION) {
106
+ if (remotionVersion !== version_1.VERSION && process.env.NODE_ENV !== 'test') {
107
107
  if (remotionVersion) {
108
108
  console.warn(`The site was bundled with version ${remotionVersion} of @remotion/bundler, while @remotion/renderer is on version ${version_1.VERSION}. You may not have the newest bugfixes and features. Re-bundle the site to fix this issue.`);
109
109
  }
@@ -0,0 +1,2 @@
1
+ import type { FfmpegOverrideFn } from './ffmpeg-override';
2
+ export declare const validateFfmpegArgsHook: (ffmpegArgsHook?: FfmpegOverrideFn) => void;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateFfmpegArgsHook = void 0;
4
+ const validateFfmpegArgsHook = (ffmpegArgsHook) => {
5
+ if (typeof ffmpegArgsHook === 'undefined') {
6
+ return;
7
+ }
8
+ if (ffmpegArgsHook && typeof ffmpegArgsHook !== 'function') {
9
+ throw new TypeError(`Argument passed for "ffmpegArgsHook" is not a function: ${ffmpegArgsHook}`);
10
+ }
11
+ };
12
+ exports.validateFfmpegArgsHook = validateFfmpegArgsHook;
@@ -0,0 +1,2 @@
1
+ import type { FfmpegOverrideFn } from './ffmpeg-override';
2
+ export declare const validateFfmpegOverride: (ffmpegArgsHook?: FfmpegOverrideFn) => void;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateFfmpegOverride = void 0;
4
+ const validateFfmpegOverride = (ffmpegArgsHook) => {
5
+ if (typeof ffmpegArgsHook === 'undefined') {
6
+ return;
7
+ }
8
+ if (ffmpegArgsHook && typeof ffmpegArgsHook !== 'function') {
9
+ throw new TypeError(`Argument passed for "ffmpegArgsHook" is not a function: ${ffmpegArgsHook}`);
10
+ }
11
+ };
12
+ exports.validateFfmpegOverride = validateFfmpegOverride;
@@ -8,15 +8,15 @@ const validateFrame = (frame, durationInFrames) => {
8
8
  if (typeof frame !== 'number') {
9
9
  throw new TypeError(`Argument passed for "frame" is not a number: ${frame}`);
10
10
  }
11
- if (frame < 0) {
12
- throw new RangeError(`Frame ${frame} cannot be negative`);
13
- }
14
11
  if (!Number.isFinite(frame)) {
15
12
  throw new RangeError(`Frame ${frame} is not finite`);
16
13
  }
17
14
  if (frame % 1 !== 0) {
18
15
  throw new RangeError(`Argument for frame must be an integer, but got ${frame}`);
19
16
  }
17
+ if (frame < 0 && frame < -durationInFrames) {
18
+ throw new RangeError(`Cannot use frame ${frame}: Duration of composition is ${durationInFrames}, therefore the lowest frame that can be rendered is ${-durationInFrames}`);
19
+ }
20
20
  if (frame > durationInFrames - 1) {
21
21
  throw new RangeError(`Cannot use frame ${frame}: Duration of composition is ${durationInFrames}, therefore the highest frame that can be rendered is ${durationInFrames - 1}`);
22
22
  }
@@ -8,7 +8,7 @@ const validatePuppeteerTimeout = (timeoutInMilliseconds) => {
8
8
  if (typeof timeoutInMilliseconds !== 'number') {
9
9
  throw new TypeError(`'timeoutInMilliseconds' should be a number, but is: ${JSON.stringify(timeoutInMilliseconds)}`);
10
10
  }
11
- if (timeoutInMilliseconds < 7000) {
11
+ if (timeoutInMilliseconds < 7000 && process.env.NODE_ENV !== 'test') {
12
12
  throw new TypeError(`'timeoutInMilliseconds' should be bigger or equal than 7000, but is ${timeoutInMilliseconds}`);
13
13
  }
14
14
  if (Number.isNaN(timeoutInMilliseconds)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/renderer",
3
- "version": "3.2.24",
3
+ "version": "3.2.26-crf.18+b22217116",
4
4
  "description": "Renderer for Remotion",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -22,7 +22,7 @@
22
22
  "dependencies": {
23
23
  "execa": "5.1.1",
24
24
  "extract-zip": "2.0.1",
25
- "remotion": "3.2.24",
25
+ "remotion": "3.2.26-crf.18+b22217116",
26
26
  "source-map": "^0.8.0-beta.0",
27
27
  "ws": "8.7.0"
28
28
  },
@@ -57,5 +57,5 @@
57
57
  "publishConfig": {
58
58
  "access": "public"
59
59
  },
60
- "gitHead": "1f11ef8d122eadb6d6f6aa0570ffc4936d43a886"
60
+ "gitHead": "b222171164aefac1d44e1ad9e08231e9bad9a029"
61
61
  }