@streamplace/components 0.7.1 → 0.7.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/dist/components/chat/chat-box.js +46 -43
- package/dist/components/chat/chat-message.js +36 -33
- package/dist/components/chat/chat.js +31 -27
- package/dist/components/chat/mention-suggestions.js +16 -13
- package/dist/components/chat/mod-view.js +20 -17
- package/dist/components/mobile-player/fullscreen.js +21 -17
- package/dist/components/mobile-player/fullscreen.native.js +39 -35
- package/dist/components/mobile-player/player.js +38 -32
- package/dist/components/mobile-player/props.js +2 -1
- package/dist/components/mobile-player/shared.js +16 -13
- package/dist/components/mobile-player/ui/countdown.js +23 -19
- package/dist/components/mobile-player/ui/index.js +9 -6
- package/dist/components/mobile-player/ui/input.js +16 -12
- package/dist/components/mobile-player/ui/metrics.js +20 -16
- package/dist/components/mobile-player/ui/streamer-context-menu.js +6 -3
- package/dist/components/mobile-player/ui/viewer-context-menu.js +19 -16
- package/dist/components/mobile-player/ui/viewers.js +13 -9
- package/dist/components/mobile-player/use-webrtc.js +29 -24
- package/dist/components/mobile-player/video.js +109 -99
- package/dist/components/mobile-player/video.native.js +92 -85
- package/dist/components/mobile-player/webrtc-diagnostics.js +9 -5
- package/dist/components/mobile-player/webrtc-primitives.js +8 -6
- package/dist/components/mobile-player/webrtc-primitives.native.js +8 -1
- package/dist/components/ui/button.js +26 -23
- package/dist/components/ui/dialog.js +43 -40
- package/dist/components/ui/dropdown.js +121 -116
- package/dist/components/ui/icons.js +8 -5
- package/dist/components/ui/index.js +27 -19
- package/dist/components/ui/input.js +31 -28
- package/dist/components/ui/loader.js +9 -6
- package/dist/components/ui/primitives/button.js +33 -29
- package/dist/components/ui/primitives/input.js +44 -40
- package/dist/components/ui/primitives/modal.js +45 -41
- package/dist/components/ui/primitives/text.js +35 -29
- package/dist/components/ui/resizeable.js +48 -44
- package/dist/components/ui/text.js +50 -48
- package/dist/components/ui/textarea.js +13 -11
- package/dist/components/ui/toast.js +26 -23
- package/dist/components/ui/view.js +41 -39
- package/dist/hooks/index.js +12 -9
- package/dist/hooks/useAvatars.js +11 -8
- package/dist/hooks/useCameraToggle.js +7 -4
- package/dist/hooks/useKeyboard.js +13 -10
- package/dist/hooks/useKeyboardSlide.js +8 -5
- package/dist/hooks/useLivestreamInfo.js +17 -14
- package/dist/hooks/useOuterAndInnerDimensions.js +9 -6
- package/dist/hooks/usePlayerDimensions.js +9 -6
- package/dist/hooks/useSegmentDimensions.js +6 -3
- package/dist/hooks/useSegmentTiming.js +13 -10
- package/dist/index.js +24 -15
- package/dist/lib/facet.js +5 -1
- package/dist/lib/theme/atoms.js +153 -148
- package/dist/lib/theme/atoms.types.js +2 -1
- package/dist/lib/theme/index.js +31 -5
- package/dist/lib/theme/theme.js +91 -83
- package/dist/lib/theme/tokens.js +15 -12
- package/dist/lib/utils.js +22 -11
- package/dist/livestream-provider/index.js +19 -14
- package/dist/livestream-provider/websocket.js +14 -10
- package/dist/livestream-store/chat.js +26 -19
- package/dist/livestream-store/context.js +5 -2
- package/dist/livestream-store/index.js +7 -4
- package/dist/livestream-store/livestream-state.js +2 -1
- package/dist/livestream-store/livestream-store.js +31 -18
- package/dist/livestream-store/stream-key.js +22 -18
- package/dist/livestream-store/websocket-consumer.js +18 -14
- package/dist/player-store/context.js +5 -2
- package/dist/player-store/index.js +8 -5
- package/dist/player-store/player-provider.js +20 -15
- package/dist/player-store/player-state.js +9 -6
- package/dist/player-store/player-store.js +32 -21
- package/dist/player-store/single-player-provider.js +35 -23
- package/dist/streamplace-provider/context.js +5 -2
- package/dist/streamplace-provider/index.js +14 -10
- package/dist/streamplace-provider/poller.js +20 -17
- package/dist/streamplace-store/block.js +6 -3
- package/dist/streamplace-store/index.js +6 -3
- package/dist/streamplace-store/stream.js +14 -10
- package/dist/streamplace-store/streamplace-store.js +23 -13
- package/dist/streamplace-store/user.js +19 -14
- package/dist/streamplace-store/xrpc.js +10 -7
- package/node-compile-cache/v22.15.0-x64-92db9086-0/37be0eec +0 -0
- package/node-compile-cache/v22.15.0-x64-92db9086-0/56540125 +0 -0
- package/node-compile-cache/{v22.15.0-x64-efe9a9df-0 → v22.15.0-x64-92db9086-0}/67b1eb60 +0 -0
- package/node-compile-cache/{v22.15.0-x64-efe9a9df-0 → v22.15.0-x64-92db9086-0}/7c275f90 +0 -0
- package/package.json +5 -6
- package/tsconfig.json +2 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/node-compile-cache/v22.15.0-x64-efe9a9df-0/37be0eec +0 -0
- package/node-compile-cache/v22.15.0-x64-efe9a9df-0/56540125 +0 -0
|
@@ -1,48 +1,52 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Fullscreen = Fullscreen;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
const native_1 = require("@react-navigation/native");
|
|
7
|
+
const react_1 = require("react");
|
|
8
|
+
const react_native_1 = require("react-native");
|
|
9
|
+
const react_native_edge_to_edge_1 = require("react-native-edge-to-edge");
|
|
10
|
+
const react_native_safe_area_context_1 = require("react-native-safe-area-context");
|
|
11
|
+
const __1 = require("../..");
|
|
12
|
+
const video_native_1 = tslib_1.__importDefault(require("./video.native"));
|
|
9
13
|
// Standard 16:9 video aspect ratio
|
|
10
14
|
const VIDEO_ASPECT_RATIO = 16 / 9;
|
|
11
|
-
|
|
12
|
-
const ref = useRef(null);
|
|
13
|
-
const insets = useSafeAreaInsets();
|
|
14
|
-
const navigation = useNavigation();
|
|
15
|
-
const [dimensions, setDimensions] = useState(Dimensions.get("window"));
|
|
15
|
+
function Fullscreen(props) {
|
|
16
|
+
const ref = (0, react_1.useRef)(null);
|
|
17
|
+
const insets = (0, react_native_safe_area_context_1.useSafeAreaInsets)();
|
|
18
|
+
const navigation = (0, native_1.useNavigation)();
|
|
19
|
+
const [dimensions, setDimensions] = (0, react_1.useState)(react_native_1.Dimensions.get("window"));
|
|
16
20
|
// Get state from player store
|
|
17
|
-
const protocol = usePlayerStore((x) => x.protocol);
|
|
18
|
-
const fullscreen = usePlayerStore((x) => x.fullscreen);
|
|
19
|
-
const setFullscreen = usePlayerStore((x) => x.setFullscreen);
|
|
20
|
-
const handle = useLivestreamStore((x) => x.profile?.handle);
|
|
21
|
-
const setSrc = usePlayerStore((x) => x.setSrc);
|
|
22
|
-
useEffect(() => {
|
|
21
|
+
const protocol = (0, __1.usePlayerStore)((x) => x.protocol);
|
|
22
|
+
const fullscreen = (0, __1.usePlayerStore)((x) => x.fullscreen);
|
|
23
|
+
const setFullscreen = (0, __1.usePlayerStore)((x) => x.setFullscreen);
|
|
24
|
+
const handle = (0, __1.useLivestreamStore)((x) => x.profile?.handle);
|
|
25
|
+
const setSrc = (0, __1.usePlayerStore)((x) => x.setSrc);
|
|
26
|
+
(0, react_1.useEffect)(() => {
|
|
23
27
|
setSrc(props.src);
|
|
24
28
|
}, [props.src]);
|
|
25
29
|
// Re-calculate dimensions on orientation change
|
|
26
|
-
useEffect(() => {
|
|
30
|
+
(0, react_1.useEffect)(() => {
|
|
27
31
|
const updateDimensions = () => {
|
|
28
|
-
setDimensions(Dimensions.get("window"));
|
|
32
|
+
setDimensions(react_native_1.Dimensions.get("window"));
|
|
29
33
|
};
|
|
30
|
-
const subscription = Dimensions.addEventListener("change", updateDimensions);
|
|
34
|
+
const subscription = react_native_1.Dimensions.addEventListener("change", updateDimensions);
|
|
31
35
|
return () => {
|
|
32
36
|
subscription.remove();
|
|
33
37
|
};
|
|
34
38
|
}, []);
|
|
35
39
|
// Hide status bar when in fullscreen mode
|
|
36
|
-
useEffect(() => {
|
|
40
|
+
(0, react_1.useEffect)(() => {
|
|
37
41
|
if (fullscreen) {
|
|
38
|
-
SystemBars.setHidden(true);
|
|
42
|
+
react_native_edge_to_edge_1.SystemBars.setHidden(true);
|
|
39
43
|
console.log("setting sidebar hidden");
|
|
40
44
|
// Hide the navigation header
|
|
41
45
|
navigation.setOptions({
|
|
42
46
|
headerShown: false,
|
|
43
47
|
});
|
|
44
48
|
// Handle hardware back button
|
|
45
|
-
const backHandler = BackHandler.addEventListener("hardwareBackPress", () => {
|
|
49
|
+
const backHandler = react_native_1.BackHandler.addEventListener("hardwareBackPress", () => {
|
|
46
50
|
setFullscreen(false);
|
|
47
51
|
return true;
|
|
48
52
|
});
|
|
@@ -51,14 +55,14 @@ export function Fullscreen(props) {
|
|
|
51
55
|
};
|
|
52
56
|
}
|
|
53
57
|
else {
|
|
54
|
-
SystemBars.setHidden(false);
|
|
58
|
+
react_native_edge_to_edge_1.SystemBars.setHidden(false);
|
|
55
59
|
// Restore the navigation header
|
|
56
60
|
navigation.setOptions({
|
|
57
61
|
headerShown: true,
|
|
58
62
|
});
|
|
59
63
|
}
|
|
60
64
|
return () => {
|
|
61
|
-
SystemBars.setHidden(false);
|
|
65
|
+
react_native_edge_to_edge_1.SystemBars.setHidden(false);
|
|
62
66
|
// Ensure header is restored if component unmounts
|
|
63
67
|
navigation.setOptions({
|
|
64
68
|
headerShown: true,
|
|
@@ -66,9 +70,9 @@ export function Fullscreen(props) {
|
|
|
66
70
|
};
|
|
67
71
|
}, [fullscreen, navigation, setFullscreen]);
|
|
68
72
|
// Handle fullscreen state changes for native video players
|
|
69
|
-
useEffect(() => {
|
|
73
|
+
(0, react_1.useEffect)(() => {
|
|
70
74
|
// For WebRTC, we handle fullscreen manually via the custom implementation
|
|
71
|
-
if (protocol === PlayerProtocol.WEBRTC) {
|
|
75
|
+
if (protocol === __1.PlayerProtocol.WEBRTC) {
|
|
72
76
|
return;
|
|
73
77
|
}
|
|
74
78
|
// For HLS and other protocols, sync with native fullscreen
|
|
@@ -81,7 +85,7 @@ export function Fullscreen(props) {
|
|
|
81
85
|
}
|
|
82
86
|
}
|
|
83
87
|
}, [fullscreen, protocol]);
|
|
84
|
-
if (fullscreen && protocol === PlayerProtocol.WEBRTC) {
|
|
88
|
+
if (fullscreen && protocol === __1.PlayerProtocol.WEBRTC) {
|
|
85
89
|
// Determine if we're in landscape mode
|
|
86
90
|
const isLandscape = dimensions.width > dimensions.height;
|
|
87
91
|
// Calculate video container dimensions based on screen size and orientation
|
|
@@ -109,13 +113,13 @@ export function Fullscreen(props) {
|
|
|
109
113
|
const leftPosition = (dimensions.width - videoWidth) / 2;
|
|
110
114
|
const topPosition = (dimensions.height - videoHeight) / 2;
|
|
111
115
|
// When in custom fullscreen mode
|
|
112
|
-
return (
|
|
116
|
+
return ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: [
|
|
113
117
|
styles.fullscreenContainer,
|
|
114
118
|
{
|
|
115
119
|
width: isLandscape ? dimensions.width + 40 : dimensions.width,
|
|
116
120
|
height: dimensions.height,
|
|
117
121
|
},
|
|
118
|
-
], children:
|
|
122
|
+
], children: (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [
|
|
119
123
|
styles.videoContainer,
|
|
120
124
|
{
|
|
121
125
|
width: isLandscape ? videoWidth + 40 : videoWidth,
|
|
@@ -123,12 +127,12 @@ export function Fullscreen(props) {
|
|
|
123
127
|
left: leftPosition,
|
|
124
128
|
top: topPosition,
|
|
125
129
|
},
|
|
126
|
-
], children:
|
|
130
|
+
], children: (0, jsx_runtime_1.jsx)(video_native_1.default, {}) }) }));
|
|
127
131
|
}
|
|
128
132
|
// Normal non-fullscreen mode
|
|
129
|
-
return (
|
|
133
|
+
return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsx)(video_native_1.default, {}) }));
|
|
130
134
|
}
|
|
131
|
-
const styles = StyleSheet.create({
|
|
135
|
+
const styles = react_native_1.StyleSheet.create({
|
|
132
136
|
fullscreenContainer: {
|
|
133
137
|
position: "absolute",
|
|
134
138
|
top: 0,
|
|
@@ -1,34 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PlayerUI = void 0;
|
|
4
|
+
exports.Player = Player;
|
|
5
|
+
exports.usePlayerStatus = usePlayerStatus;
|
|
6
|
+
const tslib_1 = require("tslib");
|
|
7
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
const react_1 = require("react");
|
|
9
|
+
const atoms_1 = require("../../lib/theme/atoms");
|
|
10
|
+
const livestream_store_1 = require("../../livestream-store");
|
|
11
|
+
const player_store_1 = require("../../player-store");
|
|
12
|
+
const streamplace_store_1 = require("../../streamplace-store");
|
|
13
|
+
const ui_1 = require("../ui");
|
|
14
|
+
const fullscreen_1 = require("./fullscreen");
|
|
9
15
|
const OFFLINE_THRESHOLD = 10000;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const playing = usePlayerStore((x) => x.status === PlayerStatus.PLAYING);
|
|
13
|
-
const setOffline = usePlayerStore((x) => x.setOffline);
|
|
14
|
-
const setIngest = usePlayerStore((x) => x.setIngestConnectionState);
|
|
15
|
-
const clearControlsTimeout = usePlayerStore((x) => x.clearControlsTimeout);
|
|
16
|
+
exports.PlayerUI = tslib_1.__importStar(require("./ui"));
|
|
17
|
+
function Player(props) {
|
|
18
|
+
const playing = (0, player_store_1.usePlayerStore)((x) => x.status === player_store_1.PlayerStatus.PLAYING);
|
|
19
|
+
const setOffline = (0, player_store_1.usePlayerStore)((x) => x.setOffline);
|
|
20
|
+
const setIngest = (0, player_store_1.usePlayerStore)((x) => x.setIngestConnectionState);
|
|
21
|
+
const clearControlsTimeout = (0, player_store_1.usePlayerStore)((x) => x.clearControlsTimeout);
|
|
16
22
|
// Will call back every few seconds to send health updates
|
|
17
23
|
usePlayerStatus();
|
|
18
|
-
useEffect(() => {
|
|
24
|
+
(0, react_1.useEffect)(() => {
|
|
19
25
|
setIngest(props.ingest ? "new" : null);
|
|
20
26
|
}, []);
|
|
21
27
|
if (typeof props.src !== "string") {
|
|
22
|
-
return (
|
|
28
|
+
return ((0, jsx_runtime_1.jsx)(ui_1.View, { children: (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "No source provided \uD83E\uDD37" }) }));
|
|
23
29
|
}
|
|
24
|
-
useEffect(() => {
|
|
30
|
+
(0, react_1.useEffect)(() => {
|
|
25
31
|
return () => {
|
|
26
32
|
clearControlsTimeout();
|
|
27
33
|
};
|
|
28
34
|
}, []);
|
|
29
|
-
const segment = useSegment();
|
|
30
|
-
const [lastCheck, setLastCheck] = useState(0);
|
|
31
|
-
useEffect(() => {
|
|
35
|
+
const segment = (0, livestream_store_1.useSegment)();
|
|
36
|
+
const [lastCheck, setLastCheck] = (0, react_1.useState)(0);
|
|
37
|
+
(0, react_1.useEffect)(() => {
|
|
32
38
|
if (playing) {
|
|
33
39
|
setOffline(false);
|
|
34
40
|
return;
|
|
@@ -52,17 +58,17 @@ export function Player(props) {
|
|
|
52
58
|
}, 1000);
|
|
53
59
|
return () => clearTimeout(handle);
|
|
54
60
|
}, [segment, playing, lastCheck]);
|
|
55
|
-
return (
|
|
61
|
+
return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsx)(ui_1.View, { style: [atoms_1.zIndex[0], atoms_1.flex.values[1], atoms_1.w.percent[100], atoms_1.layout.flex.center], children: (0, jsx_runtime_1.jsx)(fullscreen_1.Fullscreen, { src: props.src }) }) }));
|
|
56
62
|
}
|
|
57
63
|
const POLL_INTERVAL = 5000;
|
|
58
|
-
|
|
59
|
-
const playerStatus = usePlayerStore((x) => x.status);
|
|
60
|
-
const url = useStreamplaceStore((x) => x.url);
|
|
61
|
-
const playerEvent = usePlayerStore((x) => x.playerEvent);
|
|
62
|
-
const [whatDoing, setWhatDoing] = useState(PlayerStatus.START);
|
|
63
|
-
const [whatDid, setWhatDid] = useState({});
|
|
64
|
-
const [doingSince, setDoingSince] = useState(Date.now());
|
|
65
|
-
const [lastUpdated, setLastUpdated] = useState(0);
|
|
64
|
+
function usePlayerStatus() {
|
|
65
|
+
const playerStatus = (0, player_store_1.usePlayerStore)((x) => x.status);
|
|
66
|
+
const url = (0, streamplace_store_1.useStreamplaceStore)((x) => x.url);
|
|
67
|
+
const playerEvent = (0, player_store_1.usePlayerStore)((x) => x.playerEvent);
|
|
68
|
+
const [whatDoing, setWhatDoing] = (0, react_1.useState)(player_store_1.PlayerStatus.START);
|
|
69
|
+
const [whatDid, setWhatDid] = (0, react_1.useState)({});
|
|
70
|
+
const [doingSince, setDoingSince] = (0, react_1.useState)(Date.now());
|
|
71
|
+
const [lastUpdated, setLastUpdated] = (0, react_1.useState)(0);
|
|
66
72
|
const updateWhatDid = (now) => {
|
|
67
73
|
const prev = whatDid[whatDoing] ?? 0;
|
|
68
74
|
const duration = now.getTime() - doingSince;
|
|
@@ -73,7 +79,7 @@ export function usePlayerStatus() {
|
|
|
73
79
|
return ret;
|
|
74
80
|
};
|
|
75
81
|
// callback to update the status
|
|
76
|
-
useEffect(() => {
|
|
82
|
+
(0, react_1.useEffect)(() => {
|
|
77
83
|
const now = new Date();
|
|
78
84
|
if (playerStatus !== whatDoing) {
|
|
79
85
|
setWhatDid(updateWhatDid(now));
|
|
@@ -81,7 +87,7 @@ export function usePlayerStatus() {
|
|
|
81
87
|
setDoingSince(now.getTime());
|
|
82
88
|
}
|
|
83
89
|
}, [playerStatus]);
|
|
84
|
-
useEffect(() => {
|
|
90
|
+
(0, react_1.useEffect)(() => {
|
|
85
91
|
if (lastUpdated === 0) {
|
|
86
92
|
return;
|
|
87
93
|
}
|
|
@@ -93,7 +99,7 @@ export function usePlayerStatus() {
|
|
|
93
99
|
whatHappened: fullWhatDid,
|
|
94
100
|
});
|
|
95
101
|
}, [lastUpdated]);
|
|
96
|
-
useEffect(() => {
|
|
102
|
+
(0, react_1.useEffect)(() => {
|
|
97
103
|
const interval = setInterval((_) => {
|
|
98
104
|
setLastUpdated(Date.now());
|
|
99
105
|
}, POLL_INTERVAL);
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.srcToUrl = srcToUrl;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const __1 = require("../..");
|
|
3
6
|
const protocolSuffixes = {
|
|
4
|
-
m3u8: PlayerProtocol.HLS,
|
|
5
|
-
mp4: PlayerProtocol.PROGRESSIVE_MP4,
|
|
6
|
-
webm: PlayerProtocol.PROGRESSIVE_WEBM,
|
|
7
|
-
webrtc: PlayerProtocol.WEBRTC,
|
|
7
|
+
m3u8: __1.PlayerProtocol.HLS,
|
|
8
|
+
mp4: __1.PlayerProtocol.PROGRESSIVE_MP4,
|
|
9
|
+
webm: __1.PlayerProtocol.PROGRESSIVE_WEBM,
|
|
10
|
+
webrtc: __1.PlayerProtocol.WEBRTC,
|
|
8
11
|
};
|
|
9
|
-
|
|
10
|
-
const url = useStreamplaceStore((x) => x.url);
|
|
11
|
-
return useMemo(() => {
|
|
12
|
+
function srcToUrl(props, protocol) {
|
|
13
|
+
const url = (0, __1.useStreamplaceStore)((x) => x.url);
|
|
14
|
+
return (0, react_1.useMemo)(() => {
|
|
12
15
|
if (props.src.startsWith("http://") || props.src.startsWith("https://")) {
|
|
13
16
|
const segments = props.src.split(/[./]/);
|
|
14
17
|
const suffix = segments[segments.length - 1];
|
|
@@ -23,7 +26,7 @@ export function srcToUrl(props, protocol) {
|
|
|
23
26
|
}
|
|
24
27
|
}
|
|
25
28
|
let outUrl;
|
|
26
|
-
if (protocol === PlayerProtocol.HLS) {
|
|
29
|
+
if (protocol === __1.PlayerProtocol.HLS) {
|
|
27
30
|
if (props.selectedRendition === "auto") {
|
|
28
31
|
outUrl = `${url}/api/playback/${props.src}/hls/index.m3u8`;
|
|
29
32
|
}
|
|
@@ -31,13 +34,13 @@ export function srcToUrl(props, protocol) {
|
|
|
31
34
|
outUrl = `${url}/api/playback/${props.src}/hls/index.m3u8?rendition=${props.selectedRendition || "source"}`;
|
|
32
35
|
}
|
|
33
36
|
}
|
|
34
|
-
else if (protocol === PlayerProtocol.PROGRESSIVE_MP4) {
|
|
37
|
+
else if (protocol === __1.PlayerProtocol.PROGRESSIVE_MP4) {
|
|
35
38
|
outUrl = `${url}/api/playback/${props.src}/stream.mp4`;
|
|
36
39
|
}
|
|
37
|
-
else if (protocol === PlayerProtocol.PROGRESSIVE_WEBM) {
|
|
40
|
+
else if (protocol === __1.PlayerProtocol.PROGRESSIVE_WEBM) {
|
|
38
41
|
outUrl = `${url}/api/playback/${props.src}/stream.webm`;
|
|
39
42
|
}
|
|
40
|
-
else if (protocol === PlayerProtocol.WEBRTC) {
|
|
43
|
+
else if (protocol === __1.PlayerProtocol.WEBRTC) {
|
|
41
44
|
outUrl = `${url}/api/playback/${props.src}/webrtc?rendition=${props.selectedRendition || "source"}`;
|
|
42
45
|
}
|
|
43
46
|
else {
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CountdownOverlay = CountdownOverlay;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
const react_1 = require("react");
|
|
7
|
+
const react_native_reanimated_1 = tslib_1.__importStar(require("react-native-reanimated"));
|
|
8
|
+
function CountdownOverlay({ visible, width, height, startFrom = 3, onDone, }) {
|
|
9
|
+
const [countdown, setCountdown] = (0, react_1.useState)(startFrom);
|
|
10
|
+
const startTimestamp = (0, react_native_reanimated_1.useSharedValue)(null);
|
|
11
|
+
const done = (0, react_native_reanimated_1.useSharedValue)(false);
|
|
8
12
|
// Animation values
|
|
9
|
-
const scale = useSharedValue(1);
|
|
10
|
-
const opacity = useSharedValue(1);
|
|
13
|
+
const scale = (0, react_native_reanimated_1.useSharedValue)(1);
|
|
14
|
+
const opacity = (0, react_native_reanimated_1.useSharedValue)(1);
|
|
11
15
|
const updateCountdown = (value) => {
|
|
12
16
|
setCountdown(value);
|
|
13
17
|
};
|
|
@@ -16,7 +20,7 @@ export function CountdownOverlay({ visible, width, height, startFrom = 3, onDone
|
|
|
16
20
|
onDone();
|
|
17
21
|
};
|
|
18
22
|
// Accurate countdown using useFrameCallback
|
|
19
|
-
useFrameCallback(({ timestamp }) => {
|
|
23
|
+
(0, react_native_reanimated_1.useFrameCallback)(({ timestamp }) => {
|
|
20
24
|
if (!visible)
|
|
21
25
|
return;
|
|
22
26
|
// Set start timestamp on first frame
|
|
@@ -27,13 +31,13 @@ export function CountdownOverlay({ visible, width, height, startFrom = 3, onDone
|
|
|
27
31
|
const elapsed = (timestamp - startTimestamp.value) / 1000; // Convert to seconds
|
|
28
32
|
const remaining = Math.max(0, startFrom - Math.floor(elapsed));
|
|
29
33
|
// Use runOnJS to call JavaScript functions from worklet
|
|
30
|
-
runOnJS(updateCountdown)(remaining);
|
|
34
|
+
(0, react_native_reanimated_1.runOnJS)(updateCountdown)(remaining);
|
|
31
35
|
if (remaining === 0 && !done.value) {
|
|
32
36
|
done.value = true;
|
|
33
|
-
runOnJS(handleDone)();
|
|
37
|
+
(0, react_native_reanimated_1.runOnJS)(handleDone)();
|
|
34
38
|
}
|
|
35
39
|
});
|
|
36
|
-
useEffect(() => {
|
|
40
|
+
(0, react_1.useEffect)(() => {
|
|
37
41
|
if (visible) {
|
|
38
42
|
startTimestamp.value = null; // Will be set on first frame
|
|
39
43
|
setCountdown(startFrom);
|
|
@@ -44,21 +48,21 @@ export function CountdownOverlay({ visible, width, height, startFrom = 3, onDone
|
|
|
44
48
|
}
|
|
45
49
|
}, [visible, startFrom]);
|
|
46
50
|
// Animate scale and opacity on countdown change
|
|
47
|
-
useEffect(() => {
|
|
51
|
+
(0, react_1.useEffect)(() => {
|
|
48
52
|
if (visible && countdown > 0) {
|
|
49
53
|
scale.value = 1;
|
|
50
54
|
opacity.value = 1;
|
|
51
|
-
scale.value = withTiming(1.5, { duration: 1000 });
|
|
52
|
-
opacity.value = withTiming(0, { duration: 1000 });
|
|
55
|
+
scale.value = (0, react_native_reanimated_1.withTiming)(1.5, { duration: 1000 });
|
|
56
|
+
opacity.value = (0, react_native_reanimated_1.withTiming)(0, { duration: 1000 });
|
|
53
57
|
}
|
|
54
58
|
}, [countdown, visible, scale, opacity]);
|
|
55
|
-
const animatedStyle = useAnimatedStyle(() => ({
|
|
59
|
+
const animatedStyle = (0, react_native_reanimated_1.useAnimatedStyle)(() => ({
|
|
56
60
|
transform: [{ scale: scale.value }],
|
|
57
61
|
opacity: opacity.value,
|
|
58
62
|
}));
|
|
59
63
|
if (!visible || countdown === 0)
|
|
60
64
|
return null;
|
|
61
|
-
return (
|
|
65
|
+
return ((0, jsx_runtime_1.jsx)(react_native_reanimated_1.default.View, { style: {
|
|
62
66
|
position: "absolute",
|
|
63
67
|
top: 0,
|
|
64
68
|
left: 0,
|
|
@@ -68,7 +72,7 @@ export function CountdownOverlay({ visible, width, height, startFrom = 3, onDone
|
|
|
68
72
|
alignItems: "center",
|
|
69
73
|
justifyContent: "center",
|
|
70
74
|
zIndex: 1000,
|
|
71
|
-
}, children:
|
|
75
|
+
}, children: (0, jsx_runtime_1.jsx)(react_native_reanimated_1.default.Text, { style: [
|
|
72
76
|
{
|
|
73
77
|
color: "white",
|
|
74
78
|
fontSize: 120,
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
tslib_1.__exportStar(require("./countdown"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./input"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./metrics"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./streamer-context-menu"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./viewer-context-menu"), exports);
|
|
9
|
+
tslib_1.__exportStar(require("./viewers"), exports);
|
|
@@ -1,24 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InputPanel = InputPanel;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
const react_native_1 = require("react-native");
|
|
7
|
+
const hooks_1 = require("../../../hooks");
|
|
8
|
+
const atoms = tslib_1.__importStar(require("../../../lib/theme/atoms"));
|
|
9
|
+
const ui_1 = require("../../ui");
|
|
6
10
|
const { gap, h, layout, mt, p, position, px, py, sizes, w } = atoms;
|
|
7
|
-
|
|
8
|
-
const { slideKeyboard } = useKeyboardSlide();
|
|
9
|
-
return (
|
|
11
|
+
function InputPanel({ title, setTitle, ingestStarting, toggleGoLive, }) {
|
|
12
|
+
const { slideKeyboard } = (0, hooks_1.useKeyboardSlide)();
|
|
13
|
+
return ((0, jsx_runtime_1.jsx)(ui_1.View, { style: [
|
|
10
14
|
layout.position.absolute,
|
|
11
15
|
h.percent[30],
|
|
12
16
|
position.bottom[0],
|
|
13
17
|
w.percent[100],
|
|
14
18
|
layout.flex.center,
|
|
15
19
|
{ transform: [{ translateY: slideKeyboard }] },
|
|
16
|
-
], children:
|
|
20
|
+
], children: (0, jsx_runtime_1.jsxs)(ui_1.View, { style: [
|
|
17
21
|
layout.flex.column,
|
|
18
22
|
gap.all[2],
|
|
19
23
|
sizes.maxWidth[80],
|
|
20
24
|
{ padding: 10 },
|
|
21
|
-
], children: [
|
|
25
|
+
], children: [(0, jsx_runtime_1.jsx)(ui_1.View, { backgroundColor: "rgba(64,64,64,0.8)", borderRadius: 12, children: (0, jsx_runtime_1.jsx)(ui_1.Input, { value: title, onChange: setTitle, placeholder: "Enter stream title", onEndEditing: react_native_1.Keyboard.dismiss }) }), ingestStarting ? ((0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Starting your stream..." })) : ((0, jsx_runtime_1.jsxs)(ui_1.View, { style: [layout.flex.center], children: [(0, jsx_runtime_1.jsxs)(react_native_1.Pressable, { onPress: toggleGoLive, style: [
|
|
22
26
|
px[4],
|
|
23
27
|
py[2],
|
|
24
28
|
layout.flex.row,
|
|
@@ -28,11 +32,11 @@ export function InputPanel({ title, setTitle, ingestStarting, toggleGoLive, }) {
|
|
|
28
32
|
backgroundColor: "rgba(64,64,64, 0.8)",
|
|
29
33
|
borderRadius: 12,
|
|
30
34
|
},
|
|
31
|
-
], children: [
|
|
35
|
+
], children: [(0, jsx_runtime_1.jsx)(ui_1.View, { style: [
|
|
32
36
|
p[2],
|
|
33
37
|
{
|
|
34
38
|
backgroundColor: "rgba(256,0,0, 0.8)",
|
|
35
39
|
borderRadius: 12,
|
|
36
40
|
},
|
|
37
|
-
] }),
|
|
41
|
+
] }), (0, jsx_runtime_1.jsx)(ui_1.Text, { center: true, children: "Go Live" })] }), (0, jsx_runtime_1.jsx)(ui_1.Text, { color: "muted", size: "xs", style: [mt[2]], children: "We'll announce that you're live on Bluesky." })] }))] }) }));
|
|
38
42
|
}
|
|
@@ -1,40 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MetricsPanel = MetricsPanel;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
const lucide_react_native_1 = require("lucide-react-native");
|
|
7
|
+
const useSegmentTiming_1 = require("../../../hooks/useSegmentTiming");
|
|
8
|
+
const atoms = tslib_1.__importStar(require("../../../lib/theme/atoms"));
|
|
9
|
+
const ui_1 = require("../../ui");
|
|
10
|
+
function MetricsPanel({ showMetrics }) {
|
|
11
|
+
const { connectionQuality, segmentDeltas, mean, range } = (0, useSegmentTiming_1.useSegmentTiming)();
|
|
12
|
+
let icon = (0, jsx_runtime_1.jsx)(lucide_react_native_1.CircleX, { color: "#d44" });
|
|
9
13
|
let color = "#d44";
|
|
10
14
|
if (connectionQuality === "good") {
|
|
11
|
-
icon =
|
|
15
|
+
icon = (0, jsx_runtime_1.jsx)(lucide_react_native_1.CircleCheck, { color: "#4d4" });
|
|
12
16
|
color = "#4d4";
|
|
13
17
|
}
|
|
14
18
|
else if (connectionQuality === "degraded") {
|
|
15
|
-
icon =
|
|
19
|
+
icon = (0, jsx_runtime_1.jsx)(lucide_react_native_1.AlertCircle, { color: "#aa4" });
|
|
16
20
|
color = "#aa4";
|
|
17
21
|
}
|
|
18
22
|
else {
|
|
19
|
-
icon =
|
|
23
|
+
icon = (0, jsx_runtime_1.jsx)(lucide_react_native_1.CircleX, { color: "#d44" });
|
|
20
24
|
color = "#d44";
|
|
21
25
|
}
|
|
22
|
-
return (
|
|
26
|
+
return ((0, jsx_runtime_1.jsxs)(ui_1.View, { style: {
|
|
23
27
|
alignItems: "center",
|
|
24
28
|
gap: 8,
|
|
25
|
-
}, children: [
|
|
29
|
+
}, children: [(0, jsx_runtime_1.jsxs)(ui_1.View, { style: {
|
|
26
30
|
flexDirection: "row",
|
|
27
31
|
alignItems: "center",
|
|
28
32
|
padding: 10,
|
|
29
33
|
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
30
34
|
borderRadius: 8,
|
|
31
35
|
gap: 4,
|
|
32
|
-
}, children: [icon,
|
|
36
|
+
}, children: [icon, (0, jsx_runtime_1.jsx)(ui_1.Text, { style: [
|
|
33
37
|
atoms.pt[0],
|
|
34
38
|
{
|
|
35
39
|
color,
|
|
36
40
|
},
|
|
37
|
-
], children: connectionQuality.toUpperCase() })] }), showMetrics && (
|
|
41
|
+
], children: connectionQuality.toUpperCase() })] }), showMetrics && ((0, jsx_runtime_1.jsxs)(ui_1.View, { children: [(0, jsx_runtime_1.jsxs)(ui_1.Text, { children: ["last \u0394:", " ", segmentDeltas.length > 0
|
|
38
42
|
? segmentDeltas[segmentDeltas.length - 1]
|
|
39
|
-
: "—"] }),
|
|
43
|
+
: "—"] }), (0, jsx_runtime_1.jsxs)(ui_1.Text, { children: ["mean: ", mean] }), (0, jsx_runtime_1.jsxs)(ui_1.Text, { children: ["range: ", range] })] }))] }));
|
|
40
44
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StreamContextMenu = StreamContextMenu;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
function StreamContextMenu() {
|
|
6
|
+
return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {});
|
|
4
7
|
}
|
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ContextMenu = ContextMenu;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const lucide_react_native_1 = require("lucide-react-native");
|
|
6
|
+
const theme_1 = require("../../../lib/theme");
|
|
7
|
+
const livestream_store_1 = require("../../../livestream-store");
|
|
8
|
+
const player_store_1 = require("../../../player-store/");
|
|
9
|
+
const ui_1 = require("../../ui");
|
|
10
|
+
function ContextMenu() {
|
|
11
|
+
const quality = (0, player_store_1.usePlayerStore)((x) => x.selectedRendition);
|
|
12
|
+
const setQuality = (0, player_store_1.usePlayerStore)((x) => x.setSelectedRendition);
|
|
13
|
+
const qualities = (0, livestream_store_1.useLivestreamStore)((x) => x.renditions);
|
|
14
|
+
const protocol = (0, player_store_1.usePlayerStore)((x) => x.protocol);
|
|
15
|
+
const setProtocol = (0, player_store_1.usePlayerStore)((x) => x.setProtocol);
|
|
16
|
+
const debugInfo = (0, player_store_1.usePlayerStore)((x) => x.showDebugInfo);
|
|
17
|
+
const setShowDebugInfo = (0, player_store_1.usePlayerStore)((x) => x.setShowDebugInfo);
|
|
15
18
|
const lowLatency = protocol === "webrtc";
|
|
16
19
|
const setLowLatency = (value) => {
|
|
17
|
-
setProtocol(value ? PlayerProtocol.WEBRTC : PlayerProtocol.HLS);
|
|
20
|
+
setProtocol(value ? player_store_1.PlayerProtocol.WEBRTC : player_store_1.PlayerProtocol.HLS);
|
|
18
21
|
};
|
|
19
|
-
return (
|
|
22
|
+
return ((0, jsx_runtime_1.jsxs)(ui_1.DropdownMenu, { children: [(0, jsx_runtime_1.jsx)(ui_1.DropdownMenuTrigger, { children: (0, jsx_runtime_1.jsx)(lucide_react_native_1.Menu, { size: 32, color: theme_1.colors.gray[200] }) }), (0, jsx_runtime_1.jsxs)(ui_1.ResponsiveDropdownMenuContent, { children: [(0, jsx_runtime_1.jsx)(ui_1.DropdownMenuGroup, { title: "Resolution", children: (0, jsx_runtime_1.jsxs)(ui_1.DropdownMenuRadioGroup, { value: quality, onValueChange: setQuality, children: [(0, jsx_runtime_1.jsx)(ui_1.DropdownMenuRadioItem, { value: "source", children: (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Source (Original Quality)" }) }), qualities.map((r) => ((0, jsx_runtime_1.jsx)(ui_1.DropdownMenuRadioItem, { value: r.name, children: (0, jsx_runtime_1.jsx)(ui_1.Text, { children: r.name }) })))] }) }), (0, jsx_runtime_1.jsx)(ui_1.DropdownMenuGroup, { title: "Advanced", children: (0, jsx_runtime_1.jsx)(ui_1.DropdownMenuCheckboxItem, { checked: lowLatency, onCheckedChange: () => setLowLatency(!lowLatency), children: (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Low Latency" }) }) }), (0, jsx_runtime_1.jsx)(ui_1.DropdownMenuInfo, { description: "Reduces the delay between video and chat for a more real-time experience." }), (0, jsx_runtime_1.jsx)(ui_1.DropdownMenuGroup, { children: (0, jsx_runtime_1.jsx)(ui_1.DropdownMenuCheckboxItem, { checked: debugInfo, onCheckedChange: () => setShowDebugInfo(!debugInfo), children: (0, jsx_runtime_1.jsx)(ui_1.Text, { children: "Show Debug Info" }) }) })] })] }));
|
|
20
23
|
}
|