Skip to content

Add support for basic SRT subtitle import to Captions panel#756

Merged
mazeincoding merged 12 commits intoOpenCut-app:mainfrom
kcfancher:feature/subtitles
Apr 14, 2026
Merged

Add support for basic SRT subtitle import to Captions panel#756
mazeincoding merged 12 commits intoOpenCut-app:mainfrom
kcfancher:feature/subtitles

Conversation

@kcfancher
Copy link
Copy Markdown
Contributor

@kcfancher kcfancher commented Apr 2, 2026

Phase one support for #749

Changelog

  • Splits Captions panel into two "tabs": Generate and Import
  • adds .srt import support for generating text elements
  • Presents warning when some subtitle cues are skipped
  • Improves default subtitle layout for captions by shrinking default text size, "pinning" to bottom, and auto-wrapping long lines

Notes

  • Only .srt support is implemented in this PR, but parsing interface is generic to allow future formats.
  • Followup work is planned to add other format support, particularly .ass.
  • I rebuilt the first four commits on top of the recent architectural changes merged in, they all reference the original commits.

Summary by CodeRabbit

  • New Features
    • Captions panel now offers combined Generate + Import workflow and an Import action for .srt/.ass files.
  • Improvements
    • Better subtitle layout: sizing, wrapping, alignment, and styling fidelity when inserted.
    • Clearer processing feedback and persistent warnings during generate/import.
  • Bug Fixes
    • More reliable caption insertion flow to reduce failures and duplication.

Update

  • Added preliminary .ass subtitle support for the styles that the OpenCut editor currently supports
  • Presents a warning to user of file formats that were skipped as unsupported

.ass Support

  • font family
  • font size
  • primary text color
  • bold / italic / underline / strikeout
  • letter spacing
  • alignment / margins
  • boxed background in limited cases
  • outline / shadow
  • rotation / scale style features
  • ASS event effects
  • karaoke / timing-based effects
  • Inline formats

[Modified from 0bd641b, 2026-03-28 08:46:23 -0400]

Parse .srt files into chunks and insert them as text elements on a new text track using the existing caption styling defaults. Displays a warning when malformed cues are skipped during import.
[Modified from eece3bb, 2026-03-28 09:13:18 -0400]

Batch caption insertion in a BatchCommand so that undo will batch undo all subtitle insertion from either srt file or ai transcriptions.
[Modified from e84404b, 2026-03-28 09:52:31 -0400]

Extracted the srt specific extraction behind a generic shared interface to allow easier adding of other subtitle formats in the future.
[Modified from b5deec4, 2026-03-31 11:49:34 -0400]

Shrink font size, aim to layout 5% above bottom, keep subtitle width 80% of video, wrap text on new lines if too long.
Split captions panel into Generate and Import tabs as they are two different approaches for adding captions.
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 2, 2026

@kcfancher is attempting to deploy a commit to the OpenCut OSS Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 2, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Adds subtitle import to the Captions panel (Import action/button and hidden file input), SRT/ASS parsers and types, measured/wrapped subtitle element builder, and batched insertion of parsed cues as a text track via a new insert helper. Also replaces local processing state with a reducer.

Changes

Cohort / File(s) Summary
Captions panel
apps/web/src/components/editor/panels/assets/views/captions.tsx
Reworked UI to expose an Import action/button and hidden .srt/.ass file input; switched processing state to a reducer; added file read/parse flow calling parseSubtitleFile, surfaces warnings/skipped counts, and inserts captions via insertCaptionChunksAsTextTrack.
Subtitle parsing & types
apps/web/src/lib/subtitles/parse.ts, apps/web/src/lib/subtitles/srt.ts, apps/web/src/lib/subtitles/ass.ts, apps/web/src/lib/subtitles/types.ts
New parsing entrypoint (parseSubtitleFile) and implementations for SRT and ASS returning ParseSubtitleResult (captions, skippedCueCount, warnings). Added subtitle-related types and ASS style-to-override mapping with warning aggregation.
Element builder & insertion
apps/web/src/lib/subtitles/build-subtitle-text-element.ts, apps/web/src/lib/subtitles/insert.ts
Added buildSubtitleTextElement to compute font, wrap text to canvas, measure visual rect, and produce CreateTextElement with positioning; added insertCaptionChunksAsTextTrack to add a text track and batch InsertElementCommands for each cue, returning the new trackId.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CaptionsUI as Captions Panel
    participant FileInput as File Input
    participant Parser as parseSubtitleFile
    participant Editor as Editor Core
    participant Builder as buildSubtitleTextElement

    User->>CaptionsUI: Open Import / choose file
    User->>FileInput: Select .srt/.ass
    FileInput->>CaptionsUI: fileName + content
    CaptionsUI->>Parser: parseSubtitleFile(fileName, content)
    Parser-->>CaptionsUI: {captions, skippedCueCount, warnings}
    alt warnings or skipped cues
        CaptionsUI->>User: Display warnings/skipped count
    end
    User->>CaptionsUI: Insert captions
    CaptionsUI->>Editor: insertCaptionChunksAsTextTrack(captions)
    Editor->>Editor: AddTrackCommand -> create text track (trackId)
    loop per caption
        Editor->>Builder: buildSubtitleTextElement(index, caption, canvasSize)
        Builder-->>Editor: CreateTextElement
        Editor->>Editor: InsertElementCommand (trackId)
    end
    Editor->>Editor: BatchCommand -> execute
    Editor-->>CaptionsUI: trackId
    CaptionsUI->>User: Confirm insertion
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Poem

🐰 I nibble lines of timing neat,

I wrap each word and tap my feet.
I build the text and stack it right,
then hop the captions into sight.
Hooray — the subtitles take flight!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description deviates significantly from the repository's required template, which explicitly states 'We are not currently accepting PRs except for critical bugs' and requires either bug approval or a note that feature PRs should be closed. Acknowledge the repository's PR acceptance policy in the description and confirm this was pre-approved as required by the template, or update to follow the mandatory template structure.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add support for basic SRT subtitle import to Captions panel' accurately and specifically describes the main feature being added, matching the primary changeset objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
apps/web/src/components/editor/panels/assets/views/captions.tsx (2)

253-261: Add explicit type="button" here as well.

Same as above—explicit type="button" for consistency and to prevent unintended behavior if this component is ever placed inside a form.

Suggested change
 <Button
+  type="button"
   variant="outline"
   className="mt-auto w-full"
   onClick={handleImportClick}
   disabled={isProcessing}
 >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/editor/panels/assets/views/captions.tsx` around lines
253 - 261, The Button used for importing captions should explicitly set
type="button" to avoid accidental form submissions if this component is rendered
inside a form; update the Button element that uses onClick={handleImportClick}
(and references isProcessing and processingStep) to include type="button"
alongside its existing props.

226-233: Add explicit type="button" to Button elements.

Per coding guidelines, button elements should always include a type attribute to prevent accidental form submissions. While the Button component may default to type="button", explicitly setting it improves clarity.

Suggested change
 <Button
+  type="button"
   className="mt-auto w-full"
   onClick={handleGenerateTranscript}
   disabled={isProcessing}
 >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/editor/panels/assets/views/captions.tsx` around lines
226 - 233, The Button rendering that triggers handleGenerateTranscript (the JSX
using <Button className="mt-auto w-full" onClick={handleGenerateTranscript}
disabled={isProcessing}>) should include an explicit type attribute to avoid
accidental form submissions; update that Button to add type="button" (while
preserving className, onClick, disabled and the Spinner/label logic using
isProcessing and processingStep).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/web/src/components/editor/panels/assets/views/captions.tsx`:
- Around line 253-261: The Button used for importing captions should explicitly
set type="button" to avoid accidental form submissions if this component is
rendered inside a form; update the Button element that uses
onClick={handleImportClick} (and references isProcessing and processingStep) to
include type="button" alongside its existing props.
- Around line 226-233: The Button rendering that triggers
handleGenerateTranscript (the JSX using <Button className="mt-auto w-full"
onClick={handleGenerateTranscript} disabled={isProcessing}>) should include an
explicit type attribute to avoid accidental form submissions; update that Button
to add type="button" (while preserving className, onClick, disabled and the
Spinner/label logic using isProcessing and processingStep).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 838b65e4-db65-4028-8096-48883624e38b

📥 Commits

Reviewing files that changed from the base of the PR and between 3516bd6 and 38b3afc.

📒 Files selected for processing (5)
  • apps/web/src/components/editor/panels/assets/views/captions.tsx
  • apps/web/src/lib/subtitles/build-subtitle-text-element.ts
  • apps/web/src/lib/subtitles/insert.ts
  • apps/web/src/lib/subtitles/parse.ts
  • apps/web/src/lib/subtitles/srt.ts

Extend subtitle import to accept .ass files alongside .srt, map supported .ass styles onto imported text elements, and display warnings when unsupported .ass features are skipped.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
apps/web/src/components/editor/panels/assets/views/captions.tsx (2)

97-106: Consider more specific error message.

When insertCaptionChunksAsTextTrack returns no trackId, the error "No captions were generated" is slightly misleading for the import flow since captions were parsed but insertion failed. The message is accurate for the generate flow.

♻️ Proposed fix with context-aware error
-const insertCaptionChunks = ({ captions }: { captions: CaptionChunk[] }) => {
+const insertCaptionChunks = ({
+	captions,
+	errorMessage = "No captions were generated",
+}: {
+	captions: CaptionChunk[];
+	errorMessage?: string;
+}) => {
 	const trackId = insertCaptionChunksAsTextTrack({
 		editor,
 		captions,
 	});

 	if (!trackId) {
-		throw new Error("No captions were generated");
+		throw new Error(errorMessage);
 	}
 };

Then call with appropriate message:

// In handleImportFile:
insertCaptionChunks({ captions: result.captions, errorMessage: "Failed to insert imported subtitles" });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/editor/panels/assets/views/captions.tsx` around lines
97 - 106, Update insertCaptionChunks to accept an optional errorMessage string
and use that when throwing the Error if insertCaptionChunksAsTextTrack returns
no trackId (change signature of insertCaptionChunks to ({ captions, errorMessage
}:{ captions: CaptionChunk[]; errorMessage?: string })). Replace the current
generic throw new Error("No captions were generated") with throw new
Error(errorMessage ?? "No captions were generated") and update callers (e.g.,
handleImportFile) to pass a contextual message like "Failed to insert imported
subtitles" when the failure is in the import flow.

275-283: Potential duplicate key issue in warnings list.

Using the warning message string as the key will cause React key collisions if the same warning appears multiple times. Consider using the index or a unique identifier.

♻️ Proposed fix using index as key
 <ul className="text-sm text-amber-700 space-y-1">
-	{warnings.map((warning) => (
-		<li key={warning}>{warning}</li>
+	{warnings.map((warning, index) => (
+		<li key={index}>{warning}</li>
 	))}
 </ul>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/editor/panels/assets/views/captions.tsx` around lines
275 - 283, The list uses the warning string as the React key in
warnings.map((warning) => <li key={warning}>…), which can collide when identical
messages appear; update the map to include a stable unique key (e.g., use the
index or combine the message with the index) such as warnings.map((warning, i)
=> <li key={`${warning}-${i}`}>…) to guarantee uniqueness and avoid React key
collisions in the warnings render block.
apps/web/src/lib/subtitles/srt.ts (1)

27-30: Single-line blocks are silently skipped.

Blocks with only one line (e.g., just a cue index or just text) are counted as skipped. This is correct behavior, but the user won't know why these blocks were skipped since warnings is always empty for SRT files. Consider whether SRT parsing should also populate warnings for better user feedback.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/lib/subtitles/srt.ts` around lines 27 - 30, The parser currently
silently increments skippedCueCount when a block has lines.length < 2; update
the SRT parsing path (where lines and skippedCueCount are used) to also append a
descriptive warning to the warnings array explaining why the block was skipped
(include the offending block text or its cue index if available), so users
receive feedback for single-line blocks instead of silent skips.
apps/web/src/lib/subtitles/ass.ts (1)

302-316: Type assertion bypasses type safety.

The mapFieldsToRecord function uses as T which bypasses TypeScript's type checking. While this is acceptable for internal use with known field structures, the return type doesn't guarantee all required properties exist.

This is a common pattern for dynamic field mapping and is acceptable here since the caller validates required fields (e.g., if (!record.name) at line 141). No change needed, but documenting the assumption would help maintainability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/lib/subtitles/ass.ts` around lines 302 - 316, The function
mapFieldsToRecord currently returns a forced type (record as T) which bypasses
TypeScript safety; add a short inline comment above mapFieldsToRecord
documenting the assumption that callers validate required fields (e.g., checks
like if (!record.name) used elsewhere) and that the function intentionally
returns a partial record of string|undefined for dynamic ASS field mapping, or
alternatively change the return type to
Partial<Record<string,string|undefined>>/Record<string,string|undefined> and
keep callers validating required properties (refer to mapFieldsToRecord and its
callers that perform checks such as the name existence check).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/web/src/components/editor/panels/assets/views/captions.tsx`:
- Around line 97-106: Update insertCaptionChunks to accept an optional
errorMessage string and use that when throwing the Error if
insertCaptionChunksAsTextTrack returns no trackId (change signature of
insertCaptionChunks to ({ captions, errorMessage }:{ captions: CaptionChunk[];
errorMessage?: string })). Replace the current generic throw new Error("No
captions were generated") with throw new Error(errorMessage ?? "No captions were
generated") and update callers (e.g., handleImportFile) to pass a contextual
message like "Failed to insert imported subtitles" when the failure is in the
import flow.
- Around line 275-283: The list uses the warning string as the React key in
warnings.map((warning) => <li key={warning}>…), which can collide when identical
messages appear; update the map to include a stable unique key (e.g., use the
index or combine the message with the index) such as warnings.map((warning, i)
=> <li key={`${warning}-${i}`}>…) to guarantee uniqueness and avoid React key
collisions in the warnings render block.

In `@apps/web/src/lib/subtitles/ass.ts`:
- Around line 302-316: The function mapFieldsToRecord currently returns a forced
type (record as T) which bypasses TypeScript safety; add a short inline comment
above mapFieldsToRecord documenting the assumption that callers validate
required fields (e.g., checks like if (!record.name) used elsewhere) and that
the function intentionally returns a partial record of string|undefined for
dynamic ASS field mapping, or alternatively change the return type to
Partial<Record<string,string|undefined>>/Record<string,string|undefined> and
keep callers validating required properties (refer to mapFieldsToRecord and its
callers that perform checks such as the name existence check).

In `@apps/web/src/lib/subtitles/srt.ts`:
- Around line 27-30: The parser currently silently increments skippedCueCount
when a block has lines.length < 2; update the SRT parsing path (where lines and
skippedCueCount are used) to also append a descriptive warning to the warnings
array explaining why the block was skipped (include the offending block text or
its cue index if available), so users receive feedback for single-line blocks
instead of silent skips.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2e66d122-4f29-4a02-9533-87a3a52f4950

📥 Commits

Reviewing files that changed from the base of the PR and between 38b3afc and bdfe172.

📒 Files selected for processing (7)
  • apps/web/src/components/editor/panels/assets/views/captions.tsx
  • apps/web/src/lib/subtitles/ass.ts
  • apps/web/src/lib/subtitles/build-subtitle-text-element.ts
  • apps/web/src/lib/subtitles/insert.ts
  • apps/web/src/lib/subtitles/parse.ts
  • apps/web/src/lib/subtitles/srt.ts
  • apps/web/src/lib/subtitles/types.ts
✅ Files skipped from review due to trivial changes (1)
  • apps/web/src/lib/subtitles/types.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/src/lib/subtitles/insert.ts

# Conflicts:
#	apps/web/src/components/editor/panels/assets/views/captions.tsx
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/web/src/components/editor/panels/assets/views/captions.tsx (1)

86-90: Avoid console.error in these client-side failure paths.

These handlers already surface the error through component state, so shipping raw console logging here just adds noisy browser output. If diagnostics are needed, please send them through the app’s logger/telemetry path instead.

As per coding guidelines, "Don't use console".

Also applies to: 143-147

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/editor/panels/assets/views/captions.tsx` around lines
86 - 90, Remove the console.error call in the catch block and route the error
through the app's telemetry/logger instead while keeping the existing
setError(state) behavior; specifically, in the catch in captions.tsx that
currently does console.error("Transcription failed:", error) replace that call
with the app logging API your app uses (e.g. appLogger.error or
telemetry.trackError) and include the same context string plus the error object,
and make the same replacement for the similar catch block around lines 143–147
so all client-side failures use the centralized logger rather than console.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/src/components/editor/panels/assets/views/captions.tsx`:
- Around line 39-45: The shared transient UI state (isProcessing,
processingStep, error, warnings) currently spans both CaptionsView tabs causing
bleed when switching views; change these to be scoped per-tab (e.g., maintain a
map keyed by view or separate state objects like generateState/importState) and
update usages in handlers (where setIsProcessing, setProcessingStep, setError,
setWarnings are called) to read/write the state for the active view (use
view/setView to choose key), or alternatively disable/lock tab switching while
any of those flags for the active workflow are true; update any other instances
noted around lines 185-193 to follow the same per-tab pattern.
- Around line 197-200: Add unit and integration tests that cover ASS and SRT
parsing and the subtitle import/export flow before enabling those formats in the
UI: write tests exercising parseAss (in apps/web/src/lib/subtitles/ass.ts) and
the SRT parser (parseSrt or equivalent), including valid files, malformed
inputs, edge cases (overlapping timestamps, no events, non-UTF8/encoding), and
error paths, then add integration tests that simulate the file input flow used
by the component (the handler invoked via fileInputRef/File input in
captions.tsx) to assert correct parsing, validation, and round‑trip export
behavior; use the existing test framework (Jest/Testing Library) and assert both
successful parsed output shapes and that failures produce the expected
errors/validation results.

---

Nitpick comments:
In `@apps/web/src/components/editor/panels/assets/views/captions.tsx`:
- Around line 86-90: Remove the console.error call in the catch block and route
the error through the app's telemetry/logger instead while keeping the existing
setError(state) behavior; specifically, in the catch in captions.tsx that
currently does console.error("Transcription failed:", error) replace that call
with the app logging API your app uses (e.g. appLogger.error or
telemetry.trackError) and include the same context string plus the error object,
and make the same replacement for the similar catch block around lines 143–147
so all client-side failures use the centralized logger rather than console.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e3101364-70aa-44b5-82ed-2e260d8c6134

📥 Commits

Reviewing files that changed from the base of the PR and between bdfe172 and fa82d61.

📒 Files selected for processing (1)
  • apps/web/src/components/editor/panels/assets/views/captions.tsx

Comment thread apps/web/src/components/editor/panels/assets/views/captions.tsx Outdated
Comment on lines +197 to +200
<input
ref={fileInputRef}
type="file"
accept=".srt,.ass"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== ASS parser/import references ==="
rg -n -C2 '\bparseAss\b|\.ass\b' apps/web/src

echo
echo "=== Tests covering subtitle parsing/import ==="
fd -i 'test|spec' apps/web/src | xargs -r rg -n -C2 '\bparseAss\b|parseSubtitleFile|\.ass\b|\.srt\b'

Repository: OpenCut-app/OpenCut

Length of output: 2130


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Checking for test files in the repo ==="
fd -i 'test|spec' apps/web/src --type f | head -20

echo
echo "=== Full ASS parser implementation ==="
sed -n '61,120p' apps/web/src/lib/subtitles/ass.ts

echo
echo "=== Check for TODO/FIXME markers in subtitle code ==="
rg -n 'TODO|FIXME|XXX|WIP' apps/web/src/lib/subtitles/ || echo "No markers found"

echo
echo "=== Check if ASS support is explicitly mentioned as incomplete ==="
rg -n 'ass|ASS' apps/web/src/lib/subtitles/ | grep -i 'todo\|fixme\|wip\|incomplete\|phase' || echo "No phase/incomplete markers"

Repository: OpenCut-app/OpenCut

Length of output: 3069


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check git log for ASS-related commits ==="
git log --oneline --all --grep='ass\|subtitle' -i | head -20

echo
echo "=== Check if there's a test file specifically for subtitles ==="
fd -type f subtitle apps/web/src

echo
echo "=== Check the full parseSubtitleFile function that routes to parseAss ==="
sed -n '1,30p' apps/web/src/lib/subtitles/parse.ts

echo
echo "=== Check if ASS type/format detection is defined ==="
rg -n 'type.*[Aa]ss|format.*[Aa]ss' apps/web/src/lib/subtitles/

echo
echo "=== Verify parseAss is being exported and used ==="
rg -n 'parseAss' apps/web/src --type ts --type tsx

Repository: OpenCut-app/OpenCut

Length of output: 1340


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Search for subtitle-related test files ==="
find apps/web/src -path '*subtitles*' -o -path '*caption*' | grep -i test || echo "No subtitle tests found"

echo
echo "=== Check when ASS parsing was added to the codebase ==="
git log --all --oneline -- apps/web/src/lib/subtitles/ass.ts | head -5

echo
echo "=== Check the full captions.tsx file context around lines 197-200 and 256-258 ==="
sed -n '190,210p' apps/web/src/components/editor/panels/assets/views/captions.tsx
sed -n '250,260p' apps/web/src/components/editor/panels/assets/views/captions.tsx

echo
echo "=== Check if this is a new file or modified in current changes ==="
git diff HEAD~1 apps/web/src/lib/subtitles/ass.ts 2>/dev/null | head -50 || echo "File not recently changed or no git history available"

Repository: OpenCut-app/OpenCut

Length of output: 1320


Add test coverage for ASS subtitle parsing before exposing it to users.

ASS parsing is fully implemented (parseAss in apps/web/src/lib/subtitles/ass.ts), but there are no tests for ASS parsing, or SRT parsing, or subtitle import/export at all. Exposing an untested code path creates risk: validation logic, edge cases, and error handling may not work as expected. Add tests covering both SRT and ASS formats before accepting these formats in the UI.

Also applies to: 256-258

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/editor/panels/assets/views/captions.tsx` around lines
197 - 200, Add unit and integration tests that cover ASS and SRT parsing and the
subtitle import/export flow before enabling those formats in the UI: write tests
exercising parseAss (in apps/web/src/lib/subtitles/ass.ts) and the SRT parser
(parseSrt or equivalent), including valid files, malformed inputs, edge cases
(overlapping timestamps, no events, non-UTF8/encoding), and error paths, then
add integration tests that simulate the file input flow used by the component
(the handler invoked via fileInputRef/File input in captions.tsx) to assert
correct parsing, validation, and round‑trip export behavior; use the existing
test framework (Jest/Testing Library) and assert both successful parsed output
shapes and that failures produce the expected errors/validation results.

@kcfancher
Copy link
Copy Markdown
Contributor Author

I've fixed the latest merge conflicts and added preliminary support for the .ass file format. As the OpenCut editor does not yet support all the styles allowed in .ass I've presented a warning to the user of style cues that were skipped during import.

@mazeincoding mazeincoding merged commit e3d4f3f into OpenCut-app:main Apr 14, 2026
0 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants