@remotion/studio
Version:
APIs for interacting with the Remotion Studio
202 lines (201 loc) • 10.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeReadOnlyStudioRenderCommand = exports.normalizeServeUrlForRenderCommand = exports.getNpmRemotionCommandPrefix = void 0;
const client_1 = require("@remotion/renderer/client");
const shellQuote = (value) => {
return `'${value.replace(/'/g, "'\\''")}'`;
};
const addFlagWithValue = (flags, flag, value) => {
if (value === null || value === undefined) {
return;
}
flags.push(`--${flag}=${shellQuote(String(value))}`);
};
const addBooleanFlag = (flags, flag, value) => {
if (value) {
flags.push(`--${flag}`);
}
};
const valueFlag = (flag, value, defaultValue) => {
return { flag, value, defaultValue };
};
const booleanFlag = (flag, value, defaultValue) => {
return { flag, value, defaultValue };
};
const addValueFlagsIfChanged = (flags, mappings) => {
for (const mapping of mappings) {
if (mapping.value !== mapping.defaultValue) {
addFlagWithValue(flags, mapping.flag, mapping.value);
}
}
};
const addTrueBooleanFlagsIfChanged = (flags, mappings) => {
for (const mapping of mappings) {
if (mapping.value && mapping.value !== mapping.defaultValue) {
addBooleanFlag(flags, mapping.flag, true);
}
}
};
const getNpmRemotionCommandPrefix = (version) => {
return version.trim() === ''
? 'bunx --yes --location=global -p @remotion/cli remotion'
: `bunx --yes --location=global -p @remotion/cli@${version} remotion`;
};
exports.getNpmRemotionCommandPrefix = getNpmRemotionCommandPrefix;
const normalizeServeUrlForRenderCommand = ({ locationHref, compositionId, }) => {
const parsed = new URL(locationHref);
parsed.hash = '';
parsed.search = '';
const suffix = `/${compositionId}`;
if (parsed.pathname === suffix) {
parsed.pathname = '/';
}
else if (parsed.pathname.endsWith(suffix)) {
const basePath = parsed.pathname.slice(0, -suffix.length);
parsed.pathname = basePath === '' ? '/' : basePath;
}
if (parsed.pathname !== '/' && parsed.pathname.endsWith('/')) {
parsed.pathname = parsed.pathname.slice(0, -1);
}
return `${parsed.origin}${parsed.pathname === '/' ? '' : parsed.pathname}`;
};
exports.normalizeServeUrlForRenderCommand = normalizeServeUrlForRenderCommand;
const trimDefaultOutPrefix = (outName) => {
if (outName.startsWith('out/')) {
const trimmed = outName.slice('out/'.length);
return trimmed.length === 0 ? outName : trimmed;
}
if (outName.startsWith('./out/')) {
const trimmed = outName.slice('./out/'.length);
return trimmed.length === 0 ? outName : trimmed;
}
return outName;
};
const getRenderMediaFlag = (option) => {
return client_1.BrowserSafeApis.optionsMap.renderMedia[option].cliFlag;
};
const renderMediaValueFlag = (option, value, defaultValue) => {
return valueFlag(getRenderMediaFlag(option), value, defaultValue);
};
const renderMediaBooleanFlag = (option, value, defaultValue) => {
return booleanFlag(getRenderMediaFlag(option), value, defaultValue);
};
const makeReadOnlyStudioRenderCommand = ({ remotionVersion, locationHref, compositionId, outName, renderMode, renderDefaults, durationInFrames, concurrency, frame, startFrame, endFrame, stillImageFormat, sequenceImageFormat, videoImageFormat, jpegQuality, codec, muted, enforceAudioTrack, proResProfile, x264Preset, pixelFormat, crf, videoBitrate, audioBitrate, audioCodec, everyNthFrame, numberOfGifLoops, disallowParallelEncoding, encodingBufferSize, encodingMaxRate, forSeamlessAacConcatenation, separateAudioTo, colorSpace, scale, logLevel, delayRenderTimeout, hardwareAcceleration, chromeMode, headless, disableWebSecurity, ignoreCertificateErrors, gl, userAgent, multiProcessOnLinux, darkMode, offthreadVideoCacheSizeInBytes, offthreadVideoThreads, mediaCacheSizeInBytes, beepOnFinish, repro, metadata, envVariables, inputProps, }) => {
var _a;
const serveUrl = (0, exports.normalizeServeUrlForRenderCommand)({
locationHref,
compositionId,
});
const isStillRender = renderMode === 'still';
const isSequenceRender = renderMode === 'sequence';
const hasCodecSpecificOptions = !isSequenceRender;
const commandType = isStillRender ? 'still' : 'render';
const command = (0, exports.getNpmRemotionCommandPrefix)(remotionVersion);
const { options } = client_1.BrowserSafeApis;
const flags = [];
addValueFlagsIfChanged(flags, [
valueFlag(options.scaleOption.cliFlag, scale, renderDefaults.scale),
renderMediaValueFlag('logLevel', logLevel, renderDefaults.logLevel),
renderMediaValueFlag('timeoutInMilliseconds', delayRenderTimeout, renderDefaults.delayRenderTimeout),
renderMediaValueFlag('chromeMode', chromeMode, renderDefaults.chromeMode),
valueFlag(options.glOption.cliFlag, gl, renderDefaults.openGlRenderer),
valueFlag(options.userAgentOption.cliFlag, userAgent, renderDefaults.userAgent),
renderMediaValueFlag('offthreadVideoCacheSizeInBytes', offthreadVideoCacheSizeInBytes, renderDefaults.offthreadVideoCacheSizeInBytes),
renderMediaValueFlag('offthreadVideoThreads', offthreadVideoThreads, renderDefaults.offthreadVideoThreads),
renderMediaValueFlag('mediaCacheSizeInBytes', mediaCacheSizeInBytes, renderDefaults.mediaCacheSizeInBytes),
]);
if (headless !== renderDefaults.headless) {
addFlagWithValue(flags, options.headlessOption.cliFlag, !headless);
}
addTrueBooleanFlagsIfChanged(flags, [
booleanFlag(options.disableWebSecurityOption.cliFlag, disableWebSecurity, renderDefaults.disableWebSecurity),
booleanFlag(options.ignoreCertificateErrorsOption.cliFlag, ignoreCertificateErrors, renderDefaults.ignoreCertificateErrors),
booleanFlag(options.enableMultiprocessOnLinuxOption.cliFlag, multiProcessOnLinux, renderDefaults.multiProcessOnLinux),
booleanFlag(options.darkModeOption.cliFlag, darkMode, renderDefaults.darkMode),
booleanFlag(options.beepOnFinishOption.cliFlag, beepOnFinish, renderDefaults.beepOnFinish),
]);
if (isStillRender) {
addValueFlagsIfChanged(flags, [
valueFlag(options.stillFrameOption.cliFlag, frame, 0),
valueFlag(options.stillImageFormatOption.cliFlag, stillImageFormat, renderDefaults.stillImageFormat),
valueFlag(options.jpegQualityOption.cliFlag, jpegQuality, renderDefaults.jpegQuality),
]);
}
else {
addValueFlagsIfChanged(flags, [
valueFlag(options.concurrencyOption.cliFlag, concurrency, renderDefaults.concurrency),
]);
if (isSequenceRender) {
addBooleanFlag(flags, options.imageSequenceOption.cliFlag, true);
if (sequenceImageFormat !== 'jpeg') {
addFlagWithValue(flags, options.videoImageFormatOption.cliFlag, sequenceImageFormat);
}
}
else {
addValueFlagsIfChanged(flags, [
valueFlag(options.videoImageFormatOption.cliFlag, videoImageFormat, renderDefaults.videoImageFormat),
renderMediaValueFlag('hardwareAcceleration', hardwareAcceleration, renderDefaults.hardwareAcceleration),
]);
}
if (hasCodecSpecificOptions && codec !== renderDefaults.codec) {
addFlagWithValue(flags, getRenderMediaFlag('codec'), codec);
}
if (startFrame !== 0 || endFrame !== durationInFrames - 1) {
addFlagWithValue(flags, options.framesOption.cliFlag, `${startFrame}-${endFrame}`);
}
if (hasCodecSpecificOptions) {
addTrueBooleanFlagsIfChanged(flags, [
renderMediaBooleanFlag('muted', muted, renderDefaults.muted),
booleanFlag(options.enforceAudioOption.cliFlag, enforceAudioTrack, renderDefaults.enforceAudioTrack),
renderMediaBooleanFlag('forSeamlessAacConcatenation', forSeamlessAacConcatenation, renderDefaults.forSeamlessAacConcatenation),
]);
addValueFlagsIfChanged(flags, [
valueFlag(options.pixelFormatOption.cliFlag, pixelFormat, renderDefaults.pixelFormat),
renderMediaValueFlag('colorSpace', colorSpace, renderDefaults.colorSpace),
valueFlag(options.proResProfileOption.cliFlag, proResProfile, renderDefaults.proResProfile),
renderMediaValueFlag('x264Preset', x264Preset, renderDefaults.x264Preset),
valueFlag(options.crfOption.cliFlag, crf, null),
valueFlag(options.jpegQualityOption.cliFlag, jpegQuality, renderDefaults.jpegQuality),
renderMediaValueFlag('videoBitrate', videoBitrate, renderDefaults.videoBitrate),
renderMediaValueFlag('audioBitrate', audioBitrate, renderDefaults.audioBitrate),
valueFlag(options.everyNthFrameOption.cliFlag, everyNthFrame, renderDefaults.everyNthFrame),
renderMediaValueFlag('numberOfGifLoops', numberOfGifLoops, renderDefaults.numberOfGifLoops),
renderMediaValueFlag('encodingBufferSize', encodingBufferSize, renderDefaults.encodingBufferSize),
renderMediaValueFlag('encodingMaxRate', encodingMaxRate, renderDefaults.encodingMaxRate),
renderMediaValueFlag('separateAudioTo', separateAudioTo, null),
]);
const defaultAudioCodec = (_a = client_1.BrowserSafeApis.defaultAudioCodecs[codec]) === null || _a === void 0 ? void 0 : _a.compressed;
if (audioCodec !== defaultAudioCodec) {
addFlagWithValue(flags, getRenderMediaFlag('audioCodec'), audioCodec);
}
}
addTrueBooleanFlagsIfChanged(flags, [
renderMediaBooleanFlag('disallowParallelEncoding', disallowParallelEncoding, false),
renderMediaBooleanFlag('repro', repro, renderDefaults.repro),
]);
}
if (metadata) {
for (const [key, value] of Object.entries(metadata)) {
addFlagWithValue(flags, options.metadataOption.cliFlag, `${key}=${value}`);
}
}
if (Object.keys(inputProps).length > 0) {
addFlagWithValue(flags, options.propsOption.cliFlag, JSON.stringify(inputProps));
}
const envArgs = Object.entries(envVariables)
.sort(([a], [b]) => a.localeCompare(b))
.map(([key, value]) => shellQuote(`${key}=${value}`));
const renderCommand = [
command,
commandType,
shellQuote(serveUrl),
shellQuote(compositionId),
shellQuote(trimDefaultOutPrefix(outName)),
...flags,
].join(' ');
if (envArgs.length === 0) {
return renderCommand;
}
return ['env', ...envArgs, renderCommand].join(' ');
};
exports.makeReadOnlyStudioRenderCommand = makeReadOnlyStudioRenderCommand;