hls.js 1.5.12-0.canary.10338 → 1.5.12-0.canary.10341

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/hls.js CHANGED
@@ -463,14 +463,151 @@
463
463
  return ErrorDetails;
464
464
  }({});
465
465
 
466
+ var Logger = function Logger(label, logger) {
467
+ this.trace = void 0;
468
+ this.debug = void 0;
469
+ this.log = void 0;
470
+ this.warn = void 0;
471
+ this.info = void 0;
472
+ this.error = void 0;
473
+ var lb = "[" + label + "]:";
474
+ this.trace = noop;
475
+ this.debug = logger.debug.bind(null, lb);
476
+ this.log = logger.log.bind(null, lb);
477
+ this.warn = logger.warn.bind(null, lb);
478
+ this.info = logger.info.bind(null, lb);
479
+ this.error = logger.error.bind(null, lb);
480
+ };
481
+ var noop = function noop() {};
482
+ var fakeLogger = {
483
+ trace: noop,
484
+ debug: noop,
485
+ log: noop,
486
+ warn: noop,
487
+ info: noop,
488
+ error: noop
489
+ };
490
+ function createLogger() {
491
+ return _extends({}, fakeLogger);
492
+ }
493
+
494
+ // let lastCallTime;
495
+ // function formatMsgWithTimeInfo(type, msg) {
496
+ // const now = Date.now();
497
+ // const diff = lastCallTime ? '+' + (now - lastCallTime) : '0';
498
+ // lastCallTime = now;
499
+ // msg = (new Date(now)).toISOString() + ' | [' + type + '] > ' + msg + ' ( ' + diff + ' ms )';
500
+ // return msg;
501
+ // }
502
+
503
+ function consolePrintFn(type, id) {
504
+ var func = self.console[type];
505
+ return func ? func.bind(self.console, ('') + "[" + type + "] >") : noop;
506
+ }
507
+ function getLoggerFn(key, debugConfig, id) {
508
+ return debugConfig[key] ? debugConfig[key].bind(debugConfig) : consolePrintFn(key);
509
+ }
510
+ var exportedLogger = createLogger();
511
+ function enableLogs(debugConfig, context, id) {
512
+ // check that console is available
513
+ var newLogger = createLogger();
514
+ if (typeof console === 'object' && debugConfig === true || typeof debugConfig === 'object') {
515
+ var keys = [
516
+ // Remove out from list here to hard-disable a log-level
517
+ // 'trace',
518
+ 'debug', 'log', 'info', 'warn', 'error'];
519
+ keys.forEach(function (key) {
520
+ newLogger[key] = getLoggerFn(key, debugConfig);
521
+ });
522
+ // Some browsers don't allow to use bind on console object anyway
523
+ // fallback to default if needed
524
+ try {
525
+ newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.12-0.canary.10341");
526
+ } catch (e) {
527
+ /* log fn threw an exception. All logger methods are no-ops. */
528
+ return createLogger();
529
+ }
530
+ // global exported logger uses the same functions as new logger without `id`
531
+ keys.forEach(function (key) {
532
+ exportedLogger[key] = getLoggerFn(key, debugConfig);
533
+ });
534
+ } else {
535
+ // Reset global exported logger
536
+ _extends(exportedLogger, newLogger);
537
+ }
538
+ return newLogger;
539
+ }
540
+ var logger = exportedLogger;
541
+
542
+ var VARIABLE_REPLACEMENT_REGEX = /\{\$([a-zA-Z0-9-_]+)\}/g;
543
+ function hasVariableReferences(str) {
544
+ return VARIABLE_REPLACEMENT_REGEX.test(str);
545
+ }
546
+ function substituteVariables(parsed, value) {
547
+ if (parsed.variableList !== null || parsed.hasVariableRefs) {
548
+ var variableList = parsed.variableList;
549
+ return value.replace(VARIABLE_REPLACEMENT_REGEX, function (variableReference) {
550
+ var variableName = variableReference.substring(2, variableReference.length - 1);
551
+ var variableValue = variableList == null ? void 0 : variableList[variableName];
552
+ if (variableValue === undefined) {
553
+ parsed.playlistParsingError || (parsed.playlistParsingError = new Error("Missing preceding EXT-X-DEFINE tag for Variable Reference: \"" + variableName + "\""));
554
+ return variableReference;
555
+ }
556
+ return variableValue;
557
+ });
558
+ }
559
+ return value;
560
+ }
561
+ function addVariableDefinition(parsed, attr, parentUrl) {
562
+ var variableList = parsed.variableList;
563
+ if (!variableList) {
564
+ parsed.variableList = variableList = {};
565
+ }
566
+ var NAME;
567
+ var VALUE;
568
+ if ('QUERYPARAM' in attr) {
569
+ NAME = attr.QUERYPARAM;
570
+ try {
571
+ var searchParams = new self.URL(parentUrl).searchParams;
572
+ if (searchParams.has(NAME)) {
573
+ VALUE = searchParams.get(NAME);
574
+ } else {
575
+ throw new Error("\"" + NAME + "\" does not match any query parameter in URI: \"" + parentUrl + "\"");
576
+ }
577
+ } catch (error) {
578
+ parsed.playlistParsingError || (parsed.playlistParsingError = new Error("EXT-X-DEFINE QUERYPARAM: " + error.message));
579
+ }
580
+ } else {
581
+ NAME = attr.NAME;
582
+ VALUE = attr.VALUE;
583
+ }
584
+ if (NAME in variableList) {
585
+ parsed.playlistParsingError || (parsed.playlistParsingError = new Error("EXT-X-DEFINE duplicate Variable Name declarations: \"" + NAME + "\""));
586
+ } else {
587
+ variableList[NAME] = VALUE || '';
588
+ }
589
+ }
590
+ function importVariableDefinition(parsed, attr, sourceVariableList) {
591
+ var IMPORT = attr.IMPORT;
592
+ if (sourceVariableList && IMPORT in sourceVariableList) {
593
+ var variableList = parsed.variableList;
594
+ if (!variableList) {
595
+ parsed.variableList = variableList = {};
596
+ }
597
+ variableList[IMPORT] = sourceVariableList[IMPORT];
598
+ } else {
599
+ parsed.playlistParsingError || (parsed.playlistParsingError = new Error("EXT-X-DEFINE IMPORT attribute not found in Multivariant Playlist: \"" + IMPORT + "\""));
600
+ }
601
+ }
602
+
466
603
  var DECIMAL_RESOLUTION_REGEX = /^(\d+)x(\d+)$/;
467
604
  var ATTR_LIST_REGEX = /(.+?)=(".*?"|.*?)(?:,|$)/g;
468
605
 
469
606
  // adapted from https://github.com/kanongil/node-m3u8parse/blob/master/attrlist.js
470
607
  var AttrList = /*#__PURE__*/function () {
471
- function AttrList(attrs) {
608
+ function AttrList(attrs, parsed) {
472
609
  if (typeof attrs === 'string') {
473
- attrs = AttrList.parseAttrList(attrs);
610
+ attrs = AttrList.parseAttrList(attrs, parsed);
474
611
  }
475
612
  _extends(this, attrs);
476
613
  }
@@ -512,6 +649,13 @@
512
649
  _proto.enumeratedString = function enumeratedString(attrName) {
513
650
  return this[attrName];
514
651
  };
652
+ _proto.enumeratedStringList = function enumeratedStringList(attrName, dict) {
653
+ var attrValue = this[attrName];
654
+ return (attrValue ? attrValue.split(/[ ,]+/) : []).reduce(function (result, identifier) {
655
+ result[identifier.toLowerCase()] = true;
656
+ return result;
657
+ }, dict);
658
+ };
515
659
  _proto.bool = function bool(attrName) {
516
660
  return this[attrName] === 'YES';
517
661
  };
@@ -525,17 +669,75 @@
525
669
  height: parseInt(res[2], 10)
526
670
  };
527
671
  };
528
- AttrList.parseAttrList = function parseAttrList(input) {
672
+ AttrList.parseAttrList = function parseAttrList(input, parsed) {
529
673
  var match;
530
674
  var attrs = {};
531
675
  var quote = '"';
532
676
  ATTR_LIST_REGEX.lastIndex = 0;
533
677
  while ((match = ATTR_LIST_REGEX.exec(input)) !== null) {
678
+ var name = match[1].trim();
534
679
  var value = match[2];
535
- if (value.indexOf(quote) === 0 && value.lastIndexOf(quote) === value.length - 1) {
680
+ var quotedString = value.indexOf(quote) === 0 && value.lastIndexOf(quote) === value.length - 1;
681
+ var hexadecimalSequence = false;
682
+ if (quotedString) {
536
683
  value = value.slice(1, -1);
684
+ } else {
685
+ switch (name) {
686
+ case 'IV':
687
+ case 'SCTE35-CMD':
688
+ case 'SCTE35-IN':
689
+ case 'SCTE35-OUT':
690
+ hexadecimalSequence = true;
691
+ }
692
+ }
693
+ if (parsed && (quotedString || hexadecimalSequence)) {
694
+ {
695
+ value = substituteVariables(parsed, value);
696
+ }
697
+ } else if (!hexadecimalSequence && !quotedString) {
698
+ switch (name) {
699
+ case 'CLOSED-CAPTIONS':
700
+ if (value === 'NONE') {
701
+ break;
702
+ }
703
+ // falls through
704
+ case 'ALLOWED-CPC':
705
+ case 'CLASS':
706
+ case 'ASSOC-LANGUAGE':
707
+ case 'AUDIO':
708
+ case 'BYTERANGE':
709
+ case 'CHANNELS':
710
+ case 'CHARACTERISTICS':
711
+ case 'CODECS':
712
+ case 'DATA-ID':
713
+ case 'END-DATE':
714
+ case 'GROUP-ID':
715
+ case 'ID':
716
+ case 'IMPORT':
717
+ case 'INSTREAM-ID':
718
+ case 'KEYFORMAT':
719
+ case 'KEYFORMATVERSIONS':
720
+ case 'LANGUAGE':
721
+ case 'NAME':
722
+ case 'PATHWAY-ID':
723
+ case 'QUERYPARAM':
724
+ case 'RECENTLY-REMOVED-DATERANGES':
725
+ case 'SERVER-URI':
726
+ case 'STABLE-RENDITION-ID':
727
+ case 'STABLE-VARIANT-ID':
728
+ case 'START-DATE':
729
+ case 'SUBTITLES':
730
+ case 'SUPPLEMENTAL-CODECS':
731
+ case 'URI':
732
+ case 'VALUE':
733
+ case 'VIDEO':
734
+ case 'X-ASSET-LIST':
735
+ case 'X-ASSET-URI':
736
+ // Since we are not checking tag:attribute combination, just warn rather than ignoring attribute
737
+ logger.warn(input + ": attribute " + name + " is missing quotes");
738
+ // continue;
739
+ }
537
740
  }
538
- var name = match[1].trim();
539
741
  attrs[name] = value;
540
742
  }
541
743
  return attrs;
@@ -550,96 +752,30 @@
550
752
  }]);
551
753
  }();
552
754
 
553
- var Logger = function Logger(label, logger) {
554
- this.trace = void 0;
555
- this.debug = void 0;
556
- this.log = void 0;
557
- this.warn = void 0;
558
- this.info = void 0;
559
- this.error = void 0;
560
- var lb = "[" + label + "]:";
561
- this.trace = noop;
562
- this.debug = logger.debug.bind(null, lb);
563
- this.log = logger.log.bind(null, lb);
564
- this.warn = logger.warn.bind(null, lb);
565
- this.info = logger.info.bind(null, lb);
566
- this.error = logger.error.bind(null, lb);
567
- };
568
- var noop = function noop() {};
569
- var fakeLogger = {
570
- trace: noop,
571
- debug: noop,
572
- log: noop,
573
- warn: noop,
574
- info: noop,
575
- error: noop
576
- };
577
- function createLogger() {
578
- return _extends({}, fakeLogger);
579
- }
580
-
581
- // let lastCallTime;
582
- // function formatMsgWithTimeInfo(type, msg) {
583
- // const now = Date.now();
584
- // const diff = lastCallTime ? '+' + (now - lastCallTime) : '0';
585
- // lastCallTime = now;
586
- // msg = (new Date(now)).toISOString() + ' | [' + type + '] > ' + msg + ' ( ' + diff + ' ms )';
587
- // return msg;
588
- // }
589
-
590
- function consolePrintFn(type, id) {
591
- var func = self.console[type];
592
- return func ? func.bind(self.console, ('') + "[" + type + "] >") : noop;
593
- }
594
- function getLoggerFn(key, debugConfig, id) {
595
- return debugConfig[key] ? debugConfig[key].bind(debugConfig) : consolePrintFn(key);
596
- }
597
- var exportedLogger = createLogger();
598
- function enableLogs(debugConfig, context, id) {
599
- // check that console is available
600
- var newLogger = createLogger();
601
- if (typeof console === 'object' && debugConfig === true || typeof debugConfig === 'object') {
602
- var keys = [
603
- // Remove out from list here to hard-disable a log-level
604
- // 'trace',
605
- 'debug', 'log', 'info', 'warn', 'error'];
606
- keys.forEach(function (key) {
607
- newLogger[key] = getLoggerFn(key, debugConfig);
608
- });
609
- // Some browsers don't allow to use bind on console object anyway
610
- // fallback to default if needed
611
- try {
612
- newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.12-0.canary.10338");
613
- } catch (e) {
614
- /* log fn threw an exception. All logger methods are no-ops. */
615
- return createLogger();
616
- }
617
- // global exported logger uses the same functions as new logger without `id`
618
- keys.forEach(function (key) {
619
- exportedLogger[key] = getLoggerFn(key, debugConfig);
620
- });
621
- } else {
622
- // Reset global exported logger
623
- _extends(exportedLogger, newLogger);
624
- }
625
- return newLogger;
626
- }
627
- var logger = exportedLogger;
628
-
629
755
  // Avoid exporting const enum so that these values can be inlined
630
756
 
757
+ var CLASS_INTERSTITIAL = 'com.apple.hls.interstitial';
631
758
  function isDateRangeCueAttribute(attrName) {
632
- return attrName !== "ID" && attrName !== "CLASS" && attrName !== "START-DATE" && attrName !== "DURATION" && attrName !== "END-DATE" && attrName !== "END-ON-NEXT";
759
+ return attrName !== "ID" && attrName !== "CLASS" && attrName !== "CUE" && attrName !== "START-DATE" && attrName !== "DURATION" && attrName !== "END-DATE" && attrName !== "END-ON-NEXT";
633
760
  }
634
761
  function isSCTE35Attribute(attrName) {
635
- return attrName === "SCTE35-OUT" || attrName === "SCTE35-IN";
762
+ return attrName === "SCTE35-OUT" || attrName === "SCTE35-IN" || attrName === "SCTE35-CMD";
636
763
  }
637
764
  var DateRange = /*#__PURE__*/function () {
638
- function DateRange(dateRangeAttr, dateRangeWithSameId) {
765
+ function DateRange(dateRangeAttr, dateRangeWithSameId, tagCount) {
766
+ var _dateRangeWithSameId$;
767
+ if (tagCount === void 0) {
768
+ tagCount = 0;
769
+ }
639
770
  this.attr = void 0;
771
+ this.tagAnchor = void 0;
772
+ this.tagOrder = void 0;
640
773
  this._startDate = void 0;
641
774
  this._endDate = void 0;
775
+ this._cue = void 0;
642
776
  this._badValueForSameId = void 0;
777
+ this.tagAnchor = (dateRangeWithSameId == null ? void 0 : dateRangeWithSameId.tagAnchor) || null;
778
+ this.tagOrder = (_dateRangeWithSameId$ = dateRangeWithSameId == null ? void 0 : dateRangeWithSameId.tagOrder) != null ? _dateRangeWithSameId$ : tagCount;
643
779
  if (dateRangeWithSameId) {
644
780
  var previousAttr = dateRangeWithSameId.attr;
645
781
  for (var key in previousAttr) {
@@ -653,9 +789,9 @@
653
789
  dateRangeAttr = _extends(new AttrList({}), previousAttr, dateRangeAttr);
654
790
  }
655
791
  this.attr = dateRangeAttr;
656
- this._startDate = new Date(dateRangeAttr["START-DATE"]);
792
+ this._startDate = dateRangeWithSameId ? dateRangeWithSameId.startDate : new Date(dateRangeAttr["START-DATE"]);
657
793
  if ("END-DATE" in this.attr) {
658
- var endDate = new Date(this.attr["END-DATE"]);
794
+ var endDate = (dateRangeWithSameId == null ? void 0 : dateRangeWithSameId.endDate) || new Date(this.attr["END-DATE"]);
659
795
  if (isFiniteNumber(endDate.getTime())) {
660
796
  this._endDate = endDate;
661
797
  }
@@ -671,6 +807,30 @@
671
807
  get: function get() {
672
808
  return this.attr.CLASS;
673
809
  }
810
+ }, {
811
+ key: "cue",
812
+ get: function get() {
813
+ var _cue = this._cue;
814
+ if (_cue === undefined) {
815
+ return this._cue = this.attr.enumeratedStringList(this.attr.CUE ? 'CUE' : 'X-CUE', {
816
+ pre: false,
817
+ post: false,
818
+ once: false
819
+ });
820
+ }
821
+ return _cue;
822
+ }
823
+ }, {
824
+ key: "startTime",
825
+ get: function get() {
826
+ var tagAnchor = this.tagAnchor;
827
+ // eslint-disable-next-line @typescript-eslint/prefer-optional-chain
828
+ if (tagAnchor === null || tagAnchor.programDateTime === null) {
829
+ logger.warn("Expected tagAnchor Fragment with PDT set for DateRange \"" + this.id + "\": " + tagAnchor);
830
+ return NaN;
831
+ }
832
+ return tagAnchor.start + (this.startDate.getTime() - tagAnchor.programDateTime) / 1000;
833
+ }
674
834
  }, {
675
835
  key: "startDate",
676
836
  get: function get() {
@@ -714,10 +874,15 @@
714
874
  get: function get() {
715
875
  return this.attr.bool("END-ON-NEXT");
716
876
  }
877
+ }, {
878
+ key: "isInterstitial",
879
+ get: function get() {
880
+ return this.class === CLASS_INTERSTITIAL;
881
+ }
717
882
  }, {
718
883
  key: "isValid",
719
884
  get: function get() {
720
- return !!this.id && !this._badValueForSameId && isFiniteNumber(this.startDate.getTime()) && (this.duration === null || this.duration >= 0) && (!this.endOnNext || !!this.class);
885
+ return !!this.id && !this._badValueForSameId && isFiniteNumber(this.startDate.getTime()) && (this.duration === null || this.duration >= 0) && (!this.endOnNext || !!this.class) && (!this.attr.CUE || !this.cue.pre && !this.cue.post || this.cue.pre !== this.cue.post) && (!this.isInterstitial || 'X-ASSET-URI' in this.attr || 'X-ASSET-LIST' in this.attr);
721
886
  }
722
887
  }]);
723
888
  }();
@@ -809,7 +974,6 @@
809
974
  }
810
975
  }]);
811
976
  }();
812
-
813
977
  /**
814
978
  * Object representing parsed data from an HLS Segment. Found in {@link hls.js#LevelDetails.fragments}.
815
979
  */
@@ -1040,6 +1204,7 @@
1040
1204
  this.fragmentHint = void 0;
1041
1205
  this.partList = null;
1042
1206
  this.dateRanges = void 0;
1207
+ this.dateRangeTagCount = 0;
1043
1208
  this.live = true;
1044
1209
  this.ageHeader = 0;
1045
1210
  this.advancedDateTime = void 0;
@@ -2768,78 +2933,6 @@
2768
2933
  return uint8View;
2769
2934
  }
2770
2935
 
2771
- var VARIABLE_REPLACEMENT_REGEX = /\{\$([a-zA-Z0-9-_]+)\}/g;
2772
- function hasVariableReferences(str) {
2773
- return VARIABLE_REPLACEMENT_REGEX.test(str);
2774
- }
2775
- function substituteVariablesInAttributes(parsed, attr, attributeNames) {
2776
- if (parsed.variableList !== null || parsed.hasVariableRefs) {
2777
- for (var i = attributeNames.length; i--;) {
2778
- var name = attributeNames[i];
2779
- var value = attr[name];
2780
- if (value) {
2781
- attr[name] = substituteVariables(parsed, value);
2782
- }
2783
- }
2784
- }
2785
- }
2786
- function substituteVariables(parsed, value) {
2787
- if (parsed.variableList !== null || parsed.hasVariableRefs) {
2788
- var variableList = parsed.variableList;
2789
- return value.replace(VARIABLE_REPLACEMENT_REGEX, function (variableReference) {
2790
- var variableName = variableReference.substring(2, variableReference.length - 1);
2791
- var variableValue = variableList == null ? void 0 : variableList[variableName];
2792
- if (variableValue === undefined) {
2793
- parsed.playlistParsingError || (parsed.playlistParsingError = new Error("Missing preceding EXT-X-DEFINE tag for Variable Reference: \"" + variableName + "\""));
2794
- return variableReference;
2795
- }
2796
- return variableValue;
2797
- });
2798
- }
2799
- return value;
2800
- }
2801
- function addVariableDefinition(parsed, attr, parentUrl) {
2802
- var variableList = parsed.variableList;
2803
- if (!variableList) {
2804
- parsed.variableList = variableList = {};
2805
- }
2806
- var NAME;
2807
- var VALUE;
2808
- if ('QUERYPARAM' in attr) {
2809
- NAME = attr.QUERYPARAM;
2810
- try {
2811
- var searchParams = new self.URL(parentUrl).searchParams;
2812
- if (searchParams.has(NAME)) {
2813
- VALUE = searchParams.get(NAME);
2814
- } else {
2815
- throw new Error("\"" + NAME + "\" does not match any query parameter in URI: \"" + parentUrl + "\"");
2816
- }
2817
- } catch (error) {
2818
- parsed.playlistParsingError || (parsed.playlistParsingError = new Error("EXT-X-DEFINE QUERYPARAM: " + error.message));
2819
- }
2820
- } else {
2821
- NAME = attr.NAME;
2822
- VALUE = attr.VALUE;
2823
- }
2824
- if (NAME in variableList) {
2825
- parsed.playlistParsingError || (parsed.playlistParsingError = new Error("EXT-X-DEFINE duplicate Variable Name declarations: \"" + NAME + "\""));
2826
- } else {
2827
- variableList[NAME] = VALUE || '';
2828
- }
2829
- }
2830
- function importVariableDefinition(parsed, attr, sourceVariableList) {
2831
- var IMPORT = attr.IMPORT;
2832
- if (sourceVariableList && IMPORT in sourceVariableList) {
2833
- var variableList = parsed.variableList;
2834
- if (!variableList) {
2835
- parsed.variableList = variableList = {};
2836
- }
2837
- variableList[IMPORT] = sourceVariableList[IMPORT];
2838
- } else {
2839
- parsed.playlistParsingError || (parsed.playlistParsingError = new Error("EXT-X-DEFINE IMPORT attribute not found in Multivariant Playlist: \"" + IMPORT + "\""));
2840
- }
2841
- }
2842
-
2843
2936
  /**
2844
2937
  * MediaSource helper
2845
2938
  */
@@ -3097,10 +3190,7 @@
3097
3190
  if (result[1]) {
3098
3191
  var _level$unknownCodecs;
3099
3192
  // '#EXT-X-STREAM-INF' is found, parse level tag in group 1
3100
- var attrs = new AttrList(result[1]);
3101
- {
3102
- substituteVariablesInAttributes(parsed, attrs, ['CODECS', 'SUPPLEMENTAL-CODECS', 'ALLOWED-CPC', 'PATHWAY-ID', 'STABLE-VARIANT-ID', 'AUDIO', 'VIDEO', 'SUBTITLES', 'CLOSED-CAPTIONS', 'NAME']);
3103
- }
3193
+ var attrs = new AttrList(result[1], parsed);
3104
3194
  var uri = substituteVariables(parsed, result[2]) ;
3105
3195
  var level = {
3106
3196
  attrs: attrs,
@@ -3125,10 +3215,7 @@
3125
3215
  case 'SESSION-DATA':
3126
3216
  {
3127
3217
  // #EXT-X-SESSION-DATA
3128
- var sessionAttrs = new AttrList(attributes);
3129
- {
3130
- substituteVariablesInAttributes(parsed, sessionAttrs, ['DATA-ID', 'LANGUAGE', 'VALUE', 'URI']);
3131
- }
3218
+ var sessionAttrs = new AttrList(attributes, parsed);
3132
3219
  var dataId = sessionAttrs['DATA-ID'];
3133
3220
  if (dataId) {
3134
3221
  if (parsed.sessionData === null) {
@@ -3156,8 +3243,7 @@
3156
3243
  {
3157
3244
  // #EXT-X-DEFINE
3158
3245
  {
3159
- var variableAttributes = new AttrList(attributes);
3160
- substituteVariablesInAttributes(parsed, variableAttributes, ['NAME', 'VALUE', 'QUERYPARAM']);
3246
+ var variableAttributes = new AttrList(attributes, parsed);
3161
3247
  addVariableDefinition(parsed, variableAttributes, baseurl);
3162
3248
  }
3163
3249
  break;
@@ -3165,10 +3251,7 @@
3165
3251
  case 'CONTENT-STEERING':
3166
3252
  {
3167
3253
  // #EXT-X-CONTENT-STEERING
3168
- var contentSteeringAttributes = new AttrList(attributes);
3169
- {
3170
- substituteVariablesInAttributes(parsed, contentSteeringAttributes, ['SERVER-URI', 'PATHWAY-ID']);
3171
- }
3254
+ var contentSteeringAttributes = new AttrList(attributes, parsed);
3172
3255
  parsed.contentSteering = {
3173
3256
  uri: M3U8Parser.resolve(contentSteeringAttributes['SERVER-URI'], baseurl),
3174
3257
  pathwayId: contentSteeringAttributes['PATHWAY-ID'] || '.'
@@ -3214,15 +3297,12 @@
3214
3297
  var id = 0;
3215
3298
  MASTER_PLAYLIST_MEDIA_REGEX.lastIndex = 0;
3216
3299
  while ((result = MASTER_PLAYLIST_MEDIA_REGEX.exec(string)) !== null) {
3217
- var attrs = new AttrList(result[1]);
3300
+ var attrs = new AttrList(result[1], parsed);
3218
3301
  var type = attrs.TYPE;
3219
3302
  if (type) {
3220
3303
  var groups = groupsByType[type];
3221
3304
  var medias = results[type] || [];
3222
3305
  results[type] = medias;
3223
- {
3224
- substituteVariablesInAttributes(parsed, attrs, ['URI', 'GROUP-ID', 'LANGUAGE', 'ASSOC-LANGUAGE', 'STABLE-RENDITION-ID', 'NAME', 'INSTREAM-ID', 'CHARACTERISTICS', 'CHANNELS']);
3225
- }
3226
3306
  var lang = attrs.LANGUAGE;
3227
3307
  var assocLang = attrs['ASSOC-LANGUAGE'];
3228
3308
  var channels = attrs.CHANNELS;
@@ -3269,6 +3349,7 @@
3269
3349
  M3U8Parser.parseLevelPlaylist = function parseLevelPlaylist(string, baseurl, id, type, levelUrlId, multivariantVariableList) {
3270
3350
  var level = new LevelDetails(baseurl);
3271
3351
  var fragments = level.fragments;
3352
+ var programDateTimes = [];
3272
3353
  // The most recent init segment seen (applies to all subsequent segments)
3273
3354
  var currentInitSegment = null;
3274
3355
  var currentSN = 0;
@@ -3327,7 +3408,7 @@
3327
3408
  // avoid sliced strings https://github.com/video-dev/hls.js/issues/939
3328
3409
  var uri = (' ' + result[3]).slice(1);
3329
3410
  frag.relurl = substituteVariables(level, uri) ;
3330
- assignProgramDateTime(frag, prevFrag);
3411
+ assignProgramDateTime(frag, prevFrag, programDateTimes);
3331
3412
  prevFrag = frag;
3332
3413
  totalduration += frag.duration;
3333
3414
  currentSN++;
@@ -3375,22 +3456,22 @@
3375
3456
  break;
3376
3457
  case 'SKIP':
3377
3458
  {
3378
- var skipAttrs = new AttrList(value1);
3379
- {
3380
- substituteVariablesInAttributes(level, skipAttrs, ['RECENTLY-REMOVED-DATERANGES']);
3459
+ if (level.skippedSegments) {
3460
+ level.playlistParsingError = new Error("#EXT-X-SKIP MUST NOT appear more than once in a Playlist");
3381
3461
  }
3462
+ var skipAttrs = new AttrList(value1, level);
3382
3463
  var skippedSegments = skipAttrs.decimalInteger('SKIPPED-SEGMENTS');
3383
3464
  if (isFiniteNumber(skippedSegments)) {
3384
- level.skippedSegments = skippedSegments;
3465
+ level.skippedSegments += skippedSegments;
3385
3466
  // This will result in fragments[] containing undefined values, which we will fill in with `mergeDetails`
3386
3467
  for (var _i = skippedSegments; _i--;) {
3387
- fragments.unshift(null);
3468
+ fragments.push(null);
3388
3469
  }
3389
3470
  currentSN += skippedSegments;
3390
3471
  }
3391
3472
  var recentlyRemovedDateranges = skipAttrs.enumeratedString('RECENTLY-REMOVED-DATERANGES');
3392
3473
  if (recentlyRemovedDateranges) {
3393
- level.recentlyRemovedDateranges = recentlyRemovedDateranges.split('\t');
3474
+ level.recentlyRemovedDateranges = (level.recentlyRemovedDateranges || []).concat(recentlyRemovedDateranges.split('\t'));
3394
3475
  }
3395
3476
  break;
3396
3477
  }
@@ -3424,12 +3505,9 @@
3424
3505
  break;
3425
3506
  case 'DATERANGE':
3426
3507
  {
3427
- var dateRangeAttr = new AttrList(value1);
3428
- {
3429
- substituteVariablesInAttributes(level, dateRangeAttr, ['ID', 'CLASS', 'START-DATE', 'END-DATE', 'SCTE35-CMD', 'SCTE35-OUT', 'SCTE35-IN']);
3430
- substituteVariablesInAttributes(level, dateRangeAttr, dateRangeAttr.clientAttrs);
3431
- }
3432
- var dateRange = new DateRange(dateRangeAttr, level.dateRanges[dateRangeAttr.ID]);
3508
+ var dateRangeAttr = new AttrList(value1, level);
3509
+ var dateRange = new DateRange(dateRangeAttr, level.dateRanges[dateRangeAttr.ID], level.dateRangeTagCount);
3510
+ level.dateRangeTagCount++;
3433
3511
  if (dateRange.isValid || level.skippedSegments) {
3434
3512
  level.dateRanges[dateRange.id] = dateRange;
3435
3513
  } else {
@@ -3442,8 +3520,7 @@
3442
3520
  case 'DEFINE':
3443
3521
  {
3444
3522
  {
3445
- var variableAttributes = new AttrList(value1);
3446
- substituteVariablesInAttributes(level, variableAttributes, ['NAME', 'VALUE', 'IMPORT', 'QUERYPARAM']);
3523
+ var variableAttributes = new AttrList(value1, level);
3447
3524
  if ('IMPORT' in variableAttributes) {
3448
3525
  importVariableDefinition(level, variableAttributes, multivariantVariableList);
3449
3526
  } else {
@@ -3480,10 +3557,7 @@
3480
3557
  break;
3481
3558
  case 'MAP':
3482
3559
  {
3483
- var mapAttrs = new AttrList(value1);
3484
- {
3485
- substituteVariablesInAttributes(level, mapAttrs, ['BYTERANGE', 'URI']);
3486
- }
3560
+ var mapAttrs = new AttrList(value1, level);
3487
3561
  if (frag.duration) {
3488
3562
  // Initial segment tag is after segment duration tag.
3489
3563
  // #EXTINF: 6.0
@@ -3509,6 +3583,7 @@
3509
3583
  currentInitSegment = frag;
3510
3584
  createNextFrag = true;
3511
3585
  }
3586
+ currentInitSegment.cc = discontinuityCounter;
3512
3587
  break;
3513
3588
  }
3514
3589
  case 'SERVER-CONTROL':
@@ -3535,10 +3610,7 @@
3535
3610
  }
3536
3611
  var previousFragmentPart = currentPart > 0 ? partList[partList.length - 1] : undefined;
3537
3612
  var index = currentPart++;
3538
- var partAttrs = new AttrList(value1);
3539
- {
3540
- substituteVariablesInAttributes(level, partAttrs, ['BYTERANGE', 'URI']);
3541
- }
3613
+ var partAttrs = new AttrList(value1, level);
3542
3614
  var part = new Part(partAttrs, frag, baseurl, index, previousFragmentPart);
3543
3615
  partList.push(part);
3544
3616
  frag.duration += part.duration;
@@ -3546,19 +3618,13 @@
3546
3618
  }
3547
3619
  case 'PRELOAD-HINT':
3548
3620
  {
3549
- var preloadHintAttrs = new AttrList(value1);
3550
- {
3551
- substituteVariablesInAttributes(level, preloadHintAttrs, ['URI']);
3552
- }
3621
+ var preloadHintAttrs = new AttrList(value1, level);
3553
3622
  level.preloadHint = preloadHintAttrs;
3554
3623
  break;
3555
3624
  }
3556
3625
  case 'RENDITION-REPORT':
3557
3626
  {
3558
- var renditionReportAttrs = new AttrList(value1);
3559
- {
3560
- substituteVariablesInAttributes(level, renditionReportAttrs, ['URI']);
3561
- }
3627
+ var renditionReportAttrs = new AttrList(value1, level);
3562
3628
  level.renditionReports = level.renditionReports || [];
3563
3629
  level.renditionReports.push(renditionReportAttrs);
3564
3630
  break;
@@ -3576,7 +3642,7 @@
3576
3642
  level.fragmentHint = prevFrag;
3577
3643
  }
3578
3644
  } else if (level.partList) {
3579
- assignProgramDateTime(frag, prevFrag);
3645
+ assignProgramDateTime(frag, prevFrag, programDateTimes);
3580
3646
  frag.cc = discontinuityCounter;
3581
3647
  level.fragmentHint = frag;
3582
3648
  if (levelkeys) {
@@ -3597,6 +3663,21 @@
3597
3663
  if (firstFragment) {
3598
3664
  level.startCC = firstFragment.cc;
3599
3665
  }
3666
+ /**
3667
+ * Backfill any missing PDT values
3668
+ * "If the first EXT-X-PROGRAM-DATE-TIME tag in a Playlist appears after
3669
+ * one or more Media Segment URIs, the client SHOULD extrapolate
3670
+ * backward from that tag (using EXTINF durations and/or media
3671
+ * timestamps) to associate dates with those segments."
3672
+ * We have already extrapolated forward, but all fragments up to the first instance of PDT do not have their PDTs
3673
+ * computed.
3674
+ */
3675
+ if (firstPdtIndex > 0) {
3676
+ backfillProgramDateTimes(fragments, firstPdtIndex);
3677
+ if (firstFragment) {
3678
+ programDateTimes.unshift(firstFragment);
3679
+ }
3680
+ }
3600
3681
  } else {
3601
3682
  level.endSN = 0;
3602
3683
  level.startCC = 0;
@@ -3605,31 +3686,63 @@
3605
3686
  totalduration += level.fragmentHint.duration;
3606
3687
  }
3607
3688
  level.totalduration = totalduration;
3608
- level.endCC = discontinuityCounter;
3609
-
3610
- /**
3611
- * Backfill any missing PDT values
3612
- * "If the first EXT-X-PROGRAM-DATE-TIME tag in a Playlist appears after
3613
- * one or more Media Segment URIs, the client SHOULD extrapolate
3614
- * backward from that tag (using EXTINF durations and/or media
3615
- * timestamps) to associate dates with those segments."
3616
- * We have already extrapolated forward, but all fragments up to the first instance of PDT do not have their PDTs
3617
- * computed.
3618
- */
3619
- if (firstPdtIndex > 0) {
3620
- backfillProgramDateTimes(fragments, firstPdtIndex);
3689
+ if (programDateTimes.length && level.dateRangeTagCount && firstFragment) {
3690
+ mapDateRanges(programDateTimes, level);
3621
3691
  }
3692
+ level.endCC = discontinuityCounter;
3622
3693
  return level;
3623
3694
  };
3624
3695
  return M3U8Parser;
3625
3696
  }();
3697
+ function mapDateRanges(programDateTimes, details) {
3698
+ // Make sure DateRanges are mapped to a ProgramDateTime tag that applies a date to a segment that overlaps with its start date
3699
+ var programDateTimeCount = programDateTimes.length;
3700
+ var lastProgramDateTime = programDateTimes[programDateTimeCount - 1];
3701
+ var playlistEnd = details.live ? Infinity : details.totalduration;
3702
+ var dateRangeIds = Object.keys(details.dateRanges);
3703
+ for (var i = dateRangeIds.length; i--;) {
3704
+ var dateRange = details.dateRanges[dateRangeIds[i]];
3705
+ var startDateTime = dateRange.startDate.getTime();
3706
+ dateRange.tagAnchor = lastProgramDateTime;
3707
+ for (var j = programDateTimeCount; j--;) {
3708
+ var fragIndex = findFragmentWithStartDate(details, startDateTime, programDateTimes, j, playlistEnd);
3709
+ if (fragIndex !== -1) {
3710
+ dateRange.tagAnchor = details.fragments[fragIndex];
3711
+ break;
3712
+ }
3713
+ }
3714
+ }
3715
+ }
3716
+ function findFragmentWithStartDate(details, startDateTime, programDateTimes, index, endTime) {
3717
+ var pdtFragment = programDateTimes[index];
3718
+ if (pdtFragment) {
3719
+ var _programDateTimes;
3720
+ // find matching range between PDT tags
3721
+ var durationBetweenPdt = (((_programDateTimes = programDateTimes[index + 1]) == null ? void 0 : _programDateTimes.start) || endTime) - pdtFragment.start;
3722
+ var pdtStart = pdtFragment.programDateTime;
3723
+ if ((startDateTime >= pdtStart || index === 0) && startDateTime <= pdtStart + durationBetweenPdt * 1000) {
3724
+ // map to fragment with date-time range
3725
+ var startIndex = programDateTimes[index].sn - details.startSN;
3726
+ var fragments = details.fragments;
3727
+ if (fragments.length > programDateTimes.length) {
3728
+ var endSegment = programDateTimes[index + 1] || fragments[fragments.length - 1];
3729
+ var endIndex = endSegment.sn - details.startSN;
3730
+ for (var i = endIndex; i > startIndex; i--) {
3731
+ var fragStartDateTime = fragments[i].programDateTime;
3732
+ if (startDateTime >= fragStartDateTime && startDateTime < fragStartDateTime + fragments[i].duration * 1000) {
3733
+ return i;
3734
+ }
3735
+ }
3736
+ }
3737
+ return startIndex;
3738
+ }
3739
+ }
3740
+ return -1;
3741
+ }
3626
3742
  function parseKey(keyTagAttributes, baseurl, parsed) {
3627
3743
  var _keyAttrs$METHOD, _keyAttrs$KEYFORMAT;
3628
3744
  // https://tools.ietf.org/html/rfc8216#section-4.3.2.4
3629
- var keyAttrs = new AttrList(keyTagAttributes);
3630
- {
3631
- substituteVariablesInAttributes(parsed, keyAttrs, ['KEYFORMAT', 'KEYFORMATVERSIONS', 'URI', 'IV', 'URI']);
3632
- }
3745
+ var keyAttrs = new AttrList(keyTagAttributes, parsed);
3633
3746
  var decryptmethod = (_keyAttrs$METHOD = keyAttrs.METHOD) != null ? _keyAttrs$METHOD : '';
3634
3747
  var decrypturi = keyAttrs.URI;
3635
3748
  var decryptiv = keyAttrs.hexadecimalInteger('IV');
@@ -3690,16 +3803,18 @@
3690
3803
  fragPrev = frag;
3691
3804
  }
3692
3805
  }
3693
- function assignProgramDateTime(frag, prevFrag) {
3806
+ function assignProgramDateTime(frag, prevFrag, programDateTimes) {
3694
3807
  if (frag.rawProgramDateTime) {
3695
3808
  frag.programDateTime = Date.parse(frag.rawProgramDateTime);
3809
+ if (!isFiniteNumber(frag.programDateTime)) {
3810
+ frag.programDateTime = null;
3811
+ frag.rawProgramDateTime = null;
3812
+ return;
3813
+ }
3814
+ programDateTimes.push(frag);
3696
3815
  } else if (prevFrag != null && prevFrag.programDateTime) {
3697
3816
  frag.programDateTime = prevFrag.endProgramDateTime;
3698
3817
  }
3699
- if (!isFiniteNumber(frag.programDateTime)) {
3700
- frag.programDateTime = null;
3701
- frag.rawProgramDateTime = null;
3702
- }
3703
3818
  }
3704
3819
  function setInitSegment(frag, mapAttrs, id, levelkeys) {
3705
3820
  frag.relurl = mapAttrs.URI;
@@ -4923,9 +5038,6 @@
4923
5038
  }
4924
5039
  return Number.POSITIVE_INFINITY;
4925
5040
  }();
4926
- function dateRangeDateToTimelineSeconds(date, offset) {
4927
- return date.getTime() / 1000 - offset;
4928
- }
4929
5041
  function hexToArrayBuffer(str) {
4930
5042
  return Uint8Array.from(str.replace(/^0x/, '').replace(/([\da-fA-F]{2}) ?/g, '0x$1 ').replace(/ +$/, '').split(' ')).buffer;
4931
5043
  }
@@ -4955,6 +5067,7 @@
4955
5067
  hls.on(Events.FRAG_PARSING_METADATA, this.onFragParsingMetadata, this);
4956
5068
  hls.on(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
4957
5069
  hls.on(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
5070
+ hls.on(Events.LEVEL_PTS_UPDATED, this.onLevelPtsUpdated, this);
4958
5071
  };
4959
5072
  _proto._unregisterListeners = function _unregisterListeners() {
4960
5073
  var hls = this.hls;
@@ -4964,6 +5077,7 @@
4964
5077
  hls.off(Events.FRAG_PARSING_METADATA, this.onFragParsingMetadata, this);
4965
5078
  hls.off(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
4966
5079
  hls.off(Events.LEVEL_UPDATED, this.onLevelUpdated, this);
5080
+ hls.off(Events.LEVEL_PTS_UPDATED, this.onLevelPtsUpdated, this);
4967
5081
  }
4968
5082
 
4969
5083
  // Add ID3 metatadata text track.
@@ -5096,8 +5210,16 @@
5096
5210
  }
5097
5211
  };
5098
5212
  _proto.onLevelUpdated = function onLevelUpdated(event, _ref2) {
5099
- var _this = this;
5100
5213
  var details = _ref2.details;
5214
+ this.updateDateRangeCues(details, true);
5215
+ };
5216
+ _proto.onLevelPtsUpdated = function onLevelPtsUpdated(event, data) {
5217
+ if (Math.abs(data.drift) > 0.01) {
5218
+ this.updateDateRangeCues(data.details);
5219
+ }
5220
+ };
5221
+ _proto.updateDateRangeCues = function updateDateRangeCues(details, removeOldCues) {
5222
+ var _this = this;
5101
5223
  if (!this.media || !details.hasProgramDateTime || !this.hls.config.enableDateRangeMetadataCues) {
5102
5224
  return;
5103
5225
  }
@@ -5106,7 +5228,7 @@
5106
5228
  var dateRanges = details.dateRanges;
5107
5229
  var ids = Object.keys(dateRanges);
5108
5230
  // Remove cues from track not found in details.dateRanges
5109
- if (id3Track) {
5231
+ if (id3Track && removeOldCues) {
5110
5232
  var idsToRemove = Object.keys(dateRangeCuesAppended).filter(function (id) {
5111
5233
  return !ids.includes(id);
5112
5234
  });
@@ -5129,21 +5251,21 @@
5129
5251
  if (!this.id3Track) {
5130
5252
  this.id3Track = this.createTrack(this.media);
5131
5253
  }
5132
- var dateTimeOffset = lastFragment.programDateTime / 1000 - lastFragment.start;
5133
5254
  var Cue = getCueClass();
5134
5255
  var _loop2 = function _loop2() {
5135
5256
  var id = ids[_i];
5136
5257
  var dateRange = dateRanges[id];
5137
- var startTime = dateRangeDateToTimelineSeconds(dateRange.startDate, dateTimeOffset);
5258
+ var startTime = dateRange.startTime;
5138
5259
 
5139
5260
  // Process DateRanges to determine end-time (known DURATION, END-DATE, or END-ON-NEXT)
5140
5261
  var appendedDateRangeCues = dateRangeCuesAppended[id];
5141
5262
  var cues = (appendedDateRangeCues == null ? void 0 : appendedDateRangeCues.cues) || {};
5142
5263
  var durationKnown = (appendedDateRangeCues == null ? void 0 : appendedDateRangeCues.durationKnown) || false;
5143
5264
  var endTime = MAX_CUE_ENDTIME;
5144
- var endDate = dateRange.endDate;
5145
- if (endDate) {
5146
- endTime = dateRangeDateToTimelineSeconds(endDate, dateTimeOffset);
5265
+ var duration = dateRange.duration,
5266
+ endDate = dateRange.endDate;
5267
+ if (endDate && duration !== null) {
5268
+ endTime = startTime + duration;
5147
5269
  durationKnown = true;
5148
5270
  } else if (dateRange.endOnNext && !durationKnown) {
5149
5271
  var nextDateRangeWithSameClass = ids.reduce(function (candidateDateRange, id) {
@@ -5156,7 +5278,7 @@
5156
5278
  return candidateDateRange;
5157
5279
  }, null);
5158
5280
  if (nextDateRangeWithSameClass) {
5159
- endTime = dateRangeDateToTimelineSeconds(nextDateRangeWithSameClass.startDate, dateTimeOffset);
5281
+ endTime = nextDateRangeWithSameClass.startTime;
5160
5282
  durationKnown = true;
5161
5283
  }
5162
5284
  }
@@ -5173,6 +5295,9 @@
5173
5295
  if (cue) {
5174
5296
  if (durationKnown && !appendedDateRangeCues.durationKnown) {
5175
5297
  cue.endTime = endTime;
5298
+ } else if (Math.abs(cue.startTime - startTime) > 0.01) {
5299
+ cue.startTime = startTime;
5300
+ cue.endTime = endTime;
5176
5301
  }
5177
5302
  } else if (Cue) {
5178
5303
  var data = dateRange.attr[key];
@@ -5703,7 +5828,7 @@
5703
5828
  frag.endPTS = endPTS;
5704
5829
  frag.minEndPTS = minEndPTS;
5705
5830
  frag.endDTS = endDTS;
5706
- var sn = frag.sn; // 'initSegment'
5831
+ var sn = frag.sn;
5707
5832
  // exit if sn out of range
5708
5833
  if (!details || sn < details.startSN || sn > details.endSN) {
5709
5834
  return 0;
@@ -5781,8 +5906,8 @@
5781
5906
  currentInitSegment = oldFrag.initSegment;
5782
5907
  }
5783
5908
  });
5909
+ var fragmentsToCheck = newDetails.fragmentHint ? newDetails.fragments.concat(newDetails.fragmentHint) : newDetails.fragments;
5784
5910
  if (currentInitSegment) {
5785
- var fragmentsToCheck = newDetails.fragmentHint ? newDetails.fragments.concat(newDetails.fragmentHint) : newDetails.fragments;
5786
5911
  fragmentsToCheck.forEach(function (frag) {
5787
5912
  var _currentInitSegment;
5788
5913
  if (frag && (!frag.initSegment || frag.initSegment.relurl === ((_currentInitSegment = currentInitSegment) == null ? void 0 : _currentInitSegment.relurl))) {
@@ -5801,15 +5926,28 @@
5801
5926
  }
5802
5927
  newDetails.startSN = newDetails.fragments[0].sn;
5803
5928
  newDetails.startCC = newDetails.fragments[0].cc;
5804
- } else if (newDetails.canSkipDateRanges) {
5805
- newDetails.dateRanges = mergeDateRanges(oldDetails.dateRanges, newDetails.dateRanges, newDetails.recentlyRemovedDateranges);
5929
+ } else {
5930
+ if (newDetails.canSkipDateRanges) {
5931
+ newDetails.dateRanges = mergeDateRanges(oldDetails.dateRanges, newDetails);
5932
+ }
5933
+ var programDateTimes = oldDetails.fragments.filter(function (frag) {
5934
+ return frag.rawProgramDateTime;
5935
+ });
5936
+ if (oldDetails.hasProgramDateTime && !newDetails.hasProgramDateTime) {
5937
+ for (var _i2 = 1; _i2 < fragmentsToCheck.length; _i2++) {
5938
+ if (fragmentsToCheck[_i2].programDateTime === null) {
5939
+ assignProgramDateTime(fragmentsToCheck[_i2], fragmentsToCheck[_i2 - 1], programDateTimes);
5940
+ }
5941
+ }
5942
+ }
5943
+ mapDateRanges(programDateTimes, newDetails);
5806
5944
  }
5807
5945
  }
5808
5946
  var newFragments = newDetails.fragments;
5809
5947
  if (ccOffset) {
5810
5948
  logger.warn('discontinuity sliding from playlist, take drift into account');
5811
- for (var _i2 = 0; _i2 < newFragments.length; _i2++) {
5812
- newFragments[_i2].cc += ccOffset;
5949
+ for (var _i3 = 0; _i3 < newFragments.length; _i3++) {
5950
+ newFragments[_i3].cc += ccOffset;
5813
5951
  }
5814
5952
  }
5815
5953
  if (newDetails.skippedSegments) {
@@ -5851,21 +5989,31 @@
5851
5989
  newDetails.advancedDateTime = oldDetails.advancedDateTime;
5852
5990
  }
5853
5991
  }
5854
- function mergeDateRanges(oldDateRanges, deltaDateRanges, recentlyRemovedDateranges) {
5992
+ function mergeDateRanges(oldDateRanges, newDetails) {
5993
+ var deltaDateRanges = newDetails.dateRanges,
5994
+ recentlyRemovedDateranges = newDetails.recentlyRemovedDateranges;
5855
5995
  var dateRanges = _extends({}, oldDateRanges);
5856
5996
  if (recentlyRemovedDateranges) {
5857
5997
  recentlyRemovedDateranges.forEach(function (id) {
5858
5998
  delete dateRanges[id];
5859
5999
  });
5860
6000
  }
5861
- Object.keys(deltaDateRanges).forEach(function (id) {
5862
- var dateRange = new DateRange(deltaDateRanges[id].attr, dateRanges[id]);
5863
- if (dateRange.isValid) {
5864
- dateRanges[id] = dateRange;
5865
- } else {
5866
- logger.warn("Ignoring invalid Playlist Delta Update DATERANGE tag: \"" + JSON.stringify(deltaDateRanges[id].attr) + "\"");
5867
- }
5868
- });
6001
+ var mergeIds = Object.keys(dateRanges);
6002
+ var mergeCount = mergeIds.length;
6003
+ if (mergeCount) {
6004
+ Object.keys(deltaDateRanges).forEach(function (id) {
6005
+ var mergedDateRange = dateRanges[id];
6006
+ var dateRange = new DateRange(deltaDateRanges[id].attr, mergedDateRange);
6007
+ if (dateRange.isValid) {
6008
+ dateRanges[id] = dateRange;
6009
+ if (!mergedDateRange) {
6010
+ dateRange.tagOrder += mergeCount;
6011
+ }
6012
+ } else {
6013
+ logger.warn("Ignoring invalid Playlist Delta Update DATERANGE tag: \"" + JSON.stringify(deltaDateRanges[id].attr) + "\"");
6014
+ }
6015
+ });
6016
+ }
5869
6017
  return dateRanges;
5870
6018
  }
5871
6019
  function mapPartIntersection(oldParts, newParts, intersectionFn) {
@@ -5892,7 +6040,7 @@
5892
6040
  for (var i = start; i <= end; i++) {
5893
6041
  var _oldFrag = oldFrags[delta + i];
5894
6042
  var _newFrag = newFrags[i];
5895
- if (skippedSegments && !_newFrag && i < skippedSegments) {
6043
+ if (skippedSegments && !_newFrag && _oldFrag) {
5896
6044
  // Fill in skipped segments in delta playlist
5897
6045
  _newFrag = newDetails.fragments[i] = _oldFrag;
5898
6046
  }
@@ -5945,19 +6093,19 @@
5945
6093
  return Math.round(reloadInterval);
5946
6094
  }
5947
6095
  function getFragmentWithSN(level, sn, fragCurrent) {
5948
- if (!(level != null && level.details)) {
6096
+ var details = level == null ? void 0 : level.details;
6097
+ if (!details) {
5949
6098
  return null;
5950
6099
  }
5951
- var levelDetails = level.details;
5952
- var fragment = levelDetails.fragments[sn - levelDetails.startSN];
6100
+ var fragment = details.fragments[sn - details.startSN];
5953
6101
  if (fragment) {
5954
6102
  return fragment;
5955
6103
  }
5956
- fragment = levelDetails.fragmentHint;
6104
+ fragment = details.fragmentHint;
5957
6105
  if (fragment && fragment.sn === sn) {
5958
6106
  return fragment;
5959
6107
  }
5960
- if (sn < levelDetails.startSN && fragCurrent && fragCurrent.sn === sn) {
6108
+ if (sn < details.startSN && fragCurrent && fragCurrent.sn === sn) {
5961
6109
  return fragCurrent;
5962
6110
  }
5963
6111
  return null;
@@ -8333,11 +8481,10 @@
8333
8481
  _proto.detectPartialFragments = function detectPartialFragments(data) {
8334
8482
  var _this2 = this;
8335
8483
  var timeRanges = this.timeRanges;
8336
- var frag = data.frag,
8337
- part = data.part;
8338
- if (!timeRanges || frag.sn === 'initSegment') {
8484
+ if (!timeRanges || data.frag.sn === 'initSegment') {
8339
8485
  return;
8340
8486
  }
8487
+ var frag = data.frag;
8341
8488
  var fragKey = getFragmentKey(frag);
8342
8489
  var fragmentEntity = this.fragments[fragKey];
8343
8490
  if (!fragmentEntity || fragmentEntity.buffered && frag.gap) {
@@ -8351,7 +8498,7 @@
8351
8498
  }
8352
8499
  var timeRange = timeRanges[elementaryStream];
8353
8500
  var partial = isFragHint || streamInfo.partial === true;
8354
- fragmentEntity.range[elementaryStream] = _this2.getBufferedTimes(frag, part, partial, timeRange);
8501
+ fragmentEntity.range[elementaryStream] = _this2.getBufferedTimes(frag, data.part, partial, timeRange);
8355
8502
  });
8356
8503
  fragmentEntity.loaded = null;
8357
8504
  if (Object.keys(fragmentEntity.range).length) {
@@ -8504,16 +8651,14 @@
8504
8651
  return false;
8505
8652
  };
8506
8653
  _proto.onFragLoaded = function onFragLoaded(event, data) {
8507
- var frag = data.frag,
8508
- part = data.part;
8509
8654
  // don't track initsegment (for which sn is not a number)
8510
8655
  // don't track frags used for bitrateTest, they're irrelevant.
8511
- if (frag.sn === 'initSegment' || frag.bitrateTest) {
8656
+ if (data.frag.sn === 'initSegment' || data.frag.bitrateTest) {
8512
8657
  return;
8513
8658
  }
8514
-
8659
+ var frag = data.frag;
8515
8660
  // Fragment entity `loaded` FragLoadedData is null when loading parts
8516
- var loaded = part ? null : data;
8661
+ var loaded = data.part ? null : data;
8517
8662
  var fragKey = getFragmentKey(frag);
8518
8663
  this.fragments[fragKey] = {
8519
8664
  body: frag,
@@ -10403,14 +10548,12 @@
10403
10548
  part.stats.parsing.end = now;
10404
10549
  }
10405
10550
  // See if part loading should be disabled/enabled based on buffer and playback position.
10406
- if (frag.sn !== 'initSegment') {
10407
- var levelDetails = this.getLevelDetails();
10408
- var loadingPartsAtEdge = levelDetails && frag.sn > levelDetails.endSN;
10409
- var shouldLoadParts = loadingPartsAtEdge || this.shouldLoadParts(levelDetails, frag.end);
10410
- if (shouldLoadParts !== this.loadingParts) {
10411
- this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " after parsing segment ending @" + frag.end.toFixed(2));
10412
- this.loadingParts = shouldLoadParts;
10413
- }
10551
+ var levelDetails = this.getLevelDetails();
10552
+ var loadingPartsAtEdge = levelDetails && frag.sn > levelDetails.endSN;
10553
+ var shouldLoadParts = loadingPartsAtEdge || this.shouldLoadParts(levelDetails, frag.end);
10554
+ if (shouldLoadParts !== this.loadingParts) {
10555
+ this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " after parsing segment ending @" + frag.end.toFixed(2));
10556
+ this.loadingParts = shouldLoadParts;
10414
10557
  }
10415
10558
  this.updateLevelTiming(frag, part, level, chunkMeta.partial);
10416
10559
  };
@@ -17491,7 +17634,7 @@
17491
17634
  baseTime: initPTS,
17492
17635
  timescale: timescale
17493
17636
  };
17494
- this.log("InitPTS for cc: " + cc + " found from main: " + initPTS);
17637
+ this.log("InitPTS for cc: " + cc + " found from main: " + initPTS + "/" + timescale);
17495
17638
  this.videoTrackCC = cc;
17496
17639
  // If we are waiting, tick immediately to unblock audio fragment transmuxing
17497
17640
  if (this.state === State.WAITING_INIT_PTS) {
@@ -17823,8 +17966,8 @@
17823
17966
  };
17824
17967
  _proto._handleFragmentLoadProgress = function _handleFragmentLoadProgress(data) {
17825
17968
  var _frag$initSegment;
17826
- var frag = data.frag,
17827
- part = data.part,
17969
+ var frag = data.frag;
17970
+ var part = data.part,
17828
17971
  payload = data.payload;
17829
17972
  var config = this.config,
17830
17973
  trackId = this.trackId,
@@ -29010,8 +29153,8 @@
29010
29153
  };
29011
29154
  _proto._handleFragmentLoadProgress = function _handleFragmentLoadProgress(data) {
29012
29155
  var _frag$initSegment;
29013
- var frag = data.frag,
29014
- part = data.part,
29156
+ var frag = data.frag;
29157
+ var part = data.part,
29015
29158
  payload = data.payload;
29016
29159
  var levels = this.levels;
29017
29160
  if (!levels) {
@@ -29351,7 +29494,7 @@
29351
29494
  }
29352
29495
 
29353
29496
  // Avoid buffering if backtracking this fragment
29354
- if (video && details && frag.sn !== 'initSegment') {
29497
+ if (video && details) {
29355
29498
  var prevFrag = details.fragments[frag.sn - 1 - details.startSN];
29356
29499
  var isFirstFragment = frag.sn === details.startSN;
29357
29500
  var isFirstInDiscontinuity = !prevFrag || frag.cc > prevFrag.cc;
@@ -30520,7 +30663,7 @@
30520
30663
  * Get the video-dev/hls.js package version.
30521
30664
  */
30522
30665
  function get() {
30523
- return "1.5.12-0.canary.10338";
30666
+ return "1.5.12-0.canary.10341";
30524
30667
  }
30525
30668
  }, {
30526
30669
  key: "Events",