stormcloud-video-player 0.1.13 → 0.2.0

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,3 +1,6 @@
1
+ // src/StormcloudPlayer.tsx
2
+ import React2, { Component as Component4, Suspense } from "react";
3
+
1
4
  // src/player/StormcloudVideoPlayer.ts
2
5
  import Hls from "hls.js";
3
6
 
@@ -1092,7 +1095,6 @@ var StormcloudVideoPlayer = class {
1092
1095
  }
1093
1096
  parseScte35Binary(data) {
1094
1097
  class BitReader {
1095
- // 0..7
1096
1098
  constructor(buf) {
1097
1099
  this.buf = buf;
1098
1100
  this.bytePos = 0;
@@ -1630,8 +1632,896 @@ var StormcloudVideoPlayer = class {
1630
1632
  }
1631
1633
  };
1632
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);
1822
+ }
1823
+ }
1824
+ };
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;
1841
+ }
1842
+ };
1843
+ this.seekTo = (seconds, keepPlaying) => {
1844
+ if (this.props.videoElement) {
1845
+ this.props.videoElement.currentTime = seconds;
1846
+ if (!keepPlaying) {
1847
+ this.pause();
1848
+ }
1849
+ }
1850
+ };
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;
1869
+ }
1870
+ };
1871
+ this.getDuration = () => {
1872
+ if (this.props.videoElement && isFinite(this.props.videoElement.duration)) {
1873
+ return this.props.videoElement.duration;
1874
+ }
1875
+ return null;
1876
+ };
1877
+ this.getCurrentTime = () => {
1878
+ if (this.props.videoElement && isFinite(this.props.videoElement.currentTime)) {
1879
+ return this.props.videoElement.currentTime;
1880
+ }
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
1887
+ );
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?.();
1935
+ }
1936
+ };
1937
+ const handlePlay = () => {
1938
+ if (this.mounted) {
1939
+ this.props.onPlay?.();
1940
+ }
1941
+ };
1942
+ const handlePause = () => {
1943
+ if (this.mounted) {
1944
+ this.props.onPause?.();
1945
+ }
1946
+ };
1947
+ const handleEnded = () => {
1948
+ if (this.mounted) {
1949
+ this.props.onEnded?.();
1950
+ }
1951
+ };
1952
+ const handleError = (error) => {
1953
+ if (this.mounted) {
1954
+ this.props.onError?.(error);
1955
+ }
1956
+ };
1957
+ const handleLoadedData = () => {
1958
+ if (this.mounted) {
1959
+ this.props.onLoaded?.();
1960
+ }
1961
+ };
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);
1986
+ };
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
2053
+ );
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);
2076
+ }
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;
2167
+ }
2168
+ }
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);
2431
+ };
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
+
1633
2523
  // src/ui/StormcloudVideoPlayer.tsx
1634
- import React, { useEffect, useRef, useMemo } from "react";
2524
+ import React3, { useEffect, useRef, useMemo } from "react";
1635
2525
  import {
1636
2526
  FaPlay,
1637
2527
  FaPause,
@@ -1650,7 +2540,7 @@ var CRITICAL_PROPS = [
1650
2540
  "lowLatencyMode",
1651
2541
  "driftToleranceMs"
1652
2542
  ];
1653
- var StormcloudVideoPlayerComponent = React.memo(
2543
+ var StormcloudVideoPlayerComponent = React3.memo(
1654
2544
  (props) => {
1655
2545
  const {
1656
2546
  src,
@@ -1680,20 +2570,20 @@ var StormcloudVideoPlayerComponent = React.memo(
1680
2570
  } = props;
1681
2571
  const videoRef = useRef(null);
1682
2572
  const playerRef = useRef(null);
1683
- const [adStatus, setAdStatus] = React.useState({ showAds: false, currentIndex: 0, totalAds: 0 });
1684
- const [shouldShowNativeControls, setShouldShowNativeControls] = React.useState(true);
1685
- const [isMuted, setIsMuted] = React.useState(false);
1686
- const [isFullscreen, setIsFullscreen] = React.useState(false);
1687
- const [isPlaying, setIsPlaying] = React.useState(false);
1688
- const [currentTime, setCurrentTime] = React.useState(0);
1689
- const [duration, setDuration] = React.useState(0);
1690
- const [volume, setVolume] = React.useState(1);
1691
- const [playbackRate, setPlaybackRate] = React.useState(1);
1692
- const [showVolumeSlider, setShowVolumeSlider] = React.useState(false);
1693
- const [showSpeedMenu, setShowSpeedMenu] = React.useState(false);
1694
- const [isLoading, setIsLoading] = React.useState(true);
1695
- const [isBuffering, setIsBuffering] = React.useState(false);
1696
- const [showCenterPlay, setShowCenterPlay] = React.useState(false);
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);
1697
2587
  const formatTime = (seconds) => {
1698
2588
  if (!isFinite(seconds)) return "0:00:00";
1699
2589
  const hours = Math.floor(seconds / 3600);
@@ -2873,11 +3763,28 @@ var StormcloudVideoPlayerComponent = React.memo(
2873
3763
  }
2874
3764
  );
2875
3765
  export {
3766
+ IS_BROWSER,
3767
+ IS_GLOBAL,
3768
+ IS_IOS,
3769
+ IS_SAFARI,
3770
+ SUPPORTS_DASH,
3771
+ SUPPORTS_HLS,
2876
3772
  StormcloudVideoPlayer,
2877
3773
  StormcloudVideoPlayerComponent,
3774
+ canPlay,
3775
+ createStormcloudPlayer,
3776
+ StormcloudPlayer_default as default,
2878
3777
  getBrowserID,
2879
3778
  getClientInfo,
3779
+ isMediaStream,
3780
+ lazy,
3781
+ merge,
3782
+ omit,
3783
+ parseQuery,
3784
+ players_default as players,
3785
+ randomString,
2880
3786
  sendHeartbeat,
2881
- sendInitialTracking
3787
+ sendInitialTracking,
3788
+ supportsWebKitPresentationMode
2882
3789
  };
2883
3790
  //# sourceMappingURL=index.js.map