Files
v10/dist/dev/media/text/parse-vtt-timestamp-map.js
T

42 lines
1.7 KiB
JavaScript

//#region src/media/text/parse-vtt-timestamp-map.ts
const TIMESTAMP_MAP_PREFIX = "X-TIMESTAMP-MAP=";
/**
* Scrape a WebVTT segment's `X-TIMESTAMP-MAP` header into a {@link TimestampMap}
* — the only header line we need to correlate LOCAL cue times with the media
* presentation timeline. Deliberately *not* a WebVTT parser: cue parsing stays
* with the browser's native `<track>` parser (which drops this line); this reads
* just the one header field the native path discards.
*
* Returns `undefined` when the segment carries no map (e.g. cues already in
* absolute presentation time) — per the HLS spec that means LOCAL 0 maps to
* MPEGTS 0. Tolerant of attribute order and `[HH:]MM:SS.mmm` LOCAL forms.
*/
function parseVttTimestampMap(text) {
const timestampMapLine = text.split(/\r\n|\r|\n/).find((line) => line.startsWith(TIMESTAMP_MAP_PREFIX));
return timestampMapLine ? parseTimestampMapBody(timestampMapLine.slice(16)) : void 0;
}
const TimeStampMapParserMap = {
LOCAL: parseWebVttTimestamp,
MPEGTS: (v) => +v
};
function parseTimestampMapBody(body) {
return Object.fromEntries(body.split(",").map((kvStr) => {
const [k, v] = kvStr.split(/:(.*)/).map((kOrV) => kOrV.trim());
return [k?.toLowerCase(), TimeStampMapParserMap[k](v)];
}));
}
/** Seconds-per-unit for the `[HH:]MM:SS.mmm` parts, right-aligned so a missing HH just drops the leading weight. */
const VTT_TIMESTAMP_WEIGHTS = [
3600,
60,
1,
.001
];
function parseWebVttTimestamp(value) {
const parts = value.split(/[:.]/);
return parts.reduce((acc, val, i) => acc + +val * (VTT_TIMESTAMP_WEIGHTS[i + 4 - parts.length] ?? 0), 0);
}
//#endregion
export { parseVttTimestampMap };
//# sourceMappingURL=parse-vtt-timestamp-map.js.map