stormcloud-video-player 0.7.11 → 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.js CHANGED
@@ -1413,7 +1413,6 @@ function createAdStormPlayer(contentVideo, options) {
1413
1413
  contentVideo.muted = originalMutedState;
1414
1414
  contentVideo.volume = originalVolume;
1415
1415
  currentAd = void 0;
1416
- tornDown = false;
1417
1416
  return [
1418
1417
  2,
1419
1418
  Promise.resolve()
@@ -1528,6 +1527,15 @@ function createAdStormPlayer(contentVideo, options) {
1528
1527
  if (!token) return [
1529
1528
  2
1530
1529
  ];
1530
+ if (currentAd) {
1531
+ preloadSlots.set(token, {
1532
+ ad: currentAd
1533
+ });
1534
+ currentAd = void 0;
1535
+ return [
1536
+ 2
1537
+ ];
1538
+ }
1531
1539
  requestContext = typeof arg1 === "string" ? arg2 : arg1;
1532
1540
  return [
1533
1541
  4,
@@ -2021,56 +2029,6 @@ function sendInitialTracking(licenseKey) {
2021
2029
  });
2022
2030
  })();
2023
2031
  }
2024
- function sendAdDetectTracking(licenseKey, adDetectInfo) {
2025
- return _async_to_generator(function() {
2026
- var clientInfo, browserId, trackingData, error;
2027
- return _ts_generator(this, function(_state) {
2028
- switch(_state.label){
2029
- case 0:
2030
- _state.trys.push([
2031
- 0,
2032
- 3,
2033
- ,
2034
- 4
2035
- ]);
2036
- clientInfo = getClientInfo();
2037
- return [
2038
- 4,
2039
- getBrowserID(clientInfo)
2040
- ];
2041
- case 1:
2042
- browserId = _state.sent();
2043
- trackingData = _object_spread({
2044
- browserId: browserId
2045
- }, clientInfo);
2046
- return [
2047
- 4,
2048
- sendTrackRequest(licenseKey, _object_spread_props(_object_spread({}, trackingData), {
2049
- licenseKey: licenseKey,
2050
- adDetectInfo: adDetectInfo
2051
- }))
2052
- ];
2053
- case 2:
2054
- _state.sent();
2055
- return [
2056
- 3,
2057
- 4
2058
- ];
2059
- case 3:
2060
- error = _state.sent();
2061
- console.error("[StormcloudVideoPlayer] Error sending ad detect tracking:", error);
2062
- return [
2063
- 3,
2064
- 4
2065
- ];
2066
- case 4:
2067
- return [
2068
- 2
2069
- ];
2070
- }
2071
- });
2072
- })();
2073
- }
2074
2032
  function sendAdLoadedTracking(licenseKey, adLoadedInfo) {
2075
2033
  return _async_to_generator(function() {
2076
2034
  var clientInfo, browserId, trackingData, error;
@@ -2783,7 +2741,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2783
2741
  this.continuousFetchLoopPromise = null;
2784
2742
  this.attached = false;
2785
2743
  this.inAdBreak = false;
2786
- this.ptsDriftEmaMs = 0;
2787
2744
  this.adPodQueue = [];
2788
2745
  this.lastHeartbeatTime = 0;
2789
2746
  this.currentAdIndex = 0;
@@ -2807,7 +2764,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2807
2764
  this.totalAdRequestsInBreak = 0;
2808
2765
  this.maxTotalAdRequestsPerBreak = 20;
2809
2766
  this.pendingAdBreak = null;
2810
- this.savedMutedStateBeforeScte = null;
2767
+ this.savedMutedStateBeforeAd = null;
2811
2768
  this.consecutiveFailures = 0;
2812
2769
  this.maxConsecutiveFailures = 5;
2813
2770
  this.lastAdRequestTime = 0;
@@ -2820,7 +2777,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2820
2777
  this.adRequestRetryBackoffMs = 1500;
2821
2778
  this.preloadedTokens = [];
2822
2779
  this.debugLogEntries = [];
2823
- this.scteMarkerHistory = [];
2824
2780
  this.adInsertionDebugHistory = [];
2825
2781
  initializePolyfills();
2826
2782
  var browserOverrides = getBrowserConfigOverrides();
@@ -3109,18 +3065,44 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3109
3065
  _this.pushAdInsertionDebug("ad_triggered", segmentName, {
3110
3066
  detail: "ad break started (60s)"
3111
3067
  });
3112
- var marker = {
3113
- type: "start",
3114
- durationSeconds: 60,
3115
- raw: {
3116
- apiInsertionPoint: _this.lastAdInsertionPoint
3117
- }
3118
- };
3119
- _this.onScte35Marker(marker);
3068
+ void _this.handleAdStart(60);
3120
3069
  }, offsetMs);
3121
3070
  }
3122
3071
  }
3123
3072
  });
3073
+ this.hls.on(Hls.Events.FRAG_PARSING_USERDATA, function(_evt, data) {
3074
+ var _ref;
3075
+ var samples = (_ref = data === null || data === void 0 ? void 0 : data.samples) !== null && _ref !== void 0 ? _ref : [];
3076
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
3077
+ try {
3078
+ for(var _iterator = samples[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
3079
+ var sample = _step.value;
3080
+ var _ref1, _ref2;
3081
+ var _data_frag, _data_frag1;
3082
+ var bytes = sample === null || sample === void 0 ? void 0 : sample.data;
3083
+ if (!bytes || bytes.length < 5) continue;
3084
+ var isSCTE35 = bytes[0] === 252;
3085
+ if (!isSCTE35) continue;
3086
+ 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 : "";
3087
+ _this.pushAdInsertionDebug("scte35_inserted", segName, {
3088
+ detail: "len=".concat(bytes.length, "B")
3089
+ });
3090
+ }
3091
+ } catch (err) {
3092
+ _didIteratorError = true;
3093
+ _iteratorError = err;
3094
+ } finally{
3095
+ try {
3096
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
3097
+ _iterator.return();
3098
+ }
3099
+ } finally{
3100
+ if (_didIteratorError) {
3101
+ throw _iteratorError;
3102
+ }
3103
+ }
3104
+ }
3105
+ });
3124
3106
  this.hls.on(Hls.Events.ERROR, function(_evt, data) {
3125
3107
  if (data === null || data === void 0 ? void 0 : data.fatal) {
3126
3108
  switch(data.type){
@@ -3195,8 +3177,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3195
3177
  _this.activeAdRequestToken = null;
3196
3178
  _this.showAds = true;
3197
3179
  if (_this.config.disableFiller) {
3198
- if (_this.savedMutedStateBeforeScte == null) {
3199
- _this.savedMutedStateBeforeScte = {
3180
+ if (_this.savedMutedStateBeforeAd == null) {
3181
+ _this.savedMutedStateBeforeAd = {
3200
3182
  muted: _this.video.muted,
3201
3183
  volume: _this.video.volume
3202
3184
  };
@@ -3224,10 +3206,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3224
3206
  });
3225
3207
  this.adLayer.on("content_resume", function() {
3226
3208
  var _ref, _ref1;
3227
- var _this_savedMutedStateBeforeScte, _this_savedMutedStateBeforeScte1;
3209
+ var _this_savedMutedStateBeforeAd, _this_savedMutedStateBeforeAd1;
3228
3210
  var remaining = _this.getRemainingAdMs();
3229
- 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();
3230
- 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();
3211
+ 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();
3212
+ 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();
3231
3213
  if (_this.config.debugAdTiming) {
3232
3214
  console.log("[StormcloudVideoPlayer] content_resume received, inAdBreak=%s, remaining=%s, preloadedTokens=%d, pendingNext=%s", _this.inAdBreak, remaining, _this.preloadedTokens.length, !!_this.pendingNextAdBids);
3233
3215
  }
@@ -3304,7 +3286,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3304
3286
  var remainingFinal = _this.getRemainingAdMs();
3305
3287
  if (_this.inAdBreak && remainingFinal > _this.MIN_AD_REMAINING_MS) {
3306
3288
  if (_this.config.debugAdTiming) {
3307
- console.log("[StormcloudVideoPlayer] content_resume: no more ads, showing filler for", remainingFinal, "ms");
3289
+ console.log("[StormcloudVideoPlayer] content_resume: ad ended/failed with time remaining, showing filler and continuing fetch for", remainingFinal, "ms");
3308
3290
  }
3309
3291
  if (!_this.config.disableFiller) {
3310
3292
  _this.showPlaceholderLayer();
@@ -3322,7 +3304,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3322
3304
  (_this_video_play = _this.video.play()) === null || _this_video_play === void 0 ? void 0 : _this_video_play.catch(function() {});
3323
3305
  }
3324
3306
  }
3325
- _this.stopContinuousFetching();
3307
+ _this.continuousFetchingActive = true;
3308
+ _this.startContinuousFetchLoop();
3326
3309
  return;
3327
3310
  }
3328
3311
  if (_this.config.debugAdTiming) {
@@ -3469,547 +3452,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3469
3452
  return !!(this.config.allowNativeHls && canNative);
3470
3453
  }
3471
3454
  },
3472
- {
3473
- key: "onId3Tag",
3474
- value: function onId3Tag(tag) {
3475
- if (typeof tag.ptsSeconds === "number") {
3476
- this.updatePtsDrift(tag.ptsSeconds);
3477
- }
3478
- var marker = this.parseScte35FromId3(tag);
3479
- if (marker) {
3480
- this.onScte35Marker(marker);
3481
- }
3482
- }
3483
- },
3484
- {
3485
- key: "parseScte35FromId3",
3486
- value: function parseScte35FromId3(tag) {
3487
- var text = this.decodeId3ValueToText(tag.value);
3488
- if (!text) return void 0;
3489
- var cueOutMatch = text.match(/EXT-X-CUE-OUT(?::([^\r\n]*))?/i) || text.match(/CUE-OUT(?::([^\r\n]*))?/i);
3490
- if (cueOutMatch) {
3491
- var _cueOutMatch_;
3492
- var arg = ((_cueOutMatch_ = cueOutMatch[1]) !== null && _cueOutMatch_ !== void 0 ? _cueOutMatch_ : "").trim();
3493
- var dur = this.parseCueOutDuration(arg);
3494
- var marker = _object_spread_props(_object_spread({
3495
- type: "start"
3496
- }, tag.ptsSeconds !== void 0 ? {
3497
- ptsSeconds: tag.ptsSeconds
3498
- } : {}, dur !== void 0 ? {
3499
- durationSeconds: dur
3500
- } : {}), {
3501
- raw: {
3502
- id3: text
3503
- }
3504
- });
3505
- return marker;
3506
- }
3507
- var cueOutContMatch = text.match(/EXT-X-CUE-OUT-CONT:([^\r\n]*)/i);
3508
- if (cueOutContMatch) {
3509
- var _cueOutContMatch_;
3510
- var arg1 = ((_cueOutContMatch_ = cueOutContMatch[1]) !== null && _cueOutContMatch_ !== void 0 ? _cueOutContMatch_ : "").trim();
3511
- var cont = this.parseCueOutCont(arg1);
3512
- var marker1 = _object_spread_props(_object_spread({
3513
- type: "progress"
3514
- }, tag.ptsSeconds !== void 0 ? {
3515
- ptsSeconds: tag.ptsSeconds
3516
- } : {}, (cont === null || cont === void 0 ? void 0 : cont.duration) !== void 0 ? {
3517
- durationSeconds: cont.duration
3518
- } : {}), {
3519
- raw: {
3520
- id3: text
3521
- }
3522
- });
3523
- return marker1;
3524
- }
3525
- var cueInMatch = text.match(/EXT-X-CUE-IN\b/i) || text.match(/CUE-IN\b/i);
3526
- if (cueInMatch) {
3527
- var marker2 = _object_spread_props(_object_spread({
3528
- type: "end"
3529
- }, tag.ptsSeconds !== void 0 ? {
3530
- ptsSeconds: tag.ptsSeconds
3531
- } : {}), {
3532
- raw: {
3533
- id3: text
3534
- }
3535
- });
3536
- return marker2;
3537
- }
3538
- var daterangeMatch = text.match(/EXT-X-DATERANGE:([^\r\n]*)/i);
3539
- if (daterangeMatch) {
3540
- var _daterangeMatch_, _attrs_CLASS;
3541
- var attrs = this.parseAttributeList((_daterangeMatch_ = daterangeMatch[1]) !== null && _daterangeMatch_ !== void 0 ? _daterangeMatch_ : "");
3542
- var hasScteOut = "SCTE35-OUT" in attrs || attrs["SCTE35-OUT"] !== void 0;
3543
- var hasScteIn = "SCTE35-IN" in attrs || attrs["SCTE35-IN"] !== void 0;
3544
- var klass = String((_attrs_CLASS = attrs["CLASS"]) !== null && _attrs_CLASS !== void 0 ? _attrs_CLASS : "");
3545
- var duration = this.toNumber(attrs["DURATION"]);
3546
- if (hasScteOut || /com\.apple\.hls\.cue/i.test(klass)) {
3547
- var marker3 = _object_spread_props(_object_spread({
3548
- type: "start"
3549
- }, tag.ptsSeconds !== void 0 ? {
3550
- ptsSeconds: tag.ptsSeconds
3551
- } : {}, duration !== void 0 ? {
3552
- durationSeconds: duration
3553
- } : {}), {
3554
- raw: {
3555
- id3: text,
3556
- attrs: attrs
3557
- }
3558
- });
3559
- return marker3;
3560
- }
3561
- if (hasScteIn) {
3562
- var marker4 = _object_spread_props(_object_spread({
3563
- type: "end"
3564
- }, tag.ptsSeconds !== void 0 ? {
3565
- ptsSeconds: tag.ptsSeconds
3566
- } : {}), {
3567
- raw: {
3568
- id3: text,
3569
- attrs: attrs
3570
- }
3571
- });
3572
- return marker4;
3573
- }
3574
- }
3575
- if (/SCTE35-OUT/i.test(text)) {
3576
- var marker5 = _object_spread_props(_object_spread({
3577
- type: "start"
3578
- }, tag.ptsSeconds !== void 0 ? {
3579
- ptsSeconds: tag.ptsSeconds
3580
- } : {}), {
3581
- raw: {
3582
- id3: text
3583
- }
3584
- });
3585
- return marker5;
3586
- }
3587
- if (/SCTE35-IN/i.test(text)) {
3588
- var marker6 = _object_spread_props(_object_spread({
3589
- type: "end"
3590
- }, tag.ptsSeconds !== void 0 ? {
3591
- ptsSeconds: tag.ptsSeconds
3592
- } : {}), {
3593
- raw: {
3594
- id3: text
3595
- }
3596
- });
3597
- return marker6;
3598
- }
3599
- if (_instanceof(tag.value, Uint8Array)) {
3600
- var bin = this.parseScte35Binary(tag.value);
3601
- if (bin) return bin;
3602
- }
3603
- return void 0;
3604
- }
3605
- },
3606
- {
3607
- key: "decodeId3ValueToText",
3608
- value: function decodeId3ValueToText(value) {
3609
- try {
3610
- if (typeof value === "string") return value;
3611
- var decoder = new TextDecoder("utf-8", {
3612
- fatal: false
3613
- });
3614
- var text = decoder.decode(value);
3615
- if (text && /[\x20-\x7E]/.test(text)) return text;
3616
- var out = "";
3617
- for(var i = 0; i < value.length; i++)out += String.fromCharCode(value[i]);
3618
- return out;
3619
- } catch (unused) {
3620
- return void 0;
3621
- }
3622
- }
3623
- },
3624
- {
3625
- key: "onScte35Marker",
3626
- value: function onScte35Marker(marker) {
3627
- var _this = this;
3628
- if (this.config.disableAds) return;
3629
- this.pushScteMarker(marker);
3630
- this.pushDebugLog("info", "scte35", "SCTE-35 marker detected", {
3631
- type: marker.type,
3632
- ptsSeconds: marker.ptsSeconds,
3633
- durationSeconds: marker.durationSeconds,
3634
- currentTime: this.video.currentTime
3635
- });
3636
- if (this.config.debugAdTiming) {
3637
- console.log("[StormcloudVideoPlayer] SCTE-35 marker detected:", {
3638
- type: marker.type,
3639
- ptsSeconds: marker.ptsSeconds,
3640
- durationSeconds: marker.durationSeconds,
3641
- currentTime: this.video.currentTime,
3642
- raw: marker.raw,
3643
- hasPendingAdBreak: !!this.pendingAdBreak
3644
- });
3645
- }
3646
- if (marker.type === "start") {
3647
- var _this_config_immediateManifestAds;
3648
- var _this_pendingAdBreak;
3649
- if (this.savedMutedStateBeforeScte == null) {
3650
- this.savedMutedStateBeforeScte = {
3651
- muted: this.video.muted,
3652
- volume: this.video.volume
3653
- };
3654
- this.adLayer.updateOriginalMutedState(this.video.muted, this.video.volume);
3655
- }
3656
- if (!this.config.disableFiller && !this.video.muted && !this.adLayer.isAdPlaying()) {
3657
- this.video.muted = true;
3658
- this.video.volume = 0;
3659
- if (this.config.debugAdTiming) {
3660
- console.log("[StormcloudVideoPlayer] Muted video on SCTE start marker");
3661
- }
3662
- }
3663
- if (this.inAdBreak) {
3664
- if (marker.durationSeconds != null) {
3665
- var newDurationMs = marker.durationSeconds * 1e3;
3666
- if (this.expectedAdBreakDurationMs == null || newDurationMs > this.expectedAdBreakDurationMs) {
3667
- this.expectedAdBreakDurationMs = newDurationMs;
3668
- var elapsedMs = this.currentAdBreakStartWallClockMs != null ? Date.now() - this.currentAdBreakStartWallClockMs : 0;
3669
- var remainingMs = Math.max(0, newDurationMs - elapsedMs);
3670
- this.scheduleAdStopCountdown(remainingMs);
3671
- if (this.config.debugAdTiming) {
3672
- console.log("[StormcloudVideoPlayer] Updated ad break duration from subsequent marker: ".concat(newDurationMs, "ms, remaining: ").concat(remainingMs, "ms"));
3673
- }
3674
- }
3675
- }
3676
- return;
3677
- }
3678
- this.inAdBreak = true;
3679
- 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;
3680
- this.expectedAdBreakDurationMs = durationMs;
3681
- this.currentAdBreakStartWallClockMs = Date.now();
3682
- if (this.config.licenseKey) {
3683
- var _this_pendingAdBreak1;
3684
- var adDetectInfo = _object_spread({
3685
- source: "scte35",
3686
- timestamp: /* @__PURE__ */ new Date().toISOString()
3687
- }, marker.durationSeconds != null && {
3688
- durationSeconds: marker.durationSeconds
3689
- }, marker.ptsSeconds != null && {
3690
- ptsSeconds: marker.ptsSeconds
3691
- }, ((_this_pendingAdBreak1 = this.pendingAdBreak) === null || _this_pendingAdBreak1 === void 0 ? void 0 : _this_pendingAdBreak1.detectedAtFragmentSn) != null && {
3692
- detectedAtFragmentSn: this.pendingAdBreak.detectedAtFragmentSn
3693
- });
3694
- sendAdDetectTracking(this.config.licenseKey, adDetectInfo);
3695
- }
3696
- var isManifestMarker = this.isManifestBasedMarker(marker);
3697
- var forceImmediate = (_this_config_immediateManifestAds = this.config.immediateManifestAds) !== null && _this_config_immediateManifestAds !== void 0 ? _this_config_immediateManifestAds : true;
3698
- if (this.config.debugAdTiming) {
3699
- console.log("[StormcloudVideoPlayer] Ad start decision:", {
3700
- isManifestMarker: isManifestMarker,
3701
- forceImmediate: forceImmediate,
3702
- hasPts: typeof marker.ptsSeconds === "number"
3703
- });
3704
- }
3705
- if (isManifestMarker && forceImmediate) {
3706
- if (this.config.debugAdTiming) {
3707
- console.log("[StormcloudVideoPlayer] Starting ad immediately (manifest-based)");
3708
- }
3709
- this.clearAdStartTimer();
3710
- this.handleAdStart(marker);
3711
- } else if (typeof marker.ptsSeconds === "number") {
3712
- var _this_config_driftToleranceMs;
3713
- var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
3714
- var nowMs = this.video.currentTime * 1e3;
3715
- var estCurrentPtsMs = nowMs - this.ptsDriftEmaMs;
3716
- var deltaMs = Math.floor(marker.ptsSeconds * 1e3 - estCurrentPtsMs);
3717
- if (this.config.debugAdTiming) {
3718
- console.log("[StormcloudVideoPlayer] PTS-based timing calculation:", {
3719
- nowMs: nowMs,
3720
- estCurrentPtsMs: estCurrentPtsMs,
3721
- markerPtsMs: marker.ptsSeconds * 1e3,
3722
- deltaMs: deltaMs,
3723
- tolerance: tol
3724
- });
3725
- }
3726
- if (deltaMs > tol) {
3727
- if (this.config.debugAdTiming) {
3728
- console.log("[StormcloudVideoPlayer] Scheduling ad start in ".concat(deltaMs, "ms"));
3729
- }
3730
- this.scheduleAdStartIn(deltaMs);
3731
- } else {
3732
- if (this.config.debugAdTiming) {
3733
- console.log("[StormcloudVideoPlayer] Starting ad immediately (within tolerance)");
3734
- }
3735
- this.clearAdStartTimer();
3736
- this.handleAdStart(marker);
3737
- }
3738
- } else {
3739
- if (this.config.debugAdTiming) {
3740
- console.log("[StormcloudVideoPlayer] Starting ad immediately (fallback)");
3741
- }
3742
- this.clearAdStartTimer();
3743
- this.handleAdStart(marker);
3744
- }
3745
- if (this.expectedAdBreakDurationMs != null) {
3746
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
3747
- }
3748
- return;
3749
- }
3750
- if (marker.type === "progress" && this.inAdBreak) {
3751
- if (marker.durationSeconds != null) {
3752
- this.expectedAdBreakDurationMs = marker.durationSeconds * 1e3;
3753
- }
3754
- if (this.expectedAdBreakDurationMs != null && this.currentAdBreakStartWallClockMs != null) {
3755
- var elapsedMs1 = Date.now() - this.currentAdBreakStartWallClockMs;
3756
- var remainingMs1 = Math.max(0, this.expectedAdBreakDurationMs - elapsedMs1);
3757
- this.scheduleAdStopCountdown(remainingMs1);
3758
- }
3759
- if (!this.adLayer.isAdPlaying() && this.pendingNextAdBids != null && this.pendingNextAdBids.length > 0) {
3760
- var bids = this.pendingNextAdBids;
3761
- this.pendingNextAdBids = null;
3762
- this.currentAdIndex++;
3763
- this.adLayer.playAd(bids).catch(function() {
3764
- return _this.handleAdFailure();
3765
- });
3766
- }
3767
- return;
3768
- }
3769
- if (marker.type === "end") {
3770
- var remaining = this.getRemainingAdMs();
3771
- var adPlaying = this.adLayer.isAdPlaying();
3772
- var hasQueuedAds = this.pendingNextAdBids != null && this.pendingNextAdBids.length > 0;
3773
- if (this.config.debugAdTiming) {
3774
- console.log("[StormcloudVideoPlayer] SCTE-35 end marker received:", {
3775
- inAdBreak: this.inAdBreak,
3776
- remaining: remaining,
3777
- adPlaying: adPlaying,
3778
- hasQueuedAds: hasQueuedAds,
3779
- activeAdRequest: this.activeAdRequestToken !== null
3780
- });
3781
- }
3782
- if (!this.inAdBreak) {
3783
- if (this.config.debugAdTiming) {
3784
- console.log("[StormcloudVideoPlayer] Ignoring SCTE-35 end marker - not in ad break");
3785
- }
3786
- return;
3787
- }
3788
- if (adPlaying || remaining > 500) {
3789
- if (this.config.debugAdTiming) {
3790
- console.log("[StormcloudVideoPlayer] Ignoring premature SCTE-35 end marker - ads still active or time remaining");
3791
- }
3792
- return;
3793
- }
3794
- this.inAdBreak = false;
3795
- this.expectedAdBreakDurationMs = void 0;
3796
- this.currentAdBreakStartWallClockMs = void 0;
3797
- this.clearAdStartTimer();
3798
- this.clearAdStopTimer();
3799
- if (adPlaying) {
3800
- this.adLayer.stop().catch(function() {});
3801
- }
3802
- this.handleAdPodComplete();
3803
- return;
3804
- }
3805
- }
3806
- },
3807
- {
3808
- key: "parseCueOutDuration",
3809
- value: function parseCueOutDuration(value) {
3810
- var num = parseFloat(value.trim());
3811
- if (!Number.isNaN(num)) return num;
3812
- var match = value.match(/(?:^|[,\s])DURATION\s*=\s*([0-9.]+)/i) || value.match(/Duration\s*=\s*([0-9.]+)/i);
3813
- if (match && match[1] != null) {
3814
- var dStr = match[1];
3815
- var d = parseFloat(dStr);
3816
- return Number.isNaN(d) ? void 0 : d;
3817
- }
3818
- return void 0;
3819
- }
3820
- },
3821
- {
3822
- key: "parseCueOutCont",
3823
- value: function parseCueOutCont(value) {
3824
- var res = {};
3825
- var elapsedMatch = value.match(/Elapsed\s*=\s*([0-9.]+)/i);
3826
- var durationMatch = value.match(/Duration\s*=\s*([0-9.]+)/i);
3827
- if (elapsedMatch && elapsedMatch[1] != null) {
3828
- var e = parseFloat(elapsedMatch[1]);
3829
- if (!Number.isNaN(e)) res.elapsed = e;
3830
- }
3831
- if (durationMatch && durationMatch[1] != null) {
3832
- var d = parseFloat(durationMatch[1]);
3833
- if (!Number.isNaN(d)) res.duration = d;
3834
- }
3835
- if (!("elapsed" in res) || !("duration" in res)) {
3836
- var slashMatch = value.match(/([0-9.]+)\s*\/\s*([0-9.]+)/);
3837
- if (slashMatch && slashMatch[1] && slashMatch[2]) {
3838
- var elapsed = parseFloat(slashMatch[1]);
3839
- var duration = parseFloat(slashMatch[2]);
3840
- if (!Number.isNaN(elapsed) && !("elapsed" in res)) res.elapsed = elapsed;
3841
- if (!Number.isNaN(duration) && !("duration" in res)) res.duration = duration;
3842
- }
3843
- }
3844
- if ("elapsed" in res || "duration" in res) return res;
3845
- return void 0;
3846
- }
3847
- },
3848
- {
3849
- key: "parseAttributeList",
3850
- value: function parseAttributeList(value) {
3851
- var attrs = {};
3852
- var regex = /([A-Z0-9-]+)=(("[^"]*")|([^",]*))(?:,|$)/gi;
3853
- var match;
3854
- while((match = regex.exec(value)) !== null){
3855
- var _match_, _ref, _match_1;
3856
- var key = (_match_ = match[1]) !== null && _match_ !== void 0 ? _match_ : "";
3857
- var rawVal = (_ref = (_match_1 = match[3]) !== null && _match_1 !== void 0 ? _match_1 : match[4]) !== null && _ref !== void 0 ? _ref : "";
3858
- if (rawVal.startsWith('"') && rawVal.endsWith('"')) {
3859
- rawVal = rawVal.slice(1, -1);
3860
- }
3861
- if (key) {
3862
- attrs[key] = rawVal;
3863
- }
3864
- }
3865
- return attrs;
3866
- }
3867
- },
3868
- {
3869
- key: "toNumber",
3870
- value: function toNumber(val) {
3871
- if (val == null) return void 0;
3872
- var n = typeof val === "string" ? parseFloat(val) : Number(val);
3873
- return Number.isNaN(n) ? void 0 : n;
3874
- }
3875
- },
3876
- {
3877
- key: "isManifestBasedMarker",
3878
- value: function isManifestBasedMarker(marker) {
3879
- var raw = marker.raw;
3880
- if (!raw) return false;
3881
- if (raw.tag) {
3882
- var tag = String(raw.tag);
3883
- return tag.includes("EXT-X-CUE-OUT") || tag.includes("EXT-X-CUE-IN") || tag.includes("EXT-X-DATERANGE");
3884
- }
3885
- if (raw.id3) return false;
3886
- if (raw.splice_command_type) return false;
3887
- return false;
3888
- }
3889
- },
3890
- {
3891
- key: "parseScte35Binary",
3892
- value: function parseScte35Binary(data) {
3893
- var BitReader = /*#__PURE__*/ function() {
3894
- function BitReader(buf) {
3895
- _class_call_check(this, BitReader);
3896
- this.buf = buf;
3897
- this.bytePos = 0;
3898
- this.bitPos = 0;
3899
- }
3900
- _create_class(BitReader, [
3901
- {
3902
- key: "readBits",
3903
- value: function readBits(numBits) {
3904
- var result = 0;
3905
- while(numBits > 0){
3906
- if (this.bytePos >= this.buf.length) return result;
3907
- var remainingInByte = 8 - this.bitPos;
3908
- var toRead = Math.min(numBits, remainingInByte);
3909
- var currentByte = this.buf[this.bytePos];
3910
- var shift = remainingInByte - toRead;
3911
- var mask = (1 << toRead) - 1 & 255;
3912
- var bits = currentByte >> shift & mask;
3913
- result = result << toRead | bits;
3914
- this.bitPos += toRead;
3915
- if (this.bitPos >= 8) {
3916
- this.bitPos = 0;
3917
- this.bytePos += 1;
3918
- }
3919
- numBits -= toRead;
3920
- }
3921
- return result >>> 0;
3922
- }
3923
- },
3924
- {
3925
- key: "skipBits",
3926
- value: function skipBits(n) {
3927
- this.readBits(n);
3928
- }
3929
- }
3930
- ]);
3931
- return BitReader;
3932
- }();
3933
- var r = new BitReader(data);
3934
- var tableId = r.readBits(8);
3935
- if (tableId !== 252) return void 0;
3936
- r.readBits(1);
3937
- r.readBits(1);
3938
- r.readBits(2);
3939
- var sectionLength = r.readBits(12);
3940
- r.readBits(8);
3941
- r.readBits(1);
3942
- r.readBits(6);
3943
- var ptsAdjHigh = r.readBits(1);
3944
- var ptsAdjLow = r.readBits(32);
3945
- void ptsAdjHigh;
3946
- void ptsAdjLow;
3947
- r.readBits(8);
3948
- r.readBits(12);
3949
- var spliceCommandLength = r.readBits(12);
3950
- var spliceCommandType = r.readBits(8);
3951
- if (spliceCommandType !== 5) {
3952
- return void 0;
3953
- }
3954
- r.readBits(32);
3955
- var cancel = r.readBits(1) === 1;
3956
- r.readBits(7);
3957
- if (cancel) return void 0;
3958
- var outOfNetwork = r.readBits(1) === 1;
3959
- var programSpliceFlag = r.readBits(1) === 1;
3960
- var durationFlag = r.readBits(1) === 1;
3961
- var spliceImmediateFlag = r.readBits(1) === 1;
3962
- r.readBits(4);
3963
- if (programSpliceFlag && !spliceImmediateFlag) {
3964
- var timeSpecifiedFlag = r.readBits(1) === 1;
3965
- if (timeSpecifiedFlag) {
3966
- r.readBits(6);
3967
- r.readBits(33);
3968
- } else {
3969
- r.readBits(7);
3970
- }
3971
- } else if (!programSpliceFlag) {
3972
- var componentCount = r.readBits(8);
3973
- for(var i = 0; i < componentCount; i++){
3974
- r.readBits(8);
3975
- if (!spliceImmediateFlag) {
3976
- var timeSpecifiedFlag1 = r.readBits(1) === 1;
3977
- if (timeSpecifiedFlag1) {
3978
- r.readBits(6);
3979
- r.readBits(33);
3980
- } else {
3981
- r.readBits(7);
3982
- }
3983
- }
3984
- }
3985
- }
3986
- var durationSeconds = void 0;
3987
- if (durationFlag) {
3988
- r.readBits(6);
3989
- r.readBits(1);
3990
- var high = r.readBits(1);
3991
- var low = r.readBits(32);
3992
- var durationTicks = high * 4294967296 + low;
3993
- durationSeconds = durationTicks / 9e4;
3994
- }
3995
- r.readBits(16);
3996
- r.readBits(8);
3997
- r.readBits(8);
3998
- if (outOfNetwork) {
3999
- var marker = _object_spread_props(_object_spread({
4000
- type: "start"
4001
- }, durationSeconds !== void 0 ? {
4002
- durationSeconds: durationSeconds
4003
- } : {}), {
4004
- raw: {
4005
- splice_command_type: 5
4006
- }
4007
- });
4008
- return marker;
4009
- }
4010
- return void 0;
4011
- }
4012
- },
4013
3455
  {
4014
3456
  key: "initializeTracking",
4015
3457
  value: function initializeTracking() {
@@ -4131,35 +3573,35 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4131
3573
  },
4132
3574
  {
4133
3575
  key: "startAdPrefetch",
4134
- value: function startAdPrefetch(marker, fragmentSn) {
3576
+ value: function startAdPrefetch(durationSeconds, fragmentSn) {
4135
3577
  if (this.config.disableAds) return;
4136
3578
  if (this.pendingAdBreak || this.inAdBreak) {
4137
3579
  return;
4138
3580
  }
4139
- this.pendingAdBreak = _object_spread_props(_object_spread({
4140
- marker: marker
4141
- }, fragmentSn !== void 0 ? {
3581
+ this.pendingAdBreak = _object_spread_props(_object_spread({}, durationSeconds !== void 0 ? {
3582
+ durationSeconds: durationSeconds
3583
+ } : {}, fragmentSn !== void 0 ? {
4142
3584
  detectedAtFragmentSn: fragmentSn
4143
3585
  } : {}), {
4144
3586
  isFetching: false,
4145
3587
  fetchStartTime: Date.now()
4146
3588
  });
4147
- void this.runAdPrefetch(marker);
3589
+ void this.runAdPrefetch(durationSeconds);
4148
3590
  if (this.config.debugAdTiming) {
4149
- console.log("[PREFETCH] Ad break marker registered, multi-ad prefetch started");
3591
+ console.log("[PREFETCH] Ad break registered, multi-ad prefetch started");
4150
3592
  }
4151
3593
  }
4152
3594
  },
4153
3595
  {
4154
3596
  key: "runAdPrefetch",
4155
- value: function runAdPrefetch(marker) {
3597
+ value: function runAdPrefetch(durationSeconds) {
4156
3598
  return _async_to_generator(function() {
4157
- var _this, _marker_durationSeconds, _ref, _firstBids_, durSec, context, firstBids, unused, adDurationSec, estimatedCount, firstToken, remaining, results, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, result, token;
3599
+ var _this, _ref, _firstBids_, durSec, context, firstBids, unused, adDurationSec, estimatedCount, firstToken, unused1, remaining, results, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, result, token, unused2, err;
4158
3600
  return _ts_generator(this, function(_state) {
4159
3601
  switch(_state.label){
4160
3602
  case 0:
4161
3603
  _this = this;
4162
- durSec = (_marker_durationSeconds = marker.durationSeconds) !== null && _marker_durationSeconds !== void 0 ? _marker_durationSeconds : 60;
3604
+ durSec = durationSeconds !== null && durationSeconds !== void 0 ? durationSeconds : 60;
4163
3605
  context = {
4164
3606
  breakDurationSec: durSec,
4165
3607
  remainingBreakSec: durSec
@@ -4209,14 +3651,43 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4209
3651
  console.log("[PREFETCH] Ad duration=".concat(adDurationSec, "s, break=").concat(durSec, "s → ").concat(estimatedCount, " ad(s) needed"));
4210
3652
  }
4211
3653
  firstToken = "preload_".concat(Date.now(), "_").concat(Math.random().toString(36).slice(2, 7));
4212
- this.preloadedTokens.push(firstToken);
4213
- void this.adLayer.preloadAd(firstBids, firstToken);
3654
+ _state.label = 5;
3655
+ case 5:
3656
+ _state.trys.push([
3657
+ 5,
3658
+ 7,
3659
+ ,
3660
+ 8
3661
+ ]);
3662
+ return [
3663
+ 4,
3664
+ this.adLayer.preloadAd(firstBids, firstToken)
3665
+ ];
3666
+ case 6:
3667
+ _state.sent();
3668
+ if (!this.inAdBreak) {
3669
+ this.preloadedTokens.push(firstToken);
3670
+ if (this.config.debugAdTiming) {
3671
+ console.log("[PREFETCH] First ad preloaded and queued, token=".concat(firstToken));
3672
+ }
3673
+ }
3674
+ return [
3675
+ 3,
3676
+ 8
3677
+ ];
3678
+ case 7:
3679
+ unused1 = _state.sent();
4214
3680
  if (this.config.debugAdTiming) {
4215
- console.log("[PREFETCH] First ad preloading, token=".concat(firstToken));
3681
+ console.warn("[PREFETCH] First ad preload failed, token=".concat(firstToken));
4216
3682
  }
3683
+ return [
3684
+ 3,
3685
+ 8
3686
+ ];
3687
+ case 8:
4217
3688
  if (!(estimatedCount > 1)) return [
4218
3689
  3,
4219
- 6
3690
+ 19
4220
3691
  ];
4221
3692
  remaining = Array.from({
4222
3693
  length: estimatedCount - 1
@@ -4238,38 +3709,100 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4238
3709
  4,
4239
3710
  Promise.all(remaining)
4240
3711
  ];
4241
- case 5:
3712
+ case 9:
4242
3713
  results = _state.sent();
4243
3714
  _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
3715
+ _state.label = 10;
3716
+ case 10:
3717
+ _state.trys.push([
3718
+ 10,
3719
+ 17,
3720
+ 18,
3721
+ 19
3722
+ ]);
3723
+ _iterator = results[Symbol.iterator]();
3724
+ _state.label = 11;
3725
+ case 11:
3726
+ if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
3727
+ 3,
3728
+ 16
3729
+ ];
3730
+ result = _step.value;
3731
+ if (this.inAdBreak) return [
3732
+ 3,
3733
+ 16
3734
+ ];
3735
+ if (!(result.ok && result.value.length > 0)) return [
3736
+ 3,
3737
+ 15
3738
+ ];
3739
+ token = "preload_".concat(Date.now(), "_").concat(Math.random().toString(36).slice(2, 7));
3740
+ _state.label = 12;
3741
+ case 12:
3742
+ _state.trys.push([
3743
+ 12,
3744
+ 14,
3745
+ ,
3746
+ 15
3747
+ ]);
3748
+ return [
3749
+ 4,
3750
+ this.adLayer.preloadAd(result.value, token)
3751
+ ];
3752
+ case 13:
3753
+ _state.sent();
3754
+ if (!this.inAdBreak) {
3755
+ this.preloadedTokens.push(token);
3756
+ if (this.config.debugAdTiming) {
3757
+ console.log("[PREFETCH] Additional ad preloaded and queued, token=".concat(token));
3758
+ }
3759
+ }
3760
+ return [
3761
+ 3,
3762
+ 15
3763
+ ];
3764
+ case 14:
3765
+ unused2 = _state.sent();
3766
+ if (this.config.debugAdTiming) {
3767
+ console.warn("[PREFETCH] Additional ad preload failed, token=".concat(token));
3768
+ }
3769
+ return [
3770
+ 3,
3771
+ 15
3772
+ ];
3773
+ case 15:
3774
+ _iteratorNormalCompletion = true;
3775
+ return [
3776
+ 3,
3777
+ 11
3778
+ ];
3779
+ case 16:
3780
+ return [
3781
+ 3,
3782
+ 19
3783
+ ];
3784
+ case 17:
3785
+ err = _state.sent();
3786
+ _didIteratorError = true;
3787
+ _iteratorError = err;
3788
+ return [
3789
+ 3,
3790
+ 19
3791
+ ];
3792
+ case 18:
4244
3793
  try {
4245
- for(_iterator = results[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
4246
- result = _step.value;
4247
- if (this.inAdBreak) break;
4248
- if (result.ok && result.value.length > 0) {
4249
- token = "preload_".concat(Date.now(), "_").concat(Math.random().toString(36).slice(2, 7));
4250
- this.preloadedTokens.push(token);
4251
- void this.adLayer.preloadAd(result.value, token);
4252
- if (this.config.debugAdTiming) {
4253
- console.log("[PREFETCH] Additional ad preloading, token=".concat(token));
4254
- }
4255
- }
3794
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
3795
+ _iterator.return();
4256
3796
  }
4257
- } catch (err) {
4258
- _didIteratorError = true;
4259
- _iteratorError = err;
4260
3797
  } finally{
4261
- try {
4262
- if (!_iteratorNormalCompletion && _iterator.return != null) {
4263
- _iterator.return();
4264
- }
4265
- } finally{
4266
- if (_didIteratorError) {
4267
- throw _iteratorError;
4268
- }
3798
+ if (_didIteratorError) {
3799
+ throw _iteratorError;
4269
3800
  }
4270
3801
  }
4271
- _state.label = 6;
4272
- case 6:
3802
+ return [
3803
+ 7
3804
+ ];
3805
+ case 19:
4273
3806
  if (this.config.debugAdTiming) {
4274
3807
  console.log("[PREFETCH] Pre-fetch complete: ".concat(this.preloadedTokens.length, " ad(s) queued"));
4275
3808
  }
@@ -4434,15 +3967,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4434
3967
  if (this.config.debugAdTiming) {
4435
3968
  console.log('[StormcloudVideoPlayer] Ad insertion segment "'.concat(segmentName, '" found in manifest — starting pre-fetch'));
4436
3969
  }
4437
- var marker = {
4438
- type: "start",
4439
- durationSeconds: 60,
4440
- raw: {
4441
- apiInsertionPoint: this.lastAdInsertionPoint,
4442
- earlyDetection: true
4443
- }
4444
- };
4445
- this.startAdPrefetch(marker, frag === null || frag === void 0 ? void 0 : frag.sn);
3970
+ this.startAdPrefetch(60, frag === null || frag === void 0 ? void 0 : frag.sn);
4446
3971
  return;
4447
3972
  }
4448
3973
  }
@@ -4480,8 +4005,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4480
4005
  {
4481
4006
  key: "fragmentMatchesSegment",
4482
4007
  value: function fragmentMatchesSegment(frag, segmentName) {
4483
- var url = (frag === null || frag === void 0 ? void 0 : frag.url) || (frag === null || frag === void 0 ? void 0 : frag.relurl) || "";
4484
- return url.endsWith(segmentName) || url.includes("/" + segmentName);
4008
+ var _rawUrl_split_;
4009
+ var rawUrl = (frag === null || frag === void 0 ? void 0 : frag.url) || (frag === null || frag === void 0 ? void 0 : frag.relurl) || "";
4010
+ var url = (_rawUrl_split_ = rawUrl.split("?")[0]) !== null && _rawUrl_split_ !== void 0 ? _rawUrl_split_ : "";
4011
+ var name = segmentName.startsWith("/") ? segmentName : "/" + segmentName;
4012
+ return url.endsWith(name) || url.includes(name);
4485
4013
  }
4486
4014
  },
4487
4015
  {
@@ -4818,13 +4346,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4818
4346
  },
4819
4347
  {
4820
4348
  key: "handleAdStart",
4821
- value: function handleAdStart(_marker) {
4349
+ value: function handleAdStart(durationSeconds) {
4822
4350
  return _async_to_generator(function() {
4823
- var _this_savedMutedStateBeforeScte, adBreakDurationMs, mode, state, adBreakToken, adVolume, token, remaining, err;
4351
+ var _this_savedMutedStateBeforeAd, adBreakDurationMs, mode, state, adBreakToken, adVolume, token, remaining, err;
4824
4352
  return _ts_generator(this, function(_state) {
4825
4353
  switch(_state.label){
4826
4354
  case 0:
4827
- adBreakDurationMs = _marker.durationSeconds != null ? _marker.durationSeconds * 1e3 : void 0;
4355
+ adBreakDurationMs = durationSeconds != null ? durationSeconds * 1e3 : void 0;
4828
4356
  if (this.config.debugAdTiming) {
4829
4357
  mode = this.isLiveStream ? "LIVE" : "VOD";
4830
4358
  console.log("[CONTINUOUS-FETCH] \uD83D\uDCFA ".concat(mode, " MODE: Target duration=").concat(adBreakDurationMs, "ms"));
@@ -4835,13 +4363,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4835
4363
  this.pendingNextAdBids = null;
4836
4364
  this.isShowingPlaceholder = false;
4837
4365
  this.totalAdRequestsInBreak = 0;
4838
- if (this.savedMutedStateBeforeScte == null && !this.video.muted) {
4839
- this.savedMutedStateBeforeScte = {
4366
+ if (this.savedMutedStateBeforeAd == null && !this.video.muted) {
4367
+ this.savedMutedStateBeforeAd = {
4840
4368
  muted: false,
4841
4369
  volume: this.video.volume
4842
4370
  };
4843
4371
  }
4844
- state = (_this_savedMutedStateBeforeScte = this.savedMutedStateBeforeScte) !== null && _this_savedMutedStateBeforeScte !== void 0 ? _this_savedMutedStateBeforeScte : {
4372
+ state = (_this_savedMutedStateBeforeAd = this.savedMutedStateBeforeAd) !== null && _this_savedMutedStateBeforeAd !== void 0 ? _this_savedMutedStateBeforeAd : {
4845
4373
  muted: this.video.muted,
4846
4374
  volume: this.video.volume
4847
4375
  };
@@ -4868,6 +4396,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4868
4396
  if (this.expectedAdBreakDurationMs == null && adBreakDurationMs != null) {
4869
4397
  this.expectedAdBreakDurationMs = adBreakDurationMs;
4870
4398
  }
4399
+ if (this.expectedAdBreakDurationMs != null) {
4400
+ this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
4401
+ }
4871
4402
  this.clearPendingAdBreak();
4872
4403
  adBreakToken = Date.now();
4873
4404
  this.activeAdRequestToken = adBreakToken;
@@ -5366,49 +4897,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5366
4897
  this.handleAdPodComplete();
5367
4898
  }
5368
4899
  },
5369
- {
5370
- key: "scheduleAdStartIn",
5371
- value: function scheduleAdStartIn(delayMs) {
5372
- var _this = this;
5373
- this.clearAdStartTimer();
5374
- var ms = Math.max(0, Math.floor(delayMs));
5375
- if (ms === 0) {
5376
- this.handleAdStart({
5377
- type: "start"
5378
- }).catch(function() {});
5379
- return;
5380
- }
5381
- this.adStartTimerId = window.setTimeout(function() {
5382
- _this.handleAdStart({
5383
- type: "start"
5384
- }).catch(function() {});
5385
- }, ms);
5386
- }
5387
- },
5388
- {
5389
- key: "clearAdStartTimer",
5390
- value: function clearAdStartTimer() {
5391
- if (this.adStartTimerId != null) {
5392
- clearTimeout(this.adStartTimerId);
5393
- this.adStartTimerId = void 0;
5394
- }
5395
- }
5396
- },
5397
- {
5398
- key: "updatePtsDrift",
5399
- value: function updatePtsDrift(ptsSecondsSample) {
5400
- var sampleMs = (this.video.currentTime - ptsSecondsSample) * 1e3;
5401
- if (!Number.isFinite(sampleMs) || Math.abs(sampleMs) > 6e4) return;
5402
- var alpha = 0.1;
5403
- this.ptsDriftEmaMs = this.ptsDriftEmaMs * (1 - alpha) + sampleMs * alpha;
5404
- }
5405
- },
5406
4900
  {
5407
4901
  key: "handleAdPodComplete",
5408
4902
  value: function handleAdPodComplete() {
5409
4903
  var _this = this;
5410
4904
  var _ref, _ref1;
5411
- var _this_savedMutedStateBeforeScte, _this_savedMutedStateBeforeScte1;
4905
+ var _this_savedMutedStateBeforeAd, _this_savedMutedStateBeforeAd1;
5412
4906
  if (this.config.debugAdTiming) {
5413
4907
  console.log("[StormcloudVideoPlayer] \uD83C\uDFC1 Ad pod complete - cleaning up");
5414
4908
  }
@@ -5430,7 +4924,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5430
4924
  this.inAdBreak = false;
5431
4925
  this.expectedAdBreakDurationMs = void 0;
5432
4926
  this.currentAdBreakStartWallClockMs = void 0;
5433
- this.clearAdStartTimer();
5434
4927
  this.clearAdStopTimer();
5435
4928
  this.adPodQueue = [];
5436
4929
  this.showAds = false;
@@ -5438,8 +4931,8 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5438
4931
  this.totalAdsInBreak = 0;
5439
4932
  this.totalAdRequestsInBreak = 0;
5440
4933
  this.consecutiveFailures = 0;
5441
- 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();
5442
- 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();
4934
+ 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();
4935
+ 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();
5443
4936
  this.adLayer.updateOriginalMutedState(restoredMuted, restoredVolume);
5444
4937
  this.adLayer.stop().catch(function() {});
5445
4938
  if (this.video.muted !== restoredMuted) {
@@ -5548,7 +5041,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5548
5041
  }, delay);
5549
5042
  });
5550
5043
  }
5551
- this.savedMutedStateBeforeScte = null;
5044
+ this.savedMutedStateBeforeAd = null;
5552
5045
  }
5553
5046
  },
5554
5047
  {
@@ -5698,19 +5191,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5698
5191
  return Math.max(0, this.expectedAdBreakDurationMs - elapsed);
5699
5192
  }
5700
5193
  },
5701
- {
5702
- key: "pushScteMarker",
5703
- value: function pushScteMarker(marker) {
5704
- if (!this.config.debugAdTiming) return;
5705
- this.scteMarkerHistory.push({
5706
- timestampMs: Date.now(),
5707
- marker: marker
5708
- });
5709
- if (this.scteMarkerHistory.length > DEBUG_HISTORY_LIMIT) {
5710
- this.scteMarkerHistory = this.scteMarkerHistory.slice(-DEBUG_HISTORY_LIMIT);
5711
- }
5712
- }
5713
- },
5714
5194
  {
5715
5195
  key: "pushDebugLog",
5716
5196
  value: function pushDebugLog(level, category, message, details) {
@@ -5728,23 +5208,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
5728
5208
  }
5729
5209
  }
5730
5210
  },
5731
- {
5732
- key: "getRecentScteMarkers",
5733
- value: function getRecentScteMarkers() {
5734
- return this.scteMarkerHistory.map(function(entry) {
5735
- return _object_spread({
5736
- timestampMs: entry.timestampMs,
5737
- type: entry.marker.type
5738
- }, entry.marker.ptsSeconds !== void 0 ? {
5739
- ptsSeconds: entry.marker.ptsSeconds
5740
- } : {}, entry.marker.durationSeconds !== void 0 ? {
5741
- durationSeconds: entry.marker.durationSeconds
5742
- } : {}, entry.marker.raw !== void 0 ? {
5743
- raw: entry.marker.raw
5744
- } : {});
5745
- });
5746
- }
5747
- },
5748
5211
  {
5749
5212
  key: "pushAdInsertionDebug",
5750
5213
  value: function pushAdInsertionDebug(event, segmentName, opts) {
@@ -6041,7 +5504,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6041
5504
  this.clearAdInsertionOffsetTimer();
6042
5505
  this.stopContinuousFetching();
6043
5506
  this.stopFillerBreakTimer();
6044
- this.clearAdStartTimer();
6045
5507
  this.clearAdStopTimer();
6046
5508
  this.clearAdFailsafeTimer();
6047
5509
  this.clearAdRequestWatchdog();
@@ -6069,7 +5531,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6069
5531
  (_this_adLayer = this.adLayer) === null || _this_adLayer === void 0 ? void 0 : _this_adLayer.destroy();
6070
5532
  this.consecutiveFailures = 0;
6071
5533
  this.debugLogEntries = [];
6072
- this.scteMarkerHistory = [];
6073
5534
  this.adInsertionDebugHistory = [];
6074
5535
  }
6075
5536
  }
@@ -6077,7 +5538,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6077
5538
  return StormcloudVideoPlayer;
6078
5539
  }();
6079
5540
  // src/ui/StormcloudVideoPlayer.tsx
6080
- import { FaPlay, FaPause, FaVolumeUp, FaVolumeMute, FaVolumeDown, FaExpand, FaCompress, FaCog, FaTimes } from "react-icons/fa";
5541
+ import { FaPlay, FaPause, FaVolumeUp, FaVolumeMute, FaVolumeDown, FaExpand, FaCompress, FaCog, FaTimes, FaCopy } from "react-icons/fa";
6081
5542
  // src/ui/OverlayRenderer.tsx
6082
5543
  import React, { useEffect, useRef, useState, useCallback, useMemo } from "react";
6083
5544
  // src/utils/overlays.ts
@@ -7546,6 +7007,11 @@ var StormcloudVideoPlayerComponent = React2.memo(function(props) {
7546
7007
  label: "API",
7547
7008
  color: "#60a5fa"
7548
7009
  };
7010
+ case "scte35_inserted":
7011
+ return {
7012
+ label: "SCTE-35",
7013
+ color: "#f43f5e"
7014
+ };
7549
7015
  case "segment_found":
7550
7016
  return {
7551
7017
  label: "FOUND",
@@ -7716,6 +7182,7 @@ var StormcloudVideoPlayerComponent = React2.memo(function(props) {
7716
7182
  if (minSegmentsBeforePlay !== void 0) cfg.minSegmentsBeforePlay = minSegmentsBeforePlay;
7717
7183
  if (disableAds !== void 0) cfg.disableAds = disableAds;
7718
7184
  cfg.disableFiller = disableFiller !== null && disableFiller !== void 0 ? disableFiller : true;
7185
+ if (swirlProjectId !== void 0) cfg.projectId = String(swirlProjectId);
7719
7186
  var player = new StormcloudVideoPlayer(cfg);
7720
7187
  playerRef.current = player;
7721
7188
  player.load().then(function() {
@@ -8589,9 +8056,13 @@ var StormcloudVideoPlayerComponent = React2.memo(function(props) {
8589
8056
  overflowX: "hidden",
8590
8057
  height: "calc(100% - 46px)",
8591
8058
  display: "grid",
8592
- gap: "12px"
8059
+ gap: "12px",
8060
+ minWidth: 0
8593
8061
  },
8594
8062
  children: /* @__PURE__ */ jsxs2("div", {
8063
+ style: {
8064
+ minWidth: 0
8065
+ },
8595
8066
  children: [
8596
8067
  /* @__PURE__ */ jsx2("div", {
8597
8068
  style: {
@@ -8607,7 +8078,8 @@ var StormcloudVideoPlayerComponent = React2.memo(function(props) {
8607
8078
  /* @__PURE__ */ jsx2("div", {
8608
8079
  style: {
8609
8080
  display: "grid",
8610
- gap: "6px"
8081
+ gap: "6px",
8082
+ minWidth: 0
8611
8083
  },
8612
8084
  children: debugMarkers.length === 0 ? /* @__PURE__ */ jsx2("div", {
8613
8085
  style: {
@@ -8617,53 +8089,129 @@ var StormcloudVideoPlayerComponent = React2.memo(function(props) {
8617
8089
  children: "No ad insertion events yet."
8618
8090
  }) : debugMarkers.map(function(entry, idx) {
8619
8091
  var evt = formatAdInsertionEvent(entry.event);
8092
+ var fileName = entry.segmentName ? entry.segmentName.split("/").pop() || entry.segmentName : "";
8620
8093
  return /* @__PURE__ */ jsxs2("div", {
8621
8094
  style: {
8622
- display: "grid",
8623
- gridTemplateColumns: "56px 54px 1fr",
8624
- gap: "8px",
8625
- alignItems: "center",
8095
+ minWidth: 0,
8626
8096
  fontFamily: "'SF Mono', 'Cascadia Code', monospace",
8627
8097
  fontSize: "11px",
8628
8098
  background: "rgba(255,255,255,0.05)",
8629
8099
  border: "1px solid rgba(255,255,255,0.08)",
8630
8100
  borderRadius: "8px",
8631
- padding: "6px 8px"
8101
+ padding: "6px 8px",
8102
+ display: "flex",
8103
+ flexDirection: "column",
8104
+ gap: "4px"
8632
8105
  },
8633
8106
  children: [
8634
- /* @__PURE__ */ jsx2("span", {
8107
+ /* @__PURE__ */ jsxs2("div", {
8635
8108
  style: {
8636
- color: "rgba(255,255,255,0.68)"
8109
+ display: "grid",
8110
+ gridTemplateColumns: "56px 54px minmax(0, 1fr) 20px",
8111
+ gap: "6px",
8112
+ alignItems: "center",
8113
+ minWidth: 0
8637
8114
  },
8638
- children: formatDebugClock(entry.timestampMs)
8115
+ children: [
8116
+ /* @__PURE__ */ jsx2("span", {
8117
+ style: {
8118
+ color: "rgba(255,255,255,0.68)"
8119
+ },
8120
+ children: formatDebugClock(entry.timestampMs)
8121
+ }),
8122
+ /* @__PURE__ */ jsx2("span", {
8123
+ style: {
8124
+ fontWeight: 700,
8125
+ color: evt.color,
8126
+ fontSize: "10px"
8127
+ },
8128
+ children: evt.label
8129
+ }),
8130
+ /* @__PURE__ */ jsx2("span", {
8131
+ style: {
8132
+ color: "rgba(255,255,255,0.88)",
8133
+ overflow: "hidden",
8134
+ textOverflow: "ellipsis",
8135
+ whiteSpace: "nowrap",
8136
+ minWidth: 0
8137
+ },
8138
+ title: entry.segmentName,
8139
+ children: fileName
8140
+ }),
8141
+ /* @__PURE__ */ jsx2("button", {
8142
+ onClick: function onClick() {
8143
+ return navigator.clipboard.writeText(entry.segmentName);
8144
+ },
8145
+ title: entry.segmentName,
8146
+ style: {
8147
+ background: "none",
8148
+ border: "none",
8149
+ cursor: "pointer",
8150
+ padding: "2px",
8151
+ color: "rgba(255,255,255,0.45)",
8152
+ display: "flex",
8153
+ alignItems: "center",
8154
+ justifyContent: "center",
8155
+ borderRadius: "4px",
8156
+ flexShrink: 0
8157
+ },
8158
+ onMouseEnter: function onMouseEnter(e) {
8159
+ return e.currentTarget.style.color = "rgba(255,255,255,0.9)";
8160
+ },
8161
+ onMouseLeave: function onMouseLeave(e) {
8162
+ return e.currentTarget.style.color = "rgba(255,255,255,0.45)";
8163
+ },
8164
+ children: /* @__PURE__ */ jsx2(FaCopy, {
8165
+ size: 10
8166
+ })
8167
+ })
8168
+ ]
8639
8169
  }),
8640
- /* @__PURE__ */ jsx2("span", {
8170
+ (entry.offsetSeconds != null || entry.detail || entry.updatedAt) && /* @__PURE__ */ jsxs2("div", {
8641
8171
  style: {
8642
- fontWeight: 700,
8643
- color: evt.color,
8172
+ display: "flex",
8173
+ flexWrap: "wrap",
8174
+ gap: "6px",
8175
+ paddingLeft: "0px",
8644
8176
  fontSize: "10px"
8645
8177
  },
8646
- children: evt.label
8647
- }),
8648
- /* @__PURE__ */ jsx2("span", {
8649
- style: {
8650
- color: "rgba(255,255,255,0.88)"
8651
- },
8652
- children: /* @__PURE__ */ jsxs2("span", {
8653
- style: {
8654
- display: "inline-block",
8655
- maxWidth: "100%",
8656
- verticalAlign: "bottom",
8657
- overflow: "hidden",
8658
- textOverflow: "ellipsis",
8659
- whiteSpace: "nowrap"
8660
- },
8661
- children: [
8662
- entry.segmentName,
8663
- entry.offsetSeconds != null ? " +".concat(entry.offsetSeconds, "s") : "",
8664
- entry.detail ? " (".concat(entry.detail, ")") : ""
8665
- ]
8666
- })
8178
+ children: [
8179
+ entry.offsetSeconds != null && /* @__PURE__ */ jsxs2("span", {
8180
+ style: {
8181
+ color: "rgba(255,255,255,0.55)",
8182
+ background: "rgba(255,255,255,0.06)",
8183
+ borderRadius: "4px",
8184
+ padding: "1px 5px"
8185
+ },
8186
+ children: [
8187
+ "+",
8188
+ entry.offsetSeconds.toFixed(2),
8189
+ "s"
8190
+ ]
8191
+ }),
8192
+ entry.detail && /* @__PURE__ */ jsx2("span", {
8193
+ style: {
8194
+ color: "rgba(255,255,255,0.55)",
8195
+ background: "rgba(255,255,255,0.06)",
8196
+ borderRadius: "4px",
8197
+ padding: "1px 5px",
8198
+ overflow: "hidden",
8199
+ textOverflow: "ellipsis",
8200
+ whiteSpace: "nowrap",
8201
+ maxWidth: "100%"
8202
+ },
8203
+ children: entry.detail
8204
+ }),
8205
+ entry.updatedAt && /* @__PURE__ */ jsx2("span", {
8206
+ style: {
8207
+ color: "rgba(255,255,255,0.38)",
8208
+ background: "rgba(255,255,255,0.04)",
8209
+ borderRadius: "4px",
8210
+ padding: "1px 5px"
8211
+ },
8212
+ children: formatAiRelativeTime(entry.updatedAt)
8213
+ })
8214
+ ]
8667
8215
  })
8668
8216
  ]
8669
8217
  }, "".concat(entry.timestampMs, "-").concat(idx));