stormcloud-video-player 0.6.5 → 0.6.7

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
@@ -964,6 +964,7 @@ function createVastAdLayer(contentVideo, options) {
964
964
  var tornDown = false;
965
965
  var trackingFired = createEmptyTrackingState();
966
966
  var adStallTimerId;
967
+ var savedContentVideoStyles;
967
968
  var currentAdEventHandlers;
968
969
  var preloadSlots = /* @__PURE__ */ new Map();
969
970
  function emit(event, payload) {
@@ -1080,7 +1081,7 @@ function createVastAdLayer(contentVideo, options) {
1080
1081
  video.style.top = "0";
1081
1082
  video.style.width = "100%";
1082
1083
  video.style.height = "100%";
1083
- video.style.objectFit = "contain";
1084
+ video.style.objectFit = "cover";
1084
1085
  video.style.backgroundColor = "#000";
1085
1086
  video.playsInline = true;
1086
1087
  video.muted = false;
@@ -1195,12 +1196,31 @@ function createVastAdLayer(contentVideo, options) {
1195
1196
  delete contentVideo.dataset.stormcloudAdPlaying;
1196
1197
  }
1197
1198
  }
1199
+ function applyContentVideoAdCoverStyles() {
1200
+ if (!singleElementMode) return;
1201
+ savedContentVideoStyles = {
1202
+ objectFit: contentVideo.style.objectFit,
1203
+ width: contentVideo.style.width,
1204
+ height: contentVideo.style.height
1205
+ };
1206
+ contentVideo.style.objectFit = "cover";
1207
+ contentVideo.style.width = "100%";
1208
+ contentVideo.style.height = "100%";
1209
+ }
1210
+ function restoreContentVideoStyles() {
1211
+ if (!singleElementMode || !savedContentVideoStyles) return;
1212
+ contentVideo.style.objectFit = savedContentVideoStyles.objectFit;
1213
+ contentVideo.style.width = savedContentVideoStyles.width;
1214
+ contentVideo.style.height = savedContentVideoStyles.height;
1215
+ savedContentVideoStyles = void 0;
1216
+ }
1198
1217
  function handleAdComplete() {
1199
1218
  if (tornDown) return;
1200
1219
  clearAdStallTimer();
1201
1220
  if (debug) console.log("".concat(LOG, " Handling ad completion"));
1202
1221
  adPlaying = false;
1203
1222
  setAdPlayingFlag(false);
1223
+ restoreContentVideoStyles();
1204
1224
  if (adContainerEl) {
1205
1225
  adContainerEl.style.display = "none";
1206
1226
  adContainerEl.style.pointerEvents = "none";
@@ -1215,6 +1235,7 @@ function createVastAdLayer(contentVideo, options) {
1215
1235
  if (debug) console.log("".concat(LOG, " Handling ad error"));
1216
1236
  adPlaying = false;
1217
1237
  setAdPlayingFlag(false);
1238
+ restoreContentVideoStyles();
1218
1239
  if (adContainerEl) {
1219
1240
  adContainerEl.style.display = "none";
1220
1241
  adContainerEl.style.pointerEvents = "none";
@@ -1385,6 +1406,7 @@ function createVastAdLayer(contentVideo, options) {
1385
1406
  ];
1386
1407
  contentVideo.style.visibility = "visible";
1387
1408
  contentVideo.style.opacity = "1";
1409
+ applyContentVideoAdCoverStyles();
1388
1410
  emit("content_pause");
1389
1411
  setupAdEventListeners();
1390
1412
  adVolume2 = originalMutedState ? 1 : originalVolume;
@@ -1623,6 +1645,7 @@ function createVastAdLayer(contentVideo, options) {
1623
1645
  ];
1624
1646
  contentVideo.style.visibility = "visible";
1625
1647
  contentVideo.style.opacity = "1";
1648
+ applyContentVideoAdCoverStyles();
1626
1649
  emit("content_pause");
1627
1650
  setupAdEventListeners();
1628
1651
  adVolume2 = originalMutedState ? 1 : originalVolume;
@@ -1773,6 +1796,7 @@ function createVastAdLayer(contentVideo, options) {
1773
1796
  if (debug) console.log("".concat(LOG, " Stopping ad"));
1774
1797
  adPlaying = false;
1775
1798
  setAdPlayingFlag(false);
1799
+ restoreContentVideoStyles();
1776
1800
  contentVideo.muted = originalMutedState;
1777
1801
  contentVideo.volume = originalMutedState ? 0 : originalVolume;
1778
1802
  contentVideo.style.visibility = "visible";
@@ -1811,6 +1835,7 @@ function createVastAdLayer(contentVideo, options) {
1811
1835
  destroyed = true;
1812
1836
  adPlaying = false;
1813
1837
  setAdPlayingFlag(false);
1838
+ restoreContentVideoStyles();
1814
1839
  contentVideo.muted = originalMutedState;
1815
1840
  contentVideo.volume = originalVolume;
1816
1841
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
@@ -6068,7 +6093,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6068
6093
  return StormcloudVideoPlayer;
6069
6094
  }();
6070
6095
  // src/ui/StormcloudVideoPlayer.tsx
6071
- import { FaPlay, FaPause, FaVolumeUp, FaVolumeMute, FaVolumeDown, FaExpand, FaCompress, FaSpinner } from "react-icons/fa";
6096
+ import { FaPlay, FaPause, FaVolumeUp, FaVolumeMute, FaVolumeDown, FaExpand, FaCompress } from "react-icons/fa";
6072
6097
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6073
6098
  var CRITICAL_PROPS = [
6074
6099
  "src",
@@ -6078,6 +6103,7 @@ var CRITICAL_PROPS = [
6078
6103
  "driftToleranceMs"
6079
6104
  ];
6080
6105
  var CONTROLS_HIDE_DELAY = 3e3;
6106
+ var DEFAULT_PLAYER_ASPECT_RATIO = 16 / 9;
6081
6107
  var StormcloudVideoPlayerComponent = React.memo(function(props) {
6082
6108
  var src = props.src, autoplay = props.autoplay, muted = props.muted, lowLatencyMode = props.lowLatencyMode, allowNativeHls = props.allowNativeHls, driftToleranceMs = props.driftToleranceMs, immediateManifestAds = props.immediateManifestAds, debugAdTiming = props.debugAdTiming, showCustomControls = props.showCustomControls, hideLoadingIndicator = props.hideLoadingIndicator, onVolumeToggle = props.onVolumeToggle, onFullscreenToggle = props.onFullscreenToggle, onControlClick = props.onControlClick, onReady = props.onReady, wrapperClassName = props.wrapperClassName, wrapperStyle = props.wrapperStyle, className = props.className, style = props.style, controls = props.controls, playsInline = props.playsInline, preload = props.preload, poster = props.poster, children = props.children, licenseKey = props.licenseKey, minSegmentsBeforePlay = props.minSegmentsBeforePlay, disableAds = props.disableAds, disableFiller = props.disableFiller, restVideoAttrs = _object_without_properties(props, [
6083
6109
  "src",
@@ -6135,6 +6161,7 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
6135
6161
  var _React_useState15 = _sliced_to_array(React.useState(true), 2), controlsVisible = _React_useState15[0], setControlsVisible = _React_useState15[1];
6136
6162
  var _React_useState16 = _sliced_to_array(React.useState(typeof window !== "undefined" ? window.innerWidth : 1920), 2), viewportWidth = _React_useState16[0], setViewportWidth = _React_useState16[1];
6137
6163
  var _React_useState17 = _sliced_to_array(React.useState(typeof window !== "undefined" ? window.innerHeight > window.innerWidth : false), 2), isPortrait = _React_useState17[0], setIsPortrait = _React_useState17[1];
6164
+ var _React_useState18 = _sliced_to_array(React.useState(DEFAULT_PLAYER_ASPECT_RATIO), 2), playerAspectRatio = _React_useState18[0], setPlayerAspectRatio = _React_useState18[1];
6138
6165
  var getResponsiveScale = function getResponsiveScale() {
6139
6166
  if (viewportWidth < 480) return 0.7;
6140
6167
  if (viewportWidth < 768) return 0.8;
@@ -6376,6 +6403,13 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
6376
6403
  }, []);
6377
6404
  useEffect(function() {
6378
6405
  if (!videoRef.current) return;
6406
+ var handleLoadedMetadata = function handleLoadedMetadata() {
6407
+ var video2 = videoRef.current;
6408
+ if (!video2) return;
6409
+ if (video2.videoWidth > 0 && video2.videoHeight > 0) {
6410
+ setPlayerAspectRatio(video2.videoWidth / video2.videoHeight);
6411
+ }
6412
+ };
6379
6413
  var handleCanPlay = function handleCanPlay() {
6380
6414
  setIsLoading(false);
6381
6415
  if (bufferingTimeoutRef.current) {
@@ -6422,6 +6456,8 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
6422
6456
  setShowCenterPlay(true);
6423
6457
  };
6424
6458
  var video = videoRef.current;
6459
+ handleLoadedMetadata();
6460
+ video.addEventListener("loadedmetadata", handleLoadedMetadata);
6425
6461
  video.addEventListener("canplay", handleCanPlay);
6426
6462
  video.addEventListener("canplaythrough", handleCanPlayThrough);
6427
6463
  video.addEventListener("waiting", handleWaiting);
@@ -6436,6 +6472,7 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
6436
6472
  clearTimeout(bufferingTimeoutRef.current);
6437
6473
  bufferingTimeoutRef.current = null;
6438
6474
  }
6475
+ video.removeEventListener("loadedmetadata", handleLoadedMetadata);
6439
6476
  video.removeEventListener("canplay", handleCanPlay);
6440
6477
  video.removeEventListener("canplaythrough", handleCanPlayThrough);
6441
6478
  video.removeEventListener("waiting", handleWaiting);
@@ -6446,6 +6483,11 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
6446
6483
  }, [
6447
6484
  debugAdTiming
6448
6485
  ]);
6486
+ useEffect(function() {
6487
+ setPlayerAspectRatio(DEFAULT_PLAYER_ASPECT_RATIO);
6488
+ }, [
6489
+ src
6490
+ ]);
6449
6491
  useEffect(function() {
6450
6492
  return function() {
6451
6493
  if (controlsTimerRef.current) {
@@ -6471,7 +6513,7 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
6471
6513
  return /* @__PURE__ */ jsxs(Fragment, {
6472
6514
  children: [
6473
6515
  /* @__PURE__ */ jsx("style", {
6474
- children: "\n @keyframes sc-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n @keyframes sc-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.6; }\n }\n @keyframes sc-fade-in {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .sc-wrapper:fullscreen,\n .sc-wrapper:has(*:fullscreen) {\n border-radius: 0 !important;\n box-shadow: none !important;\n width: 100vw !important;\n height: 100vh !important;\n max-width: 100vw !important;\n max-height: 100vh !important;\n position: fixed !important;\n top: 0 !important;\n left: 0 !important;\n z-index: 999999 !important;\n background: #000 !important;\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n }\n .sc-ctrl-btn {\n background: none;\n border: none;\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n padding: 8px;\n transition: background 0.15s ease, opacity 0.15s ease;\n opacity: 0.9;\n }\n .sc-ctrl-btn:hover {\n opacity: 1;\n background: rgba(255, 255, 255, 0.1);\n }\n .sc-ctrl-btn:active {\n opacity: 0.7;\n }\n .sc-controls-bar {\n transition: opacity 0.35s ease, transform 0.35s ease;\n }\n .sc-progress-track:hover .sc-progress-thumb {\n transform: translate(-50%, -50%) scale(1) !important;\n }\n .sc-loading-hidden .sc-loading-indicator {\n display: none !important;\n }\n "
6516
+ children: "\n @keyframes sc-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n @keyframes sc-loading-glow {\n 0%, 100% { opacity: 0.85; transform: scale(1); }\n 50% { opacity: 1; transform: scale(1.05); }\n }\n @keyframes sc-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.6; }\n }\n @keyframes sc-fade-in {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .sc-wrapper:fullscreen,\n .sc-wrapper:has(*:fullscreen) {\n border-radius: 0 !important;\n box-shadow: none !important;\n width: 100vw !important;\n height: 100vh !important;\n max-width: 100vw !important;\n max-height: 100vh !important;\n position: fixed !important;\n top: 0 !important;\n left: 0 !important;\n z-index: 999999 !important;\n background: #000 !important;\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n }\n .sc-ctrl-btn {\n background: none;\n border: none;\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n padding: 8px;\n transition: background 0.15s ease, opacity 0.15s ease;\n opacity: 0.9;\n }\n .sc-ctrl-btn:hover {\n opacity: 1;\n background: rgba(255, 255, 255, 0.1);\n }\n .sc-ctrl-btn:active {\n opacity: 0.7;\n }\n .sc-controls-bar {\n transition: opacity 0.35s ease, transform 0.35s ease;\n }\n .sc-progress-track:hover .sc-progress-thumb {\n transform: translate(-50%, -50%) scale(1) !important;\n }\n .sc-loading-hidden .sc-loading-indicator {\n display: none !important;\n }\n "
6475
6517
  }),
6476
6518
  /* @__PURE__ */ jsxs("div", {
6477
6519
  ref: wrapperRef,
@@ -6489,6 +6531,7 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
6489
6531
  width: isFullscreen ? "100vw" : "100%",
6490
6532
  height: isFullscreen ? "100vh" : "auto",
6491
6533
  minHeight: isFullscreen ? "100vh" : "auto",
6534
+ aspectRatio: isFullscreen ? void 0 : playerAspectRatio,
6492
6535
  maxWidth: isFullscreen ? "100vw" : "100%",
6493
6536
  maxHeight: isFullscreen ? "100vh" : "none",
6494
6537
  zIndex: isFullscreen ? 999999 : void 0,
@@ -6503,7 +6546,7 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
6503
6546
  style: _object_spread({
6504
6547
  display: "block",
6505
6548
  width: "100%",
6506
- height: isFullscreen ? "100%" : "auto",
6549
+ height: "100%",
6507
6550
  maxWidth: "100%",
6508
6551
  maxHeight: isFullscreen ? "100%" : "none",
6509
6552
  objectFit: isFullscreen ? "cover" : "contain",
@@ -6517,18 +6560,44 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
6517
6560
  }, restVideoAttrs), {
6518
6561
  children: children
6519
6562
  })),
6520
- (isLoading || isBuffering) && !hideLoadingIndicator && /* @__PURE__ */ jsx(FaSpinner, {
6563
+ (isLoading || isBuffering) && !hideLoadingIndicator && /* @__PURE__ */ jsxs("div", {
6521
6564
  className: "sc-loading-indicator",
6522
- size: 40,
6523
- color: "rgba(255, 255, 255, 0.85)",
6524
6565
  style: {
6525
6566
  position: "absolute",
6526
- top: "calc(50% - 20px)",
6527
- left: "calc(50% - 20px)",
6567
+ top: "50%",
6568
+ left: "50%",
6569
+ transform: "translate(-50%, -50%)",
6528
6570
  zIndex: 20,
6529
- animation: "sc-spin 0.9s linear infinite",
6530
- filter: "drop-shadow(0 2px 8px rgba(0, 0, 0, 0.6))"
6531
- }
6571
+ width: "".concat(Math.max(34, 38 * responsiveScale), "px"),
6572
+ height: "".concat(Math.max(34, 38 * responsiveScale), "px"),
6573
+ display: "flex",
6574
+ alignItems: "center",
6575
+ justifyContent: "center",
6576
+ animation: "sc-loading-glow 1.4s ease-in-out infinite",
6577
+ filter: "drop-shadow(0 6px 14px rgba(0, 0, 0, 0.55))"
6578
+ },
6579
+ children: [
6580
+ /* @__PURE__ */ jsx("div", {
6581
+ style: {
6582
+ position: "absolute",
6583
+ inset: 0,
6584
+ borderRadius: "50%",
6585
+ border: "3px solid rgba(255, 255, 255, 0.25)",
6586
+ borderTopColor: "#ff0000",
6587
+ borderRightColor: "rgba(255, 255, 255, 0.85)",
6588
+ animation: "sc-spin 0.8s linear infinite"
6589
+ }
6590
+ }),
6591
+ /* @__PURE__ */ jsx("div", {
6592
+ style: {
6593
+ width: "7px",
6594
+ height: "7px",
6595
+ borderRadius: "50%",
6596
+ background: "#ff0000",
6597
+ boxShadow: "0 0 10px rgba(255, 0, 0, 0.65)"
6598
+ }
6599
+ })
6600
+ ]
6532
6601
  }),
6533
6602
  showLicenseWarning && /* @__PURE__ */ jsxs("div", {
6534
6603
  style: {
@@ -6764,7 +6833,8 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
6764
6833
  /* @__PURE__ */ jsxs("div", {
6765
6834
  style: {
6766
6835
  display: "flex",
6767
- alignItems: "center"
6836
+ alignItems: "center",
6837
+ paddingRight: "".concat(6 * responsiveScale, "px")
6768
6838
  },
6769
6839
  onMouseEnter: function onMouseEnter() {
6770
6840
  return setShowVolumeSlider(true);
@@ -6795,13 +6865,13 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
6795
6865
  }),
6796
6866
  /* @__PURE__ */ jsx("div", {
6797
6867
  style: {
6798
- width: showVolumeSlider ? "".concat(62 * responsiveScale, "px") : "0px",
6868
+ width: showVolumeSlider ? "".concat(68 * responsiveScale, "px") : "0px",
6799
6869
  overflow: "hidden",
6800
6870
  transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
6801
6871
  display: "flex",
6802
6872
  alignItems: "center",
6803
- paddingLeft: showVolumeSlider ? "2px" : "0",
6804
- paddingRight: showVolumeSlider ? "4px" : "0"
6873
+ paddingLeft: showVolumeSlider ? "".concat(3 * responsiveScale, "px") : "0",
6874
+ paddingRight: showVolumeSlider ? "".concat(8 * responsiveScale, "px") : "0"
6805
6875
  },
6806
6876
  children: /* @__PURE__ */ jsxs("div", {
6807
6877
  style: {
@@ -7048,7 +7118,8 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
7048
7118
  alignItems: "center",
7049
7119
  background: "rgba(0, 0, 0, 0.6)",
7050
7120
  borderRadius: "".concat(18 * responsiveScale, "px"),
7051
- padding: "2px"
7121
+ padding: "2px",
7122
+ paddingRight: "".concat(8 * responsiveScale, "px")
7052
7123
  },
7053
7124
  onMouseEnter: function onMouseEnter() {
7054
7125
  return setShowVolumeSlider(true);
@@ -7077,13 +7148,13 @@ var StormcloudVideoPlayerComponent = React.memo(function(props) {
7077
7148
  }),
7078
7149
  /* @__PURE__ */ jsx("div", {
7079
7150
  style: {
7080
- width: showVolumeSlider ? "".concat(62 * responsiveScale, "px") : "0px",
7151
+ width: showVolumeSlider ? "".concat(68 * responsiveScale, "px") : "0px",
7081
7152
  overflow: "hidden",
7082
7153
  transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
7083
7154
  display: "flex",
7084
7155
  alignItems: "center",
7085
- paddingLeft: showVolumeSlider ? "2px" : "0",
7086
- paddingRight: showVolumeSlider ? "6px" : "0"
7156
+ paddingLeft: showVolumeSlider ? "".concat(3 * responsiveScale, "px") : "0",
7157
+ paddingRight: showVolumeSlider ? "".concat(10 * responsiveScale, "px") : "0"
7087
7158
  },
7088
7159
  children: /* @__PURE__ */ jsxs("div", {
7089
7160
  style: {