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.
package/lib/index.cjs CHANGED
@@ -1582,7 +1582,6 @@ function createAdStormPlayer(contentVideo, options) {
1582
1582
  contentVideo.muted = originalMutedState;
1583
1583
  contentVideo.volume = originalVolume;
1584
1584
  currentAd = void 0;
1585
- tornDown = false;
1586
1585
  return [
1587
1586
  2,
1588
1587
  Promise.resolve()
@@ -1697,6 +1696,15 @@ function createAdStormPlayer(contentVideo, options) {
1697
1696
  if (!token) return [
1698
1697
  2
1699
1698
  ];
1699
+ if (currentAd) {
1700
+ preloadSlots.set(token, {
1701
+ ad: currentAd
1702
+ });
1703
+ currentAd = void 0;
1704
+ return [
1705
+ 2
1706
+ ];
1707
+ }
1700
1708
  requestContext = typeof arg1 === "string" ? arg2 : arg1;
1701
1709
  return [
1702
1710
  4,
@@ -2190,56 +2198,6 @@ function sendInitialTracking(licenseKey) {
2190
2198
  });
2191
2199
  })();
2192
2200
  }
2193
- function sendAdDetectTracking(licenseKey, adDetectInfo) {
2194
- return _async_to_generator(function() {
2195
- var clientInfo, browserId, trackingData, error;
2196
- return _ts_generator(this, function(_state) {
2197
- switch(_state.label){
2198
- case 0:
2199
- _state.trys.push([
2200
- 0,
2201
- 3,
2202
- ,
2203
- 4
2204
- ]);
2205
- clientInfo = getClientInfo();
2206
- return [
2207
- 4,
2208
- getBrowserID(clientInfo)
2209
- ];
2210
- case 1:
2211
- browserId = _state.sent();
2212
- trackingData = _object_spread({
2213
- browserId: browserId
2214
- }, clientInfo);
2215
- return [
2216
- 4,
2217
- sendTrackRequest(licenseKey, _object_spread_props(_object_spread({}, trackingData), {
2218
- licenseKey: licenseKey,
2219
- adDetectInfo: adDetectInfo
2220
- }))
2221
- ];
2222
- case 2:
2223
- _state.sent();
2224
- return [
2225
- 3,
2226
- 4
2227
- ];
2228
- case 3:
2229
- error = _state.sent();
2230
- console.error("[StormcloudVideoPlayer] Error sending ad detect tracking:", error);
2231
- return [
2232
- 3,
2233
- 4
2234
- ];
2235
- case 4:
2236
- return [
2237
- 2
2238
- ];
2239
- }
2240
- });
2241
- })();
2242
- }
2243
2201
  function sendAdLoadedTracking(licenseKey, adLoadedInfo) {
2244
2202
  return _async_to_generator(function() {
2245
2203
  var clientInfo, browserId, trackingData, error;
@@ -2949,7 +2907,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2949
2907
  this.continuousFetchLoopPromise = null;
2950
2908
  this.attached = false;
2951
2909
  this.inAdBreak = false;
2952
- this.ptsDriftEmaMs = 0;
2953
2910
  this.adPodQueue = [];
2954
2911
  this.lastHeartbeatTime = 0;
2955
2912
  this.currentAdIndex = 0;
@@ -2968,10 +2925,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2968
2925
  this.isInAdTransition = false;
2969
2926
  this.maxPlaceholderDurationMs = 5e3;
2970
2927
  this.isShowingPlaceholder = false;
2928
+ this.lastAdInsertionPoint = null;
2929
+ this.processedAdInsertionUpdatedAt = null;
2971
2930
  this.totalAdRequestsInBreak = 0;
2972
2931
  this.maxTotalAdRequestsPerBreak = 20;
2973
2932
  this.pendingAdBreak = null;
2974
- this.savedMutedStateBeforeScte = null;
2933
+ this.savedMutedStateBeforeAd = null;
2975
2934
  this.consecutiveFailures = 0;
2976
2935
  this.maxConsecutiveFailures = 5;
2977
2936
  this.lastAdRequestTime = 0;
@@ -2984,7 +2943,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2984
2943
  this.adRequestRetryBackoffMs = 1500;
2985
2944
  this.preloadedTokens = [];
2986
2945
  this.debugLogEntries = [];
2987
- this.scteMarkerHistory = [];
2946
+ this.adInsertionDebugHistory = [];
2988
2947
  initializePolyfills();
2989
2948
  var browserOverrides = getBrowserConfigOverrides();
2990
2949
  this.config = _object_spread({}, browserOverrides, config);
@@ -3169,6 +3128,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3169
3128
  _state.sent();
3170
3129
  _state.label = 2;
3171
3130
  case 2:
3131
+ if (!this.config.disableAds && this.config.projectId) {
3132
+ this.startAdInsertionPolling();
3133
+ }
3172
3134
  return [
3173
3135
  2
3174
3136
  ];
@@ -3176,78 +3138,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3176
3138
  });
3177
3139
  }).call(_this);
3178
3140
  });
3179
- this.hls.on(import_hls.default.Events.LEVEL_LOADED, function(_evt, data) {
3141
+ this.hls.on(import_hls.default.Events.LEVEL_LOADED, function() {
3180
3142
  if (_this.inAdBreak || _this.pendingAdBreak) {
3181
3143
  return;
3182
3144
  }
3183
- var details = data === null || data === void 0 ? void 0 : data.details;
3184
- if (!details || !details.fragments || details.fragments.length === 0) {
3185
- return;
3186
- }
3187
- var fragmentsToScan = Math.min(5, details.fragments.length);
3188
- for(var i = 0; i < fragmentsToScan; i++){
3189
- var frag = details.fragments[i];
3190
- var tagList = frag === null || frag === void 0 ? void 0 : frag.tagList;
3191
- if (!Array.isArray(tagList)) continue;
3192
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
3193
- try {
3194
- for(var _iterator = tagList[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
3195
- var entry = _step.value;
3196
- var tag = "";
3197
- var value = "";
3198
- if (Array.isArray(entry)) {
3199
- var _entry_, _entry_1;
3200
- tag = String((_entry_ = entry[0]) !== null && _entry_ !== void 0 ? _entry_ : "");
3201
- value = String((_entry_1 = entry[1]) !== null && _entry_1 !== void 0 ? _entry_1 : "");
3202
- } else if (typeof entry === "string") {
3203
- var idx = entry.indexOf(":");
3204
- if (idx >= 0) {
3205
- tag = entry.substring(0, idx);
3206
- value = entry.substring(idx + 1);
3207
- } else {
3208
- tag = entry;
3209
- }
3210
- }
3211
- if (!tag) continue;
3212
- if (tag.includes("EXT-X-CUE-OUT") || tag.includes("EXT-X-DATERANGE")) {
3213
- var attrs = tag.includes("EXT-X-DATERANGE") ? _this.parseAttributeList(value) : {};
3214
- var hasScteOut = tag.includes("EXT-X-CUE-OUT") || "SCTE35-OUT" in attrs || attrs["SCTE35-OUT"] !== void 0;
3215
- if (hasScteOut) {
3216
- var durationSeconds = _this.parseCueOutDuration(value);
3217
- var marker = _object_spread_props(_object_spread({
3218
- type: "start"
3219
- }, durationSeconds !== void 0 ? {
3220
- durationSeconds: durationSeconds
3221
- } : {}), {
3222
- raw: {
3223
- tag: tag,
3224
- value: value,
3225
- earlyDetection: true
3226
- }
3227
- });
3228
- if (_this.config.debugAdTiming) {
3229
- console.log("[StormcloudVideoPlayer] \uD83C\uDFAF EARLY SCTE-35 DETECTION: Ad break marker found in fragment", i, "- starting pre-fetch (NOT playing yet)");
3230
- }
3231
- _this.startAdPrefetch(marker, frag === null || frag === void 0 ? void 0 : frag.sn);
3232
- return;
3233
- }
3234
- }
3235
- }
3236
- } catch (err) {
3237
- _didIteratorError = true;
3238
- _iteratorError = err;
3239
- } finally{
3240
- try {
3241
- if (!_iteratorNormalCompletion && _iterator.return != null) {
3242
- _iterator.return();
3243
- }
3244
- } finally{
3245
- if (_didIteratorError) {
3246
- throw _iteratorError;
3247
- }
3248
- }
3249
- }
3250
- }
3145
+ _this.checkAdInsertionInManifest();
3251
3146
  });
3252
3147
  this.hls.on(import_hls.default.Events.FRAG_BUFFERED, function(_evt, data) {
3253
3148
  return _async_to_generator(function() {
@@ -3309,111 +3204,55 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3309
3204
  });
3310
3205
  }).call(_this);
3311
3206
  });
3312
- this.hls.on(import_hls.default.Events.FRAG_PARSING_METADATA, function(_evt, data) {
3313
- var id3Tags = ((data === null || data === void 0 ? void 0 : data.samples) || []).map(function(s) {
3314
- return {
3315
- key: "ID3",
3316
- value: s === null || s === void 0 ? void 0 : s.data,
3317
- ptsSeconds: s === null || s === void 0 ? void 0 : s.pts
3318
- };
3319
- });
3320
- id3Tags.forEach(function(tag) {
3321
- return _this.onId3Tag(tag);
3322
- });
3323
- });
3324
3207
  this.hls.on(import_hls.default.Events.FRAG_CHANGED, function(_evt, data) {
3325
3208
  var frag = data === null || data === void 0 ? void 0 : data.frag;
3326
- var tagList = frag === null || frag === void 0 ? void 0 : frag.tagList;
3327
- if (!Array.isArray(tagList)) return;
3328
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
3329
- try {
3330
- for(var _iterator = tagList[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
3331
- var entry = _step.value;
3332
- var tag = "";
3333
- var value = "";
3334
- if (Array.isArray(entry)) {
3335
- var _entry_, _entry_1;
3336
- tag = String((_entry_ = entry[0]) !== null && _entry_ !== void 0 ? _entry_ : "");
3337
- value = String((_entry_1 = entry[1]) !== null && _entry_1 !== void 0 ? _entry_1 : "");
3338
- } else if (typeof entry === "string") {
3339
- var idx = entry.indexOf(":");
3340
- if (idx >= 0) {
3341
- tag = entry.substring(0, idx);
3342
- value = entry.substring(idx + 1);
3343
- } else {
3344
- tag = entry;
3345
- value = "";
3346
- }
3209
+ if (!frag) return;
3210
+ if (_this.lastAdInsertionPoint && !_this.inAdBreak && _this.lastAdInsertionPoint.updated_at !== _this.processedAdInsertionUpdatedAt) {
3211
+ var segmentName = _this.lastAdInsertionPoint.segment_ts_name;
3212
+ if (_this.fragmentMatchesSegment(frag, segmentName)) {
3213
+ var _ref;
3214
+ _this.processedAdInsertionUpdatedAt = _this.lastAdInsertionPoint.updated_at;
3215
+ var offsetMs = (_this.lastAdInsertionPoint.offset_seconds || 0) * 1e3;
3216
+ _this.pushAdInsertionDebug("segment_playing", segmentName, {
3217
+ offsetSeconds: _this.lastAdInsertionPoint.offset_seconds,
3218
+ detail: "sn=".concat((_ref = frag === null || frag === void 0 ? void 0 : frag.sn) !== null && _ref !== void 0 ? _ref : "?")
3219
+ });
3220
+ if (_this.config.debugAdTiming) {
3221
+ console.log('[StormcloudVideoPlayer] Ad insertion segment "'.concat(segmentName, '" now playing — scheduling ad start in ').concat(offsetMs, "ms"));
3347
3222
  }
3348
- if (!tag) continue;
3349
- if (tag.includes("EXT-X-CUE-OUT-CONT")) {
3350
- var prog = _this.parseCueOutCont(value);
3351
- var marker = _object_spread_props(_object_spread({
3352
- type: "progress"
3353
- }, (prog === null || prog === void 0 ? void 0 : prog.duration) !== void 0 ? {
3354
- durationSeconds: prog.duration
3355
- } : {}, (prog === null || prog === void 0 ? void 0 : prog.elapsed) !== void 0 ? {
3356
- ptsSeconds: prog.elapsed
3357
- } : {}), {
3358
- raw: {
3359
- tag: tag,
3360
- value: value
3361
- }
3362
- });
3363
- _this.onScte35Marker(marker);
3364
- } else if (tag.includes("EXT-X-CUE-OUT")) {
3365
- var durationSeconds = _this.parseCueOutDuration(value);
3366
- var marker1 = _object_spread_props(_object_spread({
3367
- type: "start"
3368
- }, durationSeconds !== void 0 ? {
3369
- durationSeconds: durationSeconds
3370
- } : {}), {
3371
- raw: {
3372
- tag: tag,
3373
- value: value
3374
- }
3375
- });
3376
- _this.onScte35Marker(marker1);
3377
- } else if (tag.includes("EXT-X-CUE-IN")) {
3378
- _this.onScte35Marker({
3379
- type: "end",
3380
- raw: {
3381
- tag: tag,
3382
- value: value
3383
- }
3223
+ _this.pushAdInsertionDebug("ad_scheduled", segmentName, {
3224
+ offsetSeconds: _this.lastAdInsertionPoint.offset_seconds,
3225
+ detail: "in ".concat(offsetMs, "ms, dur=60s")
3226
+ });
3227
+ _this.clearAdInsertionOffsetTimer();
3228
+ _this.adInsertionOffsetTimerId = window.setTimeout(function() {
3229
+ _this.adInsertionOffsetTimerId = void 0;
3230
+ if (_this.inAdBreak) return;
3231
+ _this.pushAdInsertionDebug("ad_triggered", segmentName, {
3232
+ detail: "ad break started (60s)"
3384
3233
  });
3385
- } else if (tag.includes("EXT-X-DATERANGE")) {
3386
- var _attrs_CLASS;
3387
- var attrs = _this.parseAttributeList(value);
3388
- var hasScteOut = "SCTE35-OUT" in attrs || attrs["SCTE35-OUT"] !== void 0;
3389
- var hasScteIn = "SCTE35-IN" in attrs || attrs["SCTE35-IN"] !== void 0;
3390
- var klass = String((_attrs_CLASS = attrs["CLASS"]) !== null && _attrs_CLASS !== void 0 ? _attrs_CLASS : "");
3391
- var duration = _this.toNumber(attrs["DURATION"]);
3392
- if (hasScteOut || /com\.apple\.hls\.cue/i.test(klass)) {
3393
- var marker2 = _object_spread_props(_object_spread({
3394
- type: "start"
3395
- }, duration !== void 0 ? {
3396
- durationSeconds: duration
3397
- } : {}), {
3398
- raw: {
3399
- tag: tag,
3400
- value: value,
3401
- attrs: attrs
3402
- }
3403
- });
3404
- _this.onScte35Marker(marker2);
3405
- }
3406
- if (hasScteIn) {
3407
- _this.onScte35Marker({
3408
- type: "end",
3409
- raw: {
3410
- tag: tag,
3411
- value: value,
3412
- attrs: attrs
3413
- }
3414
- });
3415
- }
3416
- }
3234
+ void _this.handleAdStart(60);
3235
+ }, offsetMs);
3236
+ }
3237
+ }
3238
+ });
3239
+ this.hls.on(import_hls.default.Events.FRAG_PARSING_USERDATA, function(_evt, data) {
3240
+ var _ref;
3241
+ var samples = (_ref = data === null || data === void 0 ? void 0 : data.samples) !== null && _ref !== void 0 ? _ref : [];
3242
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
3243
+ try {
3244
+ for(var _iterator = samples[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
3245
+ var sample = _step.value;
3246
+ var _ref1, _ref2;
3247
+ var _data_frag, _data_frag1;
3248
+ var bytes = sample === null || sample === void 0 ? void 0 : sample.data;
3249
+ if (!bytes || bytes.length < 5) continue;
3250
+ var isSCTE35 = bytes[0] === 252;
3251
+ if (!isSCTE35) continue;
3252
+ 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 : "";
3253
+ _this.pushAdInsertionDebug("scte35_inserted", segName, {
3254
+ detail: "len=".concat(bytes.length, "B")
3255
+ });
3417
3256
  }
3418
3257
  } catch (err) {
3419
3258
  _didIteratorError = true;
@@ -3504,8 +3343,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3504
3343
  _this.activeAdRequestToken = null;
3505
3344
  _this.showAds = true;
3506
3345
  if (_this.config.disableFiller) {
3507
- if (_this.savedMutedStateBeforeScte == null) {
3508
- _this.savedMutedStateBeforeScte = {
3346
+ if (_this.savedMutedStateBeforeAd == null) {
3347
+ _this.savedMutedStateBeforeAd = {
3509
3348
  muted: _this.video.muted,
3510
3349
  volume: _this.video.volume
3511
3350
  };
@@ -3533,10 +3372,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3533
3372
  });
3534
3373
  this.adLayer.on("content_resume", function() {
3535
3374
  var _ref, _ref1;
3536
- var _this_savedMutedStateBeforeScte, _this_savedMutedStateBeforeScte1;
3375
+ var _this_savedMutedStateBeforeAd, _this_savedMutedStateBeforeAd1;
3537
3376
  var remaining = _this.getRemainingAdMs();
3538
- 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();
3539
- 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();
3377
+ 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();
3378
+ 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();
3540
3379
  if (_this.config.debugAdTiming) {
3541
3380
  console.log("[StormcloudVideoPlayer] content_resume received, inAdBreak=%s, remaining=%s, preloadedTokens=%d, pendingNext=%s", _this.inAdBreak, remaining, _this.preloadedTokens.length, !!_this.pendingNextAdBids);
3542
3381
  }
@@ -3613,7 +3452,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3613
3452
  var remainingFinal = _this.getRemainingAdMs();
3614
3453
  if (_this.inAdBreak && remainingFinal > _this.MIN_AD_REMAINING_MS) {
3615
3454
  if (_this.config.debugAdTiming) {
3616
- console.log("[StormcloudVideoPlayer] content_resume: no more ads, showing filler for", remainingFinal, "ms");
3455
+ console.log("[StormcloudVideoPlayer] content_resume: ad ended/failed with time remaining, showing filler and continuing fetch for", remainingFinal, "ms");
3617
3456
  }
3618
3457
  if (!_this.config.disableFiller) {
3619
3458
  _this.showPlaceholderLayer();
@@ -3631,7 +3470,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3631
3470
  (_this_video_play = _this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
3632
3471
  }
3633
3472
  }
3634
- _this.stopContinuousFetching();
3473
+ _this.continuousFetchingActive = true;
3474
+ _this.startContinuousFetchLoop();
3635
3475
  return;
3636
3476
  }
3637
3477
  if (_this.config.debugAdTiming) {
@@ -3778,547 +3618,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3778
3618
  return !!(this.config.allowNativeHls && canNative);
3779
3619
  }
3780
3620
  },
3781
- {
3782
- key: "onId3Tag",
3783
- value: function onId3Tag(tag) {
3784
- if (typeof tag.ptsSeconds === "number") {
3785
- this.updatePtsDrift(tag.ptsSeconds);
3786
- }
3787
- var marker = this.parseScte35FromId3(tag);
3788
- if (marker) {
3789
- this.onScte35Marker(marker);
3790
- }
3791
- }
3792
- },
3793
- {
3794
- key: "parseScte35FromId3",
3795
- value: function parseScte35FromId3(tag) {
3796
- var text = this.decodeId3ValueToText(tag.value);
3797
- if (!text) return void 0;
3798
- var cueOutMatch = text.match(/EXT-X-CUE-OUT(?::([^\r\n]*))?/i) || text.match(/CUE-OUT(?::([^\r\n]*))?/i);
3799
- if (cueOutMatch) {
3800
- var _cueOutMatch_;
3801
- var arg = ((_cueOutMatch_ = cueOutMatch[1]) !== null && _cueOutMatch_ !== void 0 ? _cueOutMatch_ : "").trim();
3802
- var dur = this.parseCueOutDuration(arg);
3803
- var marker = _object_spread_props(_object_spread({
3804
- type: "start"
3805
- }, tag.ptsSeconds !== void 0 ? {
3806
- ptsSeconds: tag.ptsSeconds
3807
- } : {}, dur !== void 0 ? {
3808
- durationSeconds: dur
3809
- } : {}), {
3810
- raw: {
3811
- id3: text
3812
- }
3813
- });
3814
- return marker;
3815
- }
3816
- var cueOutContMatch = text.match(/EXT-X-CUE-OUT-CONT:([^\r\n]*)/i);
3817
- if (cueOutContMatch) {
3818
- var _cueOutContMatch_;
3819
- var arg1 = ((_cueOutContMatch_ = cueOutContMatch[1]) !== null && _cueOutContMatch_ !== void 0 ? _cueOutContMatch_ : "").trim();
3820
- var cont = this.parseCueOutCont(arg1);
3821
- var marker1 = _object_spread_props(_object_spread({
3822
- type: "progress"
3823
- }, tag.ptsSeconds !== void 0 ? {
3824
- ptsSeconds: tag.ptsSeconds
3825
- } : {}, (cont === null || cont === void 0 ? void 0 : cont.duration) !== void 0 ? {
3826
- durationSeconds: cont.duration
3827
- } : {}), {
3828
- raw: {
3829
- id3: text
3830
- }
3831
- });
3832
- return marker1;
3833
- }
3834
- var cueInMatch = text.match(/EXT-X-CUE-IN\b/i) || text.match(/CUE-IN\b/i);
3835
- if (cueInMatch) {
3836
- var marker2 = _object_spread_props(_object_spread({
3837
- type: "end"
3838
- }, tag.ptsSeconds !== void 0 ? {
3839
- ptsSeconds: tag.ptsSeconds
3840
- } : {}), {
3841
- raw: {
3842
- id3: text
3843
- }
3844
- });
3845
- return marker2;
3846
- }
3847
- var daterangeMatch = text.match(/EXT-X-DATERANGE:([^\r\n]*)/i);
3848
- if (daterangeMatch) {
3849
- var _daterangeMatch_, _attrs_CLASS;
3850
- var attrs = this.parseAttributeList((_daterangeMatch_ = daterangeMatch[1]) !== null && _daterangeMatch_ !== void 0 ? _daterangeMatch_ : "");
3851
- var hasScteOut = "SCTE35-OUT" in attrs || attrs["SCTE35-OUT"] !== void 0;
3852
- var hasScteIn = "SCTE35-IN" in attrs || attrs["SCTE35-IN"] !== void 0;
3853
- var klass = String((_attrs_CLASS = attrs["CLASS"]) !== null && _attrs_CLASS !== void 0 ? _attrs_CLASS : "");
3854
- var duration = this.toNumber(attrs["DURATION"]);
3855
- if (hasScteOut || /com\.apple\.hls\.cue/i.test(klass)) {
3856
- var marker3 = _object_spread_props(_object_spread({
3857
- type: "start"
3858
- }, tag.ptsSeconds !== void 0 ? {
3859
- ptsSeconds: tag.ptsSeconds
3860
- } : {}, duration !== void 0 ? {
3861
- durationSeconds: duration
3862
- } : {}), {
3863
- raw: {
3864
- id3: text,
3865
- attrs: attrs
3866
- }
3867
- });
3868
- return marker3;
3869
- }
3870
- if (hasScteIn) {
3871
- var marker4 = _object_spread_props(_object_spread({
3872
- type: "end"
3873
- }, tag.ptsSeconds !== void 0 ? {
3874
- ptsSeconds: tag.ptsSeconds
3875
- } : {}), {
3876
- raw: {
3877
- id3: text,
3878
- attrs: attrs
3879
- }
3880
- });
3881
- return marker4;
3882
- }
3883
- }
3884
- if (/SCTE35-OUT/i.test(text)) {
3885
- var marker5 = _object_spread_props(_object_spread({
3886
- type: "start"
3887
- }, tag.ptsSeconds !== void 0 ? {
3888
- ptsSeconds: tag.ptsSeconds
3889
- } : {}), {
3890
- raw: {
3891
- id3: text
3892
- }
3893
- });
3894
- return marker5;
3895
- }
3896
- if (/SCTE35-IN/i.test(text)) {
3897
- var marker6 = _object_spread_props(_object_spread({
3898
- type: "end"
3899
- }, tag.ptsSeconds !== void 0 ? {
3900
- ptsSeconds: tag.ptsSeconds
3901
- } : {}), {
3902
- raw: {
3903
- id3: text
3904
- }
3905
- });
3906
- return marker6;
3907
- }
3908
- if (_instanceof(tag.value, Uint8Array)) {
3909
- var bin = this.parseScte35Binary(tag.value);
3910
- if (bin) return bin;
3911
- }
3912
- return void 0;
3913
- }
3914
- },
3915
- {
3916
- key: "decodeId3ValueToText",
3917
- value: function decodeId3ValueToText(value) {
3918
- try {
3919
- if (typeof value === "string") return value;
3920
- var decoder = new TextDecoder("utf-8", {
3921
- fatal: false
3922
- });
3923
- var text = decoder.decode(value);
3924
- if (text && /[\x20-\x7E]/.test(text)) return text;
3925
- var out = "";
3926
- for(var i = 0; i < value.length; i++)out += String.fromCharCode(value[i]);
3927
- return out;
3928
- } catch (unused) {
3929
- return void 0;
3930
- }
3931
- }
3932
- },
3933
- {
3934
- key: "onScte35Marker",
3935
- value: function onScte35Marker(marker) {
3936
- var _this = this;
3937
- if (this.config.disableAds) return;
3938
- this.pushScteMarker(marker);
3939
- this.pushDebugLog("info", "scte35", "SCTE-35 marker detected", {
3940
- type: marker.type,
3941
- ptsSeconds: marker.ptsSeconds,
3942
- durationSeconds: marker.durationSeconds,
3943
- currentTime: this.video.currentTime
3944
- });
3945
- if (this.config.debugAdTiming) {
3946
- console.log("[StormcloudVideoPlayer] SCTE-35 marker detected:", {
3947
- type: marker.type,
3948
- ptsSeconds: marker.ptsSeconds,
3949
- durationSeconds: marker.durationSeconds,
3950
- currentTime: this.video.currentTime,
3951
- raw: marker.raw,
3952
- hasPendingAdBreak: !!this.pendingAdBreak
3953
- });
3954
- }
3955
- if (marker.type === "start") {
3956
- var _this_config_immediateManifestAds;
3957
- var _this_pendingAdBreak;
3958
- if (this.savedMutedStateBeforeScte == null) {
3959
- this.savedMutedStateBeforeScte = {
3960
- muted: this.video.muted,
3961
- volume: this.video.volume
3962
- };
3963
- this.adLayer.updateOriginalMutedState(this.video.muted, this.video.volume);
3964
- }
3965
- if (!this.config.disableFiller && !this.video.muted && !this.adLayer.isAdPlaying()) {
3966
- this.video.muted = true;
3967
- this.video.volume = 0;
3968
- if (this.config.debugAdTiming) {
3969
- console.log("[StormcloudVideoPlayer] Muted video on SCTE start marker");
3970
- }
3971
- }
3972
- if (this.inAdBreak) {
3973
- if (marker.durationSeconds != null) {
3974
- var newDurationMs = marker.durationSeconds * 1e3;
3975
- if (this.expectedAdBreakDurationMs == null || newDurationMs > this.expectedAdBreakDurationMs) {
3976
- this.expectedAdBreakDurationMs = newDurationMs;
3977
- var elapsedMs = this.currentAdBreakStartWallClockMs != null ? Date.now() - this.currentAdBreakStartWallClockMs : 0;
3978
- var remainingMs = Math.max(0, newDurationMs - elapsedMs);
3979
- this.scheduleAdStopCountdown(remainingMs);
3980
- if (this.config.debugAdTiming) {
3981
- console.log("[StormcloudVideoPlayer] Updated ad break duration from subsequent marker: ".concat(newDurationMs, "ms, remaining: ").concat(remainingMs, "ms"));
3982
- }
3983
- }
3984
- }
3985
- return;
3986
- }
3987
- this.inAdBreak = true;
3988
- 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;
3989
- this.expectedAdBreakDurationMs = durationMs;
3990
- this.currentAdBreakStartWallClockMs = Date.now();
3991
- if (this.config.licenseKey) {
3992
- var _this_pendingAdBreak1;
3993
- var adDetectInfo = _object_spread({
3994
- source: "scte35",
3995
- timestamp: /* @__PURE__ */ new Date().toISOString()
3996
- }, marker.durationSeconds != null && {
3997
- durationSeconds: marker.durationSeconds
3998
- }, marker.ptsSeconds != null && {
3999
- ptsSeconds: marker.ptsSeconds
4000
- }, ((_this_pendingAdBreak1 = this.pendingAdBreak) === null || _this_pendingAdBreak1 === void 0 ? void 0 : _this_pendingAdBreak1.detectedAtFragmentSn) != null && {
4001
- detectedAtFragmentSn: this.pendingAdBreak.detectedAtFragmentSn
4002
- });
4003
- sendAdDetectTracking(this.config.licenseKey, adDetectInfo);
4004
- }
4005
- var isManifestMarker = this.isManifestBasedMarker(marker);
4006
- var forceImmediate = (_this_config_immediateManifestAds = this.config.immediateManifestAds) !== null && _this_config_immediateManifestAds !== void 0 ? _this_config_immediateManifestAds : true;
4007
- if (this.config.debugAdTiming) {
4008
- console.log("[StormcloudVideoPlayer] Ad start decision:", {
4009
- isManifestMarker: isManifestMarker,
4010
- forceImmediate: forceImmediate,
4011
- hasPts: typeof marker.ptsSeconds === "number"
4012
- });
4013
- }
4014
- if (isManifestMarker && forceImmediate) {
4015
- if (this.config.debugAdTiming) {
4016
- console.log("[StormcloudVideoPlayer] Starting ad immediately (manifest-based)");
4017
- }
4018
- this.clearAdStartTimer();
4019
- this.handleAdStart(marker);
4020
- } else if (typeof marker.ptsSeconds === "number") {
4021
- var _this_config_driftToleranceMs;
4022
- var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
4023
- var nowMs = this.video.currentTime * 1e3;
4024
- var estCurrentPtsMs = nowMs - this.ptsDriftEmaMs;
4025
- var deltaMs = Math.floor(marker.ptsSeconds * 1e3 - estCurrentPtsMs);
4026
- if (this.config.debugAdTiming) {
4027
- console.log("[StormcloudVideoPlayer] PTS-based timing calculation:", {
4028
- nowMs: nowMs,
4029
- estCurrentPtsMs: estCurrentPtsMs,
4030
- markerPtsMs: marker.ptsSeconds * 1e3,
4031
- deltaMs: deltaMs,
4032
- tolerance: tol
4033
- });
4034
- }
4035
- if (deltaMs > tol) {
4036
- if (this.config.debugAdTiming) {
4037
- console.log("[StormcloudVideoPlayer] Scheduling ad start in ".concat(deltaMs, "ms"));
4038
- }
4039
- this.scheduleAdStartIn(deltaMs);
4040
- } else {
4041
- if (this.config.debugAdTiming) {
4042
- console.log("[StormcloudVideoPlayer] Starting ad immediately (within tolerance)");
4043
- }
4044
- this.clearAdStartTimer();
4045
- this.handleAdStart(marker);
4046
- }
4047
- } else {
4048
- if (this.config.debugAdTiming) {
4049
- console.log("[StormcloudVideoPlayer] Starting ad immediately (fallback)");
4050
- }
4051
- this.clearAdStartTimer();
4052
- this.handleAdStart(marker);
4053
- }
4054
- if (this.expectedAdBreakDurationMs != null) {
4055
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
4056
- }
4057
- return;
4058
- }
4059
- if (marker.type === "progress" && this.inAdBreak) {
4060
- if (marker.durationSeconds != null) {
4061
- this.expectedAdBreakDurationMs = marker.durationSeconds * 1e3;
4062
- }
4063
- if (this.expectedAdBreakDurationMs != null && this.currentAdBreakStartWallClockMs != null) {
4064
- var elapsedMs1 = Date.now() - this.currentAdBreakStartWallClockMs;
4065
- var remainingMs1 = Math.max(0, this.expectedAdBreakDurationMs - elapsedMs1);
4066
- this.scheduleAdStopCountdown(remainingMs1);
4067
- }
4068
- if (!this.adLayer.isAdPlaying() && this.pendingNextAdBids != null && this.pendingNextAdBids.length > 0) {
4069
- var bids = this.pendingNextAdBids;
4070
- this.pendingNextAdBids = null;
4071
- this.currentAdIndex++;
4072
- this.adLayer.playAd(bids).catch(function() {
4073
- return _this.handleAdFailure();
4074
- });
4075
- }
4076
- return;
4077
- }
4078
- if (marker.type === "end") {
4079
- var remaining = this.getRemainingAdMs();
4080
- var adPlaying = this.adLayer.isAdPlaying();
4081
- var hasQueuedAds = this.pendingNextAdBids != null && this.pendingNextAdBids.length > 0;
4082
- if (this.config.debugAdTiming) {
4083
- console.log("[StormcloudVideoPlayer] SCTE-35 end marker received:", {
4084
- inAdBreak: this.inAdBreak,
4085
- remaining: remaining,
4086
- adPlaying: adPlaying,
4087
- hasQueuedAds: hasQueuedAds,
4088
- activeAdRequest: this.activeAdRequestToken !== null
4089
- });
4090
- }
4091
- if (!this.inAdBreak) {
4092
- if (this.config.debugAdTiming) {
4093
- console.log("[StormcloudVideoPlayer] Ignoring SCTE-35 end marker - not in ad break");
4094
- }
4095
- return;
4096
- }
4097
- if (adPlaying || remaining > 500) {
4098
- if (this.config.debugAdTiming) {
4099
- console.log("[StormcloudVideoPlayer] Ignoring premature SCTE-35 end marker - ads still active or time remaining");
4100
- }
4101
- return;
4102
- }
4103
- this.inAdBreak = false;
4104
- this.expectedAdBreakDurationMs = void 0;
4105
- this.currentAdBreakStartWallClockMs = void 0;
4106
- this.clearAdStartTimer();
4107
- this.clearAdStopTimer();
4108
- if (adPlaying) {
4109
- this.adLayer.stop().catch(function() {});
4110
- }
4111
- this.handleAdPodComplete();
4112
- return;
4113
- }
4114
- }
4115
- },
4116
- {
4117
- key: "parseCueOutDuration",
4118
- value: function parseCueOutDuration(value) {
4119
- var num = parseFloat(value.trim());
4120
- if (!Number.isNaN(num)) return num;
4121
- var match = value.match(/(?:^|[,\s])DURATION\s*=\s*([0-9.]+)/i) || value.match(/Duration\s*=\s*([0-9.]+)/i);
4122
- if (match && match[1] != null) {
4123
- var dStr = match[1];
4124
- var d = parseFloat(dStr);
4125
- return Number.isNaN(d) ? void 0 : d;
4126
- }
4127
- return void 0;
4128
- }
4129
- },
4130
- {
4131
- key: "parseCueOutCont",
4132
- value: function parseCueOutCont(value) {
4133
- var res = {};
4134
- var elapsedMatch = value.match(/Elapsed\s*=\s*([0-9.]+)/i);
4135
- var durationMatch = value.match(/Duration\s*=\s*([0-9.]+)/i);
4136
- if (elapsedMatch && elapsedMatch[1] != null) {
4137
- var e = parseFloat(elapsedMatch[1]);
4138
- if (!Number.isNaN(e)) res.elapsed = e;
4139
- }
4140
- if (durationMatch && durationMatch[1] != null) {
4141
- var d = parseFloat(durationMatch[1]);
4142
- if (!Number.isNaN(d)) res.duration = d;
4143
- }
4144
- if (!("elapsed" in res) || !("duration" in res)) {
4145
- var slashMatch = value.match(/([0-9.]+)\s*\/\s*([0-9.]+)/);
4146
- if (slashMatch && slashMatch[1] && slashMatch[2]) {
4147
- var elapsed = parseFloat(slashMatch[1]);
4148
- var duration = parseFloat(slashMatch[2]);
4149
- if (!Number.isNaN(elapsed) && !("elapsed" in res)) res.elapsed = elapsed;
4150
- if (!Number.isNaN(duration) && !("duration" in res)) res.duration = duration;
4151
- }
4152
- }
4153
- if ("elapsed" in res || "duration" in res) return res;
4154
- return void 0;
4155
- }
4156
- },
4157
- {
4158
- key: "parseAttributeList",
4159
- value: function parseAttributeList(value) {
4160
- var attrs = {};
4161
- var regex = /([A-Z0-9-]+)=(("[^"]*")|([^",]*))(?:,|$)/gi;
4162
- var match;
4163
- while((match = regex.exec(value)) !== null){
4164
- var _match_, _ref, _match_1;
4165
- var key = (_match_ = match[1]) !== null && _match_ !== void 0 ? _match_ : "";
4166
- var rawVal = (_ref = (_match_1 = match[3]) !== null && _match_1 !== void 0 ? _match_1 : match[4]) !== null && _ref !== void 0 ? _ref : "";
4167
- if (rawVal.startsWith('"') && rawVal.endsWith('"')) {
4168
- rawVal = rawVal.slice(1, -1);
4169
- }
4170
- if (key) {
4171
- attrs[key] = rawVal;
4172
- }
4173
- }
4174
- return attrs;
4175
- }
4176
- },
4177
- {
4178
- key: "toNumber",
4179
- value: function toNumber(val) {
4180
- if (val == null) return void 0;
4181
- var n = typeof val === "string" ? parseFloat(val) : Number(val);
4182
- return Number.isNaN(n) ? void 0 : n;
4183
- }
4184
- },
4185
- {
4186
- key: "isManifestBasedMarker",
4187
- value: function isManifestBasedMarker(marker) {
4188
- var raw = marker.raw;
4189
- if (!raw) return false;
4190
- if (raw.tag) {
4191
- var tag = String(raw.tag);
4192
- return tag.includes("EXT-X-CUE-OUT") || tag.includes("EXT-X-CUE-IN") || tag.includes("EXT-X-DATERANGE");
4193
- }
4194
- if (raw.id3) return false;
4195
- if (raw.splice_command_type) return false;
4196
- return false;
4197
- }
4198
- },
4199
- {
4200
- key: "parseScte35Binary",
4201
- value: function parseScte35Binary(data) {
4202
- var BitReader = /*#__PURE__*/ function() {
4203
- function BitReader(buf) {
4204
- _class_call_check(this, BitReader);
4205
- this.buf = buf;
4206
- this.bytePos = 0;
4207
- this.bitPos = 0;
4208
- }
4209
- _create_class(BitReader, [
4210
- {
4211
- key: "readBits",
4212
- value: function readBits(numBits) {
4213
- var result = 0;
4214
- while(numBits > 0){
4215
- if (this.bytePos >= this.buf.length) return result;
4216
- var remainingInByte = 8 - this.bitPos;
4217
- var toRead = Math.min(numBits, remainingInByte);
4218
- var currentByte = this.buf[this.bytePos];
4219
- var shift = remainingInByte - toRead;
4220
- var mask = (1 << toRead) - 1 & 255;
4221
- var bits = currentByte >> shift & mask;
4222
- result = result << toRead | bits;
4223
- this.bitPos += toRead;
4224
- if (this.bitPos >= 8) {
4225
- this.bitPos = 0;
4226
- this.bytePos += 1;
4227
- }
4228
- numBits -= toRead;
4229
- }
4230
- return result >>> 0;
4231
- }
4232
- },
4233
- {
4234
- key: "skipBits",
4235
- value: function skipBits(n) {
4236
- this.readBits(n);
4237
- }
4238
- }
4239
- ]);
4240
- return BitReader;
4241
- }();
4242
- var r = new BitReader(data);
4243
- var tableId = r.readBits(8);
4244
- if (tableId !== 252) return void 0;
4245
- r.readBits(1);
4246
- r.readBits(1);
4247
- r.readBits(2);
4248
- var sectionLength = r.readBits(12);
4249
- r.readBits(8);
4250
- r.readBits(1);
4251
- r.readBits(6);
4252
- var ptsAdjHigh = r.readBits(1);
4253
- var ptsAdjLow = r.readBits(32);
4254
- void ptsAdjHigh;
4255
- void ptsAdjLow;
4256
- r.readBits(8);
4257
- r.readBits(12);
4258
- var spliceCommandLength = r.readBits(12);
4259
- var spliceCommandType = r.readBits(8);
4260
- if (spliceCommandType !== 5) {
4261
- return void 0;
4262
- }
4263
- r.readBits(32);
4264
- var cancel = r.readBits(1) === 1;
4265
- r.readBits(7);
4266
- if (cancel) return void 0;
4267
- var outOfNetwork = r.readBits(1) === 1;
4268
- var programSpliceFlag = r.readBits(1) === 1;
4269
- var durationFlag = r.readBits(1) === 1;
4270
- var spliceImmediateFlag = r.readBits(1) === 1;
4271
- r.readBits(4);
4272
- if (programSpliceFlag && !spliceImmediateFlag) {
4273
- var timeSpecifiedFlag = r.readBits(1) === 1;
4274
- if (timeSpecifiedFlag) {
4275
- r.readBits(6);
4276
- r.readBits(33);
4277
- } else {
4278
- r.readBits(7);
4279
- }
4280
- } else if (!programSpliceFlag) {
4281
- var componentCount = r.readBits(8);
4282
- for(var i = 0; i < componentCount; i++){
4283
- r.readBits(8);
4284
- if (!spliceImmediateFlag) {
4285
- var timeSpecifiedFlag1 = r.readBits(1) === 1;
4286
- if (timeSpecifiedFlag1) {
4287
- r.readBits(6);
4288
- r.readBits(33);
4289
- } else {
4290
- r.readBits(7);
4291
- }
4292
- }
4293
- }
4294
- }
4295
- var durationSeconds = void 0;
4296
- if (durationFlag) {
4297
- r.readBits(6);
4298
- r.readBits(1);
4299
- var high = r.readBits(1);
4300
- var low = r.readBits(32);
4301
- var durationTicks = high * 4294967296 + low;
4302
- durationSeconds = durationTicks / 9e4;
4303
- }
4304
- r.readBits(16);
4305
- r.readBits(8);
4306
- r.readBits(8);
4307
- if (outOfNetwork) {
4308
- var marker = _object_spread_props(_object_spread({
4309
- type: "start"
4310
- }, durationSeconds !== void 0 ? {
4311
- durationSeconds: durationSeconds
4312
- } : {}), {
4313
- raw: {
4314
- splice_command_type: 5
4315
- }
4316
- });
4317
- return marker;
4318
- }
4319
- return void 0;
4320
- }
4321
- },
4322
3621
  {
4323
3622
  key: "initializeTracking",
4324
3623
  value: function initializeTracking() {
@@ -4440,35 +3739,35 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4440
3739
  },
4441
3740
  {
4442
3741
  key: "startAdPrefetch",
4443
- value: function startAdPrefetch(marker, fragmentSn) {
3742
+ value: function startAdPrefetch(durationSeconds, fragmentSn) {
4444
3743
  if (this.config.disableAds) return;
4445
3744
  if (this.pendingAdBreak || this.inAdBreak) {
4446
3745
  return;
4447
3746
  }
4448
- this.pendingAdBreak = _object_spread_props(_object_spread({
4449
- marker: marker
4450
- }, fragmentSn !== void 0 ? {
3747
+ this.pendingAdBreak = _object_spread_props(_object_spread({}, durationSeconds !== void 0 ? {
3748
+ durationSeconds: durationSeconds
3749
+ } : {}, fragmentSn !== void 0 ? {
4451
3750
  detectedAtFragmentSn: fragmentSn
4452
3751
  } : {}), {
4453
3752
  isFetching: false,
4454
3753
  fetchStartTime: Date.now()
4455
3754
  });
4456
- void this.runAdPrefetch(marker);
3755
+ void this.runAdPrefetch(durationSeconds);
4457
3756
  if (this.config.debugAdTiming) {
4458
- console.log("[PREFETCH] Ad break marker registered, multi-ad prefetch started");
3757
+ console.log("[PREFETCH] Ad break registered, multi-ad prefetch started");
4459
3758
  }
4460
3759
  }
4461
3760
  },
4462
3761
  {
4463
3762
  key: "runAdPrefetch",
4464
- value: function runAdPrefetch(marker) {
3763
+ value: function runAdPrefetch(durationSeconds) {
4465
3764
  return _async_to_generator(function() {
4466
- var _this, _marker_durationSeconds, _ref, _firstBids_, durSec, context, firstBids, unused, adDurationSec, estimatedCount, firstToken, remaining, results, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, result, token;
3765
+ var _this, _ref, _firstBids_, durSec, context, firstBids, unused, adDurationSec, estimatedCount, firstToken, unused1, remaining, results, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, result, token, unused2, err;
4467
3766
  return _ts_generator(this, function(_state) {
4468
3767
  switch(_state.label){
4469
3768
  case 0:
4470
3769
  _this = this;
4471
- durSec = (_marker_durationSeconds = marker.durationSeconds) !== null && _marker_durationSeconds !== void 0 ? _marker_durationSeconds : 60;
3770
+ durSec = durationSeconds !== null && durationSeconds !== void 0 ? durationSeconds : 60;
4472
3771
  context = {
4473
3772
  breakDurationSec: durSec,
4474
3773
  remainingBreakSec: durSec
@@ -4518,14 +3817,43 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4518
3817
  console.log("[PREFETCH] Ad duration=".concat(adDurationSec, "s, break=").concat(durSec, "s → ").concat(estimatedCount, " ad(s) needed"));
4519
3818
  }
4520
3819
  firstToken = "preload_".concat(Date.now(), "_").concat(Math.random().toString(36).slice(2, 7));
4521
- this.preloadedTokens.push(firstToken);
4522
- void this.adLayer.preloadAd(firstBids, firstToken);
3820
+ _state.label = 5;
3821
+ case 5:
3822
+ _state.trys.push([
3823
+ 5,
3824
+ 7,
3825
+ ,
3826
+ 8
3827
+ ]);
3828
+ return [
3829
+ 4,
3830
+ this.adLayer.preloadAd(firstBids, firstToken)
3831
+ ];
3832
+ case 6:
3833
+ _state.sent();
3834
+ if (!this.inAdBreak) {
3835
+ this.preloadedTokens.push(firstToken);
3836
+ if (this.config.debugAdTiming) {
3837
+ console.log("[PREFETCH] First ad preloaded and queued, token=".concat(firstToken));
3838
+ }
3839
+ }
3840
+ return [
3841
+ 3,
3842
+ 8
3843
+ ];
3844
+ case 7:
3845
+ unused1 = _state.sent();
4523
3846
  if (this.config.debugAdTiming) {
4524
- console.log("[PREFETCH] First ad preloading, token=".concat(firstToken));
3847
+ console.warn("[PREFETCH] First ad preload failed, token=".concat(firstToken));
4525
3848
  }
3849
+ return [
3850
+ 3,
3851
+ 8
3852
+ ];
3853
+ case 8:
4526
3854
  if (!(estimatedCount > 1)) return [
4527
3855
  3,
4528
- 6
3856
+ 19
4529
3857
  ];
4530
3858
  remaining = Array.from({
4531
3859
  length: estimatedCount - 1
@@ -4547,38 +3875,100 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4547
3875
  4,
4548
3876
  Promise.all(remaining)
4549
3877
  ];
4550
- case 5:
3878
+ case 9:
4551
3879
  results = _state.sent();
4552
3880
  _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
3881
+ _state.label = 10;
3882
+ case 10:
3883
+ _state.trys.push([
3884
+ 10,
3885
+ 17,
3886
+ 18,
3887
+ 19
3888
+ ]);
3889
+ _iterator = results[Symbol.iterator]();
3890
+ _state.label = 11;
3891
+ case 11:
3892
+ if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
3893
+ 3,
3894
+ 16
3895
+ ];
3896
+ result = _step.value;
3897
+ if (this.inAdBreak) return [
3898
+ 3,
3899
+ 16
3900
+ ];
3901
+ if (!(result.ok && result.value.length > 0)) return [
3902
+ 3,
3903
+ 15
3904
+ ];
3905
+ token = "preload_".concat(Date.now(), "_").concat(Math.random().toString(36).slice(2, 7));
3906
+ _state.label = 12;
3907
+ case 12:
3908
+ _state.trys.push([
3909
+ 12,
3910
+ 14,
3911
+ ,
3912
+ 15
3913
+ ]);
3914
+ return [
3915
+ 4,
3916
+ this.adLayer.preloadAd(result.value, token)
3917
+ ];
3918
+ case 13:
3919
+ _state.sent();
3920
+ if (!this.inAdBreak) {
3921
+ this.preloadedTokens.push(token);
3922
+ if (this.config.debugAdTiming) {
3923
+ console.log("[PREFETCH] Additional ad preloaded and queued, token=".concat(token));
3924
+ }
3925
+ }
3926
+ return [
3927
+ 3,
3928
+ 15
3929
+ ];
3930
+ case 14:
3931
+ unused2 = _state.sent();
3932
+ if (this.config.debugAdTiming) {
3933
+ console.warn("[PREFETCH] Additional ad preload failed, token=".concat(token));
3934
+ }
3935
+ return [
3936
+ 3,
3937
+ 15
3938
+ ];
3939
+ case 15:
3940
+ _iteratorNormalCompletion = true;
3941
+ return [
3942
+ 3,
3943
+ 11
3944
+ ];
3945
+ case 16:
3946
+ return [
3947
+ 3,
3948
+ 19
3949
+ ];
3950
+ case 17:
3951
+ err = _state.sent();
3952
+ _didIteratorError = true;
3953
+ _iteratorError = err;
3954
+ return [
3955
+ 3,
3956
+ 19
3957
+ ];
3958
+ case 18:
4553
3959
  try {
4554
- for(_iterator = results[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
4555
- result = _step.value;
4556
- if (this.inAdBreak) break;
4557
- if (result.ok && result.value.length > 0) {
4558
- token = "preload_".concat(Date.now(), "_").concat(Math.random().toString(36).slice(2, 7));
4559
- this.preloadedTokens.push(token);
4560
- void this.adLayer.preloadAd(result.value, token);
4561
- if (this.config.debugAdTiming) {
4562
- console.log("[PREFETCH] Additional ad preloading, token=".concat(token));
4563
- }
4564
- }
3960
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
3961
+ _iterator.return();
4565
3962
  }
4566
- } catch (err) {
4567
- _didIteratorError = true;
4568
- _iteratorError = err;
4569
3963
  } finally{
4570
- try {
4571
- if (!_iteratorNormalCompletion && _iterator.return != null) {
4572
- _iterator.return();
4573
- }
4574
- } finally{
4575
- if (_didIteratorError) {
4576
- throw _iteratorError;
4577
- }
3964
+ if (_didIteratorError) {
3965
+ throw _iteratorError;
4578
3966
  }
4579
3967
  }
4580
- _state.label = 6;
4581
- case 6:
3968
+ return [
3969
+ 7
3970
+ ];
3971
+ case 19:
4582
3972
  if (this.config.debugAdTiming) {
4583
3973
  console.log("[PREFETCH] Pre-fetch complete: ".concat(this.preloadedTokens.length, " ad(s) queued"));
4584
3974
  }
@@ -4626,6 +4016,177 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4626
4016
  this.preloadedTokens = [];
4627
4017
  }
4628
4018
  },
4019
+ {
4020
+ key: "startAdInsertionPolling",
4021
+ value: function startAdInsertionPolling() {
4022
+ var _this = this;
4023
+ if (this.adInsertionPollingId != null) return;
4024
+ this.fetchAdInsertionPoint();
4025
+ this.adInsertionPollingId = window.setInterval(function() {
4026
+ _this.fetchAdInsertionPoint();
4027
+ }, 1e3);
4028
+ }
4029
+ },
4030
+ {
4031
+ key: "stopAdInsertionPolling",
4032
+ value: function stopAdInsertionPolling() {
4033
+ if (this.adInsertionPollingId != null) {
4034
+ clearInterval(this.adInsertionPollingId);
4035
+ this.adInsertionPollingId = void 0;
4036
+ }
4037
+ }
4038
+ },
4039
+ {
4040
+ key: "fetchAdInsertionPoint",
4041
+ value: function fetchAdInsertionPoint() {
4042
+ return _async_to_generator(function() {
4043
+ var _this_lastAdInsertionPoint, resp, data, isNew, unused;
4044
+ return _ts_generator(this, function(_state) {
4045
+ switch(_state.label){
4046
+ case 0:
4047
+ if (!this.config.projectId) return [
4048
+ 2
4049
+ ];
4050
+ _state.label = 1;
4051
+ case 1:
4052
+ _state.trys.push([
4053
+ 1,
4054
+ 4,
4055
+ ,
4056
+ 5
4057
+ ]);
4058
+ return [
4059
+ 4,
4060
+ fetch("https://adstorm.co/api-adstorm-dev/adstorm/swirl/projects/".concat(encodeURIComponent(this.config.projectId), "/ad-insertion-point"))
4061
+ ];
4062
+ case 2:
4063
+ resp = _state.sent();
4064
+ if (!resp.ok) return [
4065
+ 2
4066
+ ];
4067
+ return [
4068
+ 4,
4069
+ resp.json()
4070
+ ];
4071
+ case 3:
4072
+ data = _state.sent();
4073
+ isNew = data.updated_at !== ((_this_lastAdInsertionPoint = this.lastAdInsertionPoint) === null || _this_lastAdInsertionPoint === void 0 ? void 0 : _this_lastAdInsertionPoint.updated_at);
4074
+ this.lastAdInsertionPoint = data;
4075
+ if (isNew) {
4076
+ this.pushAdInsertionDebug("api_response", data.segment_ts_name, {
4077
+ offsetSeconds: data.offset_seconds,
4078
+ updatedAt: data.updated_at,
4079
+ detail: "project=".concat(data.project_id)
4080
+ });
4081
+ }
4082
+ if (this.config.debugAdTiming) {
4083
+ console.log("[StormcloudVideoPlayer] Ad insertion point API response:", data);
4084
+ }
4085
+ return [
4086
+ 3,
4087
+ 5
4088
+ ];
4089
+ case 4:
4090
+ unused = _state.sent();
4091
+ if (this.config.debugAdTiming) {
4092
+ console.warn("[StormcloudVideoPlayer] Ad insertion point API fetch failed");
4093
+ }
4094
+ return [
4095
+ 3,
4096
+ 5
4097
+ ];
4098
+ case 5:
4099
+ return [
4100
+ 2
4101
+ ];
4102
+ }
4103
+ });
4104
+ }).call(this);
4105
+ }
4106
+ },
4107
+ {
4108
+ key: "checkAdInsertionInManifest",
4109
+ value: function checkAdInsertionInManifest() {
4110
+ var _this_hls;
4111
+ if (!this.lastAdInsertionPoint) return;
4112
+ if (this.inAdBreak || this.pendingAdBreak) return;
4113
+ if (this.lastAdInsertionPoint.updated_at === this.processedAdInsertionUpdatedAt) return;
4114
+ var segmentName = this.lastAdInsertionPoint.segment_ts_name;
4115
+ var levels = (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : _this_hls.levels;
4116
+ if (!levels) return;
4117
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
4118
+ try {
4119
+ for(var _iterator = levels[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
4120
+ var level = _step.value;
4121
+ var _level_details;
4122
+ var fragments = (_level_details = level.details) === null || _level_details === void 0 ? void 0 : _level_details.fragments;
4123
+ if (!Array.isArray(fragments)) continue;
4124
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
4125
+ try {
4126
+ for(var _iterator1 = fragments[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
4127
+ var frag = _step1.value;
4128
+ if (this.fragmentMatchesSegment(frag, segmentName)) {
4129
+ var _ref;
4130
+ this.pushAdInsertionDebug("segment_found", segmentName, {
4131
+ detail: "sn=".concat((_ref = frag === null || frag === void 0 ? void 0 : frag.sn) !== null && _ref !== void 0 ? _ref : "?")
4132
+ });
4133
+ if (this.config.debugAdTiming) {
4134
+ console.log('[StormcloudVideoPlayer] Ad insertion segment "'.concat(segmentName, '" found in manifest — starting pre-fetch'));
4135
+ }
4136
+ this.startAdPrefetch(60, frag === null || frag === void 0 ? void 0 : frag.sn);
4137
+ return;
4138
+ }
4139
+ }
4140
+ } catch (err) {
4141
+ _didIteratorError1 = true;
4142
+ _iteratorError1 = err;
4143
+ } finally{
4144
+ try {
4145
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
4146
+ _iterator1.return();
4147
+ }
4148
+ } finally{
4149
+ if (_didIteratorError1) {
4150
+ throw _iteratorError1;
4151
+ }
4152
+ }
4153
+ }
4154
+ }
4155
+ } catch (err) {
4156
+ _didIteratorError = true;
4157
+ _iteratorError = err;
4158
+ } finally{
4159
+ try {
4160
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
4161
+ _iterator.return();
4162
+ }
4163
+ } finally{
4164
+ if (_didIteratorError) {
4165
+ throw _iteratorError;
4166
+ }
4167
+ }
4168
+ }
4169
+ }
4170
+ },
4171
+ {
4172
+ key: "fragmentMatchesSegment",
4173
+ value: function fragmentMatchesSegment(frag, segmentName) {
4174
+ var _rawUrl_split_;
4175
+ var rawUrl = (frag === null || frag === void 0 ? void 0 : frag.url) || (frag === null || frag === void 0 ? void 0 : frag.relurl) || "";
4176
+ var url = (_rawUrl_split_ = rawUrl.split("?")[0]) !== null && _rawUrl_split_ !== void 0 ? _rawUrl_split_ : "";
4177
+ var name = segmentName.startsWith("/") ? segmentName : "/" + segmentName;
4178
+ return url.endsWith(name) || url.includes(name);
4179
+ }
4180
+ },
4181
+ {
4182
+ key: "clearAdInsertionOffsetTimer",
4183
+ value: function clearAdInsertionOffsetTimer() {
4184
+ if (this.adInsertionOffsetTimerId != null) {
4185
+ clearTimeout(this.adInsertionOffsetTimerId);
4186
+ this.adInsertionOffsetTimerId = void 0;
4187
+ }
4188
+ }
4189
+ },
4629
4190
  {
4630
4191
  key: "startContinuousFetchLoop",
4631
4192
  value: function startContinuousFetchLoop() {
@@ -4951,13 +4512,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4951
4512
  },
4952
4513
  {
4953
4514
  key: "handleAdStart",
4954
- value: function handleAdStart(_marker) {
4515
+ value: function handleAdStart(durationSeconds) {
4955
4516
  return _async_to_generator(function() {
4956
- var _this_savedMutedStateBeforeScte, adBreakDurationMs, mode, state, adBreakToken, adVolume, token, remaining, err;
4517
+ var _this_savedMutedStateBeforeAd, adBreakDurationMs, mode, state, adBreakToken, adVolume, token, remaining, err;
4957
4518
  return _ts_generator(this, function(_state) {
4958
4519
  switch(_state.label){
4959
4520
  case 0:
4960
- adBreakDurationMs = _marker.durationSeconds != null ? _marker.durationSeconds * 1e3 : void 0;
4521
+ adBreakDurationMs = durationSeconds != null ? durationSeconds * 1e3 : void 0;
4961
4522
  if (this.config.debugAdTiming) {
4962
4523
  mode = this.isLiveStream ? "LIVE" : "VOD";
4963
4524
  console.log("[CONTINUOUS-FETCH] \uD83D\uDCFA ".concat(mode, " MODE: Target duration=").concat(adBreakDurationMs, "ms"));
@@ -4968,13 +4529,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4968
4529
  this.pendingNextAdBids = null;
4969
4530
  this.isShowingPlaceholder = false;
4970
4531
  this.totalAdRequestsInBreak = 0;
4971
- if (this.savedMutedStateBeforeScte == null && !this.video.muted) {
4972
- this.savedMutedStateBeforeScte = {
4532
+ if (this.savedMutedStateBeforeAd == null && !this.video.muted) {
4533
+ this.savedMutedStateBeforeAd = {
4973
4534
  muted: false,
4974
4535
  volume: this.video.volume
4975
4536
  };
4976
4537
  }
4977
- state = (_this_savedMutedStateBeforeScte = this.savedMutedStateBeforeScte) !== null && _this_savedMutedStateBeforeScte !== void 0 ? _this_savedMutedStateBeforeScte : {
4538
+ state = (_this_savedMutedStateBeforeAd = this.savedMutedStateBeforeAd) !== null && _this_savedMutedStateBeforeAd !== void 0 ? _this_savedMutedStateBeforeAd : {
4978
4539
  muted: this.video.muted,
4979
4540
  volume: this.video.volume
4980
4541
  };
@@ -5001,6 +4562,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5001
4562
  if (this.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {
5002
4563
  this.expectedAdBreakDurationMs = adBreakDurationMs;
5003
4564
  }
4565
+ if (this.expectedAdBreakDurationMs != null) {
4566
+ this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
4567
+ }
5004
4568
  this.clearPendingAdBreak();
5005
4569
  adBreakToken = Date.now();
5006
4570
  this.activeAdRequestToken = adBreakToken;
@@ -5499,54 +5063,18 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5499
5063
  this.handleAdPodComplete();
5500
5064
  }
5501
5065
  },
5502
- {
5503
- key: "scheduleAdStartIn",
5504
- value: function scheduleAdStartIn(delayMs) {
5505
- var _this = this;
5506
- this.clearAdStartTimer();
5507
- var ms = Math.max(0, Math.floor(delayMs));
5508
- if (ms === 0) {
5509
- this.handleAdStart({
5510
- type: "start"
5511
- }).catch(function() {});
5512
- return;
5513
- }
5514
- this.adStartTimerId = window.setTimeout(function() {
5515
- _this.handleAdStart({
5516
- type: "start"
5517
- }).catch(function() {});
5518
- }, ms);
5519
- }
5520
- },
5521
- {
5522
- key: "clearAdStartTimer",
5523
- value: function clearAdStartTimer() {
5524
- if (this.adStartTimerId != null) {
5525
- clearTimeout(this.adStartTimerId);
5526
- this.adStartTimerId = void 0;
5527
- }
5528
- }
5529
- },
5530
- {
5531
- key: "updatePtsDrift",
5532
- value: function updatePtsDrift(ptsSecondsSample) {
5533
- var sampleMs = (this.video.currentTime - ptsSecondsSample) * 1e3;
5534
- if (!Number.isFinite(sampleMs) || Math.abs(sampleMs) > 6e4) return;
5535
- var alpha = 0.1;
5536
- this.ptsDriftEmaMs = this.ptsDriftEmaMs * (1 - alpha) + sampleMs * alpha;
5537
- }
5538
- },
5539
5066
  {
5540
5067
  key: "handleAdPodComplete",
5541
5068
  value: function handleAdPodComplete() {
5542
5069
  var _this = this;
5543
5070
  var _ref, _ref1;
5544
- var _this_savedMutedStateBeforeScte, _this_savedMutedStateBeforeScte1;
5071
+ var _this_savedMutedStateBeforeAd, _this_savedMutedStateBeforeAd1;
5545
5072
  if (this.config.debugAdTiming) {
5546
5073
  console.log("[StormcloudVideoPlayer] \uD83C\uDFC1 Ad pod complete - cleaning up");
5547
5074
  }
5548
5075
  this.clearAdRequestWatchdog();
5549
5076
  this.clearAdFailsafeTimer();
5077
+ this.clearAdInsertionOffsetTimer();
5550
5078
  this.activeAdRequestToken = null;
5551
5079
  this.isInAdTransition = false;
5552
5080
  this.stopContinuousFetching();
@@ -5562,7 +5090,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5562
5090
  this.inAdBreak = false;
5563
5091
  this.expectedAdBreakDurationMs = void 0;
5564
5092
  this.currentAdBreakStartWallClockMs = void 0;
5565
- this.clearAdStartTimer();
5566
5093
  this.clearAdStopTimer();
5567
5094
  this.adPodQueue = [];
5568
5095
  this.showAds = false;
@@ -5570,8 +5097,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5570
5097
  this.totalAdsInBreak = 0;
5571
5098
  this.totalAdRequestsInBreak = 0;
5572
5099
  this.consecutiveFailures = 0;
5573
- 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();
5574
- 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();
5100
+ 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();
5101
+ 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();
5575
5102
  this.adLayer.updateOriginalMutedState(restoredMuted, restoredVolume);
5576
5103
  this.adLayer.stop().catch(function() {});
5577
5104
  if (this.video.muted !== restoredMuted) {
@@ -5680,7 +5207,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5680
5207
  }, delay);
5681
5208
  });
5682
5209
  }
5683
- this.savedMutedStateBeforeScte = null;
5210
+ this.savedMutedStateBeforeAd = null;
5684
5211
  }
5685
5212
  },
5686
5213
  {
@@ -5830,19 +5357,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5830
5357
  return Math.max(0, this.expectedAdBreakDurationMs - elapsed);
5831
5358
  }
5832
5359
  },
5833
- {
5834
- key: "pushScteMarker",
5835
- value: function pushScteMarker(marker) {
5836
- if (!this.config.debugAdTiming) return;
5837
- this.scteMarkerHistory.push({
5838
- timestampMs: Date.now(),
5839
- marker: marker
5840
- });
5841
- if (this.scteMarkerHistory.length > DEBUG_HISTORY_LIMIT) {
5842
- this.scteMarkerHistory = this.scteMarkerHistory.slice(-DEBUG_HISTORY_LIMIT);
5843
- }
5844
- }
5845
- },
5846
5360
  {
5847
5361
  key: "pushDebugLog",
5848
5362
  value: function pushDebugLog(level, category, message, details) {
@@ -5861,20 +5375,29 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5861
5375
  }
5862
5376
  },
5863
5377
  {
5864
- key: "getRecentScteMarkers",
5865
- value: function getRecentScteMarkers() {
5866
- return this.scteMarkerHistory.map(function(entry) {
5867
- return _object_spread({
5868
- timestampMs: entry.timestampMs,
5869
- type: entry.marker.type
5870
- }, entry.marker.ptsSeconds !== void 0 ? {
5871
- ptsSeconds: entry.marker.ptsSeconds
5872
- } : {}, entry.marker.durationSeconds !== void 0 ? {
5873
- durationSeconds: entry.marker.durationSeconds
5874
- } : {}, entry.marker.raw !== void 0 ? {
5875
- raw: entry.marker.raw
5876
- } : {});
5877
- });
5378
+ key: "pushAdInsertionDebug",
5379
+ value: function pushAdInsertionDebug(event, segmentName, opts) {
5380
+ if (!this.config.debugAdTiming) return;
5381
+ this.adInsertionDebugHistory.push(_object_spread({
5382
+ timestampMs: Date.now(),
5383
+ event: event,
5384
+ segmentName: segmentName
5385
+ }, (opts === null || opts === void 0 ? void 0 : opts.offsetSeconds) !== void 0 ? {
5386
+ offsetSeconds: opts.offsetSeconds
5387
+ } : {}, (opts === null || opts === void 0 ? void 0 : opts.updatedAt) ? {
5388
+ updatedAt: opts.updatedAt
5389
+ } : {}, (opts === null || opts === void 0 ? void 0 : opts.detail) ? {
5390
+ detail: opts.detail
5391
+ } : {}));
5392
+ if (this.adInsertionDebugHistory.length > DEBUG_HISTORY_LIMIT) {
5393
+ this.adInsertionDebugHistory = this.adInsertionDebugHistory.slice(-DEBUG_HISTORY_LIMIT);
5394
+ }
5395
+ }
5396
+ },
5397
+ {
5398
+ key: "getAdInsertionDebugLog",
5399
+ value: function getAdInsertionDebugLog() {
5400
+ return this.adInsertionDebugHistory.slice();
5878
5401
  }
5879
5402
  },
5880
5403
  {
@@ -6143,9 +5666,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6143
5666
  key: "destroy",
6144
5667
  value: function destroy() {
6145
5668
  var _this_hls, _this_adLayer;
5669
+ this.stopAdInsertionPolling();
5670
+ this.clearAdInsertionOffsetTimer();
6146
5671
  this.stopContinuousFetching();
6147
5672
  this.stopFillerBreakTimer();
6148
- this.clearAdStartTimer();
6149
5673
  this.clearAdStopTimer();
6150
5674
  this.clearAdFailsafeTimer();
6151
5675
  this.clearAdRequestWatchdog();
@@ -6173,7 +5697,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6173
5697
  (_this_adLayer = this.adLayer) === null || _this_adLayer === void 0 ? void 0 : _this_adLayer.destroy();
6174
5698
  this.consecutiveFailures = 0;
6175
5699
  this.debugLogEntries = [];
6176
- this.scteMarkerHistory = [];
5700
+ this.adInsertionDebugHistory = [];
6177
5701
  }
6178
5702
  }
6179
5703
  ]);
@@ -7550,7 +7074,7 @@ var AI_CONTEXT_MIN_POLL_MS = 800;
7550
7074
  var PANEL_BASE_RIGHT_OFFSET = 10;
7551
7075
  var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props) {
7552
7076
  var _ref;
7553
- var _aiLiveContext_context, _aiLiveContext_context_keywords, _aiLiveContext_context1;
7077
+ var _aiLiveContext_context;
7554
7078
  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, [
7555
7079
  "src",
7556
7080
  "autoplay",
@@ -7642,13 +7166,44 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7642
7166
  return "--:--:--";
7643
7167
  }
7644
7168
  };
7645
- var formatDebugRaw = function formatDebugRaw(raw) {
7646
- if (!raw || (typeof raw === "undefined" ? "undefined" : _type_of(raw)) !== "object") return "";
7647
- var obj = raw;
7648
- if (typeof obj.tag === "string") return obj.tag;
7649
- if (typeof obj.id3 === "string") return "ID3";
7650
- if (typeof obj.splice_command_type === "number") return "binary splice";
7651
- return "marker";
7169
+ var formatAdInsertionEvent = function formatAdInsertionEvent(event) {
7170
+ switch(event){
7171
+ case "api_response":
7172
+ return {
7173
+ label: "API",
7174
+ color: "#60a5fa"
7175
+ };
7176
+ case "scte35_inserted":
7177
+ return {
7178
+ label: "SCTE-35",
7179
+ color: "#f43f5e"
7180
+ };
7181
+ case "segment_found":
7182
+ return {
7183
+ label: "FOUND",
7184
+ color: "#a78bfa"
7185
+ };
7186
+ case "segment_playing":
7187
+ return {
7188
+ label: "PLAYING",
7189
+ color: "#fbbf24"
7190
+ };
7191
+ case "ad_scheduled":
7192
+ return {
7193
+ label: "SCHED",
7194
+ color: "#fb923c"
7195
+ };
7196
+ case "ad_triggered":
7197
+ return {
7198
+ label: "TRIGGER",
7199
+ color: "#34d399"
7200
+ };
7201
+ default:
7202
+ return {
7203
+ label: event,
7204
+ color: "rgba(255,255,255,0.68)"
7205
+ };
7206
+ }
7652
7207
  };
7653
7208
  var formatAiRelativeTime = function formatAiRelativeTime(timestamp) {
7654
7209
  var epochMs = Date.parse(timestamp);
@@ -7793,6 +7348,7 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
7793
7348
  if (minSegmentsBeforePlay !== void 0) cfg.minSegmentsBeforePlay = minSegmentsBeforePlay;
7794
7349
  if (disableAds !== void 0) cfg.disableAds = disableAds;
7795
7350
  cfg.disableFiller = disableFiller !== null && disableFiller !== void 0 ? disableFiller : true;
7351
+ if (swirlProjectId !== void 0) cfg.projectId = String(swirlProjectId);
7796
7352
  var player = new StormcloudVideoPlayer(cfg);
7797
7353
  playerRef.current = player;
7798
7354
  player.load().then(function() {
@@ -8061,7 +7617,7 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
8061
7617
  var updateDebugData = function updateDebugData() {
8062
7618
  var player = playerRef.current;
8063
7619
  if (!player) return;
8064
- setDebugMarkers(player.getRecentScteMarkers().slice(-DEBUG_PANEL_MARKER_LIMIT).reverse());
7620
+ setDebugMarkers(player.getAdInsertionDebugLog().slice(-DEBUG_PANEL_MARKER_LIMIT).reverse());
8065
7621
  };
8066
7622
  updateDebugData();
8067
7623
  var interval = window.setInterval(updateDebugData, 500);
@@ -8596,34 +8152,7 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
8596
8152
  whiteSpace: "pre-wrap"
8597
8153
  },
8598
8154
  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."
8599
- }),
8600
- ((_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", {
8601
- style: {
8602
- marginTop: "10px",
8603
- display: "flex",
8604
- flexWrap: "wrap",
8605
- gap: "6px"
8606
- },
8607
- children: aiLiveContext.context.keywords.slice(0, 12).map(function(kw) {
8608
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8609
- style: {
8610
- fontSize: "10px",
8611
- fontWeight: 600,
8612
- padding: "4px 7px",
8613
- borderRadius: "999px",
8614
- background: "rgba(236, 72, 153, 0.2)",
8615
- border: "1px solid rgba(244, 114, 182, 0.42)",
8616
- color: "#fce7f3",
8617
- maxWidth: "100%",
8618
- overflow: "hidden",
8619
- textOverflow: "ellipsis",
8620
- whiteSpace: "nowrap"
8621
- },
8622
- title: kw,
8623
- children: kw
8624
- }, kw);
8625
- })
8626
- }) : null
8155
+ })
8627
8156
  ]
8628
8157
  })
8629
8158
  ]
@@ -8665,7 +8194,7 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
8665
8194
  fontWeight: 700,
8666
8195
  letterSpacing: "0.02em"
8667
8196
  },
8668
- children: "Debug Ad Timing"
8197
+ children: "Ad Insertion Debug"
8669
8198
  }),
8670
8199
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", {
8671
8200
  className: "sc-ctrl-btn",
@@ -8693,9 +8222,13 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
8693
8222
  overflowX: "hidden",
8694
8223
  height: "calc(100% - 46px)",
8695
8224
  display: "grid",
8696
- gap: "12px"
8225
+ gap: "12px",
8226
+ minWidth: 0
8697
8227
  },
8698
8228
  children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8229
+ style: {
8230
+ minWidth: 0
8231
+ },
8699
8232
  children: [
8700
8233
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8701
8234
  style: {
@@ -8706,69 +8239,145 @@ var StormcloudVideoPlayerComponent = import_react2.default.memo(function(props)
8706
8239
  color: "rgba(255,255,255,0.68)",
8707
8240
  marginBottom: "8px"
8708
8241
  },
8709
- children: "SCTE-35 markers"
8242
+ children: "Ad Insertion Points"
8710
8243
  }),
8711
8244
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8712
8245
  style: {
8713
8246
  display: "grid",
8714
- gap: "6px"
8247
+ gap: "6px",
8248
+ minWidth: 0
8715
8249
  },
8716
8250
  children: debugMarkers.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", {
8717
8251
  style: {
8718
8252
  fontSize: "12px",
8719
8253
  color: "rgba(255,255,255,0.55)"
8720
8254
  },
8721
- children: "No markers detected yet."
8255
+ children: "No ad insertion events yet."
8722
8256
  }) : debugMarkers.map(function(entry, idx) {
8257
+ var evt = formatAdInsertionEvent(entry.event);
8258
+ var fileName = entry.segmentName ? entry.segmentName.split("/").pop() || entry.segmentName : "";
8723
8259
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8724
8260
  style: {
8725
- display: "grid",
8726
- gridTemplateColumns: "56px 52px 1fr",
8727
- gap: "8px",
8728
- alignItems: "center",
8261
+ minWidth: 0,
8729
8262
  fontFamily: "'SF Mono', 'Cascadia Code', monospace",
8730
8263
  fontSize: "11px",
8731
8264
  background: "rgba(255,255,255,0.05)",
8732
8265
  border: "1px solid rgba(255,255,255,0.08)",
8733
8266
  borderRadius: "8px",
8734
- padding: "6px 8px"
8267
+ padding: "6px 8px",
8268
+ display: "flex",
8269
+ flexDirection: "column",
8270
+ gap: "4px"
8735
8271
  },
8736
8272
  children: [
8737
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8738
- style: {
8739
- color: "rgba(255,255,255,0.68)"
8740
- },
8741
- children: formatDebugClock(entry.timestampMs)
8742
- }),
8743
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8273
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8744
8274
  style: {
8745
- textTransform: "uppercase",
8746
- fontWeight: 700,
8747
- color: entry.type === "start" ? "#34d399" : entry.type === "end" ? "#f87171" : "#fbbf24"
8275
+ display: "grid",
8276
+ gridTemplateColumns: "56px 54px minmax(0, 1fr) 20px",
8277
+ gap: "6px",
8278
+ alignItems: "center",
8279
+ minWidth: 0
8748
8280
  },
8749
- children: entry.type
8281
+ children: [
8282
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8283
+ style: {
8284
+ color: "rgba(255,255,255,0.68)"
8285
+ },
8286
+ children: formatDebugClock(entry.timestampMs)
8287
+ }),
8288
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8289
+ style: {
8290
+ fontWeight: 700,
8291
+ color: evt.color,
8292
+ fontSize: "10px"
8293
+ },
8294
+ children: evt.label
8295
+ }),
8296
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8297
+ style: {
8298
+ color: "rgba(255,255,255,0.88)",
8299
+ overflow: "hidden",
8300
+ textOverflow: "ellipsis",
8301
+ whiteSpace: "nowrap",
8302
+ minWidth: 0
8303
+ },
8304
+ title: entry.segmentName,
8305
+ children: fileName
8306
+ }),
8307
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", {
8308
+ onClick: function onClick() {
8309
+ return navigator.clipboard.writeText(entry.segmentName);
8310
+ },
8311
+ title: entry.segmentName,
8312
+ style: {
8313
+ background: "none",
8314
+ border: "none",
8315
+ cursor: "pointer",
8316
+ padding: "2px",
8317
+ color: "rgba(255,255,255,0.45)",
8318
+ display: "flex",
8319
+ alignItems: "center",
8320
+ justifyContent: "center",
8321
+ borderRadius: "4px",
8322
+ flexShrink: 0
8323
+ },
8324
+ onMouseEnter: function onMouseEnter(e) {
8325
+ return e.currentTarget.style.color = "rgba(255,255,255,0.9)";
8326
+ },
8327
+ onMouseLeave: function onMouseLeave(e) {
8328
+ return e.currentTarget.style.color = "rgba(255,255,255,0.45)";
8329
+ },
8330
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_fa.FaCopy, {
8331
+ size: 10
8332
+ })
8333
+ })
8334
+ ]
8750
8335
  }),
8751
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8336
+ (entry.offsetSeconds != null || entry.detail || entry.updatedAt) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", {
8752
8337
  style: {
8753
- color: "rgba(255,255,255,0.88)"
8338
+ display: "flex",
8339
+ flexWrap: "wrap",
8340
+ gap: "6px",
8341
+ paddingLeft: "0px",
8342
+ fontSize: "10px"
8754
8343
  },
8755
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", {
8756
- style: {
8757
- display: "inline-block",
8758
- maxWidth: "100%",
8759
- verticalAlign: "bottom",
8760
- overflow: "hidden",
8761
- textOverflow: "ellipsis",
8762
- whiteSpace: "nowrap"
8763
- },
8764
- children: [
8765
- entry.durationSeconds != null ? "dur:".concat(entry.durationSeconds.toFixed(2), "s") : "dur:-",
8766
- " ",
8767
- entry.ptsSeconds != null ? "pts:".concat(entry.ptsSeconds.toFixed(2)) : "pts:-",
8768
- " ",
8769
- formatDebugRaw(entry.raw)
8770
- ]
8771
- })
8344
+ children: [
8345
+ entry.offsetSeconds != null && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", {
8346
+ style: {
8347
+ color: "rgba(255,255,255,0.55)",
8348
+ background: "rgba(255,255,255,0.06)",
8349
+ borderRadius: "4px",
8350
+ padding: "1px 5px"
8351
+ },
8352
+ children: [
8353
+ "+",
8354
+ entry.offsetSeconds.toFixed(2),
8355
+ "s"
8356
+ ]
8357
+ }),
8358
+ entry.detail && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8359
+ style: {
8360
+ color: "rgba(255,255,255,0.55)",
8361
+ background: "rgba(255,255,255,0.06)",
8362
+ borderRadius: "4px",
8363
+ padding: "1px 5px",
8364
+ overflow: "hidden",
8365
+ textOverflow: "ellipsis",
8366
+ whiteSpace: "nowrap",
8367
+ maxWidth: "100%"
8368
+ },
8369
+ children: entry.detail
8370
+ }),
8371
+ entry.updatedAt && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", {
8372
+ style: {
8373
+ color: "rgba(255,255,255,0.38)",
8374
+ background: "rgba(255,255,255,0.04)",
8375
+ borderRadius: "4px",
8376
+ padding: "1px 5px"
8377
+ },
8378
+ children: formatAiRelativeTime(entry.updatedAt)
8379
+ })
8380
+ ]
8772
8381
  })
8773
8382
  ]
8774
8383
  }, "".concat(entry.timestampMs, "-").concat(idx));