kasunk99-livestream-core 0.2.3 → 0.2.5
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/LiveStreamFeed.d.ts +3 -1
- package/dist/components/LiveStreamFeed.d.ts.map +1 -1
- package/dist/components/LiveStreamFeed.js +26 -24
- package/dist/components/LiveStreamViewerItem.js +5 -5
- package/dist/hooks/useViewerSocket.d.ts +2 -0
- package/dist/hooks/useViewerSocket.d.ts.map +1 -1
- package/dist/hooks/useViewerSocket.js +11 -1
- package/dist/services/livestream.service.d.ts.map +1 -1
- package/dist/services/livestream.service.js +6 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
/**
|
|
3
3
|
* TikTok-style vertical feed: one stream per full-screen item.
|
|
4
|
-
*
|
|
4
|
+
* Height is measured from the actual container so it fills exactly to the
|
|
5
|
+
* navigation bar on every device — no hardcoded offsets.
|
|
6
|
+
* Scrolling snaps per-item (next/previous stream only).
|
|
5
7
|
*/
|
|
6
8
|
export declare function LiveStreamFeed(): React.ReactElement;
|
|
7
9
|
//# sourceMappingURL=LiveStreamFeed.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveStreamFeed.d.ts","sourceRoot":"","sources":["../../src/components/LiveStreamFeed.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAwC,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"LiveStreamFeed.d.ts","sourceRoot":"","sources":["../../src/components/LiveStreamFeed.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAwC,MAAM,OAAO,CAAC;AAiB7D;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,KAAK,CAAC,YAAY,CAgInD"}
|
|
@@ -3,17 +3,23 @@ import { useCallback, useRef, useState } from 'react';
|
|
|
3
3
|
import { Dimensions, FlatList, RefreshControl, ScrollView, StyleSheet, Text, View, } from 'react-native';
|
|
4
4
|
import { LiveStreamViewerItem } from './LiveStreamViewerItem';
|
|
5
5
|
import { useLiveStreams } from '../hooks/useLiveStreams';
|
|
6
|
-
const { height: SCREEN_HEIGHT } = Dimensions.get('window');
|
|
7
|
-
// Adjust for top header + bottom tab bar so each item fits without extra scroll.
|
|
8
|
-
const VIEWPORT_HEIGHT = SCREEN_HEIGHT - 120;
|
|
9
6
|
/**
|
|
10
7
|
* TikTok-style vertical feed: one stream per full-screen item.
|
|
11
|
-
*
|
|
8
|
+
* Height is measured from the actual container so it fills exactly to the
|
|
9
|
+
* navigation bar on every device — no hardcoded offsets.
|
|
10
|
+
* Scrolling snaps per-item (next/previous stream only).
|
|
12
11
|
*/
|
|
13
12
|
export function LiveStreamFeed() {
|
|
14
13
|
const { streams, loading, error, refetch } = useLiveStreams();
|
|
15
14
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
16
15
|
const [refreshing, setRefreshing] = useState(false);
|
|
16
|
+
// Initialise with a rough estimate so the first render isn't empty;
|
|
17
|
+
// corrected to the exact value after the container lays out.
|
|
18
|
+
const [viewportHeight, setViewportHeight] = useState(() => Dimensions.get('window').height - 120);
|
|
19
|
+
const onContainerLayout = useCallback((e) => {
|
|
20
|
+
const h = Math.round(e.nativeEvent.layout.height);
|
|
21
|
+
setViewportHeight((prev) => (prev === h ? prev : h));
|
|
22
|
+
}, []);
|
|
17
23
|
const onRefresh = useCallback(async () => {
|
|
18
24
|
setRefreshing(true);
|
|
19
25
|
await refetch();
|
|
@@ -25,46 +31,42 @@ export function LiveStreamFeed() {
|
|
|
25
31
|
}).current;
|
|
26
32
|
const onViewableItemsChanged = useRef(({ viewableItems }) => {
|
|
27
33
|
const first = viewableItems[0];
|
|
28
|
-
if (first?.index != null)
|
|
34
|
+
if (first?.index != null)
|
|
29
35
|
setActiveIndex(first.index);
|
|
30
|
-
}
|
|
31
36
|
}).current;
|
|
32
37
|
const onMomentumScrollEnd = useCallback((e) => {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}, [streams.length]);
|
|
38
|
-
const renderItem = useCallback(({ item, index }) => (_jsx(View, { style: styles.item, children: _jsx(LiveStreamViewerItem, { stream: item, isActive: index === activeIndex, index: index }) })), [activeIndex]);
|
|
38
|
+
const index = Math.round(e.nativeEvent.contentOffset.y / viewportHeight);
|
|
39
|
+
setActiveIndex(Math.max(0, Math.min(index, streams.length - 1)));
|
|
40
|
+
}, [streams.length, viewportHeight]);
|
|
41
|
+
const renderItem = useCallback(({ item, index }) => (_jsx(View, { style: { height: viewportHeight, width: '100%' }, children: _jsx(LiveStreamViewerItem, { stream: item, isActive: index === activeIndex, index: index }) })), [activeIndex, viewportHeight]);
|
|
39
42
|
const keyExtractor = useCallback((item) => item.roomId, []);
|
|
40
43
|
const getItemLayout = useCallback((_, index) => ({
|
|
41
|
-
length:
|
|
42
|
-
offset:
|
|
44
|
+
length: viewportHeight,
|
|
45
|
+
offset: viewportHeight * index,
|
|
43
46
|
index,
|
|
44
|
-
}), []);
|
|
47
|
+
}), [viewportHeight]);
|
|
45
48
|
if (loading && streams.length === 0) {
|
|
46
|
-
return (_jsx(View, { style: styles.center, children: _jsx(Text, { style: styles.message, children: "Loading streams..." }) }));
|
|
49
|
+
return (_jsx(View, { style: styles.flex, onLayout: onContainerLayout, children: _jsx(View, { style: [styles.center, { height: viewportHeight }], children: _jsx(Text, { style: styles.message, children: "Loading streams..." }) }) }));
|
|
47
50
|
}
|
|
48
51
|
if (error && streams.length === 0) {
|
|
49
|
-
return (_jsxs(ScrollView, { contentContainerStyle: styles.center, refreshControl: _jsx(RefreshControl, { refreshing: refreshing, onRefresh: onRefresh, tintColor: "#e5e5e5" }), children: [_jsx(Text, { style: styles.error, children: error }), _jsx(Text, { style: styles.hint, children: "Check server URL and pull down to retry." })] }));
|
|
52
|
+
return (_jsx(View, { style: styles.flex, onLayout: onContainerLayout, children: _jsxs(ScrollView, { contentContainerStyle: [styles.center, { minHeight: viewportHeight }], refreshControl: _jsx(RefreshControl, { refreshing: refreshing, onRefresh: onRefresh, tintColor: "#e5e5e5" }), children: [_jsx(Text, { style: styles.error, children: error }), _jsx(Text, { style: styles.hint, children: "Check server URL and pull down to retry." })] }) }));
|
|
50
53
|
}
|
|
51
54
|
if (streams.length === 0) {
|
|
52
|
-
return (_jsxs(ScrollView, { contentContainerStyle: styles.center, refreshControl: _jsx(RefreshControl, { refreshing: refreshing, onRefresh: onRefresh, tintColor: "#e5e5e5" }), children: [_jsx(Text, { style: styles.message, children: "No live streams right now" }), _jsx(Text, { style: styles.hint, children: "Go live or pull down to refresh." })] }));
|
|
55
|
+
return (_jsx(View, { style: styles.flex, onLayout: onContainerLayout, children: _jsxs(ScrollView, { contentContainerStyle: [styles.center, { minHeight: viewportHeight }], refreshControl: _jsx(RefreshControl, { refreshing: refreshing, onRefresh: onRefresh, tintColor: "#e5e5e5" }), children: [_jsx(Text, { style: styles.message, children: "No live streams right now" }), _jsx(Text, { style: styles.hint, children: "Go live or pull down to refresh." })] }) }));
|
|
53
56
|
}
|
|
54
|
-
return (_jsx(FlatList, { data: streams, renderItem: renderItem, keyExtractor: keyExtractor, getItemLayout: getItemLayout, pagingEnabled: true,
|
|
57
|
+
return (_jsx(View, { style: styles.flex, onLayout: onContainerLayout, children: _jsx(FlatList, { data: streams, renderItem: renderItem, keyExtractor: keyExtractor, getItemLayout: getItemLayout, pagingEnabled: true, showsVerticalScrollIndicator: false, decelerationRate: "fast", snapToInterval: viewportHeight, snapToAlignment: "start", onViewableItemsChanged: onViewableItemsChanged, viewabilityConfig: viewabilityConfig, onMomentumScrollEnd: onMomentumScrollEnd, initialNumToRender: 2, maxToRenderPerBatch: 2, windowSize: 3, refreshControl: _jsx(RefreshControl, { refreshing: refreshing, onRefresh: onRefresh, tintColor: "#e5e5e5" }) }) }));
|
|
55
58
|
}
|
|
56
59
|
const styles = StyleSheet.create({
|
|
57
|
-
|
|
60
|
+
flex: {
|
|
58
61
|
flex: 1,
|
|
62
|
+
backgroundColor: '#0a0a0a',
|
|
63
|
+
},
|
|
64
|
+
center: {
|
|
59
65
|
justifyContent: 'center',
|
|
60
66
|
alignItems: 'center',
|
|
61
67
|
backgroundColor: '#0a0a0a',
|
|
62
68
|
padding: 24,
|
|
63
69
|
},
|
|
64
|
-
item: {
|
|
65
|
-
height: VIEWPORT_HEIGHT,
|
|
66
|
-
width: '100%',
|
|
67
|
-
},
|
|
68
70
|
message: {
|
|
69
71
|
color: '#e5e5e5',
|
|
70
72
|
fontSize: 16,
|
|
@@ -17,10 +17,10 @@ catch {
|
|
|
17
17
|
*/
|
|
18
18
|
export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream, isActive, index, }) {
|
|
19
19
|
const roomId = isActive ? stream.roomId : null;
|
|
20
|
-
const { joined, joining, error, producerList, roomState, remoteStream, remoteVideoStream, webrtcUnavailable, consumeError, socket, } = useViewerSocket(roomId);
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
const { joined, joining, error, producerList, roomState, remoteStream, remoteVideoStream, webrtcUnavailable, consumeError, socket, viewerCount: liveViewerCount, } = useViewerSocket(roomId);
|
|
21
|
+
// Prefer real-time socket count (updated on every join/leave event);
|
|
22
|
+
// fall back to the HTTP-polled value from the feed for the initial render.
|
|
23
|
+
const viewerCount = liveViewerCount > 0 ? liveViewerCount : stream.viewerCount;
|
|
24
24
|
const hasVideo = producerList.some((p) => p.kind === 'video');
|
|
25
25
|
const streamObj = remoteStream;
|
|
26
26
|
const hasVideoTrack = streamObj &&
|
|
@@ -147,7 +147,7 @@ export const LiveStreamViewerItem = memo(function LiveStreamViewerItem({ stream,
|
|
|
147
147
|
}
|
|
148
148
|
});
|
|
149
149
|
};
|
|
150
|
-
return (_jsxs(View, { style: styles.container, children: [showVideo && RTCViewComponent && streamURL ? (_jsx(RTCViewComponent, { streamURL: streamURL, stream: displayStream, style: styles.rtcView, objectFit: "
|
|
150
|
+
return (_jsxs(View, { style: styles.container, children: [showVideo && RTCViewComponent && streamURL ? (_jsx(RTCViewComponent, { streamURL: streamURL, stream: displayStream, style: styles.rtcView, objectFit: "contain", mirror: false }, `rtc-${trackCount}-${streamURL}`)) : (_jsxs(View, { style: styles.videoPlaceholder, children: [joining && _jsx(Text, { style: styles.placeholderText, children: "Joining..." }), error && _jsx(Text, { style: [styles.placeholderText, styles.errorText], children: error }), joined && !joining && !error && (_jsxs(_Fragment, { children: [_jsx(Text, { style: styles.liveBadge, children: "LIVE" }), _jsx(Text, { style: styles.placeholderText, children: stream.roomId }), hasVideo && webrtcUnavailable && (_jsxs(Text, { style: [styles.hintText, styles.warnText], children: ["Video needs a development build.", '\n', "Run: npx expo run:android"] })), hasVideo && consumeError && (_jsx(Text, { style: [styles.hintText, styles.errorText], children: consumeError })), hasVideo && !remoteStream && !webrtcUnavailable && !consumeError && (_jsx(Text, { style: styles.hintText, children: "Loading video..." })), !hasVideo && joined && producerList.length === 0 && (_jsxs(Text, { style: [styles.hintText, styles.warnText], children: ["Host has not started camera yet.", '\n', "Use a web client to stream, or wait for host to produce."] })), hasVideo && remoteStream && !RTCViewComponent && (_jsx(Text, { style: styles.hintText, children: "Video received (use dev build to see it)" })), hasVideo && remoteStream && RTCViewComponent && !hasVideoTrack && (_jsx(Text, { style: [styles.hintText, styles.warnText], children: "Audio only (no video track yet)" })), hasVideo && remoteStream && hasVideoTrack && !streamURL && (_jsx(Text, { style: [styles.hintText, styles.warnText], children: "Video track received but cannot display (need dev build with react-native-webrtc)" }))] }))] })), _jsxs(View, { style: styles.overlay, children: [_jsxs(View, { style: styles.topMeta, children: [_jsx(View, { style: styles.row, children: _jsxs(Text, { style: styles.roomId, numberOfLines: 1, children: ["LIVE \u00B7 ", stream.hostDisplayName || stream.title || stream.roomId] }) }), _jsxs(View, { style: styles.stats, children: [_jsxs(Text, { style: styles.statsText, children: ["\uD83D\uDC41 ", viewerCount] }), _jsxs(Text, { style: [styles.statsText, styles.statsTextSpacer], children: ["\u00B7 ", stream.producerCount, " track(s)"] })] })] }), _jsx(View, { style: styles.chatPanel, pointerEvents: "box-none", children: _jsx(KeyboardAvoidingView, { style: styles.chatKeyboardAvoider, behavior: Platform.OS === 'ios' ? 'padding' : 'height', keyboardVerticalOffset: 0, children: _jsxs(View, { style: styles.chatStack, children: [_jsx(View, { style: styles.chatListWrapper, children: _jsx(ScrollView, { ref: chatListRef, contentContainerStyle: styles.chatListContent, showsVerticalScrollIndicator: false, keyboardDismissMode: "on-drag", keyboardShouldPersistTaps: "always", nestedScrollEnabled: true, children: chatData.map((item) => (_jsxs(Text, { style: styles.chatLine, numberOfLines: 2, children: [_jsx(Text, { style: [styles.chatName, { color: getNameColor(item.displayName) }], children: item.displayName }), _jsxs(Text, { style: styles.chatText, children: [" ", item.text] })] }, item.id))) }) }), _jsxs(View, { style: styles.chatInputRow, children: [_jsx(TextInput, { style: styles.chatInput, value: chatInput, onChangeText: setChatInput, placeholder: joined ? 'Say something...' : 'Connecting...', placeholderTextColor: "#9ca3af", editable: joined && !joining && !error, onSubmitEditing: sendChat, returnKeyType: "send" }), _jsx(TouchableOpacity, { onPress: sendChat, disabled: !joined || joining || !!error || !chatInput.trim(), style: [
|
|
151
151
|
styles.chatSendButton,
|
|
152
152
|
(!joined || joining || !!error || !chatInput.trim()) && styles.chatSendButtonDisabled,
|
|
153
153
|
], children: _jsx(Text, { style: styles.chatSendText, children: "\u27A4" }) })] })] }) }) })] })] }));
|
|
@@ -13,6 +13,8 @@ type ViewerSocketState = {
|
|
|
13
13
|
consumeError: string | null;
|
|
14
14
|
/** Incremented to trigger one auto-retry when recv transport fails (ICE). */
|
|
15
15
|
consumeRetryKey: number;
|
|
16
|
+
/** Real-time viewer count, updated via viewer-count-updated socket event. */
|
|
17
|
+
viewerCount: number;
|
|
16
18
|
};
|
|
17
19
|
/**
|
|
18
20
|
* Connects to the livestream signaling server and joins a room as viewer.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useViewerSocket.d.ts","sourceRoot":"","sources":["../../src/hooks/useViewerSocket.ts"],"names":[],"mappings":"AACA,OAAO,EAAM,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAInD,OAAO,KAAK,EAAkB,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7D,KAAK,iBAAiB,GAAG;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC1C,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7B,iBAAiB,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,6EAA6E;IAC7E,eAAe,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"useViewerSocket.d.ts","sourceRoot":"","sources":["../../src/hooks/useViewerSocket.ts"],"names":[],"mappings":"AACA,OAAO,EAAM,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAInD,OAAO,KAAK,EAAkB,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7D,KAAK,iBAAiB,GAAG;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC1C,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7B,iBAAiB,EAAE,OAAO,GAAG,IAAI,CAAC;IAClC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,6EAA6E;IAC7E,eAAe,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,iBAAiB,GAAG;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CA2dpG"}
|
|
@@ -20,6 +20,7 @@ export function useViewerSocket(roomId) {
|
|
|
20
20
|
webrtcUnavailable: false,
|
|
21
21
|
consumeError: null,
|
|
22
22
|
consumeRetryKey: 0,
|
|
23
|
+
viewerCount: 0,
|
|
23
24
|
});
|
|
24
25
|
const socketRef = useRef(null);
|
|
25
26
|
const roomIdRef = useRef(roomId);
|
|
@@ -61,6 +62,7 @@ export function useViewerSocket(roomId) {
|
|
|
61
62
|
webrtcUnavailable: false,
|
|
62
63
|
consumeError: null,
|
|
63
64
|
consumeRetryKey: 0,
|
|
65
|
+
viewerCount: 0,
|
|
64
66
|
});
|
|
65
67
|
consumeRetryCountRef.current = 0;
|
|
66
68
|
}, []);
|
|
@@ -156,14 +158,17 @@ export function useViewerSocket(roomId) {
|
|
|
156
158
|
if (Array.isArray(iceFromJoin) && iceFromJoin.length > 0) {
|
|
157
159
|
iceServersRef.current = iceFromJoin;
|
|
158
160
|
}
|
|
161
|
+
const roomState = res.roomState ?? null;
|
|
162
|
+
const initialViewerCount = typeof roomState?.viewerCount === 'number' ? roomState.viewerCount : 0;
|
|
159
163
|
setState((prev) => ({
|
|
160
164
|
...prev,
|
|
161
165
|
joining: false,
|
|
162
166
|
joined: true,
|
|
163
167
|
producerList: res.producerList ?? [],
|
|
164
|
-
roomState
|
|
168
|
+
roomState,
|
|
165
169
|
rtpCapabilities: res.rtpCapabilities ?? null,
|
|
166
170
|
error: null,
|
|
171
|
+
viewerCount: initialViewerCount,
|
|
167
172
|
}));
|
|
168
173
|
});
|
|
169
174
|
});
|
|
@@ -191,6 +196,11 @@ export function useViewerSocket(roomId) {
|
|
|
191
196
|
}
|
|
192
197
|
});
|
|
193
198
|
});
|
|
199
|
+
socket.on('viewer-count-updated', (payload) => {
|
|
200
|
+
if (typeof payload?.viewerCount === 'number') {
|
|
201
|
+
setState((prev) => ({ ...prev, viewerCount: payload.viewerCount }));
|
|
202
|
+
}
|
|
203
|
+
});
|
|
194
204
|
})();
|
|
195
205
|
return () => {
|
|
196
206
|
clearTimeout(joinTimeout);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"livestream.service.d.ts","sourceRoot":"","sources":["../../src/services/livestream.service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,MAAM,MAAM,kBAAkB,GAC1B;IAAE,OAAO,EAAE,cAAc,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,GAC5C;IAAE,OAAO,EAAE,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"livestream.service.d.ts","sourceRoot":"","sources":["../../src/services/livestream.service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,MAAM,MAAM,kBAAkB,GAC1B;IAAE,OAAO,EAAE,cAAc,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,GAC5C;IAAE,OAAO,EAAE,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAiBnC,MAAM,MAAM,qBAAqB,GAC7B;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,GAChC;IAAE,KAAK,CAAC,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAErC,MAAM,MAAM,kBAAkB,GAC1B;IAAE,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,GAC/F;IAAE,MAAM,CAAC,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CA+BtE;AAED,wBAAsB,YAAY,CAAC,MAAM,CAAC,EAAE;IAC1C,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAsC9B;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAyBjC;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAGD,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
|
|
@@ -8,7 +8,12 @@ function normalizeStreamRow(row) {
|
|
|
8
8
|
return null;
|
|
9
9
|
const viewerCount = typeof row?.viewerCount === 'number' ? row.viewerCount : typeof row?.viewer_count === 'number' ? row.viewer_count : 0;
|
|
10
10
|
const producerCount = typeof row?.producerCount === 'number' ? row.producerCount : typeof row?.producer_count === 'number' ? row.producer_count : 0;
|
|
11
|
-
|
|
11
|
+
const title = typeof row?.title === 'string' ? row.title : null;
|
|
12
|
+
const hostDisplayName = typeof row?.hostDisplayName === 'string' ? row.hostDisplayName :
|
|
13
|
+
typeof row?.host_display_name === 'string' ? row.host_display_name : null;
|
|
14
|
+
const hostUserId = typeof row?.hostUserId === 'string' ? row.hostUserId :
|
|
15
|
+
typeof row?.host_user_id === 'string' ? row.host_user_id : null;
|
|
16
|
+
return { roomId, viewerCount, producerCount, title, hostDisplayName, hostUserId };
|
|
12
17
|
}
|
|
13
18
|
export async function fetchActiveStreams() {
|
|
14
19
|
const base = getBaseUrl();
|
package/dist/types.d.ts
CHANGED
|
@@ -6,6 +6,9 @@ export type LiveStreamInfo = {
|
|
|
6
6
|
roomId: string;
|
|
7
7
|
viewerCount: number;
|
|
8
8
|
producerCount: number;
|
|
9
|
+
title?: string | null;
|
|
10
|
+
hostDisplayName?: string | null;
|
|
11
|
+
hostUserId?: string | null;
|
|
9
12
|
};
|
|
10
13
|
export type ProducerInfo = {
|
|
11
14
|
id: string;
|
|
@@ -27,6 +30,8 @@ export type RoomState = {
|
|
|
27
30
|
chat?: unknown[];
|
|
28
31
|
likes?: number;
|
|
29
32
|
viewerCount?: number;
|
|
33
|
+
cards?: unknown[];
|
|
34
|
+
shares?: number;
|
|
30
35
|
[key: string]: unknown;
|
|
31
36
|
};
|
|
32
37
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,YAAY,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC"}
|
package/package.json
CHANGED