diff --git a/lib/dash.js b/lib/dash.js index 1ac581f..1593a8c 100644 --- a/lib/dash.js +++ b/lib/dash.js @@ -135,11 +135,20 @@ const parseLanguage = (representation, adaptationSet, fallbackLanguage) => { return language; }; +const identifierPattern = /\$([A-z]*)(?:(%0)([0-9]+)d)?\$/g; +const identifierReplacement = + (values) => (match, identifier, format, width) => { + if (match === '$$') return '$'; + if (typeof values[identifier] === 'undefined') return match; + const value = '' + values[identifier]; + if (identifier === 'RepresentationID') return value; + if (!format) width = 1; + else width = parseInt(width, 10); + if (value.length >= width) return value; + return value.padStart(width, '0'); + }; const buildSegmentUrl = (template, fields) => { - let result = template; - for (const [key, value] of Object.entries(fields)) - result = result.replace('$' + key + '$', value); - return result; + return template.replace(identifierPattern, identifierReplacement(fields)); }; const resolveSegmentTemplateUrls = (segmentTemplate, baseUrl, manifestUrl) => { @@ -215,10 +224,6 @@ const parseSegmentsFromTemplate = ( : DEFAULT_SEGMENTS_COUNT; const bandwidth = representation.get('bandwidth'); const id = representation.get('id'); - - const sanitizeTemplate = (template) => - template?.replace(/\$.*?(RepresentationID|Number|Time).*?\$/g, '$$$1$$'); - const segments = []; if (segmentTimeline) { segments.push( @@ -230,9 +235,8 @@ const parseSegmentsFromTemplate = ( ), ); } else { - const template = sanitizeTemplate(segmentTemplate.get('media')); for (let i = startNumber; i < startNumber + segmentsCount; i++) { - const url = buildSegmentUrl(template, { + const url = buildSegmentUrl(segmentTemplate.get('media'), { Bandwidth: bandwidth, RepresentationID: id, Number: i, @@ -241,9 +245,7 @@ const parseSegmentsFromTemplate = ( segments.push({ url }); } } - const initialization = sanitizeTemplate( - segmentTemplate.get('initialization'), - ); + const initialization = segmentTemplate.get('initialization'); if (initialization) { const url = buildSegmentUrl(initialization, { Bandwidth: bandwidth, diff --git a/package-lock.json b/package-lock.json index f59ac2d..15fe5af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -553,10 +553,11 @@ } }, "node_modules/@eslint/js": { - "version": "9.15.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz", - "integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz", + "integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -1031,9 +1032,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.10.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz", - "integrity": "sha512-XC70cRZVElFHfIUB40FgZOBbgJYFKKMa5nb9lxcwYstFG/Mi+/Y0bGS+rs6Dmhmkpq4pnNiLiuZAbc02YCOnmA==", + "version": "22.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", + "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1366,9 +1367,9 @@ } }, "node_modules/eslint": { - "version": "9.15.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.15.0.tgz", - "integrity": "sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.16.0.tgz", + "integrity": "sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==", "dev": true, "license": "MIT", "dependencies": { @@ -1377,7 +1378,7 @@ "@eslint/config-array": "^0.19.0", "@eslint/core": "^0.9.0", "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.15.0", + "@eslint/js": "9.16.0", "@eslint/plugin-kit": "^0.2.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -1497,6 +1498,16 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/@eslint/js": { + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz", + "integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", @@ -1741,10 +1752,11 @@ } }, "node_modules/globals": { - "version": "15.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.12.0.tgz", - "integrity": "sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ==", + "version": "15.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.13.0.tgz", + "integrity": "sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, diff --git a/test/axinom.test.js b/test/axinom.test.js index b97bf3d..4e0892e 100644 --- a/test/axinom.test.js +++ b/test/axinom.test.js @@ -13,7 +13,7 @@ test('axinom manifest parsing', async () => { const firstVideoSegment = firstVideoTrack.segments[1]; // Skip init strictEqual( firstVideoSegment.url, - 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/5/1.m4s', + 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/5/0001.m4s', ); const firstSubtitleTrack = manifest.tracks.subtitles[0]; diff --git a/types/dasha.d.ts b/types/dasha.d.ts index b2132da..daac1c5 100644 --- a/types/dasha.d.ts +++ b/types/dasha.d.ts @@ -145,8 +145,7 @@ export type SubtitleCodec = | 'TTML' | 'VTT' | 'STPP' - | 'fTTML' - | 'fVTT'; + | 'WVTT'; export interface SubtitleTrack extends Track { type: 'text';