dasha 4.0.0-alpha.8 → 4.0.0-alpha.9

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/dist/dasha.cjs CHANGED
@@ -217,6 +217,20 @@ const ALL_STREAM_TYPES = [
217
217
  "audio",
218
218
  "subtitle"
219
219
  ];
220
+ const bitrateToString = (bitrate) => {
221
+ return bitrate ? `${Math.round(bitrate / 1e3)} Kbps` : "";
222
+ };
223
+ const roleToString = (role) => {
224
+ for (const [key, value] of Object.entries(ROLE_TYPE)) if (value === role) return key;
225
+ return "";
226
+ };
227
+ const durationToString = (seconds) => {
228
+ if (!Number.isFinite(seconds) || seconds < 0) return "";
229
+ const mins = Math.floor(seconds / 60);
230
+ const secs = Math.round(seconds % 60);
231
+ if (mins > 0) return `~${mins}m${secs.toString().padStart(2, "0")}s`;
232
+ return `~${secs}s`;
233
+ };
220
234
  var StreamInfo = class {
221
235
  codec;
222
236
  languageCode;
@@ -272,17 +286,17 @@ var VideoStreamInfo = class extends StreamInfo {
272
286
  this.codec = info?.codec;
273
287
  }
274
288
  toShortString() {
275
- const prefix = `Vid `;
276
- const bitrate = this.bitrate ? `${this.bitrate / 1e3} Kbps` : "";
277
- return `${prefix} | ${[
278
- this.width ? `${this.width}x${this.height}` : "",
279
- bitrate,
280
- this.groupId,
281
- this.frameRate,
282
- this.codec ?? this.codecs,
283
- this.videoRange,
284
- this.role
285
- ].filter(Boolean).join(" | ")}`.trim();
289
+ const parts = ["Vid"];
290
+ if (this.width) parts.push(`${this.width}x${this.height}`);
291
+ if (this.bitrate) parts.push(bitrateToString(this.bitrate));
292
+ if (this.groupId) parts.push(this.groupId);
293
+ if (this.frameRate) parts.push(this.frameRate.toString());
294
+ if (this.codec) parts.push(this.codec);
295
+ if (this.videoRange) parts.push(this.videoRange);
296
+ if (this.segmentsCount) parts.push(`${this.segmentsCount} segments`);
297
+ if (this.role) parts.push(roleToString(this.role));
298
+ if (this.playlist) parts.push(durationToString(this.playlist.totalDuration));
299
+ return parts.filter(Boolean).join(" | ").trim();
286
300
  }
287
301
  };
288
302
  var AudioStreamInfo = class extends StreamInfo {
@@ -300,18 +314,15 @@ var AudioStreamInfo = class extends StreamInfo {
300
314
  this.codec = info?.codec;
301
315
  }
302
316
  toShortString() {
303
- const prefix = `Aud `;
304
- const bitrate = this.bitrate ? `${this.bitrate / 1e3} Kbps` : "";
305
- const channels = this.numberOfChannels || this.channels ? `${this.numberOfChannels ?? this.channels}CH` : "";
306
- return `${prefix} | ${[
307
- this.groupId,
308
- bitrate,
309
- this.name,
310
- this.codec ?? this.codecs,
311
- this.languageCode,
312
- channels,
313
- this.role
314
- ].filter(Boolean).join(" | ")}`.trim();
317
+ const parts = ["Aud"];
318
+ if (this.groupId) parts.push(this.groupId);
319
+ if (this.bitrate) parts.push(bitrateToString(this.bitrate));
320
+ if (this.name) parts.push(this.name);
321
+ if (this.codec) parts.push(this.codec);
322
+ if (this.languageCode) parts.push(this.languageCode);
323
+ if (this.numberOfChannels) parts.push(`${this.numberOfChannels}CH`);
324
+ if (this.role) parts.push(roleToString(this.role));
325
+ return parts.filter(Boolean).join(" | ").trim();
315
326
  }
316
327
  };
317
328
  var SubtitleStreamInfo = class extends StreamInfo {
@@ -327,13 +338,14 @@ var SubtitleStreamInfo = class extends StreamInfo {
327
338
  this.codec = info?.codec;
328
339
  }
329
340
  toShortString() {
330
- return `Sub | ${[
331
- this.groupId,
332
- this.languageCode,
333
- this.name,
334
- this.codecs,
335
- this.role
336
- ].filter(Boolean).join(" | ")}`.trim();
341
+ const parts = ["Sub"];
342
+ const text = parts.filter(Boolean).join(" | ");
343
+ if (this.groupId) parts.push(this.groupId);
344
+ if (this.languageCode) parts.push(this.languageCode);
345
+ if (this.name) parts.push(this.name);
346
+ if (this.codec) parts.push(this.codec);
347
+ if (this.role) parts.push(roleToString(this.role));
348
+ return text.trim();
337
349
  }
338
350
  };
339
351
 
@@ -360,15 +372,26 @@ var DefaultUrlProcessor = class {
360
372
 
361
373
  //#endregion
362
374
  //#region lib/dash/dash-content-processor.ts
375
+ const namespaceMap = new Map([
376
+ ["cenc", "urn:mpeg:cenc:2013"],
377
+ ["mspr", "urn:microsoft:playready"],
378
+ ["mas", "urn:marlin:mas:1-0:services:schemas:mpd"]
379
+ ]);
380
+ const isMissingNs = (rawText, tag) => !rawText.includes(`xmlns:${tag}`) && rawText.includes(`<${tag}:`);
381
+ function replaceFirst(source, oldValue, newValue) {
382
+ const index = source.indexOf(oldValue);
383
+ return index < 0 ? source : source.slice(0, index) + newValue + source.slice(index + oldValue.length);
384
+ }
363
385
  var DefaultDashContentProcessor = class {
364
386
  canProcess(extractorType, mpdContent) {
365
387
  if (extractorType !== EXTRACTOR_TYPES.MPEG_DASH) return false;
366
- return mpdContent.includes("<mas:") && !mpdContent.includes("xmlns:mas");
388
+ return namespaceMap.keys().some((key) => isMissingNs(mpdContent, key));
367
389
  }
368
390
  process(mpdContent) {
369
- console.debug("Fix xigua mpd...");
370
- mpdContent = mpdContent.replace("<MPD ", "<MPD xmlns:mas=\"urn:marlin:mas:1-0:services:schemas:mpd\" ");
371
- return mpdContent;
391
+ console.debug("Namespace missing, trying to fix...");
392
+ const missingNamespaceKeys = Array.from(namespaceMap.keys().filter((key) => isMissingNs(mpdContent, key)));
393
+ if (!missingNamespaceKeys.length) return mpdContent;
394
+ return replaceFirst(mpdContent, "<MPD ", `<MPD ${missingNamespaceKeys.map((key) => `xmlns:${key}="${namespaceMap.get(key)}"`).join(" ")} `);
372
395
  }
373
396
  };
374
397
 
@@ -930,6 +953,7 @@ var DashExtractor = class DashExtractor {
930
953
  streamInfo.channels = channelsString;
931
954
  }
932
955
  } else if (streamInfo.type === "subtitle") {
956
+ streamInfo.bitrate = bitrate;
933
957
  if (roles) streamInfo.cc = checkIsClosedCaption(roles);
934
958
  if (accessibilities) streamInfo.sdh = checkIsSdh(accessibilities);
935
959
  }
@@ -1465,7 +1489,7 @@ var HlsExtractor = class {
1465
1489
  url = response.url;
1466
1490
  this.#m3u8Content = await response.text();
1467
1491
  } catch (e) {
1468
- if (url !== this.parserConfig.originalUrl) {
1492
+ if (this.parserConfig.originalUrl.startsWith("http") && url !== this.parserConfig.originalUrl) {
1469
1493
  const response = await fetch(this.parserConfig.originalUrl, { headers: this.parserConfig.headers });
1470
1494
  url = response.url;
1471
1495
  this.#m3u8Content = await response.text();
package/dist/dasha.mjs CHANGED
@@ -192,6 +192,20 @@ const ALL_STREAM_TYPES = [
192
192
  "audio",
193
193
  "subtitle"
194
194
  ];
195
+ const bitrateToString = (bitrate) => {
196
+ return bitrate ? `${Math.round(bitrate / 1e3)} Kbps` : "";
197
+ };
198
+ const roleToString = (role) => {
199
+ for (const [key, value] of Object.entries(ROLE_TYPE)) if (value === role) return key;
200
+ return "";
201
+ };
202
+ const durationToString = (seconds) => {
203
+ if (!Number.isFinite(seconds) || seconds < 0) return "";
204
+ const mins = Math.floor(seconds / 60);
205
+ const secs = Math.round(seconds % 60);
206
+ if (mins > 0) return `~${mins}m${secs.toString().padStart(2, "0")}s`;
207
+ return `~${secs}s`;
208
+ };
195
209
  var StreamInfo = class {
196
210
  codec;
197
211
  languageCode;
@@ -247,17 +261,17 @@ var VideoStreamInfo = class extends StreamInfo {
247
261
  this.codec = info?.codec;
248
262
  }
249
263
  toShortString() {
250
- const prefix = `Vid `;
251
- const bitrate = this.bitrate ? `${this.bitrate / 1e3} Kbps` : "";
252
- return `${prefix} | ${[
253
- this.width ? `${this.width}x${this.height}` : "",
254
- bitrate,
255
- this.groupId,
256
- this.frameRate,
257
- this.codec ?? this.codecs,
258
- this.videoRange,
259
- this.role
260
- ].filter(Boolean).join(" | ")}`.trim();
264
+ const parts = ["Vid"];
265
+ if (this.width) parts.push(`${this.width}x${this.height}`);
266
+ if (this.bitrate) parts.push(bitrateToString(this.bitrate));
267
+ if (this.groupId) parts.push(this.groupId);
268
+ if (this.frameRate) parts.push(this.frameRate.toString());
269
+ if (this.codec) parts.push(this.codec);
270
+ if (this.videoRange) parts.push(this.videoRange);
271
+ if (this.segmentsCount) parts.push(`${this.segmentsCount} segments`);
272
+ if (this.role) parts.push(roleToString(this.role));
273
+ if (this.playlist) parts.push(durationToString(this.playlist.totalDuration));
274
+ return parts.filter(Boolean).join(" | ").trim();
261
275
  }
262
276
  };
263
277
  var AudioStreamInfo = class extends StreamInfo {
@@ -275,18 +289,15 @@ var AudioStreamInfo = class extends StreamInfo {
275
289
  this.codec = info?.codec;
276
290
  }
277
291
  toShortString() {
278
- const prefix = `Aud `;
279
- const bitrate = this.bitrate ? `${this.bitrate / 1e3} Kbps` : "";
280
- const channels = this.numberOfChannels || this.channels ? `${this.numberOfChannels ?? this.channels}CH` : "";
281
- return `${prefix} | ${[
282
- this.groupId,
283
- bitrate,
284
- this.name,
285
- this.codec ?? this.codecs,
286
- this.languageCode,
287
- channels,
288
- this.role
289
- ].filter(Boolean).join(" | ")}`.trim();
292
+ const parts = ["Aud"];
293
+ if (this.groupId) parts.push(this.groupId);
294
+ if (this.bitrate) parts.push(bitrateToString(this.bitrate));
295
+ if (this.name) parts.push(this.name);
296
+ if (this.codec) parts.push(this.codec);
297
+ if (this.languageCode) parts.push(this.languageCode);
298
+ if (this.numberOfChannels) parts.push(`${this.numberOfChannels}CH`);
299
+ if (this.role) parts.push(roleToString(this.role));
300
+ return parts.filter(Boolean).join(" | ").trim();
290
301
  }
291
302
  };
292
303
  var SubtitleStreamInfo = class extends StreamInfo {
@@ -302,13 +313,14 @@ var SubtitleStreamInfo = class extends StreamInfo {
302
313
  this.codec = info?.codec;
303
314
  }
304
315
  toShortString() {
305
- return `Sub | ${[
306
- this.groupId,
307
- this.languageCode,
308
- this.name,
309
- this.codecs,
310
- this.role
311
- ].filter(Boolean).join(" | ")}`.trim();
316
+ const parts = ["Sub"];
317
+ const text = parts.filter(Boolean).join(" | ");
318
+ if (this.groupId) parts.push(this.groupId);
319
+ if (this.languageCode) parts.push(this.languageCode);
320
+ if (this.name) parts.push(this.name);
321
+ if (this.codec) parts.push(this.codec);
322
+ if (this.role) parts.push(roleToString(this.role));
323
+ return text.trim();
312
324
  }
313
325
  };
314
326
 
@@ -335,15 +347,26 @@ var DefaultUrlProcessor = class {
335
347
 
336
348
  //#endregion
337
349
  //#region lib/dash/dash-content-processor.ts
350
+ const namespaceMap = new Map([
351
+ ["cenc", "urn:mpeg:cenc:2013"],
352
+ ["mspr", "urn:microsoft:playready"],
353
+ ["mas", "urn:marlin:mas:1-0:services:schemas:mpd"]
354
+ ]);
355
+ const isMissingNs = (rawText, tag) => !rawText.includes(`xmlns:${tag}`) && rawText.includes(`<${tag}:`);
356
+ function replaceFirst(source, oldValue, newValue) {
357
+ const index = source.indexOf(oldValue);
358
+ return index < 0 ? source : source.slice(0, index) + newValue + source.slice(index + oldValue.length);
359
+ }
338
360
  var DefaultDashContentProcessor = class {
339
361
  canProcess(extractorType, mpdContent) {
340
362
  if (extractorType !== EXTRACTOR_TYPES.MPEG_DASH) return false;
341
- return mpdContent.includes("<mas:") && !mpdContent.includes("xmlns:mas");
363
+ return namespaceMap.keys().some((key) => isMissingNs(mpdContent, key));
342
364
  }
343
365
  process(mpdContent) {
344
- console.debug("Fix xigua mpd...");
345
- mpdContent = mpdContent.replace("<MPD ", "<MPD xmlns:mas=\"urn:marlin:mas:1-0:services:schemas:mpd\" ");
346
- return mpdContent;
366
+ console.debug("Namespace missing, trying to fix...");
367
+ const missingNamespaceKeys = Array.from(namespaceMap.keys().filter((key) => isMissingNs(mpdContent, key)));
368
+ if (!missingNamespaceKeys.length) return mpdContent;
369
+ return replaceFirst(mpdContent, "<MPD ", `<MPD ${missingNamespaceKeys.map((key) => `xmlns:${key}="${namespaceMap.get(key)}"`).join(" ")} `);
347
370
  }
348
371
  };
349
372
 
@@ -905,6 +928,7 @@ var DashExtractor = class DashExtractor {
905
928
  streamInfo.channels = channelsString;
906
929
  }
907
930
  } else if (streamInfo.type === "subtitle") {
931
+ streamInfo.bitrate = bitrate;
908
932
  if (roles) streamInfo.cc = checkIsClosedCaption(roles);
909
933
  if (accessibilities) streamInfo.sdh = checkIsSdh(accessibilities);
910
934
  }
@@ -1440,7 +1464,7 @@ var HlsExtractor = class {
1440
1464
  url = response.url;
1441
1465
  this.#m3u8Content = await response.text();
1442
1466
  } catch (e) {
1443
- if (url !== this.parserConfig.originalUrl) {
1467
+ if (this.parserConfig.originalUrl.startsWith("http") && url !== this.parserConfig.originalUrl) {
1444
1468
  const response = await fetch(this.parserConfig.originalUrl, { headers: this.parserConfig.headers });
1445
1469
  url = response.url;
1446
1470
  this.#m3u8Content = await response.text();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dasha",
3
- "version": "4.0.0-alpha.8",
3
+ "version": "4.0.0-alpha.9",
4
4
  "description": "Streaming manifest parser",
5
5
  "files": [
6
6
  "dist"