stormcloud-video-player 0.7.10 → 0.7.12

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.
@@ -1429,7 +1429,6 @@ function createAdStormPlayer(contentVideo, options) {
1429
1429
  contentVideo.muted = originalMutedState;
1430
1430
  contentVideo.volume = originalVolume;
1431
1431
  currentAd = void 0;
1432
- tornDown = false;
1433
1432
  return [
1434
1433
  2,
1435
1434
  Promise.resolve()
@@ -1544,6 +1543,15 @@ function createAdStormPlayer(contentVideo, options) {
1544
1543
  if (!token) return [
1545
1544
  2
1546
1545
  ];
1546
+ if (currentAd) {
1547
+ preloadSlots.set(token, {
1548
+ ad: currentAd
1549
+ });
1550
+ currentAd = void 0;
1551
+ return [
1552
+ 2
1553
+ ];
1554
+ }
1547
1555
  requestContext = typeof arg1 === "string" ? arg2 : arg1;
1548
1556
  return [
1549
1557
  4,
@@ -2037,56 +2045,6 @@ function sendInitialTracking(licenseKey) {
2037
2045
  });
2038
2046
  })();
2039
2047
  }
2040
- function sendAdDetectTracking(licenseKey, adDetectInfo) {
2041
- return _async_to_generator(function() {
2042
- var clientInfo, browserId, trackingData, error;
2043
- return _ts_generator(this, function(_state) {
2044
- switch(_state.label){
2045
- case 0:
2046
- _state.trys.push([
2047
- 0,
2048
- 3,
2049
- ,
2050
- 4
2051
- ]);
2052
- clientInfo = getClientInfo();
2053
- return [
2054
- 4,
2055
- getBrowserID(clientInfo)
2056
- ];
2057
- case 1:
2058
- browserId = _state.sent();
2059
- trackingData = _object_spread({
2060
- browserId: browserId
2061
- }, clientInfo);
2062
- return [
2063
- 4,
2064
- sendTrackRequest(licenseKey, _object_spread_props(_object_spread({}, trackingData), {
2065
- licenseKey: licenseKey,
2066
- adDetectInfo: adDetectInfo
2067
- }))
2068
- ];
2069
- case 2:
2070
- _state.sent();
2071
- return [
2072
- 3,
2073
- 4
2074
- ];
2075
- case 3:
2076
- error = _state.sent();
2077
- console.error("[StormcloudVideoPlayer] Error sending ad detect tracking:", error);
2078
- return [
2079
- 3,
2080
- 4
2081
- ];
2082
- case 4:
2083
- return [
2084
- 2
2085
- ];
2086
- }
2087
- });
2088
- })();
2089
- }
2090
2048
  function sendAdLoadedTracking(licenseKey, adLoadedInfo) {
2091
2049
  return _async_to_generator(function() {
2092
2050
  var clientInfo, browserId, trackingData, error;
@@ -2771,7 +2729,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2771
2729
  this.continuousFetchLoopPromise = null;
2772
2730
  this.attached = false;
2773
2731
  this.inAdBreak = false;
2774
- this.ptsDriftEmaMs = 0;
2775
2732
  this.adPodQueue = [];
2776
2733
  this.lastHeartbeatTime = 0;
2777
2734
  this.currentAdIndex = 0;
@@ -2790,10 +2747,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2790
2747
  this.isInAdTransition = false;
2791
2748
  this.maxPlaceholderDurationMs = 5e3;
2792
2749
  this.isShowingPlaceholder = false;
2750
+ this.lastAdInsertionPoint = null;
2751
+ this.processedAdInsertionUpdatedAt = null;
2793
2752
  this.totalAdRequestsInBreak = 0;
2794
2753
  this.maxTotalAdRequestsPerBreak = 20;
2795
2754
  this.pendingAdBreak = null;
2796
- this.savedMutedStateBeforeScte = null;
2755
+ this.savedMutedStateBeforeAd = null;
2797
2756
  this.consecutiveFailures = 0;
2798
2757
  this.maxConsecutiveFailures = 5;
2799
2758
  this.lastAdRequestTime = 0;
@@ -2806,7 +2765,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2806
2765
  this.adRequestRetryBackoffMs = 1500;
2807
2766
  this.preloadedTokens = [];
2808
2767
  this.debugLogEntries = [];
2809
- this.scteMarkerHistory = [];
2768
+ this.adInsertionDebugHistory = [];
2810
2769
  initializePolyfills();
2811
2770
  var browserOverrides = getBrowserConfigOverrides();
2812
2771
  this.config = _object_spread({}, browserOverrides, config);
@@ -2991,6 +2950,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2991
2950
  _state.sent();
2992
2951
  _state.label = 2;
2993
2952
  case 2:
2953
+ if (!this.config.disableAds && this.config.projectId) {
2954
+ this.startAdInsertionPolling();
2955
+ }
2994
2956
  return [
2995
2957
  2
2996
2958
  ];
@@ -2998,78 +2960,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2998
2960
  });
2999
2961
  }).call(_this);
3000
2962
  });
3001
- this.hls.on(import_hls.default.Events.LEVEL_LOADED, function(_evt, data) {
2963
+ this.hls.on(import_hls.default.Events.LEVEL_LOADED, function() {
3002
2964
  if (_this.inAdBreak || _this.pendingAdBreak) {
3003
2965
  return;
3004
2966
  }
3005
- var details = data === null || data === void 0 ? void 0 : data.details;
3006
- if (!details || !details.fragments || details.fragments.length === 0) {
3007
- return;
3008
- }
3009
- var fragmentsToScan = Math.min(5, details.fragments.length);
3010
- for(var i = 0; i < fragmentsToScan; i++){
3011
- var frag = details.fragments[i];
3012
- var tagList = frag === null || frag === void 0 ? void 0 : frag.tagList;
3013
- if (!Array.isArray(tagList)) continue;
3014
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
3015
- try {
3016
- for(var _iterator = tagList[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
3017
- var entry = _step.value;
3018
- var tag = "";
3019
- var value = "";
3020
- if (Array.isArray(entry)) {
3021
- var _entry_, _entry_1;
3022
- tag = String((_entry_ = entry[0]) !== null && _entry_ !== void 0 ? _entry_ : "");
3023
- value = String((_entry_1 = entry[1]) !== null && _entry_1 !== void 0 ? _entry_1 : "");
3024
- } else if (typeof entry === "string") {
3025
- var idx = entry.indexOf(":");
3026
- if (idx >= 0) {
3027
- tag = entry.substring(0, idx);
3028
- value = entry.substring(idx + 1);
3029
- } else {
3030
- tag = entry;
3031
- }
3032
- }
3033
- if (!tag) continue;
3034
- if (tag.includes("EXT-X-CUE-OUT") || tag.includes("EXT-X-DATERANGE")) {
3035
- var attrs = tag.includes("EXT-X-DATERANGE") ? _this.parseAttributeList(value) : {};
3036
- var hasScteOut = tag.includes("EXT-X-CUE-OUT") || "SCTE35-OUT" in attrs || attrs["SCTE35-OUT"] !== void 0;
3037
- if (hasScteOut) {
3038
- var durationSeconds = _this.parseCueOutDuration(value);
3039
- var marker = _object_spread_props(_object_spread({
3040
- type: "start"
3041
- }, durationSeconds !== void 0 ? {
3042
- durationSeconds: durationSeconds
3043
- } : {}), {
3044
- raw: {
3045
- tag: tag,
3046
- value: value,
3047
- earlyDetection: true
3048
- }
3049
- });
3050
- if (_this.config.debugAdTiming) {
3051
- console.log("[StormcloudVideoPlayer] \uD83C\uDFAF EARLY SCTE-35 DETECTION: Ad break marker found in fragment", i, "- starting pre-fetch (NOT playing yet)");
3052
- }
3053
- _this.startAdPrefetch(marker, frag === null || frag === void 0 ? void 0 : frag.sn);
3054
- return;
3055
- }
3056
- }
3057
- }
3058
- } catch (err) {
3059
- _didIteratorError = true;
3060
- _iteratorError = err;
3061
- } finally{
3062
- try {
3063
- if (!_iteratorNormalCompletion && _iterator.return != null) {
3064
- _iterator.return();
3065
- }
3066
- } finally{
3067
- if (_didIteratorError) {
3068
- throw _iteratorError;
3069
- }
3070
- }
3071
- }
3072
- }
2967
+ _this.checkAdInsertionInManifest();
3073
2968
  });
3074
2969
  this.hls.on(import_hls.default.Events.FRAG_BUFFERED, function(_evt, data) {
3075
2970
  return _async_to_generator(function() {
@@ -3131,111 +3026,55 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3131
3026
  });
3132
3027
  }).call(_this);
3133
3028
  });
3134
- this.hls.on(import_hls.default.Events.FRAG_PARSING_METADATA, function(_evt, data) {
3135
- var id3Tags = ((data === null || data === void 0 ? void 0 : data.samples) || []).map(function(s) {
3136
- return {
3137
- key: "ID3",
3138
- value: s === null || s === void 0 ? void 0 : s.data,
3139
- ptsSeconds: s === null || s === void 0 ? void 0 : s.pts
3140
- };
3141
- });
3142
- id3Tags.forEach(function(tag) {
3143
- return _this.onId3Tag(tag);
3144
- });
3145
- });
3146
3029
  this.hls.on(import_hls.default.Events.FRAG_CHANGED, function(_evt, data) {
3147
3030
  var frag = data === null || data === void 0 ? void 0 : data.frag;
3148
- var tagList = frag === null || frag === void 0 ? void 0 : frag.tagList;
3149
- if (!Array.isArray(tagList)) return;
3150
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
3151
- try {
3152
- for(var _iterator = tagList[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
3153
- var entry = _step.value;
3154
- var tag = "";
3155
- var value = "";
3156
- if (Array.isArray(entry)) {
3157
- var _entry_, _entry_1;
3158
- tag = String((_entry_ = entry[0]) !== null && _entry_ !== void 0 ? _entry_ : "");
3159
- value = String((_entry_1 = entry[1]) !== null && _entry_1 !== void 0 ? _entry_1 : "");
3160
- } else if (typeof entry === "string") {
3161
- var idx = entry.indexOf(":");
3162
- if (idx >= 0) {
3163
- tag = entry.substring(0, idx);
3164
- value = entry.substring(idx + 1);
3165
- } else {
3166
- tag = entry;
3167
- value = "";
3168
- }
3031
+ if (!frag) return;
3032
+ if (_this.lastAdInsertionPoint && !_this.inAdBreak && _this.lastAdInsertionPoint.updated_at !== _this.processedAdInsertionUpdatedAt) {
3033
+ var segmentName = _this.lastAdInsertionPoint.segment_ts_name;
3034
+ if (_this.fragmentMatchesSegment(frag, segmentName)) {
3035
+ var _ref;
3036
+ _this.processedAdInsertionUpdatedAt = _this.lastAdInsertionPoint.updated_at;
3037
+ var offsetMs = (_this.lastAdInsertionPoint.offset_seconds || 0) * 1e3;
3038
+ _this.pushAdInsertionDebug("segment_playing", segmentName, {
3039
+ offsetSeconds: _this.lastAdInsertionPoint.offset_seconds,
3040
+ detail: "sn=".concat((_ref = frag === null || frag === void 0 ? void 0 : frag.sn) !== null && _ref !== void 0 ? _ref : "?")
3041
+ });
3042
+ if (_this.config.debugAdTiming) {
3043
+ console.log('[StormcloudVideoPlayer] Ad insertion segment "'.concat(segmentName, '" now playing — scheduling ad start in ').concat(offsetMs, "ms"));
3169
3044
  }
3170
- if (!tag) continue;
3171
- if (tag.includes("EXT-X-CUE-OUT-CONT")) {
3172
- var prog = _this.parseCueOutCont(value);
3173
- var marker = _object_spread_props(_object_spread({
3174
- type: "progress"
3175
- }, (prog === null || prog === void 0 ? void 0 : prog.duration) !== void 0 ? {
3176
- durationSeconds: prog.duration
3177
- } : {}, (prog === null || prog === void 0 ? void 0 : prog.elapsed) !== void 0 ? {
3178
- ptsSeconds: prog.elapsed
3179
- } : {}), {
3180
- raw: {
3181
- tag: tag,
3182
- value: value
3183
- }
3184
- });
3185
- _this.onScte35Marker(marker);
3186
- } else if (tag.includes("EXT-X-CUE-OUT")) {
3187
- var durationSeconds = _this.parseCueOutDuration(value);
3188
- var marker1 = _object_spread_props(_object_spread({
3189
- type: "start"
3190
- }, durationSeconds !== void 0 ? {
3191
- durationSeconds: durationSeconds
3192
- } : {}), {
3193
- raw: {
3194
- tag: tag,
3195
- value: value
3196
- }
3045
+ _this.pushAdInsertionDebug("ad_scheduled", segmentName, {
3046
+ offsetSeconds: _this.lastAdInsertionPoint.offset_seconds,
3047
+ detail: "in ".concat(offsetMs, "ms, dur=60s")
3048
+ });
3049
+ _this.clearAdInsertionOffsetTimer();
3050
+ _this.adInsertionOffsetTimerId = window.setTimeout(function() {
3051
+ _this.adInsertionOffsetTimerId = void 0;
3052
+ if (_this.inAdBreak) return;
3053
+ _this.pushAdInsertionDebug("ad_triggered", segmentName, {
3054
+ detail: "ad break started (60s)"
3197
3055
  });
3198
- _this.onScte35Marker(marker1);
3199
- } else if (tag.includes("EXT-X-CUE-IN")) {
3200
- _this.onScte35Marker({
3201
- type: "end",
3202
- raw: {
3203
- tag: tag,
3204
- value: value
3205
- }
3206
- });
3207
- } else if (tag.includes("EXT-X-DATERANGE")) {
3208
- var _attrs_CLASS;
3209
- var attrs = _this.parseAttributeList(value);
3210
- var hasScteOut = "SCTE35-OUT" in attrs || attrs["SCTE35-OUT"] !== void 0;
3211
- var hasScteIn = "SCTE35-IN" in attrs || attrs["SCTE35-IN"] !== void 0;
3212
- var klass = String((_attrs_CLASS = attrs["CLASS"]) !== null && _attrs_CLASS !== void 0 ? _attrs_CLASS : "");
3213
- var duration = _this.toNumber(attrs["DURATION"]);
3214
- if (hasScteOut || /com\.apple\.hls\.cue/i.test(klass)) {
3215
- var marker2 = _object_spread_props(_object_spread({
3216
- type: "start"
3217
- }, duration !== void 0 ? {
3218
- durationSeconds: duration
3219
- } : {}), {
3220
- raw: {
3221
- tag: tag,
3222
- value: value,
3223
- attrs: attrs
3224
- }
3225
- });
3226
- _this.onScte35Marker(marker2);
3227
- }
3228
- if (hasScteIn) {
3229
- _this.onScte35Marker({
3230
- type: "end",
3231
- raw: {
3232
- tag: tag,
3233
- value: value,
3234
- attrs: attrs
3235
- }
3236
- });
3237
- }
3238
- }
3056
+ void _this.handleAdStart(60);
3057
+ }, offsetMs);
3058
+ }
3059
+ }
3060
+ });
3061
+ this.hls.on(import_hls.default.Events.FRAG_PARSING_USERDATA, function(_evt, data) {
3062
+ var _ref;
3063
+ var samples = (_ref = data === null || data === void 0 ? void 0 : data.samples) !== null && _ref !== void 0 ? _ref : [];
3064
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
3065
+ try {
3066
+ for(var _iterator = samples[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
3067
+ var sample = _step.value;
3068
+ var _ref1, _ref2;
3069
+ var _data_frag, _data_frag1;
3070
+ var bytes = sample === null || sample === void 0 ? void 0 : sample.data;
3071
+ if (!bytes || bytes.length < 5) continue;
3072
+ var isSCTE35 = bytes[0] === 252;
3073
+ if (!isSCTE35) continue;
3074
+ var segName = (_ref1 = (_ref2 = data === null || data === void 0 ? void 0 : (_data_frag = data.frag) === null || _data_frag === void 0 ? void 0 : _data_frag.relurl) !== null && _ref2 !== void 0 ? _ref2 : data === null || data === void 0 ? void 0 : (_data_frag1 = data.frag) === null || _data_frag1 === void 0 ? void 0 : _data_frag1.url) !== null && _ref1 !== void 0 ? _ref1 : "";
3075
+ _this.pushAdInsertionDebug("scte35_inserted", segName, {
3076
+ detail: "len=".concat(bytes.length, "B")
3077
+ });
3239
3078
  }
3240
3079
  } catch (err) {
3241
3080
  _didIteratorError = true;
@@ -3326,8 +3165,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3326
3165
  _this.activeAdRequestToken = null;
3327
3166
  _this.showAds = true;
3328
3167
  if (_this.config.disableFiller) {
3329
- if (_this.savedMutedStateBeforeScte == null) {
3330
- _this.savedMutedStateBeforeScte = {
3168
+ if (_this.savedMutedStateBeforeAd == null) {
3169
+ _this.savedMutedStateBeforeAd = {
3331
3170
  muted: _this.video.muted,
3332
3171
  volume: _this.video.volume
3333
3172
  };
@@ -3355,10 +3194,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3355
3194
  });
3356
3195
  this.adLayer.on("content_resume", function() {
3357
3196
  var _ref, _ref1;
3358
- var _this_savedMutedStateBeforeScte, _this_savedMutedStateBeforeScte1;
3197
+ var _this_savedMutedStateBeforeAd, _this_savedMutedStateBeforeAd1;
3359
3198
  var remaining = _this.getRemainingAdMs();
3360
- var breakMuted = (_ref = (_this_savedMutedStateBeforeScte = _this.savedMutedStateBeforeScte) === null || _this_savedMutedStateBeforeScte === void 0 ? void 0 : _this_savedMutedStateBeforeScte.muted) !== null && _ref !== void 0 ? _ref : _this.adLayer.getOriginalMutedState();
3361
- var breakVolume = (_ref1 = (_this_savedMutedStateBeforeScte1 = _this.savedMutedStateBeforeScte) === null || _this_savedMutedStateBeforeScte1 === void 0 ? void 0 : _this_savedMutedStateBeforeScte1.volume) !== null && _ref1 !== void 0 ? _ref1 : _this.adLayer.getOriginalVolume();
3199
+ var breakMuted = (_ref = (_this_savedMutedStateBeforeAd = _this.savedMutedStateBeforeAd) === null || _this_savedMutedStateBeforeAd === void 0 ? void 0 : _this_savedMutedStateBeforeAd.muted) !== null && _ref !== void 0 ? _ref : _this.adLayer.getOriginalMutedState();
3200
+ var breakVolume = (_ref1 = (_this_savedMutedStateBeforeAd1 = _this.savedMutedStateBeforeAd) === null || _this_savedMutedStateBeforeAd1 === void 0 ? void 0 : _this_savedMutedStateBeforeAd1.volume) !== null && _ref1 !== void 0 ? _ref1 : _this.adLayer.getOriginalVolume();
3362
3201
  if (_this.config.debugAdTiming) {
3363
3202
  console.log("[StormcloudVideoPlayer] content_resume received, inAdBreak=%s, remaining=%s, preloadedTokens=%d, pendingNext=%s", _this.inAdBreak, remaining, _this.preloadedTokens.length, !!_this.pendingNextAdBids);
3364
3203
  }
@@ -3435,7 +3274,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3435
3274
  var remainingFinal = _this.getRemainingAdMs();
3436
3275
  if (_this.inAdBreak && remainingFinal > _this.MIN_AD_REMAINING_MS) {
3437
3276
  if (_this.config.debugAdTiming) {
3438
- console.log("[StormcloudVideoPlayer] content_resume: no more ads, showing filler for", remainingFinal, "ms");
3277
+ console.log("[StormcloudVideoPlayer] content_resume: ad ended/failed with time remaining, showing filler and continuing fetch for", remainingFinal, "ms");
3439
3278
  }
3440
3279
  if (!_this.config.disableFiller) {
3441
3280
  _this.showPlaceholderLayer();
@@ -3453,7 +3292,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3453
3292
  (_this_video_play = _this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
3454
3293
  }
3455
3294
  }
3456
- _this.stopContinuousFetching();
3295
+ _this.continuousFetchingActive = true;
3296
+ _this.startContinuousFetchLoop();
3457
3297
  return;
3458
3298
  }
3459
3299
  if (_this.config.debugAdTiming) {
@@ -3600,547 +3440,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3600
3440
  return !!(this.config.allowNativeHls && canNative);
3601
3441
  }
3602
3442
  },
3603
- {
3604
- key: "onId3Tag",
3605
- value: function onId3Tag(tag) {
3606
- if (typeof tag.ptsSeconds === "number") {
3607
- this.updatePtsDrift(tag.ptsSeconds);
3608
- }
3609
- var marker = this.parseScte35FromId3(tag);
3610
- if (marker) {
3611
- this.onScte35Marker(marker);
3612
- }
3613
- }
3614
- },
3615
- {
3616
- key: "parseScte35FromId3",
3617
- value: function parseScte35FromId3(tag) {
3618
- var text = this.decodeId3ValueToText(tag.value);
3619
- if (!text) return void 0;
3620
- var cueOutMatch = text.match(/EXT-X-CUE-OUT(?::([^\r\n]*))?/i) || text.match(/CUE-OUT(?::([^\r\n]*))?/i);
3621
- if (cueOutMatch) {
3622
- var _cueOutMatch_;
3623
- var arg = ((_cueOutMatch_ = cueOutMatch[1]) !== null && _cueOutMatch_ !== void 0 ? _cueOutMatch_ : "").trim();
3624
- var dur = this.parseCueOutDuration(arg);
3625
- var marker = _object_spread_props(_object_spread({
3626
- type: "start"
3627
- }, tag.ptsSeconds !== void 0 ? {
3628
- ptsSeconds: tag.ptsSeconds
3629
- } : {}, dur !== void 0 ? {
3630
- durationSeconds: dur
3631
- } : {}), {
3632
- raw: {
3633
- id3: text
3634
- }
3635
- });
3636
- return marker;
3637
- }
3638
- var cueOutContMatch = text.match(/EXT-X-CUE-OUT-CONT:([^\r\n]*)/i);
3639
- if (cueOutContMatch) {
3640
- var _cueOutContMatch_;
3641
- var arg1 = ((_cueOutContMatch_ = cueOutContMatch[1]) !== null && _cueOutContMatch_ !== void 0 ? _cueOutContMatch_ : "").trim();
3642
- var cont = this.parseCueOutCont(arg1);
3643
- var marker1 = _object_spread_props(_object_spread({
3644
- type: "progress"
3645
- }, tag.ptsSeconds !== void 0 ? {
3646
- ptsSeconds: tag.ptsSeconds
3647
- } : {}, (cont === null || cont === void 0 ? void 0 : cont.duration) !== void 0 ? {
3648
- durationSeconds: cont.duration
3649
- } : {}), {
3650
- raw: {
3651
- id3: text
3652
- }
3653
- });
3654
- return marker1;
3655
- }
3656
- var cueInMatch = text.match(/EXT-X-CUE-IN\b/i) || text.match(/CUE-IN\b/i);
3657
- if (cueInMatch) {
3658
- var marker2 = _object_spread_props(_object_spread({
3659
- type: "end"
3660
- }, tag.ptsSeconds !== void 0 ? {
3661
- ptsSeconds: tag.ptsSeconds
3662
- } : {}), {
3663
- raw: {
3664
- id3: text
3665
- }
3666
- });
3667
- return marker2;
3668
- }
3669
- var daterangeMatch = text.match(/EXT-X-DATERANGE:([^\r\n]*)/i);
3670
- if (daterangeMatch) {
3671
- var _daterangeMatch_, _attrs_CLASS;
3672
- var attrs = this.parseAttributeList((_daterangeMatch_ = daterangeMatch[1]) !== null && _daterangeMatch_ !== void 0 ? _daterangeMatch_ : "");
3673
- var hasScteOut = "SCTE35-OUT" in attrs || attrs["SCTE35-OUT"] !== void 0;
3674
- var hasScteIn = "SCTE35-IN" in attrs || attrs["SCTE35-IN"] !== void 0;
3675
- var klass = String((_attrs_CLASS = attrs["CLASS"]) !== null && _attrs_CLASS !== void 0 ? _attrs_CLASS : "");
3676
- var duration = this.toNumber(attrs["DURATION"]);
3677
- if (hasScteOut || /com\.apple\.hls\.cue/i.test(klass)) {
3678
- var marker3 = _object_spread_props(_object_spread({
3679
- type: "start"
3680
- }, tag.ptsSeconds !== void 0 ? {
3681
- ptsSeconds: tag.ptsSeconds
3682
- } : {}, duration !== void 0 ? {
3683
- durationSeconds: duration
3684
- } : {}), {
3685
- raw: {
3686
- id3: text,
3687
- attrs: attrs
3688
- }
3689
- });
3690
- return marker3;
3691
- }
3692
- if (hasScteIn) {
3693
- var marker4 = _object_spread_props(_object_spread({
3694
- type: "end"
3695
- }, tag.ptsSeconds !== void 0 ? {
3696
- ptsSeconds: tag.ptsSeconds
3697
- } : {}), {
3698
- raw: {
3699
- id3: text,
3700
- attrs: attrs
3701
- }
3702
- });
3703
- return marker4;
3704
- }
3705
- }
3706
- if (/SCTE35-OUT/i.test(text)) {
3707
- var marker5 = _object_spread_props(_object_spread({
3708
- type: "start"
3709
- }, tag.ptsSeconds !== void 0 ? {
3710
- ptsSeconds: tag.ptsSeconds
3711
- } : {}), {
3712
- raw: {
3713
- id3: text
3714
- }
3715
- });
3716
- return marker5;
3717
- }
3718
- if (/SCTE35-IN/i.test(text)) {
3719
- var marker6 = _object_spread_props(_object_spread({
3720
- type: "end"
3721
- }, tag.ptsSeconds !== void 0 ? {
3722
- ptsSeconds: tag.ptsSeconds
3723
- } : {}), {
3724
- raw: {
3725
- id3: text
3726
- }
3727
- });
3728
- return marker6;
3729
- }
3730
- if (_instanceof(tag.value, Uint8Array)) {
3731
- var bin = this.parseScte35Binary(tag.value);
3732
- if (bin) return bin;
3733
- }
3734
- return void 0;
3735
- }
3736
- },
3737
- {
3738
- key: "decodeId3ValueToText",
3739
- value: function decodeId3ValueToText(value) {
3740
- try {
3741
- if (typeof value === "string") return value;
3742
- var decoder = new TextDecoder("utf-8", {
3743
- fatal: false
3744
- });
3745
- var text = decoder.decode(value);
3746
- if (text && /[\x20-\x7E]/.test(text)) return text;
3747
- var out = "";
3748
- for(var i = 0; i < value.length; i++)out += String.fromCharCode(value[i]);
3749
- return out;
3750
- } catch (unused) {
3751
- return void 0;
3752
- }
3753
- }
3754
- },
3755
- {
3756
- key: "onScte35Marker",
3757
- value: function onScte35Marker(marker) {
3758
- var _this = this;
3759
- if (this.config.disableAds) return;
3760
- this.pushScteMarker(marker);
3761
- this.pushDebugLog("info", "scte35", "SCTE-35 marker detected", {
3762
- type: marker.type,
3763
- ptsSeconds: marker.ptsSeconds,
3764
- durationSeconds: marker.durationSeconds,
3765
- currentTime: this.video.currentTime
3766
- });
3767
- if (this.config.debugAdTiming) {
3768
- console.log("[StormcloudVideoPlayer] SCTE-35 marker detected:", {
3769
- type: marker.type,
3770
- ptsSeconds: marker.ptsSeconds,
3771
- durationSeconds: marker.durationSeconds,
3772
- currentTime: this.video.currentTime,
3773
- raw: marker.raw,
3774
- hasPendingAdBreak: !!this.pendingAdBreak
3775
- });
3776
- }
3777
- if (marker.type === "start") {
3778
- var _this_config_immediateManifestAds;
3779
- var _this_pendingAdBreak;
3780
- if (this.savedMutedStateBeforeScte == null) {
3781
- this.savedMutedStateBeforeScte = {
3782
- muted: this.video.muted,
3783
- volume: this.video.volume
3784
- };
3785
- this.adLayer.updateOriginalMutedState(this.video.muted, this.video.volume);
3786
- }
3787
- if (!this.config.disableFiller && !this.video.muted && !this.adLayer.isAdPlaying()) {
3788
- this.video.muted = true;
3789
- this.video.volume = 0;
3790
- if (this.config.debugAdTiming) {
3791
- console.log("[StormcloudVideoPlayer] Muted video on SCTE start marker");
3792
- }
3793
- }
3794
- if (this.inAdBreak) {
3795
- if (marker.durationSeconds != null) {
3796
- var newDurationMs = marker.durationSeconds * 1e3;
3797
- if (this.expectedAdBreakDurationMs == null || newDurationMs > this.expectedAdBreakDurationMs) {
3798
- this.expectedAdBreakDurationMs = newDurationMs;
3799
- var elapsedMs = this.currentAdBreakStartWallClockMs != null ? Date.now() - this.currentAdBreakStartWallClockMs : 0;
3800
- var remainingMs = Math.max(0, newDurationMs - elapsedMs);
3801
- this.scheduleAdStopCountdown(remainingMs);
3802
- if (this.config.debugAdTiming) {
3803
- console.log("[StormcloudVideoPlayer] Updated ad break duration from subsequent marker: ".concat(newDurationMs, "ms, remaining: ").concat(remainingMs, "ms"));
3804
- }
3805
- }
3806
- }
3807
- return;
3808
- }
3809
- this.inAdBreak = true;
3810
- var durationMs = marker.durationSeconds != null ? marker.durationSeconds * 1e3 : ((_this_pendingAdBreak = this.pendingAdBreak) === null || _this_pendingAdBreak === void 0 ? void 0 : _this_pendingAdBreak.marker.durationSeconds) != null ? this.pendingAdBreak.marker.durationSeconds * 1e3 : void 0;
3811
- this.expectedAdBreakDurationMs = durationMs;
3812
- this.currentAdBreakStartWallClockMs = Date.now();
3813
- if (this.config.licenseKey) {
3814
- var _this_pendingAdBreak1;
3815
- var adDetectInfo = _object_spread({
3816
- source: "scte35",
3817
- timestamp: /* @__PURE__ */ new Date().toISOString()
3818
- }, marker.durationSeconds != null && {
3819
- durationSeconds: marker.durationSeconds
3820
- }, marker.ptsSeconds != null && {
3821
- ptsSeconds: marker.ptsSeconds
3822
- }, ((_this_pendingAdBreak1 = this.pendingAdBreak) === null || _this_pendingAdBreak1 === void 0 ? void 0 : _this_pendingAdBreak1.detectedAtFragmentSn) != null && {
3823
- detectedAtFragmentSn: this.pendingAdBreak.detectedAtFragmentSn
3824
- });
3825
- sendAdDetectTracking(this.config.licenseKey, adDetectInfo);
3826
- }
3827
- var isManifestMarker = this.isManifestBasedMarker(marker);
3828
- var forceImmediate = (_this_config_immediateManifestAds = this.config.immediateManifestAds) !== null && _this_config_immediateManifestAds !== void 0 ? _this_config_immediateManifestAds : true;
3829
- if (this.config.debugAdTiming) {
3830
- console.log("[StormcloudVideoPlayer] Ad start decision:", {
3831
- isManifestMarker: isManifestMarker,
3832
- forceImmediate: forceImmediate,
3833
- hasPts: typeof marker.ptsSeconds === "number"
3834
- });
3835
- }
3836
- if (isManifestMarker && forceImmediate) {
3837
- if (this.config.debugAdTiming) {
3838
- console.log("[StormcloudVideoPlayer] Starting ad immediately (manifest-based)");
3839
- }
3840
- this.clearAdStartTimer();
3841
- this.handleAdStart(marker);
3842
- } else if (typeof marker.ptsSeconds === "number") {
3843
- var _this_config_driftToleranceMs;
3844
- var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
3845
- var nowMs = this.video.currentTime * 1e3;
3846
- var estCurrentPtsMs = nowMs - this.ptsDriftEmaMs;
3847
- var deltaMs = Math.floor(marker.ptsSeconds * 1e3 - estCurrentPtsMs);
3848
- if (this.config.debugAdTiming) {
3849
- console.log("[StormcloudVideoPlayer] PTS-based timing calculation:", {
3850
- nowMs: nowMs,
3851
- estCurrentPtsMs: estCurrentPtsMs,
3852
- markerPtsMs: marker.ptsSeconds * 1e3,
3853
- deltaMs: deltaMs,
3854
- tolerance: tol
3855
- });
3856
- }
3857
- if (deltaMs > tol) {
3858
- if (this.config.debugAdTiming) {
3859
- console.log("[StormcloudVideoPlayer] Scheduling ad start in ".concat(deltaMs, "ms"));
3860
- }
3861
- this.scheduleAdStartIn(deltaMs);
3862
- } else {
3863
- if (this.config.debugAdTiming) {
3864
- console.log("[StormcloudVideoPlayer] Starting ad immediately (within tolerance)");
3865
- }
3866
- this.clearAdStartTimer();
3867
- this.handleAdStart(marker);
3868
- }
3869
- } else {
3870
- if (this.config.debugAdTiming) {
3871
- console.log("[StormcloudVideoPlayer] Starting ad immediately (fallback)");
3872
- }
3873
- this.clearAdStartTimer();
3874
- this.handleAdStart(marker);
3875
- }
3876
- if (this.expectedAdBreakDurationMs != null) {
3877
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
3878
- }
3879
- return;
3880
- }
3881
- if (marker.type === "progress" && this.inAdBreak) {
3882
- if (marker.durationSeconds != null) {
3883
- this.expectedAdBreakDurationMs = marker.durationSeconds * 1e3;
3884
- }
3885
- if (this.expectedAdBreakDurationMs != null && this.currentAdBreakStartWallClockMs != null) {
3886
- var elapsedMs1 = Date.now() - this.currentAdBreakStartWallClockMs;
3887
- var remainingMs1 = Math.max(0, this.expectedAdBreakDurationMs - elapsedMs1);
3888
- this.scheduleAdStopCountdown(remainingMs1);
3889
- }
3890
- if (!this.adLayer.isAdPlaying() && this.pendingNextAdBids != null && this.pendingNextAdBids.length > 0) {
3891
- var bids = this.pendingNextAdBids;
3892
- this.pendingNextAdBids = null;
3893
- this.currentAdIndex++;
3894
- this.adLayer.playAd(bids).catch(function() {
3895
- return _this.handleAdFailure();
3896
- });
3897
- }
3898
- return;
3899
- }
3900
- if (marker.type === "end") {
3901
- var remaining = this.getRemainingAdMs();
3902
- var adPlaying = this.adLayer.isAdPlaying();
3903
- var hasQueuedAds = this.pendingNextAdBids != null && this.pendingNextAdBids.length > 0;
3904
- if (this.config.debugAdTiming) {
3905
- console.log("[StormcloudVideoPlayer] SCTE-35 end marker received:", {
3906
- inAdBreak: this.inAdBreak,
3907
- remaining: remaining,
3908
- adPlaying: adPlaying,
3909
- hasQueuedAds: hasQueuedAds,
3910
- activeAdRequest: this.activeAdRequestToken !== null
3911
- });
3912
- }
3913
- if (!this.inAdBreak) {
3914
- if (this.config.debugAdTiming) {
3915
- console.log("[StormcloudVideoPlayer] Ignoring SCTE-35 end marker - not in ad break");
3916
- }
3917
- return;
3918
- }
3919
- if (adPlaying || remaining > 500) {
3920
- if (this.config.debugAdTiming) {
3921
- console.log("[StormcloudVideoPlayer] Ignoring premature SCTE-35 end marker - ads still active or time remaining");
3922
- }
3923
- return;
3924
- }
3925
- this.inAdBreak = false;
3926
- this.expectedAdBreakDurationMs = void 0;
3927
- this.currentAdBreakStartWallClockMs = void 0;
3928
- this.clearAdStartTimer();
3929
- this.clearAdStopTimer();
3930
- if (adPlaying) {
3931
- this.adLayer.stop().catch(function() {});
3932
- }
3933
- this.handleAdPodComplete();
3934
- return;
3935
- }
3936
- }
3937
- },
3938
- {
3939
- key: "parseCueOutDuration",
3940
- value: function parseCueOutDuration(value) {
3941
- var num = parseFloat(value.trim());
3942
- if (!Number.isNaN(num)) return num;
3943
- var match = value.match(/(?:^|[,\s])DURATION\s*=\s*([0-9.]+)/i) || value.match(/Duration\s*=\s*([0-9.]+)/i);
3944
- if (match && match[1] != null) {
3945
- var dStr = match[1];
3946
- var d = parseFloat(dStr);
3947
- return Number.isNaN(d) ? void 0 : d;
3948
- }
3949
- return void 0;
3950
- }
3951
- },
3952
- {
3953
- key: "parseCueOutCont",
3954
- value: function parseCueOutCont(value) {
3955
- var res = {};
3956
- var elapsedMatch = value.match(/Elapsed\s*=\s*([0-9.]+)/i);
3957
- var durationMatch = value.match(/Duration\s*=\s*([0-9.]+)/i);
3958
- if (elapsedMatch && elapsedMatch[1] != null) {
3959
- var e = parseFloat(elapsedMatch[1]);
3960
- if (!Number.isNaN(e)) res.elapsed = e;
3961
- }
3962
- if (durationMatch && durationMatch[1] != null) {
3963
- var d = parseFloat(durationMatch[1]);
3964
- if (!Number.isNaN(d)) res.duration = d;
3965
- }
3966
- if (!("elapsed" in res) || !("duration" in res)) {
3967
- var slashMatch = value.match(/([0-9.]+)\s*\/\s*([0-9.]+)/);
3968
- if (slashMatch && slashMatch[1] && slashMatch[2]) {
3969
- var elapsed = parseFloat(slashMatch[1]);
3970
- var duration = parseFloat(slashMatch[2]);
3971
- if (!Number.isNaN(elapsed) && !("elapsed" in res)) res.elapsed = elapsed;
3972
- if (!Number.isNaN(duration) && !("duration" in res)) res.duration = duration;
3973
- }
3974
- }
3975
- if ("elapsed" in res || "duration" in res) return res;
3976
- return void 0;
3977
- }
3978
- },
3979
- {
3980
- key: "parseAttributeList",
3981
- value: function parseAttributeList(value) {
3982
- var attrs = {};
3983
- var regex = /([A-Z0-9-]+)=(("[^"]*")|([^",]*))(?:,|$)/gi;
3984
- var match;
3985
- while((match = regex.exec(value)) !== null){
3986
- var _match_, _ref, _match_1;
3987
- var key = (_match_ = match[1]) !== null && _match_ !== void 0 ? _match_ : "";
3988
- var rawVal = (_ref = (_match_1 = match[3]) !== null && _match_1 !== void 0 ? _match_1 : match[4]) !== null && _ref !== void 0 ? _ref : "";
3989
- if (rawVal.startsWith('"') && rawVal.endsWith('"')) {
3990
- rawVal = rawVal.slice(1, -1);
3991
- }
3992
- if (key) {
3993
- attrs[key] = rawVal;
3994
- }
3995
- }
3996
- return attrs;
3997
- }
3998
- },
3999
- {
4000
- key: "toNumber",
4001
- value: function toNumber(val) {
4002
- if (val == null) return void 0;
4003
- var n = typeof val === "string" ? parseFloat(val) : Number(val);
4004
- return Number.isNaN(n) ? void 0 : n;
4005
- }
4006
- },
4007
- {
4008
- key: "isManifestBasedMarker",
4009
- value: function isManifestBasedMarker(marker) {
4010
- var raw = marker.raw;
4011
- if (!raw) return false;
4012
- if (raw.tag) {
4013
- var tag = String(raw.tag);
4014
- return tag.includes("EXT-X-CUE-OUT") || tag.includes("EXT-X-CUE-IN") || tag.includes("EXT-X-DATERANGE");
4015
- }
4016
- if (raw.id3) return false;
4017
- if (raw.splice_command_type) return false;
4018
- return false;
4019
- }
4020
- },
4021
- {
4022
- key: "parseScte35Binary",
4023
- value: function parseScte35Binary(data) {
4024
- var BitReader = /*#__PURE__*/ function() {
4025
- function BitReader(buf) {
4026
- _class_call_check(this, BitReader);
4027
- this.buf = buf;
4028
- this.bytePos = 0;
4029
- this.bitPos = 0;
4030
- }
4031
- _create_class(BitReader, [
4032
- {
4033
- key: "readBits",
4034
- value: function readBits(numBits) {
4035
- var result = 0;
4036
- while(numBits > 0){
4037
- if (this.bytePos >= this.buf.length) return result;
4038
- var remainingInByte = 8 - this.bitPos;
4039
- var toRead = Math.min(numBits, remainingInByte);
4040
- var currentByte = this.buf[this.bytePos];
4041
- var shift = remainingInByte - toRead;
4042
- var mask = (1 << toRead) - 1 & 255;
4043
- var bits = currentByte >> shift & mask;
4044
- result = result << toRead | bits;
4045
- this.bitPos += toRead;
4046
- if (this.bitPos >= 8) {
4047
- this.bitPos = 0;
4048
- this.bytePos += 1;
4049
- }
4050
- numBits -= toRead;
4051
- }
4052
- return result >>> 0;
4053
- }
4054
- },
4055
- {
4056
- key: "skipBits",
4057
- value: function skipBits(n) {
4058
- this.readBits(n);
4059
- }
4060
- }
4061
- ]);
4062
- return BitReader;
4063
- }();
4064
- var r = new BitReader(data);
4065
- var tableId = r.readBits(8);
4066
- if (tableId !== 252) return void 0;
4067
- r.readBits(1);
4068
- r.readBits(1);
4069
- r.readBits(2);
4070
- var sectionLength = r.readBits(12);
4071
- r.readBits(8);
4072
- r.readBits(1);
4073
- r.readBits(6);
4074
- var ptsAdjHigh = r.readBits(1);
4075
- var ptsAdjLow = r.readBits(32);
4076
- void ptsAdjHigh;
4077
- void ptsAdjLow;
4078
- r.readBits(8);
4079
- r.readBits(12);
4080
- var spliceCommandLength = r.readBits(12);
4081
- var spliceCommandType = r.readBits(8);
4082
- if (spliceCommandType !== 5) {
4083
- return void 0;
4084
- }
4085
- r.readBits(32);
4086
- var cancel = r.readBits(1) === 1;
4087
- r.readBits(7);
4088
- if (cancel) return void 0;
4089
- var outOfNetwork = r.readBits(1) === 1;
4090
- var programSpliceFlag = r.readBits(1) === 1;
4091
- var durationFlag = r.readBits(1) === 1;
4092
- var spliceImmediateFlag = r.readBits(1) === 1;
4093
- r.readBits(4);
4094
- if (programSpliceFlag && !spliceImmediateFlag) {
4095
- var timeSpecifiedFlag = r.readBits(1) === 1;
4096
- if (timeSpecifiedFlag) {
4097
- r.readBits(6);
4098
- r.readBits(33);
4099
- } else {
4100
- r.readBits(7);
4101
- }
4102
- } else if (!programSpliceFlag) {
4103
- var componentCount = r.readBits(8);
4104
- for(var i = 0; i < componentCount; i++){
4105
- r.readBits(8);
4106
- if (!spliceImmediateFlag) {
4107
- var timeSpecifiedFlag1 = r.readBits(1) === 1;
4108
- if (timeSpecifiedFlag1) {
4109
- r.readBits(6);
4110
- r.readBits(33);
4111
- } else {
4112
- r.readBits(7);
4113
- }
4114
- }
4115
- }
4116
- }
4117
- var durationSeconds = void 0;
4118
- if (durationFlag) {
4119
- r.readBits(6);
4120
- r.readBits(1);
4121
- var high = r.readBits(1);
4122
- var low = r.readBits(32);
4123
- var durationTicks = high * 4294967296 + low;
4124
- durationSeconds = durationTicks / 9e4;
4125
- }
4126
- r.readBits(16);
4127
- r.readBits(8);
4128
- r.readBits(8);
4129
- if (outOfNetwork) {
4130
- var marker = _object_spread_props(_object_spread({
4131
- type: "start"
4132
- }, durationSeconds !== void 0 ? {
4133
- durationSeconds: durationSeconds
4134
- } : {}), {
4135
- raw: {
4136
- splice_command_type: 5
4137
- }
4138
- });
4139
- return marker;
4140
- }
4141
- return void 0;
4142
- }
4143
- },
4144
3443
  {
4145
3444
  key: "initializeTracking",
4146
3445
  value: function initializeTracking() {
@@ -4262,35 +3561,35 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4262
3561
  },
4263
3562
  {
4264
3563
  key: "startAdPrefetch",
4265
- value: function startAdPrefetch(marker, fragmentSn) {
3564
+ value: function startAdPrefetch(durationSeconds, fragmentSn) {
4266
3565
  if (this.config.disableAds) return;
4267
3566
  if (this.pendingAdBreak || this.inAdBreak) {
4268
3567
  return;
4269
3568
  }
4270
- this.pendingAdBreak = _object_spread_props(_object_spread({
4271
- marker: marker
4272
- }, fragmentSn !== void 0 ? {
3569
+ this.pendingAdBreak = _object_spread_props(_object_spread({}, durationSeconds !== void 0 ? {
3570
+ durationSeconds: durationSeconds
3571
+ } : {}, fragmentSn !== void 0 ? {
4273
3572
  detectedAtFragmentSn: fragmentSn
4274
3573
  } : {}), {
4275
3574
  isFetching: false,
4276
3575
  fetchStartTime: Date.now()
4277
3576
  });
4278
- void this.runAdPrefetch(marker);
3577
+ void this.runAdPrefetch(durationSeconds);
4279
3578
  if (this.config.debugAdTiming) {
4280
- console.log("[PREFETCH] Ad break marker registered, multi-ad prefetch started");
3579
+ console.log("[PREFETCH] Ad break registered, multi-ad prefetch started");
4281
3580
  }
4282
3581
  }
4283
3582
  },
4284
3583
  {
4285
3584
  key: "runAdPrefetch",
4286
- value: function runAdPrefetch(marker) {
3585
+ value: function runAdPrefetch(durationSeconds) {
4287
3586
  return _async_to_generator(function() {
4288
- var _this, _marker_durationSeconds, _ref, _firstBids_, durSec, context, firstBids, unused, adDurationSec, estimatedCount, firstToken, remaining, results, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, result, token;
3587
+ var _this, _ref, _firstBids_, durSec, context, firstBids, unused, adDurationSec, estimatedCount, firstToken, unused1, remaining, results, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, result, token, unused2, err;
4289
3588
  return _ts_generator(this, function(_state) {
4290
3589
  switch(_state.label){
4291
3590
  case 0:
4292
3591
  _this = this;
4293
- durSec = (_marker_durationSeconds = marker.durationSeconds) !== null && _marker_durationSeconds !== void 0 ? _marker_durationSeconds : 60;
3592
+ durSec = durationSeconds !== null && durationSeconds !== void 0 ? durationSeconds : 60;
4294
3593
  context = {
4295
3594
  breakDurationSec: durSec,
4296
3595
  remainingBreakSec: durSec
@@ -4340,14 +3639,43 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4340
3639
  console.log("[PREFETCH] Ad duration=".concat(adDurationSec, "s, break=").concat(durSec, "s → ").concat(estimatedCount, " ad(s) needed"));
4341
3640
  }
4342
3641
  firstToken = "preload_".concat(Date.now(), "_").concat(Math.random().toString(36).slice(2, 7));
4343
- this.preloadedTokens.push(firstToken);
4344
- void this.adLayer.preloadAd(firstBids, firstToken);
3642
+ _state.label = 5;
3643
+ case 5:
3644
+ _state.trys.push([
3645
+ 5,
3646
+ 7,
3647
+ ,
3648
+ 8
3649
+ ]);
3650
+ return [
3651
+ 4,
3652
+ this.adLayer.preloadAd(firstBids, firstToken)
3653
+ ];
3654
+ case 6:
3655
+ _state.sent();
3656
+ if (!this.inAdBreak) {
3657
+ this.preloadedTokens.push(firstToken);
3658
+ if (this.config.debugAdTiming) {
3659
+ console.log("[PREFETCH] First ad preloaded and queued, token=".concat(firstToken));
3660
+ }
3661
+ }
3662
+ return [
3663
+ 3,
3664
+ 8
3665
+ ];
3666
+ case 7:
3667
+ unused1 = _state.sent();
4345
3668
  if (this.config.debugAdTiming) {
4346
- console.log("[PREFETCH] First ad preloading, token=".concat(firstToken));
3669
+ console.warn("[PREFETCH] First ad preload failed, token=".concat(firstToken));
4347
3670
  }
3671
+ return [
3672
+ 3,
3673
+ 8
3674
+ ];
3675
+ case 8:
4348
3676
  if (!(estimatedCount > 1)) return [
4349
3677
  3,
4350
- 6
3678
+ 19
4351
3679
  ];
4352
3680
  remaining = Array.from({
4353
3681
  length: estimatedCount - 1
@@ -4369,38 +3697,100 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4369
3697
  4,
4370
3698
  Promise.all(remaining)
4371
3699
  ];
4372
- case 5:
3700
+ case 9:
4373
3701
  results = _state.sent();
4374
3702
  _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
3703
+ _state.label = 10;
3704
+ case 10:
3705
+ _state.trys.push([
3706
+ 10,
3707
+ 17,
3708
+ 18,
3709
+ 19
3710
+ ]);
3711
+ _iterator = results[Symbol.iterator]();
3712
+ _state.label = 11;
3713
+ case 11:
3714
+ if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
3715
+ 3,
3716
+ 16
3717
+ ];
3718
+ result = _step.value;
3719
+ if (this.inAdBreak) return [
3720
+ 3,
3721
+ 16
3722
+ ];
3723
+ if (!(result.ok && result.value.length > 0)) return [
3724
+ 3,
3725
+ 15
3726
+ ];
3727
+ token = "preload_".concat(Date.now(), "_").concat(Math.random().toString(36).slice(2, 7));
3728
+ _state.label = 12;
3729
+ case 12:
3730
+ _state.trys.push([
3731
+ 12,
3732
+ 14,
3733
+ ,
3734
+ 15
3735
+ ]);
3736
+ return [
3737
+ 4,
3738
+ this.adLayer.preloadAd(result.value, token)
3739
+ ];
3740
+ case 13:
3741
+ _state.sent();
3742
+ if (!this.inAdBreak) {
3743
+ this.preloadedTokens.push(token);
3744
+ if (this.config.debugAdTiming) {
3745
+ console.log("[PREFETCH] Additional ad preloaded and queued, token=".concat(token));
3746
+ }
3747
+ }
3748
+ return [
3749
+ 3,
3750
+ 15
3751
+ ];
3752
+ case 14:
3753
+ unused2 = _state.sent();
3754
+ if (this.config.debugAdTiming) {
3755
+ console.warn("[PREFETCH] Additional ad preload failed, token=".concat(token));
3756
+ }
3757
+ return [
3758
+ 3,
3759
+ 15
3760
+ ];
3761
+ case 15:
3762
+ _iteratorNormalCompletion = true;
3763
+ return [
3764
+ 3,
3765
+ 11
3766
+ ];
3767
+ case 16:
3768
+ return [
3769
+ 3,
3770
+ 19
3771
+ ];
3772
+ case 17:
3773
+ err = _state.sent();
3774
+ _didIteratorError = true;
3775
+ _iteratorError = err;
3776
+ return [
3777
+ 3,
3778
+ 19
3779
+ ];
3780
+ case 18:
4375
3781
  try {
4376
- for(_iterator = results[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
4377
- result = _step.value;
4378
- if (this.inAdBreak) break;
4379
- if (result.ok && result.value.length > 0) {
4380
- token = "preload_".concat(Date.now(), "_").concat(Math.random().toString(36).slice(2, 7));
4381
- this.preloadedTokens.push(token);
4382
- void this.adLayer.preloadAd(result.value, token);
4383
- if (this.config.debugAdTiming) {
4384
- console.log("[PREFETCH] Additional ad preloading, token=".concat(token));
4385
- }
4386
- }
3782
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
3783
+ _iterator.return();
4387
3784
  }
4388
- } catch (err) {
4389
- _didIteratorError = true;
4390
- _iteratorError = err;
4391
3785
  } finally{
4392
- try {
4393
- if (!_iteratorNormalCompletion && _iterator.return != null) {
4394
- _iterator.return();
4395
- }
4396
- } finally{
4397
- if (_didIteratorError) {
4398
- throw _iteratorError;
4399
- }
3786
+ if (_didIteratorError) {
3787
+ throw _iteratorError;
4400
3788
  }
4401
3789
  }
4402
- _state.label = 6;
4403
- case 6:
3790
+ return [
3791
+ 7
3792
+ ];
3793
+ case 19:
4404
3794
  if (this.config.debugAdTiming) {
4405
3795
  console.log("[PREFETCH] Pre-fetch complete: ".concat(this.preloadedTokens.length, " ad(s) queued"));
4406
3796
  }
@@ -4448,6 +3838,177 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4448
3838
  this.preloadedTokens = [];
4449
3839
  }
4450
3840
  },
3841
+ {
3842
+ key: "startAdInsertionPolling",
3843
+ value: function startAdInsertionPolling() {
3844
+ var _this = this;
3845
+ if (this.adInsertionPollingId != null) return;
3846
+ this.fetchAdInsertionPoint();
3847
+ this.adInsertionPollingId = window.setInterval(function() {
3848
+ _this.fetchAdInsertionPoint();
3849
+ }, 1e3);
3850
+ }
3851
+ },
3852
+ {
3853
+ key: "stopAdInsertionPolling",
3854
+ value: function stopAdInsertionPolling() {
3855
+ if (this.adInsertionPollingId != null) {
3856
+ clearInterval(this.adInsertionPollingId);
3857
+ this.adInsertionPollingId = void 0;
3858
+ }
3859
+ }
3860
+ },
3861
+ {
3862
+ key: "fetchAdInsertionPoint",
3863
+ value: function fetchAdInsertionPoint() {
3864
+ return _async_to_generator(function() {
3865
+ var _this_lastAdInsertionPoint, resp, data, isNew, unused;
3866
+ return _ts_generator(this, function(_state) {
3867
+ switch(_state.label){
3868
+ case 0:
3869
+ if (!this.config.projectId) return [
3870
+ 2
3871
+ ];
3872
+ _state.label = 1;
3873
+ case 1:
3874
+ _state.trys.push([
3875
+ 1,
3876
+ 4,
3877
+ ,
3878
+ 5
3879
+ ]);
3880
+ return [
3881
+ 4,
3882
+ fetch("https://adstorm.co/api-adstorm-dev/adstorm/swirl/projects/".concat(encodeURIComponent(this.config.projectId), "/ad-insertion-point"))
3883
+ ];
3884
+ case 2:
3885
+ resp = _state.sent();
3886
+ if (!resp.ok) return [
3887
+ 2
3888
+ ];
3889
+ return [
3890
+ 4,
3891
+ resp.json()
3892
+ ];
3893
+ case 3:
3894
+ data = _state.sent();
3895
+ isNew = data.updated_at !== ((_this_lastAdInsertionPoint = this.lastAdInsertionPoint) === null || _this_lastAdInsertionPoint === void 0 ? void 0 : _this_lastAdInsertionPoint.updated_at);
3896
+ this.lastAdInsertionPoint = data;
3897
+ if (isNew) {
3898
+ this.pushAdInsertionDebug("api_response", data.segment_ts_name, {
3899
+ offsetSeconds: data.offset_seconds,
3900
+ updatedAt: data.updated_at,
3901
+ detail: "project=".concat(data.project_id)
3902
+ });
3903
+ }
3904
+ if (this.config.debugAdTiming) {
3905
+ console.log("[StormcloudVideoPlayer] Ad insertion point API response:", data);
3906
+ }
3907
+ return [
3908
+ 3,
3909
+ 5
3910
+ ];
3911
+ case 4:
3912
+ unused = _state.sent();
3913
+ if (this.config.debugAdTiming) {
3914
+ console.warn("[StormcloudVideoPlayer] Ad insertion point API fetch failed");
3915
+ }
3916
+ return [
3917
+ 3,
3918
+ 5
3919
+ ];
3920
+ case 5:
3921
+ return [
3922
+ 2
3923
+ ];
3924
+ }
3925
+ });
3926
+ }).call(this);
3927
+ }
3928
+ },
3929
+ {
3930
+ key: "checkAdInsertionInManifest",
3931
+ value: function checkAdInsertionInManifest() {
3932
+ var _this_hls;
3933
+ if (!this.lastAdInsertionPoint) return;
3934
+ if (this.inAdBreak || this.pendingAdBreak) return;
3935
+ if (this.lastAdInsertionPoint.updated_at === this.processedAdInsertionUpdatedAt) return;
3936
+ var segmentName = this.lastAdInsertionPoint.segment_ts_name;
3937
+ var levels = (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : _this_hls.levels;
3938
+ if (!levels) return;
3939
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
3940
+ try {
3941
+ for(var _iterator = levels[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
3942
+ var level = _step.value;
3943
+ var _level_details;
3944
+ var fragments = (_level_details = level.details) === null || _level_details === void 0 ? void 0 : _level_details.fragments;
3945
+ if (!Array.isArray(fragments)) continue;
3946
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
3947
+ try {
3948
+ for(var _iterator1 = fragments[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
3949
+ var frag = _step1.value;
3950
+ if (this.fragmentMatchesSegment(frag, segmentName)) {
3951
+ var _ref;
3952
+ this.pushAdInsertionDebug("segment_found", segmentName, {
3953
+ detail: "sn=".concat((_ref = frag === null || frag === void 0 ? void 0 : frag.sn) !== null && _ref !== void 0 ? _ref : "?")
3954
+ });
3955
+ if (this.config.debugAdTiming) {
3956
+ console.log('[StormcloudVideoPlayer] Ad insertion segment "'.concat(segmentName, '" found in manifest — starting pre-fetch'));
3957
+ }
3958
+ this.startAdPrefetch(60, frag === null || frag === void 0 ? void 0 : frag.sn);
3959
+ return;
3960
+ }
3961
+ }
3962
+ } catch (err) {
3963
+ _didIteratorError1 = true;
3964
+ _iteratorError1 = err;
3965
+ } finally{
3966
+ try {
3967
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
3968
+ _iterator1.return();
3969
+ }
3970
+ } finally{
3971
+ if (_didIteratorError1) {
3972
+ throw _iteratorError1;
3973
+ }
3974
+ }
3975
+ }
3976
+ }
3977
+ } catch (err) {
3978
+ _didIteratorError = true;
3979
+ _iteratorError = err;
3980
+ } finally{
3981
+ try {
3982
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
3983
+ _iterator.return();
3984
+ }
3985
+ } finally{
3986
+ if (_didIteratorError) {
3987
+ throw _iteratorError;
3988
+ }
3989
+ }
3990
+ }
3991
+ }
3992
+ },
3993
+ {
3994
+ key: "fragmentMatchesSegment",
3995
+ value: function fragmentMatchesSegment(frag, segmentName) {
3996
+ var _rawUrl_split_;
3997
+ var rawUrl = (frag === null || frag === void 0 ? void 0 : frag.url) || (frag === null || frag === void 0 ? void 0 : frag.relurl) || "";
3998
+ var url = (_rawUrl_split_ = rawUrl.split("?")[0]) !== null && _rawUrl_split_ !== void 0 ? _rawUrl_split_ : "";
3999
+ var name = segmentName.startsWith("/") ? segmentName : "/" + segmentName;
4000
+ return url.endsWith(name) || url.includes(name);
4001
+ }
4002
+ },
4003
+ {
4004
+ key: "clearAdInsertionOffsetTimer",
4005
+ value: function clearAdInsertionOffsetTimer() {
4006
+ if (this.adInsertionOffsetTimerId != null) {
4007
+ clearTimeout(this.adInsertionOffsetTimerId);
4008
+ this.adInsertionOffsetTimerId = void 0;
4009
+ }
4010
+ }
4011
+ },
4451
4012
  {
4452
4013
  key: "startContinuousFetchLoop",
4453
4014
  value: function startContinuousFetchLoop() {
@@ -4773,13 +4334,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4773
4334
  },
4774
4335
  {
4775
4336
  key: "handleAdStart",
4776
- value: function handleAdStart(_marker) {
4337
+ value: function handleAdStart(durationSeconds) {
4777
4338
  return _async_to_generator(function() {
4778
- var _this_savedMutedStateBeforeScte, adBreakDurationMs, mode, state, adBreakToken, adVolume, token, remaining, err;
4339
+ var _this_savedMutedStateBeforeAd, adBreakDurationMs, mode, state, adBreakToken, adVolume, token, remaining, err;
4779
4340
  return _ts_generator(this, function(_state) {
4780
4341
  switch(_state.label){
4781
4342
  case 0:
4782
- adBreakDurationMs = _marker.durationSeconds != null ? _marker.durationSeconds * 1e3 : void 0;
4343
+ adBreakDurationMs = durationSeconds != null ? durationSeconds * 1e3 : void 0;
4783
4344
  if (this.config.debugAdTiming) {
4784
4345
  mode = this.isLiveStream ? "LIVE" : "VOD";
4785
4346
  console.log("[CONTINUOUS-FETCH] \uD83D\uDCFA ".concat(mode, " MODE: Target duration=").concat(adBreakDurationMs, "ms"));
@@ -4790,13 +4351,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4790
4351
  this.pendingNextAdBids = null;
4791
4352
  this.isShowingPlaceholder = false;
4792
4353
  this.totalAdRequestsInBreak = 0;
4793
- if (this.savedMutedStateBeforeScte == null && !this.video.muted) {
4794
- this.savedMutedStateBeforeScte = {
4354
+ if (this.savedMutedStateBeforeAd == null && !this.video.muted) {
4355
+ this.savedMutedStateBeforeAd = {
4795
4356
  muted: false,
4796
4357
  volume: this.video.volume
4797
4358
  };
4798
4359
  }
4799
- state = (_this_savedMutedStateBeforeScte = this.savedMutedStateBeforeScte) !== null && _this_savedMutedStateBeforeScte !== void 0 ? _this_savedMutedStateBeforeScte : {
4360
+ state = (_this_savedMutedStateBeforeAd = this.savedMutedStateBeforeAd) !== null && _this_savedMutedStateBeforeAd !== void 0 ? _this_savedMutedStateBeforeAd : {
4800
4361
  muted: this.video.muted,
4801
4362
  volume: this.video.volume
4802
4363
  };
@@ -4823,6 +4384,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4823
4384
  if (this.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {
4824
4385
  this.expectedAdBreakDurationMs = adBreakDurationMs;
4825
4386
  }
4387
+ if (this.expectedAdBreakDurationMs != null) {
4388
+ this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
4389
+ }
4826
4390
  this.clearPendingAdBreak();
4827
4391
  adBreakToken = Date.now();
4828
4392
  this.activeAdRequestToken = adBreakToken;
@@ -5321,54 +4885,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5321
4885
  this.handleAdPodComplete();
5322
4886
  }
5323
4887
  },
5324
- {
5325
- key: "scheduleAdStartIn",
5326
- value: function scheduleAdStartIn(delayMs) {
5327
- var _this = this;
5328
- this.clearAdStartTimer();
5329
- var ms = Math.max(0, Math.floor(delayMs));
5330
- if (ms === 0) {
5331
- this.handleAdStart({
5332
- type: "start"
5333
- }).catch(function() {});
5334
- return;
5335
- }
5336
- this.adStartTimerId = window.setTimeout(function() {
5337
- _this.handleAdStart({
5338
- type: "start"
5339
- }).catch(function() {});
5340
- }, ms);
5341
- }
5342
- },
5343
- {
5344
- key: "clearAdStartTimer",
5345
- value: function clearAdStartTimer() {
5346
- if (this.adStartTimerId != null) {
5347
- clearTimeout(this.adStartTimerId);
5348
- this.adStartTimerId = void 0;
5349
- }
5350
- }
5351
- },
5352
- {
5353
- key: "updatePtsDrift",
5354
- value: function updatePtsDrift(ptsSecondsSample) {
5355
- var sampleMs = (this.video.currentTime - ptsSecondsSample) * 1e3;
5356
- if (!Number.isFinite(sampleMs) || Math.abs(sampleMs) > 6e4) return;
5357
- var alpha = 0.1;
5358
- this.ptsDriftEmaMs = this.ptsDriftEmaMs * (1 - alpha) + sampleMs * alpha;
5359
- }
5360
- },
5361
4888
  {
5362
4889
  key: "handleAdPodComplete",
5363
4890
  value: function handleAdPodComplete() {
5364
4891
  var _this = this;
5365
4892
  var _ref, _ref1;
5366
- var _this_savedMutedStateBeforeScte, _this_savedMutedStateBeforeScte1;
4893
+ var _this_savedMutedStateBeforeAd, _this_savedMutedStateBeforeAd1;
5367
4894
  if (this.config.debugAdTiming) {
5368
4895
  console.log("[StormcloudVideoPlayer] \uD83C\uDFC1 Ad pod complete - cleaning up");
5369
4896
  }
5370
4897
  this.clearAdRequestWatchdog();
5371
4898
  this.clearAdFailsafeTimer();
4899
+ this.clearAdInsertionOffsetTimer();
5372
4900
  this.activeAdRequestToken = null;
5373
4901
  this.isInAdTransition = false;
5374
4902
  this.stopContinuousFetching();
@@ -5384,7 +4912,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5384
4912
  this.inAdBreak = false;
5385
4913
  this.expectedAdBreakDurationMs = void 0;
5386
4914
  this.currentAdBreakStartWallClockMs = void 0;
5387
- this.clearAdStartTimer();
5388
4915
  this.clearAdStopTimer();
5389
4916
  this.adPodQueue = [];
5390
4917
  this.showAds = false;
@@ -5392,8 +4919,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5392
4919
  this.totalAdsInBreak = 0;
5393
4920
  this.totalAdRequestsInBreak = 0;
5394
4921
  this.consecutiveFailures = 0;
5395
- var restoredMuted = (_ref = (_this_savedMutedStateBeforeScte = this.savedMutedStateBeforeScte) === null || _this_savedMutedStateBeforeScte === void 0 ? void 0 : _this_savedMutedStateBeforeScte.muted) !== null && _ref !== void 0 ? _ref : this.adLayer.getOriginalMutedState();
5396
- var restoredVolume = (_ref1 = (_this_savedMutedStateBeforeScte1 = this.savedMutedStateBeforeScte) === null || _this_savedMutedStateBeforeScte1 === void 0 ? void 0 : _this_savedMutedStateBeforeScte1.volume) !== null && _ref1 !== void 0 ? _ref1 : this.adLayer.getOriginalVolume();
4922
+ var restoredMuted = (_ref = (_this_savedMutedStateBeforeAd = this.savedMutedStateBeforeAd) === null || _this_savedMutedStateBeforeAd === void 0 ? void 0 : _this_savedMutedStateBeforeAd.muted) !== null && _ref !== void 0 ? _ref : this.adLayer.getOriginalMutedState();
4923
+ var restoredVolume = (_ref1 = (_this_savedMutedStateBeforeAd1 = this.savedMutedStateBeforeAd) === null || _this_savedMutedStateBeforeAd1 === void 0 ? void 0 : _this_savedMutedStateBeforeAd1.volume) !== null && _ref1 !== void 0 ? _ref1 : this.adLayer.getOriginalVolume();
5397
4924
  this.adLayer.updateOriginalMutedState(restoredMuted, restoredVolume);
5398
4925
  this.adLayer.stop().catch(function() {});
5399
4926
  if (this.video.muted !== restoredMuted) {
@@ -5502,7 +5029,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5502
5029
  }, delay);
5503
5030
  });
5504
5031
  }
5505
- this.savedMutedStateBeforeScte = null;
5032
+ this.savedMutedStateBeforeAd = null;
5506
5033
  }
5507
5034
  },
5508
5035
  {
@@ -5652,19 +5179,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5652
5179
  return Math.max(0, this.expectedAdBreakDurationMs - elapsed);
5653
5180
  }
5654
5181
  },
5655
- {
5656
- key: "pushScteMarker",
5657
- value: function pushScteMarker(marker) {
5658
- if (!this.config.debugAdTiming) return;
5659
- this.scteMarkerHistory.push({
5660
- timestampMs: Date.now(),
5661
- marker: marker
5662
- });
5663
- if (this.scteMarkerHistory.length > DEBUG_HISTORY_LIMIT) {
5664
- this.scteMarkerHistory = this.scteMarkerHistory.slice(-DEBUG_HISTORY_LIMIT);
5665
- }
5666
- }
5667
- },
5668
5182
  {
5669
5183
  key: "pushDebugLog",
5670
5184
  value: function pushDebugLog(level, category, message, details) {
@@ -5683,20 +5197,29 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5683
5197
  }
5684
5198
  },
5685
5199
  {
5686
- key: "getRecentScteMarkers",
5687
- value: function getRecentScteMarkers() {
5688
- return this.scteMarkerHistory.map(function(entry) {
5689
- return _object_spread({
5690
- timestampMs: entry.timestampMs,
5691
- type: entry.marker.type
5692
- }, entry.marker.ptsSeconds !== void 0 ? {
5693
- ptsSeconds: entry.marker.ptsSeconds
5694
- } : {}, entry.marker.durationSeconds !== void 0 ? {
5695
- durationSeconds: entry.marker.durationSeconds
5696
- } : {}, entry.marker.raw !== void 0 ? {
5697
- raw: entry.marker.raw
5698
- } : {});
5699
- });
5200
+ key: "pushAdInsertionDebug",
5201
+ value: function pushAdInsertionDebug(event, segmentName, opts) {
5202
+ if (!this.config.debugAdTiming) return;
5203
+ this.adInsertionDebugHistory.push(_object_spread({
5204
+ timestampMs: Date.now(),
5205
+ event: event,
5206
+ segmentName: segmentName
5207
+ }, (opts === null || opts === void 0 ? void 0 : opts.offsetSeconds) !== void 0 ? {
5208
+ offsetSeconds: opts.offsetSeconds
5209
+ } : {}, (opts === null || opts === void 0 ? void 0 : opts.updatedAt) ? {
5210
+ updatedAt: opts.updatedAt
5211
+ } : {}, (opts === null || opts === void 0 ? void 0 : opts.detail) ? {
5212
+ detail: opts.detail
5213
+ } : {}));
5214
+ if (this.adInsertionDebugHistory.length > DEBUG_HISTORY_LIMIT) {
5215
+ this.adInsertionDebugHistory = this.adInsertionDebugHistory.slice(-DEBUG_HISTORY_LIMIT);
5216
+ }
5217
+ }
5218
+ },
5219
+ {
5220
+ key: "getAdInsertionDebugLog",
5221
+ value: function getAdInsertionDebugLog() {
5222
+ return this.adInsertionDebugHistory.slice();
5700
5223
  }
5701
5224
  },
5702
5225
  {
@@ -5965,9 +5488,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5965
5488
  key: "destroy",
5966
5489
  value: function destroy() {
5967
5490
  var _this_hls, _this_adLayer;
5491
+ this.stopAdInsertionPolling();
5492
+ this.clearAdInsertionOffsetTimer();
5968
5493
  this.stopContinuousFetching();
5969
5494
  this.stopFillerBreakTimer();
5970
- this.clearAdStartTimer();
5971
5495
  this.clearAdStopTimer();
5972
5496
  this.clearAdFailsafeTimer();
5973
5497
  this.clearAdRequestWatchdog();
@@ -5995,7 +5519,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5995
5519
  (_this_adLayer = this.adLayer) === null || _this_adLayer === void 0 ? void 0 : _this_adLayer.destroy();
5996
5520
  this.consecutiveFailures = 0;
5997
5521
  this.debugLogEntries = [];
5998
- this.scteMarkerHistory = [];
5522
+ this.adInsertionDebugHistory = [];
5999
5523
  }
6000
5524
  }
6001
5525
  ]);
@@ -7372,7 +6896,7 @@ var AI_CONTEXT_MIN_POLL_MS = 800;
7372
6896
  var PANEL_BASE_RIGHT_OFFSET = 10;
7373
6897
  var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props) {
7374
6898
  var _ref;
7375
- var _aiLiveContext_context, _aiLiveContext_context_keywords, _aiLiveContext_context1;
6899
+ var _aiLiveContext_context;
7376
6900
  var src = props.src, autoplay = props.autoplay, muted = props.muted, lowLatencyMode = props.lowLatencyMode, allowNativeHls = props.allowNativeHls, driftToleranceMs = props.driftToleranceMs, immediateManifestAds = props.immediateManifestAds, debugAdTiming = props.debugAdTiming, showCustomControls = props.showCustomControls, hideLoadingIndicator = props.hideLoadingIndicator, onVolumeToggle = props.onVolumeToggle, onFullscreenToggle = props.onFullscreenToggle, onControlClick = props.onControlClick, onReady = props.onReady, wrapperClassName = props.wrapperClassName, wrapperStyle = props.wrapperStyle, className = props.className, style = props.style, controls = props.controls, playsInline = props.playsInline, preload = props.preload, poster = props.poster, children = props.children, licenseKey = props.licenseKey, minSegmentsBeforePlay = props.minSegmentsBeforePlay, disableAds = props.disableAds, disableFiller = props.disableFiller, swirlProjectId = props.swirlProjectId, restVideoAttrs = _object_without_properties(props, [
7377
6901
  "src",
7378
6902
  "autoplay",
@@ -7464,13 +6988,44 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7464
6988
  return "--:--:--";
7465
6989
  }
7466
6990
  };
7467
- var formatDebugRaw = function formatDebugRaw(raw) {
7468
- if (!raw || (typeof raw === "undefined" ? "undefined" : _type_of(raw)) !== "object") return "";
7469
- var obj = raw;
7470
- if (typeof obj.tag === "string") return obj.tag;
7471
- if (typeof obj.id3 === "string") return "ID3";
7472
- if (typeof obj.splice_command_type === "number") return "binary splice";
7473
- return "marker";
6991
+ var formatAdInsertionEvent = function formatAdInsertionEvent(event) {
6992
+ switch(event){
6993
+ case "api_response":
6994
+ return {
6995
+ label: "API",
6996
+ color: "#60a5fa"
6997
+ };
6998
+ case "scte35_inserted":
6999
+ return {
7000
+ label: "SCTE-35",
7001
+ color: "#f43f5e"
7002
+ };
7003
+ case "segment_found":
7004
+ return {
7005
+ label: "FOUND",
7006
+ color: "#a78bfa"
7007
+ };
7008
+ case "segment_playing":
7009
+ return {
7010
+ label: "PLAYING",
7011
+ color: "#fbbf24"
7012
+ };
7013
+ case "ad_scheduled":
7014
+ return {
7015
+ label: "SCHED",
7016
+ color: "#fb923c"
7017
+ };
7018
+ case "ad_triggered":
7019
+ return {
7020
+ label: "TRIGGER",
7021
+ color: "#34d399"
7022
+ };
7023
+ default:
7024
+ return {
7025
+ label: event,
7026
+ color: "rgba(255,255,255,0.68)"
7027
+ };
7028
+ }
7474
7029
  };
7475
7030
  var formatAiRelativeTime = function formatAiRelativeTime(timestamp) {
7476
7031
  var epochMs = Date.parse(timestamp);
@@ -7615,6 +7170,7 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7615
7170
  if (minSegmentsBeforePlay !== void 0) cfg.minSegmentsBeforePlay = minSegmentsBeforePlay;
7616
7171
  if (disableAds !== void 0) cfg.disableAds = disableAds;
7617
7172
  cfg.disableFiller = disableFiller !== null && disableFiller !== void 0 ? disableFiller : true;
7173
+ if (swirlProjectId !== void 0) cfg.projectId = String(swirlProjectId);
7618
7174
  var player = new StormcloudVideoPlayer(cfg);
7619
7175
  playerRef.current = player;
7620
7176
  player.load().then(function() {
@@ -7883,7 +7439,7 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7883
7439
  var updateDebugData = function updateDebugData() {
7884
7440
  var player = playerRef.current;
7885
7441
  if (!player) return;
7886
- setDebugMarkers(player.getRecentScteMarkers().slice(-DEBUG_PANEL_MARKER_LIMIT).reverse());
7442
+ setDebugMarkers(player.getAdInsertionDebugLog().slice(-DEBUG_PANEL_MARKER_LIMIT).reverse());
7887
7443
  };
7888
7444
  updateDebugData();
7889
7445
  var interval = window.setInterval(updateDebugData, 500);
@@ -8418,34 +7974,7 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
8418
7974
  whiteSpace: "pre-wrap"
8419
7975
  },
8420
7976
  children: (_ref = (_aiLiveContext_context = aiLiveContext.context) === null || _aiLiveContext_context === void 0 ? void 0 : _aiLiveContext_context.context) !== null && _ref !== void 0 ? _ref : aiLiveContext.isLoading ? "Analyzing live stream..." : "Waiting for AI context response."
8421
- }),
8422
- ((_aiLiveContext_context1 = aiLiveContext.context) === null || _aiLiveContext_context1 === void 0 ? void 0 : (_aiLiveContext_context_keywords = _aiLiveContext_context1.keywords) === null || _aiLiveContext_context_keywords === void 0 ? void 0 : _aiLiveContext_context_keywords.length) ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8423
- style: {
8424
- marginTop: "10px",
8425
- display: "flex",
8426
- flexWrap: "wrap",
8427
- gap: "6px"
8428
- },
8429
- children: aiLiveContext.context.keywords.slice(0, 12).map(function(kw) {
8430
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8431
- style: {
8432
- fontSize: "10px",
8433
- fontWeight: 600,
8434
- padding: "4px 7px",
8435
- borderRadius: "999px",
8436
- background: "rgba(236, 72, 153, 0.2)",
8437
- border: "1px solid rgba(244, 114, 182, 0.42)",
8438
- color: "#fce7f3",
8439
- maxWidth: "100%",
8440
- overflow: "hidden",
8441
- textOverflow: "ellipsis",
8442
- whiteSpace: "nowrap"
8443
- },
8444
- title: kw,
8445
- children: kw
8446
- }, kw);
8447
- })
8448
- }) : null
7977
+ })
8449
7978
  ]
8450
7979
  })
8451
7980
  ]
@@ -8487,7 +8016,7 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
8487
8016
  fontWeight: 700,
8488
8017
  letterSpacing: "0.02em"
8489
8018
  },
8490
- children: "Debug Ad Timing"
8019
+ children: "Ad Insertion Debug"
8491
8020
  }),
8492
8021
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", {
8493
8022
  className: "sc-ctrl-btn",
@@ -8515,9 +8044,13 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
8515
8044
  overflowX: "hidden",
8516
8045
  height: "calc(100% - 46px)",
8517
8046
  display: "grid",
8518
- gap: "12px"
8047
+ gap: "12px",
8048
+ minWidth: 0
8519
8049
  },
8520
8050
  children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8051
+ style: {
8052
+ minWidth: 0
8053
+ },
8521
8054
  children: [
8522
8055
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8523
8056
  style: {
@@ -8528,69 +8061,145 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
8528
8061
  color: "rgba(255,255,255,0.68)",
8529
8062
  marginBottom: "8px"
8530
8063
  },
8531
- children: "SCTE-35 markers"
8064
+ children: "Ad Insertion Points"
8532
8065
  }),
8533
8066
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8534
8067
  style: {
8535
8068
  display: "grid",
8536
- gap: "6px"
8069
+ gap: "6px",
8070
+ minWidth: 0
8537
8071
  },
8538
8072
  children: debugMarkers.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8539
8073
  style: {
8540
8074
  fontSize: "12px",
8541
8075
  color: "rgba(255,255,255,0.55)"
8542
8076
  },
8543
- children: "No markers detected yet."
8077
+ children: "No ad insertion events yet."
8544
8078
  }) : debugMarkers.map(function(entry, idx) {
8079
+ var evt = formatAdInsertionEvent(entry.event);
8080
+ var fileName = entry.segmentName ? entry.segmentName.split("/").pop() || entry.segmentName : "";
8545
8081
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8546
8082
  style: {
8547
- display: "grid",
8548
- gridTemplateColumns: "56px 52px 1fr",
8549
- gap: "8px",
8550
- alignItems: "center",
8083
+ minWidth: 0,
8551
8084
  fontFamily: "'SF Mono', 'Cascadia Code', monospace",
8552
8085
  fontSize: "11px",
8553
8086
  background: "rgba(255,255,255,0.05)",
8554
8087
  border: "1px solid rgba(255,255,255,0.08)",
8555
8088
  borderRadius: "8px",
8556
- padding: "6px 8px"
8089
+ padding: "6px 8px",
8090
+ display: "flex",
8091
+ flexDirection: "column",
8092
+ gap: "4px"
8557
8093
  },
8558
8094
  children: [
8559
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8560
- style: {
8561
- color: "rgba(255,255,255,0.68)"
8562
- },
8563
- children: formatDebugClock(entry.timestampMs)
8564
- }),
8565
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8095
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8566
8096
  style: {
8567
- textTransform: "uppercase",
8568
- fontWeight: 700,
8569
- color: entry.type === "start" ? "#34d399" : entry.type === "end" ? "#f87171" : "#fbbf24"
8097
+ display: "grid",
8098
+ gridTemplateColumns: "56px 54px minmax(0, 1fr) 20px",
8099
+ gap: "6px",
8100
+ alignItems: "center",
8101
+ minWidth: 0
8570
8102
  },
8571
- children: entry.type
8103
+ children: [
8104
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8105
+ style: {
8106
+ color: "rgba(255,255,255,0.68)"
8107
+ },
8108
+ children: formatDebugClock(entry.timestampMs)
8109
+ }),
8110
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8111
+ style: {
8112
+ fontWeight: 700,
8113
+ color: evt.color,
8114
+ fontSize: "10px"
8115
+ },
8116
+ children: evt.label
8117
+ }),
8118
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8119
+ style: {
8120
+ color: "rgba(255,255,255,0.88)",
8121
+ overflow: "hidden",
8122
+ textOverflow: "ellipsis",
8123
+ whiteSpace: "nowrap",
8124
+ minWidth: 0
8125
+ },
8126
+ title: entry.segmentName,
8127
+ children: fileName
8128
+ }),
8129
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", {
8130
+ onClick: function onClick() {
8131
+ return navigator.clipboard.writeText(entry.segmentName);
8132
+ },
8133
+ title: entry.segmentName,
8134
+ style: {
8135
+ background: "none",
8136
+ border: "none",
8137
+ cursor: "pointer",
8138
+ padding: "2px",
8139
+ color: "rgba(255,255,255,0.45)",
8140
+ display: "flex",
8141
+ alignItems: "center",
8142
+ justifyContent: "center",
8143
+ borderRadius: "4px",
8144
+ flexShrink: 0
8145
+ },
8146
+ onMouseEnter: function onMouseEnter(e) {
8147
+ return e.currentTarget.style.color = "rgba(255,255,255,0.9)";
8148
+ },
8149
+ onMouseLeave: function onMouseLeave(e) {
8150
+ return e.currentTarget.style.color = "rgba(255,255,255,0.45)";
8151
+ },
8152
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_fa.FaCopy, {
8153
+ size: 10
8154
+ })
8155
+ })
8156
+ ]
8572
8157
  }),
8573
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8158
+ (entry.offsetSeconds != null || entry.detail || entry.updatedAt) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8574
8159
  style: {
8575
- color: "rgba(255,255,255,0.88)"
8160
+ display: "flex",
8161
+ flexWrap: "wrap",
8162
+ gap: "6px",
8163
+ paddingLeft: "0px",
8164
+ fontSize: "10px"
8576
8165
  },
8577
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", {
8578
- style: {
8579
- display: "inline-block",
8580
- maxWidth: "100%",
8581
- verticalAlign: "bottom",
8582
- overflow: "hidden",
8583
- textOverflow: "ellipsis",
8584
- whiteSpace: "nowrap"
8585
- },
8586
- children: [
8587
- entry.durationSeconds != null ? "dur:".concat(entry.durationSeconds.toFixed(2), "s") : "dur:-",
8588
- " ",
8589
- entry.ptsSeconds != null ? "pts:".concat(entry.ptsSeconds.toFixed(2)) : "pts:-",
8590
- " ",
8591
- formatDebugRaw(entry.raw)
8592
- ]
8593
- })
8166
+ children: [
8167
+ entry.offsetSeconds != null && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", {
8168
+ style: {
8169
+ color: "rgba(255,255,255,0.55)",
8170
+ background: "rgba(255,255,255,0.06)",
8171
+ borderRadius: "4px",
8172
+ padding: "1px 5px"
8173
+ },
8174
+ children: [
8175
+ "+",
8176
+ entry.offsetSeconds.toFixed(2),
8177
+ "s"
8178
+ ]
8179
+ }),
8180
+ entry.detail && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8181
+ style: {
8182
+ color: "rgba(255,255,255,0.55)",
8183
+ background: "rgba(255,255,255,0.06)",
8184
+ borderRadius: "4px",
8185
+ padding: "1px 5px",
8186
+ overflow: "hidden",
8187
+ textOverflow: "ellipsis",
8188
+ whiteSpace: "nowrap",
8189
+ maxWidth: "100%"
8190
+ },
8191
+ children: entry.detail
8192
+ }),
8193
+ entry.updatedAt && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8194
+ style: {
8195
+ color: "rgba(255,255,255,0.38)",
8196
+ background: "rgba(255,255,255,0.04)",
8197
+ borderRadius: "4px",
8198
+ padding: "1px 5px"
8199
+ },
8200
+ children: formatAiRelativeTime(entry.updatedAt)
8201
+ })
8202
+ ]
8594
8203
  })
8595
8204
  ]
8596
8205
  }, "".concat(entry.timestampMs, "-").concat(idx));