dasha 3.0.1 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/dash.js CHANGED
@@ -56,16 +56,12 @@ const combineGetters = (representation, adaptationSet) => {
56
56
  };
57
57
 
58
58
  const parseBaseUrl = (manifestUrl, mpd, period, representation) => {
59
- let manifestBaseUrl = mpd.getBaseUrl();
60
- if (!manifestBaseUrl) manifestBaseUrl = manifestUrl;
61
- else if (!manifestBaseUrl.startsWith('https://'))
62
- manifestBaseUrl = new URL(manifestBaseUrl, manifestUrl).toString();
63
- const periodBaseUrl = new URL(period.getBaseUrl() || '', manifestBaseUrl).toString();
64
- const representationBaseUrl = new URL(
65
- representation.getBaseUrl() || '',
66
- periodBaseUrl
67
- ).toString();
68
- return representationBaseUrl;
59
+ let base = mpd.getBaseUrl();
60
+ if (!base) base = manifestUrl;
61
+ else if (!base.startsWith('https://')) base = new URL(base, manifestUrl).toString();
62
+ if (!!period.getBaseUrl() || !!base) base = new URL(period.getBaseUrl() || '', base).toString();
63
+ const baseUrl = new URL(representation.getBaseUrl() || '', base).toString();
64
+ return baseUrl;
69
65
  };
70
66
 
71
67
  const parseContentTypes = (representation) => {
@@ -236,35 +232,36 @@ const parseSegmentFromBase = async (segmentBase, baseUrl) => {
236
232
  return { url: baseUrl, range: mediaRange };
237
233
  };
238
234
 
235
+ const transformSegmentUrls = (segments) => {
236
+ for (const segment of segments) {
237
+ const hasHtmlEscapeCode = segment.url.includes('&');
238
+ if (hasHtmlEscapeCode) {
239
+ const url = new URL(segment.url);
240
+ const entries = new URLSearchParams(url.searchParams.toString()).entries();
241
+ for (const [key, value] of entries) {
242
+ url.searchParams.delete(key);
243
+ url.searchParams.append(key.replaceAll('amp;', ''), value);
244
+ }
245
+ segment.url = url.toString();
246
+ }
247
+ }
248
+ };
249
+
250
+ const protectionSchemas = {
251
+ 'urn:mpeg:dash:mp4protection:2011': 'common',
252
+ 'urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95': 'playready',
253
+ 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed': 'widevine',
254
+ };
255
+
239
256
  const parseContentProtection = (contentProtections) => {
240
257
  const protection = {};
241
- const commonId = 'urn:mpeg:dash:mp4protection:2011';
242
- const playreadyId = 'urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95';
243
- const widevineId = 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed';
244
258
  for (const contentProtection of contentProtections) {
245
259
  const id = contentProtection.get('schemeIdUri')?.toLowerCase();
246
- switch (id) {
247
- case commonId:
248
- protection.common = {
249
- id,
250
- value: contentProtection.get('value'),
251
- keyId: contentProtection.get('cenc:default_KID'),
252
- };
253
- continue;
254
- case playreadyId:
255
- protection.playready = {
256
- id,
257
- value: contentProtection.get('value'),
258
- pssh: contentProtection.get('cenc:pssh')?.get(),
259
- };
260
- continue;
261
- case widevineId:
262
- protection.widevine = {
263
- id,
264
- pssh: contentProtection.get('cenc:pssh')?.get(),
265
- };
266
- continue;
267
- }
260
+ const value = contentProtection.get('value');
261
+ const pssh = contentProtection.get('cenc:pssh')?.get();
262
+ const defaultKeyId = contentProtection.get('cenc:default_KID');
263
+ const data = { id, value, pssh, defaultKeyId };
264
+ protection[protectionSchemas[id]] = data;
268
265
  }
269
266
  return protection;
270
267
  };
@@ -312,6 +309,7 @@ const parseManifest = async (text, url, fallbackLanguage) => {
312
309
  } else {
313
310
  throw new Error('Could not find a way to get segments from this MPD manifest.');
314
311
  }
312
+ transformSegmentUrls(segments);
315
313
 
316
314
  const label = get('label');
317
315
  const fps = get('frameRate') ?? segmentBase?.attributes.timescale;
package/lib/track.js CHANGED
@@ -33,14 +33,18 @@ const createAudioLanguageFilter = (audios) => {
33
33
  if (!alreadyAdded) languages.push(audio.language);
34
34
  }
35
35
  }
36
- const results = [];
36
+ const filtered = [];
37
37
  for (const language of languages) {
38
38
  const tracks = audios.filter((track) => track.language?.startsWith(language));
39
- if (tracks.length > maxTracksPerLanguage) {
40
- results.push(...tracks.slice(0, maxTracksPerLanguage));
41
- } else {
42
- results.push(...tracks);
43
- }
39
+ filtered.push(...tracks);
40
+ }
41
+ const results = [];
42
+ const filteredLanguages = [...new Set(filtered.map((track) => track.language))];
43
+ for (const language of filteredLanguages) {
44
+ const tracks = filtered
45
+ .filter((track) => track.language === language)
46
+ .slice(0, maxTracksPerLanguage);
47
+ results.push(...tracks);
44
48
  }
45
49
  return results;
46
50
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dasha",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "author": "Vitaly Gashkov <vitalygashkov@vk.com>",
5
5
  "description": "Parser for MPEG-DASH & HLS manifests",
6
6
  "license": "AGPL-3.0",
package/types/dasha.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export function parse(text: string, url: string, fallbackLanguage?: string): Promise<Manifest>;
1
+ export function parse(text: string, url?: string, fallbackLanguage?: string): Promise<Manifest>;
2
2
 
3
3
  export interface Manifest {
4
4
  duration?: number;
@@ -50,9 +50,9 @@ export interface Segment {
50
50
  }
51
51
 
52
52
  export interface TrackProtection {
53
- common?: { id: string; value: 'cenc' | 'cbcs'; keyId?: string };
53
+ common?: { id: string; value: 'cenc' | 'cbcs'; defaultKeyId?: string };
54
54
  playready?: { id: string; pssh?: string; value?: string };
55
- widevine?: { id: string; pssh: string };
55
+ widevine?: { id: string; pssh: string; defaultKeyId?: string };
56
56
  fairplay?: { keyFormat: string; uri: string; method: string };
57
57
  }
58
58