@awesome-fe/translate
Version:
Translation utils
146 lines • 5.86 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.subtitle = void 0;
var subtitle;
(function (subtitle_1) {
let SubtitleFormat;
(function (SubtitleFormat) {
SubtitleFormat["AUTO"] = "auto";
SubtitleFormat["SRT"] = "srt";
SubtitleFormat["VTT"] = "vtt";
})(SubtitleFormat = subtitle_1.SubtitleFormat || (subtitle_1.SubtitleFormat = {}));
function parse(text, format = SubtitleFormat.AUTO) {
if (format === SubtitleFormat.AUTO) {
return parse(text, detectFormat(text));
}
else if (format === SubtitleFormat.SRT || format === SubtitleFormat.VTT) {
const { meta, items } = partition(text, format);
return {
meta,
items: items.map((segment) => {
const lines = segment.split(/\r?\n/);
const timeIndex = lines.findIndex((line) => /\d\d:\d\d:\d\d[,.]\d\d\d --> \d\d:\d\d:\d\d[,.]\d\d\d/.test(line));
const time = lines[timeIndex].split(' --> ');
return {
cue: lines[timeIndex - 1] ?? '',
startTime: parseTime(time[0]),
endTime: parseTime(time[1]),
text: unescapeSubtitle(lines.slice(timeIndex + 1).join('\n').trim(), format),
};
}),
};
}
}
subtitle_1.parse = parse;
function stringify(subtitle, format = SubtitleFormat.AUTO) {
if (format === SubtitleFormat.AUTO) {
return stringify(subtitle, subtitle.meta.format);
}
else if (format === SubtitleFormat.SRT) {
return subtitle.items.map((item, index) => {
return `${index + 1}
${formatTime(item.startTime, format)} --> ${formatTime(item.endTime, format)}
${escapeSubtitle(item.text, format)}`;
}).join('\n\n');
}
else if (format === SubtitleFormat.VTT) {
const meta = `${['WEBVTT', escapeSubtitle(subtitle.meta.header, SubtitleFormat.VTT)].filter(it => !!it).join(' - ')}
Kind: ${subtitle.meta.kind}
Language: ${subtitle.meta.language}`;
const body = subtitle.items.map((item, index) => {
return `${escapeSubtitle(item.cue ?? '', format)}
${formatTime(item.startTime, format)} --> ${formatTime(item.endTime, format)}
${escapeSubtitle(item.text, format)}`.trim();
});
return [meta, ...body].join('\n\n');
}
}
subtitle_1.stringify = stringify;
function detectFormat(text) {
if (text.startsWith('WEBVTT')) {
return SubtitleFormat.VTT;
}
else if (/\d\d:\d\d:\d\d,\d\d\d --> \d\d:\d\d:\d\d,\d\d\d/.test(text)) {
return SubtitleFormat.SRT;
}
else {
throw new Error('Unsupported subtitle format');
}
}
function parseVttMeta(text) {
const lines = text.split('\n');
const header = lines[0];
const kind = lines[1].split(':')[1].trim();
const language = lines[2].split(':')[1].trim();
return {
header: unescapeSubtitle(header.split('-')[1]?.trim() ?? '', SubtitleFormat.VTT),
format: SubtitleFormat.VTT,
kind,
language,
};
}
function partition(text, format) {
const segments = text.split(/\r?\n\r?\n/).filter(it => !!it);
if (format === SubtitleFormat.SRT) {
return {
meta: {
header: '',
format: SubtitleFormat.SRT,
kind: 'captions',
language: 'en',
},
items: segments,
};
}
else if (format === SubtitleFormat.VTT) {
return {
meta: parseVttMeta(segments[0]),
items: segments.slice(1),
};
}
}
function parseTime(string) {
const [hours, minutes, seconds, milliseconds] = string.split(/[:,.]/).map((s) => parseInt(s, 10));
return hours * 3600000 + minutes * 60000 + seconds * 1000 + milliseconds;
}
function escapeSubtitle(text, format) {
if (format === SubtitleFormat.SRT) {
return text.replace(/\xa0/g, '\\h');
}
else if (format === SubtitleFormat.VTT) {
return text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/\xa0/g, ' ');
}
}
function unescapeSubtitle(text, format) {
if (format === SubtitleFormat.SRT) {
return text.replace(/\\h/g, '\xa0').replace(/\\N/g, '\n');
}
else if (format === SubtitleFormat.VTT) {
return text
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/ /g, '\xa0')
.replace(/&/g, '&');
}
}
function pad(value, length) {
return value.toString().padStart(length, '0');
}
function formatTime(time, format) {
const hours = Math.floor(time / 3600000);
const minutes = Math.floor((time - hours * 3600000) / 60000);
const seconds = Math.floor((time - hours * 3600000 - minutes * 60000) / 1000);
const milliseconds = time - hours * 3600000 - minutes * 60000 - seconds * 1000;
if (format === SubtitleFormat.SRT) {
return `${pad(hours, 2)}:${pad(minutes, 2)}:${pad(seconds, 2)},${pad(milliseconds, 3)}`;
}
else if (format === SubtitleFormat.VTT) {
return `${pad(hours, 2)}:${pad(minutes, 2)}:${pad(seconds, 2)}.${pad(milliseconds, 3)}`;
}
}
})(subtitle = exports.subtitle || (exports.subtitle = {}));
//# sourceMappingURL=subtitle.js.map