@livepeer-frameworks/player-react 0.1.0 → 0.1.2
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/README.md +7 -9
- package/dist/cjs/_virtual/_rollupPluginBabelHelpers.js +359 -0
- package/dist/cjs/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
- package/dist/cjs/assets/logomark.svg.js +8 -0
- package/dist/cjs/assets/logomark.svg.js.map +1 -0
- package/dist/cjs/components/DevModePanel.js +826 -0
- package/dist/cjs/components/DevModePanel.js.map +1 -0
- package/dist/cjs/components/DvdLogo.js +200 -0
- package/dist/cjs/components/DvdLogo.js.map +1 -0
- package/dist/cjs/components/Icons.js +439 -0
- package/dist/cjs/components/Icons.js.map +1 -0
- package/dist/cjs/components/IdleScreen.js +587 -0
- package/dist/cjs/components/IdleScreen.js.map +1 -0
- package/dist/cjs/components/LoadingScreen.js +523 -0
- package/dist/cjs/components/LoadingScreen.js.map +1 -0
- package/dist/cjs/components/Player.js +420 -0
- package/dist/cjs/components/Player.js.map +1 -0
- package/dist/cjs/components/PlayerControls.js +798 -0
- package/dist/cjs/components/PlayerControls.js.map +1 -0
- package/dist/cjs/components/PlayerErrorBoundary.js +80 -0
- package/dist/cjs/components/PlayerErrorBoundary.js.map +1 -0
- package/dist/cjs/components/SeekBar.js +253 -0
- package/dist/cjs/components/SeekBar.js.map +1 -0
- package/dist/cjs/components/SkipIndicator.js +92 -0
- package/dist/cjs/components/SkipIndicator.js.map +1 -0
- package/dist/cjs/components/SpeedIndicator.js +43 -0
- package/dist/cjs/components/SpeedIndicator.js.map +1 -0
- package/dist/cjs/components/StatsPanel.js +202 -0
- package/dist/cjs/components/StatsPanel.js.map +1 -0
- package/dist/cjs/components/StreamStateOverlay.js +229 -0
- package/dist/cjs/components/StreamStateOverlay.js.map +1 -0
- package/dist/cjs/components/ThumbnailOverlay.js +86 -0
- package/dist/cjs/components/ThumbnailOverlay.js.map +1 -0
- package/dist/cjs/components/TitleOverlay.js +32 -0
- package/dist/cjs/components/TitleOverlay.js.map +1 -0
- package/dist/cjs/context/PlayerContext.js +46 -0
- package/dist/cjs/context/PlayerContext.js.map +1 -0
- package/dist/cjs/hooks/useMetaTrack.js +165 -0
- package/dist/cjs/hooks/useMetaTrack.js.map +1 -0
- package/dist/cjs/hooks/usePlaybackQuality.js +131 -0
- package/dist/cjs/hooks/usePlaybackQuality.js.map +1 -0
- package/dist/cjs/hooks/usePlayerController.js +518 -0
- package/dist/cjs/hooks/usePlayerController.js.map +1 -0
- package/dist/cjs/hooks/usePlayerSelection.js +90 -0
- package/dist/cjs/hooks/usePlayerSelection.js.map +1 -0
- package/dist/cjs/hooks/useStreamState.js +360 -0
- package/dist/cjs/hooks/useStreamState.js.map +1 -0
- package/dist/cjs/hooks/useTelemetry.js +120 -0
- package/dist/cjs/hooks/useTelemetry.js.map +1 -0
- package/dist/cjs/hooks/useViewerEndpoints.js +222 -0
- package/dist/cjs/hooks/useViewerEndpoints.js.map +1 -0
- package/dist/cjs/index.js +97 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/ui/badge.js +34 -0
- package/dist/cjs/ui/badge.js.map +1 -0
- package/dist/cjs/ui/button.js +74 -0
- package/dist/cjs/ui/button.js.map +1 -0
- package/dist/cjs/ui/context-menu.js +163 -0
- package/dist/cjs/ui/context-menu.js.map +1 -0
- package/dist/cjs/ui/slider.js +60 -0
- package/dist/cjs/ui/slider.js.map +1 -0
- package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +329 -0
- package/dist/esm/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
- package/dist/esm/assets/logomark.svg.js +4 -0
- package/dist/esm/assets/logomark.svg.js.map +1 -0
- package/dist/esm/components/DevModePanel.js +822 -0
- package/dist/esm/components/DevModePanel.js.map +1 -0
- package/dist/esm/components/DvdLogo.js +196 -0
- package/dist/esm/components/DvdLogo.js.map +1 -0
- package/dist/esm/components/Icons.js +421 -0
- package/dist/esm/components/Icons.js.map +1 -0
- package/dist/esm/components/IdleScreen.js +582 -0
- package/dist/esm/components/IdleScreen.js.map +1 -0
- package/dist/esm/components/LoadingScreen.js +519 -0
- package/dist/esm/components/LoadingScreen.js.map +1 -0
- package/dist/esm/components/Player.js +416 -0
- package/dist/esm/components/Player.js.map +1 -0
- package/dist/esm/components/PlayerControls.js +794 -0
- package/dist/esm/components/PlayerControls.js.map +1 -0
- package/dist/esm/components/PlayerErrorBoundary.js +76 -0
- package/dist/esm/components/PlayerErrorBoundary.js.map +1 -0
- package/dist/esm/components/SeekBar.js +249 -0
- package/dist/esm/components/SeekBar.js.map +1 -0
- package/dist/esm/components/SkipIndicator.js +88 -0
- package/dist/esm/components/SkipIndicator.js.map +1 -0
- package/dist/esm/components/SpeedIndicator.js +39 -0
- package/dist/esm/components/SpeedIndicator.js.map +1 -0
- package/dist/esm/components/StatsPanel.js +198 -0
- package/dist/esm/components/StatsPanel.js.map +1 -0
- package/dist/esm/components/StreamStateOverlay.js +224 -0
- package/dist/esm/components/StreamStateOverlay.js.map +1 -0
- package/dist/esm/components/ThumbnailOverlay.js +82 -0
- package/dist/esm/components/ThumbnailOverlay.js.map +1 -0
- package/dist/esm/components/TitleOverlay.js +28 -0
- package/dist/esm/components/TitleOverlay.js.map +1 -0
- package/dist/esm/context/PlayerContext.js +41 -0
- package/dist/esm/context/PlayerContext.js.map +1 -0
- package/dist/esm/hooks/useMetaTrack.js +163 -0
- package/dist/esm/hooks/useMetaTrack.js.map +1 -0
- package/dist/esm/hooks/usePlaybackQuality.js +129 -0
- package/dist/esm/hooks/usePlaybackQuality.js.map +1 -0
- package/dist/esm/hooks/usePlayerController.js +516 -0
- package/dist/esm/hooks/usePlayerController.js.map +1 -0
- package/dist/esm/hooks/usePlayerSelection.js +88 -0
- package/dist/esm/hooks/usePlayerSelection.js.map +1 -0
- package/dist/esm/hooks/useStreamState.js +358 -0
- package/dist/esm/hooks/useStreamState.js.map +1 -0
- package/dist/esm/hooks/useTelemetry.js +118 -0
- package/dist/esm/hooks/useTelemetry.js.map +1 -0
- package/dist/esm/hooks/useViewerEndpoints.js +220 -0
- package/dist/esm/hooks/useViewerEndpoints.js.map +1 -0
- package/dist/esm/index.js +23 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/ui/badge.js +31 -0
- package/dist/esm/ui/badge.js.map +1 -0
- package/dist/esm/ui/button.js +52 -0
- package/dist/esm/ui/button.js.map +1 -0
- package/dist/esm/ui/context-menu.js +132 -0
- package/dist/esm/ui/context-menu.js.map +1 -0
- package/dist/esm/ui/slider.js +38 -0
- package/dist/esm/ui/slider.js.map +1 -0
- package/dist/types/components/DvdLogo.d.ts +1 -1
- package/dist/types/components/Icons.d.ts +1 -1
- package/dist/types/components/Player.d.ts +1 -1
- package/dist/types/components/PlayerErrorBoundary.d.ts +2 -1
- package/dist/types/components/StreamStateOverlay.d.ts +2 -2
- package/dist/types/components/SubtitleRenderer.d.ts +2 -2
- package/dist/types/context/PlayerContext.d.ts +2 -2
- package/dist/types/context/index.d.ts +2 -2
- package/dist/types/hooks/useMetaTrack.d.ts +3 -3
- package/dist/types/hooks/usePlaybackQuality.d.ts +2 -2
- package/dist/types/hooks/usePlayerController.d.ts +26 -3
- package/dist/types/hooks/usePlayerSelection.d.ts +1 -1
- package/dist/types/hooks/useStreamState.d.ts +1 -1
- package/dist/types/hooks/useTelemetry.d.ts +1 -1
- package/dist/types/hooks/useViewerEndpoints.d.ts +3 -3
- package/dist/types/index.d.ts +28 -28
- package/dist/types/types.d.ts +3 -3
- package/dist/types/ui/select.d.ts +1 -1
- package/package.json +22 -14
- package/src/components/DevModePanel.tsx +244 -143
- package/src/components/DvdLogo.tsx +1 -1
- package/src/components/Icons.tsx +105 -25
- package/src/components/IdleScreen.tsx +262 -128
- package/src/components/LoadingScreen.tsx +169 -151
- package/src/components/LogoOverlay.tsx +3 -6
- package/src/components/Player.tsx +126 -59
- package/src/components/PlayerControls.tsx +384 -272
- package/src/components/PlayerErrorBoundary.tsx +7 -13
- package/src/components/SeekBar.tsx +96 -88
- package/src/components/SkipIndicator.tsx +2 -12
- package/src/components/SpeedIndicator.tsx +2 -11
- package/src/components/StatsPanel.tsx +31 -22
- package/src/components/StreamStateOverlay.tsx +105 -49
- package/src/components/SubtitleRenderer.tsx +29 -29
- package/src/components/ThumbnailOverlay.tsx +5 -6
- package/src/components/TitleOverlay.tsx +2 -8
- package/src/context/PlayerContext.tsx +4 -8
- package/src/context/index.ts +3 -3
- package/src/hooks/useMetaTrack.ts +27 -27
- package/src/hooks/usePlaybackQuality.ts +3 -3
- package/src/hooks/usePlayerController.ts +246 -138
- package/src/hooks/usePlayerSelection.ts +6 -6
- package/src/hooks/useStreamState.ts +51 -56
- package/src/hooks/useTelemetry.ts +18 -3
- package/src/hooks/useViewerEndpoints.ts +34 -23
- package/src/index.tsx +36 -28
- package/src/types.ts +8 -8
- package/src/ui/badge.tsx +6 -5
- package/src/ui/button.tsx +9 -8
- package/src/ui/context-menu.tsx +42 -61
- package/src/ui/select.tsx +13 -7
- package/src/ui/slider.tsx +18 -29
- package/dist/types/components/players/DashJsPlayer.d.ts +0 -18
- package/dist/types/components/players/HlsJsPlayer.d.ts +0 -18
- package/dist/types/components/players/MewsWsPlayer/index.d.ts +0 -18
- package/dist/types/components/players/MistPlayer.d.ts +0 -20
- package/dist/types/components/players/MistWebRTCPlayer/index.d.ts +0 -20
- package/dist/types/components/players/NativePlayer.d.ts +0 -19
- package/dist/types/components/players/VideoJsPlayer.d.ts +0 -18
- package/src/components/players/DashJsPlayer.tsx +0 -56
- package/src/components/players/HlsJsPlayer.tsx +0 -56
- package/src/components/players/MewsWsPlayer/index.tsx +0 -56
- package/src/components/players/MistPlayer.tsx +0 -60
- package/src/components/players/MistWebRTCPlayer/index.tsx +0 -59
- package/src/components/players/NativePlayer.tsx +0 -58
- package/src/components/players/VideoJsPlayer.tsx +0 -56
|
@@ -0,0 +1,798 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var _rollupPluginBabelHelpers = require('../_virtual/_rollupPluginBabelHelpers.js');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
var React = require('react');
|
|
8
|
+
var PlayerContext = require('../context/PlayerContext.js');
|
|
9
|
+
var playerCore = require('@livepeer-frameworks/player-core');
|
|
10
|
+
var slider = require('../ui/slider.js');
|
|
11
|
+
var SeekBar = require('./SeekBar.js');
|
|
12
|
+
var Icons = require('./Icons.js');
|
|
13
|
+
|
|
14
|
+
var PlayerControls = function PlayerControls(_ref) {
|
|
15
|
+
var _ctx$state, _mistStreamInfo$meta, _player$getTextTracks, _player$getTextTracks2, _mistStreamInfo$meta$, _mistStreamInfo$meta2, _mistStreamInfo$meta3, _player$getSeekableSt, _player$getLiveEdge;
|
|
16
|
+
var currentTime = _ref.currentTime,
|
|
17
|
+
duration = _ref.duration,
|
|
18
|
+
_ref$isVisible = _ref.isVisible,
|
|
19
|
+
isVisible = _ref$isVisible === void 0 ? true : _ref$isVisible;
|
|
20
|
+
_ref.className;
|
|
21
|
+
var _onSeek = _ref.onSeek,
|
|
22
|
+
mistStreamInfo = _ref.mistStreamInfo,
|
|
23
|
+
_ref$disabled = _ref.disabled,
|
|
24
|
+
disabled = _ref$disabled === void 0 ? false : _ref$disabled,
|
|
25
|
+
_ref$playbackMode = _ref.playbackMode,
|
|
26
|
+
playbackMode = _ref$playbackMode === void 0 ? "auto" : _ref$playbackMode,
|
|
27
|
+
onModeChange = _ref.onModeChange,
|
|
28
|
+
sourceType = _ref.sourceType,
|
|
29
|
+
isContentLive = _ref.isContentLive,
|
|
30
|
+
propVideoElement = _ref.videoElement,
|
|
31
|
+
_ref$qualities = _ref.qualities,
|
|
32
|
+
propQualities = _ref$qualities === void 0 ? [] : _ref$qualities,
|
|
33
|
+
onSelectQuality = _ref.onSelectQuality,
|
|
34
|
+
propIsMuted = _ref.isMuted,
|
|
35
|
+
propVolume = _ref.volume,
|
|
36
|
+
onVolumeChange = _ref.onVolumeChange,
|
|
37
|
+
onToggleMute = _ref.onToggleMute,
|
|
38
|
+
propIsPlaying = _ref.isPlaying,
|
|
39
|
+
onTogglePlay = _ref.onTogglePlay,
|
|
40
|
+
onToggleFullscreen = _ref.onToggleFullscreen,
|
|
41
|
+
propIsFullscreen = _ref.isFullscreen;
|
|
42
|
+
_ref.isLoopEnabled;
|
|
43
|
+
_ref.onToggleLoop;
|
|
44
|
+
var onJumpToLive = _ref.onJumpToLive;
|
|
45
|
+
// Context fallback - prefer props passed from parent over context
|
|
46
|
+
// Context provides UsePlayerControllerReturn which has state.videoElement and controller
|
|
47
|
+
var ctx = PlayerContext.usePlayerContextOptional();
|
|
48
|
+
var contextVideo = ctx === null || ctx === void 0 || (_ctx$state = ctx.state) === null || _ctx$state === void 0 ? void 0 : _ctx$state.videoElement;
|
|
49
|
+
var player = ctx === null || ctx === void 0 ? void 0 : ctx.controller;
|
|
50
|
+
// Robust video element detection - prefer prop, then context, then DOM query
|
|
51
|
+
var _useState = React.useState(null),
|
|
52
|
+
_useState2 = _rollupPluginBabelHelpers.slicedToArray(_useState, 2),
|
|
53
|
+
video = _useState2[0],
|
|
54
|
+
setVideo = _useState2[1];
|
|
55
|
+
var videoCheckIntervalRef = React.useRef(null);
|
|
56
|
+
var findVideoElement = React.useCallback(function () {
|
|
57
|
+
var _player$getVideoEleme, _ref2, _document$querySelect;
|
|
58
|
+
if (propVideoElement) return propVideoElement;
|
|
59
|
+
if (contextVideo) return contextVideo;
|
|
60
|
+
if (player !== null && player !== void 0 && (_player$getVideoEleme = player.getVideoElement) !== null && _player$getVideoEleme !== void 0 && _player$getVideoEleme.call(player)) return player.getVideoElement();
|
|
61
|
+
var domVideo = (_ref2 = (_document$querySelect = document.querySelector(".fw-player-video")) !== null && _document$querySelect !== void 0 ? _document$querySelect : document.querySelector('[data-player-container="true"] video')) !== null && _ref2 !== void 0 ? _ref2 : document.querySelector(".fw-player-container video");
|
|
62
|
+
return domVideo;
|
|
63
|
+
}, [propVideoElement, contextVideo, player]);
|
|
64
|
+
React.useEffect(function () {
|
|
65
|
+
var updateVideo = function updateVideo() {
|
|
66
|
+
var v = findVideoElement();
|
|
67
|
+
if (v && v !== video) {
|
|
68
|
+
setVideo(v);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
updateVideo();
|
|
72
|
+
if (!video) {
|
|
73
|
+
videoCheckIntervalRef.current = setInterval(function () {
|
|
74
|
+
var v = findVideoElement();
|
|
75
|
+
if (v) {
|
|
76
|
+
setVideo(v);
|
|
77
|
+
if (videoCheckIntervalRef.current) {
|
|
78
|
+
clearInterval(videoCheckIntervalRef.current);
|
|
79
|
+
videoCheckIntervalRef.current = null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}, 100);
|
|
83
|
+
setTimeout(function () {
|
|
84
|
+
if (videoCheckIntervalRef.current) {
|
|
85
|
+
clearInterval(videoCheckIntervalRef.current);
|
|
86
|
+
videoCheckIntervalRef.current = null;
|
|
87
|
+
}
|
|
88
|
+
}, 5000);
|
|
89
|
+
}
|
|
90
|
+
return function () {
|
|
91
|
+
if (videoCheckIntervalRef.current) {
|
|
92
|
+
clearInterval(videoCheckIntervalRef.current);
|
|
93
|
+
videoCheckIntervalRef.current = null;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}, [contextVideo, player, findVideoElement, video]);
|
|
97
|
+
var mistTracks = mistStreamInfo === null || mistStreamInfo === void 0 || (_mistStreamInfo$meta = mistStreamInfo.meta) === null || _mistStreamInfo$meta === void 0 ? void 0 : _mistStreamInfo$meta.tracks;
|
|
98
|
+
// Quality selection priority:
|
|
99
|
+
// 1. Player-provided qualities (HLS.js/DASH.js levels with correct numeric indices)
|
|
100
|
+
// 2. Mist track metadata (for players that don't provide quality API)
|
|
101
|
+
// This fixes a critical bug where Mist track IDs (e.g., "a1", "v0") were passed to
|
|
102
|
+
// HLS/DASH players which expect numeric indices (e.g., "0", "1", "2")
|
|
103
|
+
// Quality levels - prefer props, then player API, then Mist tracks
|
|
104
|
+
var qualities = React.useMemo(function () {
|
|
105
|
+
var _player$getQualities;
|
|
106
|
+
// Priority 1: Props from parent (usePlayerController hook)
|
|
107
|
+
if (propQualities && propQualities.length > 0) {
|
|
108
|
+
return propQualities;
|
|
109
|
+
}
|
|
110
|
+
// Priority 2: Player's quality API
|
|
111
|
+
var playerQualities = player === null || player === void 0 || (_player$getQualities = player.getQualities) === null || _player$getQualities === void 0 ? void 0 : _player$getQualities.call(player);
|
|
112
|
+
if (playerQualities && playerQualities.length > 0) {
|
|
113
|
+
return playerQualities;
|
|
114
|
+
}
|
|
115
|
+
// Fallback to Mist track metadata for players without quality API
|
|
116
|
+
if (mistTracks) {
|
|
117
|
+
return Object.entries(mistTracks).filter(function (_ref3) {
|
|
118
|
+
var _ref4 = _rollupPluginBabelHelpers.slicedToArray(_ref3, 2),
|
|
119
|
+
t = _ref4[1];
|
|
120
|
+
return t.type === "video";
|
|
121
|
+
}).map(function (_ref5) {
|
|
122
|
+
var _ref6 = _rollupPluginBabelHelpers.slicedToArray(_ref5, 2),
|
|
123
|
+
id = _ref6[0],
|
|
124
|
+
t = _ref6[1];
|
|
125
|
+
return {
|
|
126
|
+
id: id,
|
|
127
|
+
label: t.height ? "".concat(t.height, "p") : t.codec,
|
|
128
|
+
width: t.width,
|
|
129
|
+
height: t.height,
|
|
130
|
+
bitrate: t.bps
|
|
131
|
+
};
|
|
132
|
+
}).sort(function (a, b) {
|
|
133
|
+
return (b.height || 0) - (a.height || 0);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return [];
|
|
137
|
+
}, [propQualities, player, mistTracks]);
|
|
138
|
+
var textTracks = (_player$getTextTracks = player === null || player === void 0 || (_player$getTextTracks2 = player.getTextTracks) === null || _player$getTextTracks2 === void 0 ? void 0 : _player$getTextTracks2.call(player)) !== null && _player$getTextTracks !== void 0 ? _player$getTextTracks : [];
|
|
139
|
+
// Internal state - used as fallback when props not provided
|
|
140
|
+
var _useState3 = React.useState(false),
|
|
141
|
+
_useState4 = _rollupPluginBabelHelpers.slicedToArray(_useState3, 2),
|
|
142
|
+
internalIsPlaying = _useState4[0],
|
|
143
|
+
setInternalIsPlaying = _useState4[1];
|
|
144
|
+
var _useState5 = React.useState(false),
|
|
145
|
+
_useState6 = _rollupPluginBabelHelpers.slicedToArray(_useState5, 2),
|
|
146
|
+
internalIsMuted = _useState6[0],
|
|
147
|
+
setInternalIsMuted = _useState6[1];
|
|
148
|
+
var _useState7 = React.useState(false),
|
|
149
|
+
_useState8 = _rollupPluginBabelHelpers.slicedToArray(_useState7, 2),
|
|
150
|
+
internalIsFullscreen = _useState8[0],
|
|
151
|
+
setInternalIsFullscreen = _useState8[1];
|
|
152
|
+
var _useState9 = React.useState(true),
|
|
153
|
+
_useState0 = _rollupPluginBabelHelpers.slicedToArray(_useState9, 2),
|
|
154
|
+
hasAudio = _useState0[0],
|
|
155
|
+
setHasAudio = _useState0[1];
|
|
156
|
+
var _useState1 = React.useState(undefined),
|
|
157
|
+
_useState10 = _rollupPluginBabelHelpers.slicedToArray(_useState1, 2),
|
|
158
|
+
buffered = _useState10[0],
|
|
159
|
+
setBuffered = _useState10[1];
|
|
160
|
+
var _useState11 = React.useState(function () {
|
|
161
|
+
if (!video) return 100;
|
|
162
|
+
return Math.round(video.volume * 100);
|
|
163
|
+
}),
|
|
164
|
+
_useState12 = _rollupPluginBabelHelpers.slicedToArray(_useState11, 2),
|
|
165
|
+
internalVolume = _useState12[0],
|
|
166
|
+
setInternalVolume = _useState12[1];
|
|
167
|
+
var _useState13 = React.useState(function () {
|
|
168
|
+
var _video$playbackRate;
|
|
169
|
+
return (_video$playbackRate = video === null || video === void 0 ? void 0 : video.playbackRate) !== null && _video$playbackRate !== void 0 ? _video$playbackRate : 1;
|
|
170
|
+
}),
|
|
171
|
+
_useState14 = _rollupPluginBabelHelpers.slicedToArray(_useState13, 2),
|
|
172
|
+
playbackRate = _useState14[0],
|
|
173
|
+
setPlaybackRate = _useState14[1];
|
|
174
|
+
// Derived state - prefer props over internal state
|
|
175
|
+
var isPlaying = propIsPlaying !== null && propIsPlaying !== void 0 ? propIsPlaying : internalIsPlaying;
|
|
176
|
+
var isMuted = propIsMuted !== null && propIsMuted !== void 0 ? propIsMuted : internalIsMuted;
|
|
177
|
+
var isFullscreen = propIsFullscreen !== null && propIsFullscreen !== void 0 ? propIsFullscreen : internalIsFullscreen;
|
|
178
|
+
var actualVolume = propVolume !== undefined ? Math.round(propVolume * 100) : internalVolume;
|
|
179
|
+
// Show 0 when muted, actual volume otherwise
|
|
180
|
+
var volumeValue = isMuted ? 0 : actualVolume;
|
|
181
|
+
var _useState15 = React.useState("auto"),
|
|
182
|
+
_useState16 = _rollupPluginBabelHelpers.slicedToArray(_useState15, 2),
|
|
183
|
+
qualityValue = _useState16[0],
|
|
184
|
+
setQualityValue = _useState16[1];
|
|
185
|
+
var _useState17 = React.useState("none"),
|
|
186
|
+
_useState18 = _rollupPluginBabelHelpers.slicedToArray(_useState17, 2),
|
|
187
|
+
captionValue = _useState18[0],
|
|
188
|
+
setCaptionValue = _useState18[1];
|
|
189
|
+
var _useState19 = React.useState(false),
|
|
190
|
+
_useState20 = _rollupPluginBabelHelpers.slicedToArray(_useState19, 2),
|
|
191
|
+
isSettingsOpen = _useState20[0],
|
|
192
|
+
setIsSettingsOpen = _useState20[1];
|
|
193
|
+
// Hysteresis state for Live badge - prevents flip-flopping
|
|
194
|
+
var _useState21 = React.useState(true),
|
|
195
|
+
_useState22 = _rollupPluginBabelHelpers.slicedToArray(_useState21, 2),
|
|
196
|
+
isNearLiveState = _useState22[0],
|
|
197
|
+
setIsNearLiveState = _useState22[1];
|
|
198
|
+
// Close settings menu when clicking outside
|
|
199
|
+
React.useEffect(function () {
|
|
200
|
+
if (!isSettingsOpen) return;
|
|
201
|
+
var handleWindowClick = function handleWindowClick(event) {
|
|
202
|
+
var target = event.target;
|
|
203
|
+
if (target && !target.closest(".fw-settings-menu")) {
|
|
204
|
+
setIsSettingsOpen(false);
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
// Use setTimeout to avoid immediate close from the same click that opened it
|
|
208
|
+
var timeoutId = setTimeout(function () {
|
|
209
|
+
window.addEventListener("click", handleWindowClick);
|
|
210
|
+
}, 0);
|
|
211
|
+
return function () {
|
|
212
|
+
clearTimeout(timeoutId);
|
|
213
|
+
window.removeEventListener("click", handleWindowClick);
|
|
214
|
+
};
|
|
215
|
+
}, [isSettingsOpen]);
|
|
216
|
+
// Core utility-based calculations
|
|
217
|
+
var deriveBufferWindowMs = React.useCallback(function (tracks) {
|
|
218
|
+
if (!tracks) return undefined;
|
|
219
|
+
var list = Object.values(tracks);
|
|
220
|
+
if (list.length === 0) return undefined;
|
|
221
|
+
var firstmsValues = list.map(function (t) {
|
|
222
|
+
return t.firstms;
|
|
223
|
+
}).filter(function (v) {
|
|
224
|
+
return v !== undefined;
|
|
225
|
+
});
|
|
226
|
+
var lastmsValues = list.map(function (t) {
|
|
227
|
+
return t.lastms;
|
|
228
|
+
}).filter(function (v) {
|
|
229
|
+
return v !== undefined;
|
|
230
|
+
});
|
|
231
|
+
if (firstmsValues.length === 0 || lastmsValues.length === 0) return undefined;
|
|
232
|
+
var firstms = Math.max.apply(Math, _rollupPluginBabelHelpers.toConsumableArray(firstmsValues));
|
|
233
|
+
var lastms = Math.min.apply(Math, _rollupPluginBabelHelpers.toConsumableArray(lastmsValues));
|
|
234
|
+
var window = lastms - firstms;
|
|
235
|
+
if (!Number.isFinite(window) || window <= 0) return undefined;
|
|
236
|
+
return window;
|
|
237
|
+
}, []);
|
|
238
|
+
var bufferWindowMs = (_mistStreamInfo$meta$ = mistStreamInfo === null || mistStreamInfo === void 0 || (_mistStreamInfo$meta2 = mistStreamInfo.meta) === null || _mistStreamInfo$meta2 === void 0 ? void 0 : _mistStreamInfo$meta2.buffer_window) !== null && _mistStreamInfo$meta$ !== void 0 ? _mistStreamInfo$meta$ : deriveBufferWindowMs(mistStreamInfo === null || mistStreamInfo === void 0 || (_mistStreamInfo$meta3 = mistStreamInfo.meta) === null || _mistStreamInfo$meta3 === void 0 ? void 0 : _mistStreamInfo$meta3.tracks);
|
|
239
|
+
var isLive = React.useMemo(function () {
|
|
240
|
+
return playerCore.isLiveContent(isContentLive, mistStreamInfo, duration);
|
|
241
|
+
}, [isContentLive, mistStreamInfo, duration]);
|
|
242
|
+
var isWebRTC = React.useMemo(function () {
|
|
243
|
+
return playerCore.isMediaStreamSource(video);
|
|
244
|
+
}, [video]);
|
|
245
|
+
var supportsPlaybackRate = React.useMemo(function () {
|
|
246
|
+
return playerCore.supportsPlaybackRate(video);
|
|
247
|
+
}, [video]);
|
|
248
|
+
// Seekable range using core calculation (allow controller override)
|
|
249
|
+
var allowMediaStreamDvr = playerCore.isMediaStreamSource(video) && bufferWindowMs !== undefined && bufferWindowMs > 0 && sourceType !== "whep" && sourceType !== "webrtc";
|
|
250
|
+
var _useMemo = React.useMemo(function () {
|
|
251
|
+
return playerCore.calculateSeekableRange({
|
|
252
|
+
isLive: isLive,
|
|
253
|
+
video: video,
|
|
254
|
+
mistStreamInfo: mistStreamInfo,
|
|
255
|
+
currentTime: currentTime,
|
|
256
|
+
duration: duration,
|
|
257
|
+
allowMediaStreamDvr: allowMediaStreamDvr
|
|
258
|
+
});
|
|
259
|
+
}, [isLive, video, mistStreamInfo, currentTime, duration, allowMediaStreamDvr]),
|
|
260
|
+
calcSeekableStart = _useMemo.seekableStart,
|
|
261
|
+
calcLiveEdge = _useMemo.liveEdge;
|
|
262
|
+
var controllerSeekableStart = player === null || player === void 0 || (_player$getSeekableSt = player.getSeekableStart) === null || _player$getSeekableSt === void 0 ? void 0 : _player$getSeekableSt.call(player);
|
|
263
|
+
var controllerLiveEdge = player === null || player === void 0 || (_player$getLiveEdge = player.getLiveEdge) === null || _player$getLiveEdge === void 0 ? void 0 : _player$getLiveEdge.call(player);
|
|
264
|
+
var useControllerRange = Number.isFinite(controllerSeekableStart) && Number.isFinite(controllerLiveEdge) && controllerLiveEdge >= controllerSeekableStart && (controllerLiveEdge > 0 || controllerSeekableStart > 0);
|
|
265
|
+
var seekableStart = useControllerRange ? controllerSeekableStart : calcSeekableStart;
|
|
266
|
+
var liveEdge = useControllerRange ? controllerLiveEdge : calcLiveEdge;
|
|
267
|
+
var hasDvrWindow = isLive && Number.isFinite(liveEdge) && Number.isFinite(seekableStart) && liveEdge > seekableStart;
|
|
268
|
+
var commitOnRelease = isLive;
|
|
269
|
+
// Live thresholds with buffer window scaling
|
|
270
|
+
var liveThresholds = React.useMemo(function () {
|
|
271
|
+
return playerCore.calculateLiveThresholds(sourceType, isWebRTC, bufferWindowMs);
|
|
272
|
+
}, [sourceType, isWebRTC, bufferWindowMs]);
|
|
273
|
+
// Can seek - prefer PlayerController's computed value (includes player-specific canSeek)
|
|
274
|
+
// Fall back to utility function when controller not available
|
|
275
|
+
var baseCanSeek = React.useMemo(function () {
|
|
276
|
+
// PlayerController already computes canSeek with player-specific logic
|
|
277
|
+
if (player && typeof player.canSeekStream === "function") {
|
|
278
|
+
return player.canSeekStream();
|
|
279
|
+
}
|
|
280
|
+
// Fallback when no controller
|
|
281
|
+
return playerCore.canSeekStream({
|
|
282
|
+
video: video,
|
|
283
|
+
isLive: isLive,
|
|
284
|
+
duration: duration,
|
|
285
|
+
bufferWindowMs: bufferWindowMs
|
|
286
|
+
});
|
|
287
|
+
}, [video, isLive, duration, bufferWindowMs, player]);
|
|
288
|
+
var canSeek = baseCanSeek && (!isLive || hasDvrWindow);
|
|
289
|
+
// Hysteresis for live badge - using core calculation
|
|
290
|
+
React.useEffect(function () {
|
|
291
|
+
if (!isLive) {
|
|
292
|
+
setIsNearLiveState(true);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
var newState = playerCore.calculateIsNearLive(currentTime, liveEdge, liveThresholds, isNearLiveState);
|
|
296
|
+
if (newState !== isNearLiveState) {
|
|
297
|
+
setIsNearLiveState(newState);
|
|
298
|
+
}
|
|
299
|
+
}, [isLive, liveEdge, currentTime, liveThresholds, isNearLiveState]);
|
|
300
|
+
// Track if we've already seeked to live on initial playback
|
|
301
|
+
var hasSeekToLiveRef = React.useRef(false);
|
|
302
|
+
// Sync internal state from video element (only when props not provided)
|
|
303
|
+
React.useEffect(function () {
|
|
304
|
+
if (!video) return;
|
|
305
|
+
var updatePlayingState = function updatePlayingState() {
|
|
306
|
+
return setInternalIsPlaying(!video.paused);
|
|
307
|
+
};
|
|
308
|
+
var updateMutedState = function updateMutedState() {
|
|
309
|
+
var muted = video.muted || video.volume === 0;
|
|
310
|
+
setInternalIsMuted(muted);
|
|
311
|
+
setInternalVolume(Math.round(video.volume * 100));
|
|
312
|
+
};
|
|
313
|
+
var updateFullscreenState = function updateFullscreenState() {
|
|
314
|
+
if (typeof document !== "undefined") setInternalIsFullscreen(!!document.fullscreenElement);
|
|
315
|
+
};
|
|
316
|
+
var updatePlaybackRate = function updatePlaybackRate() {
|
|
317
|
+
return setPlaybackRate(video.playbackRate);
|
|
318
|
+
};
|
|
319
|
+
updatePlayingState();
|
|
320
|
+
updateMutedState();
|
|
321
|
+
updateFullscreenState();
|
|
322
|
+
updatePlaybackRate();
|
|
323
|
+
video.addEventListener("play", updatePlayingState);
|
|
324
|
+
video.addEventListener("pause", updatePlayingState);
|
|
325
|
+
video.addEventListener("playing", updatePlayingState);
|
|
326
|
+
video.addEventListener("volumechange", updateMutedState);
|
|
327
|
+
video.addEventListener("ratechange", updatePlaybackRate);
|
|
328
|
+
if (typeof document !== "undefined") document.addEventListener("fullscreenchange", updateFullscreenState);
|
|
329
|
+
return function () {
|
|
330
|
+
video.removeEventListener("play", updatePlayingState);
|
|
331
|
+
video.removeEventListener("pause", updatePlayingState);
|
|
332
|
+
video.removeEventListener("playing", updatePlayingState);
|
|
333
|
+
video.removeEventListener("volumechange", updateMutedState);
|
|
334
|
+
video.removeEventListener("ratechange", updatePlaybackRate);
|
|
335
|
+
if (typeof document !== "undefined") document.removeEventListener("fullscreenchange", updateFullscreenState);
|
|
336
|
+
};
|
|
337
|
+
}, [video, isLive]);
|
|
338
|
+
// Reset the seek-to-live flag when video element changes (new stream)
|
|
339
|
+
React.useEffect(function () {
|
|
340
|
+
hasSeekToLiveRef.current = false;
|
|
341
|
+
}, [video]);
|
|
342
|
+
React.useEffect(function () {
|
|
343
|
+
var activeTrack = textTracks.find(function (track) {
|
|
344
|
+
return track.active;
|
|
345
|
+
});
|
|
346
|
+
setCaptionValue(activeTrack ? activeTrack.id : "none");
|
|
347
|
+
}, [textTracks]);
|
|
348
|
+
// Track buffered ranges for SeekBar
|
|
349
|
+
React.useEffect(function () {
|
|
350
|
+
if (!video) return;
|
|
351
|
+
var updateBuffered = function updateBuffered() {
|
|
352
|
+
var _player$getBufferedRa, _player$getBufferedRa2;
|
|
353
|
+
var next = (_player$getBufferedRa = player === null || player === void 0 || (_player$getBufferedRa2 = player.getBufferedRanges) === null || _player$getBufferedRa2 === void 0 ? void 0 : _player$getBufferedRa2.call(player)) !== null && _player$getBufferedRa !== void 0 ? _player$getBufferedRa : video.buffered;
|
|
354
|
+
setBuffered(next);
|
|
355
|
+
};
|
|
356
|
+
updateBuffered();
|
|
357
|
+
video.addEventListener("progress", updateBuffered);
|
|
358
|
+
video.addEventListener("loadeddata", updateBuffered);
|
|
359
|
+
return function () {
|
|
360
|
+
video.removeEventListener("progress", updateBuffered);
|
|
361
|
+
video.removeEventListener("loadeddata", updateBuffered);
|
|
362
|
+
};
|
|
363
|
+
}, [video]);
|
|
364
|
+
React.useEffect(function () {
|
|
365
|
+
if (!video) {
|
|
366
|
+
setHasAudio(true);
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
var checkAudio = function checkAudio() {
|
|
370
|
+
if (video.srcObject instanceof MediaStream) {
|
|
371
|
+
var audioTracks = video.srcObject.getAudioTracks();
|
|
372
|
+
setHasAudio(audioTracks.length > 0);
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
var videoAny = video;
|
|
376
|
+
if (videoAny.audioTracks && videoAny.audioTracks.length !== undefined) {
|
|
377
|
+
setHasAudio(videoAny.audioTracks.length > 0);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
setHasAudio(true);
|
|
381
|
+
};
|
|
382
|
+
checkAudio();
|
|
383
|
+
video.addEventListener("loadedmetadata", checkAudio);
|
|
384
|
+
return function () {
|
|
385
|
+
return video.removeEventListener("loadedmetadata", checkAudio);
|
|
386
|
+
};
|
|
387
|
+
}, [video]);
|
|
388
|
+
var handlePlayPause = function handlePlayPause() {
|
|
389
|
+
var _ref7, _player$isPaused, _player$isPaused2;
|
|
390
|
+
if (disabled) return;
|
|
391
|
+
// Prefer prop callback from usePlayerController
|
|
392
|
+
if (onTogglePlay) {
|
|
393
|
+
onTogglePlay();
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
// Fallback: direct video/player manipulation
|
|
397
|
+
if (!video && !player) return;
|
|
398
|
+
var isPaused = (_ref7 = (_player$isPaused = player === null || player === void 0 || (_player$isPaused2 = player.isPaused) === null || _player$isPaused2 === void 0 ? void 0 : _player$isPaused2.call(player)) !== null && _player$isPaused !== void 0 ? _player$isPaused : video === null || video === void 0 ? void 0 : video.paused) !== null && _ref7 !== void 0 ? _ref7 : true;
|
|
399
|
+
if (isPaused) {
|
|
400
|
+
if (player !== null && player !== void 0 && player.play) player.play()["catch"](function () {});else if (video) video.play()["catch"](function () {});
|
|
401
|
+
} else {
|
|
402
|
+
if (player !== null && player !== void 0 && player.pause) player.pause();else if (video) video.pause();
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
var handleSkipBack = function handleSkipBack() {
|
|
406
|
+
var newTime = Math.max(0, currentTime - 10);
|
|
407
|
+
if (_onSeek) {
|
|
408
|
+
_onSeek(newTime);
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
var v = findVideoElement();
|
|
412
|
+
if (v) v.currentTime = newTime;
|
|
413
|
+
};
|
|
414
|
+
var handleSkipForward = function handleSkipForward() {
|
|
415
|
+
var maxTime = Number.isFinite(duration) ? duration : currentTime + 10;
|
|
416
|
+
var newTime = Math.min(maxTime, currentTime + 10);
|
|
417
|
+
if (_onSeek) {
|
|
418
|
+
_onSeek(newTime);
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
var v = findVideoElement();
|
|
422
|
+
if (v) v.currentTime = newTime;
|
|
423
|
+
};
|
|
424
|
+
var handleMute = function handleMute() {
|
|
425
|
+
var _player$isMuted, _player$isMuted2, _player$setMuted;
|
|
426
|
+
if (disabled) return;
|
|
427
|
+
// Prefer prop callback from usePlayerController
|
|
428
|
+
if (onToggleMute) {
|
|
429
|
+
onToggleMute();
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
// Fallback: direct video/player manipulation
|
|
433
|
+
var v = video !== null && video !== void 0 ? video : document.querySelector(".fw-player-video");
|
|
434
|
+
if (!v) return;
|
|
435
|
+
var nextMuted = !((_player$isMuted = player === null || player === void 0 || (_player$isMuted2 = player.isMuted) === null || _player$isMuted2 === void 0 ? void 0 : _player$isMuted2.call(player)) !== null && _player$isMuted !== void 0 ? _player$isMuted : v.muted);
|
|
436
|
+
player === null || player === void 0 || (_player$setMuted = player.setMuted) === null || _player$setMuted === void 0 || _player$setMuted.call(player, nextMuted);
|
|
437
|
+
v.muted = nextMuted;
|
|
438
|
+
setInternalIsMuted(nextMuted);
|
|
439
|
+
if (nextMuted) setInternalVolume(0);else setInternalVolume(Math.round(v.volume * 100));
|
|
440
|
+
};
|
|
441
|
+
var handleVolumeChange = React.useCallback(function (value) {
|
|
442
|
+
var _value$;
|
|
443
|
+
if (disabled) return;
|
|
444
|
+
var next = Math.max(0, Math.min(100, (_value$ = value[0]) !== null && _value$ !== void 0 ? _value$ : 0));
|
|
445
|
+
// Prefer prop callback from usePlayerController
|
|
446
|
+
if (onVolumeChange) {
|
|
447
|
+
onVolumeChange(next / 100);
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
// Fallback: direct video manipulation
|
|
451
|
+
var v = video !== null && video !== void 0 ? video : document.querySelector(".fw-player-video");
|
|
452
|
+
if (!v) return;
|
|
453
|
+
v.volume = next / 100;
|
|
454
|
+
v.muted = next === 0;
|
|
455
|
+
setInternalVolume(next);
|
|
456
|
+
setInternalIsMuted(next === 0);
|
|
457
|
+
}, [disabled, onVolumeChange, video]);
|
|
458
|
+
var handleFullscreen = function handleFullscreen() {
|
|
459
|
+
if (disabled) return;
|
|
460
|
+
// Prefer prop callback from usePlayerController
|
|
461
|
+
if (onToggleFullscreen) {
|
|
462
|
+
onToggleFullscreen();
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
// Fallback: direct DOM manipulation
|
|
466
|
+
if (typeof document === "undefined") return;
|
|
467
|
+
var container = document.querySelector('[data-player-container="true"]');
|
|
468
|
+
if (!container) return;
|
|
469
|
+
if (document.fullscreenElement) document.exitFullscreen()["catch"](function () {});else container.requestFullscreen()["catch"](function () {});
|
|
470
|
+
};
|
|
471
|
+
var handleGoLive = function handleGoLive() {
|
|
472
|
+
var _player$jumpToLive;
|
|
473
|
+
if (disabled) return;
|
|
474
|
+
if (onJumpToLive) {
|
|
475
|
+
onJumpToLive();
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
player === null || player === void 0 || (_player$jumpToLive = player.jumpToLive) === null || _player$jumpToLive === void 0 || _player$jumpToLive.call(player);
|
|
479
|
+
};
|
|
480
|
+
var handleSpeedChange = function handleSpeedChange(value) {
|
|
481
|
+
if (disabled) return;
|
|
482
|
+
var rate = Number(value);
|
|
483
|
+
setPlaybackRate(rate);
|
|
484
|
+
// Use player API if available, fall back to direct video element
|
|
485
|
+
if (player !== null && player !== void 0 && player.setPlaybackRate) {
|
|
486
|
+
player.setPlaybackRate(rate);
|
|
487
|
+
} else {
|
|
488
|
+
var v = findVideoElement();
|
|
489
|
+
if (v) v.playbackRate = rate;
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
var handleQualityChange = function handleQualityChange(value) {
|
|
493
|
+
var _player$selectQuality;
|
|
494
|
+
if (disabled) return;
|
|
495
|
+
setQualityValue(value);
|
|
496
|
+
// Prefer prop callback from usePlayerController
|
|
497
|
+
if (onSelectQuality) {
|
|
498
|
+
onSelectQuality(value);
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
// Fallback: direct player manipulation
|
|
502
|
+
player === null || player === void 0 || (_player$selectQuality = player.selectQuality) === null || _player$selectQuality === void 0 || _player$selectQuality.call(player, value);
|
|
503
|
+
};
|
|
504
|
+
var handleCaptionChange = function handleCaptionChange(value) {
|
|
505
|
+
var _player$selectTextTra, _player$selectTextTra2;
|
|
506
|
+
if (disabled) return;
|
|
507
|
+
setCaptionValue(value);
|
|
508
|
+
if (value === "none") player === null || player === void 0 || (_player$selectTextTra = player.selectTextTrack) === null || _player$selectTextTra === void 0 || _player$selectTextTra.call(player, null);else player === null || player === void 0 || (_player$selectTextTra2 = player.selectTextTrack) === null || _player$selectTextTra2 === void 0 || _player$selectTextTra2.call(player, value);
|
|
509
|
+
};
|
|
510
|
+
// Time display - using core formatTimeDisplay
|
|
511
|
+
var timeDisplay = React.useMemo(function () {
|
|
512
|
+
return playerCore.formatTimeDisplay({
|
|
513
|
+
isLive: isLive,
|
|
514
|
+
currentTime: currentTime,
|
|
515
|
+
duration: duration,
|
|
516
|
+
liveEdge: liveEdge,
|
|
517
|
+
seekableStart: seekableStart,
|
|
518
|
+
unixoffset: mistStreamInfo === null || mistStreamInfo === void 0 ? void 0 : mistStreamInfo.unixoffset
|
|
519
|
+
});
|
|
520
|
+
}, [isLive, currentTime, duration, liveEdge, seekableStart, mistStreamInfo === null || mistStreamInfo === void 0 ? void 0 : mistStreamInfo.unixoffset]);
|
|
521
|
+
var _useState23 = React.useState(false),
|
|
522
|
+
_useState24 = _rollupPluginBabelHelpers.slicedToArray(_useState23, 2),
|
|
523
|
+
isVolumeHovered = _useState24[0],
|
|
524
|
+
setIsVolumeHovered = _useState24[1];
|
|
525
|
+
var _useState25 = React.useState(false),
|
|
526
|
+
_useState26 = _rollupPluginBabelHelpers.slicedToArray(_useState25, 2),
|
|
527
|
+
isVolumeFocused = _useState26[0],
|
|
528
|
+
setIsVolumeFocused = _useState26[1];
|
|
529
|
+
var isVolumeExpanded = isVolumeHovered || isVolumeFocused;
|
|
530
|
+
var volumeGroupRef = React.useRef(null);
|
|
531
|
+
// Non-passive wheel listener for volume control
|
|
532
|
+
React.useEffect(function () {
|
|
533
|
+
var el = volumeGroupRef.current;
|
|
534
|
+
if (!el) return;
|
|
535
|
+
var handler = function handler(e) {
|
|
536
|
+
if (disabled || !hasAudio) return;
|
|
537
|
+
e.preventDefault();
|
|
538
|
+
var delta = e.deltaY < 0 ? 5 : -5;
|
|
539
|
+
handleVolumeChange([actualVolume + delta]);
|
|
540
|
+
};
|
|
541
|
+
el.addEventListener("wheel", handler, {
|
|
542
|
+
passive: false
|
|
543
|
+
});
|
|
544
|
+
return function () {
|
|
545
|
+
return el.removeEventListener("wheel", handler);
|
|
546
|
+
};
|
|
547
|
+
}, [disabled, hasAudio, actualVolume, handleVolumeChange]);
|
|
548
|
+
return jsxRuntime.jsx("div", {
|
|
549
|
+
className: playerCore.cn("fw-player-surface fw-controls-wrapper", isVisible ? "fw-controls-wrapper--visible" : "fw-controls-wrapper--hidden"),
|
|
550
|
+
children: jsxRuntime.jsxs("div", {
|
|
551
|
+
className: "fw-control-bar pointer-events-auto",
|
|
552
|
+
onClick: function onClick(e) {
|
|
553
|
+
return e.stopPropagation();
|
|
554
|
+
},
|
|
555
|
+
children: [canSeek && jsxRuntime.jsx("div", {
|
|
556
|
+
className: "fw-seek-wrapper",
|
|
557
|
+
children: jsxRuntime.jsx(SeekBar.default, {
|
|
558
|
+
currentTime: currentTime,
|
|
559
|
+
duration: duration,
|
|
560
|
+
buffered: buffered,
|
|
561
|
+
disabled: disabled,
|
|
562
|
+
isLive: isLive,
|
|
563
|
+
seekableStart: seekableStart,
|
|
564
|
+
liveEdge: liveEdge,
|
|
565
|
+
commitOnRelease: commitOnRelease,
|
|
566
|
+
onSeek: function onSeek(time) {
|
|
567
|
+
if (_onSeek) {
|
|
568
|
+
_onSeek(time);
|
|
569
|
+
} else if (video) {
|
|
570
|
+
video.currentTime = time;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
})
|
|
574
|
+
}), jsxRuntime.jsxs("div", {
|
|
575
|
+
className: "fw-controls-row",
|
|
576
|
+
children: [jsxRuntime.jsxs("div", {
|
|
577
|
+
className: "fw-controls-left",
|
|
578
|
+
children: [jsxRuntime.jsxs("div", {
|
|
579
|
+
className: "fw-control-group",
|
|
580
|
+
children: [jsxRuntime.jsx("button", {
|
|
581
|
+
type: "button",
|
|
582
|
+
className: "fw-btn-flush",
|
|
583
|
+
"aria-label": isPlaying ? "Pause" : "Play",
|
|
584
|
+
onClick: handlePlayPause,
|
|
585
|
+
children: jsxRuntime.jsx(Icons.PlayPauseIcon, {
|
|
586
|
+
isPlaying: isPlaying,
|
|
587
|
+
size: 18
|
|
588
|
+
})
|
|
589
|
+
}), canSeek && jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
590
|
+
children: [jsxRuntime.jsx("button", {
|
|
591
|
+
type: "button",
|
|
592
|
+
className: "fw-btn-flush hidden sm:flex",
|
|
593
|
+
"aria-label": "Skip back 10 seconds",
|
|
594
|
+
onClick: handleSkipBack,
|
|
595
|
+
children: jsxRuntime.jsx(Icons.SkipBackIcon, {
|
|
596
|
+
size: 16
|
|
597
|
+
})
|
|
598
|
+
}), jsxRuntime.jsx("button", {
|
|
599
|
+
type: "button",
|
|
600
|
+
className: "fw-btn-flush hidden sm:flex",
|
|
601
|
+
"aria-label": "Skip forward 10 seconds",
|
|
602
|
+
onClick: handleSkipForward,
|
|
603
|
+
children: jsxRuntime.jsx(Icons.SkipForwardIcon, {
|
|
604
|
+
size: 16
|
|
605
|
+
})
|
|
606
|
+
})]
|
|
607
|
+
})]
|
|
608
|
+
}), jsxRuntime.jsxs("div", {
|
|
609
|
+
ref: volumeGroupRef,
|
|
610
|
+
className: playerCore.cn("fw-volume-group", isVolumeExpanded && "fw-volume-group--expanded", !hasAudio && "fw-volume-group--disabled"),
|
|
611
|
+
onMouseEnter: function onMouseEnter() {
|
|
612
|
+
return hasAudio && setIsVolumeHovered(true);
|
|
613
|
+
},
|
|
614
|
+
onMouseLeave: function onMouseLeave() {
|
|
615
|
+
setIsVolumeHovered(false);
|
|
616
|
+
setIsVolumeFocused(false);
|
|
617
|
+
},
|
|
618
|
+
onFocusCapture: function onFocusCapture() {
|
|
619
|
+
return hasAudio && setIsVolumeFocused(true);
|
|
620
|
+
},
|
|
621
|
+
onBlurCapture: function onBlurCapture(e) {
|
|
622
|
+
if (!e.currentTarget.contains(e.relatedTarget)) setIsVolumeFocused(false);
|
|
623
|
+
},
|
|
624
|
+
onClick: function onClick(e) {
|
|
625
|
+
// Click on the pill (not slider) toggles mute
|
|
626
|
+
if (hasAudio && e.target === e.currentTarget) {
|
|
627
|
+
handleMute();
|
|
628
|
+
}
|
|
629
|
+
},
|
|
630
|
+
children: [jsxRuntime.jsx("button", {
|
|
631
|
+
type: "button",
|
|
632
|
+
className: "fw-volume-btn",
|
|
633
|
+
"aria-label": !hasAudio ? "No audio" : isMuted ? "Unmute" : "Mute",
|
|
634
|
+
onClick: hasAudio ? handleMute : undefined,
|
|
635
|
+
disabled: !hasAudio,
|
|
636
|
+
children: jsxRuntime.jsx(Icons.VolumeIcon, {
|
|
637
|
+
isMuted: isMuted || !hasAudio,
|
|
638
|
+
size: 16
|
|
639
|
+
})
|
|
640
|
+
}), jsxRuntime.jsx("div", {
|
|
641
|
+
className: playerCore.cn("fw-volume-slider-wrapper", isVolumeExpanded ? "fw-volume-slider-wrapper--expanded" : "fw-volume-slider-wrapper--collapsed"),
|
|
642
|
+
children: jsxRuntime.jsx(slider.Slider, {
|
|
643
|
+
orientation: "horizontal",
|
|
644
|
+
"aria-label": "Volume",
|
|
645
|
+
max: 100,
|
|
646
|
+
step: 1,
|
|
647
|
+
value: [volumeValue],
|
|
648
|
+
onValueChange: handleVolumeChange,
|
|
649
|
+
className: "w-full",
|
|
650
|
+
disabled: !hasAudio
|
|
651
|
+
})
|
|
652
|
+
})]
|
|
653
|
+
}), jsxRuntime.jsx("div", {
|
|
654
|
+
className: "fw-control-group",
|
|
655
|
+
children: jsxRuntime.jsx("span", {
|
|
656
|
+
className: "fw-time-display",
|
|
657
|
+
children: timeDisplay
|
|
658
|
+
})
|
|
659
|
+
}), isLive && jsxRuntime.jsx("div", {
|
|
660
|
+
className: "fw-control-group",
|
|
661
|
+
children: jsxRuntime.jsxs("button", {
|
|
662
|
+
type: "button",
|
|
663
|
+
onClick: handleGoLive,
|
|
664
|
+
disabled: !hasDvrWindow || isNearLiveState,
|
|
665
|
+
className: playerCore.cn("fw-live-badge", !hasDvrWindow || isNearLiveState ? "fw-live-badge--active" : "fw-live-badge--behind"),
|
|
666
|
+
title: !hasDvrWindow ? "Live only" : isNearLiveState ? "At live edge" : "Jump to live",
|
|
667
|
+
children: ["LIVE", !isNearLiveState && hasDvrWindow && jsxRuntime.jsx(Icons.SeekToLiveIcon, {
|
|
668
|
+
size: 10
|
|
669
|
+
})]
|
|
670
|
+
})
|
|
671
|
+
})]
|
|
672
|
+
}), jsxRuntime.jsxs("div", {
|
|
673
|
+
className: "fw-controls-right",
|
|
674
|
+
children: [jsxRuntime.jsxs("div", {
|
|
675
|
+
className: "fw-control-group relative",
|
|
676
|
+
children: [jsxRuntime.jsx("button", {
|
|
677
|
+
type: "button",
|
|
678
|
+
className: playerCore.cn("fw-btn-flush group", isSettingsOpen && "fw-btn-flush--active"),
|
|
679
|
+
"aria-label": "Settings",
|
|
680
|
+
title: "Settings",
|
|
681
|
+
onClick: function onClick() {
|
|
682
|
+
return setIsSettingsOpen(!isSettingsOpen);
|
|
683
|
+
},
|
|
684
|
+
children: jsxRuntime.jsx(Icons.SettingsIcon, {
|
|
685
|
+
size: 16,
|
|
686
|
+
className: "transition-transform group-hover:rotate-90"
|
|
687
|
+
})
|
|
688
|
+
}), isSettingsOpen && jsxRuntime.jsxs("div", {
|
|
689
|
+
className: "fw-player-surface fw-settings-menu",
|
|
690
|
+
children: [onModeChange && isContentLive !== false && jsxRuntime.jsxs("div", {
|
|
691
|
+
className: "fw-settings-section",
|
|
692
|
+
children: [jsxRuntime.jsx("div", {
|
|
693
|
+
className: "fw-settings-label",
|
|
694
|
+
children: "Mode"
|
|
695
|
+
}), jsxRuntime.jsx("div", {
|
|
696
|
+
className: "fw-settings-options",
|
|
697
|
+
children: ["auto", "low-latency", "quality"].map(function (mode) {
|
|
698
|
+
return jsxRuntime.jsx("button", {
|
|
699
|
+
className: playerCore.cn("fw-settings-btn", playbackMode === mode && "fw-settings-btn--active"),
|
|
700
|
+
onClick: function onClick() {
|
|
701
|
+
onModeChange(mode);
|
|
702
|
+
setIsSettingsOpen(false);
|
|
703
|
+
},
|
|
704
|
+
children: mode === "low-latency" ? "Fast" : mode === "quality" ? "Stable" : "Auto"
|
|
705
|
+
}, mode);
|
|
706
|
+
})
|
|
707
|
+
})]
|
|
708
|
+
}), supportsPlaybackRate && jsxRuntime.jsxs("div", {
|
|
709
|
+
className: "fw-settings-section",
|
|
710
|
+
children: [jsxRuntime.jsx("div", {
|
|
711
|
+
className: "fw-settings-label",
|
|
712
|
+
children: "Speed"
|
|
713
|
+
}), jsxRuntime.jsx("div", {
|
|
714
|
+
className: "fw-settings-options fw-settings-options--wrap",
|
|
715
|
+
children: playerCore.SPEED_PRESETS.map(function (rate) {
|
|
716
|
+
return jsxRuntime.jsxs("button", {
|
|
717
|
+
className: playerCore.cn("fw-settings-btn", playbackRate === rate && "fw-settings-btn--active"),
|
|
718
|
+
onClick: function onClick() {
|
|
719
|
+
handleSpeedChange(String(rate));
|
|
720
|
+
setIsSettingsOpen(false);
|
|
721
|
+
},
|
|
722
|
+
children: [rate, "x"]
|
|
723
|
+
}, rate);
|
|
724
|
+
})
|
|
725
|
+
})]
|
|
726
|
+
}), qualities.length > 0 && jsxRuntime.jsxs("div", {
|
|
727
|
+
className: "fw-settings-section",
|
|
728
|
+
children: [jsxRuntime.jsx("div", {
|
|
729
|
+
className: "fw-settings-label",
|
|
730
|
+
children: "Quality"
|
|
731
|
+
}), jsxRuntime.jsxs("div", {
|
|
732
|
+
className: "fw-settings-list",
|
|
733
|
+
children: [jsxRuntime.jsx("button", {
|
|
734
|
+
className: playerCore.cn("fw-settings-list-item", qualityValue === "auto" && "fw-settings-list-item--active"),
|
|
735
|
+
onClick: function onClick() {
|
|
736
|
+
handleQualityChange("auto");
|
|
737
|
+
setIsSettingsOpen(false);
|
|
738
|
+
},
|
|
739
|
+
children: "Auto"
|
|
740
|
+
}), qualities.map(function (q) {
|
|
741
|
+
return jsxRuntime.jsx("button", {
|
|
742
|
+
className: playerCore.cn("fw-settings-list-item", qualityValue === q.id && "fw-settings-list-item--active"),
|
|
743
|
+
onClick: function onClick() {
|
|
744
|
+
handleQualityChange(q.id);
|
|
745
|
+
setIsSettingsOpen(false);
|
|
746
|
+
},
|
|
747
|
+
children: q.label
|
|
748
|
+
}, q.id);
|
|
749
|
+
})]
|
|
750
|
+
})]
|
|
751
|
+
}), textTracks.length > 0 && jsxRuntime.jsxs("div", {
|
|
752
|
+
className: "fw-settings-section",
|
|
753
|
+
children: [jsxRuntime.jsx("div", {
|
|
754
|
+
className: "fw-settings-label",
|
|
755
|
+
children: "Captions"
|
|
756
|
+
}), jsxRuntime.jsxs("div", {
|
|
757
|
+
className: "fw-settings-list",
|
|
758
|
+
children: [jsxRuntime.jsx("button", {
|
|
759
|
+
className: playerCore.cn("fw-settings-list-item", captionValue === "none" && "fw-settings-list-item--active"),
|
|
760
|
+
onClick: function onClick() {
|
|
761
|
+
handleCaptionChange("none");
|
|
762
|
+
setIsSettingsOpen(false);
|
|
763
|
+
},
|
|
764
|
+
children: "Off"
|
|
765
|
+
}), textTracks.map(function (t) {
|
|
766
|
+
return jsxRuntime.jsx("button", {
|
|
767
|
+
className: playerCore.cn("fw-settings-list-item", captionValue === t.id && "fw-settings-list-item--active"),
|
|
768
|
+
onClick: function onClick() {
|
|
769
|
+
handleCaptionChange(t.id);
|
|
770
|
+
setIsSettingsOpen(false);
|
|
771
|
+
},
|
|
772
|
+
children: t.label || t.id
|
|
773
|
+
}, t.id);
|
|
774
|
+
})]
|
|
775
|
+
})]
|
|
776
|
+
})]
|
|
777
|
+
})]
|
|
778
|
+
}), jsxRuntime.jsx("div", {
|
|
779
|
+
className: "fw-control-group",
|
|
780
|
+
children: jsxRuntime.jsx("button", {
|
|
781
|
+
type: "button",
|
|
782
|
+
className: "fw-btn-flush",
|
|
783
|
+
"aria-label": "Toggle fullscreen",
|
|
784
|
+
onClick: handleFullscreen,
|
|
785
|
+
children: jsxRuntime.jsx(Icons.FullscreenToggleIcon, {
|
|
786
|
+
isFullscreen: isFullscreen,
|
|
787
|
+
size: 16
|
|
788
|
+
})
|
|
789
|
+
})
|
|
790
|
+
})]
|
|
791
|
+
})]
|
|
792
|
+
})]
|
|
793
|
+
})
|
|
794
|
+
});
|
|
795
|
+
};
|
|
796
|
+
|
|
797
|
+
exports.default = PlayerControls;
|
|
798
|
+
//# sourceMappingURL=PlayerControls.js.map
|