stormcloud-video-player 0.2.18 → 0.2.20

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
@@ -592,28 +592,42 @@ function createImaController(video, options) {
592
592
  adsManager.addEventListener(
593
593
  AdEvent.CONTENT_RESUME_REQUESTED,
594
594
  () => {
595
- var _a;
596
595
  console.log("[IMA] Content resume requested");
597
596
  adPlaying = false;
598
- video.muted = originalMutedState;
599
597
  setAdPlayingFlag(false);
600
- if (adContainerEl) {
601
- adContainerEl.style.pointerEvents = "none";
602
- adContainerEl.style.display = "none";
603
- console.log(
604
- "[IMA] Ad container hidden - pointer events disabled"
605
- );
606
- }
607
- if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
608
- (_a = video.play()) == null ? void 0 : _a.catch(() => {
609
- });
610
- console.log("[IMA] Video resumed (VOD mode)");
611
- } else {
612
- console.log(
613
- "[IMA] Video unmuted (Live mode - was never paused)"
614
- );
615
- }
616
598
  emit("content_resume");
599
+ setTimeout(() => {
600
+ var _a;
601
+ const stillInAdPod = video.dataset.stormcloudAdPlaying === "true";
602
+ if (stillInAdPod) {
603
+ console.log(
604
+ "[IMA] Next ad started - keeping content muted/paused and ad container visible"
605
+ );
606
+ if (adContainerEl) {
607
+ adContainerEl.style.display = "flex";
608
+ adContainerEl.style.pointerEvents = "auto";
609
+ }
610
+ return;
611
+ }
612
+ console.log("[IMA] No next ad - resuming content");
613
+ video.muted = originalMutedState;
614
+ if (adContainerEl) {
615
+ adContainerEl.style.pointerEvents = "none";
616
+ adContainerEl.style.display = "none";
617
+ console.log(
618
+ "[IMA] Ad container hidden - pointer events disabled"
619
+ );
620
+ }
621
+ if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
622
+ (_a = video.play()) == null ? void 0 : _a.catch(() => {
623
+ });
624
+ console.log("[IMA] Video resumed (VOD mode)");
625
+ } else {
626
+ console.log(
627
+ "[IMA] Video unmuted (Live mode - was never paused)"
628
+ );
629
+ }
630
+ }, 100);
617
631
  }
618
632
  );
619
633
  adsManager.addEventListener(AdEvent.ALL_ADS_COMPLETED, () => {
@@ -1188,24 +1202,38 @@ function createHlsAdPlayer(contentVideo, options) {
1188
1202
  console.log("[HlsAdPlayer] Handling ad completion");
1189
1203
  adPlaying = false;
1190
1204
  setAdPlayingFlag(false);
1191
- const previousMutedState = contentVideo.muted;
1192
- contentVideo.muted = originalMutedState;
1193
- console.log(
1194
- `[HlsAdPlayer] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
1195
- );
1196
- if (adContainerEl) {
1197
- adContainerEl.style.display = "none";
1198
- adContainerEl.style.pointerEvents = "none";
1199
- }
1200
- if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
1201
- contentVideo.play().catch(() => {
1202
- });
1203
- console.log("[HlsAdPlayer] Content resumed (VOD mode)");
1204
- } else {
1205
- console.log("[HlsAdPlayer] Content unmuted (Live mode)");
1206
- }
1207
1205
  emit("content_resume");
1208
1206
  emit("all_ads_completed");
1207
+ setTimeout(() => {
1208
+ const stillInAdPod = contentVideo.dataset.stormcloudAdPlaying === "true";
1209
+ if (stillInAdPod) {
1210
+ console.log(
1211
+ "[HlsAdPlayer] Next ad started - keeping content muted/paused and ad container visible"
1212
+ );
1213
+ if (adContainerEl) {
1214
+ adContainerEl.style.display = "flex";
1215
+ adContainerEl.style.pointerEvents = "auto";
1216
+ }
1217
+ return;
1218
+ }
1219
+ console.log("[HlsAdPlayer] No next ad - resuming content");
1220
+ const previousMutedState = contentVideo.muted;
1221
+ contentVideo.muted = originalMutedState;
1222
+ console.log(
1223
+ `[HlsAdPlayer] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
1224
+ );
1225
+ if (adContainerEl) {
1226
+ adContainerEl.style.display = "none";
1227
+ adContainerEl.style.pointerEvents = "none";
1228
+ }
1229
+ if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
1230
+ contentVideo.play().catch(() => {
1231
+ });
1232
+ console.log("[HlsAdPlayer] Content resumed (VOD mode)");
1233
+ } else {
1234
+ console.log("[HlsAdPlayer] Content unmuted (Live mode)");
1235
+ }
1236
+ }, 100);
1209
1237
  }
1210
1238
  function handleAdError() {
1211
1239
  console.log("[HlsAdPlayer] Handling ad error");
@@ -1943,6 +1971,7 @@ var StormcloudVideoPlayer = class {
1943
1971
  this.bufferedSegmentsCount = 0;
1944
1972
  this.shouldAutoplayAfterBuffering = false;
1945
1973
  this.hasInitialBufferCompleted = false;
1974
+ this.isTransitioningBetweenAds = false;
1946
1975
  initializePolyfills();
1947
1976
  const browserOverrides = getBrowserConfigOverrides();
1948
1977
  this.config = { ...config, ...browserOverrides };
@@ -2244,29 +2273,60 @@ var StormcloudVideoPlayer = class {
2244
2273
  this.ima.on("content_resume", () => {
2245
2274
  if (this.config.debugAdTiming) {
2246
2275
  console.log(
2247
- "[StormcloudVideoPlayer] IMA content_resume event received"
2276
+ "[StormcloudVideoPlayer] IMA content_resume event received",
2277
+ {
2278
+ inAdBreak: this.inAdBreak,
2279
+ isTransitioningBetweenAds: this.isTransitioningBetweenAds,
2280
+ pendingAds: this.adPodQueue.length
2281
+ }
2248
2282
  );
2249
2283
  }
2250
2284
  this.clearAdFailsafeTimer();
2251
- if (!this.inAdBreak) return;
2285
+ if (this.isTransitioningBetweenAds) {
2286
+ if (this.config.debugAdTiming) {
2287
+ console.log(
2288
+ "[StormcloudVideoPlayer] Transitioning between ads - keeping content muted/paused"
2289
+ );
2290
+ }
2291
+ return;
2292
+ }
2293
+ if (!this.inAdBreak) {
2294
+ if (this.config.debugAdTiming) {
2295
+ console.log(
2296
+ "[StormcloudVideoPlayer] Not in ad break, allowing normal content resume"
2297
+ );
2298
+ }
2299
+ return;
2300
+ }
2252
2301
  const remaining = this.getRemainingAdMs();
2253
2302
  if (remaining > 500 && this.adPodQueue.length > 0) {
2303
+ this.isTransitioningBetweenAds = true;
2304
+ this.video.muted = true;
2305
+ if (!this.shouldContinueLiveStreamDuringAds()) {
2306
+ this.video.pause();
2307
+ }
2254
2308
  const next = this.adPodQueue.shift();
2255
2309
  this.currentAdIndex++;
2256
2310
  if (this.config.debugAdTiming) {
2257
2311
  console.log(
2258
- `[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak})`
2312
+ `[StormcloudVideoPlayer] Playing next ad in pod (${this.currentAdIndex}/${this.totalAdsInBreak}) - keeping content muted/paused`
2259
2313
  );
2260
2314
  }
2261
2315
  this.playSingleAd(next).catch(() => {
2316
+ }).finally(() => {
2317
+ this.isTransitioningBetweenAds = false;
2262
2318
  });
2263
2319
  } else {
2264
2320
  if (this.config.debugAdTiming) {
2265
2321
  console.log("[StormcloudVideoPlayer] Ad pod completed");
2266
2322
  }
2323
+ this.inAdBreak = false;
2324
+ this.expectedAdBreakDurationMs = void 0;
2325
+ this.currentAdBreakStartWallClockMs = void 0;
2267
2326
  this.currentAdIndex = 0;
2268
2327
  this.totalAdsInBreak = 0;
2269
2328
  this.showAds = false;
2329
+ this.clearAdStopTimer();
2270
2330
  }
2271
2331
  });
2272
2332
  this.video.addEventListener("timeupdate", () => {
@@ -2940,14 +3000,66 @@ var StormcloudVideoPlayer = class {
2940
3000
  }
2941
3001
  }
2942
3002
  ensureAdStoppedByTimer() {
3003
+ var _a, _b;
2943
3004
  if (!this.inAdBreak) return;
3005
+ this.adStopTimerId = void 0;
3006
+ const adPlaying = this.ima.isAdPlaying();
3007
+ const pendingAds = this.adPodQueue.length > 0;
3008
+ const checkIntervalMs = Math.max(
3009
+ 250,
3010
+ Math.floor((_a = this.config.adBreakCheckIntervalMs) != null ? _a : 1e3)
3011
+ );
3012
+ const maxExtensionMsConfig = this.config.maxAdBreakExtensionMs;
3013
+ const maxExtensionMs = typeof maxExtensionMsConfig === "number" && maxExtensionMsConfig > 0 ? maxExtensionMsConfig : 6e4;
3014
+ let elapsedSinceStartMs = 0;
3015
+ if (this.currentAdBreakStartWallClockMs != null) {
3016
+ elapsedSinceStartMs = Date.now() - this.currentAdBreakStartWallClockMs;
3017
+ }
3018
+ const expectedDurationMs = (_b = this.expectedAdBreakDurationMs) != null ? _b : 0;
3019
+ const overrunMs = Math.max(0, elapsedSinceStartMs - expectedDurationMs);
3020
+ const shouldExtendAdBreak = (adPlaying || pendingAds || this.showAds) && overrunMs < maxExtensionMs;
3021
+ if (shouldExtendAdBreak) {
3022
+ if (this.config.debugAdTiming) {
3023
+ console.log(
3024
+ "[StormcloudVideoPlayer] Extending ad break beyond scheduled duration",
3025
+ {
3026
+ adPlaying,
3027
+ pendingAds,
3028
+ showAds: this.showAds,
3029
+ overrunMs,
3030
+ checkIntervalMs,
3031
+ maxExtensionMs
3032
+ }
3033
+ );
3034
+ }
3035
+ this.scheduleAdStopCountdown(checkIntervalMs);
3036
+ return;
3037
+ }
3038
+ if (this.config.debugAdTiming) {
3039
+ console.log("[StormcloudVideoPlayer] Ending ad break via timer", {
3040
+ adPlaying,
3041
+ pendingAds,
3042
+ showAds: this.showAds,
3043
+ overrunMs,
3044
+ maxExtensionMs
3045
+ });
3046
+ }
2944
3047
  this.inAdBreak = false;
2945
3048
  this.expectedAdBreakDurationMs = void 0;
2946
3049
  this.currentAdBreakStartWallClockMs = void 0;
2947
- this.adStopTimerId = void 0;
2948
- if (this.ima.isAdPlaying()) {
3050
+ this.showAds = false;
3051
+ this.adPodQueue = [];
3052
+ this.currentAdIndex = 0;
3053
+ this.totalAdsInBreak = 0;
3054
+ this.clearAdFailsafeTimer();
3055
+ if (adPlaying) {
2949
3056
  this.ima.stop().catch(() => {
2950
3057
  });
3058
+ return;
3059
+ }
3060
+ const originalMutedState = this.ima.getOriginalMutedState();
3061
+ if (this.video.muted !== originalMutedState) {
3062
+ this.video.muted = originalMutedState;
2951
3063
  }
2952
3064
  }
2953
3065
  scheduleAdStartIn(delayMs) {