@streamplace/components 0.7.14 → 0.7.15
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/package.json +13 -15
- package/src/components/mobile-player/fullscreen.native.tsx +14 -3
- package/src/components/mobile-player/fullscreen.tsx +10 -2
- package/src/components/mobile-player/player.tsx +7 -1
- package/src/components/mobile-player/props.tsx +2 -0
- package/src/components/mobile-player/video.native.tsx +28 -11
- package/src/components/mobile-player/video.tsx +14 -3
- package/src/hooks/useLivestreamInfo.ts +6 -2
- package/src/lib/browser.ts +27 -0
- package/src/livestream-store/stream-key.tsx +1 -28
- package/src/streamplace-store/stream.tsx +51 -13
- package/dist/assets/emoji-data.json +0 -19371
- package/dist/components/chat/chat-box.js +0 -314
- package/dist/components/chat/chat-message.js +0 -87
- package/dist/components/chat/chat.js +0 -149
- package/dist/components/chat/emoji-suggestions.js +0 -35
- package/dist/components/chat/mention-suggestions.js +0 -42
- package/dist/components/chat/mod-view.js +0 -94
- package/dist/components/chat/system-message.js +0 -19
- package/dist/components/dashboard/chat-panel.js +0 -38
- package/dist/components/dashboard/header.js +0 -80
- package/dist/components/dashboard/index.js +0 -14
- package/dist/components/dashboard/information-widget.js +0 -234
- package/dist/components/dashboard/mod-actions.js +0 -71
- package/dist/components/dashboard/problems.js +0 -74
- package/dist/components/icons/bluesky-icon.js +0 -9
- package/dist/components/keep-awake.js +0 -7
- package/dist/components/keep-awake.native.js +0 -16
- package/dist/components/mobile-player/fullscreen.js +0 -74
- package/dist/components/mobile-player/fullscreen.native.js +0 -141
- package/dist/components/mobile-player/player.js +0 -94
- package/dist/components/mobile-player/props.js +0 -2
- package/dist/components/mobile-player/shared.js +0 -54
- package/dist/components/mobile-player/ui/countdown.js +0 -83
- package/dist/components/mobile-player/ui/index.js +0 -11
- package/dist/components/mobile-player/ui/input.js +0 -42
- package/dist/components/mobile-player/ui/metrics.js +0 -44
- package/dist/components/mobile-player/ui/report-modal.js +0 -90
- package/dist/components/mobile-player/ui/streamer-context-menu.js +0 -7
- package/dist/components/mobile-player/ui/streamer-loading-overlay.js +0 -104
- package/dist/components/mobile-player/ui/viewer-context-menu.js +0 -51
- package/dist/components/mobile-player/ui/viewer-loading-overlay.js +0 -49
- package/dist/components/mobile-player/ui/viewers.js +0 -23
- package/dist/components/mobile-player/use-webrtc.js +0 -243
- package/dist/components/mobile-player/video-retry.js +0 -29
- package/dist/components/mobile-player/video.js +0 -460
- package/dist/components/mobile-player/video.native.js +0 -276
- package/dist/components/mobile-player/webrtc-diagnostics.js +0 -110
- package/dist/components/mobile-player/webrtc-primitives.js +0 -27
- package/dist/components/mobile-player/webrtc-primitives.native.js +0 -8
- package/dist/components/share/sharesheet.js +0 -91
- package/dist/components/ui/button.js +0 -223
- package/dist/components/ui/dialog.js +0 -206
- package/dist/components/ui/dropdown.js +0 -172
- package/dist/components/ui/icons.js +0 -25
- package/dist/components/ui/index.js +0 -34
- package/dist/components/ui/info-box.js +0 -31
- package/dist/components/ui/info-row.js +0 -23
- package/dist/components/ui/input.js +0 -205
- package/dist/components/ui/loader.js +0 -10
- package/dist/components/ui/primitives/button.js +0 -125
- package/dist/components/ui/primitives/input.js +0 -206
- package/dist/components/ui/primitives/modal.js +0 -206
- package/dist/components/ui/primitives/text.js +0 -292
- package/dist/components/ui/resizeable.js +0 -121
- package/dist/components/ui/slider.js +0 -5
- package/dist/components/ui/text.js +0 -177
- package/dist/components/ui/textarea.js +0 -19
- package/dist/components/ui/toast.js +0 -175
- package/dist/components/ui/view.js +0 -252
- package/dist/hooks/index.js +0 -14
- package/dist/hooks/useAvatars.js +0 -35
- package/dist/hooks/useCameraToggle.js +0 -12
- package/dist/hooks/useKeyboard.js +0 -36
- package/dist/hooks/useKeyboardSlide.js +0 -14
- package/dist/hooks/useLivestreamInfo.js +0 -65
- package/dist/hooks/useOuterAndInnerDimensions.js +0 -30
- package/dist/hooks/usePlayerDimensions.js +0 -22
- package/dist/hooks/usePointerDevice.js +0 -71
- package/dist/hooks/useSegmentDimensions.js +0 -17
- package/dist/hooks/useSegmentTiming.js +0 -65
- package/dist/index.js +0 -34
- package/dist/lib/facet.js +0 -92
- package/dist/lib/system-messages.js +0 -101
- package/dist/lib/theme/atoms.js +0 -646
- package/dist/lib/theme/atoms.types.js +0 -6
- package/dist/lib/theme/index.js +0 -35
- package/dist/lib/theme/theme.js +0 -256
- package/dist/lib/theme/tokens.js +0 -659
- package/dist/lib/utils.js +0 -105
- package/dist/livestream-provider/index.js +0 -30
- package/dist/livestream-provider/websocket.js +0 -45
- package/dist/livestream-store/chat.js +0 -286
- package/dist/livestream-store/context.js +0 -5
- package/dist/livestream-store/index.js +0 -7
- package/dist/livestream-store/livestream-state.js +0 -2
- package/dist/livestream-store/livestream-store.js +0 -58
- package/dist/livestream-store/problems.js +0 -76
- package/dist/livestream-store/stream-key.js +0 -119
- package/dist/livestream-store/websocket-consumer.js +0 -94
- package/dist/player-store/context.js +0 -5
- package/dist/player-store/index.js +0 -9
- package/dist/player-store/player-provider.js +0 -57
- package/dist/player-store/player-state.js +0 -25
- package/dist/player-store/player-store.js +0 -199
- package/dist/player-store/single-player-provider.js +0 -121
- package/dist/streamplace-provider/context.js +0 -5
- package/dist/streamplace-provider/index.js +0 -20
- package/dist/streamplace-provider/poller.js +0 -49
- package/dist/streamplace-provider/xrpc.js +0 -0
- package/dist/streamplace-store/block.js +0 -65
- package/dist/streamplace-store/index.js +0 -6
- package/dist/streamplace-store/stream.js +0 -218
- package/dist/streamplace-store/streamplace-store.js +0 -47
- package/dist/streamplace-store/user.js +0 -52
- package/dist/streamplace-store/xrpc.js +0 -15
- package/dist/ui/index.js +0 -79
- 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
- package/node-compile-cache/v22.15.0-x64-efe9a9df-0/67b1eb60 +0 -0
- package/node-compile-cache/v22.15.0-x64-efe9a9df-0/7c275f90 +0 -0
- package/tsconfig.tsbuildinfo +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@streamplace/components",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.15",
|
|
4
4
|
"description": "Streamplace React (Native) Components",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "src/index.tsx",
|
|
@@ -11,17 +11,11 @@
|
|
|
11
11
|
"default": "./dist/index.js"
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
|
-
"scripts": {
|
|
15
|
-
"build": "tsc",
|
|
16
|
-
"prepare": "pnpm run build",
|
|
17
|
-
"start": "tsc --watch --preserveWatchOutput"
|
|
18
|
-
},
|
|
19
14
|
"keywords": [
|
|
20
15
|
"streamplace"
|
|
21
16
|
],
|
|
22
17
|
"author": "Streamplace",
|
|
23
18
|
"license": "MIT",
|
|
24
|
-
"packageManager": "pnpm@10.11.0",
|
|
25
19
|
"devDependencies": {
|
|
26
20
|
"tsup": "^8.5.0"
|
|
27
21
|
},
|
|
@@ -34,16 +28,16 @@
|
|
|
34
28
|
"@rn-primitives/portal": "^1.3.0",
|
|
35
29
|
"@rn-primitives/slider": "^1.2.0",
|
|
36
30
|
"class-variance-authority": "^0.6.1",
|
|
37
|
-
"expo-keep-awake": "
|
|
38
|
-
"expo-video": "
|
|
31
|
+
"expo-keep-awake": "^14.0.0",
|
|
32
|
+
"expo-video": "^2.0.0",
|
|
39
33
|
"hls.js": "^1.5.17",
|
|
40
34
|
"lucide-react-native": "^0.514.0",
|
|
41
|
-
"react-native": "0.79.
|
|
35
|
+
"react-native": "^0.79.0",
|
|
42
36
|
"react-native-edge-to-edge": "^1.6.2",
|
|
43
|
-
"react-native-gesture-handler": "
|
|
44
|
-
"react-native-reanimated": "
|
|
45
|
-
"react-native-safe-area-context": "5.
|
|
46
|
-
"react-native-svg": "15.
|
|
37
|
+
"react-native-gesture-handler": "^2.20.0",
|
|
38
|
+
"react-native-reanimated": "^3.0.0",
|
|
39
|
+
"react-native-safe-area-context": "^5.0.0",
|
|
40
|
+
"react-native-svg": "^15.0.0",
|
|
47
41
|
"react-native-webrtc": "git+https://github.com/streamplace/react-native-webrtc.git#6b8472a771ac47f89217d327058a8a4124a6ae56",
|
|
48
42
|
"react-use-websocket": "^4.13.0",
|
|
49
43
|
"streamplace": "0.7.2",
|
|
@@ -53,5 +47,9 @@
|
|
|
53
47
|
"peerDependencies": {
|
|
54
48
|
"react": "*"
|
|
55
49
|
},
|
|
56
|
-
"
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsc",
|
|
52
|
+
"start": "tsc --watch --preserveWatchOutput"
|
|
53
|
+
},
|
|
54
|
+
"gitHead": "28aa086a00a3bf52bb21c5e50d139a879bcb6bc7"
|
|
57
55
|
}
|
|
@@ -14,7 +14,12 @@ import Video from "./video.native";
|
|
|
14
14
|
// Standard 16:9 video aspect ratio
|
|
15
15
|
const VIDEO_ASPECT_RATIO = 16 / 9;
|
|
16
16
|
|
|
17
|
-
export function Fullscreen(props: {
|
|
17
|
+
export function Fullscreen(props: {
|
|
18
|
+
src: string;
|
|
19
|
+
children?: React.ReactNode;
|
|
20
|
+
objectFit?: "contain" | "cover";
|
|
21
|
+
pictureInPictureEnabled?: boolean;
|
|
22
|
+
}) {
|
|
18
23
|
const ref = useRef<VideoView>(null);
|
|
19
24
|
const insets = useSafeAreaInsets();
|
|
20
25
|
const [dimensions, setDimensions] = useState(Dimensions.get("window"));
|
|
@@ -145,7 +150,10 @@ export function Fullscreen(props: { src: string; children?: React.ReactNode }) {
|
|
|
145
150
|
},
|
|
146
151
|
]}
|
|
147
152
|
>
|
|
148
|
-
<Video
|
|
153
|
+
<Video
|
|
154
|
+
objectFit={props.objectFit}
|
|
155
|
+
pictureInPictureEnabled={props.pictureInPictureEnabled}
|
|
156
|
+
/>
|
|
149
157
|
{props.children}
|
|
150
158
|
</View>
|
|
151
159
|
</View>
|
|
@@ -156,7 +164,10 @@ export function Fullscreen(props: { src: string; children?: React.ReactNode }) {
|
|
|
156
164
|
return (
|
|
157
165
|
<>
|
|
158
166
|
<VideoRetry>
|
|
159
|
-
<Video
|
|
167
|
+
<Video
|
|
168
|
+
objectFit={props.objectFit}
|
|
169
|
+
pictureInPictureEnabled={props.pictureInPictureEnabled}
|
|
170
|
+
/>
|
|
160
171
|
</VideoRetry>
|
|
161
172
|
{props.children}
|
|
162
173
|
</>
|
|
@@ -5,7 +5,12 @@ import { View } from "../../components/ui";
|
|
|
5
5
|
import Video from "./video";
|
|
6
6
|
import VideoRetry from "./video-retry";
|
|
7
7
|
|
|
8
|
-
export function Fullscreen(props: {
|
|
8
|
+
export function Fullscreen(props: {
|
|
9
|
+
src: string;
|
|
10
|
+
children?: React.ReactNode;
|
|
11
|
+
objectFit?: "contain" | "cover";
|
|
12
|
+
pictureInPictureEnabled?: boolean;
|
|
13
|
+
}) {
|
|
9
14
|
const playerId = getFirstPlayerID();
|
|
10
15
|
const protocol = usePlayerStore((x) => x.protocol, playerId);
|
|
11
16
|
const fullscreen = usePlayerStore((x) => x.fullscreen, playerId);
|
|
@@ -78,7 +83,10 @@ export function Fullscreen(props: { src: string; children?: React.ReactNode }) {
|
|
|
78
83
|
style={{ width: "100%", height: "100%", overflow: "hidden" }}
|
|
79
84
|
>
|
|
80
85
|
<VideoRetry>
|
|
81
|
-
<Video
|
|
86
|
+
<Video
|
|
87
|
+
objectFit={props.objectFit}
|
|
88
|
+
pictureInPictureEnabled={props.pictureInPictureEnabled}
|
|
89
|
+
/>
|
|
82
90
|
</VideoRetry>
|
|
83
91
|
{props.children}
|
|
84
92
|
</View>
|
|
@@ -69,7 +69,13 @@ export function Player(
|
|
|
69
69
|
onOpenChange={setReportModalOpen}
|
|
70
70
|
subject={reportSubject!}
|
|
71
71
|
/>
|
|
72
|
-
<Fullscreen
|
|
72
|
+
<Fullscreen
|
|
73
|
+
src={props.src}
|
|
74
|
+
objectFit={props.objectFit}
|
|
75
|
+
pictureInPictureEnabled={props.pictureInPictureEnabled}
|
|
76
|
+
>
|
|
77
|
+
{props.children}
|
|
78
|
+
</Fullscreen>
|
|
73
79
|
</View>
|
|
74
80
|
</>
|
|
75
81
|
);
|
|
@@ -34,24 +34,36 @@ import useWebRTC, { useWebRTCIngest } from "./use-webrtc";
|
|
|
34
34
|
import { mediaDevices, WebRTCMediaStream } from "./webrtc-primitives.native";
|
|
35
35
|
|
|
36
36
|
// Add NativeIngestPlayer to the switch below!
|
|
37
|
-
export default function VideoNative(
|
|
37
|
+
export default function VideoNative(props?: {
|
|
38
|
+
objectFit?: "contain" | "cover";
|
|
39
|
+
pictureInPictureEnabled?: boolean;
|
|
40
|
+
}) {
|
|
38
41
|
const protocol = usePlayerStore((x) => x.protocol);
|
|
39
42
|
const ingest = usePlayerStore((x) => x.ingestConnectionState) != null;
|
|
40
43
|
|
|
41
44
|
return (
|
|
42
45
|
<View>
|
|
43
46
|
{ingest ? (
|
|
44
|
-
<NativeIngestPlayer />
|
|
47
|
+
<NativeIngestPlayer objectFit={props?.objectFit} />
|
|
45
48
|
) : protocol === PlayerProtocol.WEBRTC ? (
|
|
46
|
-
<NativeWHEP
|
|
49
|
+
<NativeWHEP
|
|
50
|
+
objectFit={props?.objectFit}
|
|
51
|
+
pictureInPictureEnabled={props?.pictureInPictureEnabled}
|
|
52
|
+
/>
|
|
47
53
|
) : (
|
|
48
|
-
<NativeVideo
|
|
54
|
+
<NativeVideo
|
|
55
|
+
objectFit={props?.objectFit}
|
|
56
|
+
pictureInPictureEnabled={props?.pictureInPictureEnabled}
|
|
57
|
+
/>
|
|
49
58
|
)}
|
|
50
59
|
</View>
|
|
51
60
|
);
|
|
52
61
|
}
|
|
53
62
|
|
|
54
|
-
export function NativeVideo(
|
|
63
|
+
export function NativeVideo(props?: {
|
|
64
|
+
objectFit?: "contain" | "cover" | "fill" | "none" | "scale-down";
|
|
65
|
+
pictureInPictureEnabled?: boolean;
|
|
66
|
+
}) {
|
|
55
67
|
const videoRef = useRef<VideoView | null>(null);
|
|
56
68
|
const protocol = usePlayerStore((x) => x.protocol);
|
|
57
69
|
|
|
@@ -159,14 +171,17 @@ export function NativeVideo() {
|
|
|
159
171
|
onFullscreenExit={() => {
|
|
160
172
|
setFullscreen(false);
|
|
161
173
|
}}
|
|
162
|
-
allowsPictureInPicture
|
|
174
|
+
allowsPictureInPicture={props?.pictureInPictureEnabled !== false}
|
|
163
175
|
onLayout={handleLayout}
|
|
164
176
|
/>
|
|
165
177
|
</>
|
|
166
178
|
);
|
|
167
179
|
}
|
|
168
180
|
|
|
169
|
-
export function NativeWHEP(
|
|
181
|
+
export function NativeWHEP(props?: {
|
|
182
|
+
objectFit?: "contain" | "cover";
|
|
183
|
+
pictureInPictureEnabled?: boolean;
|
|
184
|
+
}) {
|
|
170
185
|
const selectedRendition = usePlayerStore((x) => x.selectedRendition);
|
|
171
186
|
const src = usePlayerStore((x) => x.src);
|
|
172
187
|
const { url } = srcToUrl(
|
|
@@ -246,10 +261,10 @@ export function NativeWHEP() {
|
|
|
246
261
|
<>
|
|
247
262
|
<RTCView
|
|
248
263
|
mirror={false}
|
|
249
|
-
objectFit={"contain"}
|
|
264
|
+
objectFit={props?.objectFit || "contain"}
|
|
250
265
|
streamURL={mediaStream.toURL()}
|
|
251
266
|
onLayout={handleLayout}
|
|
252
|
-
pictureInPictureEnabled={
|
|
267
|
+
pictureInPictureEnabled={props?.pictureInPictureEnabled !== false}
|
|
253
268
|
autoStartPictureInPicture={true}
|
|
254
269
|
pictureInPicturePreferredSize={{
|
|
255
270
|
width: 160,
|
|
@@ -265,7 +280,9 @@ export function NativeWHEP() {
|
|
|
265
280
|
);
|
|
266
281
|
}
|
|
267
282
|
|
|
268
|
-
export function NativeIngestPlayer(
|
|
283
|
+
export function NativeIngestPlayer(props?: {
|
|
284
|
+
objectFit?: "contain" | "cover";
|
|
285
|
+
}) {
|
|
269
286
|
const ingestStarting = useIngestPlayerStore((x) => x.ingestStarting);
|
|
270
287
|
const ingestMediaSource = useIngestPlayerStore((x) => x.ingestMediaSource);
|
|
271
288
|
const ingestAutoStart = useIngestPlayerStore((x) => x.ingestAutoStart);
|
|
@@ -406,7 +423,7 @@ export function NativeIngestPlayer() {
|
|
|
406
423
|
return (
|
|
407
424
|
<RTCViewIngest
|
|
408
425
|
mirror={ingestCamera !== "environment"}
|
|
409
|
-
objectFit={"contain"}
|
|
426
|
+
objectFit={props?.objectFit || "contain"}
|
|
410
427
|
streamURL={localMediaStream.toURL()}
|
|
411
428
|
zOrder={0}
|
|
412
429
|
style={{
|
|
@@ -34,6 +34,8 @@ function assignVideoRef(
|
|
|
34
34
|
type VideoProps = {
|
|
35
35
|
url: string;
|
|
36
36
|
videoRef?: React.RefObject<HTMLVideoElement>;
|
|
37
|
+
objectFit?: "contain" | "cover";
|
|
38
|
+
pictureInPictureEnabled?: boolean;
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
function useVideoDimensions(videoRef: React.RefObject<HTMLVideoElement>) {
|
|
@@ -67,7 +69,10 @@ function useVideoDimensions(videoRef: React.RefObject<HTMLVideoElement>) {
|
|
|
67
69
|
return dimensions;
|
|
68
70
|
}
|
|
69
71
|
|
|
70
|
-
export default function WebVideo(
|
|
72
|
+
export default function WebVideo(props?: {
|
|
73
|
+
objectFit?: "contain" | "cover";
|
|
74
|
+
pictureInPictureEnabled?: boolean;
|
|
75
|
+
}) {
|
|
71
76
|
const inProto = usePlayerStore((x) => x.protocol);
|
|
72
77
|
const isIngesting = usePlayerStore((x) => x.ingestConnectionState !== null);
|
|
73
78
|
const selectedRendition = usePlayerStore((x) => x.selectedRendition);
|
|
@@ -86,7 +91,12 @@ export default function WebVideo() {
|
|
|
86
91
|
}
|
|
87
92
|
}, [dimensions, setPlayerWidth, setPlayerHeight]);
|
|
88
93
|
|
|
89
|
-
const playerProps = {
|
|
94
|
+
const playerProps = {
|
|
95
|
+
url,
|
|
96
|
+
videoRef,
|
|
97
|
+
objectFit: props?.objectFit,
|
|
98
|
+
pictureInPictureEnabled: props?.pictureInPictureEnabled,
|
|
99
|
+
};
|
|
90
100
|
|
|
91
101
|
return (
|
|
92
102
|
<>
|
|
@@ -274,7 +284,7 @@ const VideoElement = forwardRef<
|
|
|
274
284
|
onVolumeChange={event("volumechange")}
|
|
275
285
|
onWaiting={event("waiting")}
|
|
276
286
|
style={{
|
|
277
|
-
objectFit: "contain",
|
|
287
|
+
objectFit: props.objectFit || "contain",
|
|
278
288
|
backgroundColor: "transparent",
|
|
279
289
|
width: "100%",
|
|
280
290
|
height: "100%",
|
|
@@ -282,6 +292,7 @@ const VideoElement = forwardRef<
|
|
|
282
292
|
maxHeight: "100%",
|
|
283
293
|
transform: ingest ? "scaleX(-1)" : undefined,
|
|
284
294
|
}}
|
|
295
|
+
disablePictureInPicture={props.pictureInPictureEnabled === false}
|
|
285
296
|
/>
|
|
286
297
|
);
|
|
287
298
|
});
|
|
@@ -3,7 +3,7 @@ import { useLivestreamStore } from "../livestream-store";
|
|
|
3
3
|
import { usePlayerStore } from "../player-store";
|
|
4
4
|
import { useCreateStreamRecord } from "../streamplace-store";
|
|
5
5
|
|
|
6
|
-
export function useLivestreamInfo() {
|
|
6
|
+
export function useLivestreamInfo(url?: string) {
|
|
7
7
|
const ingest = usePlayerStore((x) => x.ingestConnectionState);
|
|
8
8
|
const profile = useLivestreamStore((x) => x.profile);
|
|
9
9
|
const ingestStarting = usePlayerStore((x) => x.ingestStarting);
|
|
@@ -20,7 +20,11 @@ export function useLivestreamInfo() {
|
|
|
20
20
|
try {
|
|
21
21
|
if (title !== "") {
|
|
22
22
|
setRecordSubmitted(true);
|
|
23
|
-
|
|
23
|
+
// Create the livestream record with title and custom url if available
|
|
24
|
+
await createStreamRecord({
|
|
25
|
+
title,
|
|
26
|
+
customUrl: url || null,
|
|
27
|
+
});
|
|
24
28
|
}
|
|
25
29
|
} catch (error) {
|
|
26
30
|
console.error("Error creating livestream:", error);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function getBrowserName(userAgent: string) {
|
|
2
|
+
// The order matters here, and this may report false positives for unlisted browsers.
|
|
3
|
+
|
|
4
|
+
if (userAgent.includes("Firefox")) {
|
|
5
|
+
// "Mozilla/5.0 (X11; Linux i686; rv:104.0) Gecko/20100101 Firefox/104.0"
|
|
6
|
+
return "Mozilla Firefox";
|
|
7
|
+
} else if (userAgent.includes("SamsungBrowser")) {
|
|
8
|
+
// "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G955F Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.4 Chrome/67.0.3396.87 Mobile Safari/537.36"
|
|
9
|
+
return "Samsung Internet";
|
|
10
|
+
} else if (userAgent.includes("Opera") || userAgent.includes("OPR")) {
|
|
11
|
+
// "Mozilla/5.0 (Macintosh; Intel Mac OS X 12_5_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36 OPR/90.0.4480.54"
|
|
12
|
+
return "Opera";
|
|
13
|
+
} else if (userAgent.includes("Edge")) {
|
|
14
|
+
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299"
|
|
15
|
+
return "Microsoft Edge (Legacy)";
|
|
16
|
+
} else if (userAgent.includes("Edg")) {
|
|
17
|
+
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36 Edg/104.0.1293.70"
|
|
18
|
+
return "Microsoft Edge (Chromium)";
|
|
19
|
+
} else if (userAgent.includes("Chrome")) {
|
|
20
|
+
// "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"
|
|
21
|
+
return "Google Chrome or Chromium";
|
|
22
|
+
} else if (userAgent.includes("Safari")) {
|
|
23
|
+
// "Mozilla/5.0 (iPhone; CPU iPhone OS 15_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.6 Mobile/15E148 Safari/604.1"
|
|
24
|
+
return "Apple Safari";
|
|
25
|
+
}
|
|
26
|
+
return "unknown";
|
|
27
|
+
}
|
|
@@ -3,37 +3,10 @@ import { useEffect, useState } from "react";
|
|
|
3
3
|
import { Platform } from "react-native";
|
|
4
4
|
import { PlaceStreamKey } from "streamplace";
|
|
5
5
|
import { privateKeyToAccount } from "viem/accounts";
|
|
6
|
+
import { getBrowserName } from "../lib/browser";
|
|
6
7
|
import { usePDSAgent } from "../streamplace-store/xrpc";
|
|
7
8
|
import { useLivestreamStore } from "./livestream-store";
|
|
8
9
|
|
|
9
|
-
function getBrowserName(userAgent: string) {
|
|
10
|
-
// The order matters here, and this may report false positives for unlisted browsers.
|
|
11
|
-
|
|
12
|
-
if (userAgent.includes("Firefox")) {
|
|
13
|
-
// "Mozilla/5.0 (X11; Linux i686; rv:104.0) Gecko/20100101 Firefox/104.0"
|
|
14
|
-
return "Mozilla Firefox";
|
|
15
|
-
} else if (userAgent.includes("SamsungBrowser")) {
|
|
16
|
-
// "Mozilla/5.0 (Linux; Android 9; SAMSUNG SM-G955F Build/PPR1.180610.011) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/9.4 Chrome/67.0.3396.87 Mobile Safari/537.36"
|
|
17
|
-
return "Samsung Internet";
|
|
18
|
-
} else if (userAgent.includes("Opera") || userAgent.includes("OPR")) {
|
|
19
|
-
// "Mozilla/5.0 (Macintosh; Intel Mac OS X 12_5_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36 OPR/90.0.4480.54"
|
|
20
|
-
return "Opera";
|
|
21
|
-
} else if (userAgent.includes("Edge")) {
|
|
22
|
-
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299"
|
|
23
|
-
return "Microsoft Edge (Legacy)";
|
|
24
|
-
} else if (userAgent.includes("Edg")) {
|
|
25
|
-
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36 Edg/104.0.1293.70"
|
|
26
|
-
return "Microsoft Edge (Chromium)";
|
|
27
|
-
} else if (userAgent.includes("Chrome")) {
|
|
28
|
-
// "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"
|
|
29
|
-
return "Google Chrome or Chromium";
|
|
30
|
-
} else if (userAgent.includes("Safari")) {
|
|
31
|
-
// "Mozilla/5.0 (iPhone; CPU iPhone OS 15_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.6 Mobile/15E148 Safari/604.1"
|
|
32
|
-
return "Apple Safari";
|
|
33
|
-
}
|
|
34
|
-
return "unknown";
|
|
35
|
-
}
|
|
36
|
-
|
|
37
10
|
export const useStreamKey = (): {
|
|
38
11
|
streamKey: {
|
|
39
12
|
privateKey: string;
|
|
@@ -6,7 +6,11 @@ import { LivestreamViewHydrated } from "streamplace/src/useful-types";
|
|
|
6
6
|
import { useUrl } from "./streamplace-store";
|
|
7
7
|
import { usePDSAgent } from "./xrpc";
|
|
8
8
|
|
|
9
|
+
import PackageJson from "../../package.json";
|
|
10
|
+
|
|
9
11
|
import { useEffect, useRef } from "react";
|
|
12
|
+
import { Platform } from "react-native";
|
|
13
|
+
import { getBrowserName } from "../lib/browser";
|
|
10
14
|
|
|
11
15
|
const useUploadThumbnail = () => {
|
|
12
16
|
const abortRef = useRef<AbortController | null>(null);
|
|
@@ -123,11 +127,23 @@ export function useCreateStreamRecord() {
|
|
|
123
127
|
let url = useUrl();
|
|
124
128
|
const uploadThumbnail = useUploadThumbnail();
|
|
125
129
|
|
|
126
|
-
return async (
|
|
127
|
-
title
|
|
128
|
-
customThumbnail
|
|
129
|
-
submitPost
|
|
130
|
-
|
|
130
|
+
return async ({
|
|
131
|
+
title,
|
|
132
|
+
customThumbnail,
|
|
133
|
+
submitPost,
|
|
134
|
+
customUrl,
|
|
135
|
+
}: {
|
|
136
|
+
title: string;
|
|
137
|
+
customThumbnail?: Blob;
|
|
138
|
+
submitPost?: boolean;
|
|
139
|
+
customUrl?: string | null;
|
|
140
|
+
}) => {
|
|
141
|
+
if (!submitPost) {
|
|
142
|
+
submitPost = true;
|
|
143
|
+
}
|
|
144
|
+
if (!customUrl) {
|
|
145
|
+
customUrl = null;
|
|
146
|
+
}
|
|
131
147
|
if (!agent) {
|
|
132
148
|
throw new Error("No PDS agent found");
|
|
133
149
|
}
|
|
@@ -136,9 +152,11 @@ export function useCreateStreamRecord() {
|
|
|
136
152
|
throw new Error("No user DID found, assuming not logged in");
|
|
137
153
|
}
|
|
138
154
|
|
|
139
|
-
|
|
155
|
+
// Use customUrl if provided, otherwise fall back to the store URL
|
|
156
|
+
const finalUrl = customUrl || url;
|
|
157
|
+
const u = new URL(finalUrl);
|
|
140
158
|
|
|
141
|
-
|
|
159
|
+
let thumbnail: BlobRef | undefined = undefined;
|
|
142
160
|
|
|
143
161
|
if (customThumbnail) {
|
|
144
162
|
try {
|
|
@@ -185,10 +203,10 @@ export function useCreateStreamRecord() {
|
|
|
185
203
|
|
|
186
204
|
let newPost: undefined | { uri: string; cid: string } = undefined;
|
|
187
205
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const profile = await agent.getProfile({ actor: did });
|
|
206
|
+
const did = agent.did;
|
|
207
|
+
const profile = await agent.getProfile({ actor: did });
|
|
191
208
|
|
|
209
|
+
if (submitPost) {
|
|
192
210
|
if (!profile) {
|
|
193
211
|
throw new Error("No profile found for the user DID");
|
|
194
212
|
}
|
|
@@ -216,10 +234,27 @@ export function useCreateStreamRecord() {
|
|
|
216
234
|
}
|
|
217
235
|
}
|
|
218
236
|
|
|
237
|
+
// get version? only works on andoid/ios
|
|
238
|
+
//
|
|
239
|
+
let platform: string = Platform.OS;
|
|
240
|
+
let platVersion: string = Platform.Version.toString();
|
|
241
|
+
if (
|
|
242
|
+
platform === "web" &&
|
|
243
|
+
typeof window !== "undefined" &&
|
|
244
|
+
window.navigator
|
|
245
|
+
) {
|
|
246
|
+
platVersion = getBrowserName(window.navigator.userAgent);
|
|
247
|
+
}
|
|
248
|
+
|
|
219
249
|
const record: PlaceStreamLivestream.Record = {
|
|
220
250
|
title: title,
|
|
221
|
-
url:
|
|
251
|
+
url: finalUrl,
|
|
222
252
|
createdAt: new Date().toISOString(),
|
|
253
|
+
// would match up with e.g. https://stream.place/iame.li
|
|
254
|
+
canonicalUrl: `${finalUrl}/${profile.data.handle}`,
|
|
255
|
+
// user agent style string
|
|
256
|
+
// e.g. `@streamplace/components/0.1.0 (ios, 32.0)`
|
|
257
|
+
agent: `@streamplace/components/${PackageJson.version} (${platform}, ${platVersion})`,
|
|
223
258
|
post: newPost,
|
|
224
259
|
thumb: thumbnail,
|
|
225
260
|
};
|
|
@@ -233,7 +268,7 @@ export function useCreateStreamRecord() {
|
|
|
233
268
|
};
|
|
234
269
|
}
|
|
235
270
|
|
|
236
|
-
export function useUpdateStreamRecord() {
|
|
271
|
+
export function useUpdateStreamRecord(customUrl: string | null = null) {
|
|
237
272
|
let agent = usePDSAgent();
|
|
238
273
|
let url = useUrl();
|
|
239
274
|
const uploadThumbnail = useUploadThumbnail();
|
|
@@ -255,6 +290,9 @@ export function useUpdateStreamRecord() {
|
|
|
255
290
|
throw new Error("No latest record");
|
|
256
291
|
}
|
|
257
292
|
|
|
293
|
+
// Use customUrl if provided, otherwise fall back to the store URL
|
|
294
|
+
const finalUrl = customUrl || url;
|
|
295
|
+
|
|
258
296
|
let rkey = livestream.uri.split("/").pop();
|
|
259
297
|
let oldRecordValue: PlaceStreamLivestream.Record = livestream.record;
|
|
260
298
|
|
|
@@ -275,7 +313,7 @@ export function useUpdateStreamRecord() {
|
|
|
275
313
|
|
|
276
314
|
const record: PlaceStreamLivestream.Record = {
|
|
277
315
|
title: title,
|
|
278
|
-
url:
|
|
316
|
+
url: finalUrl,
|
|
279
317
|
createdAt: new Date().toISOString(),
|
|
280
318
|
post: oldRecordValue.post,
|
|
281
319
|
thumb: thumbnail,
|