stormcloud-video-player 0.2.26 → 0.2.28

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
@@ -270,6 +270,7 @@ function createImaController(video, options) {
270
270
  const listeners = /* @__PURE__ */ new Map();
271
271
  const preloadedVast = /* @__PURE__ */ new Map();
272
272
  const preloadingVast = /* @__PURE__ */ new Map();
273
+ let adVideoElement;
273
274
  function setAdPlayingFlag(isPlaying) {
274
275
  if (isPlaying) {
275
276
  video.dataset.stormcloudAdPlaying = "true";
@@ -277,6 +278,24 @@ function createImaController(video, options) {
277
278
  delete video.dataset.stormcloudAdPlaying;
278
279
  }
279
280
  }
281
+ function createAdVideoElement() {
282
+ const adVideo = document.createElement("video");
283
+ adVideo.style.position = "absolute";
284
+ adVideo.style.top = "0";
285
+ adVideo.style.left = "0";
286
+ adVideo.style.width = "100%";
287
+ adVideo.style.height = "100%";
288
+ adVideo.style.objectFit = "contain";
289
+ adVideo.style.backgroundColor = "#000";
290
+ adVideo.style.zIndex = "15";
291
+ adVideo.playsInline = true;
292
+ adVideo.muted = false;
293
+ adVideo.volume = originalMutedState ? 0 : originalVolume;
294
+ console.log(
295
+ `[IMA] Created dedicated ad video element with volume: ${adVideo.volume}, muted: ${adVideo.muted}`
296
+ );
297
+ return adVideo;
298
+ }
280
299
  function emit(event, payload) {
281
300
  const set = listeners.get(event);
282
301
  if (!set) return;
@@ -443,12 +462,22 @@ function createImaController(video, options) {
443
462
  const google = window.google;
444
463
  ensurePlaceholderContainer();
445
464
  if (!adDisplayContainer && adContainerEl) {
465
+ if (!adVideoElement) {
466
+ adVideoElement = createAdVideoElement();
467
+ adContainerEl.appendChild(adVideoElement);
468
+ console.log(
469
+ "[IMA] Dedicated ad video element added to container"
470
+ );
471
+ }
446
472
  adDisplayContainer = new google.ima.AdDisplayContainer(
447
473
  adContainerEl,
448
- video
474
+ adVideoElement
449
475
  );
450
476
  try {
451
477
  (_a = adDisplayContainer.initialize) == null ? void 0 : _a.call(adDisplayContainer);
478
+ console.log(
479
+ "[IMA] AdDisplayContainer initialized with dedicated ad video"
480
+ );
452
481
  } catch {
453
482
  }
454
483
  }
@@ -517,13 +546,22 @@ function createImaController(video, options) {
517
546
  }
518
547
  video.parentElement.appendChild(container);
519
548
  adContainerEl = container;
549
+ if (!adVideoElement) {
550
+ adVideoElement = createAdVideoElement();
551
+ adContainerEl.appendChild(adVideoElement);
552
+ console.log(
553
+ "[IMA] Dedicated ad video element created and added to container"
554
+ );
555
+ }
520
556
  adDisplayContainer = new google.ima.AdDisplayContainer(
521
557
  container,
522
- video
558
+ adVideoElement
523
559
  );
524
560
  try {
525
561
  adDisplayContainer.initialize();
526
- console.log("[IMA] Ad display container initialized");
562
+ console.log(
563
+ "[IMA] Ad display container initialized with dedicated ad video"
564
+ );
527
565
  } catch (error) {
528
566
  console.warn(
529
567
  "[IMA] Failed to initialize ad display container:",
@@ -566,11 +604,10 @@ function createImaController(video, options) {
566
604
  console.error("[IMA] Ad error:", errorEvent.getError());
567
605
  destroyAdsManager();
568
606
  adPlaying = false;
569
- const previousMutedState = video.muted;
570
- video.muted = originalMutedState;
607
+ video.style.visibility = "visible";
571
608
  setAdPlayingFlag(false);
572
609
  console.log(
573
- `[IMA] Restored mute state after ad error: ${previousMutedState} -> ${originalMutedState}`
610
+ "[IMA] Restored main video visibility after ad error"
574
611
  );
575
612
  if (adContainerEl) {
576
613
  adContainerEl.style.pointerEvents = "none";
@@ -614,18 +651,17 @@ function createImaController(video, options) {
614
651
  AdEvent.CONTENT_PAUSE_REQUESTED,
615
652
  () => {
616
653
  console.log(
617
- "[IMA] Content pause requested - FORCE MUTING main video"
654
+ "[IMA] Content pause requested - hiding main video, showing ad video"
618
655
  );
619
656
  if (!(options == null ? void 0 : options.continueLiveStreamDuringAds)) {
620
657
  video.pause();
621
- console.log("[IMA] Video paused (VOD mode)");
658
+ console.log("[IMA] Content video paused (VOD mode)");
622
659
  } else {
623
660
  console.log(
624
- "[IMA] Video continues playing but muted (Live mode)"
661
+ "[IMA] Content video continues playing in background (Live mode)"
625
662
  );
626
663
  }
627
- video.muted = true;
628
- video.volume = 0;
664
+ video.style.visibility = "hidden";
629
665
  adPlaying = true;
630
666
  setAdPlayingFlag(true);
631
667
  emit("content_pause");
@@ -633,36 +669,46 @@ function createImaController(video, options) {
633
669
  );
634
670
  adsManager.addEventListener(AdEvent.STARTED, () => {
635
671
  console.log(
636
- "[IMA] Ad started playing - FORCE MUTING main video"
672
+ "[IMA] Ad started playing - showing dedicated ad video"
637
673
  );
638
674
  setAdPlayingFlag(true);
639
- video.muted = true;
640
- video.volume = 0;
675
+ video.style.visibility = "hidden";
676
+ if (adVideoElement) {
677
+ adVideoElement.volume = originalMutedState ? 0 : originalVolume;
678
+ adVideoElement.muted = originalMutedState;
679
+ console.log(
680
+ `[IMA] Ad video volume: ${adVideoElement.volume}, muted: ${adVideoElement.muted}`
681
+ );
682
+ }
641
683
  if (adContainerEl) {
642
684
  adContainerEl.style.pointerEvents = "auto";
643
685
  adContainerEl.style.display = "flex";
644
686
  console.log(
645
- "[IMA] Ad container visibility set to flex with pointer events enabled"
687
+ "[IMA] Ad container visible with dedicated ad video"
646
688
  );
647
689
  }
648
690
  });
649
691
  adsManager.addEventListener(
650
692
  AdEvent.CONTENT_RESUME_REQUESTED,
651
693
  () => {
652
- console.log("[IMA] Content resume requested");
694
+ console.log(
695
+ "[IMA] Content resume requested - showing main video"
696
+ );
653
697
  adPlaying = false;
654
698
  setAdPlayingFlag(false);
699
+ video.style.visibility = "visible";
655
700
  emit("content_resume");
656
701
  setTimeout(() => {
657
702
  const stillInPod = video.dataset.stormcloudAdPlaying === "true";
658
703
  if (stillInPod) {
659
704
  console.log(
660
- "[IMA] Still in ad pod - keeping ad container visible (black screen)"
705
+ "[IMA] Still in ad pod - keeping ad video visible"
661
706
  );
662
707
  if (adContainerEl) {
663
708
  adContainerEl.style.display = "flex";
664
709
  adContainerEl.style.pointerEvents = "auto";
665
710
  }
711
+ video.style.visibility = "hidden";
666
712
  }
667
713
  }, 50);
668
714
  }
@@ -682,7 +728,7 @@ function createImaController(video, options) {
682
728
  } catch (e) {
683
729
  console.error("[IMA] Error setting up ads manager:", e);
684
730
  adPlaying = false;
685
- video.muted = originalMutedState;
731
+ video.style.visibility = "visible";
686
732
  setAdPlayingFlag(false);
687
733
  if (adContainerEl) {
688
734
  adContainerEl.style.pointerEvents = "none";
@@ -713,11 +759,10 @@ function createImaController(video, options) {
713
759
  (adErrorEvent) => {
714
760
  console.error("[IMA] Ads loader error:", adErrorEvent.getError());
715
761
  adPlaying = false;
716
- const previousMutedState = video.muted;
717
- video.muted = originalMutedState;
762
+ video.style.visibility = "visible";
718
763
  setAdPlayingFlag(false);
719
764
  console.log(
720
- `[IMA] Restored mute state: ${previousMutedState} -> ${originalMutedState}`
765
+ "[IMA] Restored main video visibility after loader error"
721
766
  );
722
767
  if (adContainerEl) {
723
768
  adContainerEl.style.pointerEvents = "none";
@@ -797,11 +842,18 @@ function createImaController(video, options) {
797
842
  adsManager.init(width, height, window.google.ima.ViewMode.NORMAL);
798
843
  adPlaying = true;
799
844
  const adVolume = originalMutedState ? 0 : originalVolume;
845
+ if (adVideoElement) {
846
+ adVideoElement.volume = adVolume;
847
+ adVideoElement.muted = originalMutedState;
848
+ console.log(
849
+ `[IMA] Set dedicated ad video volume to ${adVolume}, muted: ${originalMutedState}`
850
+ );
851
+ }
800
852
  try {
801
853
  adsManager.setVolume(adVolume);
802
- console.log(`[IMA] Set ad volume to ${adVolume}`);
854
+ console.log(`[IMA] Set IMA manager volume to ${adVolume}`);
803
855
  } catch (error) {
804
- console.warn("[IMA] Failed to set ad volume:", error);
856
+ console.warn("[IMA] Failed to set IMA manager volume:", error);
805
857
  }
806
858
  console.log("[IMA] Starting ad playback");
807
859
  adsManager.start();
@@ -822,6 +874,7 @@ function createImaController(video, options) {
822
874
  console.log("[IMA] Stopping ad playback");
823
875
  adPlaying = false;
824
876
  setAdPlayingFlag(false);
877
+ video.style.visibility = "visible";
825
878
  if (adContainerEl) {
826
879
  adContainerEl.style.pointerEvents = "none";
827
880
  adContainerEl.style.display = "none";
@@ -837,8 +890,7 @@ function createImaController(video, options) {
837
890
  var _a;
838
891
  destroyAdsManager();
839
892
  adPlaying = false;
840
- video.muted = originalMutedState;
841
- video.volume = originalVolume;
893
+ video.style.visibility = "visible";
842
894
  setAdPlayingFlag(false);
843
895
  if (adContainerEl) {
844
896
  adContainerEl.style.pointerEvents = "none";
@@ -854,6 +906,7 @@ function createImaController(video, options) {
854
906
  adContainerEl = void 0;
855
907
  adDisplayContainer = void 0;
856
908
  adsLoader = void 0;
909
+ adVideoElement = void 0;
857
910
  preloadedVast.clear();
858
911
  preloadingVast.clear();
859
912
  },
@@ -898,15 +951,26 @@ function createImaController(video, options) {
898
951
  return originalVolume;
899
952
  },
900
953
  setAdVolume(volume) {
954
+ const clampedVolume = Math.max(0, Math.min(1, volume));
955
+ if (adVideoElement && adPlaying) {
956
+ adVideoElement.volume = clampedVolume;
957
+ adVideoElement.muted = clampedVolume === 0;
958
+ console.log(
959
+ `[IMA] Set dedicated ad video volume to ${clampedVolume}, muted: ${clampedVolume === 0}`
960
+ );
961
+ }
901
962
  if (adsManager && adPlaying) {
902
963
  try {
903
- adsManager.setVolume(Math.max(0, Math.min(1, volume)));
964
+ adsManager.setVolume(clampedVolume);
904
965
  } catch (error) {
905
- console.warn("[IMA] Failed to set ad volume:", error);
966
+ console.warn("[IMA] Failed to set IMA manager volume:", error);
906
967
  }
907
968
  }
908
969
  },
909
970
  getAdVolume() {
971
+ if (adVideoElement && adPlaying) {
972
+ return adVideoElement.volume;
973
+ }
910
974
  if (adsManager && adPlaying) {
911
975
  try {
912
976
  return adsManager.getVolume();
@@ -3523,11 +3587,6 @@ var StormcloudVideoPlayer = class {
3523
3587
  }
3524
3588
  return false;
3525
3589
  }
3526
- if (this.config.debugAdTiming) {
3527
- console.log(
3528
- `[StormcloudVideoPlayer] isMuted() no ad playing: video.muted=${this.video.muted}`
3529
- );
3530
- }
3531
3590
  return this.video.muted;
3532
3591
  }
3533
3592
  setMuted(muted) {
@@ -3557,6 +3616,26 @@ var StormcloudVideoPlayer = class {
3557
3616
  console.log("[StormcloudVideoPlayer] setMuted called:", muted);
3558
3617
  }
3559
3618
  }
3619
+ setVolume(volume) {
3620
+ const clampedVolume = Math.max(0, Math.min(1, volume));
3621
+ const adPlaying = this.ima.isAdPlaying();
3622
+ if (adPlaying) {
3623
+ this.ima.setAdVolume(clampedVolume);
3624
+ this.ima.updateOriginalMutedState(clampedVolume === 0, clampedVolume);
3625
+ if (this.config.debugAdTiming) {
3626
+ console.log("[StormcloudVideoPlayer] setVolume applied during ad", {
3627
+ volume: clampedVolume
3628
+ });
3629
+ }
3630
+ } else {
3631
+ this.video.volume = clampedVolume;
3632
+ this.video.muted = clampedVolume === 0;
3633
+ this.ima.updateOriginalMutedState(clampedVolume === 0, clampedVolume);
3634
+ if (this.config.debugAdTiming) {
3635
+ console.log("[StormcloudVideoPlayer] setVolume called:", clampedVolume);
3636
+ }
3637
+ }
3638
+ }
3560
3639
  isFullscreen() {
3561
3640
  return !!document.fullscreenElement;
3562
3641
  }
@@ -3728,10 +3807,9 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3728
3807
  }
3729
3808
  };
3730
3809
  const handleVolumeChange = (newVolume) => {
3731
- if (videoRef.current && isFinite(newVolume)) {
3810
+ if (playerRef.current && isFinite(newVolume)) {
3732
3811
  const clampedVolume = Math.max(0, Math.min(1, newVolume));
3733
- videoRef.current.volume = clampedVolume;
3734
- videoRef.current.muted = clampedVolume === 0;
3812
+ playerRef.current.setVolume(clampedVolume);
3735
3813
  }
3736
3814
  };
3737
3815
  const handlePlaybackRateChange = (rate) => {
@@ -3833,7 +3911,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(
3833
3911
  if (autoplay !== void 0 && playerRef.current.videoElement) {
3834
3912
  playerRef.current.videoElement.autoplay = autoplay;
3835
3913
  }
3836
- if (muted !== void 0) {
3914
+ if (muted !== void 0 && !playerRef.current.isShowingAds()) {
3837
3915
  playerRef.current.setMuted(muted);
3838
3916
  }
3839
3917
  } catch (error) {