@remotion/renderer 4.0.102 → 4.0.103

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 (39) hide show
  1. package/LICENSE.md +1 -1
  2. package/dist/assets/download-and-map-assets-to-file.js +11 -4
  3. package/dist/assets/get-audio-channels.js +1 -1
  4. package/dist/call-ffmpeg.d.ts +7 -13
  5. package/dist/call-ffmpeg.js +4 -23
  6. package/dist/combine-videos.js +6 -1
  7. package/dist/compositor/compose.js +7 -2
  8. package/dist/compositor/compositor.js +21 -10
  9. package/dist/compositor/get-executable-path.d.ts +1 -1
  10. package/dist/compositor/get-executable-path.js +6 -13
  11. package/dist/create-silent-audio.js +18 -13
  12. package/dist/error-handling/handle-javascript-exception.d.ts +1 -1
  13. package/dist/error-handling/handle-javascript-exception.js +1 -0
  14. package/dist/get-browser-instance.d.ts +1 -1
  15. package/dist/get-browser-instance.js +2 -0
  16. package/dist/get-compositions.js +3 -1
  17. package/dist/get-extension-from-codec.d.ts +2 -2
  18. package/dist/guess-extension-for-media.js +6 -1
  19. package/dist/index.d.ts +8 -14
  20. package/dist/index.js +0 -1
  21. package/dist/merge-audio-track.js +1 -1
  22. package/dist/options/color-space.d.ts +1 -1
  23. package/dist/pixel-format.d.ts +1 -1
  24. package/dist/prepare-server.js +1 -2
  25. package/dist/preprocess-audio-track.js +1 -1
  26. package/dist/prespawn-ffmpeg.js +6 -1
  27. package/dist/pure.d.ts +3 -3
  28. package/dist/render-frames.js +6 -4
  29. package/dist/render-media.js +5 -2
  30. package/dist/render-still.js +3 -1
  31. package/dist/select-composition.js +5 -1
  32. package/dist/set-props-and-env.js +19 -0
  33. package/dist/stitch-frames-to-video.d.ts +1 -3
  34. package/dist/stitch-frames-to-video.js +22 -15
  35. package/dist/take-frame-and-compose.js +2 -2
  36. package/dist/validate-output-filename.d.ts +1 -1
  37. package/package.json +9 -9
  38. package/dist/check-apple-silicon.d.ts +0 -3
  39. package/dist/check-apple-silicon.js +0 -42
package/LICENSE.md CHANGED
@@ -7,7 +7,7 @@ Depending on the type of your legal entity, you are granted permission to use Re
7
7
 
8
8
  ## Free license
9
9
 
10
- Copyright © 2023 [Remotion](https://www.remotion.dev)
10
+ Copyright © 2024 [Remotion](https://www.remotion.dev)
11
11
 
12
12
  ### Eligibility
13
13
 
@@ -269,17 +269,24 @@ const attachDownloadListenerToEmitter = (downloadMap, onDownload) => {
269
269
  downloadMap.downloadListeners.push(onDownload);
270
270
  cleanup.push(() => {
271
271
  downloadMap.downloadListeners = downloadMap.downloadListeners.filter((l) => l !== onDownload);
272
+ return Promise.resolve();
272
273
  });
273
- const a = downloadMap.emitter.addEventListener('download', ({ detail: { src: initialSrc } }) => {
274
+ const cleanupDownloadListener = downloadMap.emitter.addEventListener('download', ({ detail: { src: initialSrc } }) => {
274
275
  const progress = onDownload(initialSrc);
275
- const b = downloadMap.emitter.addEventListener('progress', ({ detail: { downloaded, percent, src: progressSrc, totalSize } }) => {
276
+ const cleanupProgressListener = downloadMap.emitter.addEventListener('progress', ({ detail: { downloaded, percent, src: progressSrc, totalSize } }) => {
276
277
  if (initialSrc === progressSrc) {
277
278
  progress === null || progress === void 0 ? void 0 : progress({ downloaded, percent, totalSize });
278
279
  }
279
280
  });
280
- cleanup.push(b);
281
+ cleanup.push(() => {
282
+ cleanupProgressListener();
283
+ return Promise.resolve();
284
+ });
285
+ });
286
+ cleanup.push(() => {
287
+ cleanupDownloadListener();
288
+ return Promise.resolve();
281
289
  });
282
- cleanup.push(() => a());
283
290
  return () => {
284
291
  cleanup.forEach((c) => c());
285
292
  };
@@ -13,7 +13,7 @@ const getAudioChannelsAndDurationWithoutCache = async (src, indent, logLevel) =>
13
13
  ]
14
14
  .reduce((acc, val) => acc.concat(val), [])
15
15
  .filter(Boolean);
16
- const task = await (0, call_ffmpeg_1.callFf)('ffprobe', args, indent, logLevel);
16
+ const task = await (0, call_ffmpeg_1.callFf)({ bin: 'ffprobe', args, indent, logLevel });
17
17
  const channels = task.stdout.match(/channels=([0-9]+)/);
18
18
  const duration = task.stdout.match(/duration=([0-9.]+)/);
19
19
  const result = {
@@ -1,15 +1,9 @@
1
1
  import execa from 'execa';
2
2
  import type { LogLevel } from './log-level';
3
- export declare const dynamicLibraryPathOptions: (indent: boolean, logLevel: LogLevel) => {
4
- env: {
5
- DYLD_LIBRARY_PATH: string;
6
- RUST_BACKTRACE: string;
7
- } | {
8
- PATH: string;
9
- RUST_BACKTRACE: string;
10
- } | {
11
- LD_LIBRARY_PATH: string;
12
- RUST_BACKTRACE: string;
13
- };
14
- };
15
- export declare const callFf: (bin: 'ffmpeg' | 'ffprobe', args: (string | null)[], indent: boolean, logLevel: LogLevel, options?: execa.Options<string>) => execa.ExecaChildProcess<string>;
3
+ export declare const callFf: ({ args, bin, indent, logLevel, options, }: {
4
+ bin: 'ffmpeg' | 'ffprobe';
5
+ args: (string | null)[];
6
+ indent: boolean;
7
+ logLevel: LogLevel;
8
+ options?: execa.Options<string> | undefined;
9
+ }) => execa.ExecaChildProcess<string>;
@@ -3,38 +3,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.callFf = exports.dynamicLibraryPathOptions = void 0;
6
+ exports.callFf = void 0;
7
7
  const execa_1 = __importDefault(require("execa"));
8
8
  const node_fs_1 = require("node:fs");
9
+ const path_1 = __importDefault(require("path"));
9
10
  const get_executable_path_1 = require("./compositor/get-executable-path");
10
11
  const truthy_1 = require("./truthy");
11
- const dynamicLibraryPathOptions = (indent, logLevel) => {
12
- const lib = (0, get_executable_path_1.getExecutablePath)('lib', indent, logLevel);
13
- return {
14
- env: {
15
- RUST_BACKTRACE: 'full',
16
- ...(process.platform === 'darwin'
17
- ? {
18
- DYLD_LIBRARY_PATH: lib,
19
- }
20
- : process.platform === 'win32'
21
- ? {
22
- PATH: `${lib};${process.env.PATH}`,
23
- }
24
- : {
25
- LD_LIBRARY_PATH: lib,
26
- }),
27
- },
28
- };
29
- };
30
- exports.dynamicLibraryPathOptions = dynamicLibraryPathOptions;
31
- const callFf = (bin, args, indent, logLevel, options) => {
12
+ const callFf = ({ args, bin, indent, logLevel, options, }) => {
32
13
  const executablePath = (0, get_executable_path_1.getExecutablePath)(bin, indent, logLevel);
33
14
  if (!process.env.READ_ONLY_FS) {
34
15
  (0, node_fs_1.chmodSync)(executablePath, 0o755);
35
16
  }
36
17
  return (0, execa_1.default)(executablePath, args.filter(truthy_1.truthy), {
37
- ...(0, exports.dynamicLibraryPathOptions)(indent, logLevel),
18
+ cwd: path_1.default.dirname(executablePath),
38
19
  ...options,
39
20
  });
40
21
  };
@@ -48,7 +48,12 @@ const combineVideos = async (options) => {
48
48
  ].filter(truthy_1.truthy);
49
49
  logger_1.Log.verbose({ indent, logLevel }, 'Combining command: ', command);
50
50
  try {
51
- const task = (0, call_ffmpeg_1.callFf)('ffmpeg', command, options.indent, options.logLevel);
51
+ const task = (0, call_ffmpeg_1.callFf)({
52
+ bin: 'ffmpeg',
53
+ args: command,
54
+ indent: options.indent,
55
+ logLevel: options.logLevel,
56
+ });
52
57
  (_a = task.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
53
58
  if (onProgress) {
54
59
  const parsed = (0, parse_ffmpeg_progress_1.parseFfmpegProgress)(data.toString('utf8'));
@@ -1,11 +1,14 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.callCompositor = exports.compose = exports.composeWithoutCache = exports.serializeCommand = void 0;
4
7
  const node_child_process_1 = require("node:child_process");
5
8
  const node_crypto_1 = require("node:crypto");
6
9
  const node_fs_1 = require("node:fs");
7
10
  const promises_1 = require("node:fs/promises");
8
- const call_ffmpeg_1 = require("../call-ffmpeg");
11
+ const node_path_1 = __importDefault(require("node:path"));
9
12
  const get_executable_path_1 = require("./get-executable-path");
10
13
  const make_nonce_1 = require("./make-nonce");
11
14
  const getCompositorHash = ({ ...input }) => {
@@ -54,7 +57,9 @@ const callCompositor = (payload, indent, logLevel) => {
54
57
  if (!process.env.READ_ONLY_FS) {
55
58
  (0, node_fs_1.chmodSync)(execPath, 0o755);
56
59
  }
57
- const child = (0, node_child_process_1.spawn)(execPath, [payload], (0, call_ffmpeg_1.dynamicLibraryPathOptions)(indent, logLevel));
60
+ const child = (0, node_child_process_1.spawn)(execPath, [payload], {
61
+ cwd: node_path_1.default.dirname(execPath),
62
+ });
58
63
  const stderrChunks = [];
59
64
  child.stderr.on('data', (d) => stderrChunks.push(d));
60
65
  child.on('close', (code) => {
@@ -1,9 +1,12 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.startCompositor = exports.startLongRunningCompositor = void 0;
4
7
  const node_child_process_1 = require("node:child_process");
5
8
  const node_fs_1 = require("node:fs");
6
- const call_ffmpeg_1 = require("../call-ffmpeg");
9
+ const node_path_1 = __importDefault(require("node:path"));
7
10
  const get_concurrency_1 = require("../get-concurrency");
8
11
  const log_level_1 = require("../log-level");
9
12
  const logger_1 = require("../logger");
@@ -25,7 +28,9 @@ const startCompositor = (type, payload, logLevel, indent) => {
25
28
  (0, node_fs_1.chmodSync)(bin, 0o755);
26
29
  }
27
30
  const fullCommand = (0, compose_1.serializeCommand)(type, payload);
28
- const child = (0, node_child_process_1.spawn)(bin, [JSON.stringify(fullCommand)], (0, call_ffmpeg_1.dynamicLibraryPathOptions)(indent, logLevel));
31
+ const child = (0, node_child_process_1.spawn)(bin, [JSON.stringify(fullCommand)], {
32
+ cwd: node_path_1.default.dirname(bin),
33
+ });
29
34
  const stderrChunks = [];
30
35
  let outputBuffer = Buffer.from('');
31
36
  const separator = Buffer.from('remotion_buffer:');
@@ -176,10 +181,10 @@ const startCompositor = (type, payload, logLevel, indent) => {
176
181
  },
177
182
  finishCommands: () => {
178
183
  if (runningStatus.type === 'quit-with-error') {
179
- throw new Error(`Compositor quit${runningStatus.signal ? ` with signal ${runningStatus.signal}` : ''}: ${runningStatus.error}`);
184
+ return Promise.reject(new Error(`Compositor quit${runningStatus.signal ? ` with signal ${runningStatus.signal}` : ''}: ${runningStatus.error}`));
180
185
  }
181
186
  if (runningStatus.type === 'quit-without-error') {
182
- throw new Error(`Compositor quit${runningStatus.signal ? ` with signal ${runningStatus.signal}` : ''}`);
187
+ return Promise.reject(new Error(`Compositor quit${runningStatus.signal ? ` with signal ${runningStatus.signal}` : ''}`));
183
188
  }
184
189
  return new Promise((res, rej) => {
185
190
  child.stdin.write('EOF\n', (e) => {
@@ -192,13 +197,19 @@ const startCompositor = (type, payload, logLevel, indent) => {
192
197
  });
193
198
  },
194
199
  executeCommand: (command, params) => {
195
- if (runningStatus.type === 'quit-without-error') {
196
- throw new Error(`Compositor quit${runningStatus.signal ? ` with signal ${runningStatus.signal}` : ''}`);
197
- }
198
- if (runningStatus.type === 'quit-with-error') {
199
- throw new Error(`Compositor quit${runningStatus.signal ? ` with signal ${runningStatus.signal}` : ''}: ${runningStatus.error}`);
200
- }
201
200
  return new Promise((_resolve, _reject) => {
201
+ if (runningStatus.type === 'quit-without-error') {
202
+ _reject(new Error(`Compositor quit${runningStatus.signal
203
+ ? ` with signal ${runningStatus.signal}`
204
+ : ''}`));
205
+ return;
206
+ }
207
+ if (runningStatus.type === 'quit-with-error') {
208
+ _reject(new Error(`Compositor quit${runningStatus.signal
209
+ ? ` with signal ${runningStatus.signal}`
210
+ : ''}: ${runningStatus.error}`));
211
+ return;
212
+ }
202
213
  const nonce = (0, make_nonce_1.makeNonce)();
203
214
  const composed = {
204
215
  nonce,
@@ -3,5 +3,5 @@ export declare function isMusl({ indent, logLevel, }: {
3
3
  indent: boolean;
4
4
  logLevel: LogLevel;
5
5
  }): boolean;
6
- export declare const getExecutablePath: (type: 'compositor' | 'ffmpeg' | 'ffprobe' | 'lib', indent: boolean, logLevel: LogLevel) => string;
6
+ export declare const getExecutablePath: (type: 'compositor' | 'ffmpeg' | 'ffprobe', indent: boolean, logLevel: LogLevel) => string;
7
7
  export declare const getExecutableDir: (indent: boolean, logLevel: LogLevel) => string;
@@ -27,32 +27,25 @@ const getExecutablePath = (type, indent, logLevel) => {
27
27
  switch (type) {
28
28
  case 'compositor':
29
29
  if (process.platform === 'win32') {
30
- return path_1.default.resolve(base, 'compositor.exe');
30
+ return path_1.default.resolve(base, 'remotion.exe');
31
31
  }
32
- return path_1.default.resolve(base, 'compositor');
32
+ return path_1.default.resolve(base, 'remotion');
33
33
  case 'ffmpeg':
34
34
  if (process.platform === 'win32') {
35
- return path_1.default.resolve(base, 'ffmpeg', 'remotion', 'bin', 'ffmpeg.exe');
35
+ return path_1.default.join(base, 'ffmpeg.exe');
36
36
  }
37
- return path_1.default.resolve(base, 'ffmpeg', 'remotion', 'bin', 'ffmpeg');
37
+ return path_1.default.join(base, 'ffmpeg');
38
38
  case 'ffprobe':
39
39
  if (process.platform === 'win32') {
40
- return path_1.default.resolve(base, 'ffmpeg', 'remotion', 'bin', 'ffprobe.exe');
40
+ return path_1.default.join(base, 'ffprobe.exe');
41
41
  }
42
- return path_1.default.resolve(base, 'ffmpeg', 'remotion', 'bin', 'ffprobe');
43
- case 'lib': {
44
- const dir = path_1.default.resolve(base, 'ffmpeg', 'remotion', 'lib');
45
- return dir;
46
- }
42
+ return path_1.default.join(base, 'ffprobe');
47
43
  default:
48
44
  throw new Error(`Unknown executable type: ${type}`);
49
45
  }
50
46
  };
51
47
  exports.getExecutablePath = getExecutablePath;
52
48
  const getExecutableDir = (indent, logLevel) => {
53
- if (process.env.COMPOSITOR_DIR) {
54
- return process.env.COMPOSITOR_DIR;
55
- }
56
49
  switch (process.platform) {
57
50
  case 'win32':
58
51
  switch (process.arch) {
@@ -4,18 +4,23 @@ exports.createSilentAudio = void 0;
4
4
  const call_ffmpeg_1 = require("./call-ffmpeg");
5
5
  const sample_rate_1 = require("./sample-rate");
6
6
  const createSilentAudio = async ({ numberOfSeconds, outName, indent, logLevel, }) => {
7
- await (0, call_ffmpeg_1.callFf)('ffmpeg', [
8
- '-f',
9
- 'lavfi',
10
- '-i',
11
- `anullsrc=r=${sample_rate_1.DEFAULT_SAMPLE_RATE}`,
12
- '-c:a',
13
- 'pcm_s16le',
14
- '-t',
15
- String(numberOfSeconds),
16
- '-ar',
17
- String(sample_rate_1.DEFAULT_SAMPLE_RATE),
18
- outName,
19
- ], indent, logLevel);
7
+ await (0, call_ffmpeg_1.callFf)({
8
+ bin: 'ffmpeg',
9
+ args: [
10
+ '-f',
11
+ 'lavfi',
12
+ '-i',
13
+ `anullsrc=r=${sample_rate_1.DEFAULT_SAMPLE_RATE}`,
14
+ '-c:a',
15
+ 'pcm_s16le',
16
+ '-t',
17
+ String(numberOfSeconds),
18
+ '-ar',
19
+ String(sample_rate_1.DEFAULT_SAMPLE_RATE),
20
+ outName,
21
+ ],
22
+ indent,
23
+ logLevel,
24
+ });
20
25
  };
21
26
  exports.createSilentAudio = createSilentAudio;
@@ -18,4 +18,4 @@ export declare const handleJavascriptException: ({ page, onError, frame, }: {
18
18
  page: Page;
19
19
  frame: number | null;
20
20
  onError: (err: Error) => void;
21
- }) => () => void;
21
+ }) => () => Promise<void>;
@@ -77,6 +77,7 @@ const handleJavascriptException = ({ page, onError, frame, }) => {
77
77
  client.on('Runtime.exceptionThrown', handler);
78
78
  return () => {
79
79
  client.off('Runtime.exceptionThrown', handler);
80
+ return Promise.resolve();
80
81
  };
81
82
  };
82
83
  exports.handleJavascriptException = handleJavascriptException;
@@ -11,6 +11,6 @@ export declare const getPageAndCleanupFn: ({ passedInInstance, browserExecutable
11
11
  forceDeviceScaleFactor: number | undefined;
12
12
  logLevel: LogLevel;
13
13
  }) => Promise<{
14
- cleanup: () => void;
14
+ cleanup: () => Promise<void>;
15
15
  page: Page;
16
16
  }>;
@@ -14,6 +14,7 @@ const getPageAndCleanupFn = async ({ passedInInstance, browserExecutable, chromi
14
14
  page.close().catch((err) => {
15
15
  console.error('Was not able to close puppeteer page', err);
16
16
  });
17
+ return Promise.resolve();
17
18
  },
18
19
  };
19
20
  }
@@ -34,6 +35,7 @@ const getPageAndCleanupFn = async ({ passedInInstance, browserExecutable, chromi
34
35
  browserInstance.close(true, logLevel, indent).catch((err) => {
35
36
  console.error('Was not able to close puppeteer page', err);
36
37
  });
38
+ return Promise.resolve();
37
39
  },
38
40
  };
39
41
  };
@@ -111,7 +111,9 @@ const internalGetCompositionsRaw = async ({ browserExecutable, chromiumOptions,
111
111
  })
112
112
  .then(({ server: { serveUrl, offthreadPort, sourceMap }, cleanupServer }) => {
113
113
  page.setBrowserSourceMapGetter(sourceMap);
114
- cleanup.push(() => cleanupServer(true));
114
+ cleanup.push(() => {
115
+ return cleanupServer(true);
116
+ });
115
117
  return innerGetCompositions({
116
118
  envVariables,
117
119
  serializedInputPropsWithCustomSchema,
@@ -1,6 +1,6 @@
1
1
  import type { AudioCodec } from './audio-codec';
2
2
  import type { Codec } from './codec';
3
3
  import type { FileExtension } from './file-extensions';
4
- export declare const getFileExtensionFromCodec: <T extends "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif">(codec: T, audioCodec: AudioCodec | null) => FileExtension;
5
- export declare const makeFileExtensionMap: () => Record<string, ("h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif")[]>;
4
+ export declare const getFileExtensionFromCodec: <T extends "h264" | "h265" | "vp8" | "vp9" | "prores" | "aac" | "mp3" | "wav" | "h264-mkv" | "gif">(codec: T, audioCodec: AudioCodec | null) => FileExtension;
5
+ export declare const makeFileExtensionMap: () => Record<string, ("h264" | "h265" | "vp8" | "vp9" | "prores" | "aac" | "mp3" | "wav" | "h264-mkv" | "gif")[]>;
6
6
  export declare const defaultCodecsForFileExtension: Record<FileExtension, Codec>;
@@ -3,7 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.guessExtensionForVideo = void 0;
4
4
  const call_ffmpeg_1 = require("./call-ffmpeg");
5
5
  const guessExtensionForVideo = async ({ src, indent, logLevel, }) => {
6
- const { stderr } = await (0, call_ffmpeg_1.callFf)('ffprobe', [src], indent, logLevel);
6
+ const { stderr } = await (0, call_ffmpeg_1.callFf)({
7
+ bin: 'ffprobe',
8
+ args: [src],
9
+ indent,
10
+ logLevel,
11
+ });
7
12
  if (stderr.includes('Audio: mp3,')) {
8
13
  return 'mp3';
9
14
  }
package/dist/index.d.ts CHANGED
@@ -313,20 +313,14 @@ export declare const RenderInternals: {
313
313
  };
314
314
  makeFileExtensionMap: () => Record<string, ("h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif")[]>;
315
315
  defaultCodecsForFileExtension: Record<import("./file-extensions").FileExtension, "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif">;
316
- getExecutablePath: (type: "compositor" | "ffmpeg" | "ffprobe" | "lib", indent: boolean, logLevel: "verbose" | "info" | "warn" | "error") => string;
317
- callFf: (bin: "ffmpeg" | "ffprobe", args: (string | null)[], indent: boolean, logLevel: "verbose" | "info" | "warn" | "error", options?: execa.Options<string> | undefined) => execa.ExecaChildProcess<string>;
318
- dynamicLibraryPathOptions: (indent: boolean, logLevel: "verbose" | "info" | "warn" | "error") => {
319
- env: {
320
- DYLD_LIBRARY_PATH: string;
321
- RUST_BACKTRACE: string;
322
- } | {
323
- PATH: string;
324
- RUST_BACKTRACE: string;
325
- } | {
326
- LD_LIBRARY_PATH: string;
327
- RUST_BACKTRACE: string;
328
- };
329
- };
316
+ getExecutablePath: (type: "compositor" | "ffmpeg" | "ffprobe", indent: boolean, logLevel: "verbose" | "info" | "warn" | "error") => string;
317
+ callFf: ({ args, bin, indent, logLevel, options, }: {
318
+ bin: "ffmpeg" | "ffprobe";
319
+ args: (string | null)[];
320
+ indent: boolean;
321
+ logLevel: "verbose" | "info" | "warn" | "error";
322
+ options?: execa.Options<string> | undefined;
323
+ }) => execa.ExecaChildProcess<string>;
330
324
  validStillImageFormats: readonly ["png", "jpeg", "pdf", "webp"];
331
325
  validVideoImageFormats: readonly ["png", "jpeg", "none"];
332
326
  DEFAULT_STILL_IMAGE_FORMAT: "jpeg" | "png" | "webp" | "pdf";
package/dist/index.js CHANGED
@@ -171,7 +171,6 @@ exports.RenderInternals = {
171
171
  defaultCodecsForFileExtension: get_extension_from_codec_1.defaultCodecsForFileExtension,
172
172
  getExecutablePath: get_executable_path_1.getExecutablePath,
173
173
  callFf: call_ffmpeg_1.callFf,
174
- dynamicLibraryPathOptions: call_ffmpeg_1.dynamicLibraryPathOptions,
175
174
  validStillImageFormats: image_format_1.validStillImageFormats,
176
175
  validVideoImageFormats: image_format_1.validVideoImageFormats,
177
176
  DEFAULT_STILL_IMAGE_FORMAT: image_format_1.DEFAULT_STILL_IMAGE_FORMAT,
@@ -77,7 +77,7 @@ const mergeAudioTrackUnlimited = async ({ outName, files, numberOfSeconds, downl
77
77
  ]
78
78
  .filter(truthy_1.truthy)
79
79
  .flat(2);
80
- const task = (0, call_ffmpeg_1.callFf)('ffmpeg', args, indent, logLevel);
80
+ const task = (0, call_ffmpeg_1.callFf)({ bin: 'ffmpeg', args, indent, logLevel });
81
81
  await task;
82
82
  cleanup();
83
83
  };
@@ -6,6 +6,6 @@ export declare const colorSpaceOption: {
6
6
  description: () => import("react/jsx-runtime").JSX.Element;
7
7
  docLink: string;
8
8
  ssrName: string;
9
- type: "default" | "bt709" | "bt2020-ncl";
9
+ type: "bt709" | "bt2020-ncl" | "default";
10
10
  };
11
11
  export declare const validateColorSpace: (option: unknown) => void;
@@ -2,5 +2,5 @@ import type { Codec } from './codec';
2
2
  export declare const validPixelFormats: readonly ["yuv420p", "yuva420p", "yuv422p", "yuv444p", "yuv420p10le", "yuv422p10le", "yuv444p10le", "yuva444p10le"];
3
3
  export type PixelFormat = (typeof validPixelFormats)[number];
4
4
  export declare const DEFAULT_PIXEL_FORMAT: PixelFormat;
5
- export declare const validPixelFormatsForCodec: (codec: Codec) => readonly ["yuv420p", "yuva420p", "yuv422p", "yuv444p", "yuv420p10le", "yuv422p10le", "yuv444p10le", "yuva444p10le"] | ("yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le")[];
5
+ export declare const validPixelFormatsForCodec: (codec: Codec) => readonly ["yuv420p", "yuva420p", "yuv422p", "yuv444p", "yuv420p10le", "yuv422p10le", "yuv444p10le", "yuva444p10le"] | ("yuv420p" | "yuv422p" | "yuv444p" | "yuva420p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le")[];
6
6
  export declare const validateSelectedPixelFormatAndCodecCombination: (pixelFormat: PixelFormat | undefined, codec: Codec) => undefined;
@@ -114,10 +114,9 @@ const makeOrReuseServer = async (server, config, { onDownload, onError, }) => {
114
114
  return {
115
115
  server: newServer,
116
116
  cleanupServer: (force) => {
117
- newServer.closeServer(force);
118
117
  cleanupOnDownloadNew();
119
118
  cleanupErrorNew();
120
- return Promise.resolve();
119
+ return Promise.all([newServer.closeServer(force)]);
121
120
  },
122
121
  };
123
122
  };
@@ -29,7 +29,7 @@ const preprocessAudioTrackUnlimited = async ({ outName, asset, expectedFrames, f
29
29
  ['-ar', String(sample_rate_1.DEFAULT_SAMPLE_RATE)],
30
30
  ['-y', outName],
31
31
  ].flat(2);
32
- await (0, call_ffmpeg_1.callFf)('ffmpeg', args, indent, logLevel);
32
+ await (0, call_ffmpeg_1.callFf)({ bin: 'ffmpeg', args, indent, logLevel });
33
33
  cleanup();
34
34
  return { outName, filter };
35
35
  };
@@ -65,7 +65,12 @@ const prespawnFfmpeg = (options) => {
65
65
  const finalFfmpegString = options.ffmpegOverride
66
66
  ? options.ffmpegOverride({ type: 'pre-stitcher', args: ffmpegString })
67
67
  : ffmpegString;
68
- const task = (0, call_ffmpeg_1.callFf)('ffmpeg', finalFfmpegString, options.indent, options.logLevel);
68
+ const task = (0, call_ffmpeg_1.callFf)({
69
+ bin: 'ffmpeg',
70
+ args: finalFfmpegString,
71
+ indent: options.indent,
72
+ logLevel: options.logLevel,
73
+ });
69
74
  options.signal(() => {
70
75
  task.kill();
71
76
  });
package/dist/pure.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  export declare const NoReactAPIs: {
2
2
  wrapWithErrorHandling: <A extends unknown[], R>(fn: (...args: A) => Promise<R>) => (...args: A) => Promise<R>;
3
3
  getExtensionOfFilename: (filename: string | null) => string | null;
4
- getFileExtensionFromCodec: <T extends "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif">(codec: T, audioCodec: "mp3" | "aac" | "pcm-16" | "opus" | null) => import("./file-extensions").FileExtension;
5
- validateOutputFilename: <T_1 extends "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif">({ codec, audioCodec, extension, preferLossless, }: {
4
+ getFileExtensionFromCodec: <T extends "h264" | "h265" | "vp8" | "vp9" | "prores" | "aac" | "mp3" | "wav" | "h264-mkv" | "gif">(codec: T, audioCodec: "opus" | "aac" | "mp3" | "pcm-16" | null) => import("./file-extensions").FileExtension;
5
+ validateOutputFilename: <T_1 extends "h264" | "h265" | "vp8" | "vp9" | "prores" | "aac" | "mp3" | "wav" | "h264-mkv" | "gif">({ codec, audioCodec, extension, preferLossless, }: {
6
6
  codec: T_1;
7
- audioCodec: "mp3" | "aac" | "pcm-16" | "opus" | null;
7
+ audioCodec: "opus" | "aac" | "mp3" | "pcm-16" | null;
8
8
  extension: string;
9
9
  preferLossless: boolean;
10
10
  }) => void;
@@ -141,6 +141,7 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serialized
141
141
  cancelSignal === null || cancelSignal === void 0 ? void 0 : cancelSignal(() => {
142
142
  stopped = true;
143
143
  });
144
+ const frameDir = outputDir !== null && outputDir !== void 0 ? outputDir : downloadMap.compositingDir;
144
145
  const renderFrameWithOptionToReject = async ({ frame, index, reject, width, height, compId, }) => {
145
146
  const pool = await poolPromise;
146
147
  const freePage = await pool.acquire();
@@ -177,7 +178,6 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serialized
177
178
  throw new Error('Pass either `outputDir` or `onFrameBuffer` to renderFrames(), not both.');
178
179
  }
179
180
  const id = (0, perf_1.startPerfMeasure)('save');
180
- const frameDir = outputDir !== null && outputDir !== void 0 ? outputDir : downloadMap.compositingDir;
181
181
  const { buffer, collectedAssets } = await (0, take_frame_and_compose_1.takeFrameAndCompose)({
182
182
  frame,
183
183
  freePage,
@@ -298,7 +298,7 @@ const innerRenderFrames = async ({ onFrameUpdate, outputDir, onStart, serialized
298
298
  const returnValue = {
299
299
  assetsInfo: {
300
300
  assets,
301
- imageSequenceName: `element-%0${filePadLength}d.${imageFormat}`,
301
+ imageSequenceName: node_path_1.default.join(frameDir, `element-%0${filePadLength}d.${imageFormat}`),
302
302
  firstFrameIndex,
303
303
  downloadMap,
304
304
  },
@@ -360,8 +360,10 @@ const internalRenderFramesRaw = ({ browserExecutable, cancelSignal, chromiumOpti
360
360
  ]).then(([{ server: openedServer, cleanupServer }, pInstance]) => {
361
361
  const { serveUrl, offthreadPort, compositor, sourceMap, downloadMap } = openedServer;
362
362
  const browserReplacer = (0, replace_browser_1.handleBrowserCrash)(pInstance, logLevel, indent);
363
- cleanup.push((0, cycle_browser_tabs_1.cycleBrowserTabs)(browserReplacer, actualConcurrency, logLevel, indent)
364
- .stopCycling);
363
+ cleanup.push(() => {
364
+ (0, cycle_browser_tabs_1.cycleBrowserTabs)(browserReplacer, actualConcurrency, logLevel, indent).stopCycling();
365
+ return Promise.resolve();
366
+ });
365
367
  cleanup.push(() => cleanupServer(false));
366
368
  return innerRenderFrames({
367
369
  onError,
@@ -381,7 +381,6 @@ const internalRenderMediaRaw = ({ proResProfile, x264Preset, crf, composition, s
381
381
  onDownload,
382
382
  numberOfGifLoops,
383
383
  logLevel,
384
- dir: workingDir,
385
384
  cancelSignal: cancelStitcher.cancelSignal,
386
385
  muted: disableAudio,
387
386
  enforceAudioTrack,
@@ -454,7 +453,11 @@ const internalRenderMediaRaw = ({ proResProfile, x264Preset, crf, composition, s
454
453
  if (workingDir && node_fs_1.default.existsSync(workingDir)) {
455
454
  (0, delete_directory_1.deleteDirectory)(workingDir);
456
455
  }
457
- cleanupServerFn === null || cleanupServerFn === void 0 ? void 0 : cleanupServerFn(false);
456
+ cleanupServerFn === null || cleanupServerFn === void 0 ? void 0 : cleanupServerFn(false).catch((err) => {
457
+ // Must prevent unhandled exception in cleanup function.
458
+ // Might crash whole runtime.
459
+ console.log('Could not cleanup: ', err);
460
+ });
458
461
  });
459
462
  });
460
463
  return Promise.race([
@@ -234,7 +234,9 @@ const internalRenderStillRaw = (options) => {
234
234
  .catch((err) => reject(err))
235
235
  .finally(() => {
236
236
  cleanup.forEach((c) => {
237
- c();
237
+ c().catch((err) => {
238
+ console.log('Cleanup error:', err);
239
+ });
238
240
  });
239
241
  });
240
242
  });
@@ -152,7 +152,11 @@ const internalSelectCompositionRaw = async (options) => {
152
152
  })
153
153
  .finally(() => {
154
154
  cleanup.forEach((c) => {
155
- c();
155
+ // Must prevent unhandled exception in cleanup function.
156
+ // Promise has already been resolved, so we can't reject it.
157
+ c().catch((err) => {
158
+ console.log('Cleanup error:', err);
159
+ });
156
160
  });
157
161
  });
158
162
  });
@@ -37,6 +37,25 @@ const innerSetPropsAndEnv = async ({ serializedInputPropsWithCustomSchema, envVa
37
37
  await page.evaluateOnNewDocument((enabled) => {
38
38
  window.remotion_videoEnabled = enabled;
39
39
  }, videoEnabled);
40
+ await page.evaluateOnNewDocument(() => {
41
+ window.alert = (message) => {
42
+ if (message) {
43
+ window.window.remotion_cancelledError = new Error(`alert("${message}") was called. It cannot be called in a headless browser.`).stack;
44
+ }
45
+ else {
46
+ window.window.remotion_cancelledError = new Error('alert() was called. It cannot be called in a headless browser.').stack;
47
+ }
48
+ };
49
+ window.confirm = (message) => {
50
+ if (message) {
51
+ window.remotion_cancelledError = new Error(`confirm("${message}") was called. It cannot be called in a headless browser.`).stack;
52
+ }
53
+ else {
54
+ window.remotion_cancelledError = new Error('confirm() was called. It cannot be called in a headless browser.').stack;
55
+ }
56
+ return false;
57
+ };
58
+ });
40
59
  const pageRes = await page.goto({ url: urlToVisit, timeout: actualTimeout });
41
60
  if (pageRes === null) {
42
61
  throw new Error(`Visited "${urlToVisit}" but got no response.`);
@@ -30,7 +30,6 @@ type InternalStitchFramesToVideoOptions = {
30
30
  onDownload: undefined | RenderMediaOnDownload;
31
31
  proResProfile: undefined | ProResProfile;
32
32
  logLevel: LogLevel;
33
- dir: string;
34
33
  cancelSignal: CancelSignal | null;
35
34
  preEncodedFileLocation: string | null;
36
35
  preferLossless: boolean;
@@ -61,7 +60,6 @@ export type StitchFramesToVideoOptions = {
61
60
  onDownload?: RenderMediaOnDownload;
62
61
  proResProfile?: ProResProfile;
63
62
  verbose?: boolean;
64
- dir: string;
65
63
  cancelSignal?: CancelSignal;
66
64
  muted?: boolean;
67
65
  enforceAudioTrack?: boolean;
@@ -74,5 +72,5 @@ export declare const internalStitchFramesToVideo: (options: InternalStitchFrames
74
72
  * @description Takes a series of images and audio information generated by renderFrames() and encodes it to a video.
75
73
  * @see [Documentation](https://www.remotion.dev/docs/renderer/stitch-frames-to-video)
76
74
  */
77
- export declare const stitchFramesToVideo: ({ assetsInfo, force, fps, height, width, audioBitrate, audioCodec, cancelSignal, codec, crf, dir, enforceAudioTrack, ffmpegOverride, muted, numberOfGifLoops, onDownload, onProgress, outputLocation, pixelFormat, proResProfile, verbose, videoBitrate, encodingMaxRate, encodingBufferSize, x264Preset, colorSpace, }: StitchFramesToVideoOptions) => Promise<Buffer | null>;
75
+ export declare const stitchFramesToVideo: ({ assetsInfo, force, fps, height, width, audioBitrate, audioCodec, cancelSignal, codec, crf, enforceAudioTrack, ffmpegOverride, muted, numberOfGifLoops, onDownload, onProgress, outputLocation, pixelFormat, proResProfile, verbose, videoBitrate, encodingMaxRate, encodingBufferSize, x264Preset, colorSpace, }: StitchFramesToVideoOptions) => Promise<Buffer | null>;
78
76
  export {};
@@ -106,7 +106,7 @@ const getAssetsData = async ({ assets, onDownload, fps, expectedFrames, logLevel
106
106
  });
107
107
  return outName;
108
108
  };
109
- const innerStitchFramesToVideo = async ({ assetsInfo, audioBitrate, audioCodec, cancelSignal, codec, crf, dir, enforceAudioTrack, ffmpegOverride, force, fps, height, indent, muted, onDownload, outputLocation, pixelFormat, preEncodedFileLocation, preferLossless, proResProfile, logLevel, videoBitrate, encodingMaxRate, encodingBufferSize, width, numberOfGifLoops, onProgress, x264Preset, colorSpace, }, remotionRoot) => {
109
+ const innerStitchFramesToVideo = async ({ assetsInfo, audioBitrate, audioCodec, cancelSignal, codec, crf, enforceAudioTrack, ffmpegOverride, force, fps, height, indent, muted, onDownload, outputLocation, pixelFormat, preEncodedFileLocation, preferLossless, proResProfile, logLevel, videoBitrate, encodingMaxRate, encodingBufferSize, width, numberOfGifLoops, onProgress, x264Preset, colorSpace, }, remotionRoot) => {
110
110
  var _a;
111
111
  (0, validate_1.validateDimension)(height, 'height', 'passed to `stitchFramesToVideo()`');
112
112
  (0, validate_1.validateDimension)(width, 'width', 'passed to `stitchFramesToVideo()`');
@@ -197,16 +197,21 @@ const innerStitchFramesToVideo = async ({ assetsInfo, audioBitrate, audioCodec,
197
197
  if (!resolvedAudioCodec) {
198
198
  throw new TypeError('exporting audio but has no audio codec name. Report this in the Remotion repo.');
199
199
  }
200
- const ffmpegTask = (0, call_ffmpeg_1.callFf)('ffmpeg', [
201
- '-i',
202
- audio,
203
- '-c:a',
204
- (0, audio_codec_1.mapAudioCodecToFfmpegAudioCodecName)(resolvedAudioCodec),
205
- '-b:a',
206
- audioBitrate ? audioBitrate : '320k',
207
- force ? '-y' : null,
208
- outputLocation !== null && outputLocation !== void 0 ? outputLocation : tempFile,
209
- ].filter(no_react_1.NoReactInternals.truthy), indent, logLevel);
200
+ const ffmpegTask = (0, call_ffmpeg_1.callFf)({
201
+ bin: 'ffmpeg',
202
+ args: [
203
+ '-i',
204
+ audio,
205
+ '-c:a',
206
+ (0, audio_codec_1.mapAudioCodecToFfmpegAudioCodecName)(resolvedAudioCodec),
207
+ '-b:a',
208
+ audioBitrate ? audioBitrate : '320k',
209
+ force ? '-y' : null,
210
+ outputLocation !== null && outputLocation !== void 0 ? outputLocation : tempFile,
211
+ ].filter(no_react_1.NoReactInternals.truthy),
212
+ indent,
213
+ logLevel,
214
+ });
210
215
  cancelSignal === null || cancelSignal === void 0 ? void 0 : cancelSignal(() => {
211
216
  ffmpegTask.kill();
212
217
  });
@@ -294,8 +299,11 @@ const innerStitchFramesToVideo = async ({ assetsInfo, audioBitrate, audioCodec,
294
299
  logLevel,
295
300
  tag: 'stitchFramesToVideo()',
296
301
  }, finalFfmpegString.join(' '));
297
- const task = (0, call_ffmpeg_1.callFf)('ffmpeg', finalFfmpegString, indent, logLevel, {
298
- cwd: dir,
302
+ const task = (0, call_ffmpeg_1.callFf)({
303
+ bin: 'ffmpeg',
304
+ args: finalFfmpegString,
305
+ indent,
306
+ logLevel,
299
307
  });
300
308
  cancelSignal === null || cancelSignal === void 0 ? void 0 : cancelSignal(() => {
301
309
  task.kill();
@@ -366,7 +374,7 @@ exports.internalStitchFramesToVideo = internalStitchFramesToVideo;
366
374
  * @description Takes a series of images and audio information generated by renderFrames() and encodes it to a video.
367
375
  * @see [Documentation](https://www.remotion.dev/docs/renderer/stitch-frames-to-video)
368
376
  */
369
- const stitchFramesToVideo = ({ assetsInfo, force, fps, height, width, audioBitrate, audioCodec, cancelSignal, codec, crf, dir, enforceAudioTrack, ffmpegOverride, muted, numberOfGifLoops, onDownload, onProgress, outputLocation, pixelFormat, proResProfile, verbose, videoBitrate, encodingMaxRate, encodingBufferSize, x264Preset, colorSpace, }) => {
377
+ const stitchFramesToVideo = ({ assetsInfo, force, fps, height, width, audioBitrate, audioCodec, cancelSignal, codec, crf, enforceAudioTrack, ffmpegOverride, muted, numberOfGifLoops, onDownload, onProgress, outputLocation, pixelFormat, proResProfile, verbose, videoBitrate, encodingMaxRate, encodingBufferSize, x264Preset, colorSpace, }) => {
370
378
  return (0, exports.internalStitchFramesToVideo)({
371
379
  assetsInfo,
372
380
  audioBitrate: audioBitrate !== null && audioBitrate !== void 0 ? audioBitrate : null,
@@ -376,7 +384,6 @@ const stitchFramesToVideo = ({ assetsInfo, force, fps, height, width, audioBitra
376
384
  cancelSignal: cancelSignal !== null && cancelSignal !== void 0 ? cancelSignal : null,
377
385
  codec: codec !== null && codec !== void 0 ? codec : codec_1.DEFAULT_CODEC,
378
386
  crf: crf !== null && crf !== void 0 ? crf : null,
379
- dir,
380
387
  enforceAudioTrack: enforceAudioTrack !== null && enforceAudioTrack !== void 0 ? enforceAudioTrack : false,
381
388
  ffmpegOverride: ffmpegOverride !== null && ffmpegOverride !== void 0 ? ffmpegOverride : null,
382
389
  force,
@@ -66,10 +66,10 @@ const takeFrameAndCompose = async ({ freePage, imageFormat, jpegQuality, frame,
66
66
  }
67
67
  if (needsComposing) {
68
68
  if (imageFormat === 'pdf') {
69
- throw new Error("You cannot use compositor APIs (like <Clipper>) if `imageFormat` is 'pdf'.");
69
+ throw new Error("You cannot use Rust APIs (like <Clipper>) if `imageFormat` is 'pdf'.");
70
70
  }
71
71
  if (imageFormat === 'webp') {
72
- throw new Error("You cannot use compositor APIs (like <Clipper>) if `imageFormat` is 'webp'.");
72
+ throw new Error("You cannot use Rust APIs (like <Clipper>) if `imageFormat` is 'webp'.");
73
73
  }
74
74
  await (0, compose_1.compose)({
75
75
  height: height * scale,
@@ -1,5 +1,5 @@
1
1
  import type { AudioCodec } from './audio-codec';
2
- export declare const validateOutputFilename: <T extends "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif">({ codec, audioCodec, extension, preferLossless, }: {
2
+ export declare const validateOutputFilename: <T extends "h264" | "h265" | "vp8" | "vp9" | "prores" | "aac" | "mp3" | "wav" | "h264-mkv" | "gif">({ codec, audioCodec, extension, preferLossless, }: {
3
3
  codec: T;
4
4
  audioCodec: AudioCodec | null;
5
5
  extension: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/renderer",
3
- "version": "4.0.102",
3
+ "version": "4.0.103",
4
4
  "description": "Renderer for Remotion",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,7 +18,7 @@
18
18
  "extract-zip": "2.0.1",
19
19
  "source-map": "^0.8.0-beta.0",
20
20
  "ws": "8.7.0",
21
- "remotion": "4.0.102"
21
+ "remotion": "4.0.103"
22
22
  },
23
23
  "peerDependencies": {
24
24
  "react": ">=16.8.0",
@@ -40,13 +40,13 @@
40
40
  "vitest": "0.31.1"
41
41
  },
42
42
  "optionalDependencies": {
43
- "@remotion/compositor-darwin-x64": "4.0.102",
44
- "@remotion/compositor-darwin-arm64": "4.0.102",
45
- "@remotion/compositor-linux-x64-gnu": "4.0.102",
46
- "@remotion/compositor-linux-arm64-musl": "4.0.102",
47
- "@remotion/compositor-win32-x64-msvc": "4.0.102",
48
- "@remotion/compositor-linux-arm64-gnu": "4.0.102",
49
- "@remotion/compositor-linux-x64-musl": "4.0.102"
43
+ "@remotion/compositor-darwin-x64": "4.0.103",
44
+ "@remotion/compositor-darwin-arm64": "4.0.103",
45
+ "@remotion/compositor-linux-arm64-musl": "4.0.103",
46
+ "@remotion/compositor-linux-x64-gnu": "4.0.103",
47
+ "@remotion/compositor-linux-arm64-gnu": "4.0.103",
48
+ "@remotion/compositor-linux-x64-musl": "4.0.103",
49
+ "@remotion/compositor-win32-x64-msvc": "4.0.103"
50
50
  },
51
51
  "keywords": [
52
52
  "remotion",
@@ -1,3 +0,0 @@
1
- import type { LogLevel } from './log-level';
2
- export declare const gLibCErrorMessage: (libCString: string) => string | null;
3
- export declare const checkNodeVersionAndWarnAboutRosetta: (logLevel: LogLevel, indent: boolean) => void;
@@ -1,42 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.checkNodeVersionAndWarnAboutRosetta = exports.gLibCErrorMessage = void 0;
4
- const logger_1 = require("./logger");
5
- const gLibCErrorMessage = (libCString) => {
6
- const split = libCString.split('.');
7
- if (split.length !== 2) {
8
- return null;
9
- }
10
- if (split[0] === '2' && Number(split[1]) >= 35) {
11
- return null;
12
- }
13
- if (Number(split[0]) > 2) {
14
- return null;
15
- }
16
- return `Rendering videos requires glibc 2.35 or higher. Your system has glibc ${libCString}.`;
17
- };
18
- exports.gLibCErrorMessage = gLibCErrorMessage;
19
- const checkLibCRequirement = (logLevel, indent) => {
20
- const { report } = process;
21
- if (report) {
22
- // @ts-expect-error no types
23
- const { glibcVersionRuntime } = report.getReport().header;
24
- if (!glibcVersionRuntime) {
25
- return;
26
- }
27
- const error = (0, exports.gLibCErrorMessage)(glibcVersionRuntime);
28
- if (error) {
29
- logger_1.Log.warn({ logLevel, indent }, error);
30
- }
31
- }
32
- };
33
- const checkNodeVersionAndWarnAboutRosetta = (logLevel, indent) => {
34
- const version = process.version.replace('v', '').split('.');
35
- const majorVersion = Number(version[0]);
36
- const requiredNodeVersion = 16;
37
- if (majorVersion < 16) {
38
- throw new Error(`Remotion requires at least Node ${requiredNodeVersion}. You currently have ${process.version}. Update your node version to ${requiredNodeVersion} to use Remotion.`);
39
- }
40
- checkLibCRequirement(logLevel, indent);
41
- };
42
- exports.checkNodeVersionAndWarnAboutRosetta = checkNodeVersionAndWarnAboutRosetta;