// Functions for parsing and creating a media fragment identifiers. // A media fragment is used to specify a time range of an audio/video track, e.g. #t=12,18.5. // See https://www.w3.org/TR/media-frags/ // Creates a media fragment identifier for a given time range (in seconds). export function createMediaFragmentIdentifier({ start, end }) { // Always output the time in seconds, as it is more widely supported than h:m:s syntax. const maybeStart = start !== undefined ? start : ''; const maybeEnd = end !== undefined ? `,${end}` : ''; const fragmentIdentifier = `t=${maybeStart}${maybeEnd}`; return fragmentIdentifier; } // Parses the time range from a media fragment identifier. // Returns an object { start, end }; both numbers are given in seconds (possibly non-integer). // Note this only supports the usual npt (normal playing time) format, not smpte or wall clock time. export function parseMediaFragmentIdentifier(fragmentIdentifier) { // Strip possible leading hash character '#'. if (fragmentIdentifier.startsWith('#')) { fragmentIdentifier = fragmentIdentifier.substring(1); } const temporalDimensionRegex = /(?:^|&)(?:t|%74)=([^&]+)(?=&|$)/g; const temporalDimensionMatches = [...fragmentIdentifier.matchAll(temporalDimensionRegex)]; if (temporalDimensionMatches.length === 0) { throw new Error('No time dimension defined'); } // If there are multiple occurrences (e.g. t=1&t=2), take the last one. const temporalDimensionMatch = temporalDimensionMatches[temporalDimensionMatches.length - 1]; const temporalDimensionValue = decodeURIComponent(temporalDimensionMatch[1]); const nptRegex = /^(?:npt:)?(?:(?:(\d+):)??(?:(\d+):)?(\d+(?:\.\d*)?))?(?:,(?:(\d+):)??(?:(\d+):)?(\d+(?:\.\d*)?))?$/; const nptMatch = temporalDimensionValue.match(nptRegex); if (!nptMatch) { throw new Error('Unable to parse fragment identifier.'); } const start = (nptMatch[3] ? Number.parseFloat(nptMatch[3]) : 0) + (nptMatch[2] ? Number.parseInt(nptMatch[2]) * 60 : 0) + (nptMatch[1] ? Number.parseInt(nptMatch[1]) * 60 * 60 : 0); let end; if (nptMatch[6]) { end = Number.parseFloat(nptMatch[6]) + (nptMatch[5] ? Number.parseInt(nptMatch[5]) * 60 : 0) + (nptMatch[4] ? Number.parseInt(nptMatch[4]) * 60 * 60 : 0); } return { start, end }; }