@remotion/cli 3.0.31 → 3.1.0

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.
@@ -35,7 +35,7 @@ const listCompositionsCommand = async () => {
35
35
  const fullPath = path_1.default.join(process.cwd(), file);
36
36
  await (0, get_config_file_name_1.loadConfig)();
37
37
  const { browserExecutable, ffmpegExecutable, ffprobeExecutable, chromiumOptions, envVariables, inputProps, puppeteerTimeout, port, } = await (0, get_cli_options_1.getCliOptions)({ isLambda: false, type: 'get-compositions' });
38
- const bundled = await (0, setup_cache_1.bundleOnCli)(fullPath, ['bundling']);
38
+ const bundled = await (0, setup_cache_1.bundleOnCli)({ fullPath, steps: ['bundling'] });
39
39
  const compositions = await (0, renderer_1.getCompositions)(bundled, {
40
40
  browserExecutable,
41
41
  ffmpegExecutable,
@@ -46,12 +46,18 @@ const listCompositionsCommand = async () => {
46
46
  timeoutInMilliseconds: puppeteerTimeout,
47
47
  port,
48
48
  });
49
- log_1.Log.info();
50
- log_1.Log.info('The following compositions are available:');
51
- log_1.Log.info();
49
+ if (!(0, parse_command_line_1.quietFlagProvided)()) {
50
+ log_1.Log.info();
51
+ log_1.Log.info('The following compositions are available:');
52
+ log_1.Log.info();
53
+ }
52
54
  const firstColumnLength = max(compositions.map(({ id }) => id.length)) + 4;
53
55
  const secondColumnLength = 8;
54
56
  const thirdColumnLength = 15;
57
+ if ((0, parse_command_line_1.quietFlagProvided)()) {
58
+ log_1.Log.info(compositions.map((c) => c.id).join(' '));
59
+ return;
60
+ }
55
61
  log_1.Log.info(`${'Composition'.padEnd(firstColumnLength, ' ')}${'FPS'.padEnd(secondColumnLength)}${'Dimensions'.padEnd(thirdColumnLength, ' ')}Duration`);
56
62
  log_1.Log.info(compositions
57
63
  .map((comp) => {
@@ -8,7 +8,7 @@ export declare const getCliOptions: (options: {
8
8
  parallelism: number | null;
9
9
  frameRange: FrameRange | null;
10
10
  shouldOutputImageSequence: boolean;
11
- codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv";
11
+ codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif";
12
12
  overwrite: boolean;
13
13
  inputProps: object;
14
14
  envVariables: Record<string, string>;
@@ -19,6 +19,8 @@ export declare const getCliOptions: (options: {
19
19
  pixelFormat: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le";
20
20
  imageFormat: "png" | "jpeg" | "none";
21
21
  proResProfile: "4444-xq" | "4444" | "hq" | "standard" | "light" | "proxy" | undefined;
22
+ everyNthFrame: number;
23
+ numberOfGifLoops: number | null;
22
24
  stillFrame: number;
23
25
  browserExecutable: BrowserExecutable;
24
26
  ffmpegExecutable: import("remotion").FfmpegExecutable;
@@ -152,6 +152,8 @@ const getCliOptions = async (options) => {
152
152
  headless: remotion_1.Internals.getChromiumHeadlessMode(),
153
153
  gl: (_a = remotion_1.Internals.getChromiumOpenGlRenderer()) !== null && _a !== void 0 ? _a : remotion_1.Internals.DEFAULT_OPENGL_RENDERER,
154
154
  };
155
+ const everyNthFrame = remotion_1.Internals.getAndValidateEveryNthFrame(codec);
156
+ const numberOfGifLoops = remotion_1.Internals.getAndValidateNumberOfGifLoops(codec);
155
157
  const parallelism = remotion_1.Internals.getConcurrency();
156
158
  renderer_1.RenderInternals.validateConcurrency(parallelism, 'concurrency');
157
159
  return {
@@ -172,6 +174,8 @@ const getCliOptions = async (options) => {
172
174
  pixelFormat,
173
175
  imageFormat,
174
176
  proResProfile,
177
+ everyNthFrame,
178
+ numberOfGifLoops,
175
179
  stillFrame: remotion_1.Internals.getStillFrame(),
176
180
  browserExecutable,
177
181
  ffmpegExecutable,
@@ -15,7 +15,8 @@ const getImageFormat = (codec) => {
15
15
  codec === 'h265' ||
16
16
  codec === 'vp8' ||
17
17
  codec === 'vp9' ||
18
- codec === 'prores') {
18
+ codec === 'prores' ||
19
+ codec === 'gif') {
19
20
  return 'jpeg';
20
21
  }
21
22
  if (codec === undefined) {
package/dist/index.d.ts CHANGED
@@ -74,7 +74,7 @@ export declare const CliInternals: {
74
74
  parallelism: number | null;
75
75
  frameRange: import("remotion").FrameRange | null;
76
76
  shouldOutputImageSequence: boolean;
77
- codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv";
77
+ codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif";
78
78
  overwrite: boolean;
79
79
  inputProps: object;
80
80
  envVariables: Record<string, string>;
@@ -85,6 +85,8 @@ export declare const CliInternals: {
85
85
  pixelFormat: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le";
86
86
  imageFormat: "png" | "jpeg" | "none";
87
87
  proResProfile: "4444-xq" | "4444" | "hq" | "standard" | "light" | "proxy" | undefined;
88
+ everyNthFrame: number;
89
+ numberOfGifLoops: number | null;
88
90
  stillFrame: number;
89
91
  browserExecutable: import("remotion").BrowserExecutable;
90
92
  ffmpegExecutable: import("remotion").FfmpegExecutable;
@@ -11,6 +11,8 @@ export declare type CommandLineOptions = {
11
11
  ['env-file']: string;
12
12
  ['ignore-certificate-errors']: string;
13
13
  ['disable-web-security']: string;
14
+ ['every-nth-frame']: number;
15
+ ['number-of-gif-loops']: number;
14
16
  codec: Codec;
15
17
  concurrency: number;
16
18
  timeout: number;
@@ -42,6 +42,9 @@ const parseCommandLine = (type) => {
42
42
  if (exports.parsedCli['ffmpeg-executable']) {
43
43
  remotion_1.Config.Rendering.setFfmpegExecutable((0, path_1.resolve)(exports.parsedCli['ffmpeg-executable']));
44
44
  }
45
+ if (exports.parsedCli['number-of-gif-loops']) {
46
+ remotion_1.Config.Rendering.setNumberOfGifLoops(exports.parsedCli['number-of-gif-loops']);
47
+ }
45
48
  if (exports.parsedCli['ffprobe-executable']) {
46
49
  remotion_1.Config.Rendering.setFfprobeExecutable((0, path_1.resolve)(exports.parsedCli['ffprobe-executable']));
47
50
  }
@@ -57,9 +60,6 @@ const parseCommandLine = (type) => {
57
60
  if (exports.parsedCli['disable-headless']) {
58
61
  remotion_1.Config.Puppeteer.setChromiumHeadlessMode(false);
59
62
  }
60
- if (exports.parsedCli.gl) {
61
- remotion_1.Config.Puppeteer.setChromiumOpenGlRenderer(exports.parsedCli.gl);
62
- }
63
63
  if (exports.parsedCli.log) {
64
64
  if (!remotion_1.Internals.Logging.isValidLogLevel(exports.parsedCli.log)) {
65
65
  log_1.Log.error('Invalid `--log` value passed.');
@@ -104,6 +104,12 @@ const parseCommandLine = (type) => {
104
104
  if (exports.parsedCli.codec) {
105
105
  remotion_1.Config.Output.setCodec(exports.parsedCli.codec);
106
106
  }
107
+ if (exports.parsedCli['every-nth-frame']) {
108
+ remotion_1.Config.Rendering.setEveryNthFrame(exports.parsedCli['every-nth-frame']);
109
+ }
110
+ if (exports.parsedCli.gl) {
111
+ remotion_1.Config.Puppeteer.setChromiumOpenGlRenderer(exports.parsedCli.gl);
112
+ }
107
113
  if (exports.parsedCli['prores-profile']) {
108
114
  remotion_1.Config.Output.setProResProfile(String(exports.parsedCli['prores-profile']));
109
115
  }
@@ -1,4 +1,5 @@
1
1
  import type { StitchingState } from '@remotion/renderer';
2
+ import type { Codec } from 'remotion';
2
3
  import type { RenderStep } from './step';
3
4
  export declare const createProgressBar: (quiet: boolean) => {
4
5
  update: (str: string) => boolean;
@@ -25,8 +26,9 @@ declare type StitchingProgressInput = {
25
26
  steps: RenderStep[];
26
27
  doneIn: number | null;
27
28
  stage: StitchingState;
29
+ codec: Codec;
28
30
  };
29
- export declare const makeStitchingProgress: ({ frames, totalFrames, steps, doneIn, stage, }: StitchingProgressInput) => string;
31
+ export declare const makeStitchingProgress: ({ frames, totalFrames, steps, doneIn, stage, codec, }: StitchingProgressInput) => string;
30
32
  export declare type DownloadProgress = {
31
33
  name: string;
32
34
  id: number;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.makeRenderingAndStitchingProgress = exports.makeStitchingProgress = exports.makeRenderingProgress = exports.makeBundlingProgress = exports.createOverwriteableCliOutput = exports.createProgressBar = void 0;
4
+ const renderer_1 = require("@remotion/renderer");
4
5
  const remotion_1 = require("remotion");
5
6
  const ansi_diff_1 = require("./ansi/ansi-diff");
6
7
  const chalk_1 = require("./chalk");
@@ -46,14 +47,14 @@ const makeRenderingProgress = ({ frames, totalFrames, steps, concurrency, doneIn
46
47
  ].join(' ');
47
48
  };
48
49
  exports.makeRenderingProgress = makeRenderingProgress;
49
- const makeStitchingProgress = ({ frames, totalFrames, steps, doneIn, stage, }) => {
50
+ const makeStitchingProgress = ({ frames, totalFrames, steps, doneIn, stage, codec, }) => {
50
51
  const progress = frames / totalFrames;
51
52
  return [
52
53
  `(${steps.indexOf('stitching') + 1}/${steps.length})`,
53
54
  (0, make_progress_bar_1.makeProgressBar)(progress),
54
- stage === 'muxing'
55
+ stage === 'muxing' && renderer_1.RenderInternals.canUseParallelEncoding(codec)
55
56
  ? `${doneIn ? 'Muxed' : 'Muxing'} audio`
56
- : `${doneIn ? 'Encoded' : 'Encoding'} video`,
57
+ : `${doneIn ? 'Encoded' : 'Encoding'} ${codec === 'gif' ? 'GIF' : 'video'}`,
57
58
  doneIn === null ? `${frames}/${totalFrames}` : chalk_1.chalk.gray(`${doneIn}ms`),
58
59
  ].join(' ');
59
60
  };
package/dist/render.js CHANGED
@@ -31,7 +31,7 @@ const render = async () => {
31
31
  ? file
32
32
  : path_1.default.join(process.cwd(), file);
33
33
  await (0, initialize_render_cli_1.initializeRenderCli)('sequence');
34
- const { codec, proResProfile, parallelism, frameRange, shouldOutputImageSequence, absoluteOutputFile, overwrite, inputProps, envVariables, quality, browser, crf, pixelFormat, imageFormat, browserExecutable, ffmpegExecutable, ffprobeExecutable, scale, chromiumOptions, port, puppeteerTimeout, } = await (0, get_cli_options_1.getCliOptions)({ isLambda: false, type: 'series' });
34
+ const { codec, proResProfile, parallelism, frameRange, shouldOutputImageSequence, absoluteOutputFile, overwrite, inputProps, envVariables, quality, browser, crf, pixelFormat, imageFormat, browserExecutable, ffmpegExecutable, ffprobeExecutable, scale, chromiumOptions, port, numberOfGifLoops, everyNthFrame, puppeteerTimeout, } = await (0, get_cli_options_1.getCliOptions)({ isLambda: false, type: 'series' });
35
35
  if (!absoluteOutputFile) {
36
36
  throw new Error('assertion error - expected absoluteOutputFile to not be null');
37
37
  }
@@ -52,7 +52,7 @@ const render = async () => {
52
52
  ].filter(remotion_1.Internals.truthy);
53
53
  const urlOrBundle = renderer_1.RenderInternals.isServeUrl(fullPath)
54
54
  ? fullPath
55
- : await (0, setup_cache_1.bundleOnCli)(fullPath, steps);
55
+ : await (0, setup_cache_1.bundleOnCli)({ fullPath, steps });
56
56
  const onDownload = (src) => {
57
57
  const id = Math.random();
58
58
  const download = {
@@ -96,7 +96,8 @@ const render = async () => {
96
96
  : await fs_1.default.promises.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'react-motion-render'));
97
97
  log_1.Log.verbose('Output dir', outputDir);
98
98
  const renderProgress = (0, progress_bar_1.createOverwriteableCliOutput)((0, parse_command_line_1.quietFlagProvided)());
99
- let totalFrames = renderer_1.RenderInternals.getDurationFromFrameRange(frameRange, config.durationInFrames);
99
+ const realFrameRange = renderer_1.RenderInternals.getRealFrameRange(config.durationInFrames, frameRange);
100
+ const totalFrames = renderer_1.RenderInternals.getFramesToRender(realFrameRange, everyNthFrame);
100
101
  let encodedFrames = 0;
101
102
  let renderedFrames = 0;
102
103
  let encodedDoneIn = null;
@@ -104,13 +105,13 @@ const render = async () => {
104
105
  let stitchStage = 'encoding';
105
106
  const downloads = [];
106
107
  const updateRenderProgress = () => {
107
- if (totalFrames === null) {
108
+ if (totalFrames.length === 0) {
108
109
  throw new Error('totalFrames should not be 0');
109
110
  }
110
111
  return renderProgress.update((0, progress_bar_1.makeRenderingAndStitchingProgress)({
111
112
  rendering: {
112
113
  frames: renderedFrames,
113
- totalFrames,
114
+ totalFrames: totalFrames.length,
114
115
  concurrency: renderer_1.RenderInternals.getActualConcurrency(parallelism),
115
116
  doneIn: renderedDoneIn,
116
117
  steps,
@@ -122,7 +123,8 @@ const render = async () => {
122
123
  frames: encodedFrames,
123
124
  stage: stitchStage,
124
125
  steps,
125
- totalFrames,
126
+ totalFrames: totalFrames.length,
127
+ codec,
126
128
  },
127
129
  downloads,
128
130
  }));
@@ -144,10 +146,7 @@ const render = async () => {
144
146
  renderedFrames = rendered;
145
147
  updateRenderProgress();
146
148
  },
147
- onStart: ({ frameCount }) => {
148
- totalFrames = frameCount;
149
- return updateRenderProgress();
150
- },
149
+ onStart: () => undefined,
151
150
  onDownload: (src) => {
152
151
  if (src.startsWith('data:')) {
153
152
  log_1.Log.info('\nWriting Data URL to file: ', src.substring(0, 30) + '...');
@@ -159,6 +158,7 @@ const render = async () => {
159
158
  outputDir,
160
159
  serveUrl: urlOrBundle,
161
160
  dumpBrowserLogs: remotion_1.Internals.Logging.isEqualOrBelowLogLevel(remotion_1.Internals.Logging.getLogLevel(), 'verbose'),
161
+ everyNthFrame,
162
162
  envVariables,
163
163
  frameRange,
164
164
  parallelism,
@@ -207,13 +207,12 @@ const render = async () => {
207
207
  serveUrl: urlOrBundle,
208
208
  onDownload,
209
209
  dumpBrowserLogs: remotion_1.Internals.Logging.isEqualOrBelowLogLevel(remotion_1.Internals.Logging.getLogLevel(), 'verbose'),
210
- onStart: ({ frameCount }) => {
211
- totalFrames = frameCount;
212
- },
213
210
  chromiumOptions,
214
211
  timeoutInMilliseconds: remotion_1.Internals.getCurrentPuppeteerTimeout(),
215
212
  scale,
216
213
  port,
214
+ numberOfGifLoops,
215
+ everyNthFrame,
217
216
  });
218
217
  log_1.Log.info();
219
218
  log_1.Log.info();
@@ -234,7 +233,7 @@ const render = async () => {
234
233
  log_1.Log.warn(err);
235
234
  log_1.Log.warn('Do you have minimum required Node.js version?');
236
235
  }
237
- log_1.Log.info(chalk_1.chalk.green('\nYour video is ready!'));
236
+ log_1.Log.info(chalk_1.chalk.green(`\nYour ${codec === 'gif' ? 'GIF' : 'video'} is ready!`));
238
237
  if (remotion_1.Internals.Logging.isEqualOrBelowLogLevel(remotion_1.Internals.Logging.getLogLevel(), 'verbose')) {
239
238
  remotion_1.Internals.perf.logPerf();
240
239
  }
@@ -1,2 +1,5 @@
1
1
  import type { RenderStep } from './step';
2
- export declare const bundleOnCli: (fullPath: string, steps: RenderStep[]) => Promise<string>;
2
+ export declare const bundleOnCli: ({ fullPath, steps, }: {
3
+ fullPath: string;
4
+ steps: RenderStep[];
5
+ }) => Promise<string>;
@@ -6,7 +6,7 @@ const remotion_1 = require("remotion");
6
6
  const log_1 = require("./log");
7
7
  const parse_command_line_1 = require("./parse-command-line");
8
8
  const progress_bar_1 = require("./progress-bar");
9
- const bundleOnCli = async (fullPath, steps) => {
9
+ const bundleOnCli = async ({ fullPath, steps, }) => {
10
10
  var _a;
11
11
  const shouldCache = remotion_1.Internals.getWebpackCaching();
12
12
  const cacheExistedBefore = bundler_1.BundlerInternals.cacheExists('production');
package/dist/still.js CHANGED
@@ -62,7 +62,7 @@ const still = async () => {
62
62
  ].filter(remotion_1.Internals.truthy);
63
63
  const urlOrBundle = renderer_1.RenderInternals.isServeUrl(fullPath)
64
64
  ? Promise.resolve(fullPath)
65
- : await (0, setup_cache_1.bundleOnCli)(fullPath, steps);
65
+ : await (0, setup_cache_1.bundleOnCli)({ fullPath, steps });
66
66
  const puppeteerInstance = await browserInstance;
67
67
  const comps = await (0, renderer_1.getCompositions)(await urlOrBundle, {
68
68
  inputProps,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/cli",
3
- "version": "3.0.31",
3
+ "version": "3.1.0",
4
4
  "description": "CLI for Remotion",
5
5
  "main": "dist/index.js",
6
6
  "sideEffects": false,
@@ -10,7 +10,7 @@
10
10
  "module": "true",
11
11
  "scripts": {
12
12
  "lint": "eslint src --ext ts,tsx",
13
- "test": "jest",
13
+ "test": "vitest --run",
14
14
  "build": "tsc -d",
15
15
  "watch": "tsc -w"
16
16
  },
@@ -23,17 +23,18 @@
23
23
  "author": "Jonny Burger <jonny@remotion.dev>",
24
24
  "license": "SEE LICENSE IN LICENSE.md",
25
25
  "dependencies": {
26
- "@remotion/bundler": "3.0.31",
27
- "@remotion/media-utils": "3.0.31",
28
- "@remotion/player": "3.0.31",
29
- "@remotion/renderer": "3.0.31",
26
+ "@remotion/bundler": "3.1.0",
27
+ "@remotion/media-utils": "3.1.0",
28
+ "@remotion/player": "3.1.0",
29
+ "@remotion/renderer": "3.1.0",
30
30
  "better-opn": "2.1.1",
31
31
  "dotenv": "9.0.2",
32
32
  "memfs": "3.4.3",
33
33
  "minimist": "1.2.6",
34
- "remotion": "3.0.31",
34
+ "remotion": "3.1.0",
35
35
  "semver": "7.3.5",
36
- "source-map": "0.6.1"
36
+ "source-map": "0.6.1",
37
+ "vitest": "^0.18.0"
37
38
  },
38
39
  "peerDependencies": {
39
40
  "react": ">=16.8.0",
@@ -41,7 +42,6 @@
41
42
  },
42
43
  "devDependencies": {
43
44
  "@jonny/eslint-config": "3.0.266",
44
- "@types/jest": "^27.4.0",
45
45
  "@types/minimist": "^1.2.2",
46
46
  "@types/node": "^16.7.5",
47
47
  "@types/react": "18.0.1",
@@ -54,12 +54,10 @@
54
54
  "eslint-plugin-10x": "1.5.2",
55
55
  "eslint-plugin-react": "7.29.4",
56
56
  "eslint-plugin-react-hooks": "4.4.0",
57
- "jest": "^27.2.4",
58
57
  "prettier": "^2.0.5",
59
58
  "prettier-plugin-organize-imports": "^2.3.4",
60
59
  "react": "^18.0.0",
61
60
  "react-dom": "^18.0.0",
62
- "ts-jest": "^27.0.5",
63
61
  "typescript": "^4.7.0"
64
62
  },
65
63
  "keywords": [
@@ -73,5 +71,5 @@
73
71
  "publishConfig": {
74
72
  "access": "public"
75
73
  },
76
- "gitHead": "9342296ce1634b8b7b6dbdaee810a961f6922516"
74
+ "gitHead": "482c66127662171577aa427f10fe265fa1bc933b"
77
75
  }
package/tsconfig.json CHANGED
@@ -12,5 +12,6 @@
12
12
  {"path": "../renderer"},
13
13
  {"path": "../player"},
14
14
  {"path": "../media-utils"}
15
- ]
15
+ ],
16
+ "exclude": ["vitest.config.ts", "dist"]
16
17
  }
@@ -0,0 +1,9 @@
1
+ import {defineConfig} from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ testTimeout: 90000,
6
+ maxConcurrency: 1,
7
+ threads: false,
8
+ },
9
+ });