@remotion/studio 4.0.422 → 4.0.423
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/dist/api/save-render-output.d.ts +7 -0
- package/dist/api/save-render-output.js +45 -0
- package/dist/components/RenderModal/ClientRenderProgress.js +3 -0
- package/dist/components/RenderModal/RenderStatusModal.js +4 -0
- package/dist/components/RenderModal/ServerRenderModal.js +1 -1
- package/dist/components/RenderModal/WebRenderModal.js +7 -2
- package/dist/components/RenderModal/WebRenderModalBasic.js +1 -1
- package/dist/components/RenderQueue/ClientRenderQueueProcessor.d.ts +1 -0
- package/dist/components/RenderQueue/ClientRenderQueueProcessor.js +34 -4
- package/dist/components/RenderQueue/RenderQueueDownloadItem.d.ts +5 -0
- package/dist/components/RenderQueue/RenderQueueDownloadItem.js +35 -0
- package/dist/components/RenderQueue/RenderQueueItem.js +48 -16
- package/dist/components/RenderQueue/RenderQueueItemStatus.js +3 -0
- package/dist/components/RenderQueue/RenderQueueOpenInFolder.d.ts +2 -2
- package/dist/components/RenderQueue/RenderQueueOutputName.js +1 -8
- package/dist/components/RenderQueue/RenderQueueRemoveItem.js +4 -2
- package/dist/components/RenderQueue/RenderQueueSavingMessage.d.ts +2 -0
- package/dist/components/RenderQueue/RenderQueueSavingMessage.js +13 -0
- package/dist/components/RenderQueue/client-side-render-types.d.ts +11 -8
- package/dist/components/RenderQueue/client-side-render-types.js +5 -0
- package/dist/components/RenderQueue/context.d.ts +6 -3
- package/dist/components/RenderQueue/context.js +37 -6
- package/dist/components/RenderQueue/index.js +1 -14
- package/dist/esm/{chunk-4153e552.js → chunk-112w480k.js} +4686 -3752
- package/dist/esm/internals.mjs +4686 -3752
- package/dist/esm/previewEntry.mjs +4695 -3761
- package/dist/esm/renderEntry.mjs +1 -1
- package/dist/helpers/client-id.js +4 -1
- package/dist/helpers/retry-payload.d.ts +2 -2
- package/package.json +10 -10
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CompletedClientRender } from '@remotion/studio-shared';
|
|
2
|
+
export declare const saveOutputFile: ({ blob, filePath, }: {
|
|
3
|
+
blob: Blob;
|
|
4
|
+
filePath: string;
|
|
5
|
+
}) => Promise<void>;
|
|
6
|
+
export declare const registerClientRender: (render: CompletedClientRender) => Promise<void>;
|
|
7
|
+
export declare const unregisterClientRender: (id: string) => Promise<void>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.unregisterClientRender = exports.registerClientRender = exports.saveOutputFile = void 0;
|
|
4
|
+
const throwIfNotOk = async (response) => {
|
|
5
|
+
if (!response.ok) {
|
|
6
|
+
try {
|
|
7
|
+
const jsonResponse = await response.json();
|
|
8
|
+
throw new Error(jsonResponse.error);
|
|
9
|
+
}
|
|
10
|
+
catch (parseError) {
|
|
11
|
+
if (parseError instanceof Error && parseError.message) {
|
|
12
|
+
throw parseError;
|
|
13
|
+
}
|
|
14
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const saveOutputFile = async ({ blob, filePath, }) => {
|
|
19
|
+
const url = new URL('/api/upload-output', window.location.origin);
|
|
20
|
+
url.search = new URLSearchParams({ filePath }).toString();
|
|
21
|
+
const response = await fetch(url, {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
body: blob,
|
|
24
|
+
});
|
|
25
|
+
await throwIfNotOk(response);
|
|
26
|
+
};
|
|
27
|
+
exports.saveOutputFile = saveOutputFile;
|
|
28
|
+
const registerClientRender = async (render) => {
|
|
29
|
+
const response = await fetch('/api/register-client-render', {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
headers: { 'Content-Type': 'application/json' },
|
|
32
|
+
body: JSON.stringify(render),
|
|
33
|
+
});
|
|
34
|
+
await throwIfNotOk(response);
|
|
35
|
+
};
|
|
36
|
+
exports.registerClientRender = registerClientRender;
|
|
37
|
+
const unregisterClientRender = async (id) => {
|
|
38
|
+
const response = await fetch('/api/unregister-client-render', {
|
|
39
|
+
method: 'POST',
|
|
40
|
+
headers: { 'Content-Type': 'application/json' },
|
|
41
|
+
body: JSON.stringify({ id }),
|
|
42
|
+
});
|
|
43
|
+
await throwIfNotOk(response);
|
|
44
|
+
};
|
|
45
|
+
exports.unregisterClientRender = unregisterClientRender;
|
|
@@ -50,6 +50,9 @@ const ClientRenderProgress = ({ job }) => {
|
|
|
50
50
|
if (job.status === 'done') {
|
|
51
51
|
return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)(layout_1.Spacing, { y: 0.5 }), (0, jsx_runtime_1.jsx)(DoneStatus, { job: job }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { y: 1 })] }));
|
|
52
52
|
}
|
|
53
|
+
if (job.status === 'saving') {
|
|
54
|
+
return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)(layout_1.Spacing, { y: 0.5 }), (0, jsx_runtime_1.jsx)("div", { style: label, children: "Saving to out/..." }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { y: 1 })] }));
|
|
55
|
+
}
|
|
53
56
|
const { renderedFrames, encodedFrames, totalFrames } = job.progress;
|
|
54
57
|
return ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)(layout_1.Spacing, { y: 0.5 }), (0, jsx_runtime_1.jsx)(RenderingProgress, { renderedFrames: renderedFrames, totalFrames: totalFrames }), job.type === 'client-video' && ((0, jsx_runtime_1.jsx)(EncodingProgress, { encodedFrames: encodedFrames, totalFrames: totalFrames })), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { y: 1 })] }));
|
|
55
58
|
};
|
|
@@ -11,6 +11,7 @@ const ModalContainer_1 = require("../ModalContainer");
|
|
|
11
11
|
const ModalHeader_1 = require("../ModalHeader");
|
|
12
12
|
const NotificationCenter_1 = require("../Notifications/NotificationCenter");
|
|
13
13
|
const actions_1 = require("../RenderQueue/actions");
|
|
14
|
+
const client_side_render_types_1 = require("../RenderQueue/client-side-render-types");
|
|
14
15
|
const context_1 = require("../RenderQueue/context");
|
|
15
16
|
const layout_1 = require("../layout");
|
|
16
17
|
const ClientRenderProgress_1 = require("./ClientRenderProgress");
|
|
@@ -51,6 +52,9 @@ const RenderStatusModal = ({ jobId, }) => {
|
|
|
51
52
|
}, [setSelectedModal]);
|
|
52
53
|
const onRetry = (0, react_1.useCallback)(() => {
|
|
53
54
|
if (isClientJob) {
|
|
55
|
+
if ((0, client_side_render_types_1.isRestoredClientJob)(job)) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
54
58
|
const retryPayload = (0, retry_payload_1.makeClientRetryPayload)(job);
|
|
55
59
|
setSelectedModal(retryPayload);
|
|
56
60
|
}
|
|
@@ -103,7 +103,7 @@ const RenderModal = ({ initialFrame, initialVideoImageFormat, initialStillImageF
|
|
|
103
103
|
: initialStillImageFormat,
|
|
104
104
|
type: 'asset',
|
|
105
105
|
compositionDefaultOutName: resolvedComposition.defaultOutName,
|
|
106
|
-
|
|
106
|
+
outputLocation: renderDefaults.outputLocation,
|
|
107
107
|
});
|
|
108
108
|
});
|
|
109
109
|
const [videoCodecForAudioTab, setVideoCodecForAudioTab] = (0, react_1.useState)(() => initialVideoCodecForAudioTab);
|
|
@@ -148,10 +148,11 @@ const WebRenderModal = ({ initialFrame, defaultProps, inFrameMark, outFrameMark,
|
|
|
148
148
|
return Math.max(0, Math.min(finalEndFrame, startFrame));
|
|
149
149
|
}, [finalEndFrame, startFrame]);
|
|
150
150
|
const [initialOutNameState] = (0, react_1.useState)(() => {
|
|
151
|
+
var _a, _b;
|
|
151
152
|
if (initialDefaultOutName) {
|
|
152
153
|
return initialDefaultOutName;
|
|
153
154
|
}
|
|
154
|
-
|
|
155
|
+
const defaultOut = (0, studio_shared_1.getDefaultOutLocation)({
|
|
155
156
|
compositionName: resolvedComposition.id,
|
|
156
157
|
defaultExtension: renderMode === 'still'
|
|
157
158
|
? imageFormat
|
|
@@ -160,8 +161,12 @@ const WebRenderModal = ({ initialFrame, defaultProps, inFrameMark, outFrameMark,
|
|
|
160
161
|
: imageFormat,
|
|
161
162
|
type: 'asset',
|
|
162
163
|
compositionDefaultOutName: resolvedComposition.defaultOutName,
|
|
163
|
-
|
|
164
|
+
outputLocation: (_b = (_a = window.remotion_renderDefaults) === null || _a === void 0 ? void 0 : _a.outputLocation) !== null && _b !== void 0 ? _b : null,
|
|
164
165
|
});
|
|
166
|
+
if (window.remotion_isReadOnlyStudio) {
|
|
167
|
+
return defaultOut.replace(/^out\//, '');
|
|
168
|
+
}
|
|
169
|
+
return defaultOut;
|
|
165
170
|
});
|
|
166
171
|
const [outName, setOutName] = (0, react_1.useState)(() => initialOutNameState);
|
|
167
172
|
const setStillFormat = (0, react_1.useCallback)((format) => {
|
|
@@ -101,6 +101,6 @@ const WebRenderModalBasic = ({ renderMode, resolvedComposition, imageFormat, set
|
|
|
101
101
|
value: c,
|
|
102
102
|
}));
|
|
103
103
|
}, [encodableVideoCodecs, effectiveVideoCodec, setCodec, codecLabels]);
|
|
104
|
-
return ((0, jsx_runtime_1.jsxs)("div", { style: tabContainer, children: [renderMode === 'still' ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { style: layout_2.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_2.label, children: "Format" }), (0, jsx_runtime_1.jsx)("div", { style: layout_2.rightRow, children: (0, jsx_runtime_1.jsx)(SegmentedControl_1.SegmentedControl, { items: imageFormatOptions, needsWrapping: true }) })] }), resolvedComposition.durationInFrames > 1 ? ((0, jsx_runtime_1.jsxs)("div", { style: layout_2.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_2.label, children: "Frame" }), (0, jsx_runtime_1.jsx)("div", { style: layout_2.rightRow, children: (0, jsx_runtime_1.jsx)(RemInput_1.RightAlignInput, { children: (0, jsx_runtime_1.jsx)(InputDragger_1.InputDragger, { value: frame, onTextChange: onFrameChanged, placeholder: `0-${resolvedComposition.durationInFrames - 1}`, onValueChange: onFrameSetDirectly, name: "frame", step: 1, min: 0, status: "ok", max: resolvedComposition.durationInFrames - 1, rightAlign: true }) }) })] })) : null] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { style: layout_2.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_2.label, children: "Container" }), (0, jsx_runtime_1.jsx)("div", { style: layout_2.rightRow, children: (0, jsx_runtime_1.jsx)(ComboBox_1.Combobox, { values: containerOptions, selectedId: container, title: "Container" }) })] }), (0, jsx_runtime_1.jsxs)("div", { style: layout_2.optionRow, children: [(0, jsx_runtime_1.jsxs)("div", { style: layout_2.label, children: ["Codec", (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 0.5 }), (0, jsx_runtime_1.jsx)(OptionExplainerBubble_1.OptionExplainerBubble, { id: "videoCodecOption" })] }), (0, jsx_runtime_1.jsx)("div", { style: layout_2.rightRow, children: (0, jsx_runtime_1.jsx)(ComboBox_1.Combobox, { values: codecOptions, selectedId: effectiveVideoCodec, title: "Codec" }) })] }), (0, jsx_runtime_1.jsx)(FrameRangeSetting_1.FrameRangeSetting, { durationInFrames: resolvedComposition.durationInFrames, startFrame: startFrame !== null && startFrame !== void 0 ? startFrame : 0, endFrame: endFrame !== null && endFrame !== void 0 ? endFrame : resolvedComposition.durationInFrames - 1, setStartFrame: setStartFrame, setEndFrame: setEndFrame })] })), (0, jsx_runtime_1.jsx)(RenderModalOutputName_1.RenderModalOutputName, { existence: false, inputStyle: layout_2.input, outName: outName, onValueChange: onOutNameChange, validationMessage: validationMessage, label:
|
|
104
|
+
return ((0, jsx_runtime_1.jsxs)("div", { style: tabContainer, children: [renderMode === 'still' ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { style: layout_2.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_2.label, children: "Format" }), (0, jsx_runtime_1.jsx)("div", { style: layout_2.rightRow, children: (0, jsx_runtime_1.jsx)(SegmentedControl_1.SegmentedControl, { items: imageFormatOptions, needsWrapping: true }) })] }), resolvedComposition.durationInFrames > 1 ? ((0, jsx_runtime_1.jsxs)("div", { style: layout_2.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_2.label, children: "Frame" }), (0, jsx_runtime_1.jsx)("div", { style: layout_2.rightRow, children: (0, jsx_runtime_1.jsx)(RemInput_1.RightAlignInput, { children: (0, jsx_runtime_1.jsx)(InputDragger_1.InputDragger, { value: frame, onTextChange: onFrameChanged, placeholder: `0-${resolvedComposition.durationInFrames - 1}`, onValueChange: onFrameSetDirectly, name: "frame", step: 1, min: 0, status: "ok", max: resolvedComposition.durationInFrames - 1, rightAlign: true }) }) })] })) : null] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { style: layout_2.optionRow, children: [(0, jsx_runtime_1.jsx)("div", { style: layout_2.label, children: "Container" }), (0, jsx_runtime_1.jsx)("div", { style: layout_2.rightRow, children: (0, jsx_runtime_1.jsx)(ComboBox_1.Combobox, { values: containerOptions, selectedId: container, title: "Container" }) })] }), (0, jsx_runtime_1.jsxs)("div", { style: layout_2.optionRow, children: [(0, jsx_runtime_1.jsxs)("div", { style: layout_2.label, children: ["Codec", (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 0.5 }), (0, jsx_runtime_1.jsx)(OptionExplainerBubble_1.OptionExplainerBubble, { id: "videoCodecOption" })] }), (0, jsx_runtime_1.jsx)("div", { style: layout_2.rightRow, children: (0, jsx_runtime_1.jsx)(ComboBox_1.Combobox, { values: codecOptions, selectedId: effectiveVideoCodec, title: "Codec" }) })] }), (0, jsx_runtime_1.jsx)(FrameRangeSetting_1.FrameRangeSetting, { durationInFrames: resolvedComposition.durationInFrames, startFrame: startFrame !== null && startFrame !== void 0 ? startFrame : 0, endFrame: endFrame !== null && endFrame !== void 0 ? endFrame : resolvedComposition.durationInFrames - 1, setStartFrame: setStartFrame, setEndFrame: setEndFrame })] })), (0, jsx_runtime_1.jsx)(RenderModalOutputName_1.RenderModalOutputName, { existence: false, inputStyle: layout_2.input, outName: outName, onValueChange: onOutNameChange, validationMessage: validationMessage, label: window.remotion_isReadOnlyStudio ? 'Download name' : 'Output name' }), (0, jsx_runtime_1.jsxs)("div", { style: layout_2.optionRow, children: [(0, jsx_runtime_1.jsxs)("div", { style: layout_2.label, children: ["Log Level ", (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 0.5 }), (0, jsx_runtime_1.jsx)(OptionExplainerBubble_1.OptionExplainerBubble, { id: "logLevelOption" })] }), (0, jsx_runtime_1.jsx)("div", { style: layout_2.rightRow, children: (0, jsx_runtime_1.jsx)(ComboBox_1.Combobox, { values: logLevelOptions, selectedId: logLevel, title: "Log Level" }) })] })] }));
|
|
105
105
|
};
|
|
106
106
|
exports.WebRenderModalBasic = WebRenderModalBasic;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ClientRenderQueueProcessor = void 0;
|
|
3
|
+
exports.ClientRenderQueueProcessor = exports.downloadBlob = void 0;
|
|
4
4
|
const web_renderer_1 = require("@remotion/web-renderer");
|
|
5
5
|
const react_1 = require("react");
|
|
6
|
+
const save_render_output_1 = require("../../api/save-render-output");
|
|
6
7
|
const context_1 = require("./context");
|
|
7
8
|
const downloadBlob = (blob, filename) => {
|
|
8
9
|
const url = URL.createObjectURL(blob);
|
|
@@ -15,8 +16,9 @@ const downloadBlob = (blob, filename) => {
|
|
|
15
16
|
a.click();
|
|
16
17
|
URL.revokeObjectURL(url);
|
|
17
18
|
};
|
|
19
|
+
exports.downloadBlob = downloadBlob;
|
|
18
20
|
const ClientRenderQueueProcessor = () => {
|
|
19
|
-
const { getAbortController, getCompositionForJob, updateClientJobProgress, markClientJobDone, markClientJobFailed, markClientJobCancelled, setProcessJobCallback, } = (0, react_1.useContext)(context_1.RenderQueueContext);
|
|
21
|
+
const { getAbortController, getCompositionForJob, updateClientJobProgress, markClientJobSaving, markClientJobDone, markClientJobFailed, markClientJobCancelled, setProcessJobCallback, } = (0, react_1.useContext)(context_1.RenderQueueContext);
|
|
20
22
|
const processStillJob = (0, react_1.useCallback)(async (job, signal) => {
|
|
21
23
|
var _a, _b;
|
|
22
24
|
const compositionRef = getCompositionForJob(job.id);
|
|
@@ -114,13 +116,40 @@ const ClientRenderQueueProcessor = () => {
|
|
|
114
116
|
throw new Error(`Unknown job type`);
|
|
115
117
|
}
|
|
116
118
|
const blob = await result.getBlob();
|
|
117
|
-
downloadBlob(blob, job.outName);
|
|
118
119
|
const metadata = {
|
|
119
120
|
width: result.width,
|
|
120
121
|
height: result.height,
|
|
121
122
|
sizeInBytes: blob.size,
|
|
122
123
|
};
|
|
123
|
-
|
|
124
|
+
markClientJobSaving(job.id);
|
|
125
|
+
const getBlob = () => Promise.resolve(blob);
|
|
126
|
+
const downloadAndFinish = () => {
|
|
127
|
+
(0, exports.downloadBlob)(blob, job.outName);
|
|
128
|
+
markClientJobDone(job.id, metadata, getBlob);
|
|
129
|
+
};
|
|
130
|
+
if (window.remotion_isReadOnlyStudio) {
|
|
131
|
+
downloadAndFinish();
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
try {
|
|
135
|
+
await (0, save_render_output_1.saveOutputFile)({ blob, filePath: job.outName });
|
|
136
|
+
await (0, save_render_output_1.registerClientRender)({
|
|
137
|
+
id: job.id,
|
|
138
|
+
type: job.type,
|
|
139
|
+
compositionId: job.compositionId,
|
|
140
|
+
outName: job.outName,
|
|
141
|
+
startedAt: job.startedAt,
|
|
142
|
+
deletedOutputLocation: false,
|
|
143
|
+
metadata,
|
|
144
|
+
});
|
|
145
|
+
markClientJobDone(job.id, metadata);
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
// eslint-disable-next-line no-console
|
|
149
|
+
console.error('Failed to save render output, falling back to browser download.', err);
|
|
150
|
+
downloadAndFinish();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
124
153
|
}
|
|
125
154
|
catch (err) {
|
|
126
155
|
if (abortController.signal.aborted) {
|
|
@@ -135,6 +164,7 @@ const ClientRenderQueueProcessor = () => {
|
|
|
135
164
|
processStillJob,
|
|
136
165
|
processVideoJob,
|
|
137
166
|
updateClientJobProgress,
|
|
167
|
+
markClientJobSaving,
|
|
138
168
|
markClientJobDone,
|
|
139
169
|
markClientJobFailed,
|
|
140
170
|
markClientJobCancelled,
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RenderQueueDownloadItem = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const InlineAction_1 = require("../InlineAction");
|
|
7
|
+
const NotificationCenter_1 = require("../Notifications/NotificationCenter");
|
|
8
|
+
const ClientRenderQueueProcessor_1 = require("./ClientRenderQueueProcessor");
|
|
9
|
+
const RenderQueueDownloadItem = ({ job }) => {
|
|
10
|
+
const onClick = (0, react_1.useCallback)((e) => {
|
|
11
|
+
e.stopPropagation();
|
|
12
|
+
if (job.status !== 'done' || !job.getBlob) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
job
|
|
16
|
+
.getBlob()
|
|
17
|
+
.then((blob) => {
|
|
18
|
+
(0, ClientRenderQueueProcessor_1.downloadBlob)(blob, job.outName);
|
|
19
|
+
})
|
|
20
|
+
.catch((err) => {
|
|
21
|
+
(0, NotificationCenter_1.showNotification)(`Could not download file: ${err.message}`, 2000);
|
|
22
|
+
});
|
|
23
|
+
}, [job]);
|
|
24
|
+
const icon = (0, react_1.useMemo)(() => {
|
|
25
|
+
return {
|
|
26
|
+
height: 12,
|
|
27
|
+
color: 'currentColor',
|
|
28
|
+
};
|
|
29
|
+
}, []);
|
|
30
|
+
const renderAction = (0, react_1.useCallback)((color) => {
|
|
31
|
+
return ((0, jsx_runtime_1.jsx)("svg", { style: icon, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 512 512", children: (0, jsx_runtime_1.jsx)("path", { fill: color, d: "M288 32c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 242.7-73.4-73.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l128 128c12.5 12.5 32.8 12.5 45.3 0l128-128c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L288 274.7 288 32zM64 352c-35.3 0-64 28.7-64 64l0 32c0 35.3 28.7 64 64 64l384 0c35.3 0 64-28.7 64-64l0-32c0-35.3-28.7-64-64-64l-101.5 0-45.3 45.3c-25 25-65.5 25-90.5 0L165.5 352 64 352zm368 56a24 24 0 1 1 0 48 24 24 0 1 1 0-48z" }) }));
|
|
32
|
+
}, [icon]);
|
|
33
|
+
return ((0, jsx_runtime_1.jsx)(InlineAction_1.InlineAction, { renderAction: renderAction, onClick: onClick, title: "Download" }));
|
|
34
|
+
};
|
|
35
|
+
exports.RenderQueueDownloadItem = RenderQueueDownloadItem;
|
|
@@ -7,9 +7,11 @@ const remotion_1 = require("remotion");
|
|
|
7
7
|
const colors_1 = require("../../helpers/colors");
|
|
8
8
|
const url_state_1 = require("../../helpers/url-state");
|
|
9
9
|
const layout_1 = require("../layout");
|
|
10
|
+
const client_side_render_types_1 = require("./client-side-render-types");
|
|
10
11
|
const context_1 = require("./context");
|
|
11
12
|
const RenderQueueCancelledMessage_1 = require("./RenderQueueCancelledMessage");
|
|
12
13
|
const RenderQueueCopyToClipboard_1 = require("./RenderQueueCopyToClipboard");
|
|
14
|
+
const RenderQueueDownloadItem_1 = require("./RenderQueueDownloadItem");
|
|
13
15
|
const RenderQueueError_1 = require("./RenderQueueError");
|
|
14
16
|
const RenderQueueItemCancelButton_1 = require("./RenderQueueItemCancelButton");
|
|
15
17
|
const RenderQueueItemStatus_1 = require("./RenderQueueItemStatus");
|
|
@@ -18,6 +20,7 @@ const RenderQueueOutputName_1 = require("./RenderQueueOutputName");
|
|
|
18
20
|
const RenderQueueProgressMessage_1 = require("./RenderQueueProgressMessage");
|
|
19
21
|
const RenderQueueRemoveItem_1 = require("./RenderQueueRemoveItem");
|
|
20
22
|
const RenderQueueRepeat_1 = require("./RenderQueueRepeat");
|
|
23
|
+
const RenderQueueSavingMessage_1 = require("./RenderQueueSavingMessage");
|
|
21
24
|
const container = {
|
|
22
25
|
padding: 12,
|
|
23
26
|
display: 'flex',
|
|
@@ -69,24 +72,41 @@ const RenderQueueItem = ({ job, selected }) => {
|
|
|
69
72
|
(_a = document
|
|
70
73
|
.querySelector(`.${SELECTED_CLASSNAME}`)) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: 'smooth' });
|
|
71
74
|
}, []);
|
|
75
|
+
const clientBlobInfo = (0, react_1.useMemo)(() => {
|
|
76
|
+
if (!isClientJob || job.status !== 'done' || !job.getBlob) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
getBlob: job.getBlob,
|
|
81
|
+
width: job.metadata.width,
|
|
82
|
+
height: job.metadata.height,
|
|
83
|
+
sizeInBytes: job.metadata.sizeInBytes,
|
|
84
|
+
};
|
|
85
|
+
}, [isClientJob, job]);
|
|
72
86
|
const onClick = (0, react_1.useCallback)(() => {
|
|
73
87
|
if (job.status !== 'done') {
|
|
74
88
|
return;
|
|
75
89
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
setCanvasContent({
|
|
79
|
-
type: 'output-blob',
|
|
80
|
-
displayName: job.outName,
|
|
81
|
-
getBlob: clientJob.getBlob,
|
|
82
|
-
width: clientJob.metadata.width,
|
|
83
|
-
height: clientJob.metadata.height,
|
|
84
|
-
sizeInBytes: clientJob.metadata.sizeInBytes,
|
|
85
|
-
});
|
|
90
|
+
// Cannot show folders
|
|
91
|
+
if (!isClientJob && job.type === 'sequence') {
|
|
86
92
|
return;
|
|
87
93
|
}
|
|
88
|
-
|
|
89
|
-
|
|
94
|
+
if (clientBlobInfo) {
|
|
95
|
+
setCanvasContent((c) => {
|
|
96
|
+
const isAlreadySelected = c && c.type === 'output-blob' && c.displayName === job.outName;
|
|
97
|
+
if (isAlreadySelected && !selected) {
|
|
98
|
+
scrollCurrentIntoView();
|
|
99
|
+
return c;
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
type: 'output-blob',
|
|
103
|
+
displayName: job.outName,
|
|
104
|
+
getBlob: clientBlobInfo.getBlob,
|
|
105
|
+
width: clientBlobInfo.width,
|
|
106
|
+
height: clientBlobInfo.height,
|
|
107
|
+
sizeInBytes: clientBlobInfo.sizeInBytes,
|
|
108
|
+
};
|
|
109
|
+
});
|
|
90
110
|
return;
|
|
91
111
|
}
|
|
92
112
|
setCanvasContent((c) => {
|
|
@@ -98,14 +118,26 @@ const RenderQueueItem = ({ job, selected }) => {
|
|
|
98
118
|
return { type: 'output', path: `/${job.outName}` };
|
|
99
119
|
});
|
|
100
120
|
(0, url_state_1.pushUrl)(`/outputs/${job.outName}`);
|
|
101
|
-
}, [
|
|
121
|
+
}, [
|
|
122
|
+
job,
|
|
123
|
+
isClientJob,
|
|
124
|
+
clientBlobInfo,
|
|
125
|
+
scrollCurrentIntoView,
|
|
126
|
+
selected,
|
|
127
|
+
setCanvasContent,
|
|
128
|
+
]);
|
|
102
129
|
(0, react_1.useEffect)(() => {
|
|
103
130
|
if (selected) {
|
|
104
131
|
scrollCurrentIntoView();
|
|
105
132
|
}
|
|
106
133
|
}, [scrollCurrentIntoView, selected]);
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
134
|
+
const canCopyToClipboard = job.status === 'done' &&
|
|
135
|
+
!isClientJob &&
|
|
136
|
+
(0, RenderQueueCopyToClipboard_1.supportsCopyingToClipboard)(job);
|
|
137
|
+
const canRepeat = (job.status === 'done' ||
|
|
138
|
+
job.status === 'failed' ||
|
|
139
|
+
job.status === 'cancelled') &&
|
|
140
|
+
!((0, context_1.isClientRenderJob)(job) && (0, client_side_render_types_1.isRestoredClientJob)(job));
|
|
141
|
+
return ((0, jsx_runtime_1.jsxs)(layout_1.Row, { onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, style: containerStyle, align: "center", onClick: onClick, className: selected ? SELECTED_CLASSNAME : undefined, children: [(0, jsx_runtime_1.jsx)(RenderQueueItemStatus_1.RenderQueueItemStatus, { job: job }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1 }), (0, jsx_runtime_1.jsxs)("div", { style: right, children: [(0, jsx_runtime_1.jsx)("div", { style: title, children: job.compositionId }), (0, jsx_runtime_1.jsx)("div", { style: subtitle, children: job.status === 'done' ? ((0, jsx_runtime_1.jsx)(RenderQueueOutputName_1.RenderQueueOutputName, { job: job })) : job.status === 'failed' ? ((0, jsx_runtime_1.jsx)(RenderQueueError_1.RenderQueueError, { job: job })) : job.status === 'running' ? ((0, jsx_runtime_1.jsx)(RenderQueueProgressMessage_1.RenderQueueProgressMessage, { job: job })) : job.status === 'saving' ? ((0, jsx_runtime_1.jsx)(RenderQueueSavingMessage_1.RenderQueueSavingMessage, {})) : job.status === 'cancelled' ? ((0, jsx_runtime_1.jsx)(RenderQueueCancelledMessage_1.RenderQueueCancelledMessage, {})) : null })] }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1 }), canCopyToClipboard ? ((0, jsx_runtime_1.jsx)(RenderQueueCopyToClipboard_1.RenderQueueCopyToClipboard, { job: job })) : null, canRepeat ? (0, jsx_runtime_1.jsx)(RenderQueueRepeat_1.RenderQueueRepeatItem, { job: job }) : null, job.status === 'running' ? ((0, jsx_runtime_1.jsx)(RenderQueueItemCancelButton_1.RenderQueueCancelButton, { job: job })) : ((0, jsx_runtime_1.jsx)(RenderQueueRemoveItem_1.RenderQueueRemoveItem, { job: job })), job.status === 'done' ? (clientBlobInfo ? ((0, jsx_runtime_1.jsx)(RenderQueueDownloadItem_1.RenderQueueDownloadItem, { job: job })) : ((0, jsx_runtime_1.jsx)(RenderQueueOpenInFolder_1.RenderQueueOpenInFinderItem, { job: job }))) : null] }));
|
|
110
142
|
};
|
|
111
143
|
exports.RenderQueueItem = RenderQueueItem;
|
|
@@ -88,6 +88,9 @@ const RenderQueueItemStatus = ({ job }) => {
|
|
|
88
88
|
}
|
|
89
89
|
return ((0, jsx_runtime_1.jsx)("button", { type: "button", style: invisibleStyle, onClick: onClick, children: (0, jsx_runtime_1.jsx)(CircularProgress_1.CircularProgress, { progress: Math.max(0.07, progressValue) }) }));
|
|
90
90
|
}
|
|
91
|
+
if (job.status === 'saving') {
|
|
92
|
+
return ((0, jsx_runtime_1.jsx)("button", { type: "button", style: invisibleStyle, onClick: onClick, children: (0, jsx_runtime_1.jsx)(CircularProgress_1.CircularProgress, { progress: 0.95 }) }));
|
|
93
|
+
}
|
|
91
94
|
if (job.status === 'cancelled') {
|
|
92
95
|
return ((0, jsx_runtime_1.jsx)("svg", { style: iconStyle, viewBox: "0 0 512 512", children: (0, jsx_runtime_1.jsx)("path", { fill: colors_1.FAIL_COLOR, d: "M0 160V352L160 512H352L512 352V160L352 0H160L0 160zm353.9 32l-17 17-47 47 47 47 17 17L320 353.9l-17-17-47-47-47 47-17 17L158.1 320l17-17 47-47-47-47-17-17L192 158.1l17 17 47 47 47-47 17-17L353.9 192z" }) }));
|
|
93
96
|
}
|
|
@@ -3,13 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.RenderQueueOutputName = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const react_1 = require("react");
|
|
6
|
-
const context_1 = require("./context");
|
|
7
6
|
const item_style_1 = require("./item-style");
|
|
8
7
|
const RenderQueueOutputName = ({ job }) => {
|
|
9
|
-
const
|
|
10
|
-
const deletedOutputLocation = isClientJob
|
|
11
|
-
? false
|
|
12
|
-
: job.deletedOutputLocation;
|
|
8
|
+
const deletedOutputLocation = 'deletedOutputLocation' in job && job.deletedOutputLocation;
|
|
13
9
|
const style = (0, react_1.useMemo)(() => {
|
|
14
10
|
return {
|
|
15
11
|
...item_style_1.renderQueueItemSubtitleStyle,
|
|
@@ -19,9 +15,6 @@ const RenderQueueOutputName = ({ job }) => {
|
|
|
19
15
|
};
|
|
20
16
|
}, [deletedOutputLocation]);
|
|
21
17
|
const getTitle = () => {
|
|
22
|
-
if (isClientJob) {
|
|
23
|
-
return `Downloaded as ${job.outName}`;
|
|
24
|
-
}
|
|
25
18
|
if (deletedOutputLocation) {
|
|
26
19
|
return 'File was deleted';
|
|
27
20
|
}
|
|
@@ -4,6 +4,7 @@ exports.RenderQueueRemoveItem = void 0;
|
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const react_1 = require("react");
|
|
6
6
|
const remotion_1 = require("remotion");
|
|
7
|
+
const save_render_output_1 = require("../../api/save-render-output");
|
|
7
8
|
const InlineAction_1 = require("../InlineAction");
|
|
8
9
|
const NotificationCenter_1 = require("../Notifications/NotificationCenter");
|
|
9
10
|
const actions_1 = require("./actions");
|
|
@@ -17,12 +18,13 @@ const RenderQueueRemoveItem = ({ job }) => {
|
|
|
17
18
|
e.stopPropagation();
|
|
18
19
|
if (isClientJob) {
|
|
19
20
|
if (canvasContent &&
|
|
20
|
-
canvasContent.type === 'output
|
|
21
|
+
canvasContent.type === 'output' &&
|
|
21
22
|
job.status === 'done' &&
|
|
22
|
-
canvasContent.
|
|
23
|
+
canvasContent.path === `/${job.outName}`) {
|
|
23
24
|
setCanvasContent(null);
|
|
24
25
|
}
|
|
25
26
|
removeClientJob(job.id);
|
|
27
|
+
(0, save_render_output_1.unregisterClientRender)(job.id).catch(() => { });
|
|
26
28
|
(0, NotificationCenter_1.showNotification)('Removed job', 2000);
|
|
27
29
|
return;
|
|
28
30
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RenderQueueSavingMessage = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const item_style_1 = require("./item-style");
|
|
6
|
+
const savingStyle = {
|
|
7
|
+
...item_style_1.renderQueueItemSubtitleStyle,
|
|
8
|
+
cursor: 'default',
|
|
9
|
+
};
|
|
10
|
+
const RenderQueueSavingMessage = () => {
|
|
11
|
+
return (0, jsx_runtime_1.jsx)("span", { style: savingStyle, children: "Saving to out/..." });
|
|
12
|
+
};
|
|
13
|
+
exports.RenderQueueSavingMessage = RenderQueueSavingMessage;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CompletedClientRender } from '@remotion/studio-shared';
|
|
1
2
|
import type { RenderStillOnWebImageFormat, WebRendererAudioCodec, WebRendererContainer, WebRendererQuality, WebRendererVideoCodec } from '@remotion/web-renderer';
|
|
2
3
|
import type { LogLevel } from 'remotion';
|
|
3
4
|
export type ClientRenderJobProgress = {
|
|
@@ -6,20 +7,17 @@ export type ClientRenderJobProgress = {
|
|
|
6
7
|
totalFrames: number;
|
|
7
8
|
};
|
|
8
9
|
export type GetBlobCallback = () => Promise<Blob>;
|
|
9
|
-
export type ClientRenderMetadata = {
|
|
10
|
-
width: number;
|
|
11
|
-
height: number;
|
|
12
|
-
sizeInBytes: number;
|
|
13
|
-
};
|
|
14
10
|
type ClientRenderJobDynamicStatus = {
|
|
15
11
|
status: 'idle';
|
|
16
12
|
} | {
|
|
17
13
|
status: 'running';
|
|
18
14
|
progress: ClientRenderJobProgress;
|
|
15
|
+
} | {
|
|
16
|
+
status: 'saving';
|
|
19
17
|
} | {
|
|
20
18
|
status: 'done';
|
|
21
|
-
getBlob
|
|
22
|
-
metadata:
|
|
19
|
+
getBlob?: GetBlobCallback;
|
|
20
|
+
metadata: CompletedClientRender['metadata'];
|
|
23
21
|
} | {
|
|
24
22
|
status: 'cancelled';
|
|
25
23
|
} | {
|
|
@@ -60,5 +58,10 @@ export type ClientVideoRenderJob = ClientRenderJobBase & {
|
|
|
60
58
|
transparent: boolean;
|
|
61
59
|
muted: boolean;
|
|
62
60
|
} & ClientRenderJobDynamicStatus;
|
|
63
|
-
export type
|
|
61
|
+
export type RestoredClientRenderJob = CompletedClientRender & {
|
|
62
|
+
status: 'done';
|
|
63
|
+
getBlob?: GetBlobCallback;
|
|
64
|
+
};
|
|
65
|
+
export type ClientRenderJob = ClientStillRenderJob | ClientVideoRenderJob | RestoredClientRenderJob;
|
|
66
|
+
export declare const isRestoredClientJob: (job: ClientRenderJob) => job is RestoredClientRenderJob;
|
|
64
67
|
export {};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import type { RenderJob } from '@remotion/studio-shared';
|
|
1
|
+
import type { CompletedClientRender, RenderJob } from '@remotion/studio-shared';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { type AddClientStillJobParams, type AddClientVideoJobParams, type CompositionRef } from './client-render-queue';
|
|
4
|
-
import type { ClientRenderJob, ClientRenderJobProgress,
|
|
4
|
+
import type { ClientRenderJob, ClientRenderJobProgress, GetBlobCallback } from './client-side-render-types';
|
|
5
5
|
declare global {
|
|
6
6
|
interface Window {
|
|
7
7
|
remotion_initialRenderQueue: RenderJob[] | null;
|
|
8
|
+
remotion_initialClientRenders: CompletedClientRender[] | null;
|
|
8
9
|
}
|
|
9
10
|
}
|
|
10
11
|
export type AnyRenderJob = RenderJob | ClientRenderJob;
|
|
@@ -16,7 +17,8 @@ type RenderQueueContextType = {
|
|
|
16
17
|
addClientStillJob: (params: AddClientStillJobParams, compositionRef: CompositionRef) => string;
|
|
17
18
|
addClientVideoJob: (params: AddClientVideoJobParams, compositionRef: CompositionRef) => string;
|
|
18
19
|
updateClientJobProgress: (jobId: string, progress: ClientRenderJobProgress) => void;
|
|
19
|
-
|
|
20
|
+
markClientJobSaving: (jobId: string) => void;
|
|
21
|
+
markClientJobDone: (jobId: string, metadata: CompletedClientRender['metadata'], getBlob?: GetBlobCallback) => void;
|
|
20
22
|
markClientJobFailed: (jobId: string, error: Error) => void;
|
|
21
23
|
markClientJobCancelled: (jobId: string) => void;
|
|
22
24
|
removeClientJob: (jobId: string) => void;
|
|
@@ -28,6 +30,7 @@ type RenderQueueContextType = {
|
|
|
28
30
|
export declare const RenderQueueContext: React.Context<RenderQueueContextType>;
|
|
29
31
|
export declare const renderJobsRef: React.RefObject<{
|
|
30
32
|
updateRenderJobs: (jobs: RenderJob[]) => void;
|
|
33
|
+
updateClientRenders: (renders: CompletedClientRender[]) => void;
|
|
31
34
|
} | null>;
|
|
32
35
|
export declare const RenderQueueContextProvider: React.FC<{
|
|
33
36
|
readonly children: React.ReactNode;
|
|
@@ -37,6 +37,11 @@ exports.RenderQueueContextProvider = exports.renderJobsRef = exports.RenderQueue
|
|
|
37
37
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
38
38
|
const react_1 = __importStar(require("react"));
|
|
39
39
|
const client_render_queue_1 = require("./client-render-queue");
|
|
40
|
+
const restorePersistedClientRenders = () => {
|
|
41
|
+
var _a;
|
|
42
|
+
const persisted = (_a = window.remotion_initialClientRenders) !== null && _a !== void 0 ? _a : [];
|
|
43
|
+
return persisted.map((r) => ({ ...r, status: 'done' }));
|
|
44
|
+
};
|
|
40
45
|
const isClientRenderJob = (job) => {
|
|
41
46
|
return job.type === 'client-still' || job.type === 'client-video';
|
|
42
47
|
};
|
|
@@ -50,6 +55,7 @@ exports.RenderQueueContext = react_1.default.createContext({
|
|
|
50
55
|
addClientStillJob: noopString,
|
|
51
56
|
addClientVideoJob: noopString,
|
|
52
57
|
updateClientJobProgress: noop,
|
|
58
|
+
markClientJobSaving: noop,
|
|
53
59
|
markClientJobDone: noop,
|
|
54
60
|
markClientJobFailed: noop,
|
|
55
61
|
markClientJobCancelled: noop,
|
|
@@ -63,7 +69,7 @@ exports.renderJobsRef = (0, react_1.createRef)();
|
|
|
63
69
|
const RenderQueueContextProvider = ({ children }) => {
|
|
64
70
|
var _a;
|
|
65
71
|
const [serverJobs, setServerJobs] = (0, react_1.useState)((_a = window.remotion_initialRenderQueue) !== null && _a !== void 0 ? _a : []);
|
|
66
|
-
const [clientJobs, setClientJobs] = (0, react_1.useState)(
|
|
72
|
+
const [clientJobs, setClientJobs] = (0, react_1.useState)(restorePersistedClientRenders);
|
|
67
73
|
const [currentlyProcessing, setCurrentlyProcessing] = (0, react_1.useState)(null);
|
|
68
74
|
const processJobCallbackRef = (0, react_1.useRef)(null);
|
|
69
75
|
// Process next job when state changes
|
|
@@ -114,12 +120,15 @@ const RenderQueueContextProvider = ({ children }) => {
|
|
|
114
120
|
? { ...job, status: 'running', progress }
|
|
115
121
|
: job));
|
|
116
122
|
}, []);
|
|
117
|
-
const
|
|
118
|
-
(0, client_render_queue_1.deleteAbortController)(jobId);
|
|
119
|
-
(0, client_render_queue_1.cleanupCompositionForJob)(jobId);
|
|
123
|
+
const markClientJobSaving = (0, react_1.useCallback)((jobId) => {
|
|
120
124
|
setClientJobs((prev) => prev.map((job) => job.id === jobId
|
|
121
|
-
? { ...job, status: '
|
|
125
|
+
? { ...job, status: 'saving' }
|
|
122
126
|
: job));
|
|
127
|
+
}, []);
|
|
128
|
+
const markClientJobDone = (0, react_1.useCallback)((jobId, metadata, getBlob) => {
|
|
129
|
+
(0, client_render_queue_1.deleteAbortController)(jobId);
|
|
130
|
+
(0, client_render_queue_1.cleanupCompositionForJob)(jobId);
|
|
131
|
+
setClientJobs((prev) => prev.map((job) => job.id === jobId ? { ...job, status: 'done', metadata, getBlob } : job));
|
|
123
132
|
setCurrentlyProcessing(null);
|
|
124
133
|
}, []);
|
|
125
134
|
const markClientJobFailed = (0, react_1.useCallback)((jobId, error) => {
|
|
@@ -166,15 +175,36 @@ const RenderQueueContextProvider = ({ children }) => {
|
|
|
166
175
|
updateRenderJobs: (newJobs) => {
|
|
167
176
|
setServerJobs(newJobs);
|
|
168
177
|
},
|
|
178
|
+
updateClientRenders: (renders) => {
|
|
179
|
+
setClientJobs((prev) => {
|
|
180
|
+
const existingIds = new Set(prev.map((j) => j.id));
|
|
181
|
+
const updatedPrev = prev.map((job) => {
|
|
182
|
+
const updated = renders.find((r) => r.id === job.id);
|
|
183
|
+
if (updated && job.status === 'done') {
|
|
184
|
+
return {
|
|
185
|
+
...job,
|
|
186
|
+
deletedOutputLocation: updated.deletedOutputLocation,
|
|
187
|
+
metadata: updated.metadata,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
return job;
|
|
191
|
+
});
|
|
192
|
+
const newJobs = renders
|
|
193
|
+
.filter((r) => !existingIds.has(r.id))
|
|
194
|
+
.map((r) => ({ ...r, status: 'done' }));
|
|
195
|
+
return [...updatedPrev, ...newJobs];
|
|
196
|
+
});
|
|
197
|
+
},
|
|
169
198
|
}), []);
|
|
170
199
|
const value = (0, react_1.useMemo)(() => {
|
|
171
200
|
return {
|
|
172
|
-
jobs: [...serverJobs, ...clientJobs],
|
|
201
|
+
jobs: [...serverJobs, ...clientJobs].sort((a, b) => a.startedAt - b.startedAt),
|
|
173
202
|
serverJobs,
|
|
174
203
|
clientJobs,
|
|
175
204
|
addClientStillJob,
|
|
176
205
|
addClientVideoJob,
|
|
177
206
|
updateClientJobProgress,
|
|
207
|
+
markClientJobSaving,
|
|
178
208
|
markClientJobDone,
|
|
179
209
|
markClientJobFailed,
|
|
180
210
|
markClientJobCancelled,
|
|
@@ -190,6 +220,7 @@ const RenderQueueContextProvider = ({ children }) => {
|
|
|
190
220
|
addClientStillJob,
|
|
191
221
|
addClientVideoJob,
|
|
192
222
|
updateClientJobProgress,
|
|
223
|
+
markClientJobSaving,
|
|
193
224
|
markClientJobDone,
|
|
194
225
|
markClientJobFailed,
|
|
195
226
|
markClientJobCancelled,
|