diff --git a/apps/web/src/components/editor/panels/assets/views/captions.tsx b/apps/web/src/components/editor/panels/assets/views/captions.tsx index 7a3b16bf..514050a5 100644 --- a/apps/web/src/components/editor/panels/assets/views/captions.tsx +++ b/apps/web/src/components/editor/panels/assets/views/captions.tsx @@ -11,6 +11,11 @@ import { useState, useRef } from "react"; import { extractTimelineAudio } from "@/lib/media/mediabunny"; import { useEditor } from "@/hooks/use-editor"; import { DEFAULT_TEXT_ELEMENT } from "@/constants/text-constants"; +import { + BatchCommand, + AddTrackCommand, + InsertElementCommand, +} from "@/lib/commands"; import { TRANSCRIPTION_LANGUAGES } from "@/constants/transcription-constants"; import type { TranscriptionLanguage, @@ -20,7 +25,12 @@ import { transcriptionService } from "@/services/transcription/service"; import { decodeAudioToFloat32 } from "@/lib/media/audio"; import { buildCaptionChunks } from "@/lib/transcription/caption"; import { Spinner } from "@/components/ui/spinner"; -import { Label } from "@/components/ui/label"; +import { + Section, + SectionContent, + SectionField, + SectionFields, +} from "@/components/editor/panels/properties/section"; export function Captions() { const [selectedLanguage, setSelectedLanguage] = @@ -60,29 +70,28 @@ export function Captions() { onProgress: handleProgress, }); - setProcessingStep("Generating captions..."); - const captionChunks = buildCaptionChunks({ segments: result.segments }); + setProcessingStep("Generating captions..."); + const captionChunks = buildCaptionChunks({ segments: result.segments }); - const captionTrackId = editor.timeline.addTrack({ - type: "text", - index: 0, - }); + const addTrackCommand = new AddTrackCommand("text", 0); + const insertCommands = captionChunks.map((caption, i) => + new InsertElementCommand({ + placement: { mode: "explicit", trackId: addTrackCommand.getTrackId() }, + element: { + ...DEFAULT_TEXT_ELEMENT, + name: `Caption ${i + 1}`, + content: caption.text, + duration: caption.duration, + startTime: caption.startTime, + fontSize: 65, + fontWeight: "bold", + }, + }) + ); - for (let i = 0; i < captionChunks.length; i++) { - const caption = captionChunks[i]; - editor.timeline.insertElement({ - placement: { mode: "explicit", trackId: captionTrackId }, - element: { - ...DEFAULT_TEXT_ELEMENT, - name: `Caption ${i + 1}`, - content: caption.text, - duration: caption.duration, - startTime: caption.startTime, - fontSize: 65, - fontWeight: "bold", - }, - }); - } + editor.command.execute({ + command: new BatchCommand([addTrackCommand, ...insertCommands]), + }); } catch (error) { console.error("Transcription failed:", error); setError( @@ -108,43 +117,49 @@ export function Captions() { }; return ( - -
- - -
- -
- {error && ( -
-

{error}

-
- )} + +
+ + + + + + + {error && ( +
+

{error}

+
+ )} +
+
+
+ -
+ className="w-full" + onClick={handleGenerateTranscript} + disabled={isProcessing} + > + {isProcessing && } + {isProcessing ? processingStep : "Generate transcript"} + + +
); }