@remotion/renderer 4.0.289 → 4.0.291

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.
@@ -43,6 +43,7 @@ export declare class HeadlessBrowser extends EventEmitter {
43
43
  indent: boolean;
44
44
  }): Promise<HeadlessBrowser>;
45
45
  connection: Connection;
46
+ id: string;
46
47
  runner: BrowserRunner;
47
48
  get _targets(): Map<string, Target>;
48
49
  constructor({ connection, defaultViewport, runner, }: {
@@ -63,6 +63,7 @@ class HeadlessBrowser extends EventEmitter_1.EventEmitter {
63
63
  _HeadlessBrowser_targets.set(this, void 0);
64
64
  __classPrivateFieldSet(this, _HeadlessBrowser_defaultViewport, defaultViewport, "f");
65
65
  this.connection = connection;
66
+ this.id = Math.random().toString(36).substring(2, 15);
66
67
  __classPrivateFieldSet(this, _HeadlessBrowser_defaultContext, new BrowserContext(this), "f");
67
68
  __classPrivateFieldSet(this, _HeadlessBrowser_contexts, new Map(), "f");
68
69
  __classPrivateFieldSet(this, _HeadlessBrowser_targets, new Map(), "f");
@@ -70,7 +70,7 @@ const makeBrowserRunner = async ({ executablePath, processArguments, userDataDir
70
70
  const dumpio = (0, log_level_1.isEqualOrBelowLogLevel)(logLevel, 'verbose');
71
71
  const stdio = dumpio
72
72
  ? ['ignore', 'pipe', 'pipe']
73
- : ['pipe', 'ignore', 'pipe'];
73
+ : ['pipe', 'pipe', 'pipe'];
74
74
  const proc = childProcess.spawn(executablePath, processArguments, {
75
75
  // On non-windows platforms, `detached: true` makes child process a
76
76
  // leader of a new process group, making it possible to kill child
@@ -235,13 +235,17 @@ const makeBrowserRunner = async ({ executablePath, processArguments, userDataDir
235
235
  exports.makeBrowserRunner = makeBrowserRunner;
236
236
  function waitForWSEndpoint({ browserProcess, timeout, logLevel, indent, }) {
237
237
  const browserStderr = browserProcess.stderr;
238
+ const browserStdout = browserProcess.stdout;
238
239
  (0, assert_1.assert)(browserStderr, '`browserProcess` does not have stderr.');
239
- let stderrString = '';
240
+ (0, assert_1.assert)(browserStdout, '`browserProcess` does not have stdout.');
241
+ let stdioString = '';
240
242
  return new Promise((resolve, reject) => {
241
- browserStderr.addListener('data', onData);
243
+ browserStderr.addListener('data', onStdIoData);
244
+ browserStdout.addListener('data', onStdIoData);
242
245
  browserStderr.addListener('close', onClose);
243
246
  const listeners = [
244
- () => browserStderr.removeListener('data', onData),
247
+ () => browserStderr.removeListener('data', onStdIoData),
248
+ () => browserStdout.removeListener('data', onStdIoData),
245
249
  () => browserStderr.removeListener('close', onClose),
246
250
  (0, util_1.addEventListener)(browserProcess, 'exit', (code, signal) => {
247
251
  logger_1.Log.verbose({ indent, logLevel }, 'Browser process exited with code', code, 'signal', signal);
@@ -257,7 +261,7 @@ function waitForWSEndpoint({ browserProcess, timeout, logLevel, indent, }) {
257
261
  reject(new Error([
258
262
  'Failed to launch the browser process!',
259
263
  error ? error.stack : null,
260
- stderrString,
264
+ stdioString,
261
265
  'Troubleshooting: https://remotion.dev/docs/troubleshooting/browser-launch',
262
266
  ]
263
267
  .filter(truthy_1.truthy)
@@ -265,11 +269,11 @@ function waitForWSEndpoint({ browserProcess, timeout, logLevel, indent, }) {
265
269
  }
266
270
  function onTimeout() {
267
271
  cleanup();
268
- reject(new Errors_1.TimeoutError(`Timed out after ${timeout} ms while trying to connect to the browser! Chrome logged the following: ${stderrString}`));
272
+ reject(new Errors_1.TimeoutError(`Timed out after ${timeout} ms while trying to connect to the browser! Chrome logged the following: ${stdioString}`));
269
273
  }
270
- function onData(data) {
271
- stderrString += data.toString('utf8');
272
- const match = stderrString.match(/DevTools listening on (ws:\/\/.*)/);
274
+ function onStdIoData(data) {
275
+ stdioString += data.toString('utf8');
276
+ const match = stdioString.match(/DevTools listening on (ws:\/\/.*)/);
273
277
  if (!match) {
274
278
  return;
275
279
  }
@@ -22,4 +22,5 @@ export interface LaunchOptions {
22
22
  indent: boolean;
23
23
  defaultViewport: Viewport;
24
24
  userDataDir: string;
25
+ timeout: number;
25
26
  }
@@ -15,4 +15,4 @@
15
15
  */
16
16
  import { HeadlessBrowser } from './Browser';
17
17
  import type { LaunchOptions } from './LaunchOptions';
18
- export declare const launchChrome: ({ args, executablePath, defaultViewport, indent, logLevel, userDataDir, }: LaunchOptions) => Promise<HeadlessBrowser>;
18
+ export declare const launchChrome: ({ args, executablePath, defaultViewport, indent, logLevel, userDataDir, timeout, }: LaunchOptions) => Promise<HeadlessBrowser>;
@@ -17,8 +17,7 @@
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.launchChrome = void 0;
19
19
  const Browser_1 = require("./Browser");
20
- const launchChrome = async ({ args, executablePath, defaultViewport, indent, logLevel, userDataDir, }) => {
21
- const timeout = 60000;
20
+ const launchChrome = async ({ args, executablePath, defaultViewport, indent, logLevel, userDataDir, timeout, }) => {
22
21
  const browser = await Browser_1.HeadlessBrowser.create({
23
22
  defaultViewport,
24
23
  args,
@@ -33,6 +33,15 @@ const shouldLogBrowserMessage = (message) => {
33
33
  if (message.includes('Received HEADERS for invalid stream')) {
34
34
  return false;
35
35
  }
36
+ if (message.includes('CVDisplayLinkCreateWithCGDisplay failed')) {
37
+ return false;
38
+ }
39
+ if (message.includes('Falling back to ALSA for audio output')) {
40
+ return false;
41
+ }
42
+ if (message.includes('VizNullHypothesis is disabled')) {
43
+ return false;
44
+ }
36
45
  return true;
37
46
  };
38
47
  exports.shouldLogBrowserMessage = shouldLogBrowserMessage;
@@ -16,16 +16,22 @@ const collectAssets = async ({ frame, freePage, timeoutInMilliseconds, }) => {
16
16
  if (asset.type !== 'artifact') {
17
17
  return asset;
18
18
  }
19
- if (typeof asset.content !== 'string') {
20
- throw new Error(`Expected string content for artifact ${asset.id}, but got ${asset.content}`);
19
+ if (asset.contentType === 'binary' || asset.contentType === 'text') {
20
+ if (typeof asset.content !== 'string') {
21
+ throw new Error(`Expected string content for artifact ${asset.id}, but got ${asset.content}`);
22
+ }
23
+ const stringOrUintArray = asset.contentType === 'binary'
24
+ ? new TextEncoder().encode(atob(asset.content))
25
+ : asset.content;
26
+ return {
27
+ ...asset,
28
+ content: stringOrUintArray,
29
+ };
21
30
  }
22
- const stringOrUintArray = asset.binary
23
- ? new TextEncoder().encode(atob(asset.content))
24
- : asset.content;
25
- return {
26
- ...asset,
27
- content: stringOrUintArray,
28
- };
31
+ if (asset.contentType === 'thumbnail') {
32
+ return asset;
33
+ }
34
+ return asset;
29
35
  });
30
36
  return fixedArtifacts;
31
37
  };
@@ -3175,6 +3175,15 @@ var shouldLogBrowserMessage = (message) => {
3175
3175
  if (message.includes("Received HEADERS for invalid stream")) {
3176
3176
  return false;
3177
3177
  }
3178
+ if (message.includes("CVDisplayLinkCreateWithCGDisplay failed")) {
3179
+ return false;
3180
+ }
3181
+ if (message.includes("Falling back to ALSA for audio output")) {
3182
+ return false;
3183
+ }
3184
+ if (message.includes("VizNullHypothesis is disabled")) {
3185
+ return false;
3186
+ }
3178
3187
  return true;
3179
3188
  };
3180
3189
  var parseBrowserLogMessage = (input) => {
@@ -3234,7 +3243,7 @@ var makeBrowserRunner = async ({
3234
3243
  timeout
3235
3244
  }) => {
3236
3245
  const dumpio = isEqualOrBelowLogLevel(logLevel, "verbose");
3237
- const stdio = dumpio ? ["ignore", "pipe", "pipe"] : ["pipe", "ignore", "pipe"];
3246
+ const stdio = dumpio ? ["ignore", "pipe", "pipe"] : ["pipe", "pipe", "pipe"];
3238
3247
  const proc = childProcess.spawn(executablePath, processArguments, {
3239
3248
  detached: process.platform !== "win32",
3240
3249
  env: process.env,
@@ -3368,13 +3377,17 @@ function waitForWSEndpoint({
3368
3377
  indent
3369
3378
  }) {
3370
3379
  const browserStderr = browserProcess.stderr;
3380
+ const browserStdout = browserProcess.stdout;
3371
3381
  assert(browserStderr, "`browserProcess` does not have stderr.");
3372
- let stderrString = "";
3382
+ assert(browserStdout, "`browserProcess` does not have stdout.");
3383
+ let stdioString = "";
3373
3384
  return new Promise((resolve, reject) => {
3374
- browserStderr.addListener("data", onData);
3385
+ browserStderr.addListener("data", onStdIoData);
3386
+ browserStdout.addListener("data", onStdIoData);
3375
3387
  browserStderr.addListener("close", onClose);
3376
3388
  const listeners = [
3377
- () => browserStderr.removeListener("data", onData),
3389
+ () => browserStderr.removeListener("data", onStdIoData),
3390
+ () => browserStdout.removeListener("data", onStdIoData),
3378
3391
  () => browserStderr.removeListener("close", onClose),
3379
3392
  addEventListener(browserProcess, "exit", (code, signal) => {
3380
3393
  Log.verbose({ indent, logLevel }, "Browser process exited with code", code, "signal", signal);
@@ -3390,18 +3403,18 @@ function waitForWSEndpoint({
3390
3403
  reject(new Error([
3391
3404
  "Failed to launch the browser process!",
3392
3405
  error ? error.stack : null,
3393
- stderrString,
3406
+ stdioString,
3394
3407
  "Troubleshooting: https://remotion.dev/docs/troubleshooting/browser-launch"
3395
3408
  ].filter(truthy).join(`
3396
3409
  `)));
3397
3410
  }
3398
3411
  function onTimeout() {
3399
3412
  cleanup();
3400
- reject(new TimeoutError(`Timed out after ${timeout} ms while trying to connect to the browser! Chrome logged the following: ${stderrString}`));
3413
+ reject(new TimeoutError(`Timed out after ${timeout} ms while trying to connect to the browser! Chrome logged the following: ${stdioString}`));
3401
3414
  }
3402
- function onData(data) {
3403
- stderrString += data.toString("utf8");
3404
- const match = stderrString.match(/DevTools listening on (ws:\/\/.*)/);
3415
+ function onStdIoData(data) {
3416
+ stdioString += data.toString("utf8");
3417
+ const match = stdioString.match(/DevTools listening on (ws:\/\/.*)/);
3405
3418
  if (!match) {
3406
3419
  return;
3407
3420
  }
@@ -3569,6 +3582,7 @@ class HeadlessBrowser extends EventEmitter {
3569
3582
  #defaultContext;
3570
3583
  #contexts;
3571
3584
  #targets;
3585
+ id;
3572
3586
  runner;
3573
3587
  get _targets() {
3574
3588
  return this.#targets;
@@ -3581,6 +3595,7 @@ class HeadlessBrowser extends EventEmitter {
3581
3595
  super();
3582
3596
  this.#defaultViewport = defaultViewport;
3583
3597
  this.connection = connection;
3598
+ this.id = Math.random().toString(36).substring(2, 15);
3584
3599
  this.#defaultContext = new BrowserContext(this);
3585
3600
  this.#contexts = new Map;
3586
3601
  this.#targets = new Map;
@@ -4632,9 +4647,9 @@ var launchChrome = async ({
4632
4647
  defaultViewport,
4633
4648
  indent,
4634
4649
  logLevel,
4635
- userDataDir
4650
+ userDataDir,
4651
+ timeout
4636
4652
  }) => {
4637
- const timeout = 60000;
4638
4653
  const browser = await HeadlessBrowser.create({
4639
4654
  defaultViewport,
4640
4655
  args,
@@ -5088,6 +5103,7 @@ var internalOpenBrowser = async ({
5088
5103
  if (browser === "firefox") {
5089
5104
  throw new TypeError("Firefox supported is not yet turned on. Stay tuned for the future.");
5090
5105
  }
5106
+ Log.verbose({ indent, logLevel }, "Ensuring browser executable");
5091
5107
  await internalEnsureBrowser({
5092
5108
  browserExecutable,
5093
5109
  logLevel,
@@ -5095,6 +5111,7 @@ var internalOpenBrowser = async ({
5095
5111
  onBrowserDownload,
5096
5112
  chromeMode
5097
5113
  });
5114
+ Log.verbose({ indent, logLevel }, "Ensured browser is available.");
5098
5115
  const executablePath = getLocalBrowserExecutable({
5099
5116
  preferredBrowserExecutable: browserExecutable,
5100
5117
  logLevel,
@@ -5105,7 +5122,7 @@ var internalOpenBrowser = async ({
5105
5122
  const enableMultiProcessOnLinux = chromiumOptions.enableMultiProcessOnLinux ?? true;
5106
5123
  Log.verbose({ indent, logLevel, tag: "openBrowser()" }, `Opening browser: gl = ${chromiumOptions.gl}, executable = ${executablePath}, enableMultiProcessOnLinux = ${enableMultiProcessOnLinux}`);
5107
5124
  if (chromiumOptions.userAgent) {
5108
- Log.verbose({ indent, logLevel: "verbose", tag: "openBrowser()" }, `Using custom user agent: ${chromiumOptions.userAgent}`);
5125
+ Log.verbose({ indent, logLevel, tag: "openBrowser()" }, `Using custom user agent: ${chromiumOptions.userAgent}`);
5109
5126
  }
5110
5127
  const userDataDir = await fs9.promises.mkdtemp(path9.join(os3.tmpdir(), "puppeteer_dev_chrome_profile-"));
5111
5128
  const browserInstance = await launchChrome({
@@ -5113,6 +5130,7 @@ var internalOpenBrowser = async ({
5113
5130
  logLevel,
5114
5131
  indent,
5115
5132
  userDataDir,
5133
+ timeout: 25000,
5116
5134
  args: [
5117
5135
  "about:blank",
5118
5136
  "--allow-pre-commit-input",
@@ -16832,9 +16850,7 @@ __export(exports_perf, {
16832
16850
  getPerf: () => getPerf
16833
16851
  });
16834
16852
  var perf = {
16835
- "activate-target": [],
16836
16853
  capture: [],
16837
- save: [],
16838
16854
  "extract-frame": [],
16839
16855
  piping: []
16840
16856
  };
@@ -17717,8 +17733,31 @@ import path19 from "path";
17717
17733
  var onlyAudioAndVideoAssets = (assets) => {
17718
17734
  return assets.filter((asset) => asset.type === "audio" || asset.type === "video");
17719
17735
  };
17720
- var onlyArtifact = (assets) => {
17721
- return assets.filter((asset) => asset.type === "artifact");
17736
+ var onlyArtifact = ({
17737
+ assets,
17738
+ frameBuffer
17739
+ }) => {
17740
+ const artifacts = assets.filter((asset) => asset.type === "artifact");
17741
+ return artifacts.map((artifact) => {
17742
+ if (artifact.contentType === "binary" || artifact.contentType === "text") {
17743
+ return {
17744
+ frame: artifact.frame,
17745
+ content: artifact.content,
17746
+ filename: artifact.filename
17747
+ };
17748
+ }
17749
+ if (artifact.contentType === "thumbnail") {
17750
+ if (frameBuffer === null) {
17751
+ return null;
17752
+ }
17753
+ return {
17754
+ frame: artifact.frame,
17755
+ content: new Uint8Array(frameBuffer),
17756
+ filename: artifact.filename
17757
+ };
17758
+ }
17759
+ throw new Error("Unknown artifact type: " + artifact);
17760
+ }).filter(truthy);
17722
17761
  };
17723
17762
 
17724
17763
  // src/collect-assets.ts
@@ -17740,14 +17779,20 @@ var collectAssets = async ({
17740
17779
  if (asset.type !== "artifact") {
17741
17780
  return asset;
17742
17781
  }
17743
- if (typeof asset.content !== "string") {
17744
- throw new Error(`Expected string content for artifact ${asset.id}, but got ${asset.content}`);
17782
+ if (asset.contentType === "binary" || asset.contentType === "text") {
17783
+ if (typeof asset.content !== "string") {
17784
+ throw new Error(`Expected string content for artifact ${asset.id}, but got ${asset.content}`);
17785
+ }
17786
+ const stringOrUintArray = asset.contentType === "binary" ? new TextEncoder().encode(atob(asset.content)) : asset.content;
17787
+ return {
17788
+ ...asset,
17789
+ content: stringOrUintArray
17790
+ };
17791
+ }
17792
+ if (asset.contentType === "thumbnail") {
17793
+ return asset;
17745
17794
  }
17746
- const stringOrUintArray = asset.binary ? new TextEncoder().encode(atob(asset.content)) : asset.content;
17747
- return {
17748
- ...asset,
17749
- content: stringOrUintArray
17750
- };
17795
+ return asset;
17751
17796
  });
17752
17797
  return fixedArtifacts;
17753
17798
  };
@@ -17769,16 +17814,14 @@ var screenshotTask = async ({
17769
17814
  }) => {
17770
17815
  const client = page._client();
17771
17816
  const target = page.target();
17772
- const perfTarget = startPerfMeasure("activate-target");
17773
17817
  await client.send("Target.activateTarget", {
17774
17818
  targetId: target._targetId
17775
17819
  });
17776
- stopPerfMeasure(perfTarget);
17777
- const shouldSetDefaultBackground = omitBackground;
17778
- if (shouldSetDefaultBackground)
17820
+ if (omitBackground) {
17779
17821
  await client.send("Emulation.setDefaultBackgroundColorOverride", {
17780
17822
  color: { r: 0, g: 0, b: 0, a: 0 }
17781
17823
  });
17824
+ }
17782
17825
  const cap = startPerfMeasure("capture");
17783
17826
  try {
17784
17827
  let result;
@@ -17814,13 +17857,13 @@ var screenshotTask = async ({
17814
17857
  result = value;
17815
17858
  }
17816
17859
  stopPerfMeasure(cap);
17817
- if (shouldSetDefaultBackground)
17860
+ if (omitBackground) {
17818
17861
  await client.send("Emulation.setDefaultBackgroundColorOverride");
17819
- const saveMarker = startPerfMeasure("save");
17862
+ }
17820
17863
  const buffer = Buffer.from(result.data, "base64");
17821
- if (path19)
17864
+ if (path19) {
17822
17865
  await fs12.promises.writeFile(path19, buffer);
17823
- stopPerfMeasure(saveMarker);
17866
+ }
17824
17867
  return buffer;
17825
17868
  } catch (err) {
17826
17869
  if (err.message.includes("Unable to capture screenshot")) {
@@ -17853,18 +17896,27 @@ var screenshot = (options) => {
17853
17896
  }));
17854
17897
  };
17855
17898
 
17856
- // src/screenshot-dom-element.ts
17857
- var screenshotDOMElement = async ({
17858
- page,
17899
+ // src/take-frame.ts
17900
+ var takeFrame = async ({
17901
+ freePage,
17859
17902
  imageFormat,
17860
17903
  jpegQuality,
17861
- opts,
17862
- height,
17904
+ frame,
17863
17905
  width,
17864
- timeoutInMilliseconds,
17865
- scale
17906
+ height,
17907
+ output,
17908
+ scale,
17909
+ wantsBuffer,
17910
+ timeoutInMilliseconds
17866
17911
  }) => {
17867
- const { path: path19 } = opts;
17912
+ const collectedAssets = await collectAssets({
17913
+ frame,
17914
+ freePage,
17915
+ timeoutInMilliseconds
17916
+ });
17917
+ if (imageFormat === "none") {
17918
+ return { buffer: null, collectedAssets };
17919
+ }
17868
17920
  if (imageFormat === "png" || imageFormat === "pdf" || imageFormat === "webp") {
17869
17921
  await puppeteerEvaluateWithCatch({
17870
17922
  pageFunction: () => {
@@ -17872,7 +17924,7 @@ var screenshotDOMElement = async ({
17872
17924
  },
17873
17925
  args: [],
17874
17926
  frame: null,
17875
- page,
17927
+ page: freePage,
17876
17928
  timeoutInMilliseconds
17877
17929
  });
17878
17930
  } else {
@@ -17882,93 +17934,21 @@ var screenshotDOMElement = async ({
17882
17934
  },
17883
17935
  args: [],
17884
17936
  frame: null,
17885
- page,
17937
+ page: freePage,
17886
17938
  timeoutInMilliseconds
17887
17939
  });
17888
17940
  }
17889
- if (imageFormat === "none") {
17890
- throw new TypeError('Tried to make a screenshot with format "none"');
17891
- }
17892
17941
  const buf = await screenshot({
17893
- page,
17942
+ page: freePage,
17894
17943
  omitBackground: imageFormat === "png",
17895
- path: path19 ?? undefined,
17944
+ path: (wantsBuffer ? undefined : output) ?? undefined,
17896
17945
  type: imageFormat,
17897
17946
  jpegQuality,
17898
17947
  width,
17899
17948
  height,
17900
17949
  scale
17901
17950
  });
17902
- if (typeof buf === "string") {
17903
- throw new TypeError("Expected a buffer");
17904
- }
17905
- return buf;
17906
- };
17907
-
17908
- // src/provide-screenshot.ts
17909
- var provideScreenshot = ({
17910
- page,
17911
- imageFormat,
17912
- options,
17913
- jpegQuality,
17914
- height,
17915
- width,
17916
- timeoutInMilliseconds,
17917
- scale
17918
- }) => {
17919
- return screenshotDOMElement({
17920
- page,
17921
- opts: {
17922
- path: options.output
17923
- },
17924
- imageFormat,
17925
- jpegQuality,
17926
- height,
17927
- width,
17928
- timeoutInMilliseconds,
17929
- scale
17930
- });
17931
- };
17932
-
17933
- // src/take-frame.ts
17934
- var takeFrame = async ({
17935
- freePage,
17936
- imageFormat,
17937
- jpegQuality,
17938
- frame,
17939
- width,
17940
- height,
17941
- output,
17942
- scale,
17943
- wantsBuffer,
17944
- timeoutInMilliseconds
17945
- }) => {
17946
- const collectedAssets = await collectAssets({
17947
- frame,
17948
- freePage,
17949
- timeoutInMilliseconds
17950
- });
17951
- if (imageFormat === "none") {
17952
- return { buffer: null, collectedAssets };
17953
- }
17954
- const shouldMakeBuffer = wantsBuffer;
17955
- const buf = await provideScreenshot({
17956
- page: freePage,
17957
- imageFormat,
17958
- jpegQuality,
17959
- options: {
17960
- frame,
17961
- output: wantsBuffer ? null : output
17962
- },
17963
- height,
17964
- width,
17965
- timeoutInMilliseconds,
17966
- scale
17967
- });
17968
- if (shouldMakeBuffer) {
17969
- return { buffer: buf, collectedAssets };
17970
- }
17971
- return { buffer: null, collectedAssets };
17951
+ return { buffer: buf, collectedAssets };
17972
17952
  };
17973
17953
 
17974
17954
  // src/render-frame-with-option-to-reject.ts
@@ -18038,7 +18018,6 @@ var renderFrameWithOptionToReject = async ({
18038
18018
  if (outputDir && onFrameBuffer && imageFormat !== "none") {
18039
18019
  throw new Error("Pass either `outputDir` or `onFrameBuffer` to renderFrames(), not both.");
18040
18020
  }
18041
- const id = startPerfMeasure("save");
18042
18021
  const { buffer, collectedAssets } = await takeFrame({
18043
18022
  frame,
18044
18023
  freePage: page,
@@ -18064,12 +18043,14 @@ var renderFrameWithOptionToReject = async ({
18064
18043
  }
18065
18044
  onFrameBuffer(buffer, frame);
18066
18045
  }
18067
- stopPerfMeasure(id);
18068
18046
  const onlyAvailableAssets = assets.filter(truthy);
18069
18047
  const previousAudioRenderAssets = onlyAvailableAssets.map((a) => a.audioAndVideoAssets).flat(2);
18070
18048
  const previousArtifactAssets = onlyAvailableAssets.map((a) => a.artifactAssets).flat(2);
18071
18049
  const audioAndVideoAssets = onlyAudioAndVideoAssets(collectedAssets);
18072
- const artifactAssets = onlyArtifact(collectedAssets);
18050
+ const artifactAssets = onlyArtifact({
18051
+ assets: collectedAssets,
18052
+ frameBuffer: buffer
18053
+ });
18073
18054
  for (const artifact of artifactAssets) {
18074
18055
  for (const previousArtifact of previousArtifactAssets) {
18075
18056
  if (artifact.filename === previousArtifact.filename) {
@@ -21695,7 +21676,10 @@ var innerRenderStill = async ({
21695
21676
  wantsBuffer: !output,
21696
21677
  timeoutInMilliseconds
21697
21678
  });
21698
- const artifactAssets = onlyArtifact(collectedAssets);
21679
+ const artifactAssets = onlyArtifact({
21680
+ assets: collectedAssets,
21681
+ frameBuffer: buffer
21682
+ });
21699
21683
  const previousArtifactAssets = [];
21700
21684
  for (const artifact of artifactAssets) {
21701
21685
  for (const previousArtifact of previousArtifactAssets) {
@@ -1,3 +1,7 @@
1
- import type { ArtifactAsset, AudioOrVideoAsset, TRenderAsset } from 'remotion/no-react';
1
+ import type { AudioOrVideoAsset, TRenderAsset } from 'remotion/no-react';
2
+ import type { EmittedArtifact } from './serialize-artifact';
2
3
  export declare const onlyAudioAndVideoAssets: (assets: TRenderAsset[]) => AudioOrVideoAsset[];
3
- export declare const onlyArtifact: (assets: TRenderAsset[]) => ArtifactAsset[];
4
+ export declare const onlyArtifact: ({ assets, frameBuffer, }: {
5
+ assets: TRenderAsset[];
6
+ frameBuffer: Buffer | null;
7
+ }) => EmittedArtifact[];
@@ -1,11 +1,38 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.onlyArtifact = exports.onlyAudioAndVideoAssets = void 0;
4
+ const truthy_1 = require("./truthy");
4
5
  const onlyAudioAndVideoAssets = (assets) => {
5
6
  return assets.filter((asset) => asset.type === 'audio' || asset.type === 'video');
6
7
  };
7
8
  exports.onlyAudioAndVideoAssets = onlyAudioAndVideoAssets;
8
- const onlyArtifact = (assets) => {
9
- return assets.filter((asset) => asset.type === 'artifact');
9
+ const onlyArtifact = ({ assets, frameBuffer, }) => {
10
+ const artifacts = assets.filter((asset) => asset.type === 'artifact');
11
+ return artifacts
12
+ .map((artifact) => {
13
+ if (artifact.contentType === 'binary' ||
14
+ artifact.contentType === 'text') {
15
+ return {
16
+ frame: artifact.frame,
17
+ content: artifact.content,
18
+ filename: artifact.filename,
19
+ };
20
+ }
21
+ if (artifact.contentType === 'thumbnail') {
22
+ if (frameBuffer === null) {
23
+ // A thumbnail artifact was defined to be emitted, but the output was not a video.
24
+ // Also, in Lambda, there are extra frames which are not video frames.
25
+ // This could happen if a thumbnail is unconditionally emitted.
26
+ return null;
27
+ }
28
+ return {
29
+ frame: artifact.frame,
30
+ content: new Uint8Array(frameBuffer),
31
+ filename: artifact.filename,
32
+ };
33
+ }
34
+ throw new Error('Unknown artifact type: ' + artifact);
35
+ })
36
+ .filter(truthy_1.truthy);
10
37
  };
11
38
  exports.onlyArtifact = onlyArtifact;
@@ -55,6 +55,7 @@ const internalOpenBrowser = async ({ browser, browserExecutable, chromiumOptions
55
55
  if (browser === 'firefox') {
56
56
  throw new TypeError('Firefox supported is not yet turned on. Stay tuned for the future.');
57
57
  }
58
+ logger_1.Log.verbose({ indent, logLevel }, 'Ensuring browser executable');
58
59
  await (0, ensure_browser_1.internalEnsureBrowser)({
59
60
  browserExecutable,
60
61
  logLevel,
@@ -62,6 +63,7 @@ const internalOpenBrowser = async ({ browser, browserExecutable, chromiumOptions
62
63
  onBrowserDownload,
63
64
  chromeMode,
64
65
  });
66
+ logger_1.Log.verbose({ indent, logLevel }, 'Ensured browser is available.');
65
67
  const executablePath = (0, get_local_browser_executable_1.getLocalBrowserExecutable)({
66
68
  preferredBrowserExecutable: browserExecutable,
67
69
  logLevel,
@@ -72,7 +74,7 @@ const internalOpenBrowser = async ({ browser, browserExecutable, chromiumOptions
72
74
  const enableMultiProcessOnLinux = (_b = chromiumOptions.enableMultiProcessOnLinux) !== null && _b !== void 0 ? _b : true;
73
75
  logger_1.Log.verbose({ indent, logLevel, tag: 'openBrowser()' }, `Opening browser: gl = ${chromiumOptions.gl}, executable = ${executablePath}, enableMultiProcessOnLinux = ${enableMultiProcessOnLinux}`);
74
76
  if (chromiumOptions.userAgent) {
75
- logger_1.Log.verbose({ indent, logLevel: 'verbose', tag: 'openBrowser()' }, `Using custom user agent: ${chromiumOptions.userAgent}`);
77
+ logger_1.Log.verbose({ indent, logLevel, tag: 'openBrowser()' }, `Using custom user agent: ${chromiumOptions.userAgent}`);
76
78
  }
77
79
  const userDataDir = await node_fs_1.default.promises.mkdtemp(node_path_1.default.join(node_os_1.default.tmpdir(), 'puppeteer_dev_chrome_profile-'));
78
80
  const browserInstance = await (0, Launcher_1.launchChrome)({
@@ -80,6 +82,7 @@ const internalOpenBrowser = async ({ browser, browserExecutable, chromiumOptions
80
82
  logLevel,
81
83
  indent,
82
84
  userDataDir,
85
+ timeout: 25000,
83
86
  args: [
84
87
  'about:blank',
85
88
  '--allow-pre-commit-input',
package/dist/perf.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- type PerfId = 'activate-target' | 'capture' | 'save' | 'extract-frame' | 'piping';
1
+ type PerfId = 'capture' | 'extract-frame' | 'piping';
2
2
  export declare const startPerfMeasure: (marker: PerfId) => number;
3
3
  export declare const stopPerfMeasure: (id: number) => void;
4
4
  export declare const getPerf: () => string[];
package/dist/perf.js CHANGED
@@ -2,9 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getPerf = exports.stopPerfMeasure = exports.startPerfMeasure = void 0;
4
4
  const perf = {
5
- 'activate-target': [],
6
5
  capture: [],
7
- save: [],
8
6
  'extract-frame': [],
9
7
  piping: [],
10
8
  };
@@ -9,4 +9,4 @@ export declare const screenshot: (options: {
9
9
  width: number;
10
10
  height: number;
11
11
  scale: number;
12
- }) => Promise<Buffer | string>;
12
+ }) => Promise<Buffer>;
@@ -11,7 +11,6 @@ const handle_javascript_exception_1 = require("./error-handling/handle-javascrip
11
11
  const filter_asset_types_1 = require("./filter-asset-types");
12
12
  const get_frame_padded_index_1 = require("./get-frame-padded-index");
13
13
  const logger_1 = require("./logger");
14
- const perf_1 = require("./perf");
15
14
  const seek_to_frame_1 = require("./seek-to-frame");
16
15
  const take_frame_1 = require("./take-frame");
17
16
  const truthy_1 = require("./truthy");
@@ -51,7 +50,6 @@ const renderFrameWithOptionToReject = async ({ reject, width, height, compId, at
51
50
  if (outputDir && onFrameBuffer && imageFormat !== 'none') {
52
51
  throw new Error('Pass either `outputDir` or `onFrameBuffer` to renderFrames(), not both.');
53
52
  }
54
- const id = (0, perf_1.startPerfMeasure)('save');
55
53
  const { buffer, collectedAssets } = await (0, take_frame_1.takeFrame)({
56
54
  frame,
57
55
  freePage: page,
@@ -79,7 +77,6 @@ const renderFrameWithOptionToReject = async ({ reject, width, height, compId, at
79
77
  }
80
78
  onFrameBuffer(buffer, frame);
81
79
  }
82
- (0, perf_1.stopPerfMeasure)(id);
83
80
  const onlyAvailableAssets = assets.filter(truthy_1.truthy);
84
81
  const previousAudioRenderAssets = onlyAvailableAssets
85
82
  .map((a) => a.audioAndVideoAssets)
@@ -88,7 +85,10 @@ const renderFrameWithOptionToReject = async ({ reject, width, height, compId, at
88
85
  .map((a) => a.artifactAssets)
89
86
  .flat(2);
90
87
  const audioAndVideoAssets = (0, filter_asset_types_1.onlyAudioAndVideoAssets)(collectedAssets);
91
- const artifactAssets = (0, filter_asset_types_1.onlyArtifact)(collectedAssets);
88
+ const artifactAssets = (0, filter_asset_types_1.onlyArtifact)({
89
+ assets: collectedAssets,
90
+ frameBuffer: buffer,
91
+ });
92
92
  for (const artifact of artifactAssets) {
93
93
  for (const previousArtifact of previousArtifactAssets) {
94
94
  if (artifact.filename === previousArtifact.filename) {
@@ -209,7 +209,10 @@ const innerRenderStill = async ({ composition, imageFormat = image_format_1.DEFA
209
209
  wantsBuffer: !output,
210
210
  timeoutInMilliseconds,
211
211
  });
212
- const artifactAssets = (0, filter_asset_types_1.onlyArtifact)(collectedAssets);
212
+ const artifactAssets = (0, filter_asset_types_1.onlyArtifact)({
213
+ assets: collectedAssets,
214
+ frameBuffer: buffer,
215
+ });
213
216
  const previousArtifactAssets = [];
214
217
  for (const artifact of artifactAssets) {
215
218
  for (const previousArtifact of previousArtifactAssets) {
@@ -9,4 +9,4 @@ export declare const screenshotTask: ({ format, height, omitBackground, page, wi
9
9
  width: number;
10
10
  height: number;
11
11
  scale: number;
12
- }) => Promise<Buffer | string>;
12
+ }) => Promise<Buffer>;
@@ -10,16 +10,14 @@ const screenshotTask = async ({ format, height, omitBackground, page, width, pat
10
10
  var _a;
11
11
  const client = page._client();
12
12
  const target = page.target();
13
- const perfTarget = (0, perf_1.startPerfMeasure)('activate-target');
14
13
  await client.send('Target.activateTarget', {
15
14
  targetId: target._targetId,
16
15
  });
17
- (0, perf_1.stopPerfMeasure)(perfTarget);
18
- const shouldSetDefaultBackground = omitBackground;
19
- if (shouldSetDefaultBackground)
16
+ if (omitBackground) {
20
17
  await client.send('Emulation.setDefaultBackgroundColorOverride', {
21
18
  color: { r: 0, g: 0, b: 0, a: 0 },
22
19
  });
20
+ }
23
21
  const cap = (0, perf_1.startPerfMeasure)('capture');
24
22
  try {
25
23
  let result;
@@ -63,13 +61,13 @@ const screenshotTask = async ({ format, height, omitBackground, page, width, pat
63
61
  result = value;
64
62
  }
65
63
  (0, perf_1.stopPerfMeasure)(cap);
66
- if (shouldSetDefaultBackground)
64
+ if (omitBackground) {
67
65
  await client.send('Emulation.setDefaultBackgroundColorOverride');
68
- const saveMarker = (0, perf_1.startPerfMeasure)('save');
66
+ }
69
67
  const buffer = Buffer.from(result.data, 'base64');
70
- if (path)
68
+ if (path) {
71
69
  await node_fs_1.default.promises.writeFile(path, buffer);
72
- (0, perf_1.stopPerfMeasure)(saveMarker);
70
+ }
73
71
  return buffer;
74
72
  }
75
73
  catch (err) {
@@ -2,8 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.takeFrame = void 0;
4
4
  const collect_assets_1 = require("./collect-assets");
5
- const provide_screenshot_1 = require("./provide-screenshot");
5
+ const puppeteer_evaluate_1 = require("./puppeteer-evaluate");
6
+ const puppeteer_screenshot_1 = require("./puppeteer-screenshot");
6
7
  const takeFrame = async ({ freePage, imageFormat, jpegQuality, frame, width, height, output, scale, wantsBuffer, timeoutInMilliseconds, }) => {
8
+ var _a;
7
9
  const collectedAssets = await (0, collect_assets_1.collectAssets)({
8
10
  frame,
9
11
  freePage,
@@ -12,23 +14,40 @@ const takeFrame = async ({ freePage, imageFormat, jpegQuality, frame, width, hei
12
14
  if (imageFormat === 'none') {
13
15
  return { buffer: null, collectedAssets };
14
16
  }
15
- const shouldMakeBuffer = wantsBuffer;
16
- const buf = await (0, provide_screenshot_1.provideScreenshot)({
17
+ if (imageFormat === 'png' ||
18
+ imageFormat === 'pdf' ||
19
+ imageFormat === 'webp') {
20
+ await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
21
+ pageFunction: () => {
22
+ document.body.style.background = 'transparent';
23
+ },
24
+ args: [],
25
+ frame: null,
26
+ page: freePage,
27
+ timeoutInMilliseconds,
28
+ });
29
+ }
30
+ else {
31
+ await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
32
+ pageFunction: () => {
33
+ document.body.style.background = 'black';
34
+ },
35
+ args: [],
36
+ frame: null,
37
+ page: freePage,
38
+ timeoutInMilliseconds,
39
+ });
40
+ }
41
+ const buf = await (0, puppeteer_screenshot_1.screenshot)({
17
42
  page: freePage,
18
- imageFormat,
43
+ omitBackground: imageFormat === 'png',
44
+ path: (_a = (wantsBuffer ? undefined : output)) !== null && _a !== void 0 ? _a : undefined,
45
+ type: imageFormat,
19
46
  jpegQuality,
20
- options: {
21
- frame,
22
- output: wantsBuffer ? null : output,
23
- },
24
- height,
25
47
  width,
26
- timeoutInMilliseconds,
48
+ height,
27
49
  scale,
28
50
  });
29
- if (shouldMakeBuffer) {
30
- return { buffer: buf, collectedAssets };
31
- }
32
- return { buffer: null, collectedAssets };
51
+ return { buffer: buf, collectedAssets };
33
52
  };
34
53
  exports.takeFrame = takeFrame;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/renderer"
4
4
  },
5
5
  "name": "@remotion/renderer",
6
- "version": "4.0.289",
6
+ "version": "4.0.291",
7
7
  "description": "Render Remotion videos using Node.js or Bun",
8
8
  "main": "dist/index.js",
9
9
  "types": "dist/index.d.ts",
@@ -18,8 +18,8 @@
18
18
  "extract-zip": "2.0.1",
19
19
  "source-map": "^0.8.0-beta.0",
20
20
  "ws": "8.17.1",
21
- "remotion": "4.0.289",
22
- "@remotion/streaming": "4.0.289"
21
+ "remotion": "4.0.291",
22
+ "@remotion/streaming": "4.0.291"
23
23
  },
24
24
  "peerDependencies": {
25
25
  "react": ">=16.8.0",
@@ -33,17 +33,17 @@
33
33
  "react-dom": "19.0.0",
34
34
  "@types/ws": "8.5.10",
35
35
  "eslint": "9.19.0",
36
- "@remotion/example-videos": "4.0.289",
37
- "@remotion/eslint-config-internal": "4.0.289"
36
+ "@remotion/example-videos": "4.0.291",
37
+ "@remotion/eslint-config-internal": "4.0.291"
38
38
  },
39
39
  "optionalDependencies": {
40
- "@remotion/compositor-darwin-arm64": "4.0.289",
41
- "@remotion/compositor-linux-arm64-musl": "4.0.289",
42
- "@remotion/compositor-linux-x64-gnu": "4.0.289",
43
- "@remotion/compositor-darwin-x64": "4.0.289",
44
- "@remotion/compositor-linux-x64-musl": "4.0.289",
45
- "@remotion/compositor-win32-x64-msvc": "4.0.289",
46
- "@remotion/compositor-linux-arm64-gnu": "4.0.289"
40
+ "@remotion/compositor-darwin-arm64": "4.0.291",
41
+ "@remotion/compositor-darwin-x64": "4.0.291",
42
+ "@remotion/compositor-linux-arm64-musl": "4.0.291",
43
+ "@remotion/compositor-linux-arm64-gnu": "4.0.291",
44
+ "@remotion/compositor-linux-x64-gnu": "4.0.291",
45
+ "@remotion/compositor-linux-x64-musl": "4.0.291",
46
+ "@remotion/compositor-win32-x64-msvc": "4.0.291"
47
47
  },
48
48
  "keywords": [
49
49
  "remotion",
@@ -1,8 +0,0 @@
1
- const out = await Bun.build({
2
- entrypoints: ['src/ensure-browser.ts'],
3
- target: 'node',
4
- });
5
-
6
- Bun.write('ensure-browser.mjs', await out.outputs[0].arrayBuffer());
7
-
8
- export {};
package/bundle.ts DELETED
@@ -1,27 +0,0 @@
1
- import {buildPackage} from '../.monorepo/builder';
2
-
3
- await buildPackage({
4
- formats: {
5
- cjs: 'use-tsc',
6
- esm: 'build',
7
- },
8
- external: 'dependencies',
9
- entrypoints: [
10
- {
11
- path: 'src/index.ts',
12
- target: 'node',
13
- },
14
- {
15
- path: 'src/client.ts',
16
- target: 'node',
17
- },
18
- {
19
- path: 'src/pure.ts',
20
- target: 'browser',
21
- },
22
- {
23
- path: 'src/error-handling.ts',
24
- target: 'node',
25
- },
26
- ],
27
- });
package/eslint.config.mjs DELETED
@@ -1,25 +0,0 @@
1
- import {remotionFlatConfig} from '@remotion/eslint-config-internal';
2
-
3
- const config = remotionFlatConfig({react: false});
4
-
5
- export default [
6
- {
7
- ...config,
8
- rules: {
9
- ...config.rules,
10
- '@typescript-eslint/no-use-before-define': 'off',
11
- 'no-restricted-imports': [
12
- 'error',
13
- {
14
- patterns: ['@remotion/*/src/*', 'remotion/src/*'],
15
- paths: ['remotion', 'react', 'react-dom'],
16
- },
17
- ],
18
- },
19
- ignores: ['src/browser/**'],
20
- },
21
- {
22
- ...config,
23
- files: ['src/test/**'],
24
- },
25
- ];