@byomakase/omakase-ttconv-ts
v1.0.0
Published
TypeScript subtitle conversion library (SCC, STL, SRT, VTT, TTML → VTT, IMSC, SRT)
Readme
ttconv
TypeScript subtitle conversion library. Converts between SCC, STL, SRT, VTT, and TTML/IMSC formats.
Installation
npm install omakase-ttconv-tsQuick Start
Universal convert function
The simplest API — pass input content, input format, and output format:
import { convert } from 'omakase-ttconv-ts';
import type { ConvertConfig } from 'omakase-ttconv-ts';
import { readFileSync } from 'fs';
// SCC → VTT
const sccContent = readFileSync('captions.scc', 'utf8');
const vtt = convert(sccContent, 'scc', 'vtt');
// STL → SRT
const stlData = readFileSync('subtitles.stl'); // Buffer
const srt = convert(stlData, 'stl', 'srt');
// SRT → IMSC/TTML
const srtContent = readFileSync('captions.srt', 'utf8');
const ttml = convert(srtContent, 'srt', 'ttml');
// With reader/writer config and progress callback
const config: ConvertConfig = {
reader: { textAlign: 'center' }, // SccReaderConfiguration
writer: { textFormatting: false }, // SrtWriterConfig / VttWriterConfig / ImscWriterConfig
};
const result = convert(sccContent, 'scc', 'srt', config, (p) => console.log(`${Math.round(p * 100)}%`));Supported input formats: 'scc' | 'stl' | 'srt' | 'vtt' | 'ttml'
Supported output formats: 'srt' | 'vtt' | 'ttml'
input is string for all text formats and Buffer for 'stl'.
Format-specific convenience functions (async)
import { convertScc, convertStl } from 'omakase-ttconv-ts';
import { readFileSync } from 'fs';
// SCC → VTT
const sccContent = readFileSync('captions.scc', 'utf8');
const vtt = await convertScc(sccContent, 'vtt');
// SCC → SRT
const srt = await convertScc(sccContent, 'srt');
// SCC → IMSC/TTML
const ttml = await convertScc(sccContent, 'imsc');
// STL → VTT
const stlData = readFileSync('subtitles.stl');
const vttFromStl = await convertStl(stlData, 'vtt');Two-step conversion (reader → writer)
Use this approach to apply configuration or perform multiple conversions from the same parsed document.
import { sccToModel, srtFromModel, vttFromModel, imscFromModel } from 'omakase-ttconv-ts';
import { readFileSync } from 'fs';
const sccContent = readFileSync('captions.scc', 'utf8');
const doc = sccToModel(sccContent);
const srt = srtFromModel(doc);
const vtt = vttFromModel(doc);
const ttml = imscFromModel(doc);Readers
SCC (CTA-608 Closed Captions)
import { sccToModel } from 'omakase-ttconv-ts';
import type { SccReaderConfiguration } from 'omakase-ttconv-ts';
const config: SccReaderConfiguration = {
textAlign: 'auto', // 'auto' | 'left' | 'center' | 'right'
};
const doc = sccToModel(sccContent, config);STL (EBU STL binary)
import { stlToModel } from 'omakase-ttconv-ts';
import { readFileSync } from 'fs';
const stlData = readFileSync('subtitles.stl'); // Buffer
const doc = stlToModel(stlData);SRT
import { srtToModel } from 'omakase-ttconv-ts';
const doc = srtToModel(srtContent);Supports inline HTML tags: <b>, <i>, <u>, <font color="...">.
VTT (WebVTT)
import { vttToModel } from 'omakase-ttconv-ts';
const doc = vttToModel(vttContent);TTML / IMSC
import { ttmlToModel } from 'omakase-ttconv-ts';
const doc = ttmlToModel(ttmlContent);Writers
SRT
import { srtFromModel } from 'omakase-ttconv-ts';
import type { SrtWriterConfig } from 'omakase-ttconv-ts';
const config: SrtWriterConfig = {
textFormatting: true, // default true; set false to strip all HTML tags
};
const srt = srtFromModel(doc, config);VTT (WebVTT)
import { vttFromModel } from 'omakase-ttconv-ts';
import type { VttWriterConfig } from 'omakase-ttconv-ts';
const config: VttWriterConfig = {
styleRegion: false, // default false; set true to emit VTT region/line position cues
};
const vtt = vttFromModel(doc, config);IMSC / TTML
import { imscFromModel } from 'omakase-ttconv-ts';
import type { ImscWriterConfig } from 'omakase-ttconv-ts';
import { Fraction } from 'omakase-ttconv-ts';
const config: ImscWriterConfig = {
frameRate: new Fraction(30), // output frame rate
timeExpressionSyntax: 'clock_time', // 'clock_time' | 'frames' | 'clock_time_with_frames'
contentProfilesSignaling: 'content_profiles', // 'none' | 'content_profiles'
};
const ttml = imscFromModel(doc, config);Progress Callbacks
All writers accept an optional progress callback as the third argument:
const srt = srtFromModel(doc, {}, (progress) => {
console.log(`${Math.round(progress * 100)}%`);
});Browser Bundle
A pre-built IIFE bundle is available at dist/ttconv.browser.js. It exposes the global ttconvModule:
<script src="ttconv.browser.js"></script>
<script>
const doc = ttconvModule.sccToModel(sccContent);
const vtt = ttconvModule.vttFromModel(doc);
</script>Working with the Document Model
Readers return a ContentDocument and writers consume one. You can also build or inspect a document directly using the model classes.
import {
ContentDocument, Body, Div, P, Span, Text, Region, Fraction,
StyleProperties, FontStyleType, FontWeightType, makeColor, LengthUnits, makeLengthType
} from 'omakase-ttconv-ts';
// Build a document from scratch
const doc = new ContentDocument();
doc.setLang('en');
const region = new Region('r1');
region.setStyle(StyleProperties.Origin, {
x: makeLengthType(10, LengthUnits.pct),
y: makeLengthType(85, LengthUnits.pct),
});
region.setStyle(StyleProperties.Extent, {
width: makeLengthType(80, LengthUnits.pct),
height: makeLengthType(10, LengthUnits.pct),
});
doc.putRegion(region);
const body = new Body(doc);
doc.setBody(body);
const div = new Div(doc);
body.pushChild(div);
const p = new P(doc);
p.setRegion(region);
p.setBegin(new Fraction(0)); // seconds as rational number
p.setEnd(new Fraction(5, 2)); // 2.5 seconds
div.pushChild(p);
const span = new Span(doc);
span.setStyle(StyleProperties.FontStyle, FontStyleType.italic);
span.setStyle(StyleProperties.Color, makeColor(255, 255, 255)); // white
span.pushChild(new Text(doc, 'Hello, world!'));
p.pushChild(span);
const srt = srtFromModel(doc);Fraction
Fraction represents an exact rational time value (numerator/denominator in seconds).
import { Fraction } from 'omakase-ttconv-ts';
const t = new Fraction(1001, 30000); // 1001/30000 seconds
const t2 = new Fraction(5); // 5 seconds
console.log(t.toNumber()); // 0.033366...
console.log(t2.toNumber()); // 5
const sum = t.add(t2);Style properties
import {
StyleProperties,
FontStyleType, // normal | italic | oblique
FontWeightType, // normal | bold
TextAlignType, // left | center | right | start | end | justify
DisplayAlignType, // before | center | after
NamedColors, // white, black, red, green, blue, cyan, magenta, yellow, transparent
makeColor, // makeColor(r, g, b, a?) → ColorType
} from 'omakase-ttconv-ts';License
BSD-2-Clause
