@remotion/cloudrun 4.0.21 → 4.0.23
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.
- package/.turbo/turbo-build.log +3 -3
- package/dist/api/render-media-on-cloudrun.d.ts +6 -3
- package/dist/api/render-media-on-cloudrun.js +26 -9
- package/dist/api/render-still-on-cloudrun.d.ts +5 -4
- package/dist/api/render-still-on-cloudrun.js +52 -3
- package/dist/cli/commands/render/index.js +7 -52
- package/dist/cli/commands/render/renderMedia.d.ts +2 -0
- package/dist/cli/commands/render/renderMedia.js +156 -0
- package/dist/cli/commands/render/renderStill.d.ts +2 -0
- package/dist/cli/commands/render/renderStill.js +123 -0
- package/dist/cli/commands/still.js +24 -16
- package/dist/cli/helpers/cloudrun-crash-logs.d.ts +2 -0
- package/dist/cli/helpers/cloudrun-crash-logs.js +57 -0
- package/dist/cli/index.js +18 -2
- package/dist/functions/helpers/get-composition-from-body.js +1 -0
- package/dist/functions/helpers/payloads.d.ts +35 -23
- package/dist/functions/helpers/payloads.js +10 -5
- package/dist/functions/helpers/write-cloudrun-error.d.ts +12 -0
- package/dist/functions/helpers/write-cloudrun-error.js +18 -0
- package/dist/functions/index.js +6 -8
- package/dist/functions/render-media-single-thread.js +107 -88
- package/dist/functions/render-still-single-thread.js +82 -65
- package/dist/shared/read-dir.js +4 -2
- package/package.json +7 -7
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
|
|
2
|
-
> @remotion/cloudrun@4.0.
|
|
2
|
+
> @remotion/cloudrun@4.0.22 build /Users/jonathanburger/remotion-v4/packages/cloudrun
|
|
3
3
|
> tsc -d && cp src/shared/sa-permissions.json dist/shared/sa-permissions.json && pnpm run buildContainer && pnpm run tarInstaller
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @remotion/cloudrun@4.0.
|
|
6
|
+
> @remotion/cloudrun@4.0.22 buildContainer /Users/jonathanburger/remotion-v4/packages/cloudrun
|
|
7
7
|
> ts-node src/admin/bundle-renderLogic.ts
|
|
8
8
|
|
|
9
9
|
distribution bundled.
|
|
10
10
|
|
|
11
|
-
> @remotion/cloudrun@4.0.
|
|
11
|
+
> @remotion/cloudrun@4.0.22 tarInstaller /Users/jonathanburger/remotion-v4/packages/cloudrun
|
|
12
12
|
> ts-node src/admin/bundle-installer.ts
|
|
13
13
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { AudioCodec, ChromiumOptions, FrameRange, LogLevel, PixelFormat, ProResProfile, VideoImageFormat } from '@remotion/renderer';
|
|
1
|
+
import type { AudioCodec, ChromiumOptions, FrameRange, LogLevel, PixelFormat, ProResProfile, ToOptions, VideoImageFormat, X264Preset } from '@remotion/renderer';
|
|
2
|
+
import type { BrowserSafeApis } from '@remotion/renderer/client';
|
|
2
3
|
import type { CloudRunCrashResponse, RenderMediaOnCloudrunOutput } from '../functions/helpers/payloads';
|
|
3
4
|
import type { GcpRegion } from '../pricing/gcp-regions';
|
|
4
5
|
import type { CloudrunCodec } from '../shared/validate-gcp-codec';
|
|
@@ -19,6 +20,7 @@ export type RenderMediaOnCloudrunInput = {
|
|
|
19
20
|
audioBitrate?: string | null;
|
|
20
21
|
videoBitrate?: string | null;
|
|
21
22
|
proResProfile?: ProResProfile;
|
|
23
|
+
x264Preset?: X264Preset;
|
|
22
24
|
crf?: number | undefined;
|
|
23
25
|
pixelFormat?: PixelFormat;
|
|
24
26
|
imageFormat?: VideoImageFormat;
|
|
@@ -36,7 +38,7 @@ export type RenderMediaOnCloudrunInput = {
|
|
|
36
38
|
concurrency?: number | string | null;
|
|
37
39
|
enforceAudioTrack?: boolean;
|
|
38
40
|
preferLossless?: boolean;
|
|
39
|
-
}
|
|
41
|
+
} & Partial<ToOptions<typeof BrowserSafeApis.optionsMap.renderMediaOnLambda>>;
|
|
40
42
|
/**
|
|
41
43
|
* @description Triggers a render on a GCP Cloud Run service given a composition and a Cloud Run URL.
|
|
42
44
|
* @see [Documentation](https://remotion.dev/docs/cloudrun/renderMediaOnGcp)
|
|
@@ -56,6 +58,7 @@ export type RenderMediaOnCloudrunInput = {
|
|
|
56
58
|
* @param params.audioBitrate The target bitrate for the audio of the generated video.
|
|
57
59
|
* @param params.videoBitrate The target bitrate of the generated video.
|
|
58
60
|
* @param params.proResProfile Sets a ProRes profile. Only applies to videos rendered with prores codec.
|
|
61
|
+
* @param params.x264Preset Sets a Preset profile. Only applies to videos rendered with h.264 codec.
|
|
59
62
|
* @param params.crf Constant Rate Factor, controlling the quality.
|
|
60
63
|
* @param params.pixelFormat Custom pixel format to use. Usually used for special use cases like transparent videos.
|
|
61
64
|
* @param params.imageFormat Which image format the frames should be rendered in.
|
|
@@ -75,4 +78,4 @@ export type RenderMediaOnCloudrunInput = {
|
|
|
75
78
|
* @param params.preferLossless Uses a lossless audio codec, if one is available for the codec. If you set audioCodec, it takes priority over preferLossless.
|
|
76
79
|
* @returns {Promise<RenderMediaOnCloudrunOutput>} See documentation for detailed structure
|
|
77
80
|
*/
|
|
78
|
-
export declare const renderMediaOnCloudrun: ({ cloudRunUrl, serviceName, region, serveUrl, composition, inputProps, codec, forceBucketName, privacy, outName, updateRenderProgress, jpegQuality, audioCodec, audioBitrate, videoBitrate, proResProfile, crf, pixelFormat, imageFormat, scale, everyNthFrame, numberOfGifLoops, frameRange, envVariables, chromiumOptions, muted, forceWidth, forceHeight, logLevel, delayRenderTimeoutInMilliseconds, concurrency, enforceAudioTrack, preferLossless, }: RenderMediaOnCloudrunInput) => Promise<RenderMediaOnCloudrunOutput | CloudRunCrashResponse>;
|
|
81
|
+
export declare const renderMediaOnCloudrun: ({ cloudRunUrl, serviceName, region, serveUrl, composition, inputProps, codec, forceBucketName, privacy, outName, updateRenderProgress, jpegQuality, audioCodec, audioBitrate, videoBitrate, proResProfile, x264Preset, crf, pixelFormat, imageFormat, scale, everyNthFrame, numberOfGifLoops, frameRange, envVariables, chromiumOptions, muted, forceWidth, forceHeight, logLevel, delayRenderTimeoutInMilliseconds, concurrency, enforceAudioTrack, preferLossless, offthreadVideoCacheSizeInBytes, }: RenderMediaOnCloudrunInput) => Promise<RenderMediaOnCloudrunOutput | CloudRunCrashResponse>;
|
|
@@ -28,6 +28,7 @@ const get_cloudrun_endpoint_1 = require("./helpers/get-cloudrun-endpoint");
|
|
|
28
28
|
* @param params.audioBitrate The target bitrate for the audio of the generated video.
|
|
29
29
|
* @param params.videoBitrate The target bitrate of the generated video.
|
|
30
30
|
* @param params.proResProfile Sets a ProRes profile. Only applies to videos rendered with prores codec.
|
|
31
|
+
* @param params.x264Preset Sets a Preset profile. Only applies to videos rendered with h.264 codec.
|
|
31
32
|
* @param params.crf Constant Rate Factor, controlling the quality.
|
|
32
33
|
* @param params.pixelFormat Custom pixel format to use. Usually used for special use cases like transparent videos.
|
|
33
34
|
* @param params.imageFormat Which image format the frames should be rendered in.
|
|
@@ -47,7 +48,7 @@ const get_cloudrun_endpoint_1 = require("./helpers/get-cloudrun-endpoint");
|
|
|
47
48
|
* @param params.preferLossless Uses a lossless audio codec, if one is available for the codec. If you set audioCodec, it takes priority over preferLossless.
|
|
48
49
|
* @returns {Promise<RenderMediaOnCloudrunOutput>} See documentation for detailed structure
|
|
49
50
|
*/
|
|
50
|
-
const renderMediaOnCloudrun = async ({ cloudRunUrl, serviceName, region, serveUrl, composition, inputProps, codec, forceBucketName, privacy, outName, updateRenderProgress, jpegQuality, audioCodec, audioBitrate, videoBitrate, proResProfile, crf, pixelFormat, imageFormat, scale, everyNthFrame, numberOfGifLoops, frameRange, envVariables, chromiumOptions, muted, forceWidth, forceHeight, logLevel, delayRenderTimeoutInMilliseconds, concurrency, enforceAudioTrack, preferLossless, }) => {
|
|
51
|
+
const renderMediaOnCloudrun = async ({ cloudRunUrl, serviceName, region, serveUrl, composition, inputProps, codec, forceBucketName, privacy, outName, updateRenderProgress, jpegQuality, audioCodec, audioBitrate, videoBitrate, proResProfile, x264Preset, crf, pixelFormat, imageFormat, scale, everyNthFrame, numberOfGifLoops, frameRange, envVariables, chromiumOptions, muted, forceWidth, forceHeight, logLevel, delayRenderTimeoutInMilliseconds, concurrency, enforceAudioTrack, preferLossless, offthreadVideoCacheSizeInBytes, }) => {
|
|
51
52
|
const actualCodec = (0, validate_gcp_codec_1.validateCloudrunCodec)(codec);
|
|
52
53
|
(0, validate_serveurl_1.validateServeUrl)(serveUrl);
|
|
53
54
|
if (privacy)
|
|
@@ -76,6 +77,7 @@ const renderMediaOnCloudrun = async ({ cloudRunUrl, serviceName, region, serveUr
|
|
|
76
77
|
imageFormat: imageFormat !== null && imageFormat !== void 0 ? imageFormat : renderer_1.RenderInternals.DEFAULT_VIDEO_IMAGE_FORMAT,
|
|
77
78
|
scale: scale !== null && scale !== void 0 ? scale : 1,
|
|
78
79
|
proResProfile: proResProfile !== null && proResProfile !== void 0 ? proResProfile : null,
|
|
80
|
+
x264Preset: x264Preset !== null && x264Preset !== void 0 ? x264Preset : null,
|
|
79
81
|
everyNthFrame: everyNthFrame !== null && everyNthFrame !== void 0 ? everyNthFrame : 1,
|
|
80
82
|
numberOfGifLoops: numberOfGifLoops !== null && numberOfGifLoops !== void 0 ? numberOfGifLoops : null,
|
|
81
83
|
frameRange: frameRange !== null && frameRange !== void 0 ? frameRange : null,
|
|
@@ -93,6 +95,7 @@ const renderMediaOnCloudrun = async ({ cloudRunUrl, serviceName, region, serveUr
|
|
|
93
95
|
concurrency: concurrency !== null && concurrency !== void 0 ? concurrency : null,
|
|
94
96
|
enforceAudioTrack: enforceAudioTrack !== null && enforceAudioTrack !== void 0 ? enforceAudioTrack : false,
|
|
95
97
|
preferLossless: preferLossless !== null && preferLossless !== void 0 ? preferLossless : false,
|
|
98
|
+
offthreadVideoCacheSizeInBytes: offthreadVideoCacheSizeInBytes !== null && offthreadVideoCacheSizeInBytes !== void 0 ? offthreadVideoCacheSizeInBytes : null,
|
|
96
99
|
};
|
|
97
100
|
const client = await (0, get_auth_client_for_url_1.getAuthClientForUrl)(cloudRunEndpoint);
|
|
98
101
|
const postResponse = await client.request({
|
|
@@ -107,13 +110,27 @@ const renderMediaOnCloudrun = async ({ cloudRunUrl, serviceName, region, serveUr
|
|
|
107
110
|
const startTime = Date.now();
|
|
108
111
|
const formattedStartTime = new Date().toISOString();
|
|
109
112
|
const stream = postResponse.data;
|
|
113
|
+
let accumulatedChunks = ''; // A buffer to accumulate chunks.
|
|
110
114
|
stream.on('data', (chunk) => {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
115
|
+
accumulatedChunks += chunk.toString(); // Add the new chunk to the buffer.
|
|
116
|
+
let parsedData;
|
|
117
|
+
try {
|
|
118
|
+
parsedData = JSON.parse(accumulatedChunks.trim());
|
|
119
|
+
accumulatedChunks = ''; // Clear the buffer after successful parsing.
|
|
114
120
|
}
|
|
115
|
-
|
|
116
|
-
|
|
121
|
+
catch (e) {
|
|
122
|
+
// If parsing fails, it means we don't have a complete JSON string yet.
|
|
123
|
+
// We'll wait for more chunks.
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (parsedData.response) {
|
|
127
|
+
response = parsedData.response;
|
|
128
|
+
}
|
|
129
|
+
else if (parsedData.onProgress) {
|
|
130
|
+
updateRenderProgress === null || updateRenderProgress === void 0 ? void 0 : updateRenderProgress(parsedData.onProgress);
|
|
131
|
+
}
|
|
132
|
+
if (parsedData.type === 'error') {
|
|
133
|
+
reject(parsedData);
|
|
117
134
|
}
|
|
118
135
|
});
|
|
119
136
|
stream.on('end', () => {
|
|
@@ -122,7 +139,7 @@ const renderMediaOnCloudrun = async ({ cloudRunUrl, serviceName, region, serveUr
|
|
|
122
139
|
const formattedCrashTime = new Date().toISOString();
|
|
123
140
|
updateRenderProgress === null || updateRenderProgress === void 0 ? void 0 : updateRenderProgress(0, true);
|
|
124
141
|
resolve({
|
|
125
|
-
|
|
142
|
+
type: 'crash',
|
|
126
143
|
cloudRunEndpoint,
|
|
127
144
|
message: 'Service crashed without sending a response. Check the logs in GCP console.',
|
|
128
145
|
requestStartTime: formattedStartTime,
|
|
@@ -130,8 +147,8 @@ const renderMediaOnCloudrun = async ({ cloudRunUrl, serviceName, region, serveUr
|
|
|
130
147
|
requestElapsedTimeInSeconds: (crashTime - startTime) / 1000,
|
|
131
148
|
});
|
|
132
149
|
}
|
|
133
|
-
else if (response.
|
|
134
|
-
throw
|
|
150
|
+
else if (response.type !== 'success' && response.type !== 'crash') {
|
|
151
|
+
throw response;
|
|
135
152
|
}
|
|
136
153
|
resolve(response);
|
|
137
154
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { ChromiumOptions, LogLevel, StillImageFormat } from '@remotion/renderer';
|
|
2
|
-
import type {
|
|
1
|
+
import type { ChromiumOptions, LogLevel, StillImageFormat, ToOptions } from '@remotion/renderer';
|
|
2
|
+
import type { BrowserSafeApis } from '@remotion/renderer/client';
|
|
3
|
+
import type { CloudRunCrashResponse, ErrorResponsePayload, RenderStillOnCloudrunOutput } from '../functions/helpers/payloads';
|
|
3
4
|
import type { GcpRegion } from '../pricing/gcp-regions';
|
|
4
5
|
export type RenderStillOnCloudrunInput = {
|
|
5
6
|
cloudRunUrl?: string;
|
|
@@ -21,7 +22,7 @@ export type RenderStillOnCloudrunInput = {
|
|
|
21
22
|
forceHeight?: number | null;
|
|
22
23
|
logLevel?: LogLevel;
|
|
23
24
|
delayRenderTimeoutInMilliseconds?: number;
|
|
24
|
-
}
|
|
25
|
+
} & Partial<ToOptions<typeof BrowserSafeApis.optionsMap.renderMediaOnLambda>>;
|
|
25
26
|
/**
|
|
26
27
|
* @description Triggers a render on a GCP Cloud Run service given a composition and a Cloud Run URL.
|
|
27
28
|
* @see [Documentation](https://remotion.dev/docs/cloudrun/renderstilloncloudrun)
|
|
@@ -46,4 +47,4 @@ export type RenderStillOnCloudrunInput = {
|
|
|
46
47
|
* @param params.delayRenderTimeoutInMilliseconds A number describing how long the render may take to resolve all delayRender() calls before it times out.
|
|
47
48
|
* @returns {Promise<RenderStillOnCloudrunOutput>} See documentation for detailed structure
|
|
48
49
|
*/
|
|
49
|
-
export declare const renderStillOnCloudrun: ({ cloudRunUrl, serviceName, region, serveUrl, composition, inputProps, forceBucketName, privacy, outName, imageFormat, envVariables, frame, jpegQuality, chromiumOptions, scale, forceWidth, forceHeight, logLevel, delayRenderTimeoutInMilliseconds, }: RenderStillOnCloudrunInput) => Promise<RenderStillOnCloudrunOutput>;
|
|
50
|
+
export declare const renderStillOnCloudrun: ({ cloudRunUrl, serviceName, region, serveUrl, composition, inputProps, forceBucketName, privacy, outName, imageFormat, envVariables, frame, jpegQuality, chromiumOptions, scale, forceWidth, forceHeight, logLevel, delayRenderTimeoutInMilliseconds, offthreadVideoCacheSizeInBytes, }: RenderStillOnCloudrunInput) => Promise<RenderStillOnCloudrunOutput | ErrorResponsePayload | CloudRunCrashResponse>;
|
|
@@ -32,7 +32,7 @@ const get_cloudrun_endpoint_1 = require("./helpers/get-cloudrun-endpoint");
|
|
|
32
32
|
* @param params.delayRenderTimeoutInMilliseconds A number describing how long the render may take to resolve all delayRender() calls before it times out.
|
|
33
33
|
* @returns {Promise<RenderStillOnCloudrunOutput>} See documentation for detailed structure
|
|
34
34
|
*/
|
|
35
|
-
const renderStillOnCloudrun = async ({ cloudRunUrl, serviceName, region, serveUrl, composition, inputProps, forceBucketName, privacy, outName, imageFormat, envVariables, frame, jpegQuality, chromiumOptions, scale, forceWidth, forceHeight, logLevel, delayRenderTimeoutInMilliseconds, }) => {
|
|
35
|
+
const renderStillOnCloudrun = async ({ cloudRunUrl, serviceName, region, serveUrl, composition, inputProps, forceBucketName, privacy, outName, imageFormat, envVariables, frame, jpegQuality, chromiumOptions, scale, forceWidth, forceHeight, logLevel, delayRenderTimeoutInMilliseconds, offthreadVideoCacheSizeInBytes, }) => {
|
|
36
36
|
(0, validate_serveurl_1.validateServeUrl)(serveUrl);
|
|
37
37
|
if (privacy)
|
|
38
38
|
(0, validate_privacy_1.validatePrivacy)(privacy);
|
|
@@ -64,13 +64,62 @@ const renderStillOnCloudrun = async ({ cloudRunUrl, serviceName, region, serveUr
|
|
|
64
64
|
type: 'still',
|
|
65
65
|
logLevel: logLevel !== null && logLevel !== void 0 ? logLevel : 'info',
|
|
66
66
|
delayRenderTimeoutInMilliseconds: delayRenderTimeoutInMilliseconds !== null && delayRenderTimeoutInMilliseconds !== void 0 ? delayRenderTimeoutInMilliseconds : renderer_1.RenderInternals.DEFAULT_TIMEOUT,
|
|
67
|
+
offthreadVideoCacheSizeInBytes: offthreadVideoCacheSizeInBytes !== null && offthreadVideoCacheSizeInBytes !== void 0 ? offthreadVideoCacheSizeInBytes : null,
|
|
67
68
|
};
|
|
68
69
|
const client = await (0, get_auth_client_for_url_1.getAuthClientForUrl)(cloudRunEndpoint);
|
|
69
|
-
const
|
|
70
|
+
const postResponse = await client.request({
|
|
70
71
|
url: cloudRunUrl,
|
|
71
72
|
method: 'POST',
|
|
72
73
|
data,
|
|
74
|
+
responseType: 'stream',
|
|
73
75
|
});
|
|
74
|
-
|
|
76
|
+
const renderResponse = await new Promise((resolve, reject) => {
|
|
77
|
+
let response;
|
|
78
|
+
const startTime = Date.now();
|
|
79
|
+
const formattedStartTime = new Date().toISOString();
|
|
80
|
+
const stream = postResponse.data;
|
|
81
|
+
let accumulatedChunks = ''; // A buffer to accumulate chunks.
|
|
82
|
+
stream.on('data', (chunk) => {
|
|
83
|
+
accumulatedChunks += chunk.toString(); // Add the new chunk to the buffer.
|
|
84
|
+
let parsedData;
|
|
85
|
+
try {
|
|
86
|
+
parsedData = JSON.parse(accumulatedChunks.trim());
|
|
87
|
+
accumulatedChunks = ''; // Clear the buffer after successful parsing.
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
// If parsing fails, it means we don't have a complete JSON string yet.
|
|
91
|
+
// We'll wait for more chunks.
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (parsedData.response) {
|
|
95
|
+
response = parsedData.response;
|
|
96
|
+
}
|
|
97
|
+
if (parsedData.type === 'error') {
|
|
98
|
+
reject(parsedData);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
stream.on('end', () => {
|
|
102
|
+
if (!response) {
|
|
103
|
+
const crashTime = Date.now();
|
|
104
|
+
const formattedCrashTime = new Date().toISOString();
|
|
105
|
+
resolve({
|
|
106
|
+
type: 'crash',
|
|
107
|
+
cloudRunEndpoint,
|
|
108
|
+
message: 'Service crashed without sending a response. Check the logs in GCP console.',
|
|
109
|
+
requestStartTime: formattedStartTime,
|
|
110
|
+
requestCrashTime: formattedCrashTime,
|
|
111
|
+
requestElapsedTimeInSeconds: (crashTime - startTime) / 1000,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
else if (response.type !== 'success' && response.type !== 'crash') {
|
|
115
|
+
throw response;
|
|
116
|
+
}
|
|
117
|
+
resolve(response);
|
|
118
|
+
});
|
|
119
|
+
stream.on('error', (error) => {
|
|
120
|
+
reject(error);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
return renderResponse;
|
|
75
124
|
};
|
|
76
125
|
exports.renderStillOnCloudrun = renderStillOnCloudrun;
|
|
@@ -6,12 +6,10 @@ const config_1 = require("@remotion/cli/config");
|
|
|
6
6
|
const renderer_1 = require("@remotion/renderer");
|
|
7
7
|
const remotion_1 = require("remotion");
|
|
8
8
|
const download_file_1 = require("../../../api/download-file");
|
|
9
|
-
const extract_mem_from_url_1 = require("../../../api/helpers/extract-mem-from-url");
|
|
10
|
-
const extract_time_from_url_1 = require("../../../api/helpers/extract-time-from-url");
|
|
11
|
-
const get_cloud_logging_client_1 = require("../../../api/helpers/get-cloud-logging-client");
|
|
12
9
|
const render_media_on_cloudrun_1 = require("../../../api/render-media-on-cloudrun");
|
|
13
10
|
const validate_serveurl_1 = require("../../../shared/validate-serveurl");
|
|
14
11
|
const args_1 = require("../../args");
|
|
12
|
+
const cloudrun_crash_logs_1 = require("../../helpers/cloudrun-crash-logs");
|
|
15
13
|
const log_1 = require("../../log");
|
|
16
14
|
const renderArgsCheck_1 = require("./helpers/renderArgsCheck");
|
|
17
15
|
exports.RENDER_COMMAND = 'render';
|
|
@@ -27,7 +25,7 @@ const renderCommand = async (args, remotionRoot) => {
|
|
|
27
25
|
});
|
|
28
26
|
const imageFormat = args_1.parsedCloudrunCli['image-format'];
|
|
29
27
|
const audioCodec = args_1.parsedCloudrunCli['audio-codec'];
|
|
30
|
-
const { chromiumOptions, crf, envVariables, frameRange, inputProps, logLevel, puppeteerTimeout, pixelFormat, proResProfile, jpegQuality, scale, everyNthFrame, numberOfGifLoops, muted, audioBitrate, videoBitrate, height, width, browserExecutable, port, enforceAudioTrack, } = await cli_1.CliInternals.getCliOptions({
|
|
28
|
+
const { chromiumOptions, crf, envVariables, frameRange, inputProps, logLevel, puppeteerTimeout, pixelFormat, proResProfile, jpegQuality, scale, everyNthFrame, numberOfGifLoops, muted, audioBitrate, videoBitrate, height, width, browserExecutable, port, enforceAudioTrack, offthreadVideoCacheSizeInBytes, } = await cli_1.CliInternals.getCliOptions({
|
|
31
29
|
type: 'series',
|
|
32
30
|
isLambda: true,
|
|
33
31
|
remotionRoot,
|
|
@@ -46,6 +44,7 @@ const renderCommand = async (args, remotionRoot) => {
|
|
|
46
44
|
remotionRoot,
|
|
47
45
|
logLevel,
|
|
48
46
|
webpackConfigOrServeUrl: serveUrl,
|
|
47
|
+
offthreadVideoCacheSizeInBytes: offthreadVideoCacheSizeInBytes !== null && offthreadVideoCacheSizeInBytes !== void 0 ? offthreadVideoCacheSizeInBytes : null,
|
|
49
48
|
});
|
|
50
49
|
const { compositionId } = await cli_1.CliInternals.getCompositionWithDimensionOverride({
|
|
51
50
|
args: args.slice(1),
|
|
@@ -67,6 +66,7 @@ const renderCommand = async (args, remotionRoot) => {
|
|
|
67
66
|
indent: undefined,
|
|
68
67
|
staticBase: null,
|
|
69
68
|
}).serializedString,
|
|
69
|
+
offthreadVideoCacheSizeInBytes,
|
|
70
70
|
});
|
|
71
71
|
composition = compositionId;
|
|
72
72
|
}
|
|
@@ -152,55 +152,10 @@ ${downloadName ? ` Downloaded File = ${downloadName}` : ''}
|
|
|
152
152
|
enforceAudioTrack,
|
|
153
153
|
preferLossless: false,
|
|
154
154
|
});
|
|
155
|
-
if (res.
|
|
156
|
-
|
|
157
|
-
const timeout = (0, extract_time_from_url_1.extractTimeoutFromURL)(res.cloudRunEndpoint);
|
|
158
|
-
const memoryLimit = (0, extract_mem_from_url_1.extractMemoryFromURL)(res.cloudRunEndpoint);
|
|
159
|
-
if (timeout && res.requestElapsedTimeInSeconds + 10 > timeout) {
|
|
160
|
-
timeoutPreMsg = `Render call likely timed out. Service timeout is ${timeout} seconds, and render took at least ${res.requestElapsedTimeInSeconds.toFixed(1)} seconds.\n`;
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
timeoutPreMsg = `Crash unlikely due to timeout. Render took ${res.requestElapsedTimeInSeconds.toFixed(1)} seconds, below the timeout of ${timeout} seconds.\n`;
|
|
164
|
-
}
|
|
165
|
-
log_1.Log.error(`Error rendering on Cloud Run. The Cloud Run service did not return a response.\n
|
|
166
|
-
${timeoutPreMsg}The crash may be due to the service exceeding its memory limit of ${memoryLimit}.
|
|
167
|
-
Full logs are available at https://console.cloud.google.com/run?project=${process.env.REMOTION_GCP_PROJECT_ID}\n`);
|
|
168
|
-
const cloudLoggingClient = (0, get_cloud_logging_client_1.getCloudLoggingClient)();
|
|
169
|
-
const listLogEntriesRequest = {
|
|
170
|
-
resourceNames: [`projects/${process.env.REMOTION_GCP_PROJECT_ID}`],
|
|
171
|
-
filter: `logName=projects/${process.env.REMOTION_GCP_PROJECT_ID}/logs/run.googleapis.com%2Fvarlog%2Fsystem AND (severity=WARNING OR severity=ERROR) AND timestamp >= "${res.requestStartTime}"`,
|
|
172
|
-
};
|
|
173
|
-
const logCheckCountdown = cli_1.CliInternals.createOverwriteableCliOutput({
|
|
174
|
-
quiet: cli_1.CliInternals.quietFlagProvided(),
|
|
175
|
-
cancelSignal: null,
|
|
176
|
-
updatesDontOverwrite: false,
|
|
177
|
-
indent: false,
|
|
178
|
-
});
|
|
179
|
-
await (() => {
|
|
180
|
-
return new Promise((resolve) => {
|
|
181
|
-
let timeLeft = 30;
|
|
182
|
-
const intervalId = setInterval(() => {
|
|
183
|
-
logCheckCountdown.update(`GCP Cloud Logging takes time to ingest and index logs.\nFetching recent error/warning logs in ${timeLeft} seconds`, false);
|
|
184
|
-
timeLeft--;
|
|
185
|
-
if (timeLeft < 0) {
|
|
186
|
-
logCheckCountdown.update('Fetching logs...\n\n', false);
|
|
187
|
-
clearInterval(intervalId);
|
|
188
|
-
resolve();
|
|
189
|
-
}
|
|
190
|
-
}, 1000);
|
|
191
|
-
});
|
|
192
|
-
})();
|
|
193
|
-
const iterableLogListEntries = await cloudLoggingClient.listLogEntriesAsync(listLogEntriesRequest);
|
|
194
|
-
for await (const logResponse of iterableLogListEntries) {
|
|
195
|
-
const responseDate = new Date(Number(logResponse.timestamp.seconds) * 1000 +
|
|
196
|
-
Number(logResponse.timestamp.nanos) / 1000000);
|
|
197
|
-
const convertedDate = responseDate.toLocaleString();
|
|
198
|
-
log_1.Log.info(convertedDate);
|
|
199
|
-
log_1.Log.info(logResponse.textPayload);
|
|
200
|
-
log_1.Log.info();
|
|
201
|
-
}
|
|
155
|
+
if (res.type === 'crash') {
|
|
156
|
+
(0, cloudrun_crash_logs_1.displayCrashLogs)(res);
|
|
202
157
|
}
|
|
203
|
-
else if (res.
|
|
158
|
+
else if (res.type === 'success') {
|
|
204
159
|
renderProgress.doneIn = Date.now() - renderStart;
|
|
205
160
|
updateProgress();
|
|
206
161
|
log_1.Log.info(`
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderMediaSubcommand = exports.RENDER_MEDIA_SUBCOMMAND = void 0;
|
|
4
|
+
const cli_1 = require("@remotion/cli");
|
|
5
|
+
const render_media_on_cloudrun_1 = require("../../../api/render-media-on-cloudrun");
|
|
6
|
+
// import {validateMaxRetries} from '../../../shared/validate-retries';
|
|
7
|
+
const config_1 = require("@remotion/cli/config");
|
|
8
|
+
const renderer_1 = require("@remotion/renderer");
|
|
9
|
+
const download_file_1 = require("../../../api/download-file");
|
|
10
|
+
const validate_serveurl_1 = require("../../../shared/validate-serveurl");
|
|
11
|
+
const args_1 = require("../../args");
|
|
12
|
+
const log_1 = require("../../log");
|
|
13
|
+
const renderArgsCheck_1 = require("./helpers/renderArgsCheck");
|
|
14
|
+
exports.RENDER_MEDIA_SUBCOMMAND = 'media';
|
|
15
|
+
const renderMediaSubcommand = async (args, remotionRoot) => {
|
|
16
|
+
var _a;
|
|
17
|
+
const { serveUrl, cloudRunUrl, outName, forceBucketName, downloadName, privacy, region, } = await (0, renderArgsCheck_1.renderArgsCheck)(exports.RENDER_MEDIA_SUBCOMMAND, args);
|
|
18
|
+
const { codec, reason: codecReason } = cli_1.CliInternals.getFinalOutputCodec({
|
|
19
|
+
cliFlag: cli_1.CliInternals.parsedCli.codec,
|
|
20
|
+
downloadName,
|
|
21
|
+
outName: outName !== null && outName !== void 0 ? outName : null,
|
|
22
|
+
configFile: (_a = config_1.ConfigInternals.getOutputCodecOrUndefined()) !== null && _a !== void 0 ? _a : null,
|
|
23
|
+
uiCodec: null,
|
|
24
|
+
});
|
|
25
|
+
const imageFormat = args_1.parsedCloudrunCli['image-format'];
|
|
26
|
+
const audioCodec = args_1.parsedCloudrunCli['audio-codec'];
|
|
27
|
+
const { chromiumOptions, crf, envVariables, frameRange, inputProps, logLevel, puppeteerTimeout, pixelFormat, proResProfile, jpegQuality, scale, everyNthFrame, numberOfGifLoops, muted, audioBitrate, videoBitrate, height, width, browserExecutable, port, } = await cli_1.CliInternals.getCliOptions({
|
|
28
|
+
type: 'series',
|
|
29
|
+
isLambda: true,
|
|
30
|
+
remotionRoot,
|
|
31
|
+
});
|
|
32
|
+
let composition = args[1];
|
|
33
|
+
if (!composition) {
|
|
34
|
+
log_1.Log.info('No compositions passed. Fetching compositions...');
|
|
35
|
+
(0, validate_serveurl_1.validateServeUrl)(serveUrl);
|
|
36
|
+
const server = renderer_1.RenderInternals.prepareServer({
|
|
37
|
+
concurrency: 1,
|
|
38
|
+
indent: false,
|
|
39
|
+
port,
|
|
40
|
+
remotionRoot,
|
|
41
|
+
verbose: renderer_1.RenderInternals.isEqualOrBelowLogLevel(logLevel, 'verbose'),
|
|
42
|
+
webpackConfigOrServeUrl: serveUrl,
|
|
43
|
+
});
|
|
44
|
+
const { compositionId } = await cli_1.CliInternals.getCompositionWithDimensionOverride({
|
|
45
|
+
args,
|
|
46
|
+
compositionIdFromUi: null,
|
|
47
|
+
browserExecutable,
|
|
48
|
+
chromiumOptions,
|
|
49
|
+
envVariables,
|
|
50
|
+
height,
|
|
51
|
+
indent: false,
|
|
52
|
+
inputProps,
|
|
53
|
+
port,
|
|
54
|
+
puppeteerInstance: undefined,
|
|
55
|
+
serveUrlOrWebpackUrl: serveUrl,
|
|
56
|
+
timeoutInMilliseconds: puppeteerTimeout,
|
|
57
|
+
verbose: renderer_1.RenderInternals.isEqualOrBelowLogLevel(logLevel, 'verbose'),
|
|
58
|
+
width,
|
|
59
|
+
server: await server,
|
|
60
|
+
});
|
|
61
|
+
composition = compositionId;
|
|
62
|
+
}
|
|
63
|
+
// Todo: Check cloudRunUrl is valid, as the error message is obtuse
|
|
64
|
+
cli_1.CliInternals.Log.info(cli_1.CliInternals.chalk.gray(`
|
|
65
|
+
Cloud Run Service URL = ${cloudRunUrl}
|
|
66
|
+
Region = ${region}
|
|
67
|
+
Type = media
|
|
68
|
+
Composition = ${composition}
|
|
69
|
+
Codec = ${codec}
|
|
70
|
+
Output Bucket = ${forceBucketName}
|
|
71
|
+
Output File = ${outName !== null && outName !== void 0 ? outName : 'out.mp4'}
|
|
72
|
+
Output File Privacy = ${privacy}
|
|
73
|
+
${downloadName ? ` Downloaded File = ${downloadName}` : ''}
|
|
74
|
+
`.trim()));
|
|
75
|
+
log_1.Log.info();
|
|
76
|
+
const renderStart = Date.now();
|
|
77
|
+
const progressBar = cli_1.CliInternals.createOverwriteableCliOutput({
|
|
78
|
+
quiet: cli_1.CliInternals.quietFlagProvided(),
|
|
79
|
+
cancelSignal: null,
|
|
80
|
+
updatesDontOverwrite: false,
|
|
81
|
+
indent: false,
|
|
82
|
+
});
|
|
83
|
+
const renderProgress = {
|
|
84
|
+
doneIn: null,
|
|
85
|
+
progress: 0,
|
|
86
|
+
};
|
|
87
|
+
const updateProgress = () => {
|
|
88
|
+
progressBar.update([
|
|
89
|
+
`Rendering on Cloud Run: `,
|
|
90
|
+
cli_1.CliInternals.makeProgressBar(renderProgress.progress),
|
|
91
|
+
`${renderProgress.doneIn === null ? 'Rendering' : 'Rendered'}`,
|
|
92
|
+
renderProgress.doneIn === null
|
|
93
|
+
? `${Math.round(renderProgress.progress * 100)}%`
|
|
94
|
+
: cli_1.CliInternals.chalk.gray(`${renderProgress.doneIn}ms`),
|
|
95
|
+
].join(' '), false);
|
|
96
|
+
};
|
|
97
|
+
const updateRenderProgress = (progress) => {
|
|
98
|
+
renderProgress.progress = progress;
|
|
99
|
+
updateProgress();
|
|
100
|
+
};
|
|
101
|
+
const res = await (0, render_media_on_cloudrun_1.renderMediaOnCloudrun)({
|
|
102
|
+
cloudRunUrl,
|
|
103
|
+
serveUrl,
|
|
104
|
+
region,
|
|
105
|
+
inputProps,
|
|
106
|
+
codec: codec,
|
|
107
|
+
imageFormat,
|
|
108
|
+
crf: crf !== null && crf !== void 0 ? crf : undefined,
|
|
109
|
+
envVariables,
|
|
110
|
+
pixelFormat,
|
|
111
|
+
proResProfile,
|
|
112
|
+
jpegQuality,
|
|
113
|
+
composition,
|
|
114
|
+
privacy,
|
|
115
|
+
frameRange: frameRange !== null && frameRange !== void 0 ? frameRange : undefined,
|
|
116
|
+
outName,
|
|
117
|
+
chromiumOptions,
|
|
118
|
+
scale,
|
|
119
|
+
numberOfGifLoops,
|
|
120
|
+
everyNthFrame,
|
|
121
|
+
muted,
|
|
122
|
+
audioBitrate,
|
|
123
|
+
videoBitrate,
|
|
124
|
+
forceHeight: height,
|
|
125
|
+
forceWidth: width,
|
|
126
|
+
audioCodec,
|
|
127
|
+
forceBucketName,
|
|
128
|
+
updateRenderProgress,
|
|
129
|
+
logLevel: config_1.ConfigInternals.Logging.getLogLevel(),
|
|
130
|
+
});
|
|
131
|
+
renderProgress.doneIn = Date.now() - renderStart;
|
|
132
|
+
updateProgress();
|
|
133
|
+
log_1.Log.info(`
|
|
134
|
+
|
|
135
|
+
`);
|
|
136
|
+
log_1.Log.info(cli_1.CliInternals.chalk.blueBright(`
|
|
137
|
+
${res.publicUrl ? `Public URL = ${decodeURIComponent(res.publicUrl)}` : ``}
|
|
138
|
+
Cloud Storage Uri = ${res.cloudStorageUri}
|
|
139
|
+
Size (KB) = ${Math.round(Number(res.size) / 1000)}
|
|
140
|
+
Bucket Name = ${res.bucketName}
|
|
141
|
+
Privacy = ${res.privacy}
|
|
142
|
+
Render ID = ${res.renderId}
|
|
143
|
+
Codec = ${codec} (${codecReason})
|
|
144
|
+
`.trim()));
|
|
145
|
+
if (downloadName) {
|
|
146
|
+
log_1.Log.info('');
|
|
147
|
+
log_1.Log.info('downloading file...');
|
|
148
|
+
const destination = await (0, download_file_1.downloadFile)({
|
|
149
|
+
bucketName: res.bucketName,
|
|
150
|
+
gsutilURI: res.cloudStorageUri,
|
|
151
|
+
downloadName,
|
|
152
|
+
});
|
|
153
|
+
log_1.Log.info(cli_1.CliInternals.chalk.blueBright(`Downloaded file to ${destination}!`));
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
exports.renderMediaSubcommand = renderMediaSubcommand;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderStillSubcommand = exports.RENDER_STILL_SUBCOMMAND = void 0;
|
|
4
|
+
const cli_1 = require("@remotion/cli");
|
|
5
|
+
const config_1 = require("@remotion/cli/config");
|
|
6
|
+
const renderer_1 = require("@remotion/renderer");
|
|
7
|
+
const download_file_1 = require("../../../api/download-file");
|
|
8
|
+
const render_still_on_cloudrun_1 = require("../../../api/render-still-on-cloudrun");
|
|
9
|
+
const validate_serveurl_1 = require("../../../shared/validate-serveurl");
|
|
10
|
+
const log_1 = require("../../log");
|
|
11
|
+
const renderArgsCheck_1 = require("./helpers/renderArgsCheck");
|
|
12
|
+
exports.RENDER_STILL_SUBCOMMAND = 'still';
|
|
13
|
+
const renderStillSubcommand = async (args, remotionRoot) => {
|
|
14
|
+
var _a, _b;
|
|
15
|
+
const { serveUrl, cloudRunUrl, outName, forceBucketName, privacy, downloadName, region, } = await (0, renderArgsCheck_1.renderArgsCheck)(exports.RENDER_STILL_SUBCOMMAND, args);
|
|
16
|
+
const { chromiumOptions, envVariables, inputProps, logLevel, puppeteerTimeout, jpegQuality, stillFrame, scale, height, width, browserExecutable, port, } = await cli_1.CliInternals.getCliOptions({
|
|
17
|
+
type: 'still',
|
|
18
|
+
isLambda: true,
|
|
19
|
+
remotionRoot,
|
|
20
|
+
});
|
|
21
|
+
let composition = args[1];
|
|
22
|
+
if (!composition) {
|
|
23
|
+
log_1.Log.info('No compositions passed. Fetching compositions...');
|
|
24
|
+
(0, validate_serveurl_1.validateServeUrl)(serveUrl);
|
|
25
|
+
const server = renderer_1.RenderInternals.prepareServer({
|
|
26
|
+
concurrency: 1,
|
|
27
|
+
indent: false,
|
|
28
|
+
port,
|
|
29
|
+
remotionRoot,
|
|
30
|
+
verbose: renderer_1.RenderInternals.isEqualOrBelowLogLevel(logLevel, 'verbose'),
|
|
31
|
+
webpackConfigOrServeUrl: serveUrl,
|
|
32
|
+
});
|
|
33
|
+
const { compositionId } = await cli_1.CliInternals.getCompositionWithDimensionOverride({
|
|
34
|
+
args,
|
|
35
|
+
compositionIdFromUi: null,
|
|
36
|
+
indent: false,
|
|
37
|
+
serveUrlOrWebpackUrl: serveUrl,
|
|
38
|
+
verbose: renderer_1.RenderInternals.isEqualOrBelowLogLevel(logLevel, 'verbose'),
|
|
39
|
+
browserExecutable,
|
|
40
|
+
chromiumOptions,
|
|
41
|
+
envVariables,
|
|
42
|
+
inputProps,
|
|
43
|
+
port,
|
|
44
|
+
puppeteerInstance: undefined,
|
|
45
|
+
timeoutInMilliseconds: puppeteerTimeout,
|
|
46
|
+
height,
|
|
47
|
+
width,
|
|
48
|
+
server: await server,
|
|
49
|
+
});
|
|
50
|
+
composition = compositionId;
|
|
51
|
+
}
|
|
52
|
+
const { format: imageFormat, source: imageFormatReason } = cli_1.CliInternals.determineFinalStillImageFormat({
|
|
53
|
+
downloadName,
|
|
54
|
+
outName: outName !== null && outName !== void 0 ? outName : null,
|
|
55
|
+
cliFlag: (_a = cli_1.CliInternals.parsedCli['image-format']) !== null && _a !== void 0 ? _a : null,
|
|
56
|
+
isLambda: true,
|
|
57
|
+
fromUi: null,
|
|
58
|
+
configImageFormat: (_b = config_1.ConfigInternals.getUserPreferredStillImageFormat()) !== null && _b !== void 0 ? _b : null,
|
|
59
|
+
});
|
|
60
|
+
log_1.Log.verbose(`Image format: (${imageFormat}), ${imageFormatReason}`);
|
|
61
|
+
// Todo: Check cloudRunUrl is valid, as the error message is obtuse
|
|
62
|
+
cli_1.CliInternals.Log.info(cli_1.CliInternals.chalk.gray(`
|
|
63
|
+
Cloud Run Service URL = ${cloudRunUrl}
|
|
64
|
+
Region = ${region}
|
|
65
|
+
Type = still
|
|
66
|
+
Composition = ${composition}
|
|
67
|
+
Output Bucket = ${forceBucketName}
|
|
68
|
+
Output File = ${outName !== null && outName !== void 0 ? outName : 'out.png'}
|
|
69
|
+
Output File Privacy = ${privacy}
|
|
70
|
+
${downloadName ? ` Downloaded File = ${downloadName}` : ''}
|
|
71
|
+
`.trim()));
|
|
72
|
+
log_1.Log.info();
|
|
73
|
+
const renderStart = Date.now();
|
|
74
|
+
const progressBar = cli_1.CliInternals.createOverwriteableCliOutput({
|
|
75
|
+
quiet: cli_1.CliInternals.quietFlagProvided(),
|
|
76
|
+
cancelSignal: null,
|
|
77
|
+
updatesDontOverwrite: false,
|
|
78
|
+
indent: false,
|
|
79
|
+
});
|
|
80
|
+
let doneIn = null;
|
|
81
|
+
const updateProgress = (newline) => {
|
|
82
|
+
progressBar.update([
|
|
83
|
+
`Rendering on Cloud Run:`,
|
|
84
|
+
`${doneIn === null ? '...' : `Rendered in ${doneIn}ms`}`,
|
|
85
|
+
].join(' '), newline);
|
|
86
|
+
};
|
|
87
|
+
const res = await (0, render_still_on_cloudrun_1.renderStillOnCloudrun)({
|
|
88
|
+
cloudRunUrl,
|
|
89
|
+
serveUrl,
|
|
90
|
+
region,
|
|
91
|
+
inputProps,
|
|
92
|
+
imageFormat,
|
|
93
|
+
composition,
|
|
94
|
+
privacy,
|
|
95
|
+
envVariables,
|
|
96
|
+
frame: stillFrame,
|
|
97
|
+
jpegQuality,
|
|
98
|
+
chromiumOptions,
|
|
99
|
+
scale,
|
|
100
|
+
forceHeight: height,
|
|
101
|
+
forceWidth: width,
|
|
102
|
+
forceBucketName,
|
|
103
|
+
outName,
|
|
104
|
+
logLevel: config_1.ConfigInternals.Logging.getLogLevel(),
|
|
105
|
+
});
|
|
106
|
+
doneIn = Date.now() - renderStart;
|
|
107
|
+
updateProgress(true);
|
|
108
|
+
log_1.Log.info(cli_1.CliInternals.chalk.gray(`Cloud Storage Uri = ${res.cloudStorageUri}`));
|
|
109
|
+
log_1.Log.info(cli_1.CliInternals.chalk.gray(`Render ID = ${res.renderId}`));
|
|
110
|
+
log_1.Log.info(cli_1.CliInternals.chalk.gray(`${Math.round(Number(res.size) / 1000)} KB, Privacy: ${res.privacy}, Bucket: ${res.bucketName}`));
|
|
111
|
+
log_1.Log.info(cli_1.CliInternals.chalk.blue(`○ ${res.publicUrl}`));
|
|
112
|
+
if (downloadName) {
|
|
113
|
+
log_1.Log.info('');
|
|
114
|
+
log_1.Log.info('downloading file...');
|
|
115
|
+
const destination = await (0, download_file_1.downloadFile)({
|
|
116
|
+
bucketName: res.bucketName,
|
|
117
|
+
gsutilURI: res.cloudStorageUri,
|
|
118
|
+
downloadName,
|
|
119
|
+
});
|
|
120
|
+
log_1.Log.info(cli_1.CliInternals.chalk.blueBright(`Downloaded file to ${destination}!`));
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
exports.renderStillSubcommand = renderStillSubcommand;
|