subcue 0.1.1

Parse, compose, and convert SRT, WebVTT, and ASS/SSA subtitle files
Documentation
  • Coverage
  • 100%
    215 out of 215 items documented0 out of 10 items with examples
  • Size
  • Source code size: 334.0 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 2.2 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 2s Average build duration of successful builds.
  • all releases: 2s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • hey-jj/subcue
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • hey-jj

subcue

subcue parses, composes, and converts SRT, WebVTT, and ASS/SSA subtitle files. It accepts byte slices for complete files and BufRead values for cue iteration.

The data model keeps cue order, signed millisecond timestamps, raw cue text, and format metadata. Parsing accepts UTF-8. A UTF-8 byte order mark is removed with a warning. UTF-16 input and invalid UTF-8 return typed errors.

Parse and compose

use subcue::{parse_srt, Time};

let input = b"1\n00:00:01,000 --> 00:00:02,500\nHello\n\n";
let subtitles = parse_srt(input)?;

assert_eq!(subtitles.cues.len(), 1);
assert_eq!(subtitles.cues[0].start, Time(1_000));
assert_eq!(subtitles.cues[0].text, "Hello");

let (bytes, warnings) = subtitles.compose();
assert_eq!(bytes, input);
assert!(warnings.is_empty());
# Ok::<(), subcue::Error>(())

compose_with can write CRLF line endings or add a UTF-8 byte order mark. Default composition writes LF line endings without a mark.

Convert formats

use subcue::{parse_srt, Format};

let input = b"1\n00:00:01,000 --> 00:00:02,000\n<i>Hello</i>\n\n";
let srt = parse_srt(input)?;
let vtt = srt.convert(Format::Vtt);
let (bytes, warnings) = vtt.compose();

assert!(bytes.starts_with(b"WEBVTT\n\n"));
assert!(warnings.is_empty());
# Ok::<(), subcue::Error>(())

Conversion keeps cue order and timing. ASS output truncates milliseconds to centiseconds and reports Warning::TimePrecisionLost. Settings, identifiers, blocks, events, and text tags that have no target representation produce a specific warning.

Every conversion reads the source tags into a text::Span tree and writes that tree in the target dialect. The text module is public, so a caller can parse or render inline formatting without converting a whole file.

use subcue::text::{parse, render, Span};
use subcue::Format;

let parsed = parse("<b>bold <i>both</i></b>", Format::Srt);
assert!(matches!(parsed.spans[0], Span::Bold(_)));
let ass = render(&parsed.spans, Format::Ass);
assert_eq!(ass.text, "{\\b1}bold {\\i1}both{\\i0}{\\b0}");

Iterate over cues

use std::io::Cursor;
use subcue::SrtCues;

let input = b"1\n00:00:01,000 --> 00:00:02,000\nFirst\n\n";
let mut cues = SrtCues::new(Cursor::new(input));
assert_eq!(cues.next().unwrap()?.text, "First");
assert!(cues.next().is_none());
# Ok::<(), subcue::Error>(())

VttCues reads the signature and header in its constructor. AssCues reads script and style metadata there. Each iterator keeps one line buffer and one text accumulator, allocates 1 time per cue for SRT, 3 for WebVTT, and 5 for ASS, and exposes its collected warnings. A failed read from the source is returned as Error::Io.

Errors and warnings

Fatal errors cover decoding failures, timestamp failures, a missing WebVTT signature, and content before an ASS section. Recoverable input stays in the model and adds a warning. Examples include mixed line endings, missing SRT indices, unknown ASS styles, and a cue that ends before it starts.

The library uses checked integer arithmetic for every timestamp calculation. All parser entry points return a result for arbitrary input bytes.

Toolchain and dependencies

The library has no runtime dependencies. It supports Rust 1.70.0 and edition 2021.

Relation to subparse

subcue is an independent implementation. It is not affiliated with subparse or its author. Both read SRT, WebVTT, and ASS/SSA files. subcue also composes each format, converts between the three, and streams cues from a reader.

License

MIT