@dialtribe/react-sdk 0.1.0-alpha.10 → 0.1.0-alpha.12
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 +11 -11
- package/dist/{broadcast-player-CEAnuf6t.d.mts → dialtribe-player-Rc9kfQiX.d.mts} +90 -89
- package/dist/{broadcast-player-CEAnuf6t.d.ts → dialtribe-player-Rc9kfQiX.d.ts} +90 -89
- package/dist/dialtribe-player.d.mts +3 -0
- package/dist/dialtribe-player.d.ts +3 -0
- package/dist/{broadcast-player.js → dialtribe-player.js} +110 -112
- package/dist/dialtribe-player.js.map +1 -0
- package/dist/{broadcast-player.mjs → dialtribe-player.mjs} +105 -107
- package/dist/dialtribe-player.mjs.map +1 -0
- package/dist/{broadcast-streamer.d.ts → dialtribe-streamer.d.mts} +203 -32
- package/dist/{broadcast-streamer.d.mts → dialtribe-streamer.d.ts} +203 -32
- package/dist/{broadcast-streamer.js → dialtribe-streamer.js} +391 -261
- package/dist/dialtribe-streamer.js.map +1 -0
- package/dist/{broadcast-streamer.mjs → dialtribe-streamer.mjs} +281 -154
- package/dist/dialtribe-streamer.mjs.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +387 -257
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +278 -151
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +9 -9
- package/dist/broadcast-player.d.mts +0 -3
- package/dist/broadcast-player.d.ts +0 -3
- package/dist/broadcast-player.js.map +0 -1
- package/dist/broadcast-player.mjs.map +0 -1
- package/dist/broadcast-streamer.js.map +0 -1
- package/dist/broadcast-streamer.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var React2 = require('react');
|
|
5
5
|
var ReactPlayer = require('react-player');
|
|
6
|
+
var reactDom = require('react-dom');
|
|
6
7
|
|
|
7
8
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
9
|
|
|
10
|
+
var React2__default = /*#__PURE__*/_interopDefault(React2);
|
|
9
11
|
var ReactPlayer__default = /*#__PURE__*/_interopDefault(ReactPlayer);
|
|
10
12
|
|
|
11
13
|
// src/components/HelloWorld.tsx
|
|
@@ -27,17 +29,17 @@ function HelloWorld({ name = "World" }) {
|
|
|
27
29
|
/* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: 0, fontSize: "14px" }, children: "@dialtribe/react-sdk is working correctly" })
|
|
28
30
|
] });
|
|
29
31
|
}
|
|
30
|
-
var
|
|
31
|
-
function
|
|
32
|
+
var DialtribeContext = React2.createContext(null);
|
|
33
|
+
function DialtribeProvider({
|
|
32
34
|
sessionToken: initialToken,
|
|
33
35
|
onTokenRefresh,
|
|
34
36
|
onTokenExpired,
|
|
35
37
|
apiBaseUrl,
|
|
36
38
|
children
|
|
37
39
|
}) {
|
|
38
|
-
const [sessionToken, setSessionTokenState] =
|
|
39
|
-
const [isExpired, setIsExpired] =
|
|
40
|
-
const setSessionToken =
|
|
40
|
+
const [sessionToken, setSessionTokenState] = React2.useState(initialToken);
|
|
41
|
+
const [isExpired, setIsExpired] = React2.useState(false);
|
|
42
|
+
const setSessionToken = React2.useCallback(
|
|
41
43
|
(newToken, expiresAt) => {
|
|
42
44
|
setSessionTokenState(newToken);
|
|
43
45
|
setIsExpired(false);
|
|
@@ -47,11 +49,11 @@ function DialTribeProvider({
|
|
|
47
49
|
},
|
|
48
50
|
[onTokenRefresh]
|
|
49
51
|
);
|
|
50
|
-
const markExpired =
|
|
52
|
+
const markExpired = React2.useCallback(() => {
|
|
51
53
|
setIsExpired(true);
|
|
52
54
|
onTokenExpired?.();
|
|
53
55
|
}, [onTokenExpired]);
|
|
54
|
-
|
|
56
|
+
React2.useEffect(() => {
|
|
55
57
|
if (initialToken !== sessionToken) {
|
|
56
58
|
setSessionTokenState(initialToken);
|
|
57
59
|
setIsExpired(false);
|
|
@@ -64,22 +66,22 @@ function DialTribeProvider({
|
|
|
64
66
|
markExpired,
|
|
65
67
|
apiBaseUrl
|
|
66
68
|
};
|
|
67
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
69
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DialtribeContext.Provider, { value, children });
|
|
68
70
|
}
|
|
69
|
-
function
|
|
70
|
-
const context =
|
|
71
|
+
function useDialtribe() {
|
|
72
|
+
const context = React2.useContext(DialtribeContext);
|
|
71
73
|
if (!context) {
|
|
72
74
|
throw new Error(
|
|
73
|
-
'
|
|
75
|
+
'useDialtribe must be used within a DialtribeProvider. Wrap your app with <DialtribeProvider sessionToken="sess_xxx">...</DialtribeProvider>'
|
|
74
76
|
);
|
|
75
77
|
}
|
|
76
78
|
return context;
|
|
77
79
|
}
|
|
78
|
-
function
|
|
79
|
-
return
|
|
80
|
+
function useDialtribeOptional() {
|
|
81
|
+
return React2.useContext(DialtribeContext);
|
|
80
82
|
}
|
|
81
83
|
|
|
82
|
-
// src/client/
|
|
84
|
+
// src/client/DialtribeClient.ts
|
|
83
85
|
function getDefaultApiBaseUrl() {
|
|
84
86
|
if (typeof process !== "undefined" && process.env?.NEXT_PUBLIC_DIALTRIBE_API_URL) {
|
|
85
87
|
return process.env.NEXT_PUBLIC_DIALTRIBE_API_URL;
|
|
@@ -93,18 +95,19 @@ function getEndpoints(baseUrl = DIALTRIBE_API_BASE) {
|
|
|
93
95
|
broadcast: (id) => `${baseUrl}/broadcasts/${id}`,
|
|
94
96
|
contentPlay: `${baseUrl}/content/play`,
|
|
95
97
|
presignedUrl: `${baseUrl}/media/presigned-url`,
|
|
96
|
-
|
|
97
|
-
|
|
98
|
+
audienceStart: `${baseUrl}/audiences/start`,
|
|
99
|
+
audiencePing: `${baseUrl}/audiences/ping`,
|
|
100
|
+
sessionPing: `${baseUrl}/sessions/ping`
|
|
98
101
|
};
|
|
99
102
|
}
|
|
100
103
|
var ENDPOINTS = getEndpoints();
|
|
101
|
-
var
|
|
104
|
+
var DialtribeClient = class {
|
|
102
105
|
constructor(config) {
|
|
103
106
|
this.config = config;
|
|
104
107
|
this.endpoints = config.apiBaseUrl ? getEndpoints(config.apiBaseUrl) : ENDPOINTS;
|
|
105
108
|
}
|
|
106
109
|
/**
|
|
107
|
-
* Make an authenticated request to
|
|
110
|
+
* Make an authenticated request to Dialtribe API
|
|
108
111
|
*
|
|
109
112
|
* Automatically:
|
|
110
113
|
* - Adds Authorization header with session token
|
|
@@ -218,7 +221,7 @@ var DialTribeClient = class {
|
|
|
218
221
|
* @returns audienceId and optional resumePosition
|
|
219
222
|
*/
|
|
220
223
|
async startSession(params) {
|
|
221
|
-
const response = await this.fetch(this.endpoints.
|
|
224
|
+
const response = await this.fetch(this.endpoints.audienceStart, {
|
|
222
225
|
method: "POST",
|
|
223
226
|
body: JSON.stringify(params)
|
|
224
227
|
});
|
|
@@ -237,7 +240,7 @@ var DialTribeClient = class {
|
|
|
237
240
|
* - 3: UNMOUNT
|
|
238
241
|
*/
|
|
239
242
|
async sendSessionPing(params) {
|
|
240
|
-
const response = await this.fetch(this.endpoints.
|
|
243
|
+
const response = await this.fetch(this.endpoints.audiencePing, {
|
|
241
244
|
method: "POST",
|
|
242
245
|
body: JSON.stringify(params)
|
|
243
246
|
});
|
|
@@ -256,18 +259,18 @@ function AudioWaveform({
|
|
|
256
259
|
isPlaying = false,
|
|
257
260
|
isLive = false
|
|
258
261
|
}) {
|
|
259
|
-
const canvasRef =
|
|
260
|
-
const animationFrameRef =
|
|
261
|
-
const [setupError, setSetupError] =
|
|
262
|
-
const isPlayingRef =
|
|
263
|
-
const isLiveRef =
|
|
264
|
-
|
|
262
|
+
const canvasRef = React2.useRef(null);
|
|
263
|
+
const animationFrameRef = React2.useRef(void 0);
|
|
264
|
+
const [setupError, setSetupError] = React2.useState(false);
|
|
265
|
+
const isPlayingRef = React2.useRef(isPlaying);
|
|
266
|
+
const isLiveRef = React2.useRef(isLive);
|
|
267
|
+
React2.useEffect(() => {
|
|
265
268
|
isPlayingRef.current = isPlaying;
|
|
266
269
|
}, [isPlaying]);
|
|
267
|
-
|
|
270
|
+
React2.useEffect(() => {
|
|
268
271
|
isLiveRef.current = isLive;
|
|
269
272
|
}, [isLive]);
|
|
270
|
-
|
|
273
|
+
React2.useEffect(() => {
|
|
271
274
|
const canvas = canvasRef.current;
|
|
272
275
|
if (!canvas) return;
|
|
273
276
|
const ctx = canvas.getContext("2d");
|
|
@@ -769,7 +772,7 @@ function getErrorMessage(error) {
|
|
|
769
772
|
}
|
|
770
773
|
return "Unable to play media. Please try refreshing the page or contact support if the problem persists.";
|
|
771
774
|
}
|
|
772
|
-
function
|
|
775
|
+
function DialtribePlayer({
|
|
773
776
|
broadcast,
|
|
774
777
|
appId,
|
|
775
778
|
contentId,
|
|
@@ -780,18 +783,18 @@ function BroadcastPlayer({
|
|
|
780
783
|
className = "",
|
|
781
784
|
enableKeyboardShortcuts = false
|
|
782
785
|
}) {
|
|
783
|
-
const { sessionToken, setSessionToken, markExpired, apiBaseUrl } =
|
|
784
|
-
const clientRef =
|
|
786
|
+
const { sessionToken, setSessionToken, markExpired, apiBaseUrl } = useDialtribe();
|
|
787
|
+
const clientRef = React2.useRef(null);
|
|
785
788
|
if (!clientRef.current && sessionToken) {
|
|
786
|
-
clientRef.current = new
|
|
789
|
+
clientRef.current = new DialtribeClient({
|
|
787
790
|
sessionToken,
|
|
788
791
|
apiBaseUrl,
|
|
789
792
|
onTokenRefresh: (newToken, expiresAt) => {
|
|
790
|
-
debug.log(`[
|
|
793
|
+
debug.log(`[DialtribeClient] Token refreshed, expires at ${expiresAt}`);
|
|
791
794
|
setSessionToken(newToken, expiresAt);
|
|
792
795
|
},
|
|
793
796
|
onTokenExpired: () => {
|
|
794
|
-
debug.error("[
|
|
797
|
+
debug.error("[DialtribeClient] Token expired");
|
|
795
798
|
markExpired();
|
|
796
799
|
}
|
|
797
800
|
});
|
|
@@ -799,35 +802,35 @@ function BroadcastPlayer({
|
|
|
799
802
|
clientRef.current.setSessionToken(sessionToken);
|
|
800
803
|
}
|
|
801
804
|
const client = clientRef.current;
|
|
802
|
-
const playerRef =
|
|
803
|
-
const transcriptContainerRef =
|
|
804
|
-
const activeWordRef =
|
|
805
|
-
const [audioElement, setAudioElement] =
|
|
806
|
-
const [playing, setPlaying] =
|
|
807
|
-
const [played, setPlayed] =
|
|
808
|
-
const [duration, setDuration] =
|
|
809
|
-
const [volume, setVolume] =
|
|
810
|
-
const [muted, setMuted] =
|
|
811
|
-
const [seeking, setSeeking] =
|
|
812
|
-
const [hasError, setHasError] =
|
|
813
|
-
const [errorMessage, setErrorMessage] =
|
|
814
|
-
const [hasEnded, setHasEnded] =
|
|
815
|
-
const [hasStreamEnded, setHasStreamEnded] =
|
|
816
|
-
const [showTranscript, setShowTranscript] =
|
|
817
|
-
const [transcriptData, setTranscriptData] =
|
|
818
|
-
const [currentTime, setCurrentTime] =
|
|
819
|
-
const [isLoadingTranscript, setIsLoadingTranscript] =
|
|
820
|
-
const [isLoadingVideo, setIsLoadingVideo] =
|
|
821
|
-
const [autoScrollEnabled, setAutoScrollEnabled] =
|
|
822
|
-
const isScrollingProgrammatically =
|
|
823
|
-
const lastActiveWordIndex =
|
|
824
|
-
const [showClipCreator, setShowClipCreator] =
|
|
825
|
-
const initialPlaybackTypeRef =
|
|
826
|
-
const [currentPlaybackInfo, setCurrentPlaybackInfo] =
|
|
827
|
-
const [urlExpiresAt, setUrlExpiresAt] =
|
|
828
|
-
const isRefreshingUrl =
|
|
829
|
-
const [audienceId, setAudienceId] =
|
|
830
|
-
const [sessionId] =
|
|
805
|
+
const playerRef = React2.useRef(null);
|
|
806
|
+
const transcriptContainerRef = React2.useRef(null);
|
|
807
|
+
const activeWordRef = React2.useRef(null);
|
|
808
|
+
const [audioElement, setAudioElement] = React2.useState(null);
|
|
809
|
+
const [playing, setPlaying] = React2.useState(false);
|
|
810
|
+
const [played, setPlayed] = React2.useState(0);
|
|
811
|
+
const [duration, setDuration] = React2.useState(0);
|
|
812
|
+
const [volume, setVolume] = React2.useState(1);
|
|
813
|
+
const [muted, setMuted] = React2.useState(false);
|
|
814
|
+
const [seeking, setSeeking] = React2.useState(false);
|
|
815
|
+
const [hasError, setHasError] = React2.useState(false);
|
|
816
|
+
const [errorMessage, setErrorMessage] = React2.useState("");
|
|
817
|
+
const [hasEnded, setHasEnded] = React2.useState(false);
|
|
818
|
+
const [hasStreamEnded, setHasStreamEnded] = React2.useState(false);
|
|
819
|
+
const [showTranscript, setShowTranscript] = React2.useState(false);
|
|
820
|
+
const [transcriptData, setTranscriptData] = React2.useState(null);
|
|
821
|
+
const [currentTime, setCurrentTime] = React2.useState(0);
|
|
822
|
+
const [isLoadingTranscript, setIsLoadingTranscript] = React2.useState(false);
|
|
823
|
+
const [isLoadingVideo, setIsLoadingVideo] = React2.useState(true);
|
|
824
|
+
const [autoScrollEnabled, setAutoScrollEnabled] = React2.useState(true);
|
|
825
|
+
const isScrollingProgrammatically = React2.useRef(false);
|
|
826
|
+
const lastActiveWordIndex = React2.useRef(-1);
|
|
827
|
+
const [showClipCreator, setShowClipCreator] = React2.useState(false);
|
|
828
|
+
const initialPlaybackTypeRef = React2.useRef(null);
|
|
829
|
+
const [currentPlaybackInfo, setCurrentPlaybackInfo] = React2.useState(null);
|
|
830
|
+
const [urlExpiresAt, setUrlExpiresAt] = React2.useState(null);
|
|
831
|
+
const isRefreshingUrl = React2.useRef(false);
|
|
832
|
+
const [audienceId, setAudienceId] = React2.useState(null);
|
|
833
|
+
const [sessionId] = React2.useState(() => {
|
|
831
834
|
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
832
835
|
return crypto.randomUUID();
|
|
833
836
|
}
|
|
@@ -837,9 +840,9 @@ function BroadcastPlayer({
|
|
|
837
840
|
return v.toString(16);
|
|
838
841
|
});
|
|
839
842
|
});
|
|
840
|
-
const heartbeatIntervalRef =
|
|
841
|
-
const hasInitializedSession =
|
|
842
|
-
const refreshPresignedUrl =
|
|
843
|
+
const heartbeatIntervalRef = React2.useRef(null);
|
|
844
|
+
const hasInitializedSession = React2.useRef(false);
|
|
845
|
+
const refreshPresignedUrl = React2.useCallback(
|
|
843
846
|
async (fileType) => {
|
|
844
847
|
if (!broadcast.hash || isRefreshingUrl.current || !client) {
|
|
845
848
|
debug.log("[URL Refresh] Skipping refresh - no hash, already refreshing, or no client");
|
|
@@ -890,7 +893,7 @@ function BroadcastPlayer({
|
|
|
890
893
|
if (width < 1024) return "tablet";
|
|
891
894
|
return "desktop";
|
|
892
895
|
};
|
|
893
|
-
const initializeTrackingSession =
|
|
896
|
+
const initializeTrackingSession = React2.useCallback(async () => {
|
|
894
897
|
if (!contentId || !appId || !client) return;
|
|
895
898
|
if (currentPlaybackInfo?.type === "hls" && broadcast.broadcastStatus === 1) return;
|
|
896
899
|
if (hasInitializedSession.current) return;
|
|
@@ -925,7 +928,7 @@ function BroadcastPlayer({
|
|
|
925
928
|
}
|
|
926
929
|
}
|
|
927
930
|
}, [contentId, appId, broadcast.id, broadcast.broadcastStatus, foreignId, foreignTier, sessionId, currentPlaybackInfo?.type, audioElement, client, onError]);
|
|
928
|
-
const sendTrackingPing =
|
|
931
|
+
const sendTrackingPing = React2.useCallback(
|
|
929
932
|
async (eventType) => {
|
|
930
933
|
if (!audienceId || !sessionId || !client) return;
|
|
931
934
|
try {
|
|
@@ -963,7 +966,7 @@ function BroadcastPlayer({
|
|
|
963
966
|
}
|
|
964
967
|
return null;
|
|
965
968
|
};
|
|
966
|
-
|
|
969
|
+
React2.useEffect(() => {
|
|
967
970
|
if (!currentPlaybackInfo) {
|
|
968
971
|
const info = getPlaybackInfo();
|
|
969
972
|
setCurrentPlaybackInfo(info);
|
|
@@ -979,12 +982,12 @@ function BroadcastPlayer({
|
|
|
979
982
|
}
|
|
980
983
|
}
|
|
981
984
|
}, [currentPlaybackInfo]);
|
|
982
|
-
|
|
985
|
+
React2.useEffect(() => {
|
|
983
986
|
if (currentPlaybackInfo?.url) {
|
|
984
987
|
setIsLoadingVideo(true);
|
|
985
988
|
}
|
|
986
989
|
}, [currentPlaybackInfo?.url]);
|
|
987
|
-
|
|
990
|
+
React2.useEffect(() => {
|
|
988
991
|
if (!urlExpiresAt || !currentPlaybackInfo?.type) return;
|
|
989
992
|
const checkExpiration = () => {
|
|
990
993
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -1003,7 +1006,7 @@ function BroadcastPlayer({
|
|
|
1003
1006
|
clearInterval(interval);
|
|
1004
1007
|
};
|
|
1005
1008
|
}, [urlExpiresAt, currentPlaybackInfo?.type, refreshPresignedUrl]);
|
|
1006
|
-
|
|
1009
|
+
React2.useEffect(() => {
|
|
1007
1010
|
if (initialPlaybackTypeRef.current === "hls" && currentPlaybackInfo?.type === "hls" && broadcast.broadcastStatus !== 1 && broadcast.recordingMp3Url && broadcast.hash && parseInt(broadcast.mp3Size || "0") > 0) {
|
|
1008
1011
|
const secureUrl = buildPlaybackUrl(broadcast.id, broadcast.hash);
|
|
1009
1012
|
setCurrentPlaybackInfo({ url: secureUrl, type: "mp3" });
|
|
@@ -1039,22 +1042,22 @@ function BroadcastPlayer({
|
|
|
1039
1042
|
setHasEnded(true);
|
|
1040
1043
|
}
|
|
1041
1044
|
};
|
|
1042
|
-
|
|
1045
|
+
React2.useEffect(() => {
|
|
1043
1046
|
if (broadcast.durationSeconds && broadcast.durationSeconds > 0) {
|
|
1044
1047
|
setDuration(broadcast.durationSeconds);
|
|
1045
1048
|
}
|
|
1046
1049
|
}, [broadcast.durationSeconds]);
|
|
1047
|
-
|
|
1050
|
+
React2.useEffect(() => {
|
|
1048
1051
|
if (isLiveStream && !playing) {
|
|
1049
1052
|
setPlaying(true);
|
|
1050
1053
|
}
|
|
1051
1054
|
}, [isLiveStream, playing]);
|
|
1052
|
-
|
|
1055
|
+
React2.useEffect(() => {
|
|
1053
1056
|
if (currentPlaybackInfo && audioElement && !hasInitializedSession.current) {
|
|
1054
1057
|
initializeTrackingSession();
|
|
1055
1058
|
}
|
|
1056
1059
|
}, [currentPlaybackInfo, audioElement, initializeTrackingSession]);
|
|
1057
|
-
|
|
1060
|
+
React2.useEffect(() => {
|
|
1058
1061
|
if (playing && audienceId) {
|
|
1059
1062
|
sendTrackingPing(1);
|
|
1060
1063
|
heartbeatIntervalRef.current = setInterval(() => {
|
|
@@ -1074,7 +1077,7 @@ function BroadcastPlayer({
|
|
|
1074
1077
|
}
|
|
1075
1078
|
}
|
|
1076
1079
|
}, [playing, audienceId, sendTrackingPing]);
|
|
1077
|
-
|
|
1080
|
+
React2.useEffect(() => {
|
|
1078
1081
|
return () => {
|
|
1079
1082
|
if (audienceId && sessionId && sessionToken) {
|
|
1080
1083
|
const payload = {
|
|
@@ -1099,7 +1102,7 @@ function BroadcastPlayer({
|
|
|
1099
1102
|
}
|
|
1100
1103
|
};
|
|
1101
1104
|
}, [audienceId, sessionId, sessionToken, audioElement, duration]);
|
|
1102
|
-
|
|
1105
|
+
React2.useEffect(() => {
|
|
1103
1106
|
if (broadcast.transcriptUrl && broadcast.transcriptStatus === 2 && !transcriptData) {
|
|
1104
1107
|
setIsLoadingTranscript(true);
|
|
1105
1108
|
fetch(broadcast.transcriptUrl).then((res) => {
|
|
@@ -1130,7 +1133,7 @@ function BroadcastPlayer({
|
|
|
1130
1133
|
});
|
|
1131
1134
|
}
|
|
1132
1135
|
}, [broadcast.transcriptUrl, broadcast.transcriptStatus, transcriptData]);
|
|
1133
|
-
|
|
1136
|
+
React2.useEffect(() => {
|
|
1134
1137
|
if (!audioElement) return;
|
|
1135
1138
|
const handleTimeUpdate2 = () => {
|
|
1136
1139
|
setCurrentTime(audioElement.currentTime);
|
|
@@ -1138,7 +1141,7 @@ function BroadcastPlayer({
|
|
|
1138
1141
|
audioElement.addEventListener("timeupdate", handleTimeUpdate2);
|
|
1139
1142
|
return () => audioElement.removeEventListener("timeupdate", handleTimeUpdate2);
|
|
1140
1143
|
}, [audioElement]);
|
|
1141
|
-
|
|
1144
|
+
React2.useEffect(() => {
|
|
1142
1145
|
if (showTranscript && autoScrollEnabled && activeWordRef.current && transcriptContainerRef.current) {
|
|
1143
1146
|
const container = transcriptContainerRef.current;
|
|
1144
1147
|
const activeWord = activeWordRef.current;
|
|
@@ -1153,7 +1156,7 @@ function BroadcastPlayer({
|
|
|
1153
1156
|
}
|
|
1154
1157
|
}
|
|
1155
1158
|
}, [currentTime, showTranscript, autoScrollEnabled]);
|
|
1156
|
-
|
|
1159
|
+
React2.useEffect(() => {
|
|
1157
1160
|
if (!showTranscript || !transcriptContainerRef.current) return;
|
|
1158
1161
|
const container = transcriptContainerRef.current;
|
|
1159
1162
|
const handleScroll = () => {
|
|
@@ -1236,10 +1239,10 @@ function BroadcastPlayer({
|
|
|
1236
1239
|
setAudioElement(internalPlayer);
|
|
1237
1240
|
}
|
|
1238
1241
|
} catch (error) {
|
|
1239
|
-
debug.error("[
|
|
1242
|
+
debug.error("[DialtribePlayer] Error getting internal player:", error);
|
|
1240
1243
|
}
|
|
1241
1244
|
};
|
|
1242
|
-
|
|
1245
|
+
React2.useEffect(() => {
|
|
1243
1246
|
const findAudioElement = () => {
|
|
1244
1247
|
const videoElements = document.querySelectorAll("video, audio");
|
|
1245
1248
|
if (videoElements.length > 0) {
|
|
@@ -1259,7 +1262,7 @@ function BroadcastPlayer({
|
|
|
1259
1262
|
return () => timeouts.forEach(clearTimeout);
|
|
1260
1263
|
}
|
|
1261
1264
|
}, [playbackUrl]);
|
|
1262
|
-
|
|
1265
|
+
React2.useEffect(() => {
|
|
1263
1266
|
if (playing && !audioElement) {
|
|
1264
1267
|
const videoElements = document.querySelectorAll("video, audio");
|
|
1265
1268
|
if (videoElements.length > 0) {
|
|
@@ -1338,7 +1341,7 @@ function BroadcastPlayer({
|
|
|
1338
1341
|
onError(error);
|
|
1339
1342
|
}
|
|
1340
1343
|
};
|
|
1341
|
-
const handleRetry =
|
|
1344
|
+
const handleRetry = React2.useCallback(() => {
|
|
1342
1345
|
setHasError(false);
|
|
1343
1346
|
setErrorMessage("");
|
|
1344
1347
|
setIsLoadingVideo(true);
|
|
@@ -1361,7 +1364,7 @@ function BroadcastPlayer({
|
|
|
1361
1364
|
}
|
|
1362
1365
|
}
|
|
1363
1366
|
};
|
|
1364
|
-
|
|
1367
|
+
React2.useEffect(() => {
|
|
1365
1368
|
if (!enableKeyboardShortcuts) return;
|
|
1366
1369
|
const seekBy = (seconds) => {
|
|
1367
1370
|
if (!audioElement || duration <= 0) return;
|
|
@@ -1444,7 +1447,7 @@ function BroadcastPlayer({
|
|
|
1444
1447
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center p-8", children: /* @__PURE__ */ jsxRuntime.jsx(LoadingSpinner, { variant: "white", text: "Loading..." }) });
|
|
1445
1448
|
}
|
|
1446
1449
|
const hasTranscript = broadcast.transcriptStatus === 2 && transcriptData && (transcriptData.segments && transcriptData.segments.some((s) => s.words && s.words.length > 0) || transcriptData.words && transcriptData.words.length > 0);
|
|
1447
|
-
|
|
1450
|
+
const playerContent = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `bg-black rounded-lg shadow-2xl w-full max-h-full flex flex-col overflow-hidden ${className}`, children: [
|
|
1448
1451
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-zinc-900/50 backdrop-blur-sm border-b border-zinc-800 px-3 sm:px-4 md:px-6 py-2 sm:py-3 md:py-4 flex justify-between items-center rounded-t-lg shrink-0", children: [
|
|
1449
1452
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1450
1453
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-white", children: broadcast.streamKeyRecord?.foreignName || "Broadcast" }),
|
|
@@ -1976,90 +1979,9 @@ function BroadcastPlayer({
|
|
|
1976
1979
|
}
|
|
1977
1980
|
` })
|
|
1978
1981
|
] });
|
|
1982
|
+
return playerContent;
|
|
1979
1983
|
}
|
|
1980
|
-
|
|
1981
|
-
broadcast,
|
|
1982
|
-
isOpen,
|
|
1983
|
-
onClose,
|
|
1984
|
-
appId,
|
|
1985
|
-
contentId,
|
|
1986
|
-
foreignId,
|
|
1987
|
-
foreignTier,
|
|
1988
|
-
renderClipCreator,
|
|
1989
|
-
className,
|
|
1990
|
-
enableKeyboardShortcuts = false
|
|
1991
|
-
}) {
|
|
1992
|
-
const closeButtonRef = react.useRef(null);
|
|
1993
|
-
const previousActiveElement = react.useRef(null);
|
|
1994
|
-
react.useEffect(() => {
|
|
1995
|
-
if (!isOpen) return;
|
|
1996
|
-
previousActiveElement.current = document.activeElement;
|
|
1997
|
-
setTimeout(() => {
|
|
1998
|
-
closeButtonRef.current?.focus();
|
|
1999
|
-
}, 100);
|
|
2000
|
-
return () => {
|
|
2001
|
-
if (previousActiveElement.current) {
|
|
2002
|
-
previousActiveElement.current.focus();
|
|
2003
|
-
}
|
|
2004
|
-
};
|
|
2005
|
-
}, [isOpen]);
|
|
2006
|
-
react.useEffect(() => {
|
|
2007
|
-
if (!isOpen) return;
|
|
2008
|
-
const handleKeyDown = (e) => {
|
|
2009
|
-
if (e.key === "Escape") {
|
|
2010
|
-
onClose();
|
|
2011
|
-
}
|
|
2012
|
-
};
|
|
2013
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
2014
|
-
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
2015
|
-
}, [isOpen, onClose]);
|
|
2016
|
-
if (!isOpen) return null;
|
|
2017
|
-
const handleBackdropClick = (e) => {
|
|
2018
|
-
if (e.target === e.currentTarget) {
|
|
2019
|
-
onClose();
|
|
2020
|
-
}
|
|
2021
|
-
};
|
|
2022
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2023
|
-
"div",
|
|
2024
|
-
{
|
|
2025
|
-
className: "fixed inset-0 bg-black/70 backdrop-blur-xl flex items-center justify-center z-50 p-2 sm:p-4",
|
|
2026
|
-
onClick: handleBackdropClick,
|
|
2027
|
-
role: "dialog",
|
|
2028
|
-
"aria-modal": "true",
|
|
2029
|
-
"aria-label": "Broadcast player",
|
|
2030
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full max-w-7xl max-h-[95vh] sm:max-h-[90vh] overflow-hidden", children: [
|
|
2031
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2032
|
-
"button",
|
|
2033
|
-
{
|
|
2034
|
-
ref: closeButtonRef,
|
|
2035
|
-
onClick: onClose,
|
|
2036
|
-
className: "absolute top-2 right-2 sm:top-4 sm:right-4 z-10 text-gray-400 hover:text-white text-2xl leading-none transition-colors w-8 h-8 flex items-center justify-center bg-black/50 rounded-full",
|
|
2037
|
-
title: "Close (ESC)",
|
|
2038
|
-
"aria-label": "Close player",
|
|
2039
|
-
children: "\xD7"
|
|
2040
|
-
}
|
|
2041
|
-
),
|
|
2042
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2043
|
-
BroadcastPlayer,
|
|
2044
|
-
{
|
|
2045
|
-
broadcast,
|
|
2046
|
-
appId,
|
|
2047
|
-
contentId,
|
|
2048
|
-
foreignId,
|
|
2049
|
-
foreignTier,
|
|
2050
|
-
renderClipCreator,
|
|
2051
|
-
className,
|
|
2052
|
-
enableKeyboardShortcuts,
|
|
2053
|
-
onError: (error) => {
|
|
2054
|
-
debug.error("[BroadcastPlayerModal] Player error:", error);
|
|
2055
|
-
}
|
|
2056
|
-
}
|
|
2057
|
-
)
|
|
2058
|
-
] })
|
|
2059
|
-
}
|
|
2060
|
-
);
|
|
2061
|
-
}
|
|
2062
|
-
var BroadcastPlayerErrorBoundary = class extends react.Component {
|
|
1984
|
+
var DialtribePlayerErrorBoundary = class extends React2.Component {
|
|
2063
1985
|
constructor(props) {
|
|
2064
1986
|
super(props);
|
|
2065
1987
|
this.handleReset = () => {
|
|
@@ -2185,6 +2107,84 @@ var BroadcastPlayerErrorBoundary = class extends react.Component {
|
|
|
2185
2107
|
return this.props.children;
|
|
2186
2108
|
}
|
|
2187
2109
|
};
|
|
2110
|
+
var overlayStyles = {
|
|
2111
|
+
modal: {
|
|
2112
|
+
backdrop: "bg-black/70 backdrop-blur-xl p-2 sm:p-4",
|
|
2113
|
+
container: "max-w-7xl max-h-[95vh] sm:max-h-[90vh]"
|
|
2114
|
+
},
|
|
2115
|
+
fullscreen: {
|
|
2116
|
+
backdrop: "bg-black",
|
|
2117
|
+
container: "h-full"
|
|
2118
|
+
}
|
|
2119
|
+
};
|
|
2120
|
+
function DialtribeOverlay({
|
|
2121
|
+
isOpen,
|
|
2122
|
+
onClose,
|
|
2123
|
+
mode = "modal",
|
|
2124
|
+
children,
|
|
2125
|
+
ariaLabel = "Dialog",
|
|
2126
|
+
showCloseButton = true,
|
|
2127
|
+
closeOnBackdropClick = true,
|
|
2128
|
+
closeOnEsc = true
|
|
2129
|
+
}) {
|
|
2130
|
+
const closeButtonRef = React2.useRef(null);
|
|
2131
|
+
const previousActiveElement = React2.useRef(null);
|
|
2132
|
+
React2.useEffect(() => {
|
|
2133
|
+
if (!isOpen) return;
|
|
2134
|
+
previousActiveElement.current = document.activeElement;
|
|
2135
|
+
setTimeout(() => {
|
|
2136
|
+
closeButtonRef.current?.focus();
|
|
2137
|
+
}, 100);
|
|
2138
|
+
return () => {
|
|
2139
|
+
if (previousActiveElement.current) {
|
|
2140
|
+
previousActiveElement.current.focus();
|
|
2141
|
+
}
|
|
2142
|
+
};
|
|
2143
|
+
}, [isOpen]);
|
|
2144
|
+
React2.useEffect(() => {
|
|
2145
|
+
if (!isOpen || !closeOnEsc) return;
|
|
2146
|
+
const handleKeyDown = (e) => {
|
|
2147
|
+
if (e.key === "Escape") {
|
|
2148
|
+
onClose();
|
|
2149
|
+
}
|
|
2150
|
+
};
|
|
2151
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
2152
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
2153
|
+
}, [isOpen, onClose, closeOnEsc]);
|
|
2154
|
+
if (!isOpen) {
|
|
2155
|
+
return null;
|
|
2156
|
+
}
|
|
2157
|
+
const handleBackdropClick = (e) => {
|
|
2158
|
+
if (closeOnBackdropClick && e.target === e.currentTarget) {
|
|
2159
|
+
onClose();
|
|
2160
|
+
}
|
|
2161
|
+
};
|
|
2162
|
+
const styles = overlayStyles[mode];
|
|
2163
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2164
|
+
"div",
|
|
2165
|
+
{
|
|
2166
|
+
className: `fixed inset-0 flex items-center justify-center z-50 ${styles.backdrop}`,
|
|
2167
|
+
onClick: handleBackdropClick,
|
|
2168
|
+
role: "dialog",
|
|
2169
|
+
"aria-modal": "true",
|
|
2170
|
+
"aria-label": ariaLabel,
|
|
2171
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `relative w-full overflow-hidden ${styles.container}`, children: [
|
|
2172
|
+
showCloseButton && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2173
|
+
"button",
|
|
2174
|
+
{
|
|
2175
|
+
ref: closeButtonRef,
|
|
2176
|
+
onClick: onClose,
|
|
2177
|
+
className: "absolute top-2 right-2 sm:top-4 sm:right-4 z-10 text-gray-400 hover:text-white text-2xl leading-none transition-colors w-8 h-8 flex items-center justify-center bg-black/50 rounded-full",
|
|
2178
|
+
title: "Close (ESC)",
|
|
2179
|
+
"aria-label": "Close",
|
|
2180
|
+
children: "\xD7"
|
|
2181
|
+
}
|
|
2182
|
+
),
|
|
2183
|
+
children
|
|
2184
|
+
] })
|
|
2185
|
+
}
|
|
2186
|
+
);
|
|
2187
|
+
}
|
|
2188
2188
|
|
|
2189
2189
|
// src/utils/media-constraints.ts
|
|
2190
2190
|
function getMediaConstraints(options) {
|
|
@@ -2560,8 +2560,8 @@ function StreamKeyDisplay({
|
|
|
2560
2560
|
layout = "vertical",
|
|
2561
2561
|
darkMode = false
|
|
2562
2562
|
}) {
|
|
2563
|
-
const [isRevealed, setIsRevealed] =
|
|
2564
|
-
const [copySuccess, setCopySuccess] =
|
|
2563
|
+
const [isRevealed, setIsRevealed] = React2.useState(false);
|
|
2564
|
+
const [copySuccess, setCopySuccess] = React2.useState(false);
|
|
2565
2565
|
const obscureStreamKey = (key) => {
|
|
2566
2566
|
if (key.length <= 12) {
|
|
2567
2567
|
return "\u2022".repeat(key.length);
|
|
@@ -2669,9 +2669,9 @@ function StreamingControls({
|
|
|
2669
2669
|
onAudioDeviceChange,
|
|
2670
2670
|
mediaStream
|
|
2671
2671
|
}) {
|
|
2672
|
-
const [duration, setDuration] =
|
|
2673
|
-
const [showSettings, setShowSettings] =
|
|
2674
|
-
|
|
2672
|
+
const [duration, setDuration] = React2.useState(0);
|
|
2673
|
+
const [showSettings, setShowSettings] = React2.useState(false);
|
|
2674
|
+
React2.useEffect(() => {
|
|
2675
2675
|
if (state !== "live" || !startTime) return;
|
|
2676
2676
|
const interval = setInterval(() => {
|
|
2677
2677
|
const elapsed = Math.floor((Date.now() - startTime.getTime()) / 1e3);
|
|
@@ -3004,8 +3004,8 @@ function StreamingControls({
|
|
|
3004
3004
|
] });
|
|
3005
3005
|
}
|
|
3006
3006
|
function StreamKeyInput({ onSubmit, inline = false }) {
|
|
3007
|
-
const [streamKey, setStreamKey] =
|
|
3008
|
-
const [error, setError] =
|
|
3007
|
+
const [streamKey, setStreamKey] = React2.useState("");
|
|
3008
|
+
const [error, setError] = React2.useState("");
|
|
3009
3009
|
const containerClass = inline ? "dialtribe-stream-key-input flex items-center justify-center h-full w-full p-4 overflow-auto" : "dialtribe-stream-key-input flex items-center justify-center min-h-screen p-4";
|
|
3010
3010
|
const validateStreamKey = (key) => {
|
|
3011
3011
|
const pattern = /^[abvw][a-zA-Z0-9]+_.+$/;
|
|
@@ -3071,7 +3071,7 @@ function StreamKeyInput({ onSubmit, inline = false }) {
|
|
|
3071
3071
|
] })
|
|
3072
3072
|
] }) });
|
|
3073
3073
|
}
|
|
3074
|
-
function
|
|
3074
|
+
function DialtribeStreamer({
|
|
3075
3075
|
sessionToken: propSessionToken,
|
|
3076
3076
|
streamKey: initialStreamKey,
|
|
3077
3077
|
onDone,
|
|
@@ -3080,35 +3080,35 @@ function BroadcastStreamer({
|
|
|
3080
3080
|
apiBaseUrl = DIALTRIBE_API_BASE,
|
|
3081
3081
|
inline = false
|
|
3082
3082
|
}) {
|
|
3083
|
-
const containerClass = inline ? "dialtribe-
|
|
3084
|
-
const centeredContainerClass = inline ? "dialtribe-
|
|
3085
|
-
const dialTribeContext =
|
|
3083
|
+
const containerClass = inline ? "dialtribe-dialtribe-streamer h-full w-full bg-black relative" : "dialtribe-dialtribe-streamer min-h-screen bg-black";
|
|
3084
|
+
const centeredContainerClass = inline ? "dialtribe-dialtribe-streamer flex items-center justify-center h-full w-full p-4 bg-black relative" : "dialtribe-dialtribe-streamer flex items-center justify-center min-h-screen p-4 bg-black";
|
|
3085
|
+
const dialTribeContext = useDialtribeOptional();
|
|
3086
3086
|
const sessionToken = propSessionToken ?? dialTribeContext?.sessionToken ?? null;
|
|
3087
|
-
const [streamKey, setStreamKey] =
|
|
3088
|
-
const [state, setState] =
|
|
3089
|
-
|
|
3087
|
+
const [streamKey, setStreamKey] = React2.useState(initialStreamKey || null);
|
|
3088
|
+
const [state, setState] = React2.useState("idle");
|
|
3089
|
+
React2.useEffect(() => {
|
|
3090
3090
|
if (initialStreamKey && initialStreamKey !== streamKey) {
|
|
3091
3091
|
setStreamKey(initialStreamKey);
|
|
3092
3092
|
}
|
|
3093
3093
|
}, [initialStreamKey]);
|
|
3094
|
-
const [error, setError] =
|
|
3095
|
-
const [mediaStream, setMediaStream] =
|
|
3096
|
-
const [streamer, setStreamer] =
|
|
3097
|
-
const [bytesSent, setBytesSent] =
|
|
3098
|
-
const [startTime, setStartTime] =
|
|
3099
|
-
const [isMuted, setIsMuted] =
|
|
3100
|
-
const [isVideoEnabled, setIsVideoEnabled] =
|
|
3101
|
-
const [facingMode, setFacingMode] =
|
|
3102
|
-
const [showStopConfirm, setShowStopConfirm] =
|
|
3103
|
-
const [showCloseConfirm, setShowCloseConfirm] =
|
|
3104
|
-
const [hasMultipleCameras, setHasMultipleCameras] =
|
|
3105
|
-
const [videoDevices, setVideoDevices] =
|
|
3106
|
-
const [audioDevices, setAudioDevices] =
|
|
3107
|
-
const [selectedVideoDeviceId, setSelectedVideoDeviceId] =
|
|
3108
|
-
const [selectedAudioDeviceId, setSelectedAudioDeviceId] =
|
|
3109
|
-
const videoRef =
|
|
3110
|
-
const streamerRef =
|
|
3111
|
-
const mediaStreamRef =
|
|
3094
|
+
const [error, setError] = React2.useState(null);
|
|
3095
|
+
const [mediaStream, setMediaStream] = React2.useState(null);
|
|
3096
|
+
const [streamer, setStreamer] = React2.useState(null);
|
|
3097
|
+
const [bytesSent, setBytesSent] = React2.useState(0);
|
|
3098
|
+
const [startTime, setStartTime] = React2.useState(null);
|
|
3099
|
+
const [isMuted, setIsMuted] = React2.useState(false);
|
|
3100
|
+
const [isVideoEnabled, setIsVideoEnabled] = React2.useState(true);
|
|
3101
|
+
const [facingMode, setFacingMode] = React2.useState("user");
|
|
3102
|
+
const [showStopConfirm, setShowStopConfirm] = React2.useState(false);
|
|
3103
|
+
const [showCloseConfirm, setShowCloseConfirm] = React2.useState(false);
|
|
3104
|
+
const [hasMultipleCameras, setHasMultipleCameras] = React2.useState(false);
|
|
3105
|
+
const [videoDevices, setVideoDevices] = React2.useState([]);
|
|
3106
|
+
const [audioDevices, setAudioDevices] = React2.useState([]);
|
|
3107
|
+
const [selectedVideoDeviceId, setSelectedVideoDeviceId] = React2.useState();
|
|
3108
|
+
const [selectedAudioDeviceId, setSelectedAudioDeviceId] = React2.useState();
|
|
3109
|
+
const videoRef = React2.useRef(null);
|
|
3110
|
+
const streamerRef = React2.useRef(null);
|
|
3111
|
+
const mediaStreamRef = React2.useRef(null);
|
|
3112
3112
|
const isVideoKey = streamKey ? streamKey.startsWith("v") || streamKey.startsWith("w") : false;
|
|
3113
3113
|
const handleStreamKeySubmit = (key) => {
|
|
3114
3114
|
setStreamKey(key);
|
|
@@ -3118,7 +3118,7 @@ function BroadcastStreamer({
|
|
|
3118
3118
|
setStreamKey(key);
|
|
3119
3119
|
onStreamKeyChange?.(key);
|
|
3120
3120
|
};
|
|
3121
|
-
|
|
3121
|
+
React2.useEffect(() => {
|
|
3122
3122
|
if (!streamKey) return;
|
|
3123
3123
|
const compat = checkBrowserCompatibility();
|
|
3124
3124
|
if (!compat.compatible) {
|
|
@@ -3156,13 +3156,13 @@ function BroadcastStreamer({
|
|
|
3156
3156
|
setHasMultipleCameras(false);
|
|
3157
3157
|
}
|
|
3158
3158
|
};
|
|
3159
|
-
|
|
3159
|
+
React2.useEffect(() => {
|
|
3160
3160
|
streamerRef.current = streamer;
|
|
3161
3161
|
}, [streamer]);
|
|
3162
|
-
|
|
3162
|
+
React2.useEffect(() => {
|
|
3163
3163
|
mediaStreamRef.current = mediaStream;
|
|
3164
3164
|
}, [mediaStream]);
|
|
3165
|
-
|
|
3165
|
+
React2.useEffect(() => {
|
|
3166
3166
|
return () => {
|
|
3167
3167
|
if (streamerRef.current) {
|
|
3168
3168
|
streamerRef.current.stop();
|
|
@@ -3172,7 +3172,7 @@ function BroadcastStreamer({
|
|
|
3172
3172
|
}
|
|
3173
3173
|
};
|
|
3174
3174
|
}, []);
|
|
3175
|
-
|
|
3175
|
+
React2.useEffect(() => {
|
|
3176
3176
|
if (state === "live") {
|
|
3177
3177
|
const handleBeforeUnload = (e) => {
|
|
3178
3178
|
e.preventDefault();
|
|
@@ -3183,7 +3183,7 @@ function BroadcastStreamer({
|
|
|
3183
3183
|
return () => window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
3184
3184
|
}
|
|
3185
3185
|
}, [state]);
|
|
3186
|
-
|
|
3186
|
+
React2.useEffect(() => {
|
|
3187
3187
|
if (videoRef.current && mediaStream) {
|
|
3188
3188
|
videoRef.current.srcObject = mediaStream;
|
|
3189
3189
|
}
|
|
@@ -3466,36 +3466,9 @@ function BroadcastStreamer({
|
|
|
3466
3466
|
}
|
|
3467
3467
|
};
|
|
3468
3468
|
if (!sessionToken) {
|
|
3469
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: centeredContainerClass, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
3470
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-16
|
|
3471
|
-
|
|
3472
|
-
{
|
|
3473
|
-
className: "w-8 h-8 text-red-600 dark:text-red-400",
|
|
3474
|
-
fill: "none",
|
|
3475
|
-
stroke: "currentColor",
|
|
3476
|
-
viewBox: "0 0 24 24",
|
|
3477
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3478
|
-
"path",
|
|
3479
|
-
{
|
|
3480
|
-
strokeLinecap: "round",
|
|
3481
|
-
strokeLinejoin: "round",
|
|
3482
|
-
strokeWidth: 2,
|
|
3483
|
-
d: "M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
|
|
3484
|
-
}
|
|
3485
|
-
)
|
|
3486
|
-
}
|
|
3487
|
-
) }),
|
|
3488
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-bold text-black dark:text-white mb-2", children: "Authentication Required" }),
|
|
3489
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-gray-600 dark:text-gray-400 mb-4", children: "A session token is required to use the broadcast streamer." }),
|
|
3490
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 dark:text-gray-500 mb-6", children: "Wrap your app with DialTribeProvider or pass a sessionToken prop." }),
|
|
3491
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3492
|
-
"button",
|
|
3493
|
-
{
|
|
3494
|
-
onClick: handleDone,
|
|
3495
|
-
className: "w-full px-6 py-2 bg-gray-100 dark:bg-zinc-800 hover:bg-gray-200 dark:hover:bg-zinc-700 text-black dark:text-white font-medium rounded-lg transition-colors",
|
|
3496
|
-
children: "Close"
|
|
3497
|
-
}
|
|
3498
|
-
)
|
|
3469
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: centeredContainerClass, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
3470
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-16 border-4 border-gray-700 border-t-blue-600 rounded-full animate-spin mx-auto mb-4" }),
|
|
3471
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-white text-lg", children: "Connecting..." })
|
|
3499
3472
|
] }) });
|
|
3500
3473
|
}
|
|
3501
3474
|
if (!streamKey) {
|
|
@@ -3674,7 +3647,7 @@ function BroadcastStreamer({
|
|
|
3674
3647
|
] });
|
|
3675
3648
|
}
|
|
3676
3649
|
|
|
3677
|
-
// src/utils/
|
|
3650
|
+
// src/utils/dialtribe-popup.ts
|
|
3678
3651
|
function calculatePopupDimensions() {
|
|
3679
3652
|
const screenWidth = window.screen.width;
|
|
3680
3653
|
const screenHeight = window.screen.height;
|
|
@@ -3692,26 +3665,22 @@ function calculatePopupDimensions() {
|
|
|
3692
3665
|
const top = Math.floor((screenHeight - height) / 2);
|
|
3693
3666
|
return { width, height, left, top };
|
|
3694
3667
|
}
|
|
3695
|
-
function
|
|
3668
|
+
function openDialtribeStreamerPopup(options) {
|
|
3696
3669
|
const {
|
|
3697
3670
|
sessionToken,
|
|
3698
3671
|
streamKey,
|
|
3672
|
+
streamerUrl,
|
|
3699
3673
|
appId,
|
|
3700
|
-
|
|
3701
|
-
additionalParams,
|
|
3702
|
-
baseUrl = "/broadcasts/new"
|
|
3674
|
+
additionalParams
|
|
3703
3675
|
} = options;
|
|
3704
3676
|
const { width, height, left, top } = calculatePopupDimensions();
|
|
3705
3677
|
const params = new URLSearchParams();
|
|
3706
|
-
if (mode) {
|
|
3707
|
-
params.append("mode", mode);
|
|
3708
|
-
}
|
|
3709
3678
|
if (additionalParams) {
|
|
3710
3679
|
Object.entries(additionalParams).forEach(([key, value]) => {
|
|
3711
3680
|
params.append(key, value);
|
|
3712
3681
|
});
|
|
3713
3682
|
}
|
|
3714
|
-
const url = `${
|
|
3683
|
+
const url = `${streamerUrl}${params.toString() ? `?${params.toString()}` : ""}`;
|
|
3715
3684
|
const popup = window.open(
|
|
3716
3685
|
url,
|
|
3717
3686
|
"_blank",
|
|
@@ -3741,18 +3710,177 @@ function openBroadcastStreamerPopup(options) {
|
|
|
3741
3710
|
setTimeout(sendMessage, 500);
|
|
3742
3711
|
return popup;
|
|
3743
3712
|
}
|
|
3744
|
-
var openBroadcastPopup =
|
|
3713
|
+
var openBroadcastPopup = openDialtribeStreamerPopup;
|
|
3714
|
+
function useDialtribeStreamerPopup() {
|
|
3715
|
+
const [sessionToken, setSessionToken] = React2.useState(null);
|
|
3716
|
+
const [streamKey, setStreamKey] = React2.useState(null);
|
|
3717
|
+
const [apiBaseUrl, setApiBaseUrl] = React2.useState("");
|
|
3718
|
+
const receivedDataRef = React2.useRef(false);
|
|
3719
|
+
React2.useEffect(() => {
|
|
3720
|
+
const handleMessage = (event) => {
|
|
3721
|
+
if (event.data?.type !== "STREAM_KEY") return;
|
|
3722
|
+
const { sessionToken: token, streamKey: key, apiBaseUrl: url } = event.data;
|
|
3723
|
+
if (token && key) {
|
|
3724
|
+
receivedDataRef.current = true;
|
|
3725
|
+
setSessionToken(token);
|
|
3726
|
+
setStreamKey(key);
|
|
3727
|
+
if (url) {
|
|
3728
|
+
setApiBaseUrl(url);
|
|
3729
|
+
}
|
|
3730
|
+
} else if (key) {
|
|
3731
|
+
receivedDataRef.current = true;
|
|
3732
|
+
setStreamKey(key);
|
|
3733
|
+
}
|
|
3734
|
+
};
|
|
3735
|
+
window.addEventListener("message", handleMessage);
|
|
3736
|
+
const requestCredentials = () => {
|
|
3737
|
+
if (window.opener && !receivedDataRef.current) {
|
|
3738
|
+
window.opener.postMessage({ type: "POPUP_READY" }, "*");
|
|
3739
|
+
}
|
|
3740
|
+
};
|
|
3741
|
+
requestCredentials();
|
|
3742
|
+
const pollInterval = setInterval(() => {
|
|
3743
|
+
if (!receivedDataRef.current) {
|
|
3744
|
+
requestCredentials();
|
|
3745
|
+
} else {
|
|
3746
|
+
clearInterval(pollInterval);
|
|
3747
|
+
}
|
|
3748
|
+
}, 200);
|
|
3749
|
+
const timeout = setTimeout(() => {
|
|
3750
|
+
clearInterval(pollInterval);
|
|
3751
|
+
}, 1e4);
|
|
3752
|
+
return () => {
|
|
3753
|
+
window.removeEventListener("message", handleMessage);
|
|
3754
|
+
clearInterval(pollInterval);
|
|
3755
|
+
clearTimeout(timeout);
|
|
3756
|
+
};
|
|
3757
|
+
}, []);
|
|
3758
|
+
return {
|
|
3759
|
+
sessionToken,
|
|
3760
|
+
streamKey,
|
|
3761
|
+
apiBaseUrl,
|
|
3762
|
+
setStreamKey,
|
|
3763
|
+
isReady: receivedDataRef.current
|
|
3764
|
+
};
|
|
3765
|
+
}
|
|
3766
|
+
function useDialtribeStreamerLauncher(options) {
|
|
3767
|
+
const {
|
|
3768
|
+
sessionToken,
|
|
3769
|
+
streamKey,
|
|
3770
|
+
streamerUrl,
|
|
3771
|
+
apiBaseUrl,
|
|
3772
|
+
fallback = "fullscreen",
|
|
3773
|
+
onPopupBlocked,
|
|
3774
|
+
onDone,
|
|
3775
|
+
onStreamKeyChange
|
|
3776
|
+
} = options;
|
|
3777
|
+
const [showFallback, setShowFallback] = React2.useState(false);
|
|
3778
|
+
const [wasBlocked, setWasBlocked] = React2.useState(false);
|
|
3779
|
+
const popupRef = React2.useRef(null);
|
|
3780
|
+
const sessionTokenRef = React2.useRef(sessionToken);
|
|
3781
|
+
const streamKeyRef = React2.useRef(streamKey);
|
|
3782
|
+
const apiBaseUrlRef = React2.useRef(apiBaseUrl);
|
|
3783
|
+
React2.useEffect(() => {
|
|
3784
|
+
sessionTokenRef.current = sessionToken;
|
|
3785
|
+
}, [sessionToken]);
|
|
3786
|
+
React2.useEffect(() => {
|
|
3787
|
+
streamKeyRef.current = streamKey;
|
|
3788
|
+
}, [streamKey]);
|
|
3789
|
+
React2.useEffect(() => {
|
|
3790
|
+
apiBaseUrlRef.current = apiBaseUrl;
|
|
3791
|
+
}, [apiBaseUrl]);
|
|
3792
|
+
React2.useEffect(() => {
|
|
3793
|
+
const handleMessage = (event) => {
|
|
3794
|
+
if (event.data?.type === "POPUP_READY" && popupRef.current) {
|
|
3795
|
+
popupRef.current.postMessage(
|
|
3796
|
+
{
|
|
3797
|
+
type: "STREAM_KEY",
|
|
3798
|
+
sessionToken: sessionTokenRef.current,
|
|
3799
|
+
streamKey: streamKeyRef.current,
|
|
3800
|
+
apiBaseUrl: apiBaseUrlRef.current
|
|
3801
|
+
},
|
|
3802
|
+
"*"
|
|
3803
|
+
);
|
|
3804
|
+
}
|
|
3805
|
+
};
|
|
3806
|
+
window.addEventListener("message", handleMessage);
|
|
3807
|
+
return () => window.removeEventListener("message", handleMessage);
|
|
3808
|
+
}, []);
|
|
3809
|
+
const launch = React2.useCallback(() => {
|
|
3810
|
+
if (!sessionToken) {
|
|
3811
|
+
console.warn("Cannot launch streamer: no session token");
|
|
3812
|
+
return;
|
|
3813
|
+
}
|
|
3814
|
+
setWasBlocked(false);
|
|
3815
|
+
const popup = openDialtribeStreamerPopup({
|
|
3816
|
+
sessionToken,
|
|
3817
|
+
streamKey,
|
|
3818
|
+
streamerUrl
|
|
3819
|
+
});
|
|
3820
|
+
if (popup) {
|
|
3821
|
+
popupRef.current = popup;
|
|
3822
|
+
return;
|
|
3823
|
+
}
|
|
3824
|
+
setWasBlocked(true);
|
|
3825
|
+
onPopupBlocked?.();
|
|
3826
|
+
switch (fallback) {
|
|
3827
|
+
case "fullscreen":
|
|
3828
|
+
setShowFallback(true);
|
|
3829
|
+
break;
|
|
3830
|
+
case "newTab":
|
|
3831
|
+
window.open(streamerUrl, "_blank");
|
|
3832
|
+
break;
|
|
3833
|
+
}
|
|
3834
|
+
}, [sessionToken, streamKey, streamerUrl, fallback, onPopupBlocked]);
|
|
3835
|
+
const closeFallback = React2.useCallback(() => {
|
|
3836
|
+
setShowFallback(false);
|
|
3837
|
+
onDone?.();
|
|
3838
|
+
}, [onDone]);
|
|
3839
|
+
const Fallback = React2.useCallback(() => {
|
|
3840
|
+
if (fallback !== "fullscreen" || !showFallback) {
|
|
3841
|
+
return null;
|
|
3842
|
+
}
|
|
3843
|
+
if (typeof document === "undefined") {
|
|
3844
|
+
return null;
|
|
3845
|
+
}
|
|
3846
|
+
const streamerElement = React2__default.default.createElement(DialtribeStreamer, {
|
|
3847
|
+
sessionToken: sessionToken || void 0,
|
|
3848
|
+
streamKey: streamKey || void 0,
|
|
3849
|
+
apiBaseUrl,
|
|
3850
|
+
onDone: closeFallback,
|
|
3851
|
+
onStreamKeyChange
|
|
3852
|
+
});
|
|
3853
|
+
const overlayElement = React2__default.default.createElement(
|
|
3854
|
+
DialtribeOverlay,
|
|
3855
|
+
{
|
|
3856
|
+
mode: "fullscreen",
|
|
3857
|
+
isOpen: true,
|
|
3858
|
+
onClose: closeFallback,
|
|
3859
|
+
children: streamerElement
|
|
3860
|
+
}
|
|
3861
|
+
);
|
|
3862
|
+
return reactDom.createPortal(overlayElement, document.body);
|
|
3863
|
+
}, [fallback, showFallback, closeFallback, sessionToken, streamKey, apiBaseUrl, onStreamKeyChange]);
|
|
3864
|
+
return {
|
|
3865
|
+
launch,
|
|
3866
|
+
Fallback,
|
|
3867
|
+
showFallback,
|
|
3868
|
+
closeFallback,
|
|
3869
|
+
popupRef: popupRef.current,
|
|
3870
|
+
wasBlocked
|
|
3871
|
+
};
|
|
3872
|
+
}
|
|
3745
3873
|
|
|
3746
3874
|
exports.AudioWaveform = AudioWaveform;
|
|
3747
|
-
exports.BroadcastPlayer = BroadcastPlayer;
|
|
3748
|
-
exports.BroadcastPlayerErrorBoundary = BroadcastPlayerErrorBoundary;
|
|
3749
|
-
exports.BroadcastPlayerModal = BroadcastPlayerModal;
|
|
3750
|
-
exports.BroadcastStreamer = BroadcastStreamer;
|
|
3751
3875
|
exports.CDN_DOMAIN = CDN_DOMAIN;
|
|
3752
3876
|
exports.DEFAULT_ENCODER_SERVER_URL = DEFAULT_ENCODER_SERVER_URL;
|
|
3753
3877
|
exports.DIALTRIBE_API_BASE = DIALTRIBE_API_BASE;
|
|
3754
|
-
exports.
|
|
3755
|
-
exports.
|
|
3878
|
+
exports.DialtribeClient = DialtribeClient;
|
|
3879
|
+
exports.DialtribeOverlay = DialtribeOverlay;
|
|
3880
|
+
exports.DialtribePlayer = DialtribePlayer;
|
|
3881
|
+
exports.DialtribePlayerErrorBoundary = DialtribePlayerErrorBoundary;
|
|
3882
|
+
exports.DialtribeProvider = DialtribeProvider;
|
|
3883
|
+
exports.DialtribeStreamer = DialtribeStreamer;
|
|
3756
3884
|
exports.ENDPOINTS = ENDPOINTS;
|
|
3757
3885
|
exports.HTTP_STATUS = HTTP_STATUS;
|
|
3758
3886
|
exports.HelloWorld = HelloWorld;
|
|
@@ -3770,7 +3898,9 @@ exports.formatTime = formatTime;
|
|
|
3770
3898
|
exports.getMediaConstraints = getMediaConstraints;
|
|
3771
3899
|
exports.getMediaRecorderOptions = getMediaRecorderOptions;
|
|
3772
3900
|
exports.openBroadcastPopup = openBroadcastPopup;
|
|
3773
|
-
exports.
|
|
3774
|
-
exports.
|
|
3901
|
+
exports.openDialtribeStreamerPopup = openDialtribeStreamerPopup;
|
|
3902
|
+
exports.useDialtribe = useDialtribe;
|
|
3903
|
+
exports.useDialtribeStreamerLauncher = useDialtribeStreamerLauncher;
|
|
3904
|
+
exports.useDialtribeStreamerPopup = useDialtribeStreamerPopup;
|
|
3775
3905
|
//# sourceMappingURL=index.js.map
|
|
3776
3906
|
//# sourceMappingURL=index.js.map
|