stormcloud-video-player 0.8.14 → 0.8.16

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.
@@ -9,6 +9,7 @@ declare class StormcloudVideoPlayer {
9
9
  private inAdBreak;
10
10
  private currentAdBreakStartWallClockMs;
11
11
  private expectedAdBreakDurationMs;
12
+ private scteAdBreakEndWallClockMs;
12
13
  private adStopTimerId;
13
14
  private adStartTimerId;
14
15
  private adFailsafeTimerId;
@@ -115,6 +116,9 @@ declare class StormcloudVideoPlayer {
115
116
  private activatePendingScte35CuesForFragment;
116
117
  private onScte35Marker;
117
118
  private startScte35AdBreak;
119
+ private resolveScteBreakStartWallClockMs;
120
+ private setAdBreakDurationBoundary;
121
+ private scheduleAdStopAtBreakBoundary;
118
122
  private parseCueOutDuration;
119
123
  private parseCueOutCont;
120
124
  private parseAttributeList;
@@ -198,6 +202,7 @@ declare class StormcloudVideoPlayer {
198
202
  private selectVastTagsForBreak;
199
203
  private logAdState;
200
204
  private getWallClockRemainingAdMs;
205
+ private getAdBreakEndWallClockMs;
201
206
  private getDurationBudgetRemainingMs;
202
207
  private getLoadedAdDurationMs;
203
208
  private adFitsRemainingBudget;
@@ -2709,6 +2709,7 @@ function logBrowserInfo() {
2709
2709
  // src/utils/ctvVastSignals.ts
2710
2710
  var AIRY_ANDROID_APP_ID = "com.freeairytv.android";
2711
2711
  var AIRY_APP_NAME = "AiryTV Movies & TV";
2712
+ var AIRY_DEFAULT_CONTENT_URL = "https://live.airy.tv";
2712
2713
  var CTV_SESSION_STORAGE_KEY = "stormcloud.ctv.sid";
2713
2714
  var DEVICE_ID_STORAGE_KEYS = [
2714
2715
  "rdid",
@@ -2726,8 +2727,9 @@ function resolveCtvVastSignals() {
2726
2727
  var bridgeSignals = readNativeBridgeSignals();
2727
2728
  var deviceId = bridgeSignals.deviceId || readStoredDeviceId();
2728
2729
  var deviceIdType = bridgeSignals.deviceIdType || readStoredString("deviceIdType") || inferDeviceIdType();
2730
+ var contentUrl = bridgeSignals.contentUrl || readStoredString("contentUrl") || AIRY_DEFAULT_CONTENT_URL;
2729
2731
  return _object_spread_props(_object_spread({
2730
- contentUrl: "https://".concat(AIRY_ANDROID_APP_ID, ".example.com"),
2732
+ contentUrl: contentUrl,
2731
2733
  appId: AIRY_ANDROID_APP_ID,
2732
2734
  appName: AIRY_APP_NAME,
2733
2735
  sessionId: getOrCreateCtvSessionId()
@@ -2778,6 +2780,12 @@ function readNativeBridgeSignals() {
2778
2780
  try {
2779
2781
  for(var _iterator = candidates[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2780
2782
  var source = _step.value;
2783
+ var contentUrl = readBridgeValue(source, [
2784
+ "contentUrl",
2785
+ "url",
2786
+ "videoUrl",
2787
+ "canonicalUrl"
2788
+ ]) || void 0;
2781
2789
  var deviceId = readBridgeValue(source, [
2782
2790
  "rdid",
2783
2791
  "ifa",
@@ -2785,7 +2793,7 @@ function readNativeBridgeSignals() {
2785
2793
  "adId",
2786
2794
  "deviceId"
2787
2795
  ]) || void 0;
2788
- if (!deviceId) continue;
2796
+ if (!contentUrl && !deviceId) continue;
2789
2797
  var deviceIdType = readBridgeValue(source, [
2790
2798
  "idtype",
2791
2799
  "deviceIdType",
@@ -2797,11 +2805,13 @@ function readNativeBridgeSignals() {
2797
2805
  "limitedAdTracking",
2798
2806
  "lat"
2799
2807
  ]);
2800
- return _object_spread({
2808
+ return _object_spread({}, contentUrl ? {
2809
+ contentUrl: contentUrl
2810
+ } : {}, deviceId ? {
2801
2811
  deviceId: deviceId
2802
- }, deviceIdType ? {
2812
+ } : {}, deviceId && deviceIdType ? {
2803
2813
  deviceIdType: deviceIdType
2804
- } : {}, limitAdTracking != null ? {
2814
+ } : {}, deviceId && limitAdTracking != null ? {
2805
2815
  limitAdTracking: limitAdTracking
2806
2816
  } : {});
2807
2817
  }
@@ -3561,7 +3571,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3561
3571
  _this.showAds = true;
3562
3572
  _this.resetGamNoFillCounter();
3563
3573
  if (_this.inAdBreak && _this.expectedAdBreakDurationMs != null && _this.adStopTimerId == null) {
3564
- _this.scheduleAdStopCountdown(_this.getRemainingAdMs());
3574
+ _this.scheduleAdStopAtBreakBoundary();
3565
3575
  if (_this.config.debugAdTiming) {
3566
3576
  console.log("[StormcloudVideoPlayer] Starting ad break timer on content_pause (first ad starting)");
3567
3577
  }
@@ -4216,12 +4226,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4216
4226
  if (marker.durationSeconds != null) {
4217
4227
  var newDurationMs = marker.durationSeconds * 1e3;
4218
4228
  if (this.expectedAdBreakDurationMs == null || newDurationMs > this.expectedAdBreakDurationMs) {
4219
- this.expectedAdBreakDurationMs = newDurationMs;
4220
- var elapsedMs = this.currentAdBreakStartWallClockMs != null ? Date.now() - this.currentAdBreakStartWallClockMs : 0;
4221
- var remainingMs = Math.max(0, newDurationMs - elapsedMs);
4222
- this.scheduleAdStopCountdown(remainingMs);
4229
+ this.setAdBreakDurationBoundary(newDurationMs);
4230
+ this.scheduleAdStopAtBreakBoundary();
4223
4231
  if (this.config.debugAdTiming) {
4224
- console.log("[StormcloudVideoPlayer] Updated ad break duration from subsequent marker: ".concat(newDurationMs, "ms, remaining: ").concat(remainingMs, "ms"));
4232
+ console.log("[StormcloudVideoPlayer] Updated ad break duration from subsequent marker: ".concat(newDurationMs, "ms, remaining: ").concat(this.getWallClockRemainingAdMs(), "ms"));
4225
4233
  }
4226
4234
  }
4227
4235
  }
@@ -4295,13 +4303,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4295
4303
  }
4296
4304
  if (marker.type === "progress" && this.inAdBreak) {
4297
4305
  if (marker.durationSeconds != null) {
4298
- this.expectedAdBreakDurationMs = marker.durationSeconds * 1e3;
4299
- }
4300
- if (this.expectedAdBreakDurationMs != null && this.currentAdBreakStartWallClockMs != null) {
4301
- var elapsedMs1 = Date.now() - this.currentAdBreakStartWallClockMs;
4302
- var remainingMs1 = Math.max(0, this.expectedAdBreakDurationMs - elapsedMs1);
4303
- this.scheduleAdStopCountdown(remainingMs1);
4306
+ this.setAdBreakDurationBoundary(marker.durationSeconds * 1e3);
4304
4307
  }
4308
+ this.scheduleAdStopAtBreakBoundary();
4305
4309
  if (!this.adPlayer.isAdPlaying() && this.activeAdRequestToken === null && this.adRequestQueue.length > 0 && this.hasTimeToStartAnotherAd()) {
4306
4310
  this.tryNextAvailableAdWithRateLimit();
4307
4311
  }
@@ -4325,15 +4329,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4325
4329
  activeAdRequest: this.activeAdRequestToken !== null
4326
4330
  });
4327
4331
  }
4328
- if (adPlaying || remaining > 1e3 && hasQueuedAds) {
4329
- if (this.config.debugAdTiming) {
4330
- console.log("[StormcloudVideoPlayer] Ignoring premature SCTE-35 end marker - ads still active");
4331
- }
4332
- return;
4333
- }
4334
- this.inAdBreak = false;
4335
- this.expectedAdBreakDurationMs = void 0;
4336
- this.currentAdBreakStartWallClockMs = void 0;
4332
+ this.scteAdBreakEndWallClockMs = Date.now();
4337
4333
  this.clearAdStartTimer();
4338
4334
  this.clearAdStopTimer();
4339
4335
  if (adPlaying) {
@@ -4350,12 +4346,46 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4350
4346
  this.inAdBreak = true;
4351
4347
  this.activeScte35BreakKey = cueKey !== null && cueKey !== void 0 ? cueKey : this.pendingScte35CueKey;
4352
4348
  this.scheduledScte35BreakKey = void 0;
4353
- this.expectedAdBreakDurationMs = durationMs;
4354
- this.currentAdBreakStartWallClockMs = Date.now();
4349
+ this.currentAdBreakStartWallClockMs = this.resolveScteBreakStartWallClockMs(marker);
4350
+ this.setAdBreakDurationBoundary(durationMs);
4355
4351
  this.handleAdStart(marker);
4356
- if (this.expectedAdBreakDurationMs != null) {
4357
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
4352
+ this.scheduleAdStopAtBreakBoundary();
4353
+ }
4354
+ },
4355
+ {
4356
+ key: "resolveScteBreakStartWallClockMs",
4357
+ value: function resolveScteBreakStartWallClockMs(marker) {
4358
+ var nowWallClockMs = Date.now();
4359
+ if (typeof marker.ptsSeconds !== "number") {
4360
+ return nowWallClockMs;
4361
+ }
4362
+ var nowMs = this.video.currentTime * 1e3;
4363
+ var estimatedCurrentPtsMs = nowMs - this.ptsDriftEmaMs;
4364
+ var deltaMs = marker.ptsSeconds * 1e3 - estimatedCurrentPtsMs;
4365
+ if (!Number.isFinite(deltaMs)) {
4366
+ return nowWallClockMs;
4367
+ }
4368
+ return nowWallClockMs + Math.floor(deltaMs);
4369
+ }
4370
+ },
4371
+ {
4372
+ key: "setAdBreakDurationBoundary",
4373
+ value: function setAdBreakDurationBoundary(durationMs) {
4374
+ this.expectedAdBreakDurationMs = durationMs;
4375
+ if (durationMs != null && this.currentAdBreakStartWallClockMs != null) {
4376
+ this.scteAdBreakEndWallClockMs = this.currentAdBreakStartWallClockMs + durationMs;
4377
+ } else {
4378
+ this.scteAdBreakEndWallClockMs = void 0;
4379
+ }
4380
+ }
4381
+ },
4382
+ {
4383
+ key: "scheduleAdStopAtBreakBoundary",
4384
+ value: function scheduleAdStopAtBreakBoundary() {
4385
+ if (this.expectedAdBreakDurationMs == null) {
4386
+ return;
4358
4387
  }
4388
+ this.scheduleAdStopCountdown(this.getWallClockRemainingAdMs());
4359
4389
  }
4360
4390
  },
4361
4391
  {
@@ -6005,7 +6035,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6005
6035
  currentVolume = this.video.volume;
6006
6036
  this.adPlayer.updateOriginalMutedState(currentMuted, currentVolume);
6007
6037
  this.inAdBreak = true;
6008
- this.currentAdBreakStartWallClockMs = Date.now();
6009
6038
  this.adBreakPlayedDurationMs = 0;
6010
6039
  this.currentAdIndex = 0;
6011
6040
  this.totalAdsInBreak = 0;
@@ -6111,7 +6140,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6111
6140
  _state.sent();
6112
6141
  this.markAdStarted();
6113
6142
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6114
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
6143
+ this.scheduleAdStopAtBreakBoundary();
6115
6144
  }
6116
6145
  adVolume = currentMuted ? 0 : currentVolume;
6117
6146
  this.adPlayer.setAdVolume(adVolume);
@@ -6171,7 +6200,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6171
6200
  _state.sent();
6172
6201
  this.markAdStarted();
6173
6202
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6174
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
6203
+ this.scheduleAdStopAtBreakBoundary();
6175
6204
  }
6176
6205
  adVolume1 = currentMuted ? 0 : currentVolume;
6177
6206
  this.adPlayer.setAdVolume(adVolume1);
@@ -6244,7 +6273,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6244
6273
  _state.sent();
6245
6274
  this.markAdStarted();
6246
6275
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6247
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
6276
+ this.scheduleAdStopAtBreakBoundary();
6248
6277
  }
6249
6278
  adVolume2 = currentMuted ? 0 : currentVolume;
6250
6279
  this.adPlayer.setAdVolume(adVolume2);
@@ -6627,7 +6656,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6627
6656
  _state.sent();
6628
6657
  this.markAdStarted();
6629
6658
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6630
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
6659
+ this.scheduleAdStopAtBreakBoundary();
6631
6660
  }
6632
6661
  this.adPlayer.setAdVolume(this.getAdAudioVolume());
6633
6662
  this.consecutiveFailures = 0;
@@ -7155,19 +7184,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7155
7184
  {
7156
7185
  key: "ensureAdStoppedByTimer",
7157
7186
  value: function ensureAdStoppedByTimer() {
7158
- var _this_config_adBreakCheckIntervalMs, _this_expectedAdBreakDurationMs;
7187
+ var _this_config_adBreakCheckIntervalMs, _this_getAdBreakEndWallClockMs;
7159
7188
  if (!this.inAdBreak) return;
7160
7189
  this.adStopTimerId = void 0;
7161
7190
  var adPlaying = this.adPlayer.isAdPlaying();
7162
7191
  var checkIntervalMs = Math.max(250, Math.floor((_this_config_adBreakCheckIntervalMs = this.config.adBreakCheckIntervalMs) !== null && _this_config_adBreakCheckIntervalMs !== void 0 ? _this_config_adBreakCheckIntervalMs : 1e3));
7163
7192
  var maxExtensionMsConfig = this.config.maxAdBreakExtensionMs;
7164
7193
  var maxExtensionMs = typeof maxExtensionMsConfig === "number" && maxExtensionMsConfig > 0 ? maxExtensionMsConfig : 0;
7165
- var elapsedSinceStartMs = 0;
7166
- if (this.currentAdBreakStartWallClockMs != null) {
7167
- elapsedSinceStartMs = Date.now() - this.currentAdBreakStartWallClockMs;
7168
- }
7169
- var expectedDurationMs = (_this_expectedAdBreakDurationMs = this.expectedAdBreakDurationMs) !== null && _this_expectedAdBreakDurationMs !== void 0 ? _this_expectedAdBreakDurationMs : 0;
7170
- var overrunMs = Math.max(0, elapsedSinceStartMs - expectedDurationMs);
7194
+ var endWallClockMs = (_this_getAdBreakEndWallClockMs = this.getAdBreakEndWallClockMs()) !== null && _this_getAdBreakEndWallClockMs !== void 0 ? _this_getAdBreakEndWallClockMs : Date.now();
7195
+ var overrunMs = Math.max(0, Date.now() - endWallClockMs);
7171
7196
  var shouldExtendAdBreak = adPlaying && overrunMs < maxExtensionMs;
7172
7197
  if (shouldExtendAdBreak) {
7173
7198
  this.scheduleAdStopCountdown(checkIntervalMs);
@@ -7443,7 +7468,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7443
7468
  _state.sent();
7444
7469
  this.markAdStarted();
7445
7470
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
7446
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
7471
+ this.scheduleAdStopAtBreakBoundary();
7447
7472
  }
7448
7473
  this.adPlayer.setAdVolume(this.getAdAudioVolume());
7449
7474
  this.consecutiveFailures = 0;
@@ -7495,7 +7520,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7495
7520
  _state.sent();
7496
7521
  this.markAdStarted();
7497
7522
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
7498
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
7523
+ this.scheduleAdStopAtBreakBoundary();
7499
7524
  }
7500
7525
  this.adPlayer.setAdVolume(this.getAdAudioVolume());
7501
7526
  return [
@@ -7641,6 +7666,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7641
7666
  this.scheduledScte35BreakKey = void 0;
7642
7667
  this.expectedAdBreakDurationMs = void 0;
7643
7668
  this.currentAdBreakStartWallClockMs = void 0;
7669
+ this.scteAdBreakEndWallClockMs = void 0;
7644
7670
  this.clearAdStartTimer();
7645
7671
  this.clearAdStopTimer();
7646
7672
  this.adPodQueue = [];
@@ -7828,11 +7854,23 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7828
7854
  {
7829
7855
  key: "getWallClockRemainingAdMs",
7830
7856
  value: function getWallClockRemainingAdMs() {
7857
+ var endWallClockMs = this.getAdBreakEndWallClockMs();
7858
+ if (endWallClockMs != null) {
7859
+ return Math.max(0, endWallClockMs - Date.now());
7860
+ }
7861
+ return 0;
7862
+ }
7863
+ },
7864
+ {
7865
+ key: "getAdBreakEndWallClockMs",
7866
+ value: function getAdBreakEndWallClockMs() {
7867
+ if (this.scteAdBreakEndWallClockMs != null) {
7868
+ return this.scteAdBreakEndWallClockMs;
7869
+ }
7831
7870
  if (this.expectedAdBreakDurationMs == null || this.currentAdBreakStartWallClockMs == null) {
7832
- return 0;
7871
+ return void 0;
7833
7872
  }
7834
- var elapsed = Date.now() - this.currentAdBreakStartWallClockMs;
7835
- return Math.max(0, this.expectedAdBreakDurationMs - elapsed);
7873
+ return this.currentAdBreakStartWallClockMs + this.expectedAdBreakDurationMs;
7836
7874
  }
7837
7875
  },
7838
7876
  {