@remotion/studio 4.0.527 → 4.0.528

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/dist/components/AgentPrompt.js +1 -2
  2. package/dist/components/AudioWaveform.d.ts +1 -0
  3. package/dist/components/AudioWaveform.js +10 -14
  4. package/dist/components/CodeFrame.js +1 -1
  5. package/dist/components/ColorPicker/checker.d.ts +1 -1
  6. package/dist/components/CurrentAsset.js +3 -2
  7. package/dist/components/EditorRuler/Ruler.js +6 -3
  8. package/dist/components/EffectPickerModal.js +69 -43
  9. package/dist/components/ElementInstallConfirmation.js +3 -3
  10. package/dist/components/ElementLibrariesSettings.d.ts +2 -0
  11. package/dist/components/ElementLibrariesSettings.js +200 -0
  12. package/dist/components/InitialCompositionLoader.js +3 -1
  13. package/dist/components/InspectorOpenInEditor.js +13 -0
  14. package/dist/components/InspectorPanel/AlignmentControls.js +28 -9
  15. package/dist/components/InspectorPanel/CollapsibleInspectorSectionHeader.js +1 -1
  16. package/dist/components/InspectorPanel/EasingInspector.js +6 -2
  17. package/dist/components/InspectorPanel/ElementLibraryButton.js +1 -1
  18. package/dist/components/InspectorPanel/KeyframeEasingNavigator.js +1 -1
  19. package/dist/components/InspectorPanel/KeyframeInspector.js +28 -24
  20. package/dist/components/InspectorPanel/MultiSequenceNumberField.js +1 -1
  21. package/dist/components/InspectorPanel/SequenceInspectorHeader.d.ts +3 -1
  22. package/dist/components/InspectorPanel/SequenceSelectionInspector.js +30 -2
  23. package/dist/components/InspectorPanel/SequenceWrapAction.d.ts +8 -0
  24. package/dist/components/InspectorPanel/SequenceWrapAction.js +151 -0
  25. package/dist/components/InspectorPanel/easing-inspector-selection.d.ts +2 -1
  26. package/dist/components/InspectorPanel/easing-inspector-selection.js +4 -3
  27. package/dist/components/InspectorPanel/keyframe-inspector-frame.d.ts +2 -1
  28. package/dist/components/InspectorPanel/keyframe-inspector-frame.js +2 -2
  29. package/dist/components/InspectorSequenceSection.d.ts +1 -0
  30. package/dist/components/InspectorSequenceSection.js +7 -5
  31. package/dist/components/KeyboardShortcutsSettings.js +1 -1
  32. package/dist/components/Menu/styles.d.ts +2 -2
  33. package/dist/components/Modals.js +7 -6
  34. package/dist/components/ModelManager.js +10 -9
  35. package/dist/components/NewComposition/CancelButton.js +10 -4
  36. package/dist/components/NewComposition/InputDragger.d.ts +3 -1
  37. package/dist/components/NewComposition/InputDragger.js +28 -9
  38. package/dist/components/NewComposition/NewComposition.js +7 -6
  39. package/dist/components/NewComposition/RemInput.d.ts +1 -1
  40. package/dist/components/NewComposition/menu-typeahead.js +1 -1
  41. package/dist/components/Preview.js +3 -2
  42. package/dist/components/RenderModal/SchemaEditor/create-zod-values.js +1 -2
  43. package/dist/components/RenderModal/WebRenderModalPicture.js +1 -2
  44. package/dist/components/RenderQueue/CaptionQueueItem.js +14 -5
  45. package/dist/components/RenderQueue/CaptionQueueProcessor.js +30 -7
  46. package/dist/components/RenderQueue/QueueJobError.d.ts +8 -0
  47. package/dist/components/RenderQueue/QueueJobError.js +24 -0
  48. package/dist/components/RenderQueue/QueueJobErrorModal.d.ts +8 -0
  49. package/dist/components/RenderQueue/QueueJobErrorModal.js +63 -0
  50. package/dist/components/RenderQueue/RenderQueueItemCancelButton.d.ts +3 -1
  51. package/dist/components/RenderQueue/RenderQueueItemCancelButton.js +11 -4
  52. package/dist/components/RenderQueue/RenderQueueRepeat.d.ts +3 -1
  53. package/dist/components/RenderQueue/RenderQueueRepeat.js +20 -3
  54. package/dist/components/RenderQueue/VideoMattingQueueItem.js +24 -27
  55. package/dist/components/RenderQueue/VideoMattingQueueProcessor.js +68 -28
  56. package/dist/components/RenderQueue/caption-job-types.d.ts +3 -1
  57. package/dist/components/RenderQueue/context.d.ts +4 -0
  58. package/dist/components/RenderQueue/context.js +58 -8
  59. package/dist/components/RenderQueue/index.js +2 -3
  60. package/dist/components/RenderQueue/load-model-for-job.d.ts +2 -1
  61. package/dist/components/RenderQueue/load-model-for-job.js +5 -1
  62. package/dist/components/RenderQueue/video-matting-job-types.d.ts +13 -6
  63. package/dist/components/SelectedOutlineCropControls.js +2 -1
  64. package/dist/components/SelectedOutlineEditingHandles.js +9 -2
  65. package/dist/components/SelectedOutlineElement.js +9 -3
  66. package/dist/components/SelectedOutlineKeyboardControls.d.ts +2 -4
  67. package/dist/components/SelectedOutlineKeyboardControls.js +4 -22
  68. package/dist/components/SelectedOutlineOverlay.js +152 -106
  69. package/dist/components/SelectedOutlinePathPoints.d.ts +8 -0
  70. package/dist/components/SelectedOutlinePathPoints.js +433 -0
  71. package/dist/components/SelectedOutlinePolygon.js +21 -46
  72. package/dist/components/SelectedOutlineRenderer.d.ts +3 -5
  73. package/dist/components/SelectedOutlineRenderer.js +32 -136
  74. package/dist/components/SelectedOutlineTransformOriginHandle.js +3 -2
  75. package/dist/components/SelectedOutlineUvControls.js +12 -7
  76. package/dist/components/SettingsModal.js +30 -3
  77. package/dist/components/SettingsModalFooter.d.ts +1 -0
  78. package/dist/components/SettingsModalFooter.js +7 -3
  79. package/dist/components/ShowOutlinesProvider.js +1 -1
  80. package/dist/components/SkillsSettings.d.ts +0 -1
  81. package/dist/components/SkillsSettings.js +13 -14
  82. package/dist/components/Splitter/SplitterElement.js +1 -2
  83. package/dist/components/TimeValue.js +1 -1
  84. package/dist/components/Timeline/LoopedTimelineIndicators.d.ts +1 -0
  85. package/dist/components/Timeline/LoopedTimelineIndicators.js +7 -6
  86. package/dist/components/Timeline/TimelineArrayField.js +1 -1
  87. package/dist/components/Timeline/TimelineClipboardKeybindings.js +0 -1
  88. package/dist/components/Timeline/TimelineColorField.js +1 -1
  89. package/dist/components/Timeline/TimelineDragHandler.js +1 -1
  90. package/dist/components/Timeline/TimelineEffectPropItem.d.ts +1 -0
  91. package/dist/components/Timeline/TimelineEffectPropItem.js +12 -5
  92. package/dist/components/Timeline/TimelineExpandedRow.d.ts +1 -0
  93. package/dist/components/Timeline/TimelineExpandedRow.js +5 -4
  94. package/dist/components/Timeline/TimelineExpandedSection.d.ts +1 -0
  95. package/dist/components/Timeline/TimelineExpandedSection.js +2 -2
  96. package/dist/components/Timeline/TimelineExpandedTrackKeyframes.d.ts +1 -0
  97. package/dist/components/Timeline/TimelineExpandedTrackKeyframes.js +3 -1
  98. package/dist/components/Timeline/TimelineFontFamilyField.js +12 -12
  99. package/dist/components/Timeline/TimelineKeyframeControls.d.ts +1 -0
  100. package/dist/components/Timeline/TimelineKeyframeControls.js +39 -28
  101. package/dist/components/Timeline/TimelineLayerChildren.js +1 -1
  102. package/dist/components/Timeline/TimelineList.js +1 -1
  103. package/dist/components/Timeline/TimelineNumberField.js +2 -4
  104. package/dist/components/Timeline/TimelinePrimitiveFieldValue.js +1 -1
  105. package/dist/components/Timeline/TimelineSelection.d.ts +9 -9
  106. package/dist/components/Timeline/TimelineSelection.js +16 -9
  107. package/dist/components/Timeline/TimelineSequence.d.ts +3 -1
  108. package/dist/components/Timeline/TimelineSequence.js +39 -21
  109. package/dist/components/Timeline/TimelineSequenceItem.d.ts +1 -0
  110. package/dist/components/Timeline/TimelineSequenceItem.js +18 -8
  111. package/dist/components/Timeline/TimelineSequencePropItem.d.ts +3 -0
  112. package/dist/components/Timeline/TimelineSequencePropItem.js +262 -25
  113. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.d.ts +11 -13
  114. package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.js +98 -77
  115. package/dist/components/Timeline/TimelineTextContentField.js +27 -4
  116. package/dist/components/Timeline/TimelineTimeIndicators.js +10 -5
  117. package/dist/components/Timeline/TimelineTrack.js +1 -1
  118. package/dist/components/Timeline/TimelineTrimTooltip.d.ts +11 -0
  119. package/dist/components/Timeline/TimelineTrimTooltip.js +41 -0
  120. package/dist/components/Timeline/TimelineVideoInfo.d.ts +1 -0
  121. package/dist/components/Timeline/TimelineVideoInfo.js +13 -10
  122. package/dist/components/Timeline/delete-selected-keyframe.js +22 -8
  123. package/dist/components/Timeline/delete-selected-timeline-item.d.ts +1 -5
  124. package/dist/components/Timeline/delete-selected-timeline-item.js +7 -93
  125. package/dist/components/Timeline/get-animation-item-selection-for-frame.d.ts +2 -1
  126. package/dist/components/Timeline/get-animation-item-selection-for-frame.js +7 -5
  127. package/dist/components/Timeline/get-keyframed-sequence-drag-targets.d.ts +23 -0
  128. package/dist/components/Timeline/get-keyframed-sequence-drag-targets.js +57 -0
  129. package/dist/components/Timeline/get-node-keyframes.d.ts +2 -1
  130. package/dist/components/Timeline/get-node-keyframes.js +6 -4
  131. package/dist/components/Timeline/get-playback-rate-keyframe-changes.d.ts +21 -0
  132. package/dist/components/Timeline/get-playback-rate-keyframe-changes.js +142 -0
  133. package/dist/components/Timeline/get-timeline-keyframes.d.ts +15 -2
  134. package/dist/components/Timeline/get-timeline-keyframes.js +44 -6
  135. package/dist/components/Timeline/keyframe-clipboard.js +17 -3
  136. package/dist/components/Timeline/split-selected-timeline-item.js +4 -1
  137. package/dist/components/Timeline/timeline-field-display-utils.js +1 -0
  138. package/dist/components/Timeline/timeline-field-row-layout.js +1 -0
  139. package/dist/components/Timeline/use-delete-timeline-items.js +17 -11
  140. package/dist/components/Timeline/use-expanded-track-keyframe-rows.d.ts +2 -1
  141. package/dist/components/Timeline/use-expanded-track-keyframe-rows.js +3 -1
  142. package/dist/components/Timeline/use-sequence-freeze-frame-menu-item.js +7 -3
  143. package/dist/components/Timeline/use-timeline-keyframe-drag.js +28 -19
  144. package/dist/components/Transcription/Models.js +1 -1
  145. package/dist/components/Transcription/TranscriptionModal.js +3 -1
  146. package/dist/components/Transcription/resample-media-to-16-khz.d.ts +2 -1
  147. package/dist/components/Transcription/resample-media-to-16-khz.js +20 -2
  148. package/dist/components/UpdatesSettings.js +2 -0
  149. package/dist/components/VideoMatting/Models.js +1 -1
  150. package/dist/components/VideoMatting/VideoMattingModal.js +30 -47
  151. package/dist/components/VideoMatting/VideoMattingModalWithOptionalPackage.js +1 -1
  152. package/dist/components/WebMcp.js +22 -40
  153. package/dist/components/composition-drop-preview.js +1 -0
  154. package/dist/components/effect-drag-and-drop.d.ts +13 -5
  155. package/dist/components/effect-drag-and-drop.js +19 -4
  156. package/dist/components/get-open-in-menu-items.d.ts +2 -1
  157. package/dist/components/get-open-in-menu-items.js +17 -1
  158. package/dist/components/selected-outline-drag.d.ts +1 -6
  159. package/dist/components/selected-outline-drag.js +22 -6
  160. package/dist/components/selected-outline-geometry.d.ts +2 -18
  161. package/dist/components/selected-outline-measurement.d.ts +23 -41
  162. package/dist/components/selected-outline-measurement.js +14 -252
  163. package/dist/components/selected-outline-order.d.ts +4 -11
  164. package/dist/components/selected-outline-order.js +2 -254
  165. package/dist/components/selected-outline-snap.d.ts +1 -1
  166. package/dist/components/selected-outline-snap.js +2 -1
  167. package/dist/components/selected-outline-types.d.ts +18 -28
  168. package/dist/components/selected-outline-uv.d.ts +4 -4
  169. package/dist/components/selected-outline-uv.js +6 -111
  170. package/dist/components/sequence-props-api.js +0 -10
  171. package/dist/components/use-selected-outline-control-target.js +12 -21
  172. package/dist/components/wrap-jsx-node-api.d.ts +2 -0
  173. package/dist/components/wrap-jsx-node-api.js +13 -0
  174. package/dist/error-overlay/remotion-overlay/OpenInEditor.js +45 -2
  175. package/dist/error-overlay/remotion-overlay/StackFrame.js +32 -3
  176. package/dist/esm/{CaptionQueueProcessor-npa6szn1.mjs → CaptionQueueProcessor-nr7hjcga.mjs} +63 -17
  177. package/dist/esm/LazyModels-ajkn7fs3.mjs +12 -0
  178. package/dist/esm/LazyModels-g1g7cf4e.mjs +12 -0
  179. package/dist/esm/{TranscriptionModal-79m5wgcj.mjs → TranscriptionModal-e18bzbkb.mjs} +15 -15
  180. package/dist/esm/{VideoMattingModal-31pew0xj.mjs → VideoMattingModal-5bz2s4rs.mjs} +47 -65
  181. package/dist/esm/{VideoMattingQueueProcessor-t1hgm2rm.mjs → VideoMattingQueueProcessor-4tkj0f4k.mjs} +69 -26
  182. package/dist/esm/{index-v4tr1bft.mjs → index-09txs1bj.mjs} +5 -0
  183. package/dist/esm/{index-n5gmcvhz.mjs → index-5ycb9e9q.mjs} +2 -4
  184. package/dist/esm/{index-5t2dwxsk.mjs → index-890dd9b3.mjs} +259 -21
  185. package/dist/esm/{index-ac5550e7.mjs → index-8nt6a0mw.mjs} +3 -3
  186. package/dist/esm/{index-614tdz2q.mjs → index-9q9w8v9p.mjs} +3 -3
  187. package/dist/esm/{index-s7qa3xbw.mjs → index-c2wabcdt.mjs} +6 -6
  188. package/dist/esm/{index-r1gr3j3a.mjs → index-dfy1t576.mjs} +50 -1
  189. package/dist/esm/{index-21hxsfaa.mjs → index-dh3zk2hv.mjs} +6 -25
  190. package/dist/esm/{index-4zen9prq.mjs → index-dpyss74p.mjs} +6563 -5485
  191. package/dist/esm/{index-9x6e1dq0.mjs → index-hqxc6tzp.mjs} +40 -6
  192. package/dist/esm/{index-9xxg6218.mjs → index-qve7mdfp.mjs} +19 -1
  193. package/dist/esm/{index-e855w59j.mjs → index-s6qya2gg.mjs} +3 -5
  194. package/dist/esm/index-t7tbt980.mjs +103 -0
  195. package/dist/esm/{index-r0ejh5sy.mjs → index-t7xnxdf8.mjs} +44 -26
  196. package/dist/esm/index-wqc43mw0.mjs +158 -0
  197. package/dist/esm/{index-ppspzgn9.mjs → index-x6r9bn12.mjs} +4026 -4761
  198. package/dist/esm/{index-vxwg66ar.mjs → index-xac20sv4.mjs} +44 -57
  199. package/dist/esm/index.mjs +4 -5
  200. package/dist/esm/internals.mjs +13 -13
  201. package/dist/esm/previewEntry.mjs +18 -15
  202. package/dist/esm/renderEntry.mjs +5 -1
  203. package/dist/helpers/calculate-timeline.d.ts +5 -1
  204. package/dist/helpers/calculate-timeline.js +1 -1
  205. package/dist/helpers/checkerboard-background.d.ts +2 -2
  206. package/dist/helpers/colors.d.ts +132 -112
  207. package/dist/helpers/colors.js +117 -95
  208. package/dist/helpers/create-folder-tree.js +2 -1
  209. package/dist/helpers/editor-guide-selection.d.ts +1 -1
  210. package/dist/helpers/editor-ruler.js +23 -12
  211. package/dist/helpers/get-connected-compositions.d.ts +6 -1
  212. package/dist/helpers/get-connected-compositions.js +1 -1
  213. package/dist/helpers/get-sequence-double-click-action.js +1 -1
  214. package/dist/helpers/get-sequence-visible-range.d.ts +1 -1
  215. package/dist/helpers/get-sequence-visible-range.js +2 -5
  216. package/dist/helpers/get-timeline-nestedness.d.ts +1 -1
  217. package/dist/helpers/get-timeline-nestedness.js +1 -1
  218. package/dist/helpers/get-timeline-sequence-sort-key.d.ts +1 -1
  219. package/dist/helpers/get-timeline-sequence-sort-key.js +1 -1
  220. package/dist/helpers/hoverable.js +4 -4
  221. package/dist/helpers/inject-css.js +5 -7
  222. package/dist/helpers/prism-vsc-dark-plus.d.ts +1 -1
  223. package/dist/helpers/prism-vsc-dark-plus.js +52 -51
  224. package/dist/helpers/resolve-studio-color.d.ts +1 -0
  225. package/dist/helpers/resolve-studio-color.js +11 -0
  226. package/dist/helpers/studio-css-variables.d.ts +1 -0
  227. package/dist/helpers/studio-css-variables.js +105 -0
  228. package/dist/helpers/studio-pixel-ratio.d.ts +1 -0
  229. package/dist/helpers/studio-pixel-ratio.js +7 -0
  230. package/dist/helpers/timeline-node-path-key.d.ts +1 -1
  231. package/dist/helpers/timeline-node-path-key.js +2 -2
  232. package/dist/helpers/use-runtime-values.js +2 -28
  233. package/dist/hot-middleware-client/client.js +5 -3
  234. package/dist/icons/align-center-horizontal.js +2 -1
  235. package/dist/icons/align-left.js +2 -1
  236. package/dist/icons/align-right.js +2 -1
  237. package/dist/icons/{separation.d.ts → background-removal.d.ts} +1 -1
  238. package/dist/icons/background-removal.js +9 -0
  239. package/dist/icons/wrap.d.ts +4 -0
  240. package/dist/icons/wrap.js +10 -0
  241. package/dist/previewEntry.js +2 -0
  242. package/dist/renderEntry.js +2 -0
  243. package/dist/state/modals.d.ts +15 -1
  244. package/dist/state/timeline-sequence-hover.d.ts +6 -16
  245. package/dist/state/timeline-sequence-hover.js +6 -67
  246. package/package.json +20 -19
  247. package/dist/components/Timeline/get-easing-selection-after-keyframe-delete.d.ts +0 -15
  248. package/dist/components/Timeline/get-easing-selection-after-keyframe-delete.js +0 -31
  249. package/dist/esm/LazyModels-nh3c8h9p.mjs +0 -12
  250. package/dist/esm/LazyModels-rr5v8h5y.mjs +0 -12
  251. package/dist/esm/index-cw0pnpg5.mjs +0 -50
  252. package/dist/esm/index-k426ye99.mjs +0 -139
  253. package/dist/helpers/get-box-quads-polyfill-internals.d.ts +0 -82
  254. package/dist/helpers/get-box-quads-polyfill-internals.js +0 -2403
  255. package/dist/helpers/get-box-quads-ponyfill.d.ts +0 -10
  256. package/dist/helpers/get-box-quads-ponyfill.js +0 -23
  257. package/dist/icons/separation.js +0 -7
  258. /package/dist/esm/{resolve-composition-component-location-qrp05g62.mjs → resolve-composition-component-location-2hgf6g0a.mjs} +0 -0
@@ -11,16 +11,19 @@ const resample_media_to_16_khz_1 = require("../Transcription/resample-media-to-1
11
11
  const context_1 = require("./context");
12
12
  const load_model_for_job_1 = require("./load-model-for-job");
13
13
  const CaptionQueueProcessor = () => {
14
- const { updateCaptionJobProgress, markCaptionJobDone, markCaptionJobFailed, setProcessCaptionJobCallback, } = (0, react_1.useContext)(context_1.RenderQueueContext);
14
+ const { updateCaptionJobProgress, markCaptionJobDone, markCaptionJobFailed, markCaptionJobCancelled, markCaptionJobSaving, getAbortController, setProcessCaptionJobCallback, } = (0, react_1.useContext)(context_1.RenderQueueContext);
15
15
  const processJob = (0, react_1.useCallback)(async (job) => {
16
+ const { signal } = getAbortController(job.id);
16
17
  let captionCount = null;
17
18
  let processingError = null;
18
19
  try {
20
+ signal.throwIfAborted();
19
21
  updateCaptionJobProgress(job.id, {
20
22
  message: 'Checking WebGPU support...',
21
23
  value: 0,
22
24
  });
23
25
  const support = await (0, whisper_webgpu_1.canUseWhisperWebGpu)();
26
+ signal.throwIfAborted();
24
27
  if (!support.supported) {
25
28
  throw new Error(support.detailedReason);
26
29
  }
@@ -29,15 +32,21 @@ const CaptionQueueProcessor = () => {
29
32
  value: 0.02,
30
33
  });
31
34
  await (0, whisper_webgpu_1.clearStaleModels)();
35
+ signal.throwIfAborted();
32
36
  await (0, load_model_for_job_1.loadModelForJob)({
37
+ signal,
33
38
  model: job.model,
34
39
  progressStart: 0.03,
35
40
  progressSpan: 0.27,
36
41
  isModelCached: (model) => (0, whisper_webgpu_1.isWhisperModelCached)({ model }),
37
- loadModel: (model, onProgress) => (0, whisper_webgpu_1.loadWhisperModel)({
38
- model,
39
- onProgress: (progress) => onProgress(progress.progress),
40
- }),
42
+ loadModel: async (model, onProgress) => {
43
+ await (0, whisper_webgpu_1.downloadWhisperModel)({
44
+ signal,
45
+ model,
46
+ onProgress: (progress) => onProgress(progress.progress),
47
+ });
48
+ await (0, whisper_webgpu_1.loadWhisperModel)({ model, signal });
49
+ },
41
50
  updateProgress: (progress) => updateCaptionJobProgress(job.id, progress),
42
51
  });
43
52
  updateCaptionJobProgress(job.id, {
@@ -45,6 +54,7 @@ const CaptionQueueProcessor = () => {
45
54
  value: 0.3,
46
55
  });
47
56
  const channelWaveform = await (0, resample_media_to_16_khz_1.resampleMediaTo16Khz)({
57
+ signal,
48
58
  src: job.src,
49
59
  audioStreamIndex: job.audioStreamIndex,
50
60
  requestInit: job.requestInit,
@@ -60,6 +70,7 @@ const CaptionQueueProcessor = () => {
60
70
  value: 0.5,
61
71
  });
62
72
  const transcription = await (0, whisper_webgpu_1.transcribe)({
73
+ signal,
63
74
  channelWaveform,
64
75
  model: job.model,
65
76
  task: job.task,
@@ -76,6 +87,8 @@ const CaptionQueueProcessor = () => {
76
87
  const { captions } = (0, whisper_webgpu_1.toCaptions)({
77
88
  whisperWebGpuOutput: transcription,
78
89
  });
90
+ signal.throwIfAborted();
91
+ markCaptionJobSaving(job.id);
79
92
  if (job.target === null) {
80
93
  updateCaptionJobProgress(job.id, {
81
94
  message: `Saving ${job.outName}...`,
@@ -121,13 +134,23 @@ const CaptionQueueProcessor = () => {
121
134
  // The pipeline is removed from the in-memory registry before disposal.
122
135
  // A cleanup failure should not hide a successfully written caption file.
123
136
  }
124
- if (processingError) {
137
+ if (signal.aborted) {
138
+ markCaptionJobCancelled(job.id);
139
+ }
140
+ else if (processingError) {
125
141
  markCaptionJobFailed(job.id, processingError);
126
142
  }
127
143
  else {
128
144
  markCaptionJobDone(job.id, captionCount !== null && captionCount !== void 0 ? captionCount : 0);
129
145
  }
130
- }, [markCaptionJobDone, markCaptionJobFailed, updateCaptionJobProgress]);
146
+ }, [
147
+ getAbortController,
148
+ markCaptionJobCancelled,
149
+ markCaptionJobDone,
150
+ markCaptionJobFailed,
151
+ markCaptionJobSaving,
152
+ updateCaptionJobProgress,
153
+ ]);
131
154
  (0, react_1.useEffect)(() => {
132
155
  setProcessCaptionJobCallback(processJob);
133
156
  return () => setProcessCaptionJobCallback(null);
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ export declare const QueueJobError: React.FC<{
3
+ readonly error: {
4
+ message: string;
5
+ stack: string | undefined;
6
+ };
7
+ readonly modalTitle: string;
8
+ }>;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QueueJobError = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const modals_1 = require("../../state/modals");
7
+ const item_style_1 = require("./item-style");
8
+ const errorStyle = {
9
+ ...item_style_1.renderQueueItemSubtitleStyle,
10
+ };
11
+ const QueueJobError = ({ error, modalTitle }) => {
12
+ const { setSelectedModal } = (0, react_1.useContext)(modals_1.SetSelectedModalContext);
13
+ const onClick = (0, react_1.useCallback)((event) => {
14
+ var _a;
15
+ event.stopPropagation();
16
+ setSelectedModal({
17
+ type: 'queue-job-error',
18
+ title: modalTitle,
19
+ error: { message: error.message, stack: (_a = error.stack) !== null && _a !== void 0 ? _a : null },
20
+ });
21
+ }, [error, modalTitle, setSelectedModal]);
22
+ return (jsx_runtime_1.jsx("button", { onClick: onClick, type: "button", style: errorStyle, title: error.message, children: error.message }));
23
+ };
24
+ exports.QueueJobError = QueueJobError;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ export declare const QueueJobErrorModal: React.FC<{
3
+ readonly title: string;
4
+ readonly error: {
5
+ message: string;
6
+ stack: string | null;
7
+ };
8
+ }>;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QueueJobErrorModal = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const CopyStackTrace_1 = require("../../error-overlay/remotion-overlay/CopyStackTrace");
7
+ const colors_1 = require("../../helpers/colors");
8
+ const modals_1 = require("../../state/modals");
9
+ const Button_1 = require("../Button");
10
+ const layout_1 = require("../layout");
11
+ const is_menu_item_1 = require("../Menu/is-menu-item");
12
+ const ModalContainer_1 = require("../ModalContainer");
13
+ const ModalHeader_1 = require("../ModalHeader");
14
+ const container = {
15
+ padding: 20,
16
+ maxWidth: 900,
17
+ paddingTop: 0,
18
+ };
19
+ const codeBlock = {
20
+ backgroundColor: colors_1.RENDER_STATUS_BACKGROUND,
21
+ whiteSpace: 'pre',
22
+ padding: 12,
23
+ borderRadius: 4,
24
+ fontFamily: 'monospace',
25
+ overflow: 'auto',
26
+ maxHeight: 300,
27
+ };
28
+ const description = {
29
+ color: colors_1.LIGHT_TEXT,
30
+ fontFamily: 'sans-serif',
31
+ fontSize: 14,
32
+ lineHeight: 1.5,
33
+ margin: 0,
34
+ marginBottom: 12,
35
+ marginTop: 16,
36
+ };
37
+ const spacer = {
38
+ height: layout_1.SPACING_UNIT,
39
+ width: layout_1.SPACING_UNIT,
40
+ };
41
+ const buttonRow = {
42
+ display: 'flex',
43
+ flexDirection: 'row',
44
+ justifyContent: 'flex-end',
45
+ };
46
+ const QueueJobErrorModal = ({ title, error }) => {
47
+ var _a;
48
+ const { setSelectedModal } = (0, react_1.useContext)(modals_1.SetSelectedModalContext);
49
+ const onClose = (0, react_1.useCallback)(() => {
50
+ setSelectedModal(null);
51
+ }, [setSelectedModal]);
52
+ const errorDetails = ((_a = error.stack) === null || _a === void 0 ? void 0 : _a.split('\n')[0].includes(error.message))
53
+ ? error.stack
54
+ : [error.message, error.stack].filter(Boolean).join('\n');
55
+ return (jsx_runtime_1.jsxs(ModalContainer_1.ModalContainer, { ariaLabel: title, onOutsideClick: onClose, onEscape: onClose, children: [
56
+ jsx_runtime_1.jsx(ModalHeader_1.ModalHeader, { title: title }), jsx_runtime_1.jsxs("div", { style: container, children: [
57
+ jsx_runtime_1.jsx("p", { style: description, children: "The job failed because of the following error:" }), jsx_runtime_1.jsx("div", { className: is_menu_item_1.HORIZONTAL_SCROLLBAR_CLASSNAME, style: codeBlock, children: errorDetails }), jsx_runtime_1.jsx("div", { style: spacer }), jsx_runtime_1.jsxs("div", { style: buttonRow, children: [
58
+ jsx_runtime_1.jsx(CopyStackTrace_1.CopyStackTrace, { errorText: errorDetails }), jsx_runtime_1.jsx(layout_1.Flex, {}), jsx_runtime_1.jsx(Button_1.Button, { onClick: onClose, children: "Close" })
59
+ ] })
60
+ ] })
61
+ ] }));
62
+ };
63
+ exports.QueueJobErrorModal = QueueJobErrorModal;
@@ -1,5 +1,7 @@
1
1
  import React from 'react';
2
+ import type { CaptionJob } from './caption-job-types';
2
3
  import type { AnyRenderJob } from './context';
4
+ import type { VideoMattingJob } from './video-matting-job-types';
3
5
  export declare const RenderQueueCancelButton: React.FC<{
4
- readonly job: AnyRenderJob;
6
+ readonly job: AnyRenderJob | CaptionJob | VideoMattingJob;
5
7
  }>;
@@ -10,18 +10,19 @@ const NotificationCenter_1 = require("../Notifications/NotificationCenter");
10
10
  const actions_1 = require("./actions");
11
11
  const context_1 = require("./context");
12
12
  const RenderQueueCancelButton = ({ job }) => {
13
- const isClientJob = (0, context_1.isClientRenderJob)(job);
14
13
  const { cancelClientJob } = (0, react_1.useContext)(context_1.RenderQueueContext);
15
14
  const onClick = (0, react_1.useCallback)((e) => {
16
15
  e.stopPropagation();
17
- if (isClientJob) {
16
+ if (job.type === 'caption' ||
17
+ job.type === 'video-matting' ||
18
+ (0, context_1.isClientRenderJob)(job)) {
18
19
  cancelClientJob(job.id);
19
20
  return;
20
21
  }
21
22
  (0, actions_1.cancelRenderJob)(job).catch((err) => {
22
23
  (0, NotificationCenter_1.showNotification)(`Could not cancel job: ${err.message}`, 2000);
23
24
  });
24
- }, [job, isClientJob, cancelClientJob]);
25
+ }, [job, cancelClientJob]);
25
26
  const icon = (0, react_1.useMemo)(() => {
26
27
  return {
27
28
  height: 14,
@@ -31,6 +32,12 @@ const RenderQueueCancelButton = ({ job }) => {
31
32
  const renderAction = (0, react_1.useCallback)((color) => {
32
33
  return (jsx_runtime_1.jsx("svg", { style: icon, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 512 512", children: jsx_runtime_1.jsx("path", { fill: color, d: "M367.2 412.5L99.5 144.8C77.1 176.1 64 214.5 64 256c0 106 86 192 192 192c41.5 0 79.9-13.1 111.2-35.5zm45.3-45.3C434.9 335.9 448 297.5 448 256c0-106-86-192-192-192c-41.5 0-79.9 13.1-111.2 35.5L412.5 367.2zM512 256c0 141.4-114.6 256-256 256S0 397.4 0 256S114.6 0 256 0S512 114.6 512 256z" }) }));
33
34
  }, [icon]);
34
- return (jsx_runtime_1.jsx(ActionTooltip_1.ActionTooltip, { label: "Cancel", shortcut: null, delay: 800, dismissOnClick: true, children: jsx_runtime_1.jsx(InlineAction_1.InlineAction, { "aria-label": "Cancel render", renderAction: renderAction, onClick: onClick, variant: null }) }));
35
+ return (jsx_runtime_1.jsx(ActionTooltip_1.ActionTooltip, { label: "Cancel", shortcut: null, delay: 800, dismissOnClick: true, children: jsx_runtime_1.jsx(InlineAction_1.InlineAction, { "aria-label": job.type === 'caption'
36
+ ? 'Cancel transcription'
37
+ : job.type === 'video-matting'
38
+ ? 'outName' in job
39
+ ? 'Cancel background removal'
40
+ : 'Cancel video matting'
41
+ : 'Cancel render', renderAction: renderAction, onClick: onClick, variant: null }) }));
35
42
  };
36
43
  exports.RenderQueueCancelButton = RenderQueueCancelButton;
@@ -1,5 +1,7 @@
1
1
  import React from 'react';
2
+ import type { CaptionJob } from './caption-job-types';
2
3
  import type { AnyRenderJob } from './context';
4
+ import type { VideoMattingJob } from './video-matting-job-types';
3
5
  export declare const RenderQueueRepeatItem: React.FC<{
4
- readonly job: AnyRenderJob;
6
+ readonly job: AnyRenderJob | CaptionJob | VideoMattingJob;
5
7
  }>;
@@ -11,10 +11,27 @@ const InlineAction_1 = require("../InlineAction");
11
11
  const context_1 = require("./context");
12
12
  const RenderQueueRepeatItem = ({ job }) => {
13
13
  const { setSelectedModal } = (0, react_1.useContext)(modals_1.SetSelectedModalContext);
14
- const isClientJob = (0, context_1.isClientRenderJob)(job);
15
14
  const onClick = (0, react_1.useCallback)((e) => {
16
15
  e.stopPropagation();
17
- if (isClientJob) {
16
+ if (job.type === 'caption') {
17
+ setSelectedModal({
18
+ type: 'transcribe',
19
+ src: job.src,
20
+ displayName: job.displayName,
21
+ audioStreamIndex: job.audioStreamIndex,
22
+ requestInit: job.requestInit,
23
+ target: job.target,
24
+ });
25
+ }
26
+ else if (job.type === 'video-matting') {
27
+ setSelectedModal({
28
+ type: 'video-matting',
29
+ src: job.src,
30
+ displayName: job.displayName,
31
+ target: job.target,
32
+ });
33
+ }
34
+ else if ((0, context_1.isClientRenderJob)(job)) {
18
35
  const retryPayload = (0, retry_payload_1.makeClientRetryPayload)(job);
19
36
  setSelectedModal(retryPayload);
20
37
  }
@@ -22,7 +39,7 @@ const RenderQueueRepeatItem = ({ job }) => {
22
39
  const retryPayload = (0, retry_payload_1.makeRetryPayload)(job);
23
40
  setSelectedModal(retryPayload);
24
41
  }
25
- }, [job, isClientJob, setSelectedModal]);
42
+ }, [job, setSelectedModal]);
26
43
  const icon = (0, react_1.useMemo)(() => {
27
44
  return {
28
45
  height: 12,
@@ -14,6 +14,10 @@ const use_select_asset_1 = require("../use-select-asset");
14
14
  const CircularProgress_1 = require("./CircularProgress");
15
15
  const context_1 = require("./context");
16
16
  const item_style_1 = require("./item-style");
17
+ const QueueJobError_1 = require("./QueueJobError");
18
+ const RenderQueueCancelledMessage_1 = require("./RenderQueueCancelledMessage");
19
+ const RenderQueueItemCancelButton_1 = require("./RenderQueueItemCancelButton");
20
+ const RenderQueueRepeat_1 = require("./RenderQueueRepeat");
17
21
  const SuccessIcon_1 = require("./SuccessIcon");
18
22
  const container = {
19
23
  borderRadius: 4,
@@ -50,12 +54,12 @@ const ellipsisIconStyle = {
50
54
  style: { height: 12 },
51
55
  };
52
56
  const Status = ({ job }) => {
53
- if (job.status === 'running') {
54
- return (jsx_runtime_1.jsx("div", { style: statusIcon, role: "progressbar", "aria-label": "Video matting progress", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": Math.round(job.progress.value * 100), "aria-valuetext": job.progress.message, children: jsx_runtime_1.jsx(CircularProgress_1.CircularProgress, { progress: Math.max(0.07, job.progress.value) }) }));
57
+ if (job.status === 'running' || job.status === 'saving') {
58
+ return (jsx_runtime_1.jsx("div", { style: statusIcon, role: "progressbar", "aria-label": "Background removal progress", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": Math.round(job.progress.value * 100), "aria-valuetext": job.progress.message, children: jsx_runtime_1.jsx(CircularProgress_1.CircularProgress, { progress: Math.max(0.07, job.progress.value) }) }));
55
59
  }
56
60
  if (job.status === 'done')
57
61
  return jsx_runtime_1.jsx(SuccessIcon_1.SuccessIcon, {});
58
- if (job.status === 'failed')
62
+ if (job.status === 'failed' || job.status === 'cancelled')
59
63
  return (jsx_runtime_1.jsx("svg", { style: statusIcon, viewBox: "0 0 512 512", children: jsx_runtime_1.jsx("path", { fill: colors_1.FAIL_COLOR, d: "M0 160V352L160 512H352L512 352V160L352 0H160L0 160zm353.9 32-64 64 64 64L320 353.9l-64-64-64 64L158.1 320l64-64-64-64L192 158.1l64 64 64-64z" }) }));
60
64
  return (jsx_runtime_1.jsx("svg", { style: statusIcon, viewBox: "0 0 512 512", children: jsx_runtime_1.jsx("path", { fill: colors_1.LIGHT_TEXT, d: "M256 512C114.6 512 0 397.4 0 256S114.6 0 256 0s256 114.6 256 256-114.6 256-256 256zM232 120v136c0 8 4 15.5 10.7 20l96 64 26.6-39.9-85.3-56.9V120z" }) }));
61
65
  };
@@ -74,50 +78,41 @@ const VideoMattingQueueItem = ({ job, selected }) => {
74
78
  WebkitUserSelect: 'none',
75
79
  }), [done, hovered, selected]);
76
80
  const messages = job.status === 'idle'
77
- ? ['Queued for video matting']
78
- : job.status === 'running'
81
+ ? ['Queued for background removal']
82
+ : job.status === 'running' || job.status === 'saving'
79
83
  ? [job.progress.message, job.progress.detail].filter((message) => message !== null)
80
84
  : job.status === 'failed'
81
85
  ? [job.error.message]
82
- : [job.baseOutName, job.foregroundOutName];
86
+ : job.status === 'cancelled'
87
+ ? ['Cancelled']
88
+ : [job.outName];
83
89
  const tooltip = messages.join('\n');
84
90
  const revealAsset = (0, react_1.useCallback)((assetName) => {
85
91
  selectAsset(assetName);
86
92
  (0, url_state_1.pushUrl)(`/assets/${assetName}`);
87
93
  }, [selectAsset]);
94
+ const outputName = job.outName;
88
95
  const onClick = (0, react_1.useCallback)(() => {
89
96
  if (!done)
90
97
  return;
91
- revealAsset(job.foregroundOutName);
92
- }, [done, job.foregroundOutName, revealAsset]);
98
+ revealAsset(outputName);
99
+ }, [done, outputName, revealAsset]);
93
100
  const revealItems = (0, react_1.useMemo)(() => {
94
101
  return [
95
102
  {
96
103
  disabled: false,
97
- id: 'reveal-foreground',
104
+ id: 'reveal-output',
98
105
  keyHint: null,
99
- label: 'Reveal foreground',
106
+ label: 'Reveal output',
100
107
  leftItem: null,
101
- onClick: () => revealAsset(job.foregroundOutName),
108
+ onClick: () => revealAsset(outputName),
102
109
  quickSwitcherLabel: null,
103
110
  subMenu: null,
104
111
  type: 'item',
105
- value: 'reveal-foreground',
106
- },
107
- {
108
- disabled: false,
109
- id: 'reveal-background',
110
- keyHint: null,
111
- label: 'Reveal background',
112
- leftItem: null,
113
- onClick: () => revealAsset(job.baseOutName),
114
- quickSwitcherLabel: null,
115
- subMenu: null,
116
- type: 'item',
117
- value: 'reveal-background',
112
+ value: 'reveal-output',
118
113
  },
119
114
  ];
120
- }, [job.baseOutName, job.foregroundOutName, revealAsset]);
115
+ }, [outputName, revealAsset]);
121
116
  const onRemove = (0, react_1.useCallback)((event) => {
122
117
  event.stopPropagation();
123
118
  removeVideoMattingJob(job.id);
@@ -125,7 +120,9 @@ const VideoMattingQueueItem = ({ job, selected }) => {
125
120
  const renderRemove = (0, react_1.useCallback)((color) => (jsx_runtime_1.jsx("svg", { style: removeIcon, viewBox: "0 0 320 512", children: jsx_runtime_1.jsx("path", { fill: color, d: "M310.6 150.6 205.3 256l105.3 105.4-45.3 45.3L160 301.3 54.6 406.6 9.4 361.4 114.7 256 9.4 150.6l45.2-45.2L160 210.7l105.3-105.3z" }) })), []);
126
121
  return (jsx_runtime_1.jsxs(layout_1.Row, { "data-render-queue-item": job.id, style: style, align: "center", onClick: onClick, onPointerEnter: () => setHovered(true), onPointerLeave: () => setHovered(false), children: [
127
122
  jsx_runtime_1.jsx(Status, { job: job }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), jsx_runtime_1.jsxs("div", { style: right, children: [
128
- jsx_runtime_1.jsx("div", { style: title, children: job.displayName }), jsx_runtime_1.jsx("div", { style: subtitles, title: tooltip, children: messages.map((message) => (jsx_runtime_1.jsx("span", { style: subtitle, children: message }, message))) })
129
- ] }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), done ? (jsx_runtime_1.jsx(ActionTooltip_1.ActionTooltip, { label: "Reveal video layer", shortcut: null, delay: 800, dismissOnClick: true, children: jsx_runtime_1.jsx(InlineDropdown_1.InlineDropdown, { renderAction: (color) => (jsx_runtime_1.jsx(ellipsis_1.EllipsisIcon, { fill: color, svgProps: ellipsisIconStyle })), "aria-label": "Reveal video layer", values: revealItems, variant: null }) })) : null, job.status === 'running' ? null : (jsx_runtime_1.jsx(ActionTooltip_1.ActionTooltip, { label: "Clear", shortcut: null, delay: 800, dismissOnClick: true, children: jsx_runtime_1.jsx(InlineAction_1.InlineAction, { renderAction: renderRemove, onClick: onRemove, "aria-label": "Clear", variant: null }) }))] }));
123
+ jsx_runtime_1.jsx("div", { style: title, children: job.displayName }), jsx_runtime_1.jsx("div", { style: subtitles, title: tooltip, children: job.status === 'cancelled' ? (jsx_runtime_1.jsx(RenderQueueCancelledMessage_1.RenderQueueCancelledMessage, {})) : job.status === 'failed' ? (jsx_runtime_1.jsx(QueueJobError_1.QueueJobError, { error: job.error, modalTitle: "Background removal failed" })) : (messages.map((message) => (jsx_runtime_1.jsx("span", { style: subtitle, children: message }, message)))) })
124
+ ] }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), done ? (jsx_runtime_1.jsx(ActionTooltip_1.ActionTooltip, { label: "Reveal output", shortcut: null, delay: 800, dismissOnClick: true, children: jsx_runtime_1.jsx(InlineDropdown_1.InlineDropdown, { renderAction: (color) => (jsx_runtime_1.jsx(ellipsis_1.EllipsisIcon, { fill: color, svgProps: ellipsisIconStyle })), "aria-label": "Reveal output", values: revealItems, variant: null }) })) : null, job.status === 'done' ||
125
+ job.status === 'failed' ||
126
+ job.status === 'cancelled' ? (jsx_runtime_1.jsx(RenderQueueRepeat_1.RenderQueueRepeatItem, { job: job })) : null, job.status === 'running' ? (jsx_runtime_1.jsx(RenderQueueItemCancelButton_1.RenderQueueCancelButton, { job: job })) : job.status === 'saving' ? null : (jsx_runtime_1.jsx(ActionTooltip_1.ActionTooltip, { label: "Clear", shortcut: null, delay: 800, dismissOnClick: true, children: jsx_runtime_1.jsx(InlineAction_1.InlineAction, { renderAction: renderRemove, onClick: onRemove, "aria-label": "Clear", variant: null }) }))] }));
130
127
  };
131
128
  exports.VideoMattingQueueItem = VideoMattingQueueItem;
@@ -4,41 +4,51 @@ exports.VideoMattingQueueProcessor = void 0;
4
4
  const video_matting_1 = require("@remotion/video-matting");
5
5
  const react_1 = require("react");
6
6
  const write_static_file_1 = require("../../api/write-static-file");
7
+ const browser_studio_operations_1 = require("../../helpers/browser-studio-operations");
8
+ const call_api_1 = require("../call-api");
7
9
  const context_1 = require("./context");
8
10
  const load_model_for_job_1 = require("./load-model-for-job");
9
11
  const VideoMattingQueueProcessor = () => {
10
- const { markVideoMattingJobDone, markVideoMattingJobFailed, setProcessVideoMattingJobCallback, updateVideoMattingJobProgress, } = (0, react_1.useContext)(context_1.RenderQueueContext);
12
+ const { markVideoMattingJobDone, markVideoMattingJobFailed, markVideoMattingJobCancelled, markVideoMattingJobSaving, getAbortController, setProcessVideoMattingJobCallback, updateVideoMattingJobProgress, } = (0, react_1.useContext)(context_1.RenderQueueContext);
11
13
  const processJob = (0, react_1.useCallback)(async (job) => {
12
- let outputs = null;
14
+ const { signal } = getAbortController(job.id);
15
+ let output = null;
13
16
  let processingError = null;
14
17
  try {
18
+ signal.throwIfAborted();
15
19
  updateVideoMattingJobProgress(job.id, {
16
20
  detail: null,
17
21
  message: 'Checking WebGPU support...',
18
22
  value: 0,
19
23
  });
20
24
  const support = await (0, video_matting_1.canUseVideoMatting)({ model: job.model });
25
+ signal.throwIfAborted();
21
26
  if (!support.supported) {
22
27
  throw new Error(support.detailedReason);
23
28
  }
24
29
  await (0, load_model_for_job_1.loadModelForJob)({
30
+ signal,
25
31
  model: job.model,
26
32
  progressStart: 0,
27
33
  progressSpan: 0.2,
28
34
  isModelCached: (model) => (0, video_matting_1.isVideoMattingModelCached)({ model }),
29
- loadModel: (model, onProgress) => (0, video_matting_1.loadVideoMattingModel)({
30
- model,
31
- onProgress: (progress) => onProgress(progress.progress),
32
- }),
35
+ loadModel: async (model, onProgress) => {
36
+ await (0, video_matting_1.downloadVideoMattingModel)({
37
+ signal,
38
+ model,
39
+ onProgress: (progress) => onProgress(progress.progress),
40
+ });
41
+ await (0, video_matting_1.loadVideoMattingModel)({ model, signal });
42
+ },
33
43
  updateProgress: (progress) => updateVideoMattingJobProgress(job.id, {
34
44
  ...progress,
35
45
  detail: null,
36
46
  }),
37
47
  });
38
- outputs = await (0, video_matting_1.separateVideoLayers)({
48
+ const mattingOptions = {
49
+ signal,
39
50
  src: job.src,
40
51
  model: job.model,
41
- audio: job.audio,
42
52
  videoBitrate: job.videoBitrate,
43
53
  onProgress: (progress) => {
44
54
  var _a;
@@ -47,51 +57,81 @@ const VideoMattingQueueProcessor = () => {
47
57
  ? `Processed ${progress.processedFrames} ${progress.processedFrames === 1 ? 'frame' : 'frames'}`
48
58
  : `Processed ${progress.processedFrames} ${progress.processedFrames === 1 ? 'frame' : 'frames'} · ${Math.round(progress.progress * 100)}%`,
49
59
  message: progress.stage === 'finalizing'
50
- ? 'Finalizing video layers...'
51
- : 'Separating foreground...',
60
+ ? 'Finalizing video...'
61
+ : 'Removing background...',
52
62
  value: 0.2 + ((_a = progress.progress) !== null && _a !== void 0 ? _a : 1) * 0.65,
53
63
  });
54
64
  },
65
+ };
66
+ output = await video_matting_1.VideoMattingInternals.removeVideoBackground({
67
+ ...mattingOptions,
68
+ audio: job.audio,
55
69
  });
70
+ if (output === null) {
71
+ throw new Error('Video matting produced no output.');
72
+ }
73
+ signal.throwIfAborted();
56
74
  updateVideoMattingJobProgress(job.id, {
57
75
  detail: null,
58
- message: 'Saving video layers...',
76
+ message: 'Saving video...',
59
77
  value: 0.88,
60
78
  });
61
- const [base, foreground] = await Promise.all([
62
- outputs.base.getBlob(),
63
- outputs.foreground.getBlob(),
64
- ]);
65
- await Promise.all([
66
- base
67
- .arrayBuffer()
68
- .then((contents) => (0, write_static_file_1.writeStaticFile)({ contents, filePath: job.baseOutName })),
69
- foreground
70
- .arrayBuffer()
71
- .then((contents) => (0, write_static_file_1.writeStaticFile)({ contents, filePath: job.foregroundOutName })),
72
- ]);
79
+ const video = await output.video.getBlob();
80
+ signal.throwIfAborted();
81
+ markVideoMattingJobSaving(job.id);
82
+ await video
83
+ .arrayBuffer()
84
+ .then((contents) => (0, write_static_file_1.writeStaticFile)({ contents, filePath: job.outName }));
85
+ if (job.target !== null) {
86
+ updateVideoMattingJobProgress(job.id, {
87
+ detail: null,
88
+ message: 'Replacing video source...',
89
+ value: 0.97,
90
+ });
91
+ const browserStudioOperations = (0, browser_studio_operations_1.getBrowserStudioOperations)();
92
+ const request = {
93
+ fileName: job.target.fileName,
94
+ nodePath: job.target.nodePath.nodePath,
95
+ src: job.outName,
96
+ };
97
+ const replaceSource = browserStudioOperations === null || browserStudioOperations === void 0 ? void 0 : browserStudioOperations.replaceVideoSource;
98
+ if (browserStudioOperations && !replaceSource) {
99
+ throw new Error('Browser Studio cannot replace the video source.');
100
+ }
101
+ const response = replaceSource
102
+ ? await replaceSource(request)
103
+ : await (0, call_api_1.callApi)('/api/replace-video-source', request);
104
+ if (!response.success) {
105
+ throw new Error(response.reason);
106
+ }
107
+ }
73
108
  }
74
109
  catch (error) {
75
110
  processingError =
76
111
  error instanceof Error ? error : new Error(String(error));
77
112
  }
113
+ if (output) {
114
+ await Promise.allSettled([output.video.dispose()]);
115
+ }
78
116
  try {
79
- await Promise.all([
80
- outputs === null || outputs === void 0 ? void 0 : outputs.base.dispose(),
81
- outputs === null || outputs === void 0 ? void 0 : outputs.foreground.dispose(),
82
- ]);
83
117
  await (0, video_matting_1.disposeVideoMattingModel)({ model: job.model });
84
118
  }
85
119
  catch (_a) {
86
120
  // Cleanup errors must not hide successfully written outputs.
87
121
  }
88
- if (processingError) {
122
+ if (signal.aborted) {
123
+ markVideoMattingJobCancelled(job.id);
124
+ }
125
+ else if (processingError) {
89
126
  markVideoMattingJobFailed(job.id, processingError);
90
127
  }
91
128
  else {
92
129
  markVideoMattingJobDone(job.id);
93
130
  }
94
131
  }, [
132
+ getAbortController,
133
+ markVideoMattingJobCancelled,
134
+ markVideoMattingJobSaving,
95
135
  markVideoMattingJobDone,
96
136
  markVideoMattingJobFailed,
97
137
  updateVideoMattingJobProgress,
@@ -7,7 +7,9 @@ export type CaptionJobProgress = {
7
7
  type CaptionJobStatus = {
8
8
  status: 'idle';
9
9
  } | {
10
- status: 'running';
10
+ status: 'cancelled';
11
+ } | {
12
+ status: 'running' | 'saving';
11
13
  progress: CaptionJobProgress;
12
14
  } | {
13
15
  status: 'done';
@@ -32,12 +32,16 @@ type RenderQueueContextType = {
32
32
  updateCaptionJobProgress: (jobId: string, progress: CaptionJobProgress) => void;
33
33
  markCaptionJobDone: (jobId: string, captionCount: number) => void;
34
34
  markCaptionJobFailed: (jobId: string, error: Error) => void;
35
+ markCaptionJobCancelled: (jobId: string) => void;
36
+ markCaptionJobSaving: (jobId: string) => void;
35
37
  removeCaptionJob: (jobId: string) => void;
36
38
  setProcessCaptionJobCallback: (callback: ((job: CaptionJob) => Promise<void>) | null) => void;
37
39
  addVideoMattingJob: (params: AddVideoMattingJobParams) => string;
38
40
  updateVideoMattingJobProgress: (jobId: string, progress: VideoMattingJobProgress) => void;
39
41
  markVideoMattingJobDone: (jobId: string) => void;
40
42
  markVideoMattingJobFailed: (jobId: string, error: Error) => void;
43
+ markVideoMattingJobCancelled: (jobId: string) => void;
44
+ markVideoMattingJobSaving: (jobId: string) => void;
41
45
  removeVideoMattingJob: (jobId: string) => void;
42
46
  setProcessVideoMattingJobCallback: (callback: ((job: VideoMattingJob) => Promise<void>) | null) => void;
43
47
  getAbortController: (jobId: string) => AbortController;