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.
package/lib/index.d.cts CHANGED
@@ -151,6 +151,7 @@ declare class StormcloudVideoPlayer {
151
151
  private inAdBreak;
152
152
  private currentAdBreakStartWallClockMs;
153
153
  private expectedAdBreakDurationMs;
154
+ private scteAdBreakEndWallClockMs;
154
155
  private adStopTimerId;
155
156
  private adStartTimerId;
156
157
  private adFailsafeTimerId;
@@ -257,6 +258,9 @@ declare class StormcloudVideoPlayer {
257
258
  private activatePendingScte35CuesForFragment;
258
259
  private onScte35Marker;
259
260
  private startScte35AdBreak;
261
+ private resolveScteBreakStartWallClockMs;
262
+ private setAdBreakDurationBoundary;
263
+ private scheduleAdStopAtBreakBoundary;
260
264
  private parseCueOutDuration;
261
265
  private parseCueOutCont;
262
266
  private parseAttributeList;
@@ -340,6 +344,7 @@ declare class StormcloudVideoPlayer {
340
344
  private selectVastTagsForBreak;
341
345
  private logAdState;
342
346
  private getWallClockRemainingAdMs;
347
+ private getAdBreakEndWallClockMs;
343
348
  private getDurationBudgetRemainingMs;
344
349
  private getLoadedAdDurationMs;
345
350
  private adFitsRemainingBudget;
package/lib/index.d.ts CHANGED
@@ -151,6 +151,7 @@ declare class StormcloudVideoPlayer {
151
151
  private inAdBreak;
152
152
  private currentAdBreakStartWallClockMs;
153
153
  private expectedAdBreakDurationMs;
154
+ private scteAdBreakEndWallClockMs;
154
155
  private adStopTimerId;
155
156
  private adStartTimerId;
156
157
  private adFailsafeTimerId;
@@ -257,6 +258,9 @@ declare class StormcloudVideoPlayer {
257
258
  private activatePendingScte35CuesForFragment;
258
259
  private onScte35Marker;
259
260
  private startScte35AdBreak;
261
+ private resolveScteBreakStartWallClockMs;
262
+ private setAdBreakDurationBoundary;
263
+ private scheduleAdStopAtBreakBoundary;
260
264
  private parseCueOutDuration;
261
265
  private parseCueOutCont;
262
266
  private parseAttributeList;
@@ -340,6 +344,7 @@ declare class StormcloudVideoPlayer {
340
344
  private selectVastTagsForBreak;
341
345
  private logAdState;
342
346
  private getWallClockRemainingAdMs;
347
+ private getAdBreakEndWallClockMs;
343
348
  private getDurationBudgetRemainingMs;
344
349
  private getLoadedAdDurationMs;
345
350
  private adFitsRemainingBudget;
package/lib/index.js CHANGED
@@ -2728,6 +2728,7 @@ function supportsFeature(feature) {
2728
2728
  // src/utils/ctvVastSignals.ts
2729
2729
  var AIRY_ANDROID_APP_ID = "com.freeairytv.android";
2730
2730
  var AIRY_APP_NAME = "AiryTV Movies & TV";
2731
+ var AIRY_DEFAULT_CONTENT_URL = "https://live.airy.tv";
2731
2732
  var CTV_SESSION_STORAGE_KEY = "stormcloud.ctv.sid";
2732
2733
  var DEVICE_ID_STORAGE_KEYS = [
2733
2734
  "rdid",
@@ -2745,8 +2746,9 @@ function resolveCtvVastSignals() {
2745
2746
  var bridgeSignals = readNativeBridgeSignals();
2746
2747
  var deviceId = bridgeSignals.deviceId || readStoredDeviceId();
2747
2748
  var deviceIdType = bridgeSignals.deviceIdType || readStoredString("deviceIdType") || inferDeviceIdType();
2749
+ var contentUrl = bridgeSignals.contentUrl || readStoredString("contentUrl") || AIRY_DEFAULT_CONTENT_URL;
2748
2750
  return _object_spread_props(_object_spread({
2749
- contentUrl: "https://".concat(AIRY_ANDROID_APP_ID, ".example.com"),
2751
+ contentUrl: contentUrl,
2750
2752
  appId: AIRY_ANDROID_APP_ID,
2751
2753
  appName: AIRY_APP_NAME,
2752
2754
  sessionId: getOrCreateCtvSessionId()
@@ -2797,6 +2799,12 @@ function readNativeBridgeSignals() {
2797
2799
  try {
2798
2800
  for(var _iterator = candidates[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2799
2801
  var source = _step.value;
2802
+ var contentUrl = readBridgeValue(source, [
2803
+ "contentUrl",
2804
+ "url",
2805
+ "videoUrl",
2806
+ "canonicalUrl"
2807
+ ]) || void 0;
2800
2808
  var deviceId = readBridgeValue(source, [
2801
2809
  "rdid",
2802
2810
  "ifa",
@@ -2804,7 +2812,7 @@ function readNativeBridgeSignals() {
2804
2812
  "adId",
2805
2813
  "deviceId"
2806
2814
  ]) || void 0;
2807
- if (!deviceId) continue;
2815
+ if (!contentUrl && !deviceId) continue;
2808
2816
  var deviceIdType = readBridgeValue(source, [
2809
2817
  "idtype",
2810
2818
  "deviceIdType",
@@ -2816,11 +2824,13 @@ function readNativeBridgeSignals() {
2816
2824
  "limitedAdTracking",
2817
2825
  "lat"
2818
2826
  ]);
2819
- return _object_spread({
2827
+ return _object_spread({}, contentUrl ? {
2828
+ contentUrl: contentUrl
2829
+ } : {}, deviceId ? {
2820
2830
  deviceId: deviceId
2821
- }, deviceIdType ? {
2831
+ } : {}, deviceId && deviceIdType ? {
2822
2832
  deviceIdType: deviceIdType
2823
- } : {}, limitAdTracking != null ? {
2833
+ } : {}, deviceId && limitAdTracking != null ? {
2824
2834
  limitAdTracking: limitAdTracking
2825
2835
  } : {});
2826
2836
  }
@@ -3581,7 +3591,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3581
3591
  _this.showAds = true;
3582
3592
  _this.resetGamNoFillCounter();
3583
3593
  if (_this.inAdBreak && _this.expectedAdBreakDurationMs != null && _this.adStopTimerId == null) {
3584
- _this.scheduleAdStopCountdown(_this.getRemainingAdMs());
3594
+ _this.scheduleAdStopAtBreakBoundary();
3585
3595
  if (_this.config.debugAdTiming) {
3586
3596
  console.log("[StormcloudVideoPlayer] Starting ad break timer on content_pause (first ad starting)");
3587
3597
  }
@@ -4236,12 +4246,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4236
4246
  if (marker.durationSeconds != null) {
4237
4247
  var newDurationMs = marker.durationSeconds * 1e3;
4238
4248
  if (this.expectedAdBreakDurationMs == null || newDurationMs > this.expectedAdBreakDurationMs) {
4239
- this.expectedAdBreakDurationMs = newDurationMs;
4240
- var elapsedMs = this.currentAdBreakStartWallClockMs != null ? Date.now() - this.currentAdBreakStartWallClockMs : 0;
4241
- var remainingMs = Math.max(0, newDurationMs - elapsedMs);
4242
- this.scheduleAdStopCountdown(remainingMs);
4249
+ this.setAdBreakDurationBoundary(newDurationMs);
4250
+ this.scheduleAdStopAtBreakBoundary();
4243
4251
  if (this.config.debugAdTiming) {
4244
- console.log("[StormcloudVideoPlayer] Updated ad break duration from subsequent marker: ".concat(newDurationMs, "ms, remaining: ").concat(remainingMs, "ms"));
4252
+ console.log("[StormcloudVideoPlayer] Updated ad break duration from subsequent marker: ".concat(newDurationMs, "ms, remaining: ").concat(this.getWallClockRemainingAdMs(), "ms"));
4245
4253
  }
4246
4254
  }
4247
4255
  }
@@ -4315,13 +4323,9 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4315
4323
  }
4316
4324
  if (marker.type === "progress" && this.inAdBreak) {
4317
4325
  if (marker.durationSeconds != null) {
4318
- this.expectedAdBreakDurationMs = marker.durationSeconds * 1e3;
4319
- }
4320
- if (this.expectedAdBreakDurationMs != null && this.currentAdBreakStartWallClockMs != null) {
4321
- var elapsedMs1 = Date.now() - this.currentAdBreakStartWallClockMs;
4322
- var remainingMs1 = Math.max(0, this.expectedAdBreakDurationMs - elapsedMs1);
4323
- this.scheduleAdStopCountdown(remainingMs1);
4326
+ this.setAdBreakDurationBoundary(marker.durationSeconds * 1e3);
4324
4327
  }
4328
+ this.scheduleAdStopAtBreakBoundary();
4325
4329
  if (!this.adPlayer.isAdPlaying() && this.activeAdRequestToken === null && this.adRequestQueue.length > 0 && this.hasTimeToStartAnotherAd()) {
4326
4330
  this.tryNextAvailableAdWithRateLimit();
4327
4331
  }
@@ -4345,15 +4349,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4345
4349
  activeAdRequest: this.activeAdRequestToken !== null
4346
4350
  });
4347
4351
  }
4348
- if (adPlaying || remaining > 1e3 && hasQueuedAds) {
4349
- if (this.config.debugAdTiming) {
4350
- console.log("[StormcloudVideoPlayer] Ignoring premature SCTE-35 end marker - ads still active");
4351
- }
4352
- return;
4353
- }
4354
- this.inAdBreak = false;
4355
- this.expectedAdBreakDurationMs = void 0;
4356
- this.currentAdBreakStartWallClockMs = void 0;
4352
+ this.scteAdBreakEndWallClockMs = Date.now();
4357
4353
  this.clearAdStartTimer();
4358
4354
  this.clearAdStopTimer();
4359
4355
  if (adPlaying) {
@@ -4370,12 +4366,46 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4370
4366
  this.inAdBreak = true;
4371
4367
  this.activeScte35BreakKey = cueKey !== null && cueKey !== void 0 ? cueKey : this.pendingScte35CueKey;
4372
4368
  this.scheduledScte35BreakKey = void 0;
4373
- this.expectedAdBreakDurationMs = durationMs;
4374
- this.currentAdBreakStartWallClockMs = Date.now();
4369
+ this.currentAdBreakStartWallClockMs = this.resolveScteBreakStartWallClockMs(marker);
4370
+ this.setAdBreakDurationBoundary(durationMs);
4375
4371
  this.handleAdStart(marker);
4376
- if (this.expectedAdBreakDurationMs != null) {
4377
- this.scheduleAdStopCountdown(this.expectedAdBreakDurationMs);
4372
+ this.scheduleAdStopAtBreakBoundary();
4373
+ }
4374
+ },
4375
+ {
4376
+ key: "resolveScteBreakStartWallClockMs",
4377
+ value: function resolveScteBreakStartWallClockMs(marker) {
4378
+ var nowWallClockMs = Date.now();
4379
+ if (typeof marker.ptsSeconds !== "number") {
4380
+ return nowWallClockMs;
4381
+ }
4382
+ var nowMs = this.video.currentTime * 1e3;
4383
+ var estimatedCurrentPtsMs = nowMs - this.ptsDriftEmaMs;
4384
+ var deltaMs = marker.ptsSeconds * 1e3 - estimatedCurrentPtsMs;
4385
+ if (!Number.isFinite(deltaMs)) {
4386
+ return nowWallClockMs;
4387
+ }
4388
+ return nowWallClockMs + Math.floor(deltaMs);
4389
+ }
4390
+ },
4391
+ {
4392
+ key: "setAdBreakDurationBoundary",
4393
+ value: function setAdBreakDurationBoundary(durationMs) {
4394
+ this.expectedAdBreakDurationMs = durationMs;
4395
+ if (durationMs != null && this.currentAdBreakStartWallClockMs != null) {
4396
+ this.scteAdBreakEndWallClockMs = this.currentAdBreakStartWallClockMs + durationMs;
4397
+ } else {
4398
+ this.scteAdBreakEndWallClockMs = void 0;
4399
+ }
4400
+ }
4401
+ },
4402
+ {
4403
+ key: "scheduleAdStopAtBreakBoundary",
4404
+ value: function scheduleAdStopAtBreakBoundary() {
4405
+ if (this.expectedAdBreakDurationMs == null) {
4406
+ return;
4378
4407
  }
4408
+ this.scheduleAdStopCountdown(this.getWallClockRemainingAdMs());
4379
4409
  }
4380
4410
  },
4381
4411
  {
@@ -6025,7 +6055,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6025
6055
  currentVolume = this.video.volume;
6026
6056
  this.adPlayer.updateOriginalMutedState(currentMuted, currentVolume);
6027
6057
  this.inAdBreak = true;
6028
- this.currentAdBreakStartWallClockMs = Date.now();
6029
6058
  this.adBreakPlayedDurationMs = 0;
6030
6059
  this.currentAdIndex = 0;
6031
6060
  this.totalAdsInBreak = 0;
@@ -6131,7 +6160,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6131
6160
  _state.sent();
6132
6161
  this.markAdStarted();
6133
6162
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6134
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
6163
+ this.scheduleAdStopAtBreakBoundary();
6135
6164
  }
6136
6165
  adVolume = currentMuted ? 0 : currentVolume;
6137
6166
  this.adPlayer.setAdVolume(adVolume);
@@ -6191,7 +6220,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6191
6220
  _state.sent();
6192
6221
  this.markAdStarted();
6193
6222
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6194
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
6223
+ this.scheduleAdStopAtBreakBoundary();
6195
6224
  }
6196
6225
  adVolume1 = currentMuted ? 0 : currentVolume;
6197
6226
  this.adPlayer.setAdVolume(adVolume1);
@@ -6264,7 +6293,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6264
6293
  _state.sent();
6265
6294
  this.markAdStarted();
6266
6295
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6267
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
6296
+ this.scheduleAdStopAtBreakBoundary();
6268
6297
  }
6269
6298
  adVolume2 = currentMuted ? 0 : currentVolume;
6270
6299
  this.adPlayer.setAdVolume(adVolume2);
@@ -6647,7 +6676,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6647
6676
  _state.sent();
6648
6677
  this.markAdStarted();
6649
6678
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
6650
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
6679
+ this.scheduleAdStopAtBreakBoundary();
6651
6680
  }
6652
6681
  this.adPlayer.setAdVolume(this.getAdAudioVolume());
6653
6682
  this.consecutiveFailures = 0;
@@ -7175,19 +7204,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7175
7204
  {
7176
7205
  key: "ensureAdStoppedByTimer",
7177
7206
  value: function ensureAdStoppedByTimer() {
7178
- var _this_config_adBreakCheckIntervalMs, _this_expectedAdBreakDurationMs;
7207
+ var _this_config_adBreakCheckIntervalMs, _this_getAdBreakEndWallClockMs;
7179
7208
  if (!this.inAdBreak) return;
7180
7209
  this.adStopTimerId = void 0;
7181
7210
  var adPlaying = this.adPlayer.isAdPlaying();
7182
7211
  var checkIntervalMs = Math.max(250, Math.floor((_this_config_adBreakCheckIntervalMs = this.config.adBreakCheckIntervalMs) !== null && _this_config_adBreakCheckIntervalMs !== void 0 ? _this_config_adBreakCheckIntervalMs : 1e3));
7183
7212
  var maxExtensionMsConfig = this.config.maxAdBreakExtensionMs;
7184
7213
  var maxExtensionMs = typeof maxExtensionMsConfig === "number" && maxExtensionMsConfig > 0 ? maxExtensionMsConfig : 0;
7185
- var elapsedSinceStartMs = 0;
7186
- if (this.currentAdBreakStartWallClockMs != null) {
7187
- elapsedSinceStartMs = Date.now() - this.currentAdBreakStartWallClockMs;
7188
- }
7189
- var expectedDurationMs = (_this_expectedAdBreakDurationMs = this.expectedAdBreakDurationMs) !== null && _this_expectedAdBreakDurationMs !== void 0 ? _this_expectedAdBreakDurationMs : 0;
7190
- var overrunMs = Math.max(0, elapsedSinceStartMs - expectedDurationMs);
7214
+ var endWallClockMs = (_this_getAdBreakEndWallClockMs = this.getAdBreakEndWallClockMs()) !== null && _this_getAdBreakEndWallClockMs !== void 0 ? _this_getAdBreakEndWallClockMs : Date.now();
7215
+ var overrunMs = Math.max(0, Date.now() - endWallClockMs);
7191
7216
  var shouldExtendAdBreak = adPlaying && overrunMs < maxExtensionMs;
7192
7217
  if (shouldExtendAdBreak) {
7193
7218
  this.scheduleAdStopCountdown(checkIntervalMs);
@@ -7463,7 +7488,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7463
7488
  _state.sent();
7464
7489
  this.markAdStarted();
7465
7490
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
7466
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
7491
+ this.scheduleAdStopAtBreakBoundary();
7467
7492
  }
7468
7493
  this.adPlayer.setAdVolume(this.getAdAudioVolume());
7469
7494
  this.consecutiveFailures = 0;
@@ -7515,7 +7540,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7515
7540
  _state.sent();
7516
7541
  this.markAdStarted();
7517
7542
  if (this.expectedAdBreakDurationMs != null && this.adStopTimerId == null) {
7518
- this.scheduleAdStopCountdown(this.getRemainingAdMs());
7543
+ this.scheduleAdStopAtBreakBoundary();
7519
7544
  }
7520
7545
  this.adPlayer.setAdVolume(this.getAdAudioVolume());
7521
7546
  return [
@@ -7661,6 +7686,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7661
7686
  this.scheduledScte35BreakKey = void 0;
7662
7687
  this.expectedAdBreakDurationMs = void 0;
7663
7688
  this.currentAdBreakStartWallClockMs = void 0;
7689
+ this.scteAdBreakEndWallClockMs = void 0;
7664
7690
  this.clearAdStartTimer();
7665
7691
  this.clearAdStopTimer();
7666
7692
  this.adPodQueue = [];
@@ -7848,11 +7874,23 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7848
7874
  {
7849
7875
  key: "getWallClockRemainingAdMs",
7850
7876
  value: function getWallClockRemainingAdMs() {
7877
+ var endWallClockMs = this.getAdBreakEndWallClockMs();
7878
+ if (endWallClockMs != null) {
7879
+ return Math.max(0, endWallClockMs - Date.now());
7880
+ }
7881
+ return 0;
7882
+ }
7883
+ },
7884
+ {
7885
+ key: "getAdBreakEndWallClockMs",
7886
+ value: function getAdBreakEndWallClockMs() {
7887
+ if (this.scteAdBreakEndWallClockMs != null) {
7888
+ return this.scteAdBreakEndWallClockMs;
7889
+ }
7851
7890
  if (this.expectedAdBreakDurationMs == null || this.currentAdBreakStartWallClockMs == null) {
7852
- return 0;
7891
+ return void 0;
7853
7892
  }
7854
- var elapsed = Date.now() - this.currentAdBreakStartWallClockMs;
7855
- return Math.max(0, this.expectedAdBreakDurationMs - elapsed);
7893
+ return this.currentAdBreakStartWallClockMs + this.expectedAdBreakDurationMs;
7856
7894
  }
7857
7895
  },
7858
7896
  {