stormcloud-video-player 0.8.2 → 0.8.4

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.
Files changed (36) hide show
  1. package/dist/stormcloud-vp.min.js +3 -1
  2. package/lib/index.cjs +536 -341
  3. package/lib/index.cjs.map +1 -1
  4. package/lib/index.d.cts +37 -2
  5. package/lib/index.d.ts +37 -2
  6. package/lib/index.js +477 -342
  7. package/lib/index.js.map +1 -1
  8. package/lib/player/StormcloudVideoPlayer.cjs +266 -206
  9. package/lib/player/StormcloudVideoPlayer.cjs.map +1 -1
  10. package/lib/player/StormcloudVideoPlayer.d.cts +5 -2
  11. package/lib/players/FilePlayer.cjs.map +1 -1
  12. package/lib/players/HlsPlayer.cjs +266 -206
  13. package/lib/players/HlsPlayer.cjs.map +1 -1
  14. package/lib/players/HlsPlayer.d.cts +1 -1
  15. package/lib/players/index.cjs +266 -206
  16. package/lib/players/index.cjs.map +1 -1
  17. package/lib/sdk/hlsAdPlayer.cjs.map +1 -1
  18. package/lib/sdk/hlsAdPlayer.d.cts +1 -1
  19. package/lib/sdk/pal.cjs.map +1 -1
  20. package/lib/{types-DDwAfBLt.d.cts → types-BmF_60m2.d.cts} +2 -0
  21. package/lib/ui/StormcloudVideoPlayer.cjs +450 -341
  22. package/lib/ui/StormcloudVideoPlayer.cjs.map +1 -1
  23. package/lib/ui/StormcloudVideoPlayer.d.cts +1 -1
  24. package/lib/utils/browserCompat.cjs.map +1 -1
  25. package/lib/utils/mqttClient.cjs +245 -0
  26. package/lib/utils/mqttClient.cjs.map +1 -0
  27. package/lib/utils/mqttClient.d.cts +13 -0
  28. package/lib/utils/mqttConfig.cjs +141 -0
  29. package/lib/utils/mqttConfig.cjs.map +1 -0
  30. package/lib/utils/mqttConfig.d.cts +20 -0
  31. package/lib/utils/polyfills.cjs.map +1 -1
  32. package/lib/utils/tracking.cjs +182 -170
  33. package/lib/utils/tracking.cjs.map +1 -1
  34. package/lib/utils/tracking.d.cts +1 -1
  35. package/package.json +3 -1
  36. package/src/certs/emqxsl-ca.crt +22 -0
@@ -1371,6 +1371,99 @@ function createPalNonceManager() {
1371
1371
  }
1372
1372
  };
1373
1373
  }
1374
+ // src/utils/mqttConfig.ts
1375
+ var DEFAULT_MQTT_CONFIG = {
1376
+ enabled: true,
1377
+ brokerAddress: "vecbae77.ala.us-east-1.emqxsl.com",
1378
+ brokerPort: 8883,
1379
+ wsPort: 8084,
1380
+ username: "for-sonifi",
1381
+ password: "sonifi-mqtt",
1382
+ topicPrefix: "adstorm/players",
1383
+ qos: 1
1384
+ };
1385
+ var mqttConfig = _object_spread({}, DEFAULT_MQTT_CONFIG);
1386
+ function isMQTTEnabled() {
1387
+ return mqttConfig.enabled;
1388
+ }
1389
+ function buildMQTTBrokerUrl() {
1390
+ if (mqttConfig.brokerUrl) return mqttConfig.brokerUrl;
1391
+ return "wss://".concat(mqttConfig.brokerAddress, ":").concat(mqttConfig.wsPort, "/mqtt");
1392
+ }
1393
+ function buildPlayerTopic(licenseKey, channel) {
1394
+ return "".concat(mqttConfig.topicPrefix, "/").concat(licenseKey, "/").concat(channel);
1395
+ }
1396
+ // src/utils/mqttClient.ts
1397
+ var import_mqtt = __toESM(require("mqtt"), 1);
1398
+ var LOG = "[StormcloudVideoPlayer][MQTT]";
1399
+ var client = null;
1400
+ var status = "disconnected";
1401
+ function initMQTTClient() {
1402
+ if (client || !isMQTTEnabled()) return;
1403
+ var url = buildMQTTBrokerUrl();
1404
+ status = "connecting";
1405
+ var clientId = "stormcloud-vp-".concat(Math.random().toString(36).slice(2, 9));
1406
+ try {
1407
+ client = import_mqtt.default.connect(url, {
1408
+ clientId: clientId,
1409
+ username: mqttConfig.username,
1410
+ password: mqttConfig.password,
1411
+ keepalive: 60,
1412
+ clean: true,
1413
+ reconnectPeriod: 5e3,
1414
+ connectTimeout: 1e4,
1415
+ queueQoSZero: false
1416
+ });
1417
+ } catch (err) {
1418
+ status = "error";
1419
+ console.warn("".concat(LOG, " connect() threw:"), err);
1420
+ return;
1421
+ }
1422
+ client.on("connect", function() {
1423
+ status = "connected";
1424
+ console.info("".concat(LOG, " connected to ").concat(url));
1425
+ });
1426
+ client.on("reconnect", function() {
1427
+ status = "connecting";
1428
+ console.info("".concat(LOG, " reconnecting…"));
1429
+ });
1430
+ client.on("offline", function() {
1431
+ status = "disconnected";
1432
+ console.warn("".concat(LOG, " offline"));
1433
+ });
1434
+ client.on("error", function(err) {
1435
+ status = "error";
1436
+ console.warn("".concat(LOG, " error:"), err.message);
1437
+ });
1438
+ client.on("close", function() {
1439
+ if (status === "connected") {
1440
+ status = "disconnected";
1441
+ }
1442
+ });
1443
+ }
1444
+ function ensureMQTTClient() {
1445
+ if (isMQTTEnabled() && !client) {
1446
+ initMQTTClient();
1447
+ }
1448
+ }
1449
+ function publishMQTT(topic, payload) {
1450
+ if (!isMQTTEnabled()) {
1451
+ return false;
1452
+ }
1453
+ ensureMQTTClient();
1454
+ if (!client) {
1455
+ return false;
1456
+ }
1457
+ try {
1458
+ client.publish(topic, JSON.stringify(payload), {
1459
+ qos: mqttConfig.qos
1460
+ });
1461
+ return true;
1462
+ } catch (err) {
1463
+ console.warn("".concat(LOG, " publish failed on ").concat(topic, ":"), err);
1464
+ return false;
1465
+ }
1466
+ }
1374
1467
  // src/utils/tracking.ts
1375
1468
  var cachedBrowserId = null;
1376
1469
  function getClientInfo() {
@@ -1517,7 +1610,7 @@ function getClientInfo() {
1517
1610
  }
1518
1611
  function getBrowserID(clientInfo) {
1519
1612
  return _async_to_generator(function() {
1520
- var fingerprintString, encodedData, utf8, buffer, i, hashBuffer, hashArray, hashHex, error, hash, i1, char, fallbackHash, timestamp, random;
1613
+ var _crypto_subtle, fingerprintString, encodedData, utf8, buffer, i, hashBuffer, hashHex, unused, hash, i1, char, fallbackHash, timestamp, random;
1521
1614
  return _ts_generator(this, function(_state) {
1522
1615
  switch(_state.label){
1523
1616
  case 0:
@@ -1528,7 +1621,7 @@ function getBrowserID(clientInfo) {
1528
1621
  ];
1529
1622
  }
1530
1623
  fingerprintString = JSON.stringify(clientInfo);
1531
- if (!(typeof crypto !== "undefined" && crypto.subtle && crypto.subtle.digest)) return [
1624
+ if (!(typeof crypto !== "undefined" && ((_crypto_subtle = crypto.subtle) === null || _crypto_subtle === void 0 ? void 0 : _crypto_subtle.digest))) return [
1532
1625
  3,
1533
1626
  5
1534
1627
  ];
@@ -1566,8 +1659,7 @@ function getBrowserID(clientInfo) {
1566
1659
  ];
1567
1660
  case 3:
1568
1661
  hashBuffer = _state.sent();
1569
- hashArray = Array.from(new Uint8Array(hashBuffer));
1570
- hashHex = hashArray.map(function(b) {
1662
+ hashHex = Array.from(new Uint8Array(hashBuffer)).map(function(b) {
1571
1663
  return b.toString(16).padStart(2, "0");
1572
1664
  }).join("");
1573
1665
  cachedBrowserId = hashHex;
@@ -1576,8 +1668,8 @@ function getBrowserID(clientInfo) {
1576
1668
  hashHex
1577
1669
  ];
1578
1670
  case 4:
1579
- error = _state.sent();
1580
- console.warn("[StormcloudVideoPlayer] crypto.subtle.digest not supported, using fallback hash");
1671
+ unused = _state.sent();
1672
+ console.warn("[StormcloudVideoPlayer] crypto.subtle not supported, using fallback hash");
1581
1673
  return [
1582
1674
  3,
1583
1675
  5
@@ -1601,177 +1693,91 @@ function getBrowserID(clientInfo) {
1601
1693
  });
1602
1694
  })();
1603
1695
  }
1604
- var PLAYER_TRACKING_BASE_URL = "https://adstorm.co/api-adstorm-dev/adstorm/player-tracking";
1605
- var TRACK_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/metrics/ingest");
1606
- var HEARTBEAT_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/heartbeat");
1607
- var IMPRESSIONS_URL = "".concat(PLAYER_TRACKING_BASE_URL, "/impressions/ingest");
1608
- function buildHeaders(licenseKey) {
1609
- var headers = {
1610
- "Content-Type": "application/json"
1611
- };
1612
- if (licenseKey) {
1613
- headers["Authorization"] = "Bearer ".concat(licenseKey);
1614
- }
1615
- return headers;
1616
- }
1617
- function sendTrackRequest(licenseKey, body) {
1618
- return _async_to_generator(function() {
1619
- var response;
1620
- return _ts_generator(this, function(_state) {
1621
- switch(_state.label){
1622
- case 0:
1623
- return [
1624
- 4,
1625
- fetch(TRACK_URL, {
1626
- method: "POST",
1627
- headers: buildHeaders(licenseKey),
1628
- body: JSON.stringify(body)
1629
- })
1630
- ];
1631
- case 1:
1632
- response = _state.sent();
1633
- if (!response.ok) {
1634
- throw new Error("HTTP error! status: ".concat(response.status));
1635
- }
1636
- return [
1637
- 4,
1638
- response.json()
1639
- ];
1640
- case 2:
1641
- _state.sent();
1642
- return [
1643
- 2
1644
- ];
1645
- }
1646
- });
1647
- })();
1696
+ function canPublish(licenseKey) {
1697
+ return Boolean(isMQTTEnabled() && licenseKey);
1648
1698
  }
1649
- function postJson(url, licenseKey, body) {
1699
+ function buildPlayerMetricEvent() {
1650
1700
  return _async_to_generator(function() {
1651
- var response;
1652
- return _ts_generator(this, function(_state) {
1653
- switch(_state.label){
1654
- case 0:
1655
- return [
1656
- 4,
1657
- fetch(url, {
1658
- method: "POST",
1659
- headers: buildHeaders(licenseKey),
1660
- body: JSON.stringify(body)
1661
- })
1662
- ];
1663
- case 1:
1664
- response = _state.sent();
1665
- if (!response.ok) {
1666
- throw new Error("HTTP error! status: ".concat(response.status));
1667
- }
1668
- return [
1669
- 4,
1670
- response.json()
1671
- ];
1672
- case 2:
1673
- _state.sent();
1674
- return [
1675
- 2
1676
- ];
1677
- }
1678
- });
1679
- })();
1680
- }
1681
- function buildPlayerMetricEvent(_0) {
1682
- return _async_to_generator(function(licenseKey) {
1683
- var context, flags, _flags_captureAt, clientInfo, browserId, captureAt;
1701
+ var context, flags, _flags_captureAt, _flags_adLoaded, _flags_adDetect, clientInfo, playerId, captureAt;
1684
1702
  var _arguments = arguments;
1685
1703
  return _ts_generator(this, function(_state) {
1686
1704
  switch(_state.label){
1687
1705
  case 0:
1688
- context = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {}, flags = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : {};
1706
+ context = _arguments.length > 0 && _arguments[0] !== void 0 ? _arguments[0] : {}, flags = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {};
1689
1707
  clientInfo = getClientInfo();
1690
1708
  return [
1691
1709
  4,
1692
1710
  getBrowserID(clientInfo)
1693
1711
  ];
1694
1712
  case 1:
1695
- browserId = _state.sent();
1713
+ playerId = _state.sent();
1696
1714
  captureAt = (_flags_captureAt = flags.captureAt) !== null && _flags_captureAt !== void 0 ? _flags_captureAt : /* @__PURE__ */ new Date().toISOString();
1697
1715
  return [
1698
1716
  2,
1699
- {
1700
- player_id: browserId,
1701
- browserId: browserId,
1717
+ _object_spread({
1718
+ player_id: playerId,
1702
1719
  device_type: clientInfo.deviceType,
1703
- deviceType: clientInfo.deviceType,
1704
- input_stream_type: context.inputStreamType,
1705
- os: clientInfo.os,
1706
- ad_loaded: flags.adLoaded,
1707
- ad_detect: flags.adDetect,
1708
- license_key: licenseKey,
1709
- capture_at: captureAt,
1710
- timestamp: captureAt
1711
- }
1720
+ os: clientInfo.os.toLowerCase(),
1721
+ ad_loaded: (_flags_adLoaded = flags.adLoaded) !== null && _flags_adLoaded !== void 0 ? _flags_adLoaded : false,
1722
+ ad_detect: (_flags_adDetect = flags.adDetect) !== null && _flags_adDetect !== void 0 ? _flags_adDetect : false,
1723
+ capture_at: captureAt
1724
+ }, context.inputStreamType ? {
1725
+ input_stream_type: context.inputStreamType
1726
+ } : {})
1712
1727
  ];
1713
1728
  }
1714
1729
  });
1715
1730
  }).apply(this, arguments);
1716
1731
  }
1732
+ function publishTracking(licenseKey, channel, body) {
1733
+ ensureMQTTClient();
1734
+ publishMQTT(buildPlayerTopic(licenseKey, channel), body);
1735
+ }
1717
1736
  function sendInitialTracking(_0) {
1718
1737
  return _async_to_generator(function(licenseKey) {
1719
- var context, clientInfo, browserId, trackingData, error;
1738
+ var context, metricEvent, error;
1720
1739
  var _arguments = arguments;
1721
1740
  return _ts_generator(this, function(_state) {
1722
1741
  switch(_state.label){
1723
1742
  case 0:
1724
1743
  context = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {};
1744
+ if (!canPublish(licenseKey)) return [
1745
+ 2
1746
+ ];
1725
1747
  _state.label = 1;
1726
1748
  case 1:
1727
1749
  _state.trys.push([
1728
1750
  1,
1729
- 4,
1751
+ 3,
1730
1752
  ,
1731
- 5
1753
+ 4
1732
1754
  ]);
1733
- clientInfo = getClientInfo();
1734
1755
  return [
1735
1756
  4,
1736
- getBrowserID(clientInfo)
1737
- ];
1738
- case 2:
1739
- browserId = _state.sent();
1740
- trackingData = _object_spread({
1741
- browserId: browserId
1742
- }, clientInfo);
1743
- return [
1744
- 4,
1745
- sendTrackRequest(licenseKey, {
1746
- events: [
1747
- {
1748
- player_id: browserId,
1749
- device_type: clientInfo.deviceType,
1750
- input_stream_type: context.inputStreamType,
1751
- os: clientInfo.os,
1752
- ad_loaded: false,
1753
- ad_detect: false,
1754
- license_key: licenseKey,
1755
- capture_at: /* @__PURE__ */ new Date().toISOString()
1756
- }
1757
- ],
1758
- trackingData: trackingData
1757
+ buildPlayerMetricEvent(context, {
1758
+ adLoaded: false,
1759
+ adDetect: false
1759
1760
  })
1760
1761
  ];
1761
- case 3:
1762
- _state.sent();
1762
+ case 2:
1763
+ metricEvent = _state.sent();
1764
+ publishTracking(licenseKey, "metrics", {
1765
+ events: [
1766
+ metricEvent
1767
+ ]
1768
+ });
1763
1769
  return [
1764
1770
  3,
1765
- 5
1771
+ 4
1766
1772
  ];
1767
- case 4:
1773
+ case 3:
1768
1774
  error = _state.sent();
1769
1775
  console.error("[StormcloudVideoPlayer] Error sending initial tracking data:", error);
1770
1776
  return [
1771
1777
  3,
1772
- 5
1778
+ 4
1773
1779
  ];
1774
- case 5:
1780
+ case 4:
1775
1781
  return [
1776
1782
  2
1777
1783
  ];
@@ -1875,53 +1881,48 @@ function sendAdImpressionTracking(_0, _1) {
1875
1881
  switch(_state.label){
1876
1882
  case 0:
1877
1883
  context = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : {};
1884
+ if (!canPublish(licenseKey)) return [
1885
+ 2
1886
+ ];
1878
1887
  _state.label = 1;
1879
1888
  case 1:
1880
1889
  _state.trys.push([
1881
1890
  1,
1882
- 4,
1891
+ 3,
1883
1892
  ,
1884
- 5
1893
+ 4
1885
1894
  ]);
1886
1895
  return [
1887
1896
  4,
1888
- buildPlayerMetricEvent(licenseKey, context, {
1897
+ buildPlayerMetricEvent(context, {
1889
1898
  captureAt: adImpressionInfo.timestamp
1890
1899
  })
1891
1900
  ];
1892
1901
  case 2:
1893
1902
  metricEvent = _state.sent();
1894
- return [
1895
- 4,
1896
- Promise.all([
1897
- postJson(HEARTBEAT_URL, licenseKey, metricEvent),
1898
- postJson(IMPRESSIONS_URL, licenseKey, {
1899
- events: [
1900
- {
1901
- player_id: metricEvent.player_id,
1902
- ad_played_count: 1,
1903
- ad_url: adImpressionInfo.adUrl,
1904
- license_key: licenseKey,
1905
- capture_at: adImpressionInfo.timestamp
1906
- }
1907
- ]
1908
- })
1909
- ])
1910
- ];
1911
- case 3:
1912
- _state.sent();
1903
+ publishTracking(licenseKey, "heartbeat", metricEvent);
1904
+ publishTracking(licenseKey, "impressions", {
1905
+ events: [
1906
+ {
1907
+ player_id: metricEvent.player_id,
1908
+ ad_played_count: 1,
1909
+ ad_url: adImpressionInfo.adUrl,
1910
+ capture_at: adImpressionInfo.timestamp
1911
+ }
1912
+ ]
1913
+ });
1913
1914
  return [
1914
1915
  3,
1915
- 5
1916
+ 4
1916
1917
  ];
1917
- case 4:
1918
+ case 3:
1918
1919
  error = _state.sent();
1919
1920
  console.error("[StormcloudVideoPlayer] Error sending ad impression tracking:", error);
1920
1921
  return [
1921
1922
  3,
1922
- 5
1923
+ 4
1923
1924
  ];
1924
- case 5:
1925
+ case 4:
1925
1926
  return [
1926
1927
  2
1927
1928
  ];
@@ -1937,38 +1938,36 @@ function sendHeartbeat(_0) {
1937
1938
  switch(_state.label){
1938
1939
  case 0:
1939
1940
  context = _arguments.length > 1 && _arguments[1] !== void 0 ? _arguments[1] : {}, flags = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : {};
1941
+ if (!canPublish(licenseKey)) return [
1942
+ 2
1943
+ ];
1940
1944
  _state.label = 1;
1941
1945
  case 1:
1942
1946
  _state.trys.push([
1943
1947
  1,
1944
- 4,
1948
+ 3,
1945
1949
  ,
1946
- 5
1950
+ 4
1947
1951
  ]);
1948
1952
  return [
1949
1953
  4,
1950
- buildPlayerMetricEvent(licenseKey, context, flags)
1954
+ buildPlayerMetricEvent(context, flags)
1951
1955
  ];
1952
1956
  case 2:
1953
1957
  heartbeatData = _state.sent();
1954
- return [
1955
- 4,
1956
- postJson(HEARTBEAT_URL, licenseKey, heartbeatData)
1957
- ];
1958
- case 3:
1959
- _state.sent();
1958
+ publishTracking(licenseKey, "heartbeat", heartbeatData);
1960
1959
  return [
1961
1960
  3,
1962
- 5
1961
+ 4
1963
1962
  ];
1964
- case 4:
1963
+ case 3:
1965
1964
  error = _state.sent();
1966
1965
  console.error("[StormcloudVideoPlayer] Error sending heartbeat:", error);
1967
1966
  return [
1968
1967
  3,
1969
- 5
1968
+ 4
1970
1969
  ];
1971
- case 5:
1970
+ case 4:
1972
1971
  return [
1973
1972
  2
1974
1973
  ];
@@ -2481,7 +2480,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2481
2480
  key: "load",
2482
2481
  value: function load() {
2483
2482
  return _async_to_generator(function() {
2484
- var _this, _this_config_lowLatencyMode, error, _this_config_lowLatencyMode1, _this_video_play;
2483
+ var _this, _this_config_lowLatencyMode, error, _this_config_isLiveStream, _this_config_lowLatencyMode1, _this_video_play;
2485
2484
  return _ts_generator(this, function(_state) {
2486
2485
  switch(_state.label){
2487
2486
  case 0:
@@ -2532,7 +2531,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2532
2531
  this.nativeHlsMode = true;
2533
2532
  this.videoSrcProtection = this.config.src;
2534
2533
  this.video.src = this.config.src;
2535
- this.isLiveStream = (_this_config_lowLatencyMode1 = this.config.lowLatencyMode) !== null && _this_config_lowLatencyMode1 !== void 0 ? _this_config_lowLatencyMode1 : false;
2534
+ this.isLiveStream = (_this_config_isLiveStream = this.config.isLiveStream) !== null && _this_config_isLiveStream !== void 0 ? _this_config_isLiveStream : (_this_config_lowLatencyMode1 = this.config.lowLatencyMode) !== null && _this_config_lowLatencyMode1 !== void 0 ? _this_config_lowLatencyMode1 : false;
2536
2535
  if (this.config.debugAdTiming) {
2537
2536
  console.log("[StormcloudVideoPlayer] Using native HLS playback - VOD mode:", {
2538
2537
  isLive: this.isLiveStream,
@@ -2583,15 +2582,15 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
2583
2582
  });
2584
2583
  this.hls.on(import_hls2.default.Events.MANIFEST_PARSED, function(_, data) {
2585
2584
  return _async_to_generator(function() {
2586
- var _ref, _this_config_minSegmentsBeforePlay, _this_hls_levels, _this_hls, prerollKey, adBehavior, minSegments, _this_video_play;
2585
+ var _this_config_isLiveStream, _ref, _this_config_minSegmentsBeforePlay, _this_hls_levels, _this_hls, prerollKey, adBehavior, minSegments, _this_video_play;
2587
2586
  return _ts_generator(this, function(_state) {
2588
2587
  switch(_state.label){
2589
2588
  case 0:
2590
- this.isLiveStream = (_ref = (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : (_this_hls_levels = _this_hls.levels) === null || _this_hls_levels === void 0 ? void 0 : _this_hls_levels.some(function(level) {
2589
+ this.isLiveStream = (_this_config_isLiveStream = this.config.isLiveStream) !== null && _this_config_isLiveStream !== void 0 ? _this_config_isLiveStream : (_ref = (_this_hls = this.hls) === null || _this_hls === void 0 ? void 0 : (_this_hls_levels = _this_hls.levels) === null || _this_hls_levels === void 0 ? void 0 : _this_hls_levels.some(function(level) {
2591
2590
  var _level_details, _level_details1;
2592
2591
  return (level === null || level === void 0 ? void 0 : (_level_details = level.details) === null || _level_details === void 0 ? void 0 : _level_details.live) === true || (level === null || level === void 0 ? void 0 : (_level_details1 = level.details) === null || _level_details1 === void 0 ? void 0 : _level_details1.type) === "LIVE";
2593
2592
  })) !== null && _ref !== void 0 ? _ref : false;
2594
- if (!this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
2593
+ if (!this.isVmapEnabled() && !this.isLiveStream && this.vmapBreaks.length === 0 && this.apiVastTagUrl) {
2595
2594
  prerollKey = "synthetic-vod-preroll";
2596
2595
  if (!this.consumedVmapBreakIds.has(prerollKey)) {
2597
2596
  this.vmapBreaks = [
@@ -3176,12 +3175,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
3176
3175
  _this.palNonce.sendPlaybackStart();
3177
3176
  }
3178
3177
  });
3179
- this.video.addEventListener("ended", function() {
3178
+ this.endedHandler = function() {
3180
3179
  if (_this.palPlaybackStarted) {
3181
3180
  _this.palPlaybackStarted = false;
3182
3181
  _this.palNonce.sendPlaybackEnd();
3183
3182
  }
3184
- });
3183
+ _this.onVideoEnded();
3184
+ };
3185
+ this.video.addEventListener("ended", this.endedHandler);
3185
3186
  this.video.addEventListener("mousedown", function(e) {
3186
3187
  _this.palNonce.sendAdTouch(e);
3187
3188
  });
@@ -4503,6 +4504,13 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4503
4504
  }
4504
4505
  }
4505
4506
  },
4507
+ {
4508
+ key: "isVmapEnabled",
4509
+ value: function isVmapEnabled() {
4510
+ var _this_config_vmapUrl;
4511
+ return !!(this.config.isVmap && ((_this_config_vmapUrl = this.config.vmapUrl) === null || _this_config_vmapUrl === void 0 ? void 0 : _this_config_vmapUrl.trim()));
4512
+ }
4513
+ },
4506
4514
  {
4507
4515
  key: "fetchAdConfiguration",
4508
4516
  value: function fetchAdConfiguration() {
@@ -4511,7 +4519,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4511
4519
  return _ts_generator(this, function(_state) {
4512
4520
  switch(_state.label){
4513
4521
  case 0:
4514
- if (!this.config.vmapUrl) return [
4522
+ if (!this.isVmapEnabled()) return [
4515
4523
  3,
4516
4524
  2
4517
4525
  ];
@@ -4521,7 +4529,12 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4521
4529
  ];
4522
4530
  case 1:
4523
4531
  _state.sent();
4524
- _state.label = 2;
4532
+ if (this.config.debugAdTiming) {
4533
+ console.log("[StormcloudVideoPlayer] VMAP mode enabled");
4534
+ }
4535
+ return [
4536
+ 2
4537
+ ];
4525
4538
  case 2:
4526
4539
  vastMode = this.config.vastMode || "default";
4527
4540
  if (this.config.debugAdTiming) {
@@ -4689,7 +4702,16 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4689
4702
  }
4690
4703
  return [];
4691
4704
  }
4692
- var adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
4705
+ var VMAP_NS = "http://www.iab.net/videosuite/vmap";
4706
+ var adBreakNodes = Array.from(doc.getElementsByTagNameNS(VMAP_NS, "AdBreak"));
4707
+ if (adBreakNodes.length === 0) {
4708
+ adBreakNodes = Array.from(doc.querySelectorAll("AdBreak, vmap\\:AdBreak"));
4709
+ }
4710
+ if (adBreakNodes.length === 0) {
4711
+ adBreakNodes = Array.from(doc.getElementsByTagName("*")).filter(function(el) {
4712
+ return el.localName === "AdBreak";
4713
+ });
4714
+ }
4693
4715
  var parsed = [];
4694
4716
  adBreakNodes.forEach(function(node, index) {
4695
4717
  var timeOffsetRaw = (node.getAttribute("timeOffset") || "").trim();
@@ -4697,7 +4719,11 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
4697
4719
  if (startTimeMs == null) {
4698
4720
  return;
4699
4721
  }
4700
- var adTagNode = node.querySelector("AdTagURI, vmap\\:AdTagURI");
4722
+ var adTagNode = node.getElementsByTagNameNS(VMAP_NS, "AdTagURI")[0];
4723
+ if (!adTagNode) {
4724
+ var _node_querySelector;
4725
+ adTagNode = (_node_querySelector = node.querySelector("AdTagURI, vmap\\:AdTagURI")) !== null && _node_querySelector !== void 0 ? _node_querySelector : void 0;
4726
+ }
4701
4727
  var adTagUrl = ((adTagNode === null || adTagNode === void 0 ? void 0 : adTagNode.textContent) || "").trim();
4702
4728
  if (!adTagUrl) {
4703
4729
  return;
@@ -6254,23 +6280,49 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6254
6280
  key: "onTimeUpdate",
6255
6281
  value: function onTimeUpdate(currentTimeSec) {
6256
6282
  var _this = this;
6283
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
6284
+ return;
6285
+ }
6257
6286
  if (this.adPlayer.isAdPlaying() || this.inAdBreak) return;
6258
6287
  var nowMs = currentTimeSec * 1e3;
6259
6288
  var breakToPlay = this.findBreakForTime(nowMs);
6260
6289
  if (breakToPlay) {
6261
- void this.handleMidAdJoin(breakToPlay, nowMs).catch(function(error) {
6290
+ void this.handleVmapAdBreak(breakToPlay, nowMs).catch(function(error) {
6291
+ if (_this.config.debugAdTiming) {
6292
+ console.warn("[StormcloudVideoPlayer] VMAP ad break failed gracefully:", error);
6293
+ }
6294
+ });
6295
+ }
6296
+ }
6297
+ },
6298
+ {
6299
+ key: "onVideoEnded",
6300
+ value: function onVideoEnded() {
6301
+ var _this = this;
6302
+ if (!this.isVmapEnabled() || this.vmapBreaks.length === 0) {
6303
+ return;
6304
+ }
6305
+ if (this.adPlayer.isAdPlaying() || this.inAdBreak) {
6306
+ return;
6307
+ }
6308
+ var durationMs = Number.isFinite(this.video.duration) ? Math.floor(this.video.duration * 1e3) : 0;
6309
+ var postroll = this.vmapBreaks.find(function(b) {
6310
+ return b.startTimeMs === -1 && !_this.consumedVmapBreakIds.has(_this.getAdBreakKey(b));
6311
+ });
6312
+ if (postroll) {
6313
+ void this.handleVmapAdBreak(postroll, durationMs).catch(function(error) {
6262
6314
  if (_this.config.debugAdTiming) {
6263
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP join failed gracefully:", error);
6315
+ console.warn("[StormcloudVideoPlayer] VMAP post-roll failed gracefully:", error);
6264
6316
  }
6265
6317
  });
6266
6318
  }
6267
6319
  }
6268
6320
  },
6269
6321
  {
6270
- key: "handleMidAdJoin",
6271
- value: function handleMidAdJoin(adBreak, nowMs) {
6322
+ key: "handleVmapAdBreak",
6323
+ value: function handleVmapAdBreak(adBreak, nowMs) {
6272
6324
  return _async_to_generator(function() {
6273
- var _adBreak_durationMs, _this_config_driftToleranceMs, key, breakStartMs, durationMs, endMs, tol, inWindow, remainingMs, tags, first, rest, error;
6325
+ var _adBreak_durationMs, key, breakStartMs, durationMs, endMs, inWindow, tags, first, rest, error;
6274
6326
  return _ts_generator(this, function(_state) {
6275
6327
  switch(_state.label){
6276
6328
  case 0:
@@ -6288,25 +6340,28 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6288
6340
  }
6289
6341
  durationMs = (_adBreak_durationMs = adBreak.durationMs) !== null && _adBreak_durationMs !== void 0 ? _adBreak_durationMs : 0;
6290
6342
  endMs = breakStartMs + durationMs;
6291
- tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
6292
- inWindow = durationMs > 0 ? nowMs > breakStartMs && nowMs < endMs : nowMs + tol >= breakStartMs;
6343
+ inWindow = durationMs > 0 ? nowMs >= breakStartMs && nowMs < endMs : nowMs >= breakStartMs;
6293
6344
  if (!inWindow) return [
6294
6345
  3,
6295
6346
  4
6296
6347
  ];
6297
6348
  this.consumedVmapBreakIds.add(key);
6298
- remainingMs = durationMs > 0 ? Math.max(0, endMs - nowMs) : 0;
6299
- tags = this.selectVastTagsForBreak(adBreak) || (this.apiVastTagUrl ? [
6300
- this.apiVastTagUrl
6301
- ] : void 0);
6302
- if (!(tags && tags.length > 0)) return [
6303
- 3,
6304
- 4
6305
- ];
6349
+ tags = this.selectVastTagsForBreak(adBreak);
6350
+ if (!tags || tags.length === 0) {
6351
+ return [
6352
+ 2
6353
+ ];
6354
+ }
6306
6355
  first = tags[0];
6307
6356
  rest = tags.slice(1);
6308
6357
  this.adPodQueue = rest;
6309
6358
  this.adPlayer.updateOriginalMutedState(this.video.muted, this.video.volume);
6359
+ this.showAds = true;
6360
+ this.inAdBreak = true;
6361
+ this.currentAdBreakStartWallClockMs = Date.now();
6362
+ if (!this.video.paused) {
6363
+ this.video.pause();
6364
+ }
6310
6365
  _state.label = 1;
6311
6366
  case 1:
6312
6367
  _state.trys.push([
@@ -6321,10 +6376,6 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6321
6376
  ];
6322
6377
  case 2:
6323
6378
  _state.sent();
6324
- this.inAdBreak = true;
6325
- this.expectedAdBreakDurationMs = remainingMs;
6326
- this.currentAdBreakStartWallClockMs = Date.now();
6327
- this.scheduleAdStopCountdown(remainingMs);
6328
6379
  return [
6329
6380
  3,
6330
6381
  4
@@ -6332,8 +6383,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
6332
6383
  case 3:
6333
6384
  error = _state.sent();
6334
6385
  this.adPodQueue = [];
6386
+ this.inAdBreak = false;
6387
+ this.showAds = false;
6335
6388
  if (this.config.debugAdTiming) {
6336
- console.warn("[StormcloudVideoPlayer] Mid-roll VMAP ad request failed:", error);
6389
+ console.warn("[StormcloudVideoPlayer] VMAP ad request failed:", error);
6337
6390
  }
6338
6391
  return [
6339
6392
  3,
@@ -7045,9 +7098,7 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7045
7098
  {
7046
7099
  key: "findBreakForTime",
7047
7100
  value: function findBreakForTime(nowMs) {
7048
- var _this_config_driftToleranceMs;
7049
7101
  var schedule = this.vmapBreaks;
7050
- var tol = (_this_config_driftToleranceMs = this.config.driftToleranceMs) !== null && _this_config_driftToleranceMs !== void 0 ? _this_config_driftToleranceMs : 1e3;
7051
7102
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
7052
7103
  try {
7053
7104
  for(var _iterator = schedule[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
@@ -7059,9 +7110,14 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7059
7110
  if (breakStartMs == null) {
7060
7111
  continue;
7061
7112
  }
7062
- var end = breakStartMs + (b.durationMs || 0);
7063
- var effectiveTol = breakStartMs === 0 ? Math.max(tol, 3e4) : tol;
7064
- if (nowMs >= breakStartMs && (b.durationMs ? nowMs < end : nowMs <= breakStartMs + effectiveTol)) {
7113
+ if (b.durationMs) {
7114
+ var end = breakStartMs + b.durationMs;
7115
+ if (nowMs >= breakStartMs && nowMs < end) {
7116
+ return b;
7117
+ }
7118
+ continue;
7119
+ }
7120
+ if (nowMs >= breakStartMs) {
7065
7121
  return b;
7066
7122
  }
7067
7123
  }
@@ -7269,6 +7325,10 @@ var StormcloudVideoPlayer = /*#__PURE__*/ function() {
7269
7325
  this.video.removeEventListener("timeupdate", this.timeUpdateHandler);
7270
7326
  delete this.timeUpdateHandler;
7271
7327
  }
7328
+ if (this.endedHandler) {
7329
+ this.video.removeEventListener("ended", this.endedHandler);
7330
+ delete this.endedHandler;
7331
+ }
7272
7332
  if (this.emptiedHandler) {
7273
7333
  this.video.removeEventListener("emptied", this.emptiedHandler);
7274
7334
  delete this.emptiedHandler;
@@ -7297,7 +7357,9 @@ var import_jsx_runtime = require("react/jsx-runtime");
7297
7357
  var CRITICAL_PROPS = [
7298
7358
  "src",
7299
7359
  "allowNativeHls",
7360
+ "isLiveStream",
7300
7361
  "licenseKey",
7362
+ "isVmap",
7301
7363
  "vmapUrl",
7302
7364
  "lowLatencyMode",
7303
7365
  "driftToleranceMs",
@@ -7306,12 +7368,13 @@ var CRITICAL_PROPS = [
7306
7368
  var CONTROLS_HIDE_DELAY = 3e3;
7307
7369
  var DEFAULT_PLAYER_ASPECT_RATIO = 16 / 9;
7308
7370
  var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
7309
- 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, vastMode = props.vastMode, vastTagUrl = props.vastTagUrl, vmapUrl = props.vmapUrl, minSegmentsBeforePlay = props.minSegmentsBeforePlay, restVideoAttrs = _object_without_properties(props, [
7371
+ var src = props.src, autoplay = props.autoplay, muted = props.muted, lowLatencyMode = props.lowLatencyMode, allowNativeHls = props.allowNativeHls, isLiveStream = props.isLiveStream, 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, vastMode = props.vastMode, vastTagUrl = props.vastTagUrl, isVmap = props.isVmap, vmapUrl = props.vmapUrl, minSegmentsBeforePlay = props.minSegmentsBeforePlay, restVideoAttrs = _object_without_properties(props, [
7310
7372
  "src",
7311
7373
  "autoplay",
7312
7374
  "muted",
7313
7375
  "lowLatencyMode",
7314
7376
  "allowNativeHls",
7377
+ "isLiveStream",
7315
7378
  "driftToleranceMs",
7316
7379
  "immediateManifestAds",
7317
7380
  "debugAdTiming",
@@ -7333,6 +7396,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
7333
7396
  "licenseKey",
7334
7397
  "vastMode",
7335
7398
  "vastTagUrl",
7399
+ "isVmap",
7336
7400
  "vmapUrl",
7337
7401
  "minSegmentsBeforePlay"
7338
7402
  ]);
@@ -7465,7 +7529,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
7465
7529
  setShowSpeedMenu(false);
7466
7530
  };
7467
7531
  var isHlsStream = (src === null || src === void 0 ? void 0 : src.toLowerCase().includes(".m3u8")) || (src === null || src === void 0 ? void 0 : src.toLowerCase().includes("/hls/"));
7468
- var shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls : true);
7532
+ var shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls || isLiveStream === false : true);
7469
7533
  var criticalPropsKey = (0, import_react.useMemo)(function() {
7470
7534
  return CRITICAL_PROPS.map(function(prop) {
7471
7535
  return "".concat(prop, ":").concat(props[prop]);
@@ -7473,7 +7537,9 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
7473
7537
  }, [
7474
7538
  src,
7475
7539
  allowNativeHls,
7540
+ isLiveStream,
7476
7541
  licenseKey,
7542
+ isVmap,
7477
7543
  vmapUrl,
7478
7544
  lowLatencyMode,
7479
7545
  driftToleranceMs,
@@ -7507,6 +7573,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
7507
7573
  if (muted !== void 0) cfg.muted = muted;
7508
7574
  if (lowLatencyMode !== void 0) cfg.lowLatencyMode = lowLatencyMode;
7509
7575
  if (allowNativeHls !== void 0) cfg.allowNativeHls = allowNativeHls;
7576
+ if (isLiveStream !== void 0) cfg.isLiveStream = isLiveStream;
7510
7577
  if (driftToleranceMs !== void 0) cfg.driftToleranceMs = driftToleranceMs;
7511
7578
  if (immediateManifestAds !== void 0) cfg.immediateManifestAds = immediateManifestAds;
7512
7579
  if (debugAdTiming !== void 0) cfg.debugAdTiming = debugAdTiming;
@@ -7517,6 +7584,7 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
7517
7584
  if (licenseKey !== void 0) cfg.licenseKey = licenseKey;
7518
7585
  if (vastMode !== void 0) cfg.vastMode = vastMode;
7519
7586
  if (vastTagUrl !== void 0) cfg.vastTagUrl = vastTagUrl;
7587
+ if (isVmap !== void 0) cfg.isVmap = isVmap;
7520
7588
  if (vmapUrl !== void 0) cfg.vmapUrl = vmapUrl;
7521
7589
  if (minSegmentsBeforePlay !== void 0) cfg.minSegmentsBeforePlay = minSegmentsBeforePlay;
7522
7590
  var player = new StormcloudVideoPlayer(cfg);
@@ -8345,161 +8413,202 @@ var StormcloudVideoPlayerComponent = import_react.default.memo(function(props) {
8345
8413
  ]
8346
8414
  })
8347
8415
  ]
8348
- }) : showCustomControls && !showLicenseWarning && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
8349
- className: "sc-controls-bar",
8350
- style: {
8351
- position: "absolute",
8352
- bottom: "".concat(10 * responsiveScale, "px"),
8353
- right: "".concat(10 * responsiveScale, "px"),
8354
- display: "flex",
8355
- flexDirection: isPortrait ? "column" : "row",
8356
- gap: "".concat(8 * responsiveScale, "px"),
8357
- zIndex: 10,
8358
- opacity: controlsVisible ? 1 : 0,
8359
- transform: controlsVisible ? "translateY(0)" : "translateY(4px)",
8360
- pointerEvents: controlsVisible ? "auto" : "none"
8361
- },
8416
+ }) : showCustomControls && !showLicenseWarning && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, {
8362
8417
  children: [
8363
8418
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
8364
8419
  style: {
8420
+ position: "absolute",
8421
+ top: "".concat(10 * responsiveScale, "px"),
8422
+ left: "".concat(10 * responsiveScale, "px"),
8365
8423
  display: "flex",
8366
8424
  alignItems: "center",
8367
- background: "rgba(0, 0, 0, 0.6)",
8368
- borderRadius: "".concat(18 * responsiveScale, "px"),
8369
- padding: "2px",
8370
- paddingRight: "".concat(8 * responsiveScale, "px")
8371
- },
8372
- onMouseEnter: function onMouseEnter() {
8373
- return setShowVolumeSlider(true);
8425
+ gap: "6px",
8426
+ zIndex: 10,
8427
+ opacity: controlsVisible ? 1 : 0,
8428
+ transition: "opacity 0.35s ease"
8374
8429
  },
8375
- onMouseLeave: function onMouseLeave() {
8376
- return setShowVolumeSlider(false);
8430
+ children: [
8431
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8432
+ style: {
8433
+ width: "8px",
8434
+ height: "8px",
8435
+ borderRadius: "50%",
8436
+ background: "#ff3b30",
8437
+ animation: "sc-pulse 1.5s ease-in-out infinite",
8438
+ flexShrink: 0
8439
+ }
8440
+ }),
8441
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
8442
+ style: {
8443
+ fontSize: "".concat(12 * responsiveScale, "px"),
8444
+ fontFamily: "'SF Pro Display', 'Segoe UI', Arial, sans-serif",
8445
+ fontWeight: 700,
8446
+ letterSpacing: "0.08em",
8447
+ color: "#fff",
8448
+ textShadow: "0 1px 3px rgba(0,0,0,0.6)",
8449
+ userSelect: "none"
8450
+ },
8451
+ children: "LIVE"
8452
+ })
8453
+ ]
8454
+ }),
8455
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
8456
+ className: "sc-controls-bar",
8457
+ style: {
8458
+ position: "absolute",
8459
+ bottom: "".concat(10 * responsiveScale, "px"),
8460
+ right: "".concat(10 * responsiveScale, "px"),
8461
+ display: "flex",
8462
+ flexDirection: isPortrait ? "column" : "row",
8463
+ gap: "".concat(8 * responsiveScale, "px"),
8464
+ zIndex: 10,
8465
+ opacity: controlsVisible ? 1 : 0,
8466
+ transform: controlsVisible ? "translateY(0)" : "translateY(4px)",
8467
+ pointerEvents: controlsVisible ? "auto" : "none"
8377
8468
  },
8378
8469
  children: [
8470
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
8471
+ style: {
8472
+ display: "flex",
8473
+ alignItems: "center",
8474
+ background: "rgba(0, 0, 0, 0.6)",
8475
+ borderRadius: "".concat(18 * responsiveScale, "px"),
8476
+ padding: "2px",
8477
+ paddingRight: "".concat(8 * responsiveScale, "px")
8478
+ },
8479
+ onMouseEnter: function onMouseEnter() {
8480
+ return setShowVolumeSlider(true);
8481
+ },
8482
+ onMouseLeave: function onMouseLeave() {
8483
+ return setShowVolumeSlider(false);
8484
+ },
8485
+ children: [
8486
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
8487
+ className: "sc-ctrl-btn",
8488
+ onClick: function onClick() {
8489
+ if (playerRef.current) playerRef.current.toggleMute();
8490
+ onVolumeToggle === null || onVolumeToggle === void 0 ? void 0 : onVolumeToggle();
8491
+ resetControlsTimer();
8492
+ },
8493
+ style: {
8494
+ padding: "".concat(8 * responsiveScale, "px"),
8495
+ borderRadius: "50%",
8496
+ minWidth: "".concat(36 * responsiveScale, "px"),
8497
+ minHeight: "".concat(36 * responsiveScale, "px")
8498
+ },
8499
+ title: isMuted ? "Unmute" : "Mute",
8500
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VolumeIcon, {
8501
+ size: Math.max(14, 18 * responsiveScale)
8502
+ })
8503
+ }),
8504
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8505
+ style: {
8506
+ width: showVolumeSlider ? "".concat(68 * responsiveScale, "px") : "0px",
8507
+ overflow: "hidden",
8508
+ transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
8509
+ display: "flex",
8510
+ alignItems: "center",
8511
+ paddingLeft: showVolumeSlider ? "".concat(3 * responsiveScale, "px") : "0",
8512
+ paddingRight: showVolumeSlider ? "".concat(10 * responsiveScale, "px") : "0"
8513
+ },
8514
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
8515
+ style: {
8516
+ position: "relative",
8517
+ width: "".concat(56 * responsiveScale, "px"),
8518
+ height: "3px",
8519
+ cursor: "pointer",
8520
+ borderRadius: "1.5px"
8521
+ },
8522
+ onMouseDown: function onMouseDown(e) {
8523
+ e.preventDefault();
8524
+ var el = e.currentTarget;
8525
+ var move = function move(ev) {
8526
+ var r2 = el.getBoundingClientRect();
8527
+ handleVolumeChange(Math.max(0, Math.min(1, (ev.clientX - r2.left) / r2.width)));
8528
+ };
8529
+ var up = function up1() {
8530
+ document.removeEventListener("mousemove", move);
8531
+ document.removeEventListener("mouseup", up);
8532
+ };
8533
+ document.addEventListener("mousemove", move);
8534
+ document.addEventListener("mouseup", up);
8535
+ var r = el.getBoundingClientRect();
8536
+ handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
8537
+ },
8538
+ onClick: function onClick(e) {
8539
+ e.stopPropagation();
8540
+ var r = e.currentTarget.getBoundingClientRect();
8541
+ handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
8542
+ },
8543
+ children: [
8544
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8545
+ style: {
8546
+ position: "absolute",
8547
+ inset: 0,
8548
+ background: "rgba(255, 255, 255, 0.2)",
8549
+ borderRadius: "1.5px"
8550
+ }
8551
+ }),
8552
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8553
+ style: {
8554
+ position: "absolute",
8555
+ top: 0,
8556
+ left: 0,
8557
+ bottom: 0,
8558
+ width: "".concat((isMuted ? 0 : volume) * 100, "%"),
8559
+ background: "#fff",
8560
+ borderRadius: "1.5px",
8561
+ transition: "width 0.1s ease-out"
8562
+ }
8563
+ }),
8564
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8565
+ style: {
8566
+ position: "absolute",
8567
+ top: "50%",
8568
+ left: "".concat((isMuted ? 0 : volume) * 100, "%"),
8569
+ transform: "translate(-50%, -50%)",
8570
+ width: "12px",
8571
+ height: "12px",
8572
+ background: "#fff",
8573
+ borderRadius: "50%",
8574
+ boxShadow: "0 0 3px rgba(0, 0, 0, 0.3)",
8575
+ transition: "left 0.1s ease-out"
8576
+ }
8577
+ })
8578
+ ]
8579
+ })
8580
+ })
8581
+ ]
8582
+ }),
8379
8583
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
8380
8584
  className: "sc-ctrl-btn",
8381
8585
  onClick: function onClick() {
8382
- if (playerRef.current) playerRef.current.toggleMute();
8383
- onVolumeToggle === null || onVolumeToggle === void 0 ? void 0 : onVolumeToggle();
8586
+ if (onFullscreenToggle) {
8587
+ onFullscreenToggle();
8588
+ } else if (wrapperRef.current) {
8589
+ if (!document.fullscreenElement) {
8590
+ wrapperRef.current.requestFullscreen().catch(function() {});
8591
+ } else {
8592
+ document.exitFullscreen().catch(function() {});
8593
+ }
8594
+ }
8384
8595
  resetControlsTimer();
8385
8596
  },
8386
8597
  style: {
8387
8598
  padding: "".concat(8 * responsiveScale, "px"),
8388
8599
  borderRadius: "50%",
8389
8600
  minWidth: "".concat(36 * responsiveScale, "px"),
8390
- minHeight: "".concat(36 * responsiveScale, "px")
8601
+ minHeight: "".concat(36 * responsiveScale, "px"),
8602
+ background: "rgba(0, 0, 0, 0.6)"
8391
8603
  },
8392
- title: isMuted ? "Unmute" : "Mute",
8393
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VolumeIcon, {
8604
+ title: isFullscreen ? "Exit Fullscreen" : "Enter Fullscreen",
8605
+ children: isFullscreen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaCompress, {
8606
+ size: Math.max(14, 18 * responsiveScale)
8607
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaExpand, {
8394
8608
  size: Math.max(14, 18 * responsiveScale)
8395
- })
8396
- }),
8397
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8398
- style: {
8399
- width: showVolumeSlider ? "".concat(68 * responsiveScale, "px") : "0px",
8400
- overflow: "hidden",
8401
- transition: "width 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
8402
- display: "flex",
8403
- alignItems: "center",
8404
- paddingLeft: showVolumeSlider ? "".concat(3 * responsiveScale, "px") : "0",
8405
- paddingRight: showVolumeSlider ? "".concat(10 * responsiveScale, "px") : "0"
8406
- },
8407
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
8408
- style: {
8409
- position: "relative",
8410
- width: "".concat(56 * responsiveScale, "px"),
8411
- height: "3px",
8412
- cursor: "pointer",
8413
- borderRadius: "1.5px"
8414
- },
8415
- onMouseDown: function onMouseDown(e) {
8416
- e.preventDefault();
8417
- var el = e.currentTarget;
8418
- var move = function move(ev) {
8419
- var r2 = el.getBoundingClientRect();
8420
- handleVolumeChange(Math.max(0, Math.min(1, (ev.clientX - r2.left) / r2.width)));
8421
- };
8422
- var up = function up1() {
8423
- document.removeEventListener("mousemove", move);
8424
- document.removeEventListener("mouseup", up);
8425
- };
8426
- document.addEventListener("mousemove", move);
8427
- document.addEventListener("mouseup", up);
8428
- var r = el.getBoundingClientRect();
8429
- handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
8430
- },
8431
- onClick: function onClick(e) {
8432
- e.stopPropagation();
8433
- var r = e.currentTarget.getBoundingClientRect();
8434
- handleVolumeChange(Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)));
8435
- },
8436
- children: [
8437
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8438
- style: {
8439
- position: "absolute",
8440
- inset: 0,
8441
- background: "rgba(255, 255, 255, 0.2)",
8442
- borderRadius: "1.5px"
8443
- }
8444
- }),
8445
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8446
- style: {
8447
- position: "absolute",
8448
- top: 0,
8449
- left: 0,
8450
- bottom: 0,
8451
- width: "".concat((isMuted ? 0 : volume) * 100, "%"),
8452
- background: "#fff",
8453
- borderRadius: "1.5px",
8454
- transition: "width 0.1s ease-out"
8455
- }
8456
- }),
8457
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
8458
- style: {
8459
- position: "absolute",
8460
- top: "50%",
8461
- left: "".concat((isMuted ? 0 : volume) * 100, "%"),
8462
- transform: "translate(-50%, -50%)",
8463
- width: "12px",
8464
- height: "12px",
8465
- background: "#fff",
8466
- borderRadius: "50%",
8467
- boxShadow: "0 0 3px rgba(0, 0, 0, 0.3)",
8468
- transition: "left 0.1s ease-out"
8469
- }
8470
- })
8471
- ]
8472
8609
  })
8473
8610
  })
8474
8611
  ]
8475
- }),
8476
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
8477
- className: "sc-ctrl-btn",
8478
- onClick: function onClick() {
8479
- if (onFullscreenToggle) {
8480
- onFullscreenToggle();
8481
- } else if (wrapperRef.current) {
8482
- if (!document.fullscreenElement) {
8483
- wrapperRef.current.requestFullscreen().catch(function() {});
8484
- } else {
8485
- document.exitFullscreen().catch(function() {});
8486
- }
8487
- }
8488
- resetControlsTimer();
8489
- },
8490
- style: {
8491
- padding: "".concat(8 * responsiveScale, "px"),
8492
- borderRadius: "50%",
8493
- minWidth: "".concat(36 * responsiveScale, "px"),
8494
- minHeight: "".concat(36 * responsiveScale, "px"),
8495
- background: "rgba(0, 0, 0, 0.6)"
8496
- },
8497
- title: isFullscreen ? "Exit Fullscreen" : "Enter Fullscreen",
8498
- children: isFullscreen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaCompress, {
8499
- size: Math.max(14, 18 * responsiveScale)
8500
- }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_fa.FaExpand, {
8501
- size: Math.max(14, 18 * responsiveScale)
8502
- })
8503
8612
  })
8504
8613
  ]
8505
8614
  }),