@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,88 @@
|
|
|
1
|
+
import { slicedToArray as _slicedToArray } from '../_virtual/_rollupPluginBabelHelpers.js';
|
|
2
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Subscribe to player selection changes from a PlayerManager.
|
|
6
|
+
*
|
|
7
|
+
* This hook uses the event system in PlayerManager, which means:
|
|
8
|
+
* - Initial computation happens once when streamInfo is provided
|
|
9
|
+
* - Updates only fire when selection actually changes (different player+source)
|
|
10
|
+
* - No render spam from React strict mode or frequent re-renders
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* const { selection, combinations, ready } = usePlayerSelection(globalPlayerManager, {
|
|
15
|
+
* streamInfo,
|
|
16
|
+
* playbackMode: 'auto',
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* if (!ready) return <Loading />;
|
|
20
|
+
* if (!selection) return <NoPlayerAvailable />;
|
|
21
|
+
*
|
|
22
|
+
* return <div>Selected: {selection.player} + {selection.source.type}</div>;
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
function usePlayerSelection(manager, options) {
|
|
26
|
+
var streamInfo = options.streamInfo,
|
|
27
|
+
playbackMode = options.playbackMode,
|
|
28
|
+
debug = options.debug;
|
|
29
|
+
var _useState = useState(null),
|
|
30
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
31
|
+
selection = _useState2[0],
|
|
32
|
+
setSelection = _useState2[1];
|
|
33
|
+
var _useState3 = useState([]),
|
|
34
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
35
|
+
combinations = _useState4[0],
|
|
36
|
+
setCombinations = _useState4[1];
|
|
37
|
+
var _useState5 = useState(false),
|
|
38
|
+
_useState6 = _slicedToArray(_useState5, 2),
|
|
39
|
+
ready = _useState6[0],
|
|
40
|
+
setReady = _useState6[1];
|
|
41
|
+
// Subscribe to events
|
|
42
|
+
useEffect(function () {
|
|
43
|
+
var unsubSelection = manager.on("selection-changed", function (sel) {
|
|
44
|
+
if (debug) {
|
|
45
|
+
var _sel$source;
|
|
46
|
+
console.log("[usePlayerSelection] Selection changed:", sel === null || sel === void 0 ? void 0 : sel.player, sel === null || sel === void 0 || (_sel$source = sel.source) === null || _sel$source === void 0 ? void 0 : _sel$source.type);
|
|
47
|
+
}
|
|
48
|
+
setSelection(sel);
|
|
49
|
+
});
|
|
50
|
+
var unsubCombos = manager.on("combinations-updated", function (combos) {
|
|
51
|
+
if (debug) {
|
|
52
|
+
console.log("[usePlayerSelection] Combinations updated:", combos.length);
|
|
53
|
+
}
|
|
54
|
+
setCombinations(combos);
|
|
55
|
+
setReady(true);
|
|
56
|
+
});
|
|
57
|
+
return function () {
|
|
58
|
+
unsubSelection();
|
|
59
|
+
unsubCombos();
|
|
60
|
+
};
|
|
61
|
+
}, [manager, debug]);
|
|
62
|
+
// Trigger initial computation when streamInfo changes
|
|
63
|
+
useEffect(function () {
|
|
64
|
+
if (!streamInfo) {
|
|
65
|
+
setSelection(null);
|
|
66
|
+
setCombinations([]);
|
|
67
|
+
setReady(false);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
// This will use cache if available, or compute + emit events if not
|
|
71
|
+
manager.getAllCombinations(streamInfo, playbackMode);
|
|
72
|
+
}, [manager, streamInfo, playbackMode]);
|
|
73
|
+
// Manual refresh function
|
|
74
|
+
var refresh = useCallback(function () {
|
|
75
|
+
if (!streamInfo) return;
|
|
76
|
+
manager.invalidateCache();
|
|
77
|
+
manager.getAllCombinations(streamInfo, playbackMode);
|
|
78
|
+
}, [manager, streamInfo, playbackMode]);
|
|
79
|
+
return {
|
|
80
|
+
selection: selection,
|
|
81
|
+
combinations: combinations,
|
|
82
|
+
ready: ready,
|
|
83
|
+
refresh: refresh
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export { usePlayerSelection };
|
|
88
|
+
//# sourceMappingURL=usePlayerSelection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePlayerSelection.js","sources":["../../../../src/hooks/usePlayerSelection.ts"],"sourcesContent":["/**\n * usePlayerSelection\n *\n * React hook for subscribing to PlayerManager selection events.\n * Uses event-driven updates instead of polling - no render spam.\n */\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport type {\n PlayerManager,\n PlayerSelection,\n PlayerCombination,\n StreamInfo,\n PlaybackMode,\n} from \"@livepeer-frameworks/player-core\";\n\nexport interface UsePlayerSelectionOptions {\n /** Stream info to compute selections for */\n streamInfo: StreamInfo | null;\n /** Playback mode override */\n playbackMode?: PlaybackMode;\n /** Enable debug logging */\n debug?: boolean;\n}\n\nexport interface UsePlayerSelectionReturn {\n /** Current best selection (null if no compatible player) */\n selection: PlayerSelection | null;\n /** All player+source combinations with scores */\n combinations: PlayerCombination[];\n /** Whether initial computation has completed */\n ready: boolean;\n /** Force recomputation (invalidates cache) */\n refresh: () => void;\n}\n\n/**\n * Subscribe to player selection changes from a PlayerManager.\n *\n * This hook uses the event system in PlayerManager, which means:\n * - Initial computation happens once when streamInfo is provided\n * - Updates only fire when selection actually changes (different player+source)\n * - No render spam from React strict mode or frequent re-renders\n *\n * @example\n * ```tsx\n * const { selection, combinations, ready } = usePlayerSelection(globalPlayerManager, {\n * streamInfo,\n * playbackMode: 'auto',\n * });\n *\n * if (!ready) return <Loading />;\n * if (!selection) return <NoPlayerAvailable />;\n *\n * return <div>Selected: {selection.player} + {selection.source.type}</div>;\n * ```\n */\nexport function usePlayerSelection(\n manager: PlayerManager,\n options: UsePlayerSelectionOptions\n): UsePlayerSelectionReturn {\n const { streamInfo, playbackMode, debug } = options;\n\n const [selection, setSelection] = useState<PlayerSelection | null>(null);\n const [combinations, setCombinations] = useState<PlayerCombination[]>([]);\n const [ready, setReady] = useState(false);\n\n // Subscribe to events\n useEffect(() => {\n const unsubSelection = manager.on(\"selection-changed\", (sel) => {\n if (debug) {\n console.log(\"[usePlayerSelection] Selection changed:\", sel?.player, sel?.source?.type);\n }\n setSelection(sel);\n });\n\n const unsubCombos = manager.on(\"combinations-updated\", (combos) => {\n if (debug) {\n console.log(\"[usePlayerSelection] Combinations updated:\", combos.length);\n }\n setCombinations(combos);\n setReady(true);\n });\n\n return () => {\n unsubSelection();\n unsubCombos();\n };\n }, [manager, debug]);\n\n // Trigger initial computation when streamInfo changes\n useEffect(() => {\n if (!streamInfo) {\n setSelection(null);\n setCombinations([]);\n setReady(false);\n return;\n }\n\n // This will use cache if available, or compute + emit events if not\n manager.getAllCombinations(streamInfo, playbackMode);\n }, [manager, streamInfo, playbackMode]);\n\n // Manual refresh function\n const refresh = useCallback(() => {\n if (!streamInfo) return;\n manager.invalidateCache();\n manager.getAllCombinations(streamInfo, playbackMode);\n }, [manager, streamInfo, playbackMode]);\n\n return {\n selection,\n combinations,\n ready,\n refresh,\n };\n}\n"],"names":["usePlayerSelection","manager","options","streamInfo","playbackMode","debug","_useState","useState","_useState2","_slicedToArray","selection","setSelection","_useState3","_useState4","combinations","setCombinations","_useState5","_useState6","ready","setReady","useEffect","unsubSelection","on","sel","_sel$source","console","log","player","source","type","unsubCombos","combos","length","getAllCombinations","refresh","useCallback","invalidateCache"],"mappings":"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"}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator } from '../_virtual/_rollupPluginBabelHelpers.js';
|
|
2
|
+
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Parse MistServer error string into StreamStatus enum
|
|
6
|
+
*/
|
|
7
|
+
function parseErrorToStatus(error) {
|
|
8
|
+
var lowerError = error.toLowerCase();
|
|
9
|
+
if (lowerError.includes("offline")) return "OFFLINE";
|
|
10
|
+
if (lowerError.includes("initializing")) return "INITIALIZING";
|
|
11
|
+
if (lowerError.includes("booting")) return "BOOTING";
|
|
12
|
+
if (lowerError.includes("waiting for data")) return "WAITING_FOR_DATA";
|
|
13
|
+
if (lowerError.includes("shutting down")) return "SHUTTING_DOWN";
|
|
14
|
+
if (lowerError.includes("invalid")) return "INVALID";
|
|
15
|
+
return "ERROR";
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Get human-readable message for stream status
|
|
19
|
+
*/
|
|
20
|
+
function getStatusMessage(status, percentage) {
|
|
21
|
+
switch (status) {
|
|
22
|
+
case "ONLINE":
|
|
23
|
+
return "Stream is online";
|
|
24
|
+
case "OFFLINE":
|
|
25
|
+
return "Stream is offline";
|
|
26
|
+
case "INITIALIZING":
|
|
27
|
+
return percentage !== undefined ? "Initializing... ".concat(Math.round(percentage * 10) / 10, "%") : "Stream is initializing";
|
|
28
|
+
case "BOOTING":
|
|
29
|
+
return "Stream is starting up";
|
|
30
|
+
case "WAITING_FOR_DATA":
|
|
31
|
+
return "Waiting for stream data";
|
|
32
|
+
case "SHUTTING_DOWN":
|
|
33
|
+
return "Stream is shutting down";
|
|
34
|
+
case "INVALID":
|
|
35
|
+
return "Stream status is invalid";
|
|
36
|
+
case "ERROR":
|
|
37
|
+
default:
|
|
38
|
+
return "Stream error";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Initial stream state
|
|
43
|
+
*/
|
|
44
|
+
var initialState = {
|
|
45
|
+
status: "OFFLINE",
|
|
46
|
+
isOnline: false,
|
|
47
|
+
message: "Connecting...",
|
|
48
|
+
lastUpdate: 0
|
|
49
|
+
};
|
|
50
|
+
function useStreamState(options) {
|
|
51
|
+
var mistBaseUrl = options.mistBaseUrl,
|
|
52
|
+
streamName = options.streamName,
|
|
53
|
+
_options$pollInterval = options.pollInterval,
|
|
54
|
+
pollInterval = _options$pollInterval === void 0 ? 3000 : _options$pollInterval,
|
|
55
|
+
_options$enabled = options.enabled,
|
|
56
|
+
enabled = _options$enabled === void 0 ? true : _options$enabled,
|
|
57
|
+
_options$useWebSocket = options.useWebSocket,
|
|
58
|
+
useWebSocket = _options$useWebSocket === void 0 ? true : _options$useWebSocket,
|
|
59
|
+
_options$debug = options.debug,
|
|
60
|
+
debug = _options$debug === void 0 ? false : _options$debug;
|
|
61
|
+
var _useState = useState(initialState),
|
|
62
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
63
|
+
state = _useState2[0],
|
|
64
|
+
setState = _useState2[1];
|
|
65
|
+
var _useState3 = useState(false),
|
|
66
|
+
_useState4 = _slicedToArray(_useState3, 2),
|
|
67
|
+
socketReady = _useState4[0],
|
|
68
|
+
setSocketReady = _useState4[1];
|
|
69
|
+
var wsRef = useRef(null);
|
|
70
|
+
var pollTimeoutRef = useRef(null);
|
|
71
|
+
var wsTimeoutRef = useRef(null);
|
|
72
|
+
var mountedRef = useRef(true);
|
|
73
|
+
// MistPlayer-style WebSocket timeout (5 seconds)
|
|
74
|
+
var WS_TIMEOUT_MS = 5000;
|
|
75
|
+
/**
|
|
76
|
+
* Process MistServer response data
|
|
77
|
+
*/
|
|
78
|
+
var processStreamInfo = useCallback(function (data) {
|
|
79
|
+
if (!mountedRef.current) return;
|
|
80
|
+
if (data.error) {
|
|
81
|
+
// Stream has an error state - preserve previous streamInfo (track data)
|
|
82
|
+
var status = parseErrorToStatus(data.error);
|
|
83
|
+
var message = data.on_error || getStatusMessage(status, data.perc);
|
|
84
|
+
setState(function (prev) {
|
|
85
|
+
return {
|
|
86
|
+
status: status,
|
|
87
|
+
isOnline: false,
|
|
88
|
+
message: message,
|
|
89
|
+
percentage: data.perc,
|
|
90
|
+
lastUpdate: Date.now(),
|
|
91
|
+
error: data.error,
|
|
92
|
+
streamInfo: prev.streamInfo // Preserve track data through error states
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
} else {
|
|
96
|
+
// Stream is online with valid metadata
|
|
97
|
+
// Merge new data with existing streamInfo to preserve source/tracks from initial fetch
|
|
98
|
+
// WebSocket updates may not include source array - only status updates
|
|
99
|
+
setState(function (prev) {
|
|
100
|
+
var _prev$streamInfo, _prev$streamInfo2, _data$meta, _prev$streamInfo3;
|
|
101
|
+
var mergedStreamInfo = _objectSpread2(_objectSpread2(_objectSpread2({}, prev.streamInfo), data), {}, {
|
|
102
|
+
// Override with new data
|
|
103
|
+
// Explicitly preserve source if not in new data
|
|
104
|
+
source: data.source || ((_prev$streamInfo = prev.streamInfo) === null || _prev$streamInfo === void 0 ? void 0 : _prev$streamInfo.source),
|
|
105
|
+
// Merge meta to preserve tracks
|
|
106
|
+
meta: _objectSpread2(_objectSpread2(_objectSpread2({}, (_prev$streamInfo2 = prev.streamInfo) === null || _prev$streamInfo2 === void 0 ? void 0 : _prev$streamInfo2.meta), data.meta), {}, {
|
|
107
|
+
// Preserve tracks if not in new data
|
|
108
|
+
tracks: ((_data$meta = data.meta) === null || _data$meta === void 0 ? void 0 : _data$meta.tracks) || ((_prev$streamInfo3 = prev.streamInfo) === null || _prev$streamInfo3 === void 0 || (_prev$streamInfo3 = _prev$streamInfo3.meta) === null || _prev$streamInfo3 === void 0 ? void 0 : _prev$streamInfo3.tracks)
|
|
109
|
+
})
|
|
110
|
+
});
|
|
111
|
+
return {
|
|
112
|
+
status: "ONLINE",
|
|
113
|
+
isOnline: true,
|
|
114
|
+
message: "Stream is online",
|
|
115
|
+
lastUpdate: Date.now(),
|
|
116
|
+
streamInfo: mergedStreamInfo
|
|
117
|
+
};
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}, []);
|
|
121
|
+
/**
|
|
122
|
+
* HTTP polling fallback
|
|
123
|
+
* Adds metaeverywhere=1 and inclzero=1 like MistPlayer
|
|
124
|
+
*/
|
|
125
|
+
var pollHttp = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
126
|
+
var baseUrl, url, response, text, jsonpMatch, data, _t;
|
|
127
|
+
return _regenerator().w(function (_context) {
|
|
128
|
+
while (1) switch (_context.p = _context.n) {
|
|
129
|
+
case 0:
|
|
130
|
+
if (!(!mountedRef.current || !enabled)) {
|
|
131
|
+
_context.n = 1;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
return _context.a(2);
|
|
135
|
+
case 1:
|
|
136
|
+
_context.p = 1;
|
|
137
|
+
// Build URL with MistPlayer-style params
|
|
138
|
+
baseUrl = "".concat(mistBaseUrl.replace(/\/$/, ""), "/json_").concat(encodeURIComponent(streamName), ".js");
|
|
139
|
+
url = "".concat(baseUrl, "?metaeverywhere=1&inclzero=1");
|
|
140
|
+
_context.n = 2;
|
|
141
|
+
return fetch(url, {
|
|
142
|
+
method: "GET",
|
|
143
|
+
headers: {
|
|
144
|
+
Accept: "application/json"
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
case 2:
|
|
148
|
+
response = _context.v;
|
|
149
|
+
if (response.ok) {
|
|
150
|
+
_context.n = 3;
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
throw new Error("HTTP ".concat(response.status));
|
|
154
|
+
case 3:
|
|
155
|
+
_context.n = 4;
|
|
156
|
+
return response.text();
|
|
157
|
+
case 4:
|
|
158
|
+
text = _context.v;
|
|
159
|
+
// Strip JSONP callback if present (use [\s\S]* instead of /s flag for ES5 compat)
|
|
160
|
+
jsonpMatch = text.match(/^[^(]+\(([\s\S]*)\);?$/);
|
|
161
|
+
if (jsonpMatch) {
|
|
162
|
+
text = jsonpMatch[1];
|
|
163
|
+
}
|
|
164
|
+
data = JSON.parse(text);
|
|
165
|
+
processStreamInfo(data);
|
|
166
|
+
_context.n = 7;
|
|
167
|
+
break;
|
|
168
|
+
case 5:
|
|
169
|
+
_context.p = 5;
|
|
170
|
+
_t = _context.v;
|
|
171
|
+
if (mountedRef.current) {
|
|
172
|
+
_context.n = 6;
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
return _context.a(2);
|
|
176
|
+
case 6:
|
|
177
|
+
setState(function (prev) {
|
|
178
|
+
return _objectSpread2(_objectSpread2({}, prev), {}, {
|
|
179
|
+
status: "ERROR",
|
|
180
|
+
isOnline: false,
|
|
181
|
+
message: _t instanceof Error ? _t.message : "Connection failed",
|
|
182
|
+
lastUpdate: Date.now(),
|
|
183
|
+
error: _t instanceof Error ? _t.message : "Unknown error"
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
case 7:
|
|
187
|
+
// Schedule next poll
|
|
188
|
+
if (mountedRef.current && enabled && !useWebSocket) {
|
|
189
|
+
pollTimeoutRef.current = setTimeout(pollHttp, pollInterval);
|
|
190
|
+
}
|
|
191
|
+
case 8:
|
|
192
|
+
return _context.a(2);
|
|
193
|
+
}
|
|
194
|
+
}, _callee, null, [[1, 5]]);
|
|
195
|
+
})), [mistBaseUrl, streamName, enabled, useWebSocket, pollInterval, processStreamInfo]);
|
|
196
|
+
/**
|
|
197
|
+
* WebSocket connection with MistPlayer-style 5-second timeout
|
|
198
|
+
*/
|
|
199
|
+
var connectWebSocket = useCallback(function () {
|
|
200
|
+
if (!mountedRef.current || !enabled || !useWebSocket) return;
|
|
201
|
+
// Clean up existing connection and timeout
|
|
202
|
+
if (wsTimeoutRef.current) {
|
|
203
|
+
clearTimeout(wsTimeoutRef.current);
|
|
204
|
+
wsTimeoutRef.current = null;
|
|
205
|
+
}
|
|
206
|
+
if (wsRef.current) {
|
|
207
|
+
wsRef.current.close();
|
|
208
|
+
wsRef.current = null;
|
|
209
|
+
}
|
|
210
|
+
try {
|
|
211
|
+
// Convert http(s) to ws(s)
|
|
212
|
+
var wsUrl = mistBaseUrl.replace(/^http:/, "ws:").replace(/^https:/, "wss:").replace(/\/$/, "");
|
|
213
|
+
// Build URL with MistPlayer-style params
|
|
214
|
+
var url = "".concat(wsUrl, "/json_").concat(encodeURIComponent(streamName), ".js?metaeverywhere=1&inclzero=1");
|
|
215
|
+
var ws = new WebSocket(url);
|
|
216
|
+
wsRef.current = ws;
|
|
217
|
+
// MistPlayer-style timeout: if no message within 5 seconds, fall back to HTTP
|
|
218
|
+
wsTimeoutRef.current = setTimeout(function () {
|
|
219
|
+
if (ws.readyState <= WebSocket.OPEN) {
|
|
220
|
+
if (debug) {
|
|
221
|
+
console.debug("[useStreamState] WebSocket timeout (5s), falling back to HTTP polling");
|
|
222
|
+
}
|
|
223
|
+
ws.close();
|
|
224
|
+
pollHttp();
|
|
225
|
+
}
|
|
226
|
+
}, WS_TIMEOUT_MS);
|
|
227
|
+
ws.onopen = function () {
|
|
228
|
+
if (debug) {
|
|
229
|
+
console.debug("[useStreamState] WebSocket connected");
|
|
230
|
+
}
|
|
231
|
+
setSocketReady(true);
|
|
232
|
+
};
|
|
233
|
+
ws.onmessage = function (event) {
|
|
234
|
+
// Clear timeout on first message
|
|
235
|
+
if (wsTimeoutRef.current) {
|
|
236
|
+
clearTimeout(wsTimeoutRef.current);
|
|
237
|
+
wsTimeoutRef.current = null;
|
|
238
|
+
}
|
|
239
|
+
try {
|
|
240
|
+
var data = JSON.parse(event.data);
|
|
241
|
+
processStreamInfo(data);
|
|
242
|
+
} catch (e) {
|
|
243
|
+
console.warn("[useStreamState] Failed to parse WebSocket message:", e);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
ws.onerror = function (_event) {
|
|
247
|
+
console.warn("[useStreamState] WebSocket error, falling back to HTTP polling");
|
|
248
|
+
if (wsTimeoutRef.current) {
|
|
249
|
+
clearTimeout(wsTimeoutRef.current);
|
|
250
|
+
wsTimeoutRef.current = null;
|
|
251
|
+
}
|
|
252
|
+
ws.close();
|
|
253
|
+
};
|
|
254
|
+
ws.onclose = function () {
|
|
255
|
+
wsRef.current = null;
|
|
256
|
+
setSocketReady(false);
|
|
257
|
+
if (!mountedRef.current || !enabled) return;
|
|
258
|
+
// Fallback to HTTP polling or reconnect
|
|
259
|
+
if (debug) {
|
|
260
|
+
console.debug("[useStreamState] WebSocket closed, starting HTTP polling");
|
|
261
|
+
}
|
|
262
|
+
pollHttp();
|
|
263
|
+
};
|
|
264
|
+
} catch (error) {
|
|
265
|
+
console.warn("[useStreamState] WebSocket connection failed:", error);
|
|
266
|
+
// Fallback to HTTP polling
|
|
267
|
+
pollHttp();
|
|
268
|
+
}
|
|
269
|
+
}, [mistBaseUrl, streamName, enabled, useWebSocket, debug, processStreamInfo, pollHttp]);
|
|
270
|
+
/**
|
|
271
|
+
* Manual refetch function
|
|
272
|
+
*/
|
|
273
|
+
var refetch = useCallback(function () {
|
|
274
|
+
var _wsRef$current;
|
|
275
|
+
if (useWebSocket && ((_wsRef$current = wsRef.current) === null || _wsRef$current === void 0 ? void 0 : _wsRef$current.readyState) === WebSocket.OPEN) {
|
|
276
|
+
// WebSocket will receive updates automatically
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
pollHttp();
|
|
280
|
+
}, [useWebSocket, pollHttp]);
|
|
281
|
+
/**
|
|
282
|
+
* Setup connection on mount and when options change
|
|
283
|
+
* Always do initial HTTP poll to get full stream info (including sources),
|
|
284
|
+
* then connect WebSocket for real-time status updates.
|
|
285
|
+
* MistServer WebSocket updates may not include source array.
|
|
286
|
+
*/
|
|
287
|
+
useEffect(function () {
|
|
288
|
+
mountedRef.current = true;
|
|
289
|
+
if (!enabled || !mistBaseUrl || !streamName) {
|
|
290
|
+
setState(initialState);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
// Reset state when stream changes
|
|
294
|
+
setState(_objectSpread2(_objectSpread2({}, initialState), {}, {
|
|
295
|
+
message: "Connecting...",
|
|
296
|
+
lastUpdate: Date.now()
|
|
297
|
+
}));
|
|
298
|
+
// Always do initial HTTP poll to get full data (including sources)
|
|
299
|
+
// Then connect WebSocket for real-time updates
|
|
300
|
+
var initializeConnection = /*#__PURE__*/function () {
|
|
301
|
+
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
|
|
302
|
+
return _regenerator().w(function (_context2) {
|
|
303
|
+
while (1) switch (_context2.n) {
|
|
304
|
+
case 0:
|
|
305
|
+
_context2.n = 1;
|
|
306
|
+
return pollHttp();
|
|
307
|
+
case 1:
|
|
308
|
+
// Then connect WebSocket for status updates (if enabled)
|
|
309
|
+
if (useWebSocket && mountedRef.current) {
|
|
310
|
+
connectWebSocket();
|
|
311
|
+
}
|
|
312
|
+
case 2:
|
|
313
|
+
return _context2.a(2);
|
|
314
|
+
}
|
|
315
|
+
}, _callee2);
|
|
316
|
+
}));
|
|
317
|
+
return function initializeConnection() {
|
|
318
|
+
return _ref2.apply(this, arguments);
|
|
319
|
+
};
|
|
320
|
+
}();
|
|
321
|
+
initializeConnection();
|
|
322
|
+
return function () {
|
|
323
|
+
// Set mounted=false FIRST before any other cleanup
|
|
324
|
+
mountedRef.current = false;
|
|
325
|
+
if (debug) {
|
|
326
|
+
console.debug("[useStreamState] cleanup starting, mountedRef set to false");
|
|
327
|
+
}
|
|
328
|
+
// Cleanup WebSocket timeout
|
|
329
|
+
if (wsTimeoutRef.current) {
|
|
330
|
+
clearTimeout(wsTimeoutRef.current);
|
|
331
|
+
wsTimeoutRef.current = null;
|
|
332
|
+
}
|
|
333
|
+
// Cleanup WebSocket - remove handlers BEFORE closing to prevent onclose callback
|
|
334
|
+
if (wsRef.current) {
|
|
335
|
+
// Detach handlers first to prevent onclose from triggering pollHttp
|
|
336
|
+
wsRef.current.onclose = null;
|
|
337
|
+
wsRef.current.onerror = null;
|
|
338
|
+
wsRef.current.onmessage = null;
|
|
339
|
+
wsRef.current.onopen = null;
|
|
340
|
+
wsRef.current.close();
|
|
341
|
+
wsRef.current = null;
|
|
342
|
+
}
|
|
343
|
+
// Cleanup polling timeout
|
|
344
|
+
if (pollTimeoutRef.current) {
|
|
345
|
+
clearTimeout(pollTimeoutRef.current);
|
|
346
|
+
pollTimeoutRef.current = null;
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
}, [enabled, mistBaseUrl, streamName, useWebSocket, debug, connectWebSocket, pollHttp]);
|
|
350
|
+
return _objectSpread2(_objectSpread2({}, state), {}, {
|
|
351
|
+
refetch: refetch,
|
|
352
|
+
socketRef: wsRef,
|
|
353
|
+
socketReady: socketReady
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
export { useStreamState };
|
|
358
|
+
//# sourceMappingURL=useStreamState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useStreamState.js","sources":["../../../../src/hooks/useStreamState.ts"],"sourcesContent":["import { useEffect, useState, useRef, useCallback } from \"react\";\nimport type { UseStreamStateOptions, StreamState, StreamStatus, MistStreamInfo } from \"../types\";\n\n/**\n * Parse MistServer error string into StreamStatus enum\n */\nfunction parseErrorToStatus(error: string): StreamStatus {\n const lowerError = error.toLowerCase();\n\n if (lowerError.includes(\"offline\")) return \"OFFLINE\";\n if (lowerError.includes(\"initializing\")) return \"INITIALIZING\";\n if (lowerError.includes(\"booting\")) return \"BOOTING\";\n if (lowerError.includes(\"waiting for data\")) return \"WAITING_FOR_DATA\";\n if (lowerError.includes(\"shutting down\")) return \"SHUTTING_DOWN\";\n if (lowerError.includes(\"invalid\")) return \"INVALID\";\n\n return \"ERROR\";\n}\n\n/**\n * Get human-readable message for stream status\n */\nfunction getStatusMessage(status: StreamStatus, percentage?: number): string {\n switch (status) {\n case \"ONLINE\":\n return \"Stream is online\";\n case \"OFFLINE\":\n return \"Stream is offline\";\n case \"INITIALIZING\":\n return percentage !== undefined\n ? `Initializing... ${Math.round(percentage * 10) / 10}%`\n : \"Stream is initializing\";\n case \"BOOTING\":\n return \"Stream is starting up\";\n case \"WAITING_FOR_DATA\":\n return \"Waiting for stream data\";\n case \"SHUTTING_DOWN\":\n return \"Stream is shutting down\";\n case \"INVALID\":\n return \"Stream status is invalid\";\n case \"ERROR\":\n default:\n return \"Stream error\";\n }\n}\n\n/**\n * Initial stream state\n */\nconst initialState: StreamState = {\n status: \"OFFLINE\",\n isOnline: false,\n message: \"Connecting...\",\n lastUpdate: 0,\n};\n\n/**\n * Hook to poll MistServer for stream status via WebSocket or HTTP\n *\n * Uses native MistServer protocol:\n * - WebSocket: ws://{baseUrl}/json_{streamName}.js\n * - HTTP fallback: GET {baseUrl}/json_{streamName}.js\n *\n * @example\n * ```tsx\n * const { status, isOnline, message } = useStreamState({\n * mistBaseUrl: 'https://mist.example.com',\n * streamName: 'pk_...', // playbackId (view key)\n * pollInterval: 3000,\n * });\n * ```\n */\nexport interface UseStreamStateReturn extends StreamState {\n /** Manual refetch function */\n refetch: () => void;\n /** WebSocket reference for sharing with MistReporter */\n socketRef: React.RefObject<WebSocket | null>;\n /** True when WebSocket is connected and ready (triggers re-render) */\n socketReady: boolean;\n}\n\nexport function useStreamState(options: UseStreamStateOptions): UseStreamStateReturn {\n const {\n mistBaseUrl,\n streamName,\n pollInterval = 3000,\n enabled = true,\n useWebSocket = true,\n debug = false,\n } = options;\n\n const [state, setState] = useState<StreamState>(initialState);\n const [socketReady, setSocketReady] = useState(false);\n const wsRef = useRef<WebSocket | null>(null);\n const pollTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const wsTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const mountedRef = useRef(true);\n\n // MistPlayer-style WebSocket timeout (5 seconds)\n const WS_TIMEOUT_MS = 5000;\n\n /**\n * Process MistServer response data\n */\n const processStreamInfo = useCallback((data: MistStreamInfo) => {\n if (!mountedRef.current) return;\n\n if (data.error) {\n // Stream has an error state - preserve previous streamInfo (track data)\n const status = parseErrorToStatus(data.error);\n const message = data.on_error || getStatusMessage(status, data.perc);\n\n setState((prev) => ({\n status,\n isOnline: false,\n message,\n percentage: data.perc,\n lastUpdate: Date.now(),\n error: data.error,\n streamInfo: prev.streamInfo, // Preserve track data through error states\n }));\n } else {\n // Stream is online with valid metadata\n // Merge new data with existing streamInfo to preserve source/tracks from initial fetch\n // WebSocket updates may not include source array - only status updates\n setState((prev) => {\n const mergedStreamInfo: MistStreamInfo = {\n ...prev.streamInfo, // Keep existing source/meta if present\n ...data, // Override with new data\n // Explicitly preserve source if not in new data\n source: data.source || prev.streamInfo?.source,\n // Merge meta to preserve tracks\n meta: {\n ...prev.streamInfo?.meta,\n ...data.meta,\n // Preserve tracks if not in new data\n tracks: data.meta?.tracks || prev.streamInfo?.meta?.tracks,\n },\n };\n\n return {\n status: \"ONLINE\",\n isOnline: true,\n message: \"Stream is online\",\n lastUpdate: Date.now(),\n streamInfo: mergedStreamInfo,\n };\n });\n }\n }, []);\n\n /**\n * HTTP polling fallback\n * Adds metaeverywhere=1 and inclzero=1 like MistPlayer\n */\n const pollHttp = useCallback(async () => {\n if (!mountedRef.current || !enabled) return;\n\n try {\n // Build URL with MistPlayer-style params\n const baseUrl = `${mistBaseUrl.replace(/\\/$/, \"\")}/json_${encodeURIComponent(streamName)}.js`;\n const url = `${baseUrl}?metaeverywhere=1&inclzero=1`;\n const response = await fetch(url, {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n\n // MistServer returns JSON with potential JSONP wrapper\n let text = await response.text();\n // Strip JSONP callback if present (use [\\s\\S]* instead of /s flag for ES5 compat)\n const jsonpMatch = text.match(/^[^(]+\\(([\\s\\S]*)\\);?$/);\n if (jsonpMatch) {\n text = jsonpMatch[1];\n }\n\n const data = JSON.parse(text) as MistStreamInfo;\n processStreamInfo(data);\n } catch (error) {\n if (!mountedRef.current) return;\n\n setState((prev) => ({\n ...prev,\n status: \"ERROR\",\n isOnline: false,\n message: error instanceof Error ? error.message : \"Connection failed\",\n lastUpdate: Date.now(),\n error: error instanceof Error ? error.message : \"Unknown error\",\n }));\n }\n\n // Schedule next poll\n if (mountedRef.current && enabled && !useWebSocket) {\n pollTimeoutRef.current = setTimeout(pollHttp, pollInterval);\n }\n }, [mistBaseUrl, streamName, enabled, useWebSocket, pollInterval, processStreamInfo]);\n\n /**\n * WebSocket connection with MistPlayer-style 5-second timeout\n */\n const connectWebSocket = useCallback(() => {\n if (!mountedRef.current || !enabled || !useWebSocket) return;\n\n // Clean up existing connection and timeout\n if (wsTimeoutRef.current) {\n clearTimeout(wsTimeoutRef.current);\n wsTimeoutRef.current = null;\n }\n if (wsRef.current) {\n wsRef.current.close();\n wsRef.current = null;\n }\n\n try {\n // Convert http(s) to ws(s)\n const wsUrl = mistBaseUrl\n .replace(/^http:/, \"ws:\")\n .replace(/^https:/, \"wss:\")\n .replace(/\\/$/, \"\");\n\n // Build URL with MistPlayer-style params\n const url = `${wsUrl}/json_${encodeURIComponent(streamName)}.js?metaeverywhere=1&inclzero=1`;\n const ws = new WebSocket(url);\n wsRef.current = ws;\n\n // MistPlayer-style timeout: if no message within 5 seconds, fall back to HTTP\n wsTimeoutRef.current = setTimeout(() => {\n if (ws.readyState <= WebSocket.OPEN) {\n if (debug) {\n console.debug(\"[useStreamState] WebSocket timeout (5s), falling back to HTTP polling\");\n }\n ws.close();\n pollHttp();\n }\n }, WS_TIMEOUT_MS);\n\n ws.onopen = () => {\n if (debug) {\n console.debug(\"[useStreamState] WebSocket connected\");\n }\n setSocketReady(true);\n };\n\n ws.onmessage = (event) => {\n // Clear timeout on first message\n if (wsTimeoutRef.current) {\n clearTimeout(wsTimeoutRef.current);\n wsTimeoutRef.current = null;\n }\n\n try {\n const data = JSON.parse(event.data) as MistStreamInfo;\n processStreamInfo(data);\n } catch (e) {\n console.warn(\"[useStreamState] Failed to parse WebSocket message:\", e);\n }\n };\n\n ws.onerror = (_event) => {\n console.warn(\"[useStreamState] WebSocket error, falling back to HTTP polling\");\n if (wsTimeoutRef.current) {\n clearTimeout(wsTimeoutRef.current);\n wsTimeoutRef.current = null;\n }\n ws.close();\n };\n\n ws.onclose = () => {\n wsRef.current = null;\n setSocketReady(false);\n\n if (!mountedRef.current || !enabled) return;\n\n // Fallback to HTTP polling or reconnect\n if (debug) {\n console.debug(\"[useStreamState] WebSocket closed, starting HTTP polling\");\n }\n pollHttp();\n };\n } catch (error) {\n console.warn(\"[useStreamState] WebSocket connection failed:\", error);\n // Fallback to HTTP polling\n pollHttp();\n }\n }, [mistBaseUrl, streamName, enabled, useWebSocket, debug, processStreamInfo, pollHttp]);\n\n /**\n * Manual refetch function\n */\n const refetch = useCallback(() => {\n if (useWebSocket && wsRef.current?.readyState === WebSocket.OPEN) {\n // WebSocket will receive updates automatically\n return;\n }\n pollHttp();\n }, [useWebSocket, pollHttp]);\n\n /**\n * Setup connection on mount and when options change\n * Always do initial HTTP poll to get full stream info (including sources),\n * then connect WebSocket for real-time status updates.\n * MistServer WebSocket updates may not include source array.\n */\n useEffect(() => {\n mountedRef.current = true;\n\n if (!enabled || !mistBaseUrl || !streamName) {\n setState(initialState);\n return;\n }\n\n // Reset state when stream changes\n setState({\n ...initialState,\n message: \"Connecting...\",\n lastUpdate: Date.now(),\n });\n\n // Always do initial HTTP poll to get full data (including sources)\n // Then connect WebSocket for real-time updates\n const initializeConnection = async () => {\n // First HTTP poll to get complete stream info\n await pollHttp();\n\n // Then connect WebSocket for status updates (if enabled)\n if (useWebSocket && mountedRef.current) {\n connectWebSocket();\n }\n };\n\n initializeConnection();\n\n return () => {\n // Set mounted=false FIRST before any other cleanup\n mountedRef.current = false;\n if (debug) {\n console.debug(\"[useStreamState] cleanup starting, mountedRef set to false\");\n }\n\n // Cleanup WebSocket timeout\n if (wsTimeoutRef.current) {\n clearTimeout(wsTimeoutRef.current);\n wsTimeoutRef.current = null;\n }\n\n // Cleanup WebSocket - remove handlers BEFORE closing to prevent onclose callback\n if (wsRef.current) {\n // Detach handlers first to prevent onclose from triggering pollHttp\n wsRef.current.onclose = null;\n wsRef.current.onerror = null;\n wsRef.current.onmessage = null;\n wsRef.current.onopen = null;\n wsRef.current.close();\n wsRef.current = null;\n }\n\n // Cleanup polling timeout\n if (pollTimeoutRef.current) {\n clearTimeout(pollTimeoutRef.current);\n pollTimeoutRef.current = null;\n }\n };\n }, [enabled, mistBaseUrl, streamName, useWebSocket, debug, connectWebSocket, pollHttp]);\n\n return {\n ...state,\n refetch,\n socketRef: wsRef,\n socketReady,\n };\n}\n\nexport default useStreamState;\n"],"names":["parseErrorToStatus","error","lowerError","toLowerCase","includes","getStatusMessage","status","percentage","undefined","concat","Math","round","initialState","isOnline","message","lastUpdate","useStreamState","options","mistBaseUrl","streamName","_options$pollInterval","pollInterval","_options$enabled","enabled","_options$useWebSocket","useWebSocket","_options$debug","debug","_useState","useState","_useState2","_slicedToArray","state","setState","_useState3","_useState4","socketReady","setSocketReady","wsRef","useRef","pollTimeoutRef","wsTimeoutRef","mountedRef","WS_TIMEOUT_MS","processStreamInfo","useCallback","data","current","on_error","perc","prev","Date","now","streamInfo","_prev$streamInfo","_prev$streamInfo2","_data$meta","_prev$streamInfo3","mergedStreamInfo","_objectSpread","source","meta","tracks","pollHttp","_asyncToGenerator","_regenerator","m","_callee","baseUrl","url","response","text","jsonpMatch","_t","w","_context","p","n","a","replace","encodeURIComponent","fetch","method","headers","Accept","v","ok","Error","match","JSON","parse","setTimeout","connectWebSocket","clearTimeout","close","wsUrl","ws","WebSocket","readyState","OPEN","console","onopen","onmessage","event","e","warn","onerror","_event","onclose","refetch","_wsRef$current","useEffect","initializeConnection","_ref2","_callee2","_context2","apply","arguments","socketRef"],"mappings":"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"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { useRef, useEffect, useCallback } from 'react';
|
|
2
|
+
import { TelemetryReporter } from '@livepeer-frameworks/player-core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook to send telemetry data to a server
|
|
6
|
+
*
|
|
7
|
+
* Reports playback metrics at configurable intervals:
|
|
8
|
+
* - Current time and duration
|
|
9
|
+
* - Buffer health
|
|
10
|
+
* - Stall count and duration
|
|
11
|
+
* - Quality score and bitrate
|
|
12
|
+
* - Frame decode/drop stats
|
|
13
|
+
* - Errors encountered
|
|
14
|
+
*
|
|
15
|
+
* Uses navigator.sendBeacon() for reliable reporting on page unload.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* const { sessionId, recordError } = useTelemetry({
|
|
20
|
+
* enabled: true,
|
|
21
|
+
* endpoint: '/api/telemetry',
|
|
22
|
+
* interval: 5000,
|
|
23
|
+
* videoElement,
|
|
24
|
+
* contentId: 'pk_...', // playbackId (view key)
|
|
25
|
+
* contentType: 'live',
|
|
26
|
+
* playerType: 'hlsjs',
|
|
27
|
+
* protocol: 'HLS',
|
|
28
|
+
* getQuality: () => qualityMonitor.getCurrentQuality(),
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* // Record custom error
|
|
32
|
+
* recordError('NETWORK_ERROR', 'Connection lost');
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
function useTelemetry(options) {
|
|
36
|
+
var _reporterRef$current$3, _reporterRef$current7;
|
|
37
|
+
var enabled = options.enabled,
|
|
38
|
+
endpoint = options.endpoint,
|
|
39
|
+
interval = options.interval,
|
|
40
|
+
authToken = options.authToken,
|
|
41
|
+
batchSize = options.batchSize,
|
|
42
|
+
videoElement = options.videoElement,
|
|
43
|
+
contentId = options.contentId,
|
|
44
|
+
contentType = options.contentType,
|
|
45
|
+
playerType = options.playerType,
|
|
46
|
+
protocol = options.protocol,
|
|
47
|
+
getQuality = options.getQuality;
|
|
48
|
+
var reporterRef = useRef(null);
|
|
49
|
+
// Create reporter instance
|
|
50
|
+
useEffect(function () {
|
|
51
|
+
if (!enabled || !endpoint || !contentId) {
|
|
52
|
+
var _reporterRef$current;
|
|
53
|
+
(_reporterRef$current = reporterRef.current) === null || _reporterRef$current === void 0 || _reporterRef$current.stop();
|
|
54
|
+
reporterRef.current = null;
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
reporterRef.current = new TelemetryReporter({
|
|
58
|
+
endpoint: endpoint,
|
|
59
|
+
authToken: authToken,
|
|
60
|
+
interval: interval,
|
|
61
|
+
batchSize: batchSize,
|
|
62
|
+
contentId: contentId,
|
|
63
|
+
contentType: contentType,
|
|
64
|
+
playerType: playerType,
|
|
65
|
+
protocol: protocol
|
|
66
|
+
});
|
|
67
|
+
return function () {
|
|
68
|
+
var _reporterRef$current2;
|
|
69
|
+
(_reporterRef$current2 = reporterRef.current) === null || _reporterRef$current2 === void 0 || _reporterRef$current2.stop();
|
|
70
|
+
reporterRef.current = null;
|
|
71
|
+
};
|
|
72
|
+
}, [enabled, endpoint, authToken, interval, batchSize, contentId, contentType, playerType, protocol]);
|
|
73
|
+
// Start/stop reporting when video element changes
|
|
74
|
+
useEffect(function () {
|
|
75
|
+
if (!enabled || !videoElement || !reporterRef.current) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
reporterRef.current.start(videoElement, getQuality);
|
|
79
|
+
return function () {
|
|
80
|
+
var _reporterRef$current3;
|
|
81
|
+
(_reporterRef$current3 = reporterRef.current) === null || _reporterRef$current3 === void 0 || _reporterRef$current3.stop();
|
|
82
|
+
};
|
|
83
|
+
}, [enabled, videoElement, getQuality]);
|
|
84
|
+
/**
|
|
85
|
+
* Record a custom error
|
|
86
|
+
*/
|
|
87
|
+
var recordError = useCallback(function (code, message) {
|
|
88
|
+
var _reporterRef$current4;
|
|
89
|
+
(_reporterRef$current4 = reporterRef.current) === null || _reporterRef$current4 === void 0 || _reporterRef$current4.recordError(code, message);
|
|
90
|
+
}, []);
|
|
91
|
+
/**
|
|
92
|
+
* Get current session ID
|
|
93
|
+
*/
|
|
94
|
+
var getSessionId = useCallback(function () {
|
|
95
|
+
var _reporterRef$current$, _reporterRef$current5;
|
|
96
|
+
return (_reporterRef$current$ = (_reporterRef$current5 = reporterRef.current) === null || _reporterRef$current5 === void 0 ? void 0 : _reporterRef$current5.getSessionId()) !== null && _reporterRef$current$ !== void 0 ? _reporterRef$current$ : null;
|
|
97
|
+
}, []);
|
|
98
|
+
/**
|
|
99
|
+
* Check if telemetry is active
|
|
100
|
+
*/
|
|
101
|
+
var isActive = useCallback(function () {
|
|
102
|
+
var _reporterRef$current$2, _reporterRef$current6;
|
|
103
|
+
return (_reporterRef$current$2 = (_reporterRef$current6 = reporterRef.current) === null || _reporterRef$current6 === void 0 ? void 0 : _reporterRef$current6.isActive()) !== null && _reporterRef$current$2 !== void 0 ? _reporterRef$current$2 : false;
|
|
104
|
+
}, []);
|
|
105
|
+
return {
|
|
106
|
+
/** Session ID for this playback session */
|
|
107
|
+
sessionId: (_reporterRef$current$3 = (_reporterRef$current7 = reporterRef.current) === null || _reporterRef$current7 === void 0 ? void 0 : _reporterRef$current7.getSessionId()) !== null && _reporterRef$current$3 !== void 0 ? _reporterRef$current$3 : null,
|
|
108
|
+
/** Record a custom error */
|
|
109
|
+
recordError: recordError,
|
|
110
|
+
/** Get current session ID */
|
|
111
|
+
getSessionId: getSessionId,
|
|
112
|
+
/** Check if telemetry is active */
|
|
113
|
+
isActive: isActive
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export { useTelemetry };
|
|
118
|
+
//# sourceMappingURL=useTelemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTelemetry.js","sources":["../../../../src/hooks/useTelemetry.ts"],"sourcesContent":["import { useEffect, useRef, useCallback } from \"react\";\nimport {\n TelemetryReporter,\n type TelemetryOptions,\n type PlaybackQuality,\n type ContentType,\n} from \"@livepeer-frameworks/player-core\";\n\nexport interface UseTelemetryOptions extends TelemetryOptions {\n /** Video element to monitor */\n videoElement: HTMLVideoElement | null;\n /** Content ID being played */\n contentId: string;\n /** Content type */\n contentType: ContentType;\n /** Player type name */\n playerType: string;\n /** Protocol being used */\n protocol: string;\n /** Optional quality getter function */\n getQuality?: () => PlaybackQuality | null;\n}\n\n/**\n * Hook to send telemetry data to a server\n *\n * Reports playback metrics at configurable intervals:\n * - Current time and duration\n * - Buffer health\n * - Stall count and duration\n * - Quality score and bitrate\n * - Frame decode/drop stats\n * - Errors encountered\n *\n * Uses navigator.sendBeacon() for reliable reporting on page unload.\n *\n * @example\n * ```tsx\n * const { sessionId, recordError } = useTelemetry({\n * enabled: true,\n * endpoint: '/api/telemetry',\n * interval: 5000,\n * videoElement,\n * contentId: 'pk_...', // playbackId (view key)\n * contentType: 'live',\n * playerType: 'hlsjs',\n * protocol: 'HLS',\n * getQuality: () => qualityMonitor.getCurrentQuality(),\n * });\n *\n * // Record custom error\n * recordError('NETWORK_ERROR', 'Connection lost');\n * ```\n */\nexport function useTelemetry(options: UseTelemetryOptions) {\n const {\n enabled,\n endpoint,\n interval,\n authToken,\n batchSize,\n videoElement,\n contentId,\n contentType,\n playerType,\n protocol,\n getQuality,\n } = options;\n\n const reporterRef = useRef<TelemetryReporter | null>(null);\n\n // Create reporter instance\n useEffect(() => {\n if (!enabled || !endpoint || !contentId) {\n reporterRef.current?.stop();\n reporterRef.current = null;\n return;\n }\n\n reporterRef.current = new TelemetryReporter({\n endpoint,\n authToken,\n interval,\n batchSize,\n contentId,\n contentType,\n playerType,\n protocol,\n });\n\n return () => {\n reporterRef.current?.stop();\n reporterRef.current = null;\n };\n }, [\n enabled,\n endpoint,\n authToken,\n interval,\n batchSize,\n contentId,\n contentType,\n playerType,\n protocol,\n ]);\n\n // Start/stop reporting when video element changes\n useEffect(() => {\n if (!enabled || !videoElement || !reporterRef.current) {\n return;\n }\n\n reporterRef.current.start(videoElement, getQuality);\n\n return () => {\n reporterRef.current?.stop();\n };\n }, [enabled, videoElement, getQuality]);\n\n /**\n * Record a custom error\n */\n const recordError = useCallback((code: string, message: string) => {\n reporterRef.current?.recordError(code, message);\n }, []);\n\n /**\n * Get current session ID\n */\n const getSessionId = useCallback((): string | null => {\n return reporterRef.current?.getSessionId() ?? null;\n }, []);\n\n /**\n * Check if telemetry is active\n */\n const isActive = useCallback((): boolean => {\n return reporterRef.current?.isActive() ?? false;\n }, []);\n\n return {\n /** Session ID for this playback session */\n sessionId: reporterRef.current?.getSessionId() ?? null,\n /** Record a custom error */\n recordError,\n /** Get current session ID */\n getSessionId,\n /** Check if telemetry is active */\n isActive,\n };\n}\n\nexport default useTelemetry;\n"],"names":["useTelemetry","options","_reporterRef$current$3","_reporterRef$current7","enabled","endpoint","interval","authToken","batchSize","videoElement","contentId","contentType","playerType","protocol","getQuality","reporterRef","useRef","useEffect","_reporterRef$current","current","stop","TelemetryReporter","_reporterRef$current2","start","_reporterRef$current3","recordError","useCallback","code","message","_reporterRef$current4","getSessionId","_reporterRef$current$","_reporterRef$current5","isActive","_reporterRef$current$2","_reporterRef$current6","sessionId"],"mappings":"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"}
|