Subtitles.Convert("in.srt", "out.vtt") converts a subtitle file and returns a ConversionReport of everything the target format dropped or approximated. The input format is read from the content, the output format from the extension; SRT, WebVTT, ASS/SSA, TTML/DFXP, SBV and LRC all work the same way. Subtitles are a preview in 0.4.0-preview.1.
dotnet new console -o SrtToVtt && cd SrtToVtt dotnet add package RecursiveAI.OneMedia --version 0.4.0-preview.1 cat > styled.srt <<'EOF' 1 00:00:00,500 --> 00:00:02,000 <i>A flower opens.</i> 2 00:00:02,200 --> 00:00:03,600 <font color="#ff8000">Orange</font> and <b>bold</b> 3 00:00:03,800 --> 00:00:05,000 {\an8}<s>Struck</s> in <font face="Georgia" size="28">Georgia</font>, at the top EOF
styled.srt uses the styling SRT allows: italics, a colour, bold, strike-through, a font, and {\an8} to place a cue at the top. Put this in Program.cs and run dotnet run:
using RecursiveAI.OneMedia; using RecursiveAI.OneMedia.Captions; // The format is read from the content and the target from the extension. ConversionReport report = Subtitles.Convert("styled.srt", "styled.vtt"); Console.WriteLine($"{report.Source} to {report.Target}: " + (report.IsLossless ? "nothing lost" : $"{report.Losses.Count} loss(es)")); foreach (ConversionLoss loss in report.Losses) Console.WriteLine($" cue {loss.CueIndex}: {loss.Kind} {loss.Feature}: {loss.Message}"); Console.WriteLine(); Console.Write(File.ReadAllText("styled.vtt"));
srt to webvtt: 4 loss(es) cue 2: Dropped Strike: Strike-through is not carried by webvtt. cue 2: Dropped Font: Font family and size are not carried by webvtt. cue 1: Approximated Color: Colour mapped to the nearest WebVTT default colour class 'yellow'. cue 2: Approximated Alignment: Top alignment written as line 0. WEBVTT 00:00:00.500 --> 00:00:02.000 <i>A flower opens.</i> 00:00:02.200 --> 00:00:03.600 <c.yellow>Orange</c> and <b>bold</b> 00:00:03.800 --> 00:00:05.000 line:0,start align:center Struck in Georgia, at the top
Italics and bold carry over as they are. WebVTT has no strike-through and no fonts, so those are dropped and reported. Its colours are eight named classes, so the orange becomes the nearest one, yellow; the top placement becomes line:0,start. Cue indexes count from 0. report.IsLossless is true when nothing was dropped or approximated, as for a plain SRT file.
Checked in Chrome
The VTT file was loaded as a <track> on MDN’s CC0 flower clip in headless Chrome 149, and the cues read back through the TextTrack API:
start end line align text 0.5 2 auto center <i>A flower opens.</i> 2.2 3.6 auto center <c.yellow>Orange</c> and <b>bold</b> 3.8 5 auto center Struck in Georgia, at the top
Chrome reads all three cues with their times and text. It ignores the line:0,start setting, though: Chrome 149 drops a line setting with an alignment part (line:0 alone is read as 0), so the third cue shows at the bottom in Chrome, not at the top. We have reported it to the OneMedia team. The project loaded its WebVTT output in Chromium 140, Firefox 141 and WebKit 26 and compared the cues read back.
From the command line
onemedia subs styled.srt --to styled.vtt --report converts the file and lists every loss; --offset 1.5 shifts all times by 1.5 s.
Limits
- A preview. The README: “Not yet at the speed bar: subtitle parse and convert are not published against SubtitlesParser or Subtitle Edit’s library, and tuning is in progress, so no speed claim is made.” The API may change before 1.0.
- What each format holds is in the fidelity table on the subtitles page: ASS and LRC times are rounded to 10 ms, LRC has no end times, SBV is plain text. The report lists every case.
- Encodings. A file with a byte order mark, or valid UTF-8, is read as such; otherwise as windows-1252 unless you pass an encoding (
onemedia subs … --encoding), with a note in the defects. WebVTT is always written as UTF-8. - Times are not shifted unless you ask:
SubtitleAlignment.Shift(document, offset)moves every cue.