@byomakase/omakase-ttconv-ts

中文文档
1.2.0发布于 2026/11/02BSD-2-ClauseTypeScriptESM + CJS近 30 天下载 9165

TypeScript subtitle conversion library (SCC, STL, SRT, VTT, TTML, ASS, SSA → VTT, IMSC, SRT)

原始使用文档
文档目录24 节
  1. Installation
  2. Quick Start
  3. Universal convert function
  4. Universal parse function
  5. Universal concatenate function
  6. Format-specific convenience functions (async)
  7. Two-step conversion (reader → writer)
  8. Readers
  9. SCC (CTA-608 Closed Captions)
  10. STL (EBU STL binary)
  11. SRT
  12. VTT (WebVTT)
  13. TTML / IMSC
  14. ASS / SSA
  15. Writers
  16. SRT
  17. VTT (WebVTT)
  18. IMSC / TTML
  19. Progress Callbacks
  20. Browser Bundle
  21. Working with the Document Model
  22. Fraction
  23. Style properties
  24. License

ttconv

TypeScript subtitle conversion library. Converts between SCC, STL, SRT, VTT, TTML/IMSC, and ASS/SSA formats.

Installation

npm install omakase-ttconv-ts

Quick 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' | 'ass' | 'ssa'

Supported output formats: 'srt' | 'vtt' | 'ttml'

input is string for all text formats and Buffer for 'stl'.


Universal parse function

Parses any supported input format into a simplified, format-agnostic ParsedFile — a flat list of cues plus any document-level metadata — instead of the full ContentDocument model. Throws if the reader recorded any spec-conformance errors.

import { parse } from 'omakase-ttconv-ts';
import type { ParsedFile } from 'omakase-ttconv-ts';
import { readFileSync } from 'fs';

const vttContent = readFileSync('captions.vtt', 'utf8');
const parsedFile: ParsedFile = parse(vttContent, 'vtt');

console.log(parsedFile.valid);   // true if no parse errors were recorded
console.log(parsedFile.cues);    // ParsedCue[]: { id, start, end, text }
console.log(parsedFile.meta);    // string[] | undefined — VTT-only: WEBVTT header text / X-TIMESTAMP-MAP
console.log(parsedFile.notes);   // string[] | undefined — VTT-only: NOTE block bodies

// throws if the source had any recorded parse errors
try {
  parse('not a valid VTT file', 'vtt');
} catch (e) {
  console.error(e); // "Errors found while parsing file: ..."
}

ParsedCue.start/.end are number | undefined — a cue whose begin/end couldn't be resolved from the source (e.g. a TTML <p> that inherits timing from an ancestor instead of specifying it directly, or a pop-on SCC caption with no closing/clear command) is left undefined rather than defaulted; apply any fallback (e.g. clamping to 0 or to the document's overall duration) on your own side if you need one.

meta/notes are currently populated only by the VTT reader (WEBVTT header text, including the HLS X-TIMESTAMP-MAP extension, and NOTE blocks respectively) — every other format leaves them undefined. Each is deduped by exact text and kept in order of first appearance, so parsing several concatenated VTT segments that repeat the same header/notes collapses them to one entry each.

parse is a thin composition of two lower-level functions, also exported individually:

import { toModel, toParsedFile } from 'omakase-ttconv-ts';

const doc = toModel(vttContent, 'vtt');   // same as vttToModel, dispatched by format
const parsedFile = toParsedFile(doc);     // ContentDocument -> ParsedFile, doesn't throw

Use toModel/toParsedFile directly instead of parse when you want to inspect doc.getErrors() yourself (e.g. to log parse problems without aborting), or to convert an already-parsed ContentDocument (from any reader, or one you built by hand) into a ParsedFile.

Universal concatenate function

Merges multiple same-format inputs (raw text) into a single output string of that same format — parsing each one, appending their content into a single document, and writing it back out once. Only supports the three round-trippable output formats ('srt' | 'vtt' | 'ttml'); the reader and writer for a given call always match.

import { concatenate } from 'omakase-ttconv-ts';
import { readFileSync } from 'fs';

const segments = ['segment1.vtt', 'segment2.vtt', 'segment3.vtt']
  .map(f => readFileSync(f, 'utf8'));

const merged = concatenate(segments, 'vtt');
  • A single input is returned verbatim — it isn't parsed or re-serialized at all.
  • An empty array returns undefined.
  • readerConfig/writerConfig are forwarded to every input's parse and the final write respectively.
  • For VTT specifically, repeated header metadata / NOTE / REGION blocks across the concatenated segments are deduped automatically (see parse above) — this is the intended way to reassemble a subtitle file that arrived split into HLS-style segments, since each chunk typically repeats the same WEBVTT header.
  • If a non-first input fails to parse cleanly, concatenate throws; a failure in the first input is logged (via console.error) but doesn't abort — its (possibly empty) document is still used as the base the other inputs get merged into.

concatenate is built on the same toModel/fromModel functions parse uses on the reader side:

import { toModel, fromModel } from 'omakase-ttconv-ts';

const doc = toModel(vttContent, 'vtt');
const vttOut = fromModel(doc, 'vtt');   // same as vttFromModel, dispatched by format

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);

ASS / SSA

import { assToModel } from 'omakase-ttconv-ts'; // ssaToModel is the same function

const doc = assToModel(assContent);

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. See THIRD_PARTY_NOTICES.md for third-party attributions.

版本与发布记录

@byomakase/omakase-ttconv-ts 共发布 13 个版本,首次发布于 2026/05/21;过去 12 个月发布了 13 个版本。

版本发布日期距今
1.2.0latest2026/11/026 天前
1.2.0-SNAPSHOT.1792067064snapshot2026/10/1524 天前
1.2.0-SNAPSHOT.17906074442026/09/281 个月前
1.2.0-SNAPSHOT.17901525042026/09/231 个月前
1.1.02026/09/171 个月前
1.1.0-SNAPSHOT.17895921702026/09/171 个月前

关于 @byomakase/omakase-ttconv-ts 的常见问题

@byomakase/omakase-ttconv-ts 是什么?

TypeScript subtitle conversion library (SCC, STL, SRT, VTT, TTML, ASS, SSA → VTT, IMSC, SRT)

如何安装 @byomakase/omakase-ttconv-ts?

在项目目录运行 npm install @byomakase/omakase-ttconv-ts,或使用 pnpm add / yarn add / bun add。

@byomakase/omakase-ttconv-ts 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@byomakase/omakase-ttconv-ts 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@byomakase/omakase-ttconv-ts 可以商用吗?

@byomakase/omakase-ttconv-ts 使用 BSD-2-Clause 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@byomakase/omakase-ttconv-ts 的下载量有多少?

根据 npm 官方下载统计,@byomakase/omakase-ttconv-ts 在 2026/10/09 – 2026/11/07 这 30 天内被下载 9,165 次,日均约 306 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@byomakase/omakase-ttconv-ts 还在维护吗?

最新版本 1.2.0 发布于 2026/11/02(6 天前);至今共发布 13 个版本,其中过去 12 个月发布了 13 个;首次发布于 2026/05/21。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。