dasha 3.1.2 → 3.1.4

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.mjs DELETED
@@ -1,1524 +0,0 @@
1
- var __getOwnPropNames = Object.getOwnPropertyNames;
2
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
- }) : x)(function(x) {
5
- if (typeof require !== "undefined") return require.apply(this, arguments);
6
- throw Error('Dynamic require of "' + x + '" is not supported');
7
- });
8
- var __commonJS = (cb, mod) => function __require2() {
9
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
- };
11
-
12
- // lib/xml.js
13
- var require_xml = __commonJS({
14
- "lib/xml.js"(exports, module) {
15
- "use strict";
16
- function parse(text, options = {}) {
17
- var pos = options.pos || 0;
18
- var keepComments = !!options.keepComments;
19
- var keepWhitespace = !!options.keepWhitespace;
20
- var openBracket = "<";
21
- var openBracketCC = "<".charCodeAt(0);
22
- var closeBracket = ">";
23
- var closeBracketCC = ">".charCodeAt(0);
24
- var minusCC = "-".charCodeAt(0);
25
- var slashCC = "/".charCodeAt(0);
26
- var exclamationCC = "!".charCodeAt(0);
27
- var singleQuoteCC = "'".charCodeAt(0);
28
- var doubleQuoteCC = '"'.charCodeAt(0);
29
- var openCornerBracketCC = "[".charCodeAt(0);
30
- var closeCornerBracketCC = "]".charCodeAt(0);
31
- function parseChildren(tagName) {
32
- var children = [];
33
- while (text[pos]) {
34
- if (text.charCodeAt(pos) == openBracketCC) {
35
- if (text.charCodeAt(pos + 1) === slashCC) {
36
- var closeStart = pos + 2;
37
- pos = text.indexOf(closeBracket, pos);
38
- var closeTag = text.substring(closeStart, pos);
39
- if (closeTag.indexOf(tagName) == -1) {
40
- const parsedText = text.substring(0, pos).split("\n");
41
- throw new Error(
42
- "Unexpected close tag\nLine: " + (parsedText.length - 1) + "\nColumn: " + (parsedText[parsedText.length - 1].length + 1) + "\nChar: " + text[pos]
43
- );
44
- }
45
- if (pos + 1) pos += 1;
46
- return children;
47
- } else if (text.charCodeAt(pos + 1) === exclamationCC) {
48
- if (text.charCodeAt(pos + 2) == minusCC) {
49
- const startCommentPos = pos;
50
- while (pos !== -1 && !(text.charCodeAt(pos) === closeBracketCC && text.charCodeAt(pos - 1) == minusCC && text.charCodeAt(pos - 2) == minusCC && pos != -1)) {
51
- pos = text.indexOf(closeBracket, pos + 1);
52
- }
53
- if (pos === -1) {
54
- pos = text.length;
55
- }
56
- if (keepComments) {
57
- children.push(text.substring(startCommentPos, pos + 1));
58
- }
59
- } else if (text.charCodeAt(pos + 2) === openCornerBracketCC && text.charCodeAt(pos + 8) === openCornerBracketCC && text.substr(pos + 3, 5).toLowerCase() === "cdata") {
60
- var cdataEndIndex = text.indexOf("]]>", pos);
61
- if (cdataEndIndex == -1) {
62
- children.push(text.substr(pos + 9));
63
- pos = text.length;
64
- } else {
65
- children.push(text.substring(pos + 9, cdataEndIndex));
66
- pos = cdataEndIndex + 3;
67
- }
68
- continue;
69
- } else {
70
- const startDoctype = pos + 1;
71
- pos += 2;
72
- var encapsuled = false;
73
- while ((text.charCodeAt(pos) !== closeBracketCC || encapsuled === true) && text[pos]) {
74
- if (text.charCodeAt(pos) === openCornerBracketCC) {
75
- encapsuled = true;
76
- } else if (encapsuled === true && text.charCodeAt(pos) === closeCornerBracketCC) {
77
- encapsuled = false;
78
- }
79
- pos++;
80
- }
81
- children.push(text.substring(startDoctype, pos));
82
- }
83
- pos++;
84
- continue;
85
- }
86
- var node = parseNode();
87
- children.push(node);
88
- if (node.tagName[0] === "?") {
89
- children.push(...node.children);
90
- node.children = [];
91
- }
92
- } else {
93
- const parsedText = parseText();
94
- if (keepWhitespace) {
95
- if (parsedText.length > 0) {
96
- children.push(parsedText);
97
- }
98
- } else {
99
- var trimmed = parsedText.trim();
100
- if (trimmed.length > 0) {
101
- children.push(trimmed);
102
- }
103
- }
104
- pos++;
105
- }
106
- }
107
- return children;
108
- }
109
- function parseText() {
110
- var start = pos;
111
- pos = text.indexOf(openBracket, pos) - 1;
112
- if (pos === -2) pos = text.length;
113
- return text.slice(start, pos + 1);
114
- }
115
- var nameSpacer = "\r\n >/= ";
116
- function parseName() {
117
- var start = pos;
118
- while (nameSpacer.indexOf(text[pos]) === -1 && text[pos]) {
119
- pos++;
120
- }
121
- return text.slice(start, pos);
122
- }
123
- var NoChildNodes = options.noChildNodes || [
124
- "img",
125
- "br",
126
- "input",
127
- "meta",
128
- "link",
129
- "hr"
130
- ];
131
- function parseNode() {
132
- pos++;
133
- const tagName = parseName();
134
- const attributes = {};
135
- let children = [];
136
- while (text.charCodeAt(pos) !== closeBracketCC && text[pos]) {
137
- var c = text.charCodeAt(pos);
138
- if (c > 64 && c < 91 || c > 96 && c < 123) {
139
- var name = parseName();
140
- var code = text.charCodeAt(pos);
141
- while (code && code !== singleQuoteCC && code !== doubleQuoteCC && !(code > 64 && code < 91 || code > 96 && code < 123) && code !== closeBracketCC) {
142
- pos++;
143
- code = text.charCodeAt(pos);
144
- }
145
- if (code === singleQuoteCC || code === doubleQuoteCC) {
146
- var value = parseString();
147
- if (pos === -1) {
148
- return {
149
- tagName,
150
- attributes,
151
- children
152
- };
153
- }
154
- } else {
155
- value = null;
156
- pos--;
157
- }
158
- attributes[name] = value;
159
- }
160
- pos++;
161
- }
162
- if (text.charCodeAt(pos - 1) !== slashCC) {
163
- if (tagName == "script") {
164
- const start = pos + 1;
165
- pos = text.indexOf("</script>", pos);
166
- children = [text.slice(start, pos)];
167
- pos += 9;
168
- } else if (tagName == "style") {
169
- const start = pos + 1;
170
- pos = text.indexOf("</style>", pos);
171
- children = [text.slice(start, pos)];
172
- pos += 8;
173
- } else if (NoChildNodes.indexOf(tagName) === -1) {
174
- pos++;
175
- children = parseChildren(tagName);
176
- } else {
177
- pos++;
178
- }
179
- } else {
180
- pos++;
181
- }
182
- return {
183
- tagName,
184
- attributes,
185
- children
186
- };
187
- }
188
- function parseString() {
189
- var startChar = text[pos];
190
- var startpos = pos + 1;
191
- pos = text.indexOf(startChar, startpos);
192
- return text.slice(startpos, pos);
193
- }
194
- function findElements() {
195
- var r = new RegExp(
196
- "\\s" + options.attrName + `\\s*=['"]` + options.attrValue + `['"]`
197
- ).exec(text);
198
- if (r) {
199
- return r.index;
200
- } else {
201
- return -1;
202
- }
203
- }
204
- let out = null;
205
- if (options.attrValue !== void 0) {
206
- options.attrName = options.attrName || "id";
207
- out = [];
208
- while ((pos = findElements()) !== -1) {
209
- pos = text.lastIndexOf("<", pos);
210
- if (pos !== -1) {
211
- out.push(parseNode());
212
- }
213
- text = text.substr(pos);
214
- pos = 0;
215
- }
216
- } else if (options.parseNode) {
217
- out = parseNode();
218
- } else {
219
- out = parseChildren("");
220
- }
221
- if (options.filter) {
222
- out = filter(out, options.filter);
223
- }
224
- if (options.setPos) {
225
- out.pos = pos;
226
- }
227
- return out;
228
- }
229
- function filter(children, f, dept = 0, path = "") {
230
- var out = [];
231
- children.forEach(function(child, i) {
232
- if (typeof child === "object" && f(child, i, dept, path)) out.push(child);
233
- if (child.children) {
234
- var kids = filter(
235
- child.children,
236
- f,
237
- dept + 1,
238
- (path ? path + "." : "") + i + "." + child.tagName
239
- );
240
- out = out.concat(kids);
241
- }
242
- });
243
- return out;
244
- }
245
- module.exports = { parse, filter };
246
- }
247
- });
248
-
249
- // lib/util.js
250
- var require_util = __commonJS({
251
- "lib/util.js"(exports, module) {
252
- "use strict";
253
- var formatBytes = (bytes, sizes = ["Bytes", "KB", "MB", "GB", "TB"]) => {
254
- if (bytes == 0) return `0 ${sizes[0]}`;
255
- const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
256
- if (i == 0) return bytes + " " + sizes[i];
257
- return (bytes / Math.pow(1024, i)).toFixed(1) + " " + sizes[i];
258
- };
259
- var parseSize = (bandwidth, duration) => ({
260
- b: bandwidth * duration,
261
- kb: bandwidth / 1e3 * duration,
262
- mb: bandwidth / 8e6 * duration,
263
- gb: bandwidth / 8e9 * duration,
264
- toString() {
265
- return formatBytes(bandwidth * duration);
266
- }
267
- });
268
- var parseBitrate = (bandwidth) => ({
269
- bps: bandwidth,
270
- kbps: bandwidth / 1e3,
271
- mbps: bandwidth / 8e6,
272
- gbps: bandwidth / 8e9,
273
- toString() {
274
- return formatBytes(bandwidth, ["bps", "Kbps", "Mbps", "Gbps"]);
275
- }
276
- });
277
- var qualities = [
278
- { width: 7680, height: 4320 },
279
- { width: 3840, height: 2160 },
280
- { width: 2560, height: 1440 },
281
- { width: 1920, height: 1080 },
282
- { width: 1280, height: 720 },
283
- { width: 1024, height: 576 },
284
- { width: 854, height: 480 },
285
- { width: 640, height: 360 },
286
- { width: 426, height: 240 },
287
- { width: 256, height: 144 }
288
- ];
289
- var getWidth = (height) => qualities.find((q) => q.height === height)?.width;
290
- var getHeight = (width) => qualities.find((q) => q.width === width)?.height;
291
- var getQualityLabel = (resolution) => `${getHeight(resolution.width) || resolution.height}p`;
292
- var getBestTrack = (tracks) => {
293
- const maxBitrate = Math.max(...tracks.map((track) => track.bitrate.bps));
294
- return tracks.find((track) => track.bitrate.bps === maxBitrate);
295
- };
296
- var parseDuration = (str) => {
297
- const SECONDS_IN_YEAR = 365 * 24 * 60 * 60;
298
- const SECONDS_IN_MONTH = 30 * 24 * 60 * 60;
299
- const SECONDS_IN_DAY = 24 * 60 * 60;
300
- const SECONDS_IN_HOUR = 60 * 60;
301
- const SECONDS_IN_MIN = 60;
302
- const durationRegex = /P(?:(\d*)Y)?(?:(\d*)M)?(?:(\d*)D)?(?:T(?:(\d*)H)?(?:(\d*)M)?(?:([\d.]*)S)?)?/;
303
- const match = durationRegex.exec(str);
304
- if (!match) {
305
- return 0;
306
- }
307
- const [year, month, day, hour, minute, second] = match.slice(1);
308
- return parseFloat(year || 0) * SECONDS_IN_YEAR + parseFloat(month || 0) * SECONDS_IN_MONTH + parseFloat(day || 0) * SECONDS_IN_DAY + parseFloat(hour || 0) * SECONDS_IN_HOUR + parseFloat(minute || 0) * SECONDS_IN_MIN + parseFloat(second || 0);
309
- };
310
- var isLanguageTagValid = (value) => {
311
- try {
312
- Intl.getCanonicalLocales(value);
313
- return true;
314
- } catch (e) {
315
- return;
316
- }
317
- };
318
- module.exports = {
319
- parseSize,
320
- parseBitrate,
321
- getWidth,
322
- getHeight,
323
- getQualityLabel,
324
- getBestTrack,
325
- parseDuration,
326
- isLanguageTagValid
327
- };
328
- }
329
- });
330
-
331
- // lib/video.js
332
- var require_video = __commonJS({
333
- "lib/video.js"(exports, module) {
334
- "use strict";
335
- var { parseBitrate, getQualityLabel, parseSize } = require_util();
336
- var VIDEO_CODECS = {
337
- avc: "H.264",
338
- hevc: "H.265",
339
- vc1: "VC-1",
340
- vp8: "VP8",
341
- vp9: "VP9",
342
- av1: "AV1"
343
- };
344
- var DYNAMIC_RANGE = {
345
- sdr: "SDR",
346
- // Standart Dynamic Range
347
- hlg: "HLG",
348
- // Hybrid log-gamma (HDR)
349
- hdr10: "HDR10",
350
- hdr10p: "HDR10+",
351
- dv: "DV"
352
- // Dolby Vision
353
- };
354
- var PRIMARIES = {
355
- Unspecified: 0,
356
- BT_709: 1,
357
- BT_601_625: 5,
358
- BT_601_525: 6,
359
- BT_2020_and_2100: 9,
360
- SMPTE_ST_2113_and_EG_4321: 12
361
- // P3D65
362
- };
363
- var TRANSFER = {
364
- Unspecified: 0,
365
- BT_709: 1,
366
- BT_601: 6,
367
- BT_2020: 14,
368
- BT_2100: 15,
369
- BT_2100_PQ: 16,
370
- BT_2100_HLG: 18
371
- };
372
- var MATRIX = {
373
- RGB: 0,
374
- YCbCr_BT_709: 1,
375
- YCbCr_BT_601_625: 5,
376
- YCbCr_BT_601_525: 6,
377
- YCbCr_BT_2020_and_2100: 9,
378
- // YCbCr BT.2100 shares the same CP
379
- ICtCp_BT_2100: 14
380
- };
381
- var parseVideoCodecFromMime = (mime) => {
382
- const target = mime.toLowerCase().trim().split(".")[0];
383
- const avc = ["avc1", "avc2", "avc3", "dva1", "dvav"];
384
- const hevc = [
385
- "hev1",
386
- "hev2",
387
- "hev3",
388
- "hvc1",
389
- "hvc2",
390
- "hvc3",
391
- "dvh1",
392
- "dvhe",
393
- "lhv1",
394
- "lhe1"
395
- ];
396
- const vc1 = ["vc-1"];
397
- const vp8 = ["vp08", "vp8"];
398
- const vp9 = ["vp09", "vp9"];
399
- const av1 = ["av01"];
400
- if (avc.includes(target)) return VIDEO_CODECS.avc;
401
- if (hevc.includes(target)) return VIDEO_CODECS.hevc;
402
- if (vc1.includes(target)) return VIDEO_CODECS.hevc;
403
- if (vp8.includes(target)) return VIDEO_CODECS.vp8;
404
- if (vp9.includes(target)) return VIDEO_CODECS.vp9;
405
- if (av1.includes(target)) return VIDEO_CODECS.av1;
406
- throw new Error(`The MIME ${mime} is not supported as video codec`);
407
- };
408
- var parseDynamicRangeFromCicp = (primaries, transfer, matrix) => {
409
- if (transfer == 5) transfer = TRANSFER.BT_601;
410
- if (primaries == PRIMARIES.Unspecified && transfer == TRANSFER.Unspecified && matrix == MATRIX.RGB)
411
- return DYNAMIC_RANGE.sdr;
412
- else if ([PRIMARIES.BT_601_625, PRIMARIES.BT_601_525].includes(primaries))
413
- return DYNAMIC_RANGE.sdr;
414
- else if (TRANSFER.BT_2100_PQ === transfer) return DYNAMIC_RANGE.hdr10;
415
- else if (TRANSFER.BT_2100_HLG === transfer) return DYNAMIC_RANGE.hlg;
416
- else return DYNAMIC_RANGE.sdr;
417
- };
418
- var createVideoTrack = ({
419
- id,
420
- label,
421
- type,
422
- codec,
423
- dynamicRange,
424
- contentProtection,
425
- bitrate,
426
- duration,
427
- width,
428
- height,
429
- fps,
430
- language,
431
- segments
432
- }) => {
433
- const parsedBitrate = parseBitrate(Number(bitrate));
434
- const parsedWidth = Number(width);
435
- const parsedHeight = Number(height);
436
- const size = duration ? parseSize(Number(bitrate), Number(duration)) : void 0;
437
- return {
438
- id,
439
- label,
440
- type,
441
- codec,
442
- bitrate: parsedBitrate,
443
- size,
444
- protection: contentProtection,
445
- segments,
446
- dynamicRange,
447
- language,
448
- width: parsedWidth,
449
- height: parsedHeight,
450
- fps: Number(fps),
451
- quality: getQualityLabel({ width: parsedWidth, height: parsedHeight }),
452
- toString() {
453
- return [
454
- "VIDEO",
455
- `[${codec}, ${dynamicRange}]`,
456
- language,
457
- `${width}x${height} @ ${parsedBitrate.kbps} kb/s, ${fps} FPS`
458
- ].join(" | ");
459
- }
460
- };
461
- };
462
- var parseVideoCodec = (codecs) => {
463
- for (const codec of codecs.toLowerCase().split(",")) {
464
- const mime = codec.trim().split(".")[0];
465
- try {
466
- return parseVideoCodecFromMime(mime);
467
- } catch (e) {
468
- continue;
469
- }
470
- }
471
- throw new Error(
472
- `No MIME types matched any supported Video Codecs in ${codecs}`
473
- );
474
- };
475
- var parseDynamicRange = (codecs, supplementalProps = [], essentialProps = []) => {
476
- const dv = ["dva1", "dvav", "dvhe", "dvh1"];
477
- if (dv.some((value) => codecs.startsWith(value))) return DYNAMIC_RANGE.dv;
478
- const primariesScheme = "urn:mpeg:mpegB:cicp:ColourPrimaries";
479
- const transferScheme = "urn:mpeg:mpegB:cicp:TransferCharacteristics";
480
- const matrixScheme = "urn:mpeg:mpegB:cicp:MatrixCoefficients";
481
- const allProps = [...essentialProps, ...supplementalProps];
482
- const getValues = (scheme) => allProps.filter((prop) => prop.attributes.schemeIdUri === scheme).map((prop) => parseInt(prop.attributes.value));
483
- const primaries = getValues(primariesScheme).reduce(
484
- (acc, current) => acc + current,
485
- 0
486
- );
487
- const transfer = getValues(transferScheme).reduce(
488
- (acc, current) => acc + current,
489
- 0
490
- );
491
- const matrix = getValues(matrixScheme).reduce(
492
- (acc, current) => acc + current,
493
- 0
494
- );
495
- return parseDynamicRangeFromCicp(primaries, transfer, matrix);
496
- };
497
- module.exports = {
498
- parseVideoCodec,
499
- parseDynamicRange,
500
- createVideoTrack,
501
- VIDEO_CODECS
502
- };
503
- }
504
- });
505
-
506
- // lib/track.js
507
- var require_track = __commonJS({
508
- "lib/track.js"(exports, module) {
509
- "use strict";
510
- var { getBestTrack } = require_util();
511
- var parseMimes = (codecs) => codecs.toLowerCase().split(",").map((codec) => codec.trim().split(".")[0]);
512
- var createResolutionFilter = (videos) => {
513
- return ({ width, height }) => {
514
- return videos.filter(
515
- (track) => (!width || track.width === width) && (!height || track.height === height)
516
- );
517
- };
518
- };
519
- var createCodecFilter = (tracks) => {
520
- return (codecs) => {
521
- if (!codecs?.length) return tracks;
522
- const results = tracks.filter((track) => codecs.includes(track.codec));
523
- results.sort((a, b) => b.bitrate.bps - a.bitrate.bps);
524
- return results;
525
- };
526
- };
527
- var createVideoCodecFilter = (videos) => createCodecFilter(videos);
528
- var createVideoQualityFilter = (videos) => {
529
- return (quality) => {
530
- if (!quality) return [getBestTrack(videos)];
531
- const trackQuality = String(quality).includes("p") ? quality : `${quality}p`;
532
- const results = videos.filter((track) => track.quality === trackQuality);
533
- results.sort((a, b) => b.bitrate.bps - a.bitrate.bps);
534
- return results.length ? results : [getBestTrack(videos)];
535
- };
536
- };
537
- var createAudioCodecFilter = (audios) => createCodecFilter(audios);
538
- var createAudioLanguageFilter = (audios) => {
539
- return (languages = [], maxTracksPerLanguage) => {
540
- if (!languages.length) {
541
- const audiosWithLanguage = audios.filter((track) => track.language);
542
- if (audiosWithLanguage.length) {
543
- for (const audio of audiosWithLanguage) {
544
- const alreadyAdded = languages.includes(audio.language);
545
- if (!alreadyAdded) languages.push(audio.language);
546
- }
547
- } else {
548
- audios.sort((a, b) => b.bitrate.bps - a.bitrate.bps);
549
- return audios.slice(0, maxTracksPerLanguage);
550
- }
551
- }
552
- const filtered = [];
553
- for (const language of languages) {
554
- const tracks = audios.filter(
555
- (track) => track.language?.startsWith(language)
556
- );
557
- filtered.push(...tracks);
558
- }
559
- const results = [];
560
- const filteredLanguages = [
561
- ...new Set(filtered.map((track) => track.language))
562
- ];
563
- for (const language of filteredLanguages) {
564
- const tracks = filtered.filter((track) => track.language === language).slice(0, maxTracksPerLanguage);
565
- results.push(...tracks);
566
- }
567
- return results;
568
- };
569
- };
570
- var createAudioChannelsFilter = (audios) => {
571
- return (channels) => {
572
- if (!channels) return audios;
573
- const value = typeof channels === "string" ? parseFloat(channels) : channels;
574
- return audios.filter((track) => track.channels === value);
575
- };
576
- };
577
- var createSubtitleLanguageFilter = (subtitles) => {
578
- return (languages) => {
579
- if (!languages.length) return subtitles;
580
- return subtitles.filter(
581
- (track) => languages.some(
582
- (language) => track.language?.startsWith(language) || track.label?.startsWith(language)
583
- )
584
- );
585
- };
586
- };
587
- var filterByResolution = (tracks, resolution) => createResolutionFilter(tracks)(resolution);
588
- var filterByQuality = (tracks, quality) => createVideoQualityFilter(tracks)(quality);
589
- var filterByCodecs = (tracks, codecs) => createCodecFilter(tracks)(codecs);
590
- var filterByLanguages = (tracks, languages, maxTracksPerLanguage) => createAudioLanguageFilter(tracks)(languages, maxTracksPerLanguage);
591
- var filterByChannels = (tracks, channels) => createAudioChannelsFilter(tracks)(channels);
592
- module.exports = {
593
- parseMimes,
594
- createResolutionFilter,
595
- createVideoCodecFilter,
596
- createVideoQualityFilter,
597
- createAudioCodecFilter,
598
- createAudioLanguageFilter,
599
- createAudioChannelsFilter,
600
- createSubtitleLanguageFilter,
601
- filterByResolution,
602
- filterByQuality,
603
- filterByCodecs,
604
- filterByLanguages,
605
- filterByChannels
606
- };
607
- }
608
- });
609
-
610
- // lib/audio.js
611
- var require_audio = __commonJS({
612
- "lib/audio.js"(exports, module) {
613
- "use strict";
614
- var { parseMimes } = require_track();
615
- var { parseBitrate, parseSize } = require_util();
616
- var AUDIO_CODECS = {
617
- AAC: "AAC",
618
- // https://wikipedia.org/wiki/Advanced_Audio_Coding
619
- AC3: "DD",
620
- // https://wikipedia.org/wiki/Dolby_Digital
621
- EC3: "DD+",
622
- // https://wikipedia.org/wiki/Dolby_Digital_Plus
623
- OPUS: "OPUS",
624
- // https://wikipedia.org/wiki/Opus_(audio_format)
625
- OGG: "VORB",
626
- // https://wikipedia.org/wiki/Vorbis
627
- DTS: "DTS",
628
- // https://en.wikipedia.org/wiki/DTS_(company)#DTS_Digital_Surround
629
- ALAC: "ALAC",
630
- // https://en.wikipedia.org/wiki/Apple_Lossless_Audio_Codec
631
- FLAC: "FLAC"
632
- // https://en.wikipedia.org/wiki/FLAC
633
- };
634
- var parseAudioCodecFromMime = (mime) => {
635
- const target = mime.toLowerCase().trim().split(".")[0];
636
- switch (target) {
637
- case "mp4a":
638
- return AUDIO_CODECS.AAC;
639
- case "ac-3":
640
- return AUDIO_CODECS.AC3;
641
- case "ec-3":
642
- return AUDIO_CODECS.EC3;
643
- case "opus":
644
- return AUDIO_CODECS.OPUS;
645
- case "dtsc":
646
- return AUDIO_CODECS.DTS;
647
- case "alac":
648
- return AUDIO_CODECS.ALAC;
649
- case "flac":
650
- return AUDIO_CODECS.FLAC;
651
- default:
652
- throw new Error(`The MIME ${mime} is not supported as audio codec`);
653
- }
654
- };
655
- var parseAudioCodec = (codecs) => {
656
- const mimes = parseMimes(codecs);
657
- for (const mime of mimes) {
658
- try {
659
- return parseAudioCodecFromMime(mime);
660
- } catch (e) {
661
- continue;
662
- }
663
- }
664
- throw new Error(
665
- `No MIME types matched any supported Audio Codecs in ${codecs}`
666
- );
667
- };
668
- var getDolbyDigitalPlusComplexityIndex = (supplementalProps = []) => {
669
- const targetScheme = "tag:dolby.com,2018:dash:EC3_ExtensionComplexityIndex:2018";
670
- for (const prop of supplementalProps)
671
- if (prop.attributes.schemeIdUri === targetScheme)
672
- return parseInt(prop.attributes.value);
673
- };
674
- var checkIsDescriptive = (accessibilities = []) => {
675
- for (const accessibility of accessibilities) {
676
- const { schemeIdUri, value } = accessibility.attributes;
677
- const firstMatch = schemeIdUri == "urn:mpeg:dash:role:2011" && value === "descriptive";
678
- const secondMatch = schemeIdUri == "urn:tva:metadata:cs:AudioPurposeCS:2007" && value === "1";
679
- const isDescriptive = firstMatch || secondMatch;
680
- if (isDescriptive) return true;
681
- }
682
- return false;
683
- };
684
- var parseChannels = (channels) => {
685
- const isDigit = (char) => char >= "0" && char <= "9";
686
- if (typeof channels === "string") {
687
- if (channels.toUpperCase() == "A000") return 2;
688
- else if (channels.toUpperCase() == "F801") return 5.1;
689
- else if (isDigit(channels.replace("ch", "").replace(".", "")[0]))
690
- return parseFloat(channels.replace("ch", ""));
691
- throw new Error(`Unsupported audio channels value, '${channels}'`);
692
- }
693
- return parseFloat(channels);
694
- };
695
- var createAudioTrack = ({
696
- id,
697
- label,
698
- type,
699
- codec,
700
- channels,
701
- bitrate,
702
- duration,
703
- jointObjectCoding = 0,
704
- isDescriptive = false,
705
- language,
706
- segments
707
- }) => {
708
- const parsedBitrate = parseBitrate(Number(bitrate));
709
- const parsedChannels = parseChannels(channels);
710
- const size = duration ? parseSize(Number(bitrate), Number(duration)) : void 0;
711
- return {
712
- id,
713
- label,
714
- type,
715
- codec,
716
- bitrate: parsedBitrate,
717
- size,
718
- language,
719
- segments,
720
- channels: parsedChannels,
721
- jointObjectCoding,
722
- isDescriptive,
723
- toString() {
724
- return [
725
- "AUDIO",
726
- `[${codec}]`,
727
- `${parsedChannels || "?"}` + (jointObjectCoding ? ` (JOC ${jointObjectCoding})` : ""),
728
- `${parsedBitrate.kbps} kb/s`,
729
- language
730
- ].join(" | ");
731
- }
732
- };
733
- };
734
- module.exports = {
735
- AUDIO_CODECS,
736
- parseAudioCodec,
737
- createAudioTrack,
738
- getDolbyDigitalPlusComplexityIndex,
739
- checkIsDescriptive
740
- };
741
- }
742
- });
743
-
744
- // lib/subtitle.js
745
- var require_subtitle = __commonJS({
746
- "lib/subtitle.js"(exports, module) {
747
- "use strict";
748
- var { parseMimes } = require_track();
749
- var { parseBitrate, parseSize } = require_util();
750
- var SUBTITLE_CODECS = {
751
- SubRip: "SRT",
752
- // https://wikipedia.org/wiki/SubRip
753
- SubStationAlpha: "SSA",
754
- // https://wikipedia.org/wiki/SubStation_Alpha
755
- SubStationAlphav4: "ASS",
756
- // https://wikipedia.org/wiki/SubStation_Alpha#Advanced_SubStation_Alpha=
757
- TimedTextMarkupLang: "TTML",
758
- // https://wikipedia.org/wiki/Timed_Text_Markup_Language
759
- WebVTT: "VTT",
760
- // https://wikipedia.org/wiki/WebVTT
761
- // MPEG-DASH box-encapsulated subtitle formats
762
- fTTML: "STPP",
763
- // https://www.w3.org/TR/2018/REC-ttml-imsc1.0.1-20180424
764
- fVTT: "WVTT"
765
- // https://www.w3.org/TR/webvtt1
766
- };
767
- var parseSubtitleCodecFromMime = (mime) => {
768
- const target = mime.toLowerCase().trim().split(".")[0];
769
- switch (target) {
770
- case "srt":
771
- case "x-subrip":
772
- return SUBTITLE_CODECS.SubRip;
773
- case "ssa":
774
- return SUBTITLE_CODECS.SubStationAlpha;
775
- case "ass":
776
- return SUBTITLE_CODECS.SubStationAlphav4;
777
- case "ttml":
778
- return SUBTITLE_CODECS.TimedTextMarkupLang;
779
- case "vtt":
780
- return SUBTITLE_CODECS.WebVTT;
781
- case "stpp":
782
- return SUBTITLE_CODECS.fTTML;
783
- case "wvtt":
784
- return SUBTITLE_CODECS.fVTT;
785
- default:
786
- throw new Error(`The MIME ${mime} is not supported as subtitle codec`);
787
- }
788
- };
789
- var parseSubtitleCodec = (codecs) => {
790
- const mimes = parseMimes(codecs);
791
- for (const mime of mimes) {
792
- try {
793
- return parseSubtitleCodecFromMime(mime);
794
- } catch (e) {
795
- continue;
796
- }
797
- }
798
- throw new Error(
799
- `No MIME types matched any supported Subtitle Codecs in ${codecs}`
800
- );
801
- };
802
- var checkIsClosedCaption = (roles = []) => {
803
- for (const role of roles) {
804
- const isClosedCaption = role.attributes.schemeIdUri === "urn:mpeg:dash:role:2011" && role.attributes.value === "caption";
805
- if (isClosedCaption) return true;
806
- }
807
- return false;
808
- };
809
- var checkIsSdh = (accessibilities = []) => {
810
- for (const accessibility of accessibilities) {
811
- const { schemeIdUri, value } = accessibility.attributes;
812
- const isSdh = schemeIdUri === "urn:tva:metadata:cs:AudioPurposeCS:2007" && value === "2";
813
- if (isSdh) return true;
814
- }
815
- return false;
816
- };
817
- var checkIsForced = (roles = []) => {
818
- for (const role of roles) {
819
- const isForced = role.attributes.schemeIdUri === "urn:mpeg:dash:role:2011" && (role.attributes.value === "forced-subtitle" || role.attributes.value === "forced_subtitle");
820
- if (isForced) return true;
821
- }
822
- return false;
823
- };
824
- var createSubtitleTrack = ({
825
- id,
826
- label,
827
- bitrate,
828
- duration,
829
- type,
830
- codec,
831
- isClosedCaption,
832
- isSdh,
833
- isForced,
834
- language,
835
- segments
836
- }) => {
837
- const parsedBitrate = parseBitrate(Number(bitrate));
838
- const size = duration ? parseSize(Number(bitrate), Number(duration)) : void 0;
839
- return {
840
- id,
841
- label,
842
- bitrate: parsedBitrate,
843
- size,
844
- type,
845
- codec,
846
- isClosedCaption,
847
- isSdh,
848
- isForced,
849
- segments,
850
- language,
851
- toString() {
852
- return ["SUBTITLE", `[${codec}]`, language].join(" | ");
853
- }
854
- };
855
- };
856
- module.exports = {
857
- parseSubtitleCodec,
858
- checkIsClosedCaption,
859
- checkIsSdh,
860
- checkIsForced,
861
- createSubtitleTrack
862
- };
863
- }
864
- });
865
-
866
- // lib/dash.js
867
- var require_dash = __commonJS({
868
- "lib/dash.js"(exports, module) {
869
- "use strict";
870
- var xml = require_xml();
871
- var { parseDuration, isLanguageTagValid } = require_util();
872
- var {
873
- parseVideoCodec,
874
- parseDynamicRange,
875
- createVideoTrack
876
- } = require_video();
877
- var {
878
- parseAudioCodec,
879
- createAudioTrack,
880
- getDolbyDigitalPlusComplexityIndex,
881
- checkIsDescriptive
882
- } = require_audio();
883
- var {
884
- parseSubtitleCodec,
885
- checkIsClosedCaption,
886
- checkIsSdh,
887
- checkIsForced,
888
- createSubtitleTrack
889
- } = require_subtitle();
890
- var {
891
- createResolutionFilter,
892
- createVideoQualityFilter,
893
- createAudioLanguageFilter,
894
- createSubtitleLanguageFilter,
895
- createVideoCodecFilter,
896
- createAudioCodecFilter,
897
- createAudioChannelsFilter
898
- } = require_track();
899
- var appendUtils = (element) => {
900
- if (!element) return element;
901
- if (Array.isArray(element)) {
902
- element.get = (name) => appendUtils(element.find((item) => item.tagName === name));
903
- } else {
904
- element.getAttr = (name) => element.attributes[name];
905
- element.getChild = (name) => {
906
- const tag = element.children.find((item) => item.tagName === name);
907
- const isString = !name && typeof element.children?.[0] === "string";
908
- return isString ? element.children[0] : appendUtils(tag);
909
- };
910
- element.set = (name, value) => element.attributes[name] = value;
911
- element.get = (name) => element.getAttr(name) || element.getChild(name);
912
- element.getNumber = (name) => Number(element.find(name));
913
- element.getAll = (name) => element.children.filter((item) => item.tagName === name).map(appendUtils);
914
- element.getBaseUrls = () => element.getAll("BaseURL").map((item) => item.children[0]);
915
- element.getBaseUrl = () => element.getBaseUrls()[0];
916
- }
917
- return element;
918
- };
919
- var combineGetters = (representation, adaptationSet) => {
920
- const prevGet = representation.get;
921
- const prevGetAll = representation.getAll;
922
- const get = (name) => prevGet(name) || adaptationSet.get(name);
923
- const getAll = (name) => [...prevGetAll(name), ...adaptationSet.getAll(name)].filter(Boolean);
924
- representation.get = get;
925
- representation.getAll = getAll;
926
- return { get, getAll };
927
- };
928
- var parseBaseUrl = (manifestUrl, mpd, period, representation) => {
929
- let base = mpd.getBaseUrl();
930
- if (!base) base = manifestUrl;
931
- else if (!base.startsWith("https://"))
932
- base = new URL(base, manifestUrl).toString();
933
- if (!!period.getBaseUrl() || !!base)
934
- base = new URL(period.getBaseUrl() || "", base).toString();
935
- const baseUrl = new URL(representation.getBaseUrl() || "", base).toString();
936
- return baseUrl;
937
- };
938
- var parseContentTypes = (representation) => {
939
- const mimeType = representation.get("mimeType");
940
- const contentType = representation.get("contentType") || mimeType?.split("/")[0];
941
- if (!contentType && !mimeType)
942
- throw new Error(
943
- "Unable to determine the format of a Representation, cannot continue..."
944
- );
945
- return { contentType, mimeType };
946
- };
947
- var parseCodecs = (representation, contentType, mimeType) => {
948
- const shouldUseCodecsFromMime = contentType === "text" && !mimeType.includes("mp4");
949
- const codecs = shouldUseCodecsFromMime ? mimeType.split("/")[1] : representation.get("codecs");
950
- return codecs;
951
- };
952
- var parseLanguage = (representation, adaptationSet, fallbackLanguage) => {
953
- let language = "";
954
- const options = [];
955
- const lang = representation.get("lang");
956
- const id = representation.get("id");
957
- if (representation) {
958
- options.push(lang);
959
- if (id) {
960
- const m = id.match(/\w+_(\w+)=\d+/);
961
- if (m && m[1]) options.push(m[1]);
962
- }
963
- }
964
- options.push(adaptationSet.get("lang"));
965
- if (fallbackLanguage) options.push(fallbackLanguage);
966
- for (const option of options) {
967
- const value = (option || "").trim();
968
- if (!isLanguageTagValid(value) || value.startsWith("und")) continue;
969
- language = value;
970
- continue;
971
- }
972
- if (!language) {
973
- }
974
- return language;
975
- };
976
- var buildSegmentUrl = (template, fields) => {
977
- let result = template;
978
- for (const [key, value] of Object.entries(fields))
979
- result = result.replace("$" + key + "$", value);
980
- return result;
981
- };
982
- var resolveSegmentTemplateUrls = (segmentTemplate, baseUrl, manifestUrl) => {
983
- for (const type of ["initialization", "media"]) {
984
- let value = segmentTemplate.get(type);
985
- if (!value) continue;
986
- if (!value.startsWith("https://")) {
987
- if (!baseUrl)
988
- throw new Error(
989
- `Resolved Segment URL is not absolute, and no Base URL is available.`
990
- );
991
- value = new URL(value, baseUrl).toString();
992
- }
993
- if (!new URL(value).search) {
994
- const manifestUrlQuery = new URL(manifestUrl).search;
995
- if (manifestUrlQuery) value += `?${manifestUrlQuery}`;
996
- }
997
- segmentTemplate.set(type, value);
998
- }
999
- };
1000
- var parseSegmentsFromTimeline = (segmentTimeline, segmentTemplate, representation, startNumber) => {
1001
- const times = [];
1002
- let currentTime = 0;
1003
- for (const s of segmentTimeline.getAll("S")) {
1004
- const t = Number(s.get("t"));
1005
- const r = Number(s.get("r") || 0);
1006
- const d = Number(s.get("d"));
1007
- if (t) currentTime = t;
1008
- for (let i = 0; i < r + 1; i++) {
1009
- times.push(currentTime);
1010
- currentTime += d;
1011
- }
1012
- }
1013
- const segments = [];
1014
- const numbers = [...Array(times.length).keys()].map((n) => n + startNumber);
1015
- for (let i = 0; i < times.length; i++) {
1016
- const t = times[i];
1017
- const n = numbers[i];
1018
- const url = buildSegmentUrl(segmentTemplate.get("media"), {
1019
- Bandwidth: representation.get("bandwidth"),
1020
- RepresentationID: representation.get("id"),
1021
- Number: n,
1022
- Time: t
1023
- });
1024
- segments.push({ url });
1025
- }
1026
- return segments;
1027
- };
1028
- var parseSegmentsFromTemplate = (segmentTemplate, baseUrl, manifestUrl, duration, representation) => {
1029
- const startNumber = Number(segmentTemplate.get("startNumber") || 1);
1030
- const segmentTimeline = segmentTemplate.get("SegmentTimeline");
1031
- resolveSegmentTemplateUrls(segmentTemplate, baseUrl, manifestUrl);
1032
- const segmentDuration = parseFloat(segmentTemplate.get("duration"));
1033
- const segmentTimescale = parseFloat(segmentTemplate.get("timescale") || 1);
1034
- const DEFAULT_SEGMENTS_COUNT = 35;
1035
- const segmentsCount = duration ? Math.ceil(duration / (segmentDuration / segmentTimescale)) : DEFAULT_SEGMENTS_COUNT;
1036
- const bandwidth = representation.get("bandwidth");
1037
- const id = representation.get("id");
1038
- const segments = [];
1039
- if (segmentTimeline) {
1040
- segments.push(
1041
- ...parseSegmentsFromTimeline(
1042
- segmentTimeline,
1043
- segmentTemplate,
1044
- representation,
1045
- startNumber
1046
- )
1047
- );
1048
- } else {
1049
- for (let i = startNumber; i < startNumber + segmentsCount; i++) {
1050
- const url = buildSegmentUrl(segmentTemplate.get("media"), {
1051
- Bandwidth: bandwidth,
1052
- RepresentationID: id,
1053
- Number: i,
1054
- Time: i
1055
- });
1056
- segments.push({ url });
1057
- }
1058
- }
1059
- const initialization = segmentTemplate.get("initialization");
1060
- if (initialization) {
1061
- const url = buildSegmentUrl(initialization, {
1062
- Bandwidth: bandwidth,
1063
- RepresentationID: id
1064
- });
1065
- segments.unshift({ url, init: true });
1066
- }
1067
- return segments;
1068
- };
1069
- var parseSegmentsFromList = (segmentList, baseUrl) => {
1070
- const segmentUrls = segmentList.get("SegmentURL");
1071
- const segments = [];
1072
- for (const segmentUrl of segmentUrls) {
1073
- let mediaUrl = segmentUrl.get("media");
1074
- if (!mediaUrl) mediaUrl = baseUrl;
1075
- else if (!mediaUrl.startsWith("https://"))
1076
- mediaUrl = new URL(mediaUrl, baseUrl).toString();
1077
- segments.push({ url: mediaUrl, range: segmentUrl.get("mediaRange") });
1078
- }
1079
- return segments;
1080
- };
1081
- var parseSegmentFromBase = async (segmentBase, baseUrl) => {
1082
- const initialization = segmentBase.get("Initialization");
1083
- let mediaRange = "";
1084
- if (initialization) {
1085
- }
1086
- return { url: baseUrl, range: mediaRange };
1087
- };
1088
- var transformSegmentUrls = (segments) => {
1089
- for (const segment of segments) {
1090
- const hasHtmlEscapeCode = segment.url.includes("&amp;");
1091
- if (hasHtmlEscapeCode) {
1092
- const url = new URL(segment.url);
1093
- const entries = new URLSearchParams(
1094
- url.searchParams.toString()
1095
- ).entries();
1096
- for (const [key, value] of entries) {
1097
- url.searchParams.delete(key);
1098
- url.searchParams.append(key.replaceAll("amp;", ""), value);
1099
- }
1100
- segment.url = url.toString();
1101
- }
1102
- }
1103
- };
1104
- var protectionSchemas = {
1105
- "urn:mpeg:dash:mp4protection:2011": "common",
1106
- "urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95": "playready",
1107
- "urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed": "widevine"
1108
- };
1109
- var parseContentProtection = (contentProtections) => {
1110
- const protection = {};
1111
- for (const contentProtection of contentProtections) {
1112
- const id = contentProtection.get("schemeIdUri")?.toLowerCase();
1113
- const value = contentProtection.get("value");
1114
- const pssh = contentProtection.get("cenc:pssh")?.get();
1115
- const defaultKeyId = contentProtection.get("cenc:default_KID");
1116
- const data = { id, value, pssh, defaultKeyId };
1117
- protection[protectionSchemas[id]] = data;
1118
- }
1119
- return protection;
1120
- };
1121
- var parseManifest = async (text, url, fallbackLanguage) => {
1122
- const mpd = appendUtils(xml.parse(text)).get("MPD");
1123
- const period = mpd.get("Period");
1124
- const durationString = period.get("duration") || mpd.get("mediaPresentationDuration");
1125
- const duration = parseDuration(durationString);
1126
- const videos = [];
1127
- const audios = [];
1128
- const subtitles = [];
1129
- for (const adaptationSet of period.getAll("AdaptationSet")) {
1130
- for (const representation of adaptationSet.getAll("Representation")) {
1131
- const { get, getAll } = combineGetters(representation, adaptationSet);
1132
- const { contentType, mimeType } = parseContentTypes(representation);
1133
- const codecs = parseCodecs(representation, contentType, mimeType);
1134
- const language = parseLanguage(
1135
- representation,
1136
- adaptationSet,
1137
- fallbackLanguage
1138
- );
1139
- const baseUrl = parseBaseUrl(url, mpd, period, representation);
1140
- const segmentTemplate = get("SegmentTemplate");
1141
- const segmentList = get("SegmentList");
1142
- const segmentBase = get("SegmentBase");
1143
- const segments = [];
1144
- if (segmentTemplate) {
1145
- const segmentsFromTemplate = parseSegmentsFromTemplate(
1146
- segmentTemplate,
1147
- baseUrl,
1148
- url,
1149
- duration,
1150
- representation
1151
- );
1152
- segments.push(...segmentsFromTemplate);
1153
- } else if (segmentList) {
1154
- const segmentsFromList = parseSegmentsFromList(segmentList, baseUrl);
1155
- segments.push(...segmentsFromList);
1156
- } else if (segmentBase) {
1157
- const segmentFromBase = await parseSegmentFromBase(
1158
- segmentBase,
1159
- baseUrl
1160
- );
1161
- segments.push(segmentFromBase);
1162
- } else if (baseUrl) {
1163
- segments.push({ url: baseUrl });
1164
- } else {
1165
- throw new Error(
1166
- "Could not find a way to get segments from this MPD manifest."
1167
- );
1168
- }
1169
- transformSegmentUrls(segments);
1170
- const label = get("label");
1171
- const fps = get("frameRate") ?? segmentBase?.attributes.timescale;
1172
- const width = get("width") ?? 0;
1173
- const height = get("height") ?? 0;
1174
- const bitrate = get("bandwidth");
1175
- const supplementalProps = getAll("SupplementalProperty");
1176
- const essentialProps = getAll("EssentialProperty");
1177
- const accessibilities = adaptationSet.getAll("Accessibility");
1178
- const roles = adaptationSet.getAll("Role");
1179
- const contentProtections = getAll("ContentProtection");
1180
- const id = [
1181
- new URL(baseUrl).hostname,
1182
- contentType,
1183
- codecs,
1184
- bitrate,
1185
- language,
1186
- mpd.get("id"),
1187
- period.get("id"),
1188
- get("id"),
1189
- get("audioTrackId")
1190
- ].filter(Boolean).join("-").replaceAll("/", "-");
1191
- switch (contentType) {
1192
- case "video": {
1193
- const track = createVideoTrack({
1194
- id,
1195
- label,
1196
- type: contentType,
1197
- codec: parseVideoCodec(codecs),
1198
- dynamicRange: parseDynamicRange(
1199
- codecs,
1200
- supplementalProps,
1201
- essentialProps
1202
- ),
1203
- contentProtection: parseContentProtection(contentProtections),
1204
- bitrate,
1205
- duration,
1206
- width,
1207
- height,
1208
- fps,
1209
- language,
1210
- segments
1211
- });
1212
- videos.push(track);
1213
- break;
1214
- }
1215
- case "audio": {
1216
- const track = createAudioTrack({
1217
- id,
1218
- label,
1219
- type: contentType,
1220
- codec: parseAudioCodec(codecs),
1221
- channels: get("AudioChannelConfiguration")?.get("value"),
1222
- jointObjectCoding: getDolbyDigitalPlusComplexityIndex(supplementalProps),
1223
- isDescriptive: checkIsDescriptive(accessibilities),
1224
- bitrate,
1225
- duration,
1226
- language,
1227
- segments
1228
- });
1229
- audios.push(track);
1230
- break;
1231
- }
1232
- case "text": {
1233
- const track = createSubtitleTrack({
1234
- id,
1235
- label,
1236
- type: contentType,
1237
- codec: parseSubtitleCodec(codecs || "vtt"),
1238
- isClosedCaption: checkIsClosedCaption(roles),
1239
- isSdh: checkIsSdh(accessibilities),
1240
- isForced: checkIsForced(roles),
1241
- bitrate,
1242
- duration,
1243
- language,
1244
- segments
1245
- });
1246
- subtitles.push(track);
1247
- break;
1248
- }
1249
- case "image":
1250
- break;
1251
- default:
1252
- throw new Error(`Unknown content type: ${contentType}`);
1253
- }
1254
- }
1255
- }
1256
- videos.sort((a, b) => b.bitrate.bps - a.bitrate.bps);
1257
- return {
1258
- duration,
1259
- tracks: {
1260
- all: videos.concat(audios).concat(subtitles),
1261
- videos,
1262
- audios,
1263
- subtitles,
1264
- withResolution: createResolutionFilter(videos),
1265
- withVideoCodecs: createVideoCodecFilter(videos),
1266
- withVideoQuality: createVideoQualityFilter(videos),
1267
- withAudioCodecs: createAudioCodecFilter(audios),
1268
- withAudioLanguages: createAudioLanguageFilter(audios),
1269
- withAudioChannels: createAudioChannelsFilter(audios),
1270
- withSubtitleLanguages: createSubtitleLanguageFilter(subtitles)
1271
- }
1272
- };
1273
- };
1274
- module.exports = { parseManifest };
1275
- }
1276
- });
1277
-
1278
- // lib/hls.js
1279
- var require_hls = __commonJS({
1280
- "lib/hls.js"(exports, module) {
1281
- "use strict";
1282
- var { dirname, basename } = __require("node:path");
1283
- var m3u8Parser = __require("m3u8-parser");
1284
- var { parseBitrate, getQualityLabel } = require_util();
1285
- var {
1286
- createResolutionFilter,
1287
- createVideoQualityFilter,
1288
- createAudioLanguageFilter,
1289
- createSubtitleLanguageFilter,
1290
- createVideoCodecFilter,
1291
- createAudioCodecFilter,
1292
- createAudioChannelsFilter
1293
- } = require_track();
1294
- var { createAudioTrack } = require_audio();
1295
- var { createVideoTrack } = require_video();
1296
- var parseM3u8 = (manifestString) => {
1297
- const parser = new m3u8Parser.Parser();
1298
- parser.push(manifestString);
1299
- parser.end();
1300
- return parser.manifest;
1301
- };
1302
- var fetchPlaylist = async (url) => {
1303
- const response = await fetch(url);
1304
- if (!response.ok)
1305
- throw new Error(`Failed to fetch playlist (${response.status}): ${url}`);
1306
- const text = await response.text();
1307
- return parseM3u8(text);
1308
- };
1309
- var parseUrl = (playlistUri, manifestUri) => {
1310
- let value = playlistUri;
1311
- if (!value.startsWith("https://"))
1312
- value = new URL(value, manifestUri).toString() + new URL(manifestUri).search;
1313
- return value;
1314
- };
1315
- var urlsSame = (url1, url2) => {
1316
- return new URL(url1).pathname === new URL(url2).pathname;
1317
- };
1318
- var parseMediaGroup = (groups, manifestUri) => {
1319
- const results = [];
1320
- if (!groups) return results;
1321
- for (const [groupId, group] of Object.entries(groups)) {
1322
- for (const [label, entity] of Object.entries(group)) {
1323
- const url = parseUrl(entity.uri, manifestUri);
1324
- const existing = results.find((result) => urlsSame(result.url, url));
1325
- if (!existing)
1326
- results.push({
1327
- groupId,
1328
- id: entity.uri.replace("/", ""),
1329
- type: groupId,
1330
- label,
1331
- language: entity.language,
1332
- url,
1333
- default: entity.default
1334
- });
1335
- }
1336
- }
1337
- return results;
1338
- };
1339
- var getAudioPlaylists = (m3u8, manifestUri) => {
1340
- if (!m3u8.mediaGroups) return [];
1341
- return parseMediaGroup(m3u8.mediaGroups.AUDIO, manifestUri);
1342
- };
1343
- var getSubtitlePlaylists = (m3u8, manifestUri) => {
1344
- if (!m3u8.mediaGroups) return [];
1345
- return parseMediaGroup(m3u8.mediaGroups.SUBTITLES, manifestUri);
1346
- };
1347
- var getVideoPlaylists = (m3u8, manifestUri) => {
1348
- if (!m3u8.playlists) return [];
1349
- return m3u8.playlists.map((data) => {
1350
- const bandwidth = data.attributes?.BANDWIDTH;
1351
- const url = data.resolvedUri || parseUrl(data.uri, manifestUri);
1352
- const track = {
1353
- id: data.uri.replace("/", ""),
1354
- bitrate: parseBitrate(bandwidth),
1355
- url
1356
- };
1357
- track.type = "video";
1358
- if (data.attributes.RESOLUTION) {
1359
- track.resolution = data.attributes.RESOLUTION;
1360
- track.quality = getQualityLabel(track.resolution);
1361
- }
1362
- if (data.attributes["VIDEO-RANGE"])
1363
- track.dynamicRange = data.attributes["VIDEO-RANGE"];
1364
- if (data.attributes.CODECS) track.codecs = data.attributes.CODECS;
1365
- if (data.attributes["FRAME-RATE"])
1366
- track.frameRate = data.attributes["FRAME-RATE"];
1367
- return track;
1368
- });
1369
- };
1370
- var segmentsDto = (data = [], track) => {
1371
- const mapSegment = (item) => {
1372
- let url = item.resolvedUri || item.uri;
1373
- if (!url.startsWith("https://") && track.url) {
1374
- const baseUrl = dirname(track.url) + "/";
1375
- url = new URL(url, baseUrl).toString();
1376
- }
1377
- return {
1378
- url,
1379
- duration: item.duration,
1380
- number: item.number,
1381
- presentationTime: item.presentationTime
1382
- };
1383
- };
1384
- const segments = data.map(mapSegment);
1385
- const init = data[0].map;
1386
- if (data.length && (init?.resolvedUri || init?.uri)) {
1387
- const url = init?.resolvedUri || parseUrl(init.uri, track.url);
1388
- segments.unshift({
1389
- url,
1390
- init: true,
1391
- duration: 0,
1392
- number: 0,
1393
- presentationTime: 0
1394
- });
1395
- }
1396
- return segments;
1397
- };
1398
- var parseSegments = (playlist, track) => {
1399
- track.segments = segmentsDto(playlist.segments, track);
1400
- if (playlist.contentProtection) {
1401
- track.protection = {};
1402
- const fairplayLegacy = playlist.contentProtection["com.apple.fps.1_0"];
1403
- if (fairplayLegacy)
1404
- track.protection.fairplay = {
1405
- keyFormat: fairplayLegacy.attributes.KEYFORMAT,
1406
- uri: fairplayLegacy.attributes.URI,
1407
- method: fairplayLegacy.attributes.METHOD
1408
- };
1409
- const widevine = playlist.contentProtection["com.widevine.alpha"];
1410
- if (widevine) {
1411
- track.protection.widevine = {
1412
- pssh: widevine.pssh,
1413
- uri: widevine.attributes.schemeIdUri,
1414
- keyId: widevine.attributes.keyId
1415
- };
1416
- }
1417
- }
1418
- };
1419
- var fetchTrackSegments = (tracks) => {
1420
- return Promise.all(
1421
- tracks.map(async (track) => {
1422
- const playlist = await fetchPlaylist(track.url);
1423
- parseSegments(playlist, track);
1424
- })
1425
- );
1426
- };
1427
- var parseManifest = async (manifestString, manifestUri) => {
1428
- const m3u8 = parseM3u8(manifestString);
1429
- const videos = getVideoPlaylists(m3u8, manifestUri);
1430
- const audios = getAudioPlaylists(m3u8, manifestUri);
1431
- const subtitles = getSubtitlePlaylists(m3u8, manifestUri);
1432
- if (!m3u8.playlists && m3u8.segments) {
1433
- const { pathname } = new URL(manifestUri);
1434
- const isAudio = pathname.includes(".m4a") || pathname.includes(".mp3") || pathname.includes(".opus");
1435
- if (isAudio) {
1436
- const track = createAudioTrack({
1437
- id: "audio" + basename(pathname),
1438
- label: "audio",
1439
- type: "audio",
1440
- codec: "",
1441
- channels: 2,
1442
- jointObjectCoding: "",
1443
- isDescriptive: false,
1444
- bitrate: NaN,
1445
- duration: NaN,
1446
- language: ""
1447
- });
1448
- parseSegments(m3u8, track);
1449
- audios.push(track);
1450
- } else {
1451
- const track = createVideoTrack({
1452
- id: "video" + basename(pathname),
1453
- label: "video",
1454
- type: "video",
1455
- codec: "",
1456
- dynamicRange: "",
1457
- contentProtection: "",
1458
- bitrate: NaN,
1459
- duration: NaN,
1460
- width: NaN,
1461
- height: NaN,
1462
- fps: NaN,
1463
- language: ""
1464
- });
1465
- parseSegments(m3u8, track);
1466
- videos.push(track);
1467
- }
1468
- } else {
1469
- await Promise.all([
1470
- fetchTrackSegments(videos),
1471
- fetchTrackSegments(audios),
1472
- fetchTrackSegments(subtitles)
1473
- ]);
1474
- }
1475
- const manifest = {
1476
- tracks: {
1477
- all: videos.concat(audios).concat(subtitles),
1478
- videos,
1479
- audios,
1480
- subtitles,
1481
- withResolution: createResolutionFilter(videos),
1482
- withVideoCodecs: createVideoCodecFilter(videos),
1483
- withVideoQuality: createVideoQualityFilter(videos),
1484
- withAudioCodecs: createAudioCodecFilter(audios),
1485
- withAudioLanguages: createAudioLanguageFilter(audios),
1486
- withAudioChannels: createAudioChannelsFilter(audios),
1487
- withSubtitleLanguages: createSubtitleLanguageFilter(subtitles)
1488
- }
1489
- };
1490
- return manifest;
1491
- };
1492
- module.exports = { parseManifest };
1493
- }
1494
- });
1495
-
1496
- // dasha.js
1497
- var require_dasha = __commonJS({
1498
- "dasha.js"(exports, module) {
1499
- var dash = require_dash();
1500
- var hls = require_hls();
1501
- var {
1502
- filterByResolution,
1503
- filterByQuality,
1504
- filterByCodecs,
1505
- filterByLanguages,
1506
- filterByChannels
1507
- } = require_track();
1508
- var parse = (text, url, fallbackLanguage) => {
1509
- if (text.includes("<MPD"))
1510
- return dash.parseManifest(text, url, fallbackLanguage);
1511
- else if (text.includes("#EXTM3U")) return hls.parseManifest(text, url);
1512
- else throw new Error("Invalid manifest");
1513
- };
1514
- module.exports = {
1515
- parse,
1516
- filterByResolution,
1517
- filterByQuality,
1518
- filterByCodecs,
1519
- filterByLanguages,
1520
- filterByChannels
1521
- };
1522
- }
1523
- });
1524
- export default require_dasha();