dasha 2.1.0 → 2.2.2

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/manifest.js CHANGED
@@ -5,6 +5,14 @@ const { processManifest } = require('./processor');
5
5
  const { getQualityLabel } = require('./utils');
6
6
  const { CONTENT_TYPE, KEY_SYSTEMS } = require('./constants');
7
7
 
8
+ const isUrl = (value) => {
9
+ try {
10
+ return !!new URL(value);
11
+ } catch (e) {
12
+ return false;
13
+ }
14
+ };
15
+
8
16
  class Manifest {
9
17
  constructor(manifest) {
10
18
  for (const key of Object.keys(manifest)) this[key] = manifest[key];
@@ -21,10 +29,13 @@ class Manifest {
21
29
  .flat(1)
22
30
  .filter(isVideoAdaptationSet);
23
31
  const representations = adaptationSets.map((a) => a.representations).flat(2);
24
- const matches = representations.filter((r) => r.height === height);
32
+ const matchesInHeight = representations.filter((r) => r.height === height);
33
+ const matchesInId = representations.filter((r) => r.id.includes(height));
34
+ const matches = matchesInHeight?.length ? matchesInHeight : matchesInId;
25
35
  const representation = this.findBestRepresentation(matches.length ? matches : representations);
26
36
  const adaptationSet = adaptationSets.find((a) => a.representations.includes(representation));
27
37
  return {
38
+ id: 0,
28
39
  type: CONTENT_TYPE.video,
29
40
  pssh: this.getWidevinePssh(adaptationSet),
30
41
  licenseUrl: this.getWidevineLicenseUrl(adaptationSet),
@@ -33,16 +44,15 @@ class Manifest {
33
44
  size: Math.ceil((representation.bandwidth / 8e6) * this.mediaPresentationDuration), // MB
34
45
  width: representation.width,
35
46
  height: representation.height,
36
- quality: getQualityLabel(representation.height),
47
+ quality: getQualityLabel(representation.width),
37
48
  };
38
49
  }
39
50
 
40
51
  getAudioTracks(languages) {
41
52
  const isAudioAdaptationSet = (adaptationSet) =>
42
- adaptationSet.contentType === CONTENT_TYPE.audio ||
43
- adaptationSet.mimeType === 'audio/mp4' ||
44
- !adaptationSet.maxWidth ||
45
- !adaptationSet.maxHeight;
53
+ (adaptationSet.contentType === CONTENT_TYPE.audio ||
54
+ adaptationSet.mimeType === 'audio/mp4') &&
55
+ !adaptationSet.maxWidth;
46
56
  const adaptationSets = this.periods
47
57
  .map((p) => p.adaptationSets)
48
58
  .flat(1)
@@ -50,16 +60,16 @@ class Manifest {
50
60
 
51
61
  const representations = adaptationSets.map((a) => a.representations).flat(2);
52
62
  const matches = representations.filter((r) => languages?.some((lang) => r.lang.includes(lang)));
53
- // TODO: Select all audio tracks if they with different langs but same bandwidth
54
- const selectedRepresentations = matches?.length
55
- ? matches
56
- : [this.findBestRepresentation(representations)];
63
+ const selectedRepresentations = matches?.length ? matches : representations;
57
64
 
58
65
  const tracks = [];
59
66
  for (const representation of selectedRepresentations) {
60
67
  const adaptationSet = adaptationSets.find((a) => a.representations.includes(representation));
61
68
  const track = {
69
+ id: tracks.length,
62
70
  type: CONTENT_TYPE.audio,
71
+ label: adaptationSet.label,
72
+ language: adaptationSet.lang,
63
73
  pssh: this.getWidevinePssh(adaptationSet),
64
74
  licenseUrl: this.getWidevineLicenseUrl(adaptationSet),
65
75
  segments: this.getSegments(adaptationSet, representation),
@@ -74,19 +84,53 @@ class Manifest {
74
84
  }
75
85
 
76
86
  getSubtitleTracks(languages) {
77
- // TODO: Return subtitle tracks
87
+ const isSubtitleAdaptationSet = (adaptationSet) =>
88
+ (adaptationSet.contentType === CONTENT_TYPE.text ||
89
+ adaptationSet.mimeType.includes('text')) &&
90
+ !adaptationSet.maxWidth;
91
+ const adaptationSets = this.periods
92
+ .map((p) => p.adaptationSets)
93
+ .flat(1)
94
+ .filter(isSubtitleAdaptationSet);
95
+
96
+ const representations = adaptationSets.map((a) => a.representations).flat(2);
97
+ const matches = representations.filter((r) => languages?.some((lang) => r.lang.includes(lang)));
98
+ const selectedRepresentations = matches?.length ? matches : representations;
99
+
100
+ const tracks = [];
101
+ for (const representation of selectedRepresentations) {
102
+ const adaptationSet = adaptationSets.find((a) => a.representations.includes(representation));
103
+ const baseUrl = this.baseUrls?.[0]?.value;
104
+ const representationBaseUrl = representation.baseUrls?.[0]?.value;
105
+ const url = isUrl(representationBaseUrl)
106
+ ? representationBaseUrl
107
+ : `${baseUrl || ''}${representationBaseUrl || ''}`;
108
+ const track = {
109
+ id: tracks.length,
110
+ type: CONTENT_TYPE.text,
111
+ label: adaptationSet.label,
112
+ language: adaptationSet.lang,
113
+ format: representation.mimeType?.split('/')[1] || adaptationSet.mimeType?.split('/')[1],
114
+ segments: [{ url }],
115
+ bitrate: Math.round(representation.bandwidth / 1000), // Kbps
116
+ size: Math.ceil((representation.bandwidth / 8e6) * this.mediaPresentationDuration), // MB
117
+ };
118
+ tracks.push(track);
119
+ }
120
+
121
+ return tracks;
78
122
  }
79
123
 
80
124
  getWidevinePssh(adaptationSet) {
81
125
  const isWidevineProtection = (protection) =>
82
126
  protection.schemeIdUri === KEY_SYSTEMS['com.widevine.alpha'];
83
- return adaptationSet.contentProtections.find(isWidevineProtection)?.cencPssh || null;
127
+ return adaptationSet?.contentProtections?.find(isWidevineProtection)?.cencPssh || null;
84
128
  }
85
129
 
86
130
  getWidevineLicenseUrl(adaptationSet) {
87
131
  const isWidevineProtection = (protection) =>
88
132
  protection.schemeIdUri === KEY_SYSTEMS['com.widevine.alpha'];
89
- return adaptationSet.contentProtections.find(isWidevineProtection)?.licenseUrl || null;
133
+ return adaptationSet?.contentProtections?.find(isWidevineProtection)?.licenseUrl || null;
90
134
  }
91
135
 
92
136
  findBestRepresentation(representations) {
package/lib/processor.js CHANGED
@@ -58,6 +58,8 @@ const processAdaptationSet = (adaptationSet) => {
58
58
  maxFrameRate: adaptationSet['maxFrameRate'],
59
59
  contentType: adaptationSet['contentType'],
60
60
  segmentTemplate: adaptationSet['SegmentTemplate'],
61
+ mimeType: adaptationSet['mimeType'],
62
+ label: adaptationSet['label'],
61
63
  contentProtections,
62
64
  representations,
63
65
  };
package/lib/utils.js CHANGED
@@ -34,14 +34,15 @@ const parseDuration = (durationString) => {
34
34
  return isFinite(d) ? d : null;
35
35
  };
36
36
 
37
- const getQualityLabel = (videoHeight) => {
38
- const height = typeof videoHeight === 'number' ? videoHeight : parseInt(videoHeight);
39
- if (isNaN(height)) return;
37
+ const getQualityLabel = (videoWidth) => {
38
+ const width = typeof videoWidth === 'number' ? videoWidth : parseInt(videoWidth);
39
+ if (isNaN(width)) return;
40
40
  let label = 'SD';
41
- if (height >= 720) label = 'HD';
42
- if (height >= 1080) label = 'Full HD';
43
- if (height >= 2160) label = '4K';
44
- if (height >= 4320) label = '8K';
41
+ if (width >= 1280) label = 'HD';
42
+ if (width >= 1920) label = 'Full HD';
43
+ if (width >= 3840) label = 'UHD';
44
+ if (width >= 4096) label = '4K';
45
+ if (width >= 7680) label = '8K';
45
46
  return label;
46
47
  };
47
48
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dasha",
3
- "version": "2.1.0",
3
+ "version": "2.2.2",
4
4
  "author": "Vitaliy Gashkov <vitnore@gmail.com>",
5
5
  "description": "Simple MPEG-DASH MPD parser",
6
6
  "license": "Apache-2.0",
@@ -34,13 +34,13 @@
34
34
  "format:check": "prettier --loglevel warn --check \"**/*.{ts,js,json,yaml}\""
35
35
  },
36
36
  "devDependencies": {
37
- "@types/node": "^17.0.17",
38
- "eslint": "^8.9.0",
39
- "eslint-config-prettier": "^8.3.0",
37
+ "@types/node": "^17.0.23",
38
+ "eslint": "^8.12.0",
39
+ "eslint-config-prettier": "^8.5.0",
40
40
  "eslint-plugin-import": "^2.25.4",
41
41
  "eslint-plugin-prettier": "^4.0.0",
42
42
  "jest": "^27.5.1",
43
- "prettier": "^2.5.1",
44
- "typescript": "^4.5.5"
43
+ "prettier": "^2.6.1",
44
+ "typescript": "^4.6.3"
45
45
  }
46
46
  }