stormcloud-video-player 0.2.0 → 0.2.1

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
@@ -1,5 +1,5 @@
1
- // src/StormcloudPlayer.tsx
2
- import React2, { Component as Component4, Suspense } from "react";
1
+ // src/ui/StormcloudVideoPlayer.tsx
2
+ import React, { useEffect, useRef, useMemo } from "react";
3
3
 
4
4
  // src/player/StormcloudVideoPlayer.ts
5
5
  import Hls from "hls.js";
@@ -1632,1255 +1632,371 @@ var StormcloudVideoPlayer = class {
1632
1632
  }
1633
1633
  };
1634
1634
 
1635
- // src/props.ts
1636
- var noop = () => {
1637
- };
1638
- var defaultProps = {
1639
- playing: false,
1640
- loop: false,
1641
- controls: true,
1642
- volume: 1,
1643
- muted: false,
1644
- playbackRate: 1,
1645
- width: "100%",
1646
- height: "auto",
1647
- style: {},
1648
- progressInterval: 1e3,
1649
- playsInline: false,
1650
- autoplay: false,
1651
- preload: "metadata",
1652
- poster: "",
1653
- className: "",
1654
- wrapperClassName: "",
1655
- wrapperStyle: {},
1656
- allowNativeHls: false,
1657
- lowLatencyMode: false,
1658
- driftToleranceMs: 1e3,
1659
- immediateManifestAds: true,
1660
- debugAdTiming: false,
1661
- showCustomControls: false,
1662
- licenseKey: "",
1663
- adFailsafeTimeoutMs: 1e4,
1664
- onStart: noop,
1665
- onPlay: noop,
1666
- onPause: noop,
1667
- onBuffer: noop,
1668
- onBufferEnd: noop,
1669
- onEnded: noop,
1670
- onError: noop,
1671
- onDuration: noop,
1672
- onSeek: noop,
1673
- onProgress: noop,
1674
- onVolumeToggle: noop,
1675
- onFullscreenToggle: noop,
1676
- onControlClick: noop
1677
- };
1678
-
1679
- // src/utils.ts
1680
- import { lazy as reactLazy } from "react";
1681
- var lazy = reactLazy;
1682
- var omit = (object, keys) => {
1683
- const result = { ...object };
1684
- keys.forEach((key) => {
1685
- delete result[key];
1686
- });
1687
- return result;
1688
- };
1689
- var isMediaStream = (url) => {
1690
- return typeof window !== "undefined" && window.MediaStream && url instanceof window.MediaStream;
1691
- };
1692
- var supportsWebKitPresentationMode = () => {
1693
- if (typeof window === "undefined") return false;
1694
- const video = document.createElement("video");
1695
- return "webkitSupportsPresentationMode" in video;
1696
- };
1697
- var randomString = () => {
1698
- return Math.random().toString(36).substr(2, 9);
1699
- };
1700
- var parseQuery = (url) => {
1701
- const query = {};
1702
- const params = new URLSearchParams(url.split("?")[1] || "");
1703
- params.forEach((value, key) => {
1704
- query[key] = value;
1705
- });
1706
- return query;
1707
- };
1708
- var merge = (target, ...sources) => {
1709
- if (!sources.length) return target;
1710
- const source = sources.shift();
1711
- if (isObject(target) && isObject(source)) {
1712
- for (const key in source) {
1713
- if (isObject(source[key])) {
1714
- if (!target[key]) Object.assign(target, { [key]: {} });
1715
- merge(target[key], source[key]);
1716
- } else {
1717
- Object.assign(target, { [key]: source[key] });
1718
- }
1719
- }
1720
- }
1721
- return merge(target, ...sources);
1722
- };
1723
- var isObject = (item) => {
1724
- return item && typeof item === "object" && !Array.isArray(item);
1725
- };
1726
- var IS_BROWSER = typeof window !== "undefined" && window.document;
1727
- var IS_GLOBAL = typeof globalThis !== "undefined" && globalThis.window && globalThis.window.document;
1728
- var IS_IOS = IS_BROWSER && /iPad|iPhone|iPod/.test(navigator.userAgent);
1729
- var IS_SAFARI = IS_BROWSER && /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
1730
- var SUPPORTS_HLS = () => {
1731
- if (!IS_BROWSER) return false;
1732
- const video = document.createElement("video");
1733
- return Boolean(video.canPlayType("application/vnd.apple.mpegurl"));
1734
- };
1735
- var SUPPORTS_DASH = () => {
1736
- if (!IS_BROWSER) return false;
1737
- const video = document.createElement("video");
1738
- return Boolean(video.canPlayType("application/dash+xml"));
1739
- };
1740
-
1741
- // src/patterns.ts
1742
- var HLS_EXTENSIONS = /\.(m3u8)($|\?)/i;
1743
- var HLS_PATHS = /\/hls\//i;
1744
- var DASH_EXTENSIONS = /\.(mpd)($|\?)/i;
1745
- var VIDEO_EXTENSIONS = /\.(mp4|webm|ogg|avi|mov|wmv|flv|mkv)($|\?)/i;
1746
- var AUDIO_EXTENSIONS = /\.(mp3|wav|ogg|aac|wma|flac|m4a)($|\?)/i;
1747
- var canPlay = {
1748
- hls: (url) => {
1749
- if (!url || typeof url !== "string") return false;
1750
- return HLS_EXTENSIONS.test(url) || HLS_PATHS.test(url);
1751
- },
1752
- dash: (url) => {
1753
- if (!url || typeof url !== "string") return false;
1754
- return DASH_EXTENSIONS.test(url);
1755
- },
1756
- video: (url) => {
1757
- if (!url || typeof url !== "string") return false;
1758
- return VIDEO_EXTENSIONS.test(url);
1759
- },
1760
- audio: (url) => {
1761
- if (!url || typeof url !== "string") return false;
1762
- return AUDIO_EXTENSIONS.test(url);
1763
- },
1764
- file: (url) => {
1765
- if (!url || typeof url !== "string") return false;
1766
- return VIDEO_EXTENSIONS.test(url) || AUDIO_EXTENSIONS.test(url);
1767
- }
1768
- };
1769
-
1770
- // src/players/HlsPlayer.tsx
1771
- import { Component } from "react";
1772
- var HlsPlayer = class extends Component {
1773
- constructor() {
1774
- super(...arguments);
1775
- this.player = null;
1776
- this.mounted = false;
1777
- this.load = async () => {
1778
- if (!this.props.videoElement || !this.props.src) return;
1779
- try {
1780
- if (this.player) {
1781
- this.player.destroy();
1782
- this.player = null;
1783
- }
1784
- const config = {
1785
- src: this.props.src,
1786
- videoElement: this.props.videoElement
1787
- };
1788
- if (this.props.autoplay !== void 0)
1789
- config.autoplay = this.props.autoplay;
1790
- if (this.props.muted !== void 0) config.muted = this.props.muted;
1791
- if (this.props.lowLatencyMode !== void 0)
1792
- config.lowLatencyMode = this.props.lowLatencyMode;
1793
- if (this.props.allowNativeHls !== void 0)
1794
- config.allowNativeHls = this.props.allowNativeHls;
1795
- if (this.props.driftToleranceMs !== void 0)
1796
- config.driftToleranceMs = this.props.driftToleranceMs;
1797
- if (this.props.immediateManifestAds !== void 0)
1798
- config.immediateManifestAds = this.props.immediateManifestAds;
1799
- if (this.props.debugAdTiming !== void 0)
1800
- config.debugAdTiming = this.props.debugAdTiming;
1801
- if (this.props.showCustomControls !== void 0)
1802
- config.showCustomControls = this.props.showCustomControls;
1803
- if (this.props.onVolumeToggle !== void 0)
1804
- config.onVolumeToggle = this.props.onVolumeToggle;
1805
- if (this.props.onFullscreenToggle !== void 0)
1806
- config.onFullscreenToggle = this.props.onFullscreenToggle;
1807
- if (this.props.onControlClick !== void 0)
1808
- config.onControlClick = this.props.onControlClick;
1809
- if (this.props.licenseKey !== void 0)
1810
- config.licenseKey = this.props.licenseKey;
1811
- if (this.props.adFailsafeTimeoutMs !== void 0)
1812
- config.adFailsafeTimeoutMs = this.props.adFailsafeTimeoutMs;
1813
- this.player = new StormcloudVideoPlayer(config);
1814
- this.props.onMount?.(this);
1815
- await this.player.load();
1816
- if (this.mounted) {
1817
- this.props.onReady?.();
1818
- }
1819
- } catch (error) {
1820
- if (this.mounted) {
1821
- this.props.onError?.(error);
1635
+ // src/ui/StormcloudVideoPlayer.tsx
1636
+ import {
1637
+ FaPlay,
1638
+ FaPause,
1639
+ FaVolumeUp,
1640
+ FaVolumeMute,
1641
+ FaVolumeDown,
1642
+ FaExpand,
1643
+ FaCompress,
1644
+ FaSpinner
1645
+ } from "react-icons/fa";
1646
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
1647
+ var CRITICAL_PROPS = [
1648
+ "src",
1649
+ "allowNativeHls",
1650
+ "licenseKey",
1651
+ "lowLatencyMode",
1652
+ "driftToleranceMs"
1653
+ ];
1654
+ var StormcloudVideoPlayerComponent = React.memo(
1655
+ (props) => {
1656
+ const {
1657
+ src,
1658
+ autoplay,
1659
+ muted,
1660
+ lowLatencyMode,
1661
+ allowNativeHls,
1662
+ driftToleranceMs,
1663
+ immediateManifestAds,
1664
+ debugAdTiming,
1665
+ showCustomControls,
1666
+ onVolumeToggle,
1667
+ onFullscreenToggle,
1668
+ onControlClick,
1669
+ onReady,
1670
+ wrapperClassName,
1671
+ wrapperStyle,
1672
+ className,
1673
+ style,
1674
+ controls,
1675
+ playsInline,
1676
+ preload,
1677
+ poster,
1678
+ children,
1679
+ licenseKey,
1680
+ ...restVideoAttrs
1681
+ } = props;
1682
+ const videoRef = useRef(null);
1683
+ const playerRef = useRef(null);
1684
+ const [adStatus, setAdStatus] = React.useState({ showAds: false, currentIndex: 0, totalAds: 0 });
1685
+ const [shouldShowNativeControls, setShouldShowNativeControls] = React.useState(true);
1686
+ const [isMuted, setIsMuted] = React.useState(false);
1687
+ const [isFullscreen, setIsFullscreen] = React.useState(false);
1688
+ const [isPlaying, setIsPlaying] = React.useState(false);
1689
+ const [currentTime, setCurrentTime] = React.useState(0);
1690
+ const [duration, setDuration] = React.useState(0);
1691
+ const [volume, setVolume] = React.useState(1);
1692
+ const [playbackRate, setPlaybackRate] = React.useState(1);
1693
+ const [showVolumeSlider, setShowVolumeSlider] = React.useState(false);
1694
+ const [showSpeedMenu, setShowSpeedMenu] = React.useState(false);
1695
+ const [isLoading, setIsLoading] = React.useState(true);
1696
+ const [isBuffering, setIsBuffering] = React.useState(false);
1697
+ const [showCenterPlay, setShowCenterPlay] = React.useState(false);
1698
+ const formatTime = (seconds) => {
1699
+ if (!isFinite(seconds)) return "0:00:00";
1700
+ const hours = Math.floor(seconds / 3600);
1701
+ const minutes = Math.floor(seconds % 3600 / 60);
1702
+ const remainingSeconds = Math.floor(seconds % 60);
1703
+ return `${hours}:${minutes.toString().padStart(2, "0")}:${remainingSeconds.toString().padStart(2, "0")}`;
1704
+ };
1705
+ const handlePlayPause = () => {
1706
+ if (videoRef.current) {
1707
+ if (videoRef.current.paused) {
1708
+ videoRef.current.play();
1709
+ setShowCenterPlay(false);
1710
+ } else {
1711
+ videoRef.current.pause();
1712
+ setShowCenterPlay(true);
1822
1713
  }
1823
1714
  }
1824
1715
  };
1825
- this.play = () => {
1826
- if (this.props.videoElement) {
1827
- this.props.videoElement.play();
1828
- this.props.onPlay?.();
1829
- }
1830
- };
1831
- this.pause = () => {
1832
- if (this.props.videoElement) {
1833
- this.props.videoElement.pause();
1834
- this.props.onPause?.();
1835
- }
1836
- };
1837
- this.stop = () => {
1838
- this.pause();
1839
- if (this.props.videoElement) {
1840
- this.props.videoElement.currentTime = 0;
1716
+ const handleCenterPlayClick = () => {
1717
+ if (videoRef.current && videoRef.current.paused) {
1718
+ videoRef.current.play();
1719
+ setShowCenterPlay(false);
1841
1720
  }
1842
1721
  };
1843
- this.seekTo = (seconds, keepPlaying) => {
1844
- if (this.props.videoElement) {
1845
- this.props.videoElement.currentTime = seconds;
1846
- if (!keepPlaying) {
1847
- this.pause();
1722
+ const handleTimelineSeek = (e) => {
1723
+ if (videoRef.current && duration > 0 && isFinite(duration)) {
1724
+ const rect = e.currentTarget.getBoundingClientRect();
1725
+ const clickX = e.clientX - rect.left;
1726
+ const progress = Math.max(0, Math.min(1, clickX / rect.width));
1727
+ const newTime = progress * duration;
1728
+ if (isFinite(newTime) && newTime >= 0 && newTime <= duration) {
1729
+ videoRef.current.currentTime = newTime;
1848
1730
  }
1849
1731
  }
1850
1732
  };
1851
- this.setVolume = (volume) => {
1852
- if (this.props.videoElement) {
1853
- this.props.videoElement.volume = Math.max(0, Math.min(1, volume));
1854
- }
1855
- };
1856
- this.mute = () => {
1857
- if (this.props.videoElement) {
1858
- this.props.videoElement.muted = true;
1859
- }
1860
- };
1861
- this.unmute = () => {
1862
- if (this.props.videoElement) {
1863
- this.props.videoElement.muted = false;
1864
- }
1865
- };
1866
- this.setPlaybackRate = (rate) => {
1867
- if (this.props.videoElement && rate > 0) {
1868
- this.props.videoElement.playbackRate = rate;
1733
+ const handleVolumeChange = (newVolume) => {
1734
+ if (videoRef.current && isFinite(newVolume)) {
1735
+ const clampedVolume = Math.max(0, Math.min(1, newVolume));
1736
+ videoRef.current.volume = clampedVolume;
1737
+ videoRef.current.muted = clampedVolume === 0;
1869
1738
  }
1870
1739
  };
1871
- this.getDuration = () => {
1872
- if (this.props.videoElement && isFinite(this.props.videoElement.duration)) {
1873
- return this.props.videoElement.duration;
1740
+ const handlePlaybackRateChange = (rate) => {
1741
+ if (videoRef.current && isFinite(rate) && rate > 0) {
1742
+ videoRef.current.playbackRate = rate;
1874
1743
  }
1875
- return null;
1744
+ setShowSpeedMenu(false);
1876
1745
  };
1877
- this.getCurrentTime = () => {
1878
- if (this.props.videoElement && isFinite(this.props.videoElement.currentTime)) {
1879
- return this.props.videoElement.currentTime;
1746
+ const isHlsStream = src?.toLowerCase().includes(".m3u8") || src?.toLowerCase().includes("/hls/");
1747
+ const shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls : true);
1748
+ const criticalPropsKey = useMemo(() => {
1749
+ return CRITICAL_PROPS.map((prop) => `${prop}:${props[prop]}`).join("|");
1750
+ }, [src, allowNativeHls, licenseKey, lowLatencyMode, driftToleranceMs]);
1751
+ useEffect(() => {
1752
+ if (typeof window === "undefined") return;
1753
+ const el = videoRef.current;
1754
+ if (!el || !src) return;
1755
+ if (playerRef.current) {
1756
+ try {
1757
+ playerRef.current.destroy();
1758
+ } catch {
1759
+ }
1760
+ playerRef.current = null;
1880
1761
  }
1881
- return null;
1882
- };
1883
- this.getSecondsLoaded = () => {
1884
- if (this.props.videoElement && this.props.videoElement.buffered.length > 0) {
1885
- return this.props.videoElement.buffered.end(
1886
- this.props.videoElement.buffered.length - 1
1762
+ const cfg = {
1763
+ src,
1764
+ videoElement: el
1765
+ };
1766
+ if (autoplay !== void 0) cfg.autoplay = autoplay;
1767
+ if (muted !== void 0) cfg.muted = muted;
1768
+ if (lowLatencyMode !== void 0) cfg.lowLatencyMode = lowLatencyMode;
1769
+ if (allowNativeHls !== void 0) cfg.allowNativeHls = allowNativeHls;
1770
+ if (driftToleranceMs !== void 0)
1771
+ cfg.driftToleranceMs = driftToleranceMs;
1772
+ if (immediateManifestAds !== void 0)
1773
+ cfg.immediateManifestAds = immediateManifestAds;
1774
+ if (debugAdTiming !== void 0) cfg.debugAdTiming = debugAdTiming;
1775
+ if (showCustomControls !== void 0)
1776
+ cfg.showCustomControls = showCustomControls;
1777
+ if (onVolumeToggle !== void 0) cfg.onVolumeToggle = onVolumeToggle;
1778
+ if (onFullscreenToggle !== void 0)
1779
+ cfg.onFullscreenToggle = onFullscreenToggle;
1780
+ if (onControlClick !== void 0) cfg.onControlClick = onControlClick;
1781
+ if (licenseKey !== void 0) cfg.licenseKey = licenseKey;
1782
+ const player = new StormcloudVideoPlayer(cfg);
1783
+ playerRef.current = player;
1784
+ player.load().then(() => {
1785
+ const showNative = player.shouldShowNativeControls();
1786
+ setShouldShowNativeControls(showNative);
1787
+ onReady?.(player);
1788
+ }).catch((error) => {
1789
+ console.error(
1790
+ "StormcloudVideoPlayer: Failed to load player:",
1791
+ error
1887
1792
  );
1888
- }
1889
- return null;
1890
- };
1891
- this.getInternalPlayer = (key = "player") => {
1892
- if (key === "player") return this.player;
1893
- if (key === "video") return this.props.videoElement;
1894
- if (key === "hls" && this.player) return this.player.hls;
1895
- return null;
1896
- };
1897
- }
1898
- componentDidMount() {
1899
- this.mounted = true;
1900
- this.load();
1901
- }
1902
- componentWillUnmount() {
1903
- this.mounted = false;
1904
- if (this.player) {
1905
- this.player.destroy();
1906
- this.player = null;
1907
- }
1908
- }
1909
- componentDidUpdate(prevProps) {
1910
- if (prevProps.src !== this.props.src) {
1911
- this.load();
1912
- }
1913
- }
1914
- render() {
1915
- return null;
1916
- }
1917
- };
1918
- HlsPlayer.displayName = "HlsPlayer";
1919
- HlsPlayer.canPlay = canPlay.hls;
1920
-
1921
- // src/players/FilePlayer.tsx
1922
- import { Component as Component2 } from "react";
1923
- var FilePlayer = class extends Component2 {
1924
- constructor() {
1925
- super(...arguments);
1926
- this.mounted = false;
1927
- this.ready = false;
1928
- this.load = () => {
1929
- if (!this.props.videoElement || !this.props.src) return;
1930
- const video = this.props.videoElement;
1931
- const handleLoadedMetadata = () => {
1932
- if (this.mounted && !this.ready) {
1933
- this.ready = true;
1934
- this.props.onReady?.();
1793
+ onReady?.(player);
1794
+ });
1795
+ return () => {
1796
+ try {
1797
+ player.destroy();
1798
+ } catch {
1935
1799
  }
1800
+ playerRef.current = null;
1936
1801
  };
1937
- const handlePlay = () => {
1938
- if (this.mounted) {
1939
- this.props.onPlay?.();
1802
+ }, [criticalPropsKey]);
1803
+ useEffect(() => {
1804
+ if (!playerRef.current) return;
1805
+ try {
1806
+ if (autoplay !== void 0 && playerRef.current.videoElement) {
1807
+ playerRef.current.videoElement.autoplay = autoplay;
1940
1808
  }
1941
- };
1942
- const handlePause = () => {
1943
- if (this.mounted) {
1944
- this.props.onPause?.();
1809
+ if (muted !== void 0 && playerRef.current.videoElement) {
1810
+ playerRef.current.videoElement.muted = muted;
1945
1811
  }
1946
- };
1947
- const handleEnded = () => {
1948
- if (this.mounted) {
1949
- this.props.onEnded?.();
1812
+ } catch (error) {
1813
+ console.warn("Failed to update player properties:", error);
1814
+ }
1815
+ }, [autoplay, muted]);
1816
+ useEffect(() => {
1817
+ if (!playerRef.current) return;
1818
+ const checkAdStatus = () => {
1819
+ if (playerRef.current) {
1820
+ const showAds = playerRef.current.isShowingAds();
1821
+ const currentIndex = playerRef.current.getCurrentAdIndex();
1822
+ const totalAds = playerRef.current.getTotalAdsInBreak();
1823
+ setAdStatus((prev) => {
1824
+ if (prev.showAds !== showAds || prev.currentIndex !== currentIndex || prev.totalAds !== totalAds) {
1825
+ return { showAds, currentIndex, totalAds };
1826
+ }
1827
+ return prev;
1828
+ });
1950
1829
  }
1951
1830
  };
1952
- const handleError = (error) => {
1953
- if (this.mounted) {
1954
- this.props.onError?.(error);
1831
+ const interval = setInterval(checkAdStatus, 100);
1832
+ return () => clearInterval(interval);
1833
+ }, []);
1834
+ useEffect(() => {
1835
+ if (typeof window === "undefined" || !playerRef.current) return;
1836
+ const handleResize = () => {
1837
+ if (playerRef.current && videoRef.current) {
1838
+ if (typeof playerRef.current.resize === "function") {
1839
+ playerRef.current.resize();
1840
+ }
1955
1841
  }
1956
1842
  };
1957
- const handleLoadedData = () => {
1958
- if (this.mounted) {
1959
- this.props.onLoaded?.();
1843
+ window.addEventListener("resize", handleResize);
1844
+ return () => window.removeEventListener("resize", handleResize);
1845
+ }, []);
1846
+ useEffect(() => {
1847
+ if (!playerRef.current || !videoRef.current) return;
1848
+ const updateStates = () => {
1849
+ if (playerRef.current && videoRef.current) {
1850
+ setIsMuted(playerRef.current.isMuted());
1851
+ setIsPlaying(!videoRef.current.paused);
1852
+ const currentTimeValue = videoRef.current.currentTime;
1853
+ setCurrentTime(isFinite(currentTimeValue) ? currentTimeValue : 0);
1854
+ const durationValue = videoRef.current.duration;
1855
+ setDuration(isFinite(durationValue) ? durationValue : 0);
1856
+ const volumeValue = videoRef.current.volume;
1857
+ setVolume(
1858
+ isFinite(volumeValue) ? Math.max(0, Math.min(1, volumeValue)) : 1
1859
+ );
1860
+ const rateValue = videoRef.current.playbackRate;
1861
+ setPlaybackRate(
1862
+ isFinite(rateValue) && rateValue > 0 ? rateValue : 1
1863
+ );
1960
1864
  }
1865
+ setIsFullscreen(
1866
+ document.fullscreenElement === videoRef.current?.parentElement
1867
+ );
1961
1868
  };
1962
- video.addEventListener("loadedmetadata", handleLoadedMetadata);
1963
- video.addEventListener("play", handlePlay);
1964
- video.addEventListener("pause", handlePause);
1965
- video.addEventListener("ended", handleEnded);
1966
- video.addEventListener("error", handleError);
1967
- video.addEventListener("loadeddata", handleLoadedData);
1968
- video.src = this.props.src;
1969
- if (this.props.autoplay !== void 0) video.autoplay = this.props.autoplay;
1970
- if (this.props.muted !== void 0) video.muted = this.props.muted;
1971
- if (this.props.loop !== void 0) video.loop = this.props.loop;
1972
- if (this.props.controls !== void 0) video.controls = this.props.controls;
1973
- if (this.props.playsInline !== void 0)
1974
- video.playsInline = this.props.playsInline;
1975
- if (this.props.preload !== void 0)
1976
- video.preload = this.props.preload;
1977
- if (this.props.poster !== void 0) video.poster = this.props.poster;
1978
- this.props.onMount?.(this);
1979
- return () => {
1980
- video.removeEventListener("loadedmetadata", handleLoadedMetadata);
1981
- video.removeEventListener("play", handlePlay);
1982
- video.removeEventListener("pause", handlePause);
1983
- video.removeEventListener("ended", handleEnded);
1984
- video.removeEventListener("error", handleError);
1985
- video.removeEventListener("loadeddata", handleLoadedData);
1869
+ const interval = setInterval(updateStates, 200);
1870
+ const handleFullscreenChange = () => {
1871
+ setIsFullscreen(
1872
+ document.fullscreenElement === videoRef.current?.parentElement
1873
+ );
1986
1874
  };
1987
- };
1988
- this.play = () => {
1989
- if (this.props.videoElement) {
1990
- this.props.videoElement.play();
1991
- }
1992
- };
1993
- this.pause = () => {
1994
- if (this.props.videoElement) {
1995
- this.props.videoElement.pause();
1996
- }
1997
- };
1998
- this.stop = () => {
1999
- this.pause();
2000
- if (this.props.videoElement) {
2001
- this.props.videoElement.currentTime = 0;
2002
- }
2003
- };
2004
- this.seekTo = (seconds, keepPlaying) => {
2005
- if (this.props.videoElement) {
2006
- this.props.videoElement.currentTime = seconds;
2007
- if (!keepPlaying) {
2008
- this.pause();
2009
- }
2010
- }
2011
- };
2012
- this.setVolume = (volume) => {
2013
- if (this.props.videoElement) {
2014
- this.props.videoElement.volume = Math.max(0, Math.min(1, volume));
2015
- }
2016
- };
2017
- this.mute = () => {
2018
- if (this.props.videoElement) {
2019
- this.props.videoElement.muted = true;
2020
- }
2021
- };
2022
- this.unmute = () => {
2023
- if (this.props.videoElement) {
2024
- this.props.videoElement.muted = false;
2025
- }
2026
- };
2027
- this.setPlaybackRate = (rate) => {
2028
- if (this.props.videoElement && rate > 0) {
2029
- this.props.videoElement.playbackRate = rate;
2030
- }
2031
- };
2032
- this.setLoop = (loop) => {
2033
- if (this.props.videoElement) {
2034
- this.props.videoElement.loop = loop;
2035
- }
2036
- };
2037
- this.getDuration = () => {
2038
- if (this.props.videoElement && isFinite(this.props.videoElement.duration)) {
2039
- return this.props.videoElement.duration;
2040
- }
2041
- return null;
2042
- };
2043
- this.getCurrentTime = () => {
2044
- if (this.props.videoElement && isFinite(this.props.videoElement.currentTime)) {
2045
- return this.props.videoElement.currentTime;
2046
- }
2047
- return null;
2048
- };
2049
- this.getSecondsLoaded = () => {
2050
- if (this.props.videoElement && this.props.videoElement.buffered.length > 0) {
2051
- return this.props.videoElement.buffered.end(
2052
- this.props.videoElement.buffered.length - 1
1875
+ document.addEventListener("fullscreenchange", handleFullscreenChange);
1876
+ return () => {
1877
+ clearInterval(interval);
1878
+ document.removeEventListener(
1879
+ "fullscreenchange",
1880
+ handleFullscreenChange
2053
1881
  );
2054
- }
2055
- return null;
2056
- };
2057
- this.getInternalPlayer = (key = "player") => {
2058
- if (key === "video") return this.props.videoElement;
2059
- return null;
2060
- };
2061
- this.enablePIP = async () => {
2062
- if (this.props.videoElement && "requestPictureInPicture" in this.props.videoElement) {
2063
- try {
2064
- await this.props.videoElement.requestPictureInPicture();
2065
- } catch (error) {
2066
- console.warn("Picture-in-Picture failed:", error);
2067
- }
2068
- }
2069
- };
2070
- this.disablePIP = async () => {
2071
- if (document.pictureInPictureElement) {
2072
- try {
2073
- await document.exitPictureInPicture();
2074
- } catch (error) {
2075
- console.warn("Exit Picture-in-Picture failed:", error);
1882
+ };
1883
+ }, []);
1884
+ useEffect(() => {
1885
+ if (!videoRef.current) return;
1886
+ const handleLoadedMetadata = () => {
1887
+ if (videoRef.current) {
1888
+ const video2 = videoRef.current;
1889
+ void video2.offsetHeight;
2076
1890
  }
2077
- }
2078
- };
2079
- }
2080
- componentDidMount() {
2081
- this.mounted = true;
2082
- this.load();
2083
- }
2084
- componentWillUnmount() {
2085
- this.mounted = false;
2086
- }
2087
- componentDidUpdate(prevProps) {
2088
- if (prevProps.src !== this.props.src) {
2089
- this.load();
2090
- }
2091
- }
2092
- render() {
2093
- return null;
2094
- }
2095
- };
2096
- FilePlayer.displayName = "FilePlayer";
2097
- FilePlayer.canPlay = canPlay.file;
2098
-
2099
- // src/players/index.ts
2100
- var players = [
2101
- {
2102
- key: "hls",
2103
- name: "HLS Player",
2104
- canPlay: canPlay.hls,
2105
- lazyPlayer: lazy(() => Promise.resolve({ default: HlsPlayer }))
2106
- },
2107
- {
2108
- key: "file",
2109
- name: "File Player",
2110
- canPlay: canPlay.file,
2111
- canEnablePIP: (url) => {
2112
- return canPlay.file(url) && (document.pictureInPictureEnabled || typeof document.webkitSupportsPresentationMode === "function");
2113
- },
2114
- lazyPlayer: lazy(() => Promise.resolve({ default: FilePlayer }))
2115
- }
2116
- ];
2117
- var players_default = players;
2118
-
2119
- // src/Player.tsx
2120
- import React, { Component as Component3 } from "react";
2121
- var SEEK_ON_PLAY_EXPIRY = 5e3;
2122
- var Player = class extends Component3 {
2123
- constructor() {
2124
- super(...arguments);
2125
- this.mounted = false;
2126
- this.isReady = false;
2127
- this.isPlaying = false;
2128
- this.isLoading = true;
2129
- this.loadOnReady = null;
2130
- this.startOnPlay = true;
2131
- this.seekOnPlay = null;
2132
- this.onDurationCalled = false;
2133
- this.handlePlayerMount = (player) => {
2134
- if (this.player) {
2135
- this.progress();
2136
- return;
2137
- }
2138
- this.player = player;
2139
- this.player.load(this.props.src);
2140
- this.progress();
2141
- };
2142
- this.getInternalPlayer = (key) => {
2143
- if (!this.player) return null;
2144
- return this.player.getInternalPlayer(key);
2145
- };
2146
- this.progress = () => {
2147
- if (this.props.src && this.player && this.isReady) {
2148
- const playedSeconds = this.getCurrentTime() || 0;
2149
- const loadedSeconds = this.getSecondsLoaded();
2150
- const duration = this.getDuration();
2151
- if (duration) {
2152
- const progress = {
2153
- playedSeconds,
2154
- played: playedSeconds / duration,
2155
- loaded: 0,
2156
- loadedSeconds: 0
2157
- };
2158
- if (loadedSeconds !== null) {
2159
- progress.loadedSeconds = loadedSeconds;
2160
- progress.loaded = loadedSeconds / duration;
2161
- }
2162
- if (progress.playedSeconds !== this.prevPlayed || progress.loadedSeconds !== this.prevLoaded) {
2163
- this.props.onProgress?.(progress);
2164
- }
2165
- this.prevPlayed = progress.playedSeconds;
2166
- this.prevLoaded = progress.loadedSeconds;
1891
+ };
1892
+ const handleLoadStart = () => {
1893
+ setIsLoading(true);
1894
+ setIsBuffering(false);
1895
+ };
1896
+ const handleCanPlay = () => {
1897
+ setIsLoading(false);
1898
+ setIsBuffering(false);
1899
+ };
1900
+ const handleWaiting = () => {
1901
+ setIsBuffering(true);
1902
+ };
1903
+ const handlePlaying = () => {
1904
+ setIsLoading(false);
1905
+ setIsBuffering(false);
1906
+ setShowCenterPlay(false);
1907
+ };
1908
+ const handlePause = () => {
1909
+ if (playerRef.current && !playerRef.current.isShowingAds()) {
1910
+ setShowCenterPlay(true);
1911
+ } else {
1912
+ setShowCenterPlay(false);
2167
1913
  }
1914
+ };
1915
+ const handleEnded = () => {
1916
+ setShowCenterPlay(true);
1917
+ };
1918
+ const video = videoRef.current;
1919
+ video.addEventListener("loadstart", handleLoadStart);
1920
+ video.addEventListener("loadedmetadata", handleLoadedMetadata);
1921
+ video.addEventListener("loadeddata", handleLoadedMetadata);
1922
+ video.addEventListener("canplay", handleCanPlay);
1923
+ video.addEventListener("waiting", handleWaiting);
1924
+ video.addEventListener("playing", handlePlaying);
1925
+ video.addEventListener("pause", handlePause);
1926
+ video.addEventListener("ended", handleEnded);
1927
+ if (video.paused) {
1928
+ setShowCenterPlay(true);
2168
1929
  }
2169
- this.progressTimeout = window.setTimeout(
2170
- this.progress,
2171
- this.props.progressInterval || 1e3
2172
- );
2173
- };
2174
- this.handleReady = () => {
2175
- if (!this.mounted) return;
2176
- this.isReady = true;
2177
- this.isLoading = false;
2178
- const { onReady, playing, volume, muted } = this.props;
2179
- onReady();
2180
- if (!muted && volume !== null) {
2181
- this.player.setVolume(volume);
2182
- }
2183
- if (this.loadOnReady) {
2184
- this.player.load(this.loadOnReady, true);
2185
- this.loadOnReady = null;
2186
- } else if (playing) {
2187
- this.player.play();
2188
- }
2189
- this.handleDurationCheck();
2190
- };
2191
- this.handlePlay = () => {
2192
- this.isPlaying = true;
2193
- this.isLoading = false;
2194
- const { onStart, onPlay, playbackRate } = this.props;
2195
- if (this.startOnPlay) {
2196
- if (this.player.setPlaybackRate && playbackRate !== 1) {
2197
- this.player.setPlaybackRate(playbackRate);
2198
- }
2199
- onStart?.();
2200
- this.startOnPlay = false;
2201
- }
2202
- onPlay?.();
2203
- if (this.seekOnPlay) {
2204
- this.seekTo(this.seekOnPlay);
2205
- this.seekOnPlay = null;
2206
- }
2207
- this.handleDurationCheck();
2208
- };
2209
- this.handlePause = (e) => {
2210
- this.isPlaying = false;
2211
- if (!this.isLoading) {
2212
- this.props.onPause?.(e);
2213
- }
2214
- };
2215
- this.handleEnded = () => {
2216
- const { activePlayer, loop, onEnded } = this.props;
2217
- if (activePlayer.loopOnEnded && loop) {
2218
- this.seekTo(0);
2219
- }
2220
- if (!loop) {
2221
- this.isPlaying = false;
2222
- onEnded?.();
2223
- }
2224
- };
2225
- this.handleError = (...args) => {
2226
- this.isLoading = false;
2227
- this.props.onError?.(args[0], args[1], args[2], args[3]);
2228
- };
2229
- this.handleDurationCheck = () => {
2230
- clearTimeout(this.durationCheckTimeout);
2231
- const duration = this.getDuration();
2232
- if (duration) {
2233
- if (!this.onDurationCalled) {
2234
- this.props.onDuration?.(duration);
2235
- this.onDurationCalled = true;
2236
- }
2237
- } else {
2238
- this.durationCheckTimeout = window.setTimeout(
2239
- this.handleDurationCheck,
2240
- 100
2241
- );
2242
- }
2243
- };
2244
- this.handleLoaded = () => {
2245
- this.isLoading = false;
2246
- };
2247
- }
2248
- componentDidMount() {
2249
- this.mounted = true;
2250
- }
2251
- componentWillUnmount() {
2252
- clearTimeout(this.progressTimeout);
2253
- clearTimeout(this.durationCheckTimeout);
2254
- this.mounted = false;
2255
- }
2256
- componentDidUpdate(prevProps) {
2257
- if (!this.player) return;
2258
- const { src, playing, volume, muted, playbackRate, loop, activePlayer } = this.props;
2259
- if (prevProps.src !== src) {
2260
- if (this.isLoading && !activePlayer.forceLoad && !isMediaStream(src)) {
2261
- console.warn(
2262
- `StormcloudPlayer: the attempt to load ${src} is being deferred until the player has loaded`
2263
- );
2264
- this.loadOnReady = src || null;
2265
- return;
2266
- }
2267
- this.isLoading = true;
2268
- this.startOnPlay = true;
2269
- this.onDurationCalled = false;
2270
- this.player.load(src, this.isReady);
2271
- }
2272
- if (!prevProps.playing && playing && !this.isPlaying) {
2273
- this.player.play();
2274
- }
2275
- if (prevProps.playing && !playing && this.isPlaying) {
2276
- this.player.pause();
2277
- }
2278
- if (prevProps.volume !== volume && volume !== null) {
2279
- this.player.setVolume(volume);
2280
- }
2281
- if (prevProps.muted !== muted) {
2282
- if (muted) {
2283
- this.player.mute();
2284
- } else {
2285
- this.player.unmute();
2286
- if (volume !== null) {
2287
- setTimeout(() => this.player.setVolume(volume));
2288
- }
2289
- }
2290
- }
2291
- if (prevProps.playbackRate !== playbackRate && this.player.setPlaybackRate) {
2292
- this.player.setPlaybackRate(playbackRate);
2293
- }
2294
- if (prevProps.loop !== loop && this.player.setLoop) {
2295
- this.player.setLoop(loop);
2296
- }
2297
- }
2298
- getDuration() {
2299
- if (!this.isReady) return null;
2300
- return this.player.getDuration();
2301
- }
2302
- getCurrentTime() {
2303
- if (!this.isReady) return null;
2304
- return this.player.getCurrentTime();
2305
- }
2306
- getSecondsLoaded() {
2307
- if (!this.isReady) return null;
2308
- return this.player.getSecondsLoaded();
2309
- }
2310
- seekTo(amount, type, keepPlaying) {
2311
- if (!this.isReady) {
2312
- if (amount !== 0) {
2313
- this.seekOnPlay = amount;
2314
- setTimeout(() => {
2315
- this.seekOnPlay = null;
2316
- }, SEEK_ON_PLAY_EXPIRY);
2317
- }
2318
- return;
2319
- }
2320
- const isFraction = !type ? amount > 0 && amount < 1 : type === "fraction";
2321
- if (isFraction) {
2322
- const duration = this.player.getDuration();
2323
- if (!duration) {
2324
- console.warn(
2325
- "StormcloudPlayer: could not seek using fraction \u2013 duration not yet available"
2326
- );
2327
- return;
2328
- }
2329
- this.player.seekTo(duration * amount, keepPlaying);
2330
- return;
2331
- }
2332
- this.player.seekTo(amount, keepPlaying);
2333
- }
2334
- render() {
2335
- const Player2 = this.props.activePlayer;
2336
- if (!Player2) {
2337
- return null;
2338
- }
2339
- return React.createElement(Player2, {
2340
- ...this.props,
2341
- onMount: this.handlePlayerMount,
2342
- onReady: this.handleReady,
2343
- onPlay: this.handlePlay,
2344
- onPause: this.handlePause,
2345
- onEnded: this.handleEnded,
2346
- onLoaded: this.handleLoaded,
2347
- onError: this.handleError
2348
- });
2349
- }
2350
- };
2351
- Player.displayName = "Player";
2352
- Player.defaultProps = defaultProps;
2353
-
2354
- // src/StormcloudPlayer.tsx
2355
- var IS_BROWSER2 = typeof window !== "undefined" && window.document;
2356
- var IS_GLOBAL2 = typeof globalThis !== "undefined" && globalThis.window && globalThis.window.document;
2357
- var UniversalSuspense = IS_BROWSER2 || IS_GLOBAL2 ? Suspense : () => null;
2358
- var SUPPORTED_PROPS = [
2359
- "src",
2360
- "playing",
2361
- "loop",
2362
- "controls",
2363
- "volume",
2364
- "muted",
2365
- "playbackRate",
2366
- "width",
2367
- "height",
2368
- "style",
2369
- "progressInterval",
2370
- "playsInline",
2371
- "autoplay",
2372
- "preload",
2373
- "poster",
2374
- "className",
2375
- "wrapperClassName",
2376
- "wrapperStyle",
2377
- "allowNativeHls",
2378
- "lowLatencyMode",
2379
- "driftToleranceMs",
2380
- "immediateManifestAds",
2381
- "debugAdTiming",
2382
- "showCustomControls",
2383
- "licenseKey",
2384
- "adFailsafeTimeoutMs",
2385
- "onReady",
2386
- "onStart",
2387
- "onPlay",
2388
- "onPause",
2389
- "onBuffer",
2390
- "onBufferEnd",
2391
- "onEnded",
2392
- "onError",
2393
- "onDuration",
2394
- "onSeek",
2395
- "onProgress",
2396
- "onVolumeToggle",
2397
- "onFullscreenToggle",
2398
- "onControlClick"
2399
- ];
2400
- var customPlayers = [];
2401
- var createStormcloudPlayer = (playerList, fallback) => {
2402
- var _a;
2403
- return _a = class extends Component4 {
2404
- constructor() {
2405
- super(...arguments);
2406
- this.state = {
2407
- showPreview: false
2408
- };
2409
- this.references = {
2410
- wrapper: (wrapper) => {
2411
- this.wrapper = wrapper;
2412
- },
2413
- player: (player) => {
2414
- this.player = player;
2415
- }
2416
- };
2417
- this.getActivePlayer = (src) => {
2418
- if (!src) return null;
2419
- for (const player of [...customPlayers, ...playerList]) {
2420
- if (player.canPlay(src)) {
2421
- return player;
2422
- }
2423
- }
2424
- if (fallback) {
2425
- return fallback;
2426
- }
2427
- return null;
2428
- };
2429
- this.getAttributes = (src) => {
2430
- return omit(this.props, SUPPORTED_PROPS);
1930
+ return () => {
1931
+ video.removeEventListener("loadstart", handleLoadStart);
1932
+ video.removeEventListener("loadedmetadata", handleLoadedMetadata);
1933
+ video.removeEventListener("loadeddata", handleLoadedMetadata);
1934
+ video.removeEventListener("canplay", handleCanPlay);
1935
+ video.removeEventListener("waiting", handleWaiting);
1936
+ video.removeEventListener("playing", handlePlaying);
1937
+ video.removeEventListener("pause", handlePause);
1938
+ video.removeEventListener("ended", handleEnded);
2431
1939
  };
2432
- this.handleReady = () => {
2433
- this.props.onReady?.(this);
2434
- };
2435
- this.seekTo = (fraction, type, keepPlaying) => {
2436
- if (!this.player) return null;
2437
- this.player.seekTo(fraction, type, keepPlaying);
2438
- };
2439
- this.getCurrentTime = () => {
2440
- if (!this.player) return null;
2441
- return this.player.getCurrentTime();
2442
- };
2443
- this.getSecondsLoaded = () => {
2444
- if (!this.player) return null;
2445
- return this.player.getSecondsLoaded();
2446
- };
2447
- this.getDuration = () => {
2448
- if (!this.player) return null;
2449
- return this.player.getDuration();
2450
- };
2451
- this.getInternalPlayer = (key = "player") => {
2452
- if (!this.player) return null;
2453
- return this.player.getInternalPlayer(key);
2454
- };
2455
- this.renderActivePlayer = (src) => {
2456
- if (!src) return null;
2457
- const activePlayer = this.getActivePlayer(src);
2458
- if (!activePlayer) return null;
2459
- return React2.createElement(Player, {
2460
- ...this.props,
2461
- key: activePlayer.key,
2462
- ref: this.references.player,
2463
- activePlayer: activePlayer.lazyPlayer || activePlayer,
2464
- onReady: this.handleReady
2465
- });
2466
- };
2467
- }
2468
- render() {
2469
- const {
2470
- src,
2471
- style,
2472
- width,
2473
- height,
2474
- fallback: fallbackElement,
2475
- wrapper: Wrapper
2476
- } = this.props;
2477
- const attributes = this.getAttributes(src);
2478
- const wrapperRef = typeof Wrapper === "string" ? this.references.wrapper : void 0;
2479
- return React2.createElement(
2480
- Wrapper,
2481
- {
2482
- ref: wrapperRef,
2483
- style: { ...style, width, height },
2484
- ...attributes
2485
- },
2486
- React2.createElement(
2487
- UniversalSuspense,
2488
- { fallback: fallbackElement },
2489
- this.renderActivePlayer(src)
2490
- )
2491
- );
2492
- }
2493
- }, _a.displayName = "StormcloudPlayer", _a.defaultProps = {
2494
- ...defaultProps,
2495
- fallback: null,
2496
- wrapper: "div"
2497
- }, _a.addCustomPlayer = (player) => {
2498
- customPlayers.push(player);
2499
- }, _a.removeCustomPlayers = () => {
2500
- customPlayers.length = 0;
2501
- }, _a.canPlay = (src) => {
2502
- for (const Player2 of [...customPlayers, ...playerList]) {
2503
- if (Player2.canPlay(src)) {
2504
- return true;
2505
- }
2506
- }
2507
- return false;
2508
- }, _a.canEnablePIP = (src) => {
2509
- for (const Player2 of [...customPlayers, ...playerList]) {
2510
- if (Player2.canEnablePIP && Player2.canEnablePIP(src)) {
2511
- return true;
2512
- }
2513
- }
2514
- return false;
2515
- }, _a;
2516
- };
2517
- var StormcloudPlayer = createStormcloudPlayer(
2518
- players_default,
2519
- players_default[players_default.length - 1]
2520
- );
2521
- var StormcloudPlayer_default = StormcloudPlayer;
2522
-
2523
- // src/ui/StormcloudVideoPlayer.tsx
2524
- import React3, { useEffect, useRef, useMemo } from "react";
2525
- import {
2526
- FaPlay,
2527
- FaPause,
2528
- FaVolumeUp,
2529
- FaVolumeMute,
2530
- FaVolumeDown,
2531
- FaExpand,
2532
- FaCompress,
2533
- FaSpinner
2534
- } from "react-icons/fa";
2535
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2536
- var CRITICAL_PROPS = [
2537
- "src",
2538
- "allowNativeHls",
2539
- "licenseKey",
2540
- "lowLatencyMode",
2541
- "driftToleranceMs"
2542
- ];
2543
- var StormcloudVideoPlayerComponent = React3.memo(
2544
- (props) => {
2545
- const {
2546
- src,
2547
- autoplay,
2548
- muted,
2549
- lowLatencyMode,
2550
- allowNativeHls,
2551
- driftToleranceMs,
2552
- immediateManifestAds,
2553
- debugAdTiming,
2554
- showCustomControls,
2555
- onVolumeToggle,
2556
- onFullscreenToggle,
2557
- onControlClick,
2558
- onReady,
2559
- wrapperClassName,
2560
- wrapperStyle,
2561
- className,
2562
- style,
2563
- controls,
2564
- playsInline,
2565
- preload,
2566
- poster,
2567
- children,
2568
- licenseKey,
2569
- ...restVideoAttrs
2570
- } = props;
2571
- const videoRef = useRef(null);
2572
- const playerRef = useRef(null);
2573
- const [adStatus, setAdStatus] = React3.useState({ showAds: false, currentIndex: 0, totalAds: 0 });
2574
- const [shouldShowNativeControls, setShouldShowNativeControls] = React3.useState(true);
2575
- const [isMuted, setIsMuted] = React3.useState(false);
2576
- const [isFullscreen, setIsFullscreen] = React3.useState(false);
2577
- const [isPlaying, setIsPlaying] = React3.useState(false);
2578
- const [currentTime, setCurrentTime] = React3.useState(0);
2579
- const [duration, setDuration] = React3.useState(0);
2580
- const [volume, setVolume] = React3.useState(1);
2581
- const [playbackRate, setPlaybackRate] = React3.useState(1);
2582
- const [showVolumeSlider, setShowVolumeSlider] = React3.useState(false);
2583
- const [showSpeedMenu, setShowSpeedMenu] = React3.useState(false);
2584
- const [isLoading, setIsLoading] = React3.useState(true);
2585
- const [isBuffering, setIsBuffering] = React3.useState(false);
2586
- const [showCenterPlay, setShowCenterPlay] = React3.useState(false);
2587
- const formatTime = (seconds) => {
2588
- if (!isFinite(seconds)) return "0:00:00";
2589
- const hours = Math.floor(seconds / 3600);
2590
- const minutes = Math.floor(seconds % 3600 / 60);
2591
- const remainingSeconds = Math.floor(seconds % 60);
2592
- return `${hours}:${minutes.toString().padStart(2, "0")}:${remainingSeconds.toString().padStart(2, "0")}`;
2593
- };
2594
- const handlePlayPause = () => {
2595
- if (videoRef.current) {
2596
- if (videoRef.current.paused) {
2597
- videoRef.current.play();
2598
- setShowCenterPlay(false);
2599
- } else {
2600
- videoRef.current.pause();
2601
- setShowCenterPlay(true);
2602
- }
2603
- }
2604
- };
2605
- const handleCenterPlayClick = () => {
2606
- if (videoRef.current && videoRef.current.paused) {
2607
- videoRef.current.play();
2608
- setShowCenterPlay(false);
2609
- }
2610
- };
2611
- const handleTimelineSeek = (e) => {
2612
- if (videoRef.current && duration > 0 && isFinite(duration)) {
2613
- const rect = e.currentTarget.getBoundingClientRect();
2614
- const clickX = e.clientX - rect.left;
2615
- const progress = Math.max(0, Math.min(1, clickX / rect.width));
2616
- const newTime = progress * duration;
2617
- if (isFinite(newTime) && newTime >= 0 && newTime <= duration) {
2618
- videoRef.current.currentTime = newTime;
2619
- }
2620
- }
2621
- };
2622
- const handleVolumeChange = (newVolume) => {
2623
- if (videoRef.current && isFinite(newVolume)) {
2624
- const clampedVolume = Math.max(0, Math.min(1, newVolume));
2625
- videoRef.current.volume = clampedVolume;
2626
- videoRef.current.muted = clampedVolume === 0;
2627
- }
2628
- };
2629
- const handlePlaybackRateChange = (rate) => {
2630
- if (videoRef.current && isFinite(rate) && rate > 0) {
2631
- videoRef.current.playbackRate = rate;
2632
- }
2633
- setShowSpeedMenu(false);
2634
- };
2635
- const isHlsStream = src?.toLowerCase().includes(".m3u8") || src?.toLowerCase().includes("/hls/");
2636
- const shouldShowEnhancedControls = showCustomControls && (isHlsStream ? allowNativeHls : true);
2637
- const criticalPropsKey = useMemo(() => {
2638
- return CRITICAL_PROPS.map((prop) => `${prop}:${props[prop]}`).join("|");
2639
- }, [src, allowNativeHls, licenseKey, lowLatencyMode, driftToleranceMs]);
2640
- useEffect(() => {
2641
- if (typeof window === "undefined") return;
2642
- const el = videoRef.current;
2643
- if (!el || !src) return;
2644
- if (playerRef.current) {
2645
- try {
2646
- playerRef.current.destroy();
2647
- } catch {
2648
- }
2649
- playerRef.current = null;
2650
- }
2651
- const cfg = {
2652
- src,
2653
- videoElement: el
2654
- };
2655
- if (autoplay !== void 0) cfg.autoplay = autoplay;
2656
- if (muted !== void 0) cfg.muted = muted;
2657
- if (lowLatencyMode !== void 0) cfg.lowLatencyMode = lowLatencyMode;
2658
- if (allowNativeHls !== void 0) cfg.allowNativeHls = allowNativeHls;
2659
- if (driftToleranceMs !== void 0)
2660
- cfg.driftToleranceMs = driftToleranceMs;
2661
- if (immediateManifestAds !== void 0)
2662
- cfg.immediateManifestAds = immediateManifestAds;
2663
- if (debugAdTiming !== void 0) cfg.debugAdTiming = debugAdTiming;
2664
- if (showCustomControls !== void 0)
2665
- cfg.showCustomControls = showCustomControls;
2666
- if (onVolumeToggle !== void 0) cfg.onVolumeToggle = onVolumeToggle;
2667
- if (onFullscreenToggle !== void 0)
2668
- cfg.onFullscreenToggle = onFullscreenToggle;
2669
- if (onControlClick !== void 0) cfg.onControlClick = onControlClick;
2670
- if (licenseKey !== void 0) cfg.licenseKey = licenseKey;
2671
- const player = new StormcloudVideoPlayer(cfg);
2672
- playerRef.current = player;
2673
- player.load().then(() => {
2674
- const showNative = player.shouldShowNativeControls();
2675
- setShouldShowNativeControls(showNative);
2676
- onReady?.(player);
2677
- }).catch(() => {
2678
- });
2679
- return () => {
2680
- try {
2681
- player.destroy();
2682
- } catch {
2683
- }
2684
- playerRef.current = null;
2685
- };
2686
- }, [criticalPropsKey]);
2687
- useEffect(() => {
2688
- if (!playerRef.current) return;
2689
- try {
2690
- if (autoplay !== void 0 && playerRef.current.videoElement) {
2691
- playerRef.current.videoElement.autoplay = autoplay;
2692
- }
2693
- if (muted !== void 0 && playerRef.current.videoElement) {
2694
- playerRef.current.videoElement.muted = muted;
2695
- }
2696
- } catch (error) {
2697
- console.warn("Failed to update player properties:", error);
2698
- }
2699
- }, [autoplay, muted]);
2700
- useEffect(() => {
2701
- if (!playerRef.current) return;
2702
- const checkAdStatus = () => {
2703
- if (playerRef.current) {
2704
- const showAds = playerRef.current.isShowingAds();
2705
- const currentIndex = playerRef.current.getCurrentAdIndex();
2706
- const totalAds = playerRef.current.getTotalAdsInBreak();
2707
- setAdStatus((prev) => {
2708
- if (prev.showAds !== showAds || prev.currentIndex !== currentIndex || prev.totalAds !== totalAds) {
2709
- return { showAds, currentIndex, totalAds };
2710
- }
2711
- return prev;
2712
- });
2713
- }
2714
- };
2715
- const interval = setInterval(checkAdStatus, 100);
2716
- return () => clearInterval(interval);
2717
- }, []);
2718
- useEffect(() => {
2719
- if (typeof window === "undefined" || !playerRef.current) return;
2720
- const handleResize = () => {
2721
- if (playerRef.current && videoRef.current) {
2722
- if (typeof playerRef.current.resize === "function") {
2723
- playerRef.current.resize();
2724
- }
2725
- }
2726
- };
2727
- window.addEventListener("resize", handleResize);
2728
- return () => window.removeEventListener("resize", handleResize);
2729
- }, []);
2730
- useEffect(() => {
2731
- if (!playerRef.current || !videoRef.current) return;
2732
- const updateStates = () => {
2733
- if (playerRef.current && videoRef.current) {
2734
- setIsMuted(playerRef.current.isMuted());
2735
- setIsPlaying(!videoRef.current.paused);
2736
- const currentTimeValue = videoRef.current.currentTime;
2737
- setCurrentTime(isFinite(currentTimeValue) ? currentTimeValue : 0);
2738
- const durationValue = videoRef.current.duration;
2739
- setDuration(isFinite(durationValue) ? durationValue : 0);
2740
- const volumeValue = videoRef.current.volume;
2741
- setVolume(
2742
- isFinite(volumeValue) ? Math.max(0, Math.min(1, volumeValue)) : 1
2743
- );
2744
- const rateValue = videoRef.current.playbackRate;
2745
- setPlaybackRate(
2746
- isFinite(rateValue) && rateValue > 0 ? rateValue : 1
2747
- );
2748
- }
2749
- setIsFullscreen(
2750
- document.fullscreenElement === videoRef.current?.parentElement
2751
- );
2752
- };
2753
- const interval = setInterval(updateStates, 200);
2754
- const handleFullscreenChange = () => {
2755
- setIsFullscreen(
2756
- document.fullscreenElement === videoRef.current?.parentElement
2757
- );
2758
- };
2759
- document.addEventListener("fullscreenchange", handleFullscreenChange);
2760
- return () => {
2761
- clearInterval(interval);
2762
- document.removeEventListener(
2763
- "fullscreenchange",
2764
- handleFullscreenChange
2765
- );
2766
- };
2767
- }, []);
2768
- useEffect(() => {
2769
- if (!videoRef.current) return;
2770
- const handleLoadedMetadata = () => {
2771
- if (videoRef.current) {
2772
- const video2 = videoRef.current;
2773
- void video2.offsetHeight;
2774
- }
2775
- };
2776
- const handleLoadStart = () => {
2777
- setIsLoading(true);
2778
- setIsBuffering(false);
2779
- };
2780
- const handleCanPlay = () => {
2781
- setIsLoading(false);
2782
- setIsBuffering(false);
2783
- };
2784
- const handleWaiting = () => {
2785
- setIsBuffering(true);
2786
- };
2787
- const handlePlaying = () => {
2788
- setIsLoading(false);
2789
- setIsBuffering(false);
2790
- setShowCenterPlay(false);
2791
- };
2792
- const handlePause = () => {
2793
- if (playerRef.current && !playerRef.current.isShowingAds()) {
2794
- setShowCenterPlay(true);
2795
- } else {
2796
- setShowCenterPlay(false);
2797
- }
2798
- };
2799
- const handleEnded = () => {
2800
- setShowCenterPlay(true);
2801
- };
2802
- const video = videoRef.current;
2803
- video.addEventListener("loadstart", handleLoadStart);
2804
- video.addEventListener("loadedmetadata", handleLoadedMetadata);
2805
- video.addEventListener("loadeddata", handleLoadedMetadata);
2806
- video.addEventListener("canplay", handleCanPlay);
2807
- video.addEventListener("waiting", handleWaiting);
2808
- video.addEventListener("playing", handlePlaying);
2809
- video.addEventListener("pause", handlePause);
2810
- video.addEventListener("ended", handleEnded);
2811
- if (video.paused) {
2812
- setShowCenterPlay(true);
2813
- }
2814
- return () => {
2815
- video.removeEventListener("loadstart", handleLoadStart);
2816
- video.removeEventListener("loadedmetadata", handleLoadedMetadata);
2817
- video.removeEventListener("loadeddata", handleLoadedMetadata);
2818
- video.removeEventListener("canplay", handleCanPlay);
2819
- video.removeEventListener("waiting", handleWaiting);
2820
- video.removeEventListener("playing", handlePlaying);
2821
- video.removeEventListener("pause", handlePause);
2822
- video.removeEventListener("ended", handleEnded);
2823
- };
2824
- }, []);
2825
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2826
- /* @__PURE__ */ jsx("style", { children: `
2827
- @keyframes spin {
2828
- from {
2829
- transform: rotate(0deg);
2830
- }
2831
- to {
2832
- transform: rotate(360deg);
2833
- }
2834
- }
2835
-
2836
- .stormcloud-video-wrapper:fullscreen {
2837
- border-radius: 0 !important;
2838
- box-shadow: none !important;
2839
- width: 100vw !important;
2840
- height: 100vh !important;
2841
- max-width: 100vw !important;
2842
- max-height: 100vh !important;
2843
- position: fixed !important;
2844
- top: 0 !important;
2845
- left: 0 !important;
2846
- z-index: 999999 !important;
2847
- background: #000 !important;
2848
- display: flex !important;
2849
- align-items: center !important;
2850
- justify-content: center !important;
2851
- }
2852
-
2853
- .stormcloud-video-wrapper:has(*:fullscreen) {
2854
- border-radius: 0 !important;
2855
- box-shadow: none !important;
2856
- width: 100vw !important;
2857
- height: 100vh !important;
2858
- max-width: 100vw !important;
2859
- max-height: 100vh !important;
2860
- position: fixed !important;
2861
- top: 0 !important;
2862
- left: 0 !important;
2863
- z-index: 999999 !important;
2864
- background: #000 !important;
2865
- display: flex !important;
2866
- align-items: center !important;
2867
- justify-content: center !important;
2868
- }
2869
-
2870
- *:fullscreen {
2871
- width: 100vw !important;
2872
- height: 100vh !important;
2873
- max-width: 100vw !important;
2874
- max-height: 100vh !important;
2875
- position: fixed !important;
2876
- top: 0 !important;
2877
- left: 0 !important;
2878
- z-index: 999999 !important;
2879
- background: #000 !important;
2880
- }
2881
- ` }),
2882
- /* @__PURE__ */ jsxs(
2883
- "div",
1940
+ }, []);
1941
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1942
+ /* @__PURE__ */ jsx("style", { children: `
1943
+ @keyframes spin {
1944
+ from {
1945
+ transform: rotate(0deg);
1946
+ }
1947
+ to {
1948
+ transform: rotate(360deg);
1949
+ }
1950
+ }
1951
+
1952
+ .stormcloud-video-wrapper:fullscreen {
1953
+ border-radius: 0 !important;
1954
+ box-shadow: none !important;
1955
+ width: 100vw !important;
1956
+ height: 100vh !important;
1957
+ max-width: 100vw !important;
1958
+ max-height: 100vh !important;
1959
+ position: fixed !important;
1960
+ top: 0 !important;
1961
+ left: 0 !important;
1962
+ z-index: 999999 !important;
1963
+ background: #000 !important;
1964
+ display: flex !important;
1965
+ align-items: center !important;
1966
+ justify-content: center !important;
1967
+ }
1968
+
1969
+ .stormcloud-video-wrapper:has(*:fullscreen) {
1970
+ border-radius: 0 !important;
1971
+ box-shadow: none !important;
1972
+ width: 100vw !important;
1973
+ height: 100vh !important;
1974
+ max-width: 100vw !important;
1975
+ max-height: 100vh !important;
1976
+ position: fixed !important;
1977
+ top: 0 !important;
1978
+ left: 0 !important;
1979
+ z-index: 999999 !important;
1980
+ background: #000 !important;
1981
+ display: flex !important;
1982
+ align-items: center !important;
1983
+ justify-content: center !important;
1984
+ }
1985
+
1986
+ *:fullscreen {
1987
+ width: 100vw !important;
1988
+ height: 100vh !important;
1989
+ max-width: 100vw !important;
1990
+ max-height: 100vh !important;
1991
+ position: fixed !important;
1992
+ top: 0 !important;
1993
+ left: 0 !important;
1994
+ z-index: 999999 !important;
1995
+ background: #000 !important;
1996
+ }
1997
+ ` }),
1998
+ /* @__PURE__ */ jsxs(
1999
+ "div",
2884
2000
  {
2885
2001
  className: `stormcloud-video-wrapper ${wrapperClassName || ""}`,
2886
2002
  style: {
@@ -3720,48 +2836,939 @@ var StormcloudVideoPlayerComponent = React3.memo(
3720
2836
  )
3721
2837
  ]
3722
2838
  }
3723
- )
3724
- ] });
3725
- },
3726
- (prevProps, nextProps) => {
3727
- for (const prop of CRITICAL_PROPS) {
3728
- if (prevProps[prop] !== nextProps[prop]) {
3729
- return false;
2839
+ )
2840
+ ] });
2841
+ },
2842
+ (prevProps, nextProps) => {
2843
+ for (const prop of CRITICAL_PROPS) {
2844
+ if (prevProps[prop] !== nextProps[prop]) {
2845
+ return false;
2846
+ }
2847
+ }
2848
+ const uiProps = [
2849
+ "autoplay",
2850
+ "muted",
2851
+ "controls",
2852
+ "showCustomControls",
2853
+ "className",
2854
+ "style",
2855
+ "wrapperClassName",
2856
+ "wrapperStyle",
2857
+ "playsInline",
2858
+ "preload",
2859
+ "poster",
2860
+ "children"
2861
+ ];
2862
+ for (const prop of uiProps) {
2863
+ if (prevProps[prop] !== nextProps[prop]) {
2864
+ return false;
2865
+ }
2866
+ }
2867
+ const callbackProps = [
2868
+ "onReady",
2869
+ "onVolumeToggle",
2870
+ "onFullscreenToggle",
2871
+ "onControlClick"
2872
+ ];
2873
+ for (const prop of callbackProps) {
2874
+ if (prevProps[prop] !== nextProps[prop]) {
2875
+ return false;
2876
+ }
2877
+ }
2878
+ return true;
2879
+ }
2880
+ );
2881
+
2882
+ // src/StormcloudPlayer.tsx
2883
+ import React3, { Component as Component4, Suspense } from "react";
2884
+
2885
+ // src/props.ts
2886
+ var noop = () => {
2887
+ };
2888
+ var defaultProps = {
2889
+ playing: false,
2890
+ loop: false,
2891
+ controls: true,
2892
+ volume: 1,
2893
+ muted: false,
2894
+ playbackRate: 1,
2895
+ width: "100%",
2896
+ height: "auto",
2897
+ style: {},
2898
+ progressInterval: 1e3,
2899
+ playsInline: false,
2900
+ autoplay: false,
2901
+ preload: "metadata",
2902
+ poster: "",
2903
+ className: "",
2904
+ wrapperClassName: "",
2905
+ wrapperStyle: {},
2906
+ allowNativeHls: false,
2907
+ lowLatencyMode: false,
2908
+ driftToleranceMs: 1e3,
2909
+ immediateManifestAds: true,
2910
+ debugAdTiming: false,
2911
+ showCustomControls: false,
2912
+ licenseKey: "",
2913
+ adFailsafeTimeoutMs: 1e4,
2914
+ onStart: noop,
2915
+ onPlay: noop,
2916
+ onPause: noop,
2917
+ onBuffer: noop,
2918
+ onBufferEnd: noop,
2919
+ onEnded: noop,
2920
+ onError: noop,
2921
+ onDuration: noop,
2922
+ onSeek: noop,
2923
+ onProgress: noop,
2924
+ onVolumeToggle: noop,
2925
+ onFullscreenToggle: noop,
2926
+ onControlClick: noop
2927
+ };
2928
+
2929
+ // src/utils.ts
2930
+ import { lazy as reactLazy } from "react";
2931
+ var lazy = reactLazy;
2932
+ var omit = (object, keys) => {
2933
+ const result = { ...object };
2934
+ keys.forEach((key) => {
2935
+ delete result[key];
2936
+ });
2937
+ return result;
2938
+ };
2939
+ var isMediaStream = (url) => {
2940
+ return typeof window !== "undefined" && window.MediaStream && url instanceof window.MediaStream;
2941
+ };
2942
+ var supportsWebKitPresentationMode = () => {
2943
+ if (typeof window === "undefined") return false;
2944
+ const video = document.createElement("video");
2945
+ return "webkitSupportsPresentationMode" in video;
2946
+ };
2947
+ var randomString = () => {
2948
+ return Math.random().toString(36).substr(2, 9);
2949
+ };
2950
+ var parseQuery = (url) => {
2951
+ const query = {};
2952
+ const params = new URLSearchParams(url.split("?")[1] || "");
2953
+ params.forEach((value, key) => {
2954
+ query[key] = value;
2955
+ });
2956
+ return query;
2957
+ };
2958
+ var merge = (target, ...sources) => {
2959
+ if (!sources.length) return target;
2960
+ const source = sources.shift();
2961
+ if (isObject(target) && isObject(source)) {
2962
+ for (const key in source) {
2963
+ if (isObject(source[key])) {
2964
+ if (!target[key]) Object.assign(target, { [key]: {} });
2965
+ merge(target[key], source[key]);
2966
+ } else {
2967
+ Object.assign(target, { [key]: source[key] });
2968
+ }
2969
+ }
2970
+ }
2971
+ return merge(target, ...sources);
2972
+ };
2973
+ var isObject = (item) => {
2974
+ return item && typeof item === "object" && !Array.isArray(item);
2975
+ };
2976
+ var IS_BROWSER = typeof window !== "undefined" && window.document;
2977
+ var IS_GLOBAL = typeof globalThis !== "undefined" && globalThis.window && globalThis.window.document;
2978
+ var IS_IOS = IS_BROWSER && /iPad|iPhone|iPod/.test(navigator.userAgent);
2979
+ var IS_SAFARI = IS_BROWSER && /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
2980
+ var SUPPORTS_HLS = () => {
2981
+ if (!IS_BROWSER) return false;
2982
+ const video = document.createElement("video");
2983
+ return Boolean(video.canPlayType("application/vnd.apple.mpegurl"));
2984
+ };
2985
+ var SUPPORTS_DASH = () => {
2986
+ if (!IS_BROWSER) return false;
2987
+ const video = document.createElement("video");
2988
+ return Boolean(video.canPlayType("application/dash+xml"));
2989
+ };
2990
+
2991
+ // src/patterns.ts
2992
+ var HLS_EXTENSIONS = /\.(m3u8)($|\?)/i;
2993
+ var HLS_PATHS = /\/hls\//i;
2994
+ var DASH_EXTENSIONS = /\.(mpd)($|\?)/i;
2995
+ var VIDEO_EXTENSIONS = /\.(mp4|webm|ogg|avi|mov|wmv|flv|mkv)($|\?)/i;
2996
+ var AUDIO_EXTENSIONS = /\.(mp3|wav|ogg|aac|wma|flac|m4a)($|\?)/i;
2997
+ var canPlay = {
2998
+ hls: (url) => {
2999
+ if (!url || typeof url !== "string") return false;
3000
+ return HLS_EXTENSIONS.test(url) || HLS_PATHS.test(url);
3001
+ },
3002
+ dash: (url) => {
3003
+ if (!url || typeof url !== "string") return false;
3004
+ return DASH_EXTENSIONS.test(url);
3005
+ },
3006
+ video: (url) => {
3007
+ if (!url || typeof url !== "string") return false;
3008
+ return VIDEO_EXTENSIONS.test(url);
3009
+ },
3010
+ audio: (url) => {
3011
+ if (!url || typeof url !== "string") return false;
3012
+ return AUDIO_EXTENSIONS.test(url);
3013
+ },
3014
+ file: (url) => {
3015
+ if (!url || typeof url !== "string") return false;
3016
+ return VIDEO_EXTENSIONS.test(url) || AUDIO_EXTENSIONS.test(url);
3017
+ }
3018
+ };
3019
+
3020
+ // src/players/HlsPlayer.tsx
3021
+ import { Component } from "react";
3022
+ var HlsPlayer = class extends Component {
3023
+ constructor() {
3024
+ super(...arguments);
3025
+ this.player = null;
3026
+ this.mounted = false;
3027
+ this.load = async () => {
3028
+ if (!this.props.videoElement || !this.props.src) return;
3029
+ try {
3030
+ if (this.player) {
3031
+ this.player.destroy();
3032
+ this.player = null;
3033
+ }
3034
+ const config = {
3035
+ src: this.props.src,
3036
+ videoElement: this.props.videoElement
3037
+ };
3038
+ if (this.props.autoplay !== void 0)
3039
+ config.autoplay = this.props.autoplay;
3040
+ if (this.props.muted !== void 0) config.muted = this.props.muted;
3041
+ if (this.props.lowLatencyMode !== void 0)
3042
+ config.lowLatencyMode = this.props.lowLatencyMode;
3043
+ if (this.props.allowNativeHls !== void 0)
3044
+ config.allowNativeHls = this.props.allowNativeHls;
3045
+ if (this.props.driftToleranceMs !== void 0)
3046
+ config.driftToleranceMs = this.props.driftToleranceMs;
3047
+ if (this.props.immediateManifestAds !== void 0)
3048
+ config.immediateManifestAds = this.props.immediateManifestAds;
3049
+ if (this.props.debugAdTiming !== void 0)
3050
+ config.debugAdTiming = this.props.debugAdTiming;
3051
+ if (this.props.showCustomControls !== void 0)
3052
+ config.showCustomControls = this.props.showCustomControls;
3053
+ if (this.props.onVolumeToggle !== void 0)
3054
+ config.onVolumeToggle = this.props.onVolumeToggle;
3055
+ if (this.props.onFullscreenToggle !== void 0)
3056
+ config.onFullscreenToggle = this.props.onFullscreenToggle;
3057
+ if (this.props.onControlClick !== void 0)
3058
+ config.onControlClick = this.props.onControlClick;
3059
+ if (this.props.licenseKey !== void 0)
3060
+ config.licenseKey = this.props.licenseKey;
3061
+ if (this.props.adFailsafeTimeoutMs !== void 0)
3062
+ config.adFailsafeTimeoutMs = this.props.adFailsafeTimeoutMs;
3063
+ this.player = new StormcloudVideoPlayer(config);
3064
+ this.props.onMount?.(this);
3065
+ await this.player.load();
3066
+ if (this.mounted) {
3067
+ this.props.onReady?.();
3068
+ }
3069
+ } catch (error) {
3070
+ if (this.mounted) {
3071
+ this.props.onError?.(error);
3072
+ }
3073
+ }
3074
+ };
3075
+ this.play = () => {
3076
+ if (this.props.videoElement) {
3077
+ this.props.videoElement.play();
3078
+ this.props.onPlay?.();
3079
+ }
3080
+ };
3081
+ this.pause = () => {
3082
+ if (this.props.videoElement) {
3083
+ this.props.videoElement.pause();
3084
+ this.props.onPause?.();
3085
+ }
3086
+ };
3087
+ this.stop = () => {
3088
+ this.pause();
3089
+ if (this.props.videoElement) {
3090
+ this.props.videoElement.currentTime = 0;
3091
+ }
3092
+ };
3093
+ this.seekTo = (seconds, keepPlaying) => {
3094
+ if (this.props.videoElement) {
3095
+ this.props.videoElement.currentTime = seconds;
3096
+ if (!keepPlaying) {
3097
+ this.pause();
3098
+ }
3099
+ }
3100
+ };
3101
+ this.setVolume = (volume) => {
3102
+ if (this.props.videoElement) {
3103
+ this.props.videoElement.volume = Math.max(0, Math.min(1, volume));
3104
+ }
3105
+ };
3106
+ this.mute = () => {
3107
+ if (this.props.videoElement) {
3108
+ this.props.videoElement.muted = true;
3109
+ }
3110
+ };
3111
+ this.unmute = () => {
3112
+ if (this.props.videoElement) {
3113
+ this.props.videoElement.muted = false;
3114
+ }
3115
+ };
3116
+ this.setPlaybackRate = (rate) => {
3117
+ if (this.props.videoElement && rate > 0) {
3118
+ this.props.videoElement.playbackRate = rate;
3119
+ }
3120
+ };
3121
+ this.getDuration = () => {
3122
+ if (this.props.videoElement && isFinite(this.props.videoElement.duration)) {
3123
+ return this.props.videoElement.duration;
3124
+ }
3125
+ return null;
3126
+ };
3127
+ this.getCurrentTime = () => {
3128
+ if (this.props.videoElement && isFinite(this.props.videoElement.currentTime)) {
3129
+ return this.props.videoElement.currentTime;
3130
+ }
3131
+ return null;
3132
+ };
3133
+ this.getSecondsLoaded = () => {
3134
+ if (this.props.videoElement && this.props.videoElement.buffered.length > 0) {
3135
+ return this.props.videoElement.buffered.end(
3136
+ this.props.videoElement.buffered.length - 1
3137
+ );
3138
+ }
3139
+ return null;
3140
+ };
3141
+ this.getInternalPlayer = (key = "player") => {
3142
+ if (key === "player") return this.player;
3143
+ if (key === "video") return this.props.videoElement;
3144
+ if (key === "hls" && this.player) return this.player.hls;
3145
+ return null;
3146
+ };
3147
+ }
3148
+ componentDidMount() {
3149
+ this.mounted = true;
3150
+ this.load();
3151
+ }
3152
+ componentWillUnmount() {
3153
+ this.mounted = false;
3154
+ if (this.player) {
3155
+ this.player.destroy();
3156
+ this.player = null;
3157
+ }
3158
+ }
3159
+ componentDidUpdate(prevProps) {
3160
+ if (prevProps.src !== this.props.src) {
3161
+ this.load();
3162
+ }
3163
+ }
3164
+ render() {
3165
+ return null;
3166
+ }
3167
+ };
3168
+ HlsPlayer.displayName = "HlsPlayer";
3169
+ HlsPlayer.canPlay = canPlay.hls;
3170
+
3171
+ // src/players/FilePlayer.tsx
3172
+ import { Component as Component2 } from "react";
3173
+ var FilePlayer = class extends Component2 {
3174
+ constructor() {
3175
+ super(...arguments);
3176
+ this.mounted = false;
3177
+ this.ready = false;
3178
+ this.load = () => {
3179
+ if (!this.props.videoElement || !this.props.src) return;
3180
+ const video = this.props.videoElement;
3181
+ const handleLoadedMetadata = () => {
3182
+ if (this.mounted && !this.ready) {
3183
+ this.ready = true;
3184
+ this.props.onReady?.();
3185
+ }
3186
+ };
3187
+ const handlePlay = () => {
3188
+ if (this.mounted) {
3189
+ this.props.onPlay?.();
3190
+ }
3191
+ };
3192
+ const handlePause = () => {
3193
+ if (this.mounted) {
3194
+ this.props.onPause?.();
3195
+ }
3196
+ };
3197
+ const handleEnded = () => {
3198
+ if (this.mounted) {
3199
+ this.props.onEnded?.();
3200
+ }
3201
+ };
3202
+ const handleError = (error) => {
3203
+ if (this.mounted) {
3204
+ this.props.onError?.(error);
3205
+ }
3206
+ };
3207
+ const handleLoadedData = () => {
3208
+ if (this.mounted) {
3209
+ this.props.onLoaded?.();
3210
+ }
3211
+ };
3212
+ video.addEventListener("loadedmetadata", handleLoadedMetadata);
3213
+ video.addEventListener("play", handlePlay);
3214
+ video.addEventListener("pause", handlePause);
3215
+ video.addEventListener("ended", handleEnded);
3216
+ video.addEventListener("error", handleError);
3217
+ video.addEventListener("loadeddata", handleLoadedData);
3218
+ video.src = this.props.src;
3219
+ if (this.props.autoplay !== void 0) video.autoplay = this.props.autoplay;
3220
+ if (this.props.muted !== void 0) video.muted = this.props.muted;
3221
+ if (this.props.loop !== void 0) video.loop = this.props.loop;
3222
+ if (this.props.controls !== void 0) video.controls = this.props.controls;
3223
+ if (this.props.playsInline !== void 0)
3224
+ video.playsInline = this.props.playsInline;
3225
+ if (this.props.preload !== void 0)
3226
+ video.preload = this.props.preload;
3227
+ if (this.props.poster !== void 0) video.poster = this.props.poster;
3228
+ this.props.onMount?.(this);
3229
+ return () => {
3230
+ video.removeEventListener("loadedmetadata", handleLoadedMetadata);
3231
+ video.removeEventListener("play", handlePlay);
3232
+ video.removeEventListener("pause", handlePause);
3233
+ video.removeEventListener("ended", handleEnded);
3234
+ video.removeEventListener("error", handleError);
3235
+ video.removeEventListener("loadeddata", handleLoadedData);
3236
+ };
3237
+ };
3238
+ this.play = () => {
3239
+ if (this.props.videoElement) {
3240
+ this.props.videoElement.play();
3241
+ }
3242
+ };
3243
+ this.pause = () => {
3244
+ if (this.props.videoElement) {
3245
+ this.props.videoElement.pause();
3246
+ }
3247
+ };
3248
+ this.stop = () => {
3249
+ this.pause();
3250
+ if (this.props.videoElement) {
3251
+ this.props.videoElement.currentTime = 0;
3252
+ }
3253
+ };
3254
+ this.seekTo = (seconds, keepPlaying) => {
3255
+ if (this.props.videoElement) {
3256
+ this.props.videoElement.currentTime = seconds;
3257
+ if (!keepPlaying) {
3258
+ this.pause();
3259
+ }
3260
+ }
3261
+ };
3262
+ this.setVolume = (volume) => {
3263
+ if (this.props.videoElement) {
3264
+ this.props.videoElement.volume = Math.max(0, Math.min(1, volume));
3265
+ }
3266
+ };
3267
+ this.mute = () => {
3268
+ if (this.props.videoElement) {
3269
+ this.props.videoElement.muted = true;
3270
+ }
3271
+ };
3272
+ this.unmute = () => {
3273
+ if (this.props.videoElement) {
3274
+ this.props.videoElement.muted = false;
3275
+ }
3276
+ };
3277
+ this.setPlaybackRate = (rate) => {
3278
+ if (this.props.videoElement && rate > 0) {
3279
+ this.props.videoElement.playbackRate = rate;
3280
+ }
3281
+ };
3282
+ this.setLoop = (loop) => {
3283
+ if (this.props.videoElement) {
3284
+ this.props.videoElement.loop = loop;
3285
+ }
3286
+ };
3287
+ this.getDuration = () => {
3288
+ if (this.props.videoElement && isFinite(this.props.videoElement.duration)) {
3289
+ return this.props.videoElement.duration;
3290
+ }
3291
+ return null;
3292
+ };
3293
+ this.getCurrentTime = () => {
3294
+ if (this.props.videoElement && isFinite(this.props.videoElement.currentTime)) {
3295
+ return this.props.videoElement.currentTime;
3296
+ }
3297
+ return null;
3298
+ };
3299
+ this.getSecondsLoaded = () => {
3300
+ if (this.props.videoElement && this.props.videoElement.buffered.length > 0) {
3301
+ return this.props.videoElement.buffered.end(
3302
+ this.props.videoElement.buffered.length - 1
3303
+ );
3304
+ }
3305
+ return null;
3306
+ };
3307
+ this.getInternalPlayer = (key = "player") => {
3308
+ if (key === "video") return this.props.videoElement;
3309
+ return null;
3310
+ };
3311
+ this.enablePIP = async () => {
3312
+ if (this.props.videoElement && "requestPictureInPicture" in this.props.videoElement) {
3313
+ try {
3314
+ await this.props.videoElement.requestPictureInPicture();
3315
+ } catch (error) {
3316
+ console.warn("Picture-in-Picture failed:", error);
3317
+ }
3318
+ }
3319
+ };
3320
+ this.disablePIP = async () => {
3321
+ if (document.pictureInPictureElement) {
3322
+ try {
3323
+ await document.exitPictureInPicture();
3324
+ } catch (error) {
3325
+ console.warn("Exit Picture-in-Picture failed:", error);
3326
+ }
3327
+ }
3328
+ };
3329
+ }
3330
+ componentDidMount() {
3331
+ this.mounted = true;
3332
+ this.load();
3333
+ }
3334
+ componentWillUnmount() {
3335
+ this.mounted = false;
3336
+ }
3337
+ componentDidUpdate(prevProps) {
3338
+ if (prevProps.src !== this.props.src) {
3339
+ this.load();
3340
+ }
3341
+ }
3342
+ render() {
3343
+ return null;
3344
+ }
3345
+ };
3346
+ FilePlayer.displayName = "FilePlayer";
3347
+ FilePlayer.canPlay = canPlay.file;
3348
+
3349
+ // src/players/index.ts
3350
+ var players = [
3351
+ {
3352
+ key: "hls",
3353
+ name: "HLS Player",
3354
+ canPlay: canPlay.hls,
3355
+ lazyPlayer: lazy(() => Promise.resolve({ default: HlsPlayer }))
3356
+ },
3357
+ {
3358
+ key: "file",
3359
+ name: "File Player",
3360
+ canPlay: canPlay.file,
3361
+ canEnablePIP: (url) => {
3362
+ return canPlay.file(url) && (document.pictureInPictureEnabled || typeof document.webkitSupportsPresentationMode === "function");
3363
+ },
3364
+ lazyPlayer: lazy(() => Promise.resolve({ default: FilePlayer }))
3365
+ }
3366
+ ];
3367
+ var players_default = players;
3368
+
3369
+ // src/Player.tsx
3370
+ import React2, { Component as Component3 } from "react";
3371
+ var SEEK_ON_PLAY_EXPIRY = 5e3;
3372
+ var Player = class extends Component3 {
3373
+ constructor() {
3374
+ super(...arguments);
3375
+ this.mounted = false;
3376
+ this.isReady = false;
3377
+ this.isPlaying = false;
3378
+ this.isLoading = true;
3379
+ this.loadOnReady = null;
3380
+ this.startOnPlay = true;
3381
+ this.seekOnPlay = null;
3382
+ this.onDurationCalled = false;
3383
+ this.handlePlayerMount = (player) => {
3384
+ if (this.player) {
3385
+ this.progress();
3386
+ return;
3387
+ }
3388
+ this.player = player;
3389
+ this.player.load(this.props.src);
3390
+ this.progress();
3391
+ };
3392
+ this.getInternalPlayer = (key) => {
3393
+ if (!this.player) return null;
3394
+ return this.player.getInternalPlayer(key);
3395
+ };
3396
+ this.progress = () => {
3397
+ if (this.props.src && this.player && this.isReady) {
3398
+ const playedSeconds = this.getCurrentTime() || 0;
3399
+ const loadedSeconds = this.getSecondsLoaded();
3400
+ const duration = this.getDuration();
3401
+ if (duration) {
3402
+ const progress = {
3403
+ playedSeconds,
3404
+ played: playedSeconds / duration,
3405
+ loaded: 0,
3406
+ loadedSeconds: 0
3407
+ };
3408
+ if (loadedSeconds !== null) {
3409
+ progress.loadedSeconds = loadedSeconds;
3410
+ progress.loaded = loadedSeconds / duration;
3411
+ }
3412
+ if (progress.playedSeconds !== this.prevPlayed || progress.loadedSeconds !== this.prevLoaded) {
3413
+ this.props.onProgress?.(progress);
3414
+ }
3415
+ this.prevPlayed = progress.playedSeconds;
3416
+ this.prevLoaded = progress.loadedSeconds;
3417
+ }
3418
+ }
3419
+ this.progressTimeout = window.setTimeout(
3420
+ this.progress,
3421
+ this.props.progressInterval || 1e3
3422
+ );
3423
+ };
3424
+ this.handleReady = () => {
3425
+ if (!this.mounted) return;
3426
+ this.isReady = true;
3427
+ this.isLoading = false;
3428
+ const { onReady, playing, volume, muted } = this.props;
3429
+ onReady();
3430
+ if (!muted && volume !== null) {
3431
+ this.player.setVolume(volume);
3432
+ }
3433
+ if (this.loadOnReady) {
3434
+ this.player.load(this.loadOnReady, true);
3435
+ this.loadOnReady = null;
3436
+ } else if (playing) {
3437
+ this.player.play();
3438
+ }
3439
+ this.handleDurationCheck();
3440
+ };
3441
+ this.handlePlay = () => {
3442
+ this.isPlaying = true;
3443
+ this.isLoading = false;
3444
+ const { onStart, onPlay, playbackRate } = this.props;
3445
+ if (this.startOnPlay) {
3446
+ if (this.player.setPlaybackRate && playbackRate !== 1) {
3447
+ this.player.setPlaybackRate(playbackRate);
3448
+ }
3449
+ onStart?.();
3450
+ this.startOnPlay = false;
3451
+ }
3452
+ onPlay?.();
3453
+ if (this.seekOnPlay) {
3454
+ this.seekTo(this.seekOnPlay);
3455
+ this.seekOnPlay = null;
3456
+ }
3457
+ this.handleDurationCheck();
3458
+ };
3459
+ this.handlePause = (e) => {
3460
+ this.isPlaying = false;
3461
+ if (!this.isLoading) {
3462
+ this.props.onPause?.(e);
3463
+ }
3464
+ };
3465
+ this.handleEnded = () => {
3466
+ const { activePlayer, loop, onEnded } = this.props;
3467
+ if (activePlayer.loopOnEnded && loop) {
3468
+ this.seekTo(0);
3469
+ }
3470
+ if (!loop) {
3471
+ this.isPlaying = false;
3472
+ onEnded?.();
3473
+ }
3474
+ };
3475
+ this.handleError = (...args) => {
3476
+ this.isLoading = false;
3477
+ this.props.onError?.(args[0], args[1], args[2], args[3]);
3478
+ };
3479
+ this.handleDurationCheck = () => {
3480
+ clearTimeout(this.durationCheckTimeout);
3481
+ const duration = this.getDuration();
3482
+ if (duration) {
3483
+ if (!this.onDurationCalled) {
3484
+ this.props.onDuration?.(duration);
3485
+ this.onDurationCalled = true;
3486
+ }
3487
+ } else {
3488
+ this.durationCheckTimeout = window.setTimeout(
3489
+ this.handleDurationCheck,
3490
+ 100
3491
+ );
3492
+ }
3493
+ };
3494
+ this.handleLoaded = () => {
3495
+ this.isLoading = false;
3496
+ };
3497
+ }
3498
+ componentDidMount() {
3499
+ this.mounted = true;
3500
+ }
3501
+ componentWillUnmount() {
3502
+ clearTimeout(this.progressTimeout);
3503
+ clearTimeout(this.durationCheckTimeout);
3504
+ this.mounted = false;
3505
+ }
3506
+ componentDidUpdate(prevProps) {
3507
+ if (!this.player) return;
3508
+ const { src, playing, volume, muted, playbackRate, loop, activePlayer } = this.props;
3509
+ if (prevProps.src !== src) {
3510
+ if (this.isLoading && !activePlayer.forceLoad && !isMediaStream(src)) {
3511
+ console.warn(
3512
+ `StormcloudPlayer: the attempt to load ${src} is being deferred until the player has loaded`
3513
+ );
3514
+ this.loadOnReady = src || null;
3515
+ return;
3516
+ }
3517
+ this.isLoading = true;
3518
+ this.startOnPlay = true;
3519
+ this.onDurationCalled = false;
3520
+ this.player.load(src, this.isReady);
3521
+ }
3522
+ if (!prevProps.playing && playing && !this.isPlaying) {
3523
+ this.player.play();
3524
+ }
3525
+ if (prevProps.playing && !playing && this.isPlaying) {
3526
+ this.player.pause();
3527
+ }
3528
+ if (prevProps.volume !== volume && volume !== null) {
3529
+ this.player.setVolume(volume);
3530
+ }
3531
+ if (prevProps.muted !== muted) {
3532
+ if (muted) {
3533
+ this.player.mute();
3534
+ } else {
3535
+ this.player.unmute();
3536
+ if (volume !== null) {
3537
+ setTimeout(() => this.player.setVolume(volume));
3538
+ }
3730
3539
  }
3731
3540
  }
3732
- const uiProps = [
3733
- "autoplay",
3734
- "muted",
3735
- "controls",
3736
- "showCustomControls",
3737
- "className",
3738
- "style",
3739
- "wrapperClassName",
3740
- "wrapperStyle",
3741
- "playsInline",
3742
- "preload",
3743
- "poster",
3744
- "children"
3745
- ];
3746
- for (const prop of uiProps) {
3747
- if (prevProps[prop] !== nextProps[prop]) {
3748
- return false;
3541
+ if (prevProps.playbackRate !== playbackRate && this.player.setPlaybackRate) {
3542
+ this.player.setPlaybackRate(playbackRate);
3543
+ }
3544
+ if (prevProps.loop !== loop && this.player.setLoop) {
3545
+ this.player.setLoop(loop);
3546
+ }
3547
+ }
3548
+ getDuration() {
3549
+ if (!this.isReady) return null;
3550
+ return this.player.getDuration();
3551
+ }
3552
+ getCurrentTime() {
3553
+ if (!this.isReady) return null;
3554
+ return this.player.getCurrentTime();
3555
+ }
3556
+ getSecondsLoaded() {
3557
+ if (!this.isReady) return null;
3558
+ return this.player.getSecondsLoaded();
3559
+ }
3560
+ seekTo(amount, type, keepPlaying) {
3561
+ if (!this.isReady) {
3562
+ if (amount !== 0) {
3563
+ this.seekOnPlay = amount;
3564
+ setTimeout(() => {
3565
+ this.seekOnPlay = null;
3566
+ }, SEEK_ON_PLAY_EXPIRY);
3749
3567
  }
3568
+ return;
3750
3569
  }
3751
- const callbackProps = [
3752
- "onReady",
3753
- "onVolumeToggle",
3754
- "onFullscreenToggle",
3755
- "onControlClick"
3756
- ];
3757
- for (const prop of callbackProps) {
3758
- if (prevProps[prop] !== nextProps[prop]) {
3759
- return false;
3570
+ const isFraction = !type ? amount > 0 && amount < 1 : type === "fraction";
3571
+ if (isFraction) {
3572
+ const duration = this.player.getDuration();
3573
+ if (!duration) {
3574
+ console.warn(
3575
+ "StormcloudPlayer: could not seek using fraction \u2013 duration not yet available"
3576
+ );
3577
+ return;
3760
3578
  }
3579
+ this.player.seekTo(duration * amount, keepPlaying);
3580
+ return;
3761
3581
  }
3762
- return true;
3582
+ this.player.seekTo(amount, keepPlaying);
3583
+ }
3584
+ render() {
3585
+ const Player2 = this.props.activePlayer;
3586
+ if (!Player2) {
3587
+ return null;
3588
+ }
3589
+ return React2.createElement(Player2, {
3590
+ ...this.props,
3591
+ onMount: this.handlePlayerMount,
3592
+ onReady: this.handleReady,
3593
+ onPlay: this.handlePlay,
3594
+ onPause: this.handlePause,
3595
+ onEnded: this.handleEnded,
3596
+ onLoaded: this.handleLoaded,
3597
+ onError: this.handleError
3598
+ });
3763
3599
  }
3600
+ };
3601
+ Player.displayName = "Player";
3602
+ Player.defaultProps = defaultProps;
3603
+
3604
+ // src/StormcloudPlayer.tsx
3605
+ var IS_BROWSER2 = typeof window !== "undefined" && window.document;
3606
+ var IS_GLOBAL2 = typeof globalThis !== "undefined" && globalThis.window && globalThis.window.document;
3607
+ var UniversalSuspense = IS_BROWSER2 || IS_GLOBAL2 ? Suspense : () => null;
3608
+ var SUPPORTED_PROPS = [
3609
+ "src",
3610
+ "playing",
3611
+ "loop",
3612
+ "controls",
3613
+ "volume",
3614
+ "muted",
3615
+ "playbackRate",
3616
+ "width",
3617
+ "height",
3618
+ "style",
3619
+ "progressInterval",
3620
+ "playsInline",
3621
+ "autoplay",
3622
+ "preload",
3623
+ "poster",
3624
+ "className",
3625
+ "wrapperClassName",
3626
+ "wrapperStyle",
3627
+ "allowNativeHls",
3628
+ "lowLatencyMode",
3629
+ "driftToleranceMs",
3630
+ "immediateManifestAds",
3631
+ "debugAdTiming",
3632
+ "showCustomControls",
3633
+ "licenseKey",
3634
+ "adFailsafeTimeoutMs",
3635
+ "onReady",
3636
+ "onStart",
3637
+ "onPlay",
3638
+ "onPause",
3639
+ "onBuffer",
3640
+ "onBufferEnd",
3641
+ "onEnded",
3642
+ "onError",
3643
+ "onDuration",
3644
+ "onSeek",
3645
+ "onProgress",
3646
+ "onVolumeToggle",
3647
+ "onFullscreenToggle",
3648
+ "onControlClick"
3649
+ ];
3650
+ var customPlayers = [];
3651
+ var createStormcloudPlayer = (playerList, fallback) => {
3652
+ var _a;
3653
+ return _a = class extends Component4 {
3654
+ constructor() {
3655
+ super(...arguments);
3656
+ this.state = {
3657
+ showPreview: false
3658
+ };
3659
+ this.references = {
3660
+ wrapper: (wrapper) => {
3661
+ this.wrapper = wrapper;
3662
+ },
3663
+ player: (player) => {
3664
+ this.player = player;
3665
+ }
3666
+ };
3667
+ this.getActivePlayer = (src) => {
3668
+ if (!src) return null;
3669
+ for (const player of [...customPlayers, ...playerList]) {
3670
+ if (player.canPlay(src)) {
3671
+ return player;
3672
+ }
3673
+ }
3674
+ if (fallback) {
3675
+ return fallback;
3676
+ }
3677
+ return null;
3678
+ };
3679
+ this.getAttributes = (src) => {
3680
+ return omit(this.props, SUPPORTED_PROPS);
3681
+ };
3682
+ this.handleReady = () => {
3683
+ this.props.onReady?.(this);
3684
+ };
3685
+ this.seekTo = (fraction, type, keepPlaying) => {
3686
+ if (!this.player) return null;
3687
+ this.player.seekTo(fraction, type, keepPlaying);
3688
+ };
3689
+ this.getCurrentTime = () => {
3690
+ if (!this.player) return null;
3691
+ return this.player.getCurrentTime();
3692
+ };
3693
+ this.getSecondsLoaded = () => {
3694
+ if (!this.player) return null;
3695
+ return this.player.getSecondsLoaded();
3696
+ };
3697
+ this.getDuration = () => {
3698
+ if (!this.player) return null;
3699
+ return this.player.getDuration();
3700
+ };
3701
+ this.getInternalPlayer = (key = "player") => {
3702
+ if (!this.player) return null;
3703
+ return this.player.getInternalPlayer(key);
3704
+ };
3705
+ this.renderActivePlayer = (src) => {
3706
+ if (!src) return null;
3707
+ const activePlayer = this.getActivePlayer(src);
3708
+ if (!activePlayer) return null;
3709
+ return React3.createElement(Player, {
3710
+ ...this.props,
3711
+ key: activePlayer.key,
3712
+ ref: this.references.player,
3713
+ activePlayer: activePlayer.lazyPlayer || activePlayer,
3714
+ onReady: this.handleReady
3715
+ });
3716
+ };
3717
+ }
3718
+ render() {
3719
+ const {
3720
+ src,
3721
+ style,
3722
+ width,
3723
+ height,
3724
+ fallback: fallbackElement,
3725
+ wrapper: Wrapper
3726
+ } = this.props;
3727
+ const attributes = this.getAttributes(src);
3728
+ const wrapperRef = typeof Wrapper === "string" ? this.references.wrapper : void 0;
3729
+ return React3.createElement(
3730
+ Wrapper,
3731
+ {
3732
+ ref: wrapperRef,
3733
+ style: { ...style, width, height },
3734
+ ...attributes
3735
+ },
3736
+ React3.createElement(
3737
+ UniversalSuspense,
3738
+ { fallback: fallbackElement },
3739
+ this.renderActivePlayer(src)
3740
+ )
3741
+ );
3742
+ }
3743
+ }, _a.displayName = "StormcloudPlayer", _a.defaultProps = {
3744
+ ...defaultProps,
3745
+ fallback: null,
3746
+ wrapper: "div"
3747
+ }, _a.addCustomPlayer = (player) => {
3748
+ customPlayers.push(player);
3749
+ }, _a.removeCustomPlayers = () => {
3750
+ customPlayers.length = 0;
3751
+ }, _a.canPlay = (src) => {
3752
+ for (const Player2 of [...customPlayers, ...playerList]) {
3753
+ if (Player2.canPlay(src)) {
3754
+ return true;
3755
+ }
3756
+ }
3757
+ return false;
3758
+ }, _a.canEnablePIP = (src) => {
3759
+ for (const Player2 of [...customPlayers, ...playerList]) {
3760
+ if (Player2.canEnablePIP && Player2.canEnablePIP(src)) {
3761
+ return true;
3762
+ }
3763
+ }
3764
+ return false;
3765
+ }, _a;
3766
+ };
3767
+ var StormcloudPlayer = createStormcloudPlayer(
3768
+ players_default,
3769
+ players_default[players_default.length - 1]
3764
3770
  );
3771
+ var StormcloudPlayer_default = StormcloudPlayer;
3765
3772
  export {
3766
3773
  IS_BROWSER,
3767
3774
  IS_GLOBAL,
@@ -3769,11 +3776,12 @@ export {
3769
3776
  IS_SAFARI,
3770
3777
  SUPPORTS_DASH,
3771
3778
  SUPPORTS_HLS,
3779
+ StormcloudPlayer_default as StormcloudPlayer,
3772
3780
  StormcloudVideoPlayer,
3773
3781
  StormcloudVideoPlayerComponent,
3774
3782
  canPlay,
3775
3783
  createStormcloudPlayer,
3776
- StormcloudPlayer_default as default,
3784
+ StormcloudVideoPlayerComponent as default,
3777
3785
  getBrowserID,
3778
3786
  getClientInfo,
3779
3787
  isMediaStream,