subsrt-ts
Version:
Subtitle JavaScript library and command line tool with no dependencies.
84 lines (83 loc) • 3.17 kB
JavaScript
import { buildHandler } from "../handler.js";
const FORMAT_NAME = "sub";
const DEFAULT_FPS = 25;
/**
* Parses captions in MicroDVD format.
* @param content The subtitle content
* @param options Parse options
* @returns Parsed captions
* @see https://en.wikipedia.org/wiki/MicroDVD
*/
const parse = (content, options) => {
var _a;
options.fps || (options.fps = DEFAULT_FPS);
const fps = options.fps > 0 ? options.fps : DEFAULT_FPS;
const captions = [];
const eol = (_a = options.eol) !== null && _a !== void 0 ? _a : "\r\n";
const parts = content.split(/\r?\n/);
for (let i = 0; i < parts.length; i++) {
const regex = /^\{(\d+)\}\{(\d+)\}(.*)$/;
const match = regex.exec(parts[i]);
if (match) {
const caption = {};
caption.type = "caption";
caption.index = i + 1;
caption.frame = {
start: parseInt(match[1], 10),
end: parseInt(match[2], 10),
count: parseInt(match[2]) - parseInt(match[1], 10),
};
caption.start = Math.round(caption.frame.start / fps);
caption.end = Math.round(caption.frame.end / fps);
caption.duration = caption.end - caption.start;
const lines = match[3].split(/\|/);
caption.content = lines.join(eol);
caption.text = caption.content.replace(/\{[^}]+\}/g, ""); // {0}{25}{c:$0000ff}{y:b,u}{f:DeJaVuSans}{s:12}Hello!
captions.push(caption);
continue;
}
if (options.verbose) {
console.warn("Unknown part", parts[i]);
}
}
return captions;
};
/**
* Builds captions in MicroDVD format.
* @param captions The captions to build
* @param options Build options
* @returns The built captions string in MicroDVD format
* @see https://en.wikipedia.org/wiki/MicroDVD
*/
const build = (captions, options) => {
var _a, _b;
const fps = ((_a = options.fps) !== null && _a !== void 0 ? _a : 0) > 0 ? options.fps : DEFAULT_FPS;
let sub = "";
const eol = (_b = options.eol) !== null && _b !== void 0 ? _b : "\r\n";
for (const caption of captions) {
if (!caption.type || caption.type === "caption") {
const startFrame = typeof caption.frame === "object" && caption.frame.start >= 0 ? caption.frame.start : caption.start * fps;
const endFrame = typeof caption.frame === "object" && caption.frame.end >= 0 ? caption.frame.end : caption.end * fps;
const text = caption.text.replace(/\r?\n/, "|");
sub += `{${startFrame}}{${endFrame}}${text}${eol}`;
continue;
}
if (options.verbose) {
console.log("SKIP:", caption);
}
}
return sub;
};
/**
* Detects whether the content is in MicroDVD format.
* @param content The subtitle content
* @returns Whether it's MicroDVD format
*/
const detect = (content) => {
/*
{7207}{7262}Sister, perfume?
*/
return /^\{\d+\}\{\d+\}.*/.test(content);
};
export default buildHandler({ name: FORMAT_NAME, build, detect, parse });
export { FORMAT_NAME as name, build, detect, parse };