@dialtribe/react-sdk 0.1.0-alpha.11 → 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-DnnXgWin.d.mts → dialtribe-player-Rc9kfQiX.d.mts} +87 -87
- package/dist/{broadcast-player-DnnXgWin.d.ts → dialtribe-player-Rc9kfQiX.d.ts} +87 -87
- package/dist/dialtribe-player.d.mts +3 -0
- package/dist/dialtribe-player.d.ts +3 -0
- package/dist/{broadcast-player.js → dialtribe-player.js} +105 -108
- package/dist/dialtribe-player.js.map +1 -0
- package/dist/{broadcast-player.mjs → dialtribe-player.mjs} +100 -103
- 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} +386 -257
- package/dist/dialtribe-streamer.js.map +1 -0
- package/dist/{broadcast-streamer.mjs → dialtribe-streamer.mjs} +276 -150
- 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 +382 -253
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +273 -147
- 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
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React2 = require('react');
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
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
|
-
// src/context/
|
|
12
|
-
var
|
|
13
|
-
function
|
|
13
|
+
// src/context/DialtribeProvider.tsx
|
|
14
|
+
var DialtribeContext = React2.createContext(null);
|
|
15
|
+
function DialtribeProvider({
|
|
14
16
|
sessionToken: initialToken,
|
|
15
17
|
onTokenRefresh,
|
|
16
18
|
onTokenExpired,
|
|
17
19
|
apiBaseUrl,
|
|
18
20
|
children
|
|
19
21
|
}) {
|
|
20
|
-
const [sessionToken, setSessionTokenState] =
|
|
21
|
-
const [isExpired, setIsExpired] =
|
|
22
|
-
const setSessionToken =
|
|
22
|
+
const [sessionToken, setSessionTokenState] = React2.useState(initialToken);
|
|
23
|
+
const [isExpired, setIsExpired] = React2.useState(false);
|
|
24
|
+
const setSessionToken = React2.useCallback(
|
|
23
25
|
(newToken, expiresAt) => {
|
|
24
26
|
setSessionTokenState(newToken);
|
|
25
27
|
setIsExpired(false);
|
|
@@ -29,11 +31,11 @@ function DialTribeProvider({
|
|
|
29
31
|
},
|
|
30
32
|
[onTokenRefresh]
|
|
31
33
|
);
|
|
32
|
-
const markExpired =
|
|
34
|
+
const markExpired = React2.useCallback(() => {
|
|
33
35
|
setIsExpired(true);
|
|
34
36
|
onTokenExpired?.();
|
|
35
37
|
}, [onTokenExpired]);
|
|
36
|
-
|
|
38
|
+
React2.useEffect(() => {
|
|
37
39
|
if (initialToken !== sessionToken) {
|
|
38
40
|
setSessionTokenState(initialToken);
|
|
39
41
|
setIsExpired(false);
|
|
@@ -46,22 +48,22 @@ function DialTribeProvider({
|
|
|
46
48
|
markExpired,
|
|
47
49
|
apiBaseUrl
|
|
48
50
|
};
|
|
49
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
51
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DialtribeContext.Provider, { value, children });
|
|
50
52
|
}
|
|
51
|
-
function
|
|
52
|
-
const context =
|
|
53
|
+
function useDialtribe() {
|
|
54
|
+
const context = React2.useContext(DialtribeContext);
|
|
53
55
|
if (!context) {
|
|
54
56
|
throw new Error(
|
|
55
|
-
'
|
|
57
|
+
'useDialtribe must be used within a DialtribeProvider. Wrap your app with <DialtribeProvider sessionToken="sess_xxx">...</DialtribeProvider>'
|
|
56
58
|
);
|
|
57
59
|
}
|
|
58
60
|
return context;
|
|
59
61
|
}
|
|
60
|
-
function
|
|
61
|
-
return
|
|
62
|
+
function useDialtribeOptional() {
|
|
63
|
+
return React2.useContext(DialtribeContext);
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
// src/client/
|
|
66
|
+
// src/client/DialtribeClient.ts
|
|
65
67
|
function getDefaultApiBaseUrl() {
|
|
66
68
|
if (typeof process !== "undefined" && process.env?.NEXT_PUBLIC_DIALTRIBE_API_URL) {
|
|
67
69
|
return process.env.NEXT_PUBLIC_DIALTRIBE_API_URL;
|
|
@@ -81,13 +83,13 @@ function getEndpoints(baseUrl = DIALTRIBE_API_BASE) {
|
|
|
81
83
|
};
|
|
82
84
|
}
|
|
83
85
|
var ENDPOINTS = getEndpoints();
|
|
84
|
-
var
|
|
86
|
+
var DialtribeClient = class {
|
|
85
87
|
constructor(config) {
|
|
86
88
|
this.config = config;
|
|
87
89
|
this.endpoints = config.apiBaseUrl ? getEndpoints(config.apiBaseUrl) : ENDPOINTS;
|
|
88
90
|
}
|
|
89
91
|
/**
|
|
90
|
-
* Make an authenticated request to
|
|
92
|
+
* Make an authenticated request to Dialtribe API
|
|
91
93
|
*
|
|
92
94
|
* Automatically:
|
|
93
95
|
* - Adds Authorization header with session token
|
|
@@ -531,18 +533,18 @@ function AudioWaveform({
|
|
|
531
533
|
isPlaying = false,
|
|
532
534
|
isLive = false
|
|
533
535
|
}) {
|
|
534
|
-
const canvasRef =
|
|
535
|
-
const animationFrameRef =
|
|
536
|
-
const [setupError, setSetupError] =
|
|
537
|
-
const isPlayingRef =
|
|
538
|
-
const isLiveRef =
|
|
539
|
-
|
|
536
|
+
const canvasRef = React2.useRef(null);
|
|
537
|
+
const animationFrameRef = React2.useRef(void 0);
|
|
538
|
+
const [setupError, setSetupError] = React2.useState(false);
|
|
539
|
+
const isPlayingRef = React2.useRef(isPlaying);
|
|
540
|
+
const isLiveRef = React2.useRef(isLive);
|
|
541
|
+
React2.useEffect(() => {
|
|
540
542
|
isPlayingRef.current = isPlaying;
|
|
541
543
|
}, [isPlaying]);
|
|
542
|
-
|
|
544
|
+
React2.useEffect(() => {
|
|
543
545
|
isLiveRef.current = isLive;
|
|
544
546
|
}, [isLive]);
|
|
545
|
-
|
|
547
|
+
React2.useEffect(() => {
|
|
546
548
|
const canvas = canvasRef.current;
|
|
547
549
|
if (!canvas) return;
|
|
548
550
|
const ctx = canvas.getContext("2d");
|
|
@@ -972,8 +974,8 @@ function StreamKeyDisplay({
|
|
|
972
974
|
layout = "vertical",
|
|
973
975
|
darkMode = false
|
|
974
976
|
}) {
|
|
975
|
-
const [isRevealed, setIsRevealed] =
|
|
976
|
-
const [copySuccess, setCopySuccess] =
|
|
977
|
+
const [isRevealed, setIsRevealed] = React2.useState(false);
|
|
978
|
+
const [copySuccess, setCopySuccess] = React2.useState(false);
|
|
977
979
|
const obscureStreamKey = (key) => {
|
|
978
980
|
if (key.length <= 12) {
|
|
979
981
|
return "\u2022".repeat(key.length);
|
|
@@ -1081,9 +1083,9 @@ function StreamingControls({
|
|
|
1081
1083
|
onAudioDeviceChange,
|
|
1082
1084
|
mediaStream
|
|
1083
1085
|
}) {
|
|
1084
|
-
const [duration, setDuration] =
|
|
1085
|
-
const [showSettings, setShowSettings] =
|
|
1086
|
-
|
|
1086
|
+
const [duration, setDuration] = React2.useState(0);
|
|
1087
|
+
const [showSettings, setShowSettings] = React2.useState(false);
|
|
1088
|
+
React2.useEffect(() => {
|
|
1087
1089
|
if (state !== "live" || !startTime) return;
|
|
1088
1090
|
const interval = setInterval(() => {
|
|
1089
1091
|
const elapsed = Math.floor((Date.now() - startTime.getTime()) / 1e3);
|
|
@@ -1416,8 +1418,8 @@ function StreamingControls({
|
|
|
1416
1418
|
] });
|
|
1417
1419
|
}
|
|
1418
1420
|
function StreamKeyInput({ onSubmit, inline = false }) {
|
|
1419
|
-
const [streamKey, setStreamKey] =
|
|
1420
|
-
const [error, setError] =
|
|
1421
|
+
const [streamKey, setStreamKey] = React2.useState("");
|
|
1422
|
+
const [error, setError] = React2.useState("");
|
|
1421
1423
|
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";
|
|
1422
1424
|
const validateStreamKey = (key) => {
|
|
1423
1425
|
const pattern = /^[abvw][a-zA-Z0-9]+_.+$/;
|
|
@@ -1483,7 +1485,7 @@ function StreamKeyInput({ onSubmit, inline = false }) {
|
|
|
1483
1485
|
] })
|
|
1484
1486
|
] }) });
|
|
1485
1487
|
}
|
|
1486
|
-
function
|
|
1488
|
+
function DialtribeStreamer({
|
|
1487
1489
|
sessionToken: propSessionToken,
|
|
1488
1490
|
streamKey: initialStreamKey,
|
|
1489
1491
|
onDone,
|
|
@@ -1492,35 +1494,35 @@ function BroadcastStreamer({
|
|
|
1492
1494
|
apiBaseUrl = DIALTRIBE_API_BASE,
|
|
1493
1495
|
inline = false
|
|
1494
1496
|
}) {
|
|
1495
|
-
const containerClass = inline ? "dialtribe-
|
|
1496
|
-
const centeredContainerClass = inline ? "dialtribe-
|
|
1497
|
-
const dialTribeContext =
|
|
1497
|
+
const containerClass = inline ? "dialtribe-dialtribe-streamer h-full w-full bg-black relative" : "dialtribe-dialtribe-streamer min-h-screen bg-black";
|
|
1498
|
+
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";
|
|
1499
|
+
const dialTribeContext = useDialtribeOptional();
|
|
1498
1500
|
const sessionToken = propSessionToken ?? dialTribeContext?.sessionToken ?? null;
|
|
1499
|
-
const [streamKey, setStreamKey] =
|
|
1500
|
-
const [state, setState] =
|
|
1501
|
-
|
|
1501
|
+
const [streamKey, setStreamKey] = React2.useState(initialStreamKey || null);
|
|
1502
|
+
const [state, setState] = React2.useState("idle");
|
|
1503
|
+
React2.useEffect(() => {
|
|
1502
1504
|
if (initialStreamKey && initialStreamKey !== streamKey) {
|
|
1503
1505
|
setStreamKey(initialStreamKey);
|
|
1504
1506
|
}
|
|
1505
1507
|
}, [initialStreamKey]);
|
|
1506
|
-
const [error, setError] =
|
|
1507
|
-
const [mediaStream, setMediaStream] =
|
|
1508
|
-
const [streamer, setStreamer] =
|
|
1509
|
-
const [bytesSent, setBytesSent] =
|
|
1510
|
-
const [startTime, setStartTime] =
|
|
1511
|
-
const [isMuted, setIsMuted] =
|
|
1512
|
-
const [isVideoEnabled, setIsVideoEnabled] =
|
|
1513
|
-
const [facingMode, setFacingMode] =
|
|
1514
|
-
const [showStopConfirm, setShowStopConfirm] =
|
|
1515
|
-
const [showCloseConfirm, setShowCloseConfirm] =
|
|
1516
|
-
const [hasMultipleCameras, setHasMultipleCameras] =
|
|
1517
|
-
const [videoDevices, setVideoDevices] =
|
|
1518
|
-
const [audioDevices, setAudioDevices] =
|
|
1519
|
-
const [selectedVideoDeviceId, setSelectedVideoDeviceId] =
|
|
1520
|
-
const [selectedAudioDeviceId, setSelectedAudioDeviceId] =
|
|
1521
|
-
const videoRef =
|
|
1522
|
-
const streamerRef =
|
|
1523
|
-
const mediaStreamRef =
|
|
1508
|
+
const [error, setError] = React2.useState(null);
|
|
1509
|
+
const [mediaStream, setMediaStream] = React2.useState(null);
|
|
1510
|
+
const [streamer, setStreamer] = React2.useState(null);
|
|
1511
|
+
const [bytesSent, setBytesSent] = React2.useState(0);
|
|
1512
|
+
const [startTime, setStartTime] = React2.useState(null);
|
|
1513
|
+
const [isMuted, setIsMuted] = React2.useState(false);
|
|
1514
|
+
const [isVideoEnabled, setIsVideoEnabled] = React2.useState(true);
|
|
1515
|
+
const [facingMode, setFacingMode] = React2.useState("user");
|
|
1516
|
+
const [showStopConfirm, setShowStopConfirm] = React2.useState(false);
|
|
1517
|
+
const [showCloseConfirm, setShowCloseConfirm] = React2.useState(false);
|
|
1518
|
+
const [hasMultipleCameras, setHasMultipleCameras] = React2.useState(false);
|
|
1519
|
+
const [videoDevices, setVideoDevices] = React2.useState([]);
|
|
1520
|
+
const [audioDevices, setAudioDevices] = React2.useState([]);
|
|
1521
|
+
const [selectedVideoDeviceId, setSelectedVideoDeviceId] = React2.useState();
|
|
1522
|
+
const [selectedAudioDeviceId, setSelectedAudioDeviceId] = React2.useState();
|
|
1523
|
+
const videoRef = React2.useRef(null);
|
|
1524
|
+
const streamerRef = React2.useRef(null);
|
|
1525
|
+
const mediaStreamRef = React2.useRef(null);
|
|
1524
1526
|
const isVideoKey = streamKey ? streamKey.startsWith("v") || streamKey.startsWith("w") : false;
|
|
1525
1527
|
const handleStreamKeySubmit = (key) => {
|
|
1526
1528
|
setStreamKey(key);
|
|
@@ -1530,7 +1532,7 @@ function BroadcastStreamer({
|
|
|
1530
1532
|
setStreamKey(key);
|
|
1531
1533
|
onStreamKeyChange?.(key);
|
|
1532
1534
|
};
|
|
1533
|
-
|
|
1535
|
+
React2.useEffect(() => {
|
|
1534
1536
|
if (!streamKey) return;
|
|
1535
1537
|
const compat = checkBrowserCompatibility();
|
|
1536
1538
|
if (!compat.compatible) {
|
|
@@ -1568,13 +1570,13 @@ function BroadcastStreamer({
|
|
|
1568
1570
|
setHasMultipleCameras(false);
|
|
1569
1571
|
}
|
|
1570
1572
|
};
|
|
1571
|
-
|
|
1573
|
+
React2.useEffect(() => {
|
|
1572
1574
|
streamerRef.current = streamer;
|
|
1573
1575
|
}, [streamer]);
|
|
1574
|
-
|
|
1576
|
+
React2.useEffect(() => {
|
|
1575
1577
|
mediaStreamRef.current = mediaStream;
|
|
1576
1578
|
}, [mediaStream]);
|
|
1577
|
-
|
|
1579
|
+
React2.useEffect(() => {
|
|
1578
1580
|
return () => {
|
|
1579
1581
|
if (streamerRef.current) {
|
|
1580
1582
|
streamerRef.current.stop();
|
|
@@ -1584,7 +1586,7 @@ function BroadcastStreamer({
|
|
|
1584
1586
|
}
|
|
1585
1587
|
};
|
|
1586
1588
|
}, []);
|
|
1587
|
-
|
|
1589
|
+
React2.useEffect(() => {
|
|
1588
1590
|
if (state === "live") {
|
|
1589
1591
|
const handleBeforeUnload = (e) => {
|
|
1590
1592
|
e.preventDefault();
|
|
@@ -1595,7 +1597,7 @@ function BroadcastStreamer({
|
|
|
1595
1597
|
return () => window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
1596
1598
|
}
|
|
1597
1599
|
}, [state]);
|
|
1598
|
-
|
|
1600
|
+
React2.useEffect(() => {
|
|
1599
1601
|
if (videoRef.current && mediaStream) {
|
|
1600
1602
|
videoRef.current.srcObject = mediaStream;
|
|
1601
1603
|
}
|
|
@@ -1878,36 +1880,9 @@ function BroadcastStreamer({
|
|
|
1878
1880
|
}
|
|
1879
1881
|
};
|
|
1880
1882
|
if (!sessionToken) {
|
|
1881
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: centeredContainerClass, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
1882
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-16
|
|
1883
|
-
|
|
1884
|
-
{
|
|
1885
|
-
className: "w-8 h-8 text-red-600 dark:text-red-400",
|
|
1886
|
-
fill: "none",
|
|
1887
|
-
stroke: "currentColor",
|
|
1888
|
-
viewBox: "0 0 24 24",
|
|
1889
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1890
|
-
"path",
|
|
1891
|
-
{
|
|
1892
|
-
strokeLinecap: "round",
|
|
1893
|
-
strokeLinejoin: "round",
|
|
1894
|
-
strokeWidth: 2,
|
|
1895
|
-
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"
|
|
1896
|
-
}
|
|
1897
|
-
)
|
|
1898
|
-
}
|
|
1899
|
-
) }),
|
|
1900
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-bold text-black dark:text-white mb-2", children: "Authentication Required" }),
|
|
1901
|
-
/* @__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." }),
|
|
1902
|
-
/* @__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." }),
|
|
1903
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1904
|
-
"button",
|
|
1905
|
-
{
|
|
1906
|
-
onClick: handleDone,
|
|
1907
|
-
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",
|
|
1908
|
-
children: "Close"
|
|
1909
|
-
}
|
|
1910
|
-
)
|
|
1883
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: centeredContainerClass, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
1884
|
+
/* @__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" }),
|
|
1885
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-white text-lg", children: "Connecting..." })
|
|
1911
1886
|
] }) });
|
|
1912
1887
|
}
|
|
1913
1888
|
if (!streamKey) {
|
|
@@ -2240,7 +2215,7 @@ function getErrorMessage(error) {
|
|
|
2240
2215
|
}
|
|
2241
2216
|
return "Unable to play media. Please try refreshing the page or contact support if the problem persists.";
|
|
2242
2217
|
}
|
|
2243
|
-
function
|
|
2218
|
+
function DialtribePlayer({
|
|
2244
2219
|
broadcast,
|
|
2245
2220
|
appId,
|
|
2246
2221
|
contentId,
|
|
@@ -2251,18 +2226,18 @@ function BroadcastPlayer({
|
|
|
2251
2226
|
className = "",
|
|
2252
2227
|
enableKeyboardShortcuts = false
|
|
2253
2228
|
}) {
|
|
2254
|
-
const { sessionToken, setSessionToken, markExpired, apiBaseUrl } =
|
|
2255
|
-
const clientRef =
|
|
2229
|
+
const { sessionToken, setSessionToken, markExpired, apiBaseUrl } = useDialtribe();
|
|
2230
|
+
const clientRef = React2.useRef(null);
|
|
2256
2231
|
if (!clientRef.current && sessionToken) {
|
|
2257
|
-
clientRef.current = new
|
|
2232
|
+
clientRef.current = new DialtribeClient({
|
|
2258
2233
|
sessionToken,
|
|
2259
2234
|
apiBaseUrl,
|
|
2260
2235
|
onTokenRefresh: (newToken, expiresAt) => {
|
|
2261
|
-
debug.log(`[
|
|
2236
|
+
debug.log(`[DialtribeClient] Token refreshed, expires at ${expiresAt}`);
|
|
2262
2237
|
setSessionToken(newToken, expiresAt);
|
|
2263
2238
|
},
|
|
2264
2239
|
onTokenExpired: () => {
|
|
2265
|
-
debug.error("[
|
|
2240
|
+
debug.error("[DialtribeClient] Token expired");
|
|
2266
2241
|
markExpired();
|
|
2267
2242
|
}
|
|
2268
2243
|
});
|
|
@@ -2270,35 +2245,35 @@ function BroadcastPlayer({
|
|
|
2270
2245
|
clientRef.current.setSessionToken(sessionToken);
|
|
2271
2246
|
}
|
|
2272
2247
|
const client = clientRef.current;
|
|
2273
|
-
const playerRef =
|
|
2274
|
-
const transcriptContainerRef =
|
|
2275
|
-
const activeWordRef =
|
|
2276
|
-
const [audioElement, setAudioElement] =
|
|
2277
|
-
const [playing, setPlaying] =
|
|
2278
|
-
const [played, setPlayed] =
|
|
2279
|
-
const [duration, setDuration] =
|
|
2280
|
-
const [volume, setVolume] =
|
|
2281
|
-
const [muted, setMuted] =
|
|
2282
|
-
const [seeking, setSeeking] =
|
|
2283
|
-
const [hasError, setHasError] =
|
|
2284
|
-
const [errorMessage, setErrorMessage] =
|
|
2285
|
-
const [hasEnded, setHasEnded] =
|
|
2286
|
-
const [hasStreamEnded, setHasStreamEnded] =
|
|
2287
|
-
const [showTranscript, setShowTranscript] =
|
|
2288
|
-
const [transcriptData, setTranscriptData] =
|
|
2289
|
-
const [currentTime, setCurrentTime] =
|
|
2290
|
-
const [isLoadingTranscript, setIsLoadingTranscript] =
|
|
2291
|
-
const [isLoadingVideo, setIsLoadingVideo] =
|
|
2292
|
-
const [autoScrollEnabled, setAutoScrollEnabled] =
|
|
2293
|
-
const isScrollingProgrammatically =
|
|
2294
|
-
const lastActiveWordIndex =
|
|
2295
|
-
const [showClipCreator, setShowClipCreator] =
|
|
2296
|
-
const initialPlaybackTypeRef =
|
|
2297
|
-
const [currentPlaybackInfo, setCurrentPlaybackInfo] =
|
|
2298
|
-
const [urlExpiresAt, setUrlExpiresAt] =
|
|
2299
|
-
const isRefreshingUrl =
|
|
2300
|
-
const [audienceId, setAudienceId] =
|
|
2301
|
-
const [sessionId] =
|
|
2248
|
+
const playerRef = React2.useRef(null);
|
|
2249
|
+
const transcriptContainerRef = React2.useRef(null);
|
|
2250
|
+
const activeWordRef = React2.useRef(null);
|
|
2251
|
+
const [audioElement, setAudioElement] = React2.useState(null);
|
|
2252
|
+
const [playing, setPlaying] = React2.useState(false);
|
|
2253
|
+
const [played, setPlayed] = React2.useState(0);
|
|
2254
|
+
const [duration, setDuration] = React2.useState(0);
|
|
2255
|
+
const [volume, setVolume] = React2.useState(1);
|
|
2256
|
+
const [muted, setMuted] = React2.useState(false);
|
|
2257
|
+
const [seeking, setSeeking] = React2.useState(false);
|
|
2258
|
+
const [hasError, setHasError] = React2.useState(false);
|
|
2259
|
+
const [errorMessage, setErrorMessage] = React2.useState("");
|
|
2260
|
+
const [hasEnded, setHasEnded] = React2.useState(false);
|
|
2261
|
+
const [hasStreamEnded, setHasStreamEnded] = React2.useState(false);
|
|
2262
|
+
const [showTranscript, setShowTranscript] = React2.useState(false);
|
|
2263
|
+
const [transcriptData, setTranscriptData] = React2.useState(null);
|
|
2264
|
+
const [currentTime, setCurrentTime] = React2.useState(0);
|
|
2265
|
+
const [isLoadingTranscript, setIsLoadingTranscript] = React2.useState(false);
|
|
2266
|
+
const [isLoadingVideo, setIsLoadingVideo] = React2.useState(true);
|
|
2267
|
+
const [autoScrollEnabled, setAutoScrollEnabled] = React2.useState(true);
|
|
2268
|
+
const isScrollingProgrammatically = React2.useRef(false);
|
|
2269
|
+
const lastActiveWordIndex = React2.useRef(-1);
|
|
2270
|
+
const [showClipCreator, setShowClipCreator] = React2.useState(false);
|
|
2271
|
+
const initialPlaybackTypeRef = React2.useRef(null);
|
|
2272
|
+
const [currentPlaybackInfo, setCurrentPlaybackInfo] = React2.useState(null);
|
|
2273
|
+
const [urlExpiresAt, setUrlExpiresAt] = React2.useState(null);
|
|
2274
|
+
const isRefreshingUrl = React2.useRef(false);
|
|
2275
|
+
const [audienceId, setAudienceId] = React2.useState(null);
|
|
2276
|
+
const [sessionId] = React2.useState(() => {
|
|
2302
2277
|
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
2303
2278
|
return crypto.randomUUID();
|
|
2304
2279
|
}
|
|
@@ -2308,9 +2283,9 @@ function BroadcastPlayer({
|
|
|
2308
2283
|
return v.toString(16);
|
|
2309
2284
|
});
|
|
2310
2285
|
});
|
|
2311
|
-
const heartbeatIntervalRef =
|
|
2312
|
-
const hasInitializedSession =
|
|
2313
|
-
const refreshPresignedUrl =
|
|
2286
|
+
const heartbeatIntervalRef = React2.useRef(null);
|
|
2287
|
+
const hasInitializedSession = React2.useRef(false);
|
|
2288
|
+
const refreshPresignedUrl = React2.useCallback(
|
|
2314
2289
|
async (fileType) => {
|
|
2315
2290
|
if (!broadcast.hash || isRefreshingUrl.current || !client) {
|
|
2316
2291
|
debug.log("[URL Refresh] Skipping refresh - no hash, already refreshing, or no client");
|
|
@@ -2361,7 +2336,7 @@ function BroadcastPlayer({
|
|
|
2361
2336
|
if (width < 1024) return "tablet";
|
|
2362
2337
|
return "desktop";
|
|
2363
2338
|
};
|
|
2364
|
-
const initializeTrackingSession =
|
|
2339
|
+
const initializeTrackingSession = React2.useCallback(async () => {
|
|
2365
2340
|
if (!contentId || !appId || !client) return;
|
|
2366
2341
|
if (currentPlaybackInfo?.type === "hls" && broadcast.broadcastStatus === 1) return;
|
|
2367
2342
|
if (hasInitializedSession.current) return;
|
|
@@ -2396,7 +2371,7 @@ function BroadcastPlayer({
|
|
|
2396
2371
|
}
|
|
2397
2372
|
}
|
|
2398
2373
|
}, [contentId, appId, broadcast.id, broadcast.broadcastStatus, foreignId, foreignTier, sessionId, currentPlaybackInfo?.type, audioElement, client, onError]);
|
|
2399
|
-
const sendTrackingPing =
|
|
2374
|
+
const sendTrackingPing = React2.useCallback(
|
|
2400
2375
|
async (eventType) => {
|
|
2401
2376
|
if (!audienceId || !sessionId || !client) return;
|
|
2402
2377
|
try {
|
|
@@ -2434,7 +2409,7 @@ function BroadcastPlayer({
|
|
|
2434
2409
|
}
|
|
2435
2410
|
return null;
|
|
2436
2411
|
};
|
|
2437
|
-
|
|
2412
|
+
React2.useEffect(() => {
|
|
2438
2413
|
if (!currentPlaybackInfo) {
|
|
2439
2414
|
const info = getPlaybackInfo();
|
|
2440
2415
|
setCurrentPlaybackInfo(info);
|
|
@@ -2450,12 +2425,12 @@ function BroadcastPlayer({
|
|
|
2450
2425
|
}
|
|
2451
2426
|
}
|
|
2452
2427
|
}, [currentPlaybackInfo]);
|
|
2453
|
-
|
|
2428
|
+
React2.useEffect(() => {
|
|
2454
2429
|
if (currentPlaybackInfo?.url) {
|
|
2455
2430
|
setIsLoadingVideo(true);
|
|
2456
2431
|
}
|
|
2457
2432
|
}, [currentPlaybackInfo?.url]);
|
|
2458
|
-
|
|
2433
|
+
React2.useEffect(() => {
|
|
2459
2434
|
if (!urlExpiresAt || !currentPlaybackInfo?.type) return;
|
|
2460
2435
|
const checkExpiration = () => {
|
|
2461
2436
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -2474,7 +2449,7 @@ function BroadcastPlayer({
|
|
|
2474
2449
|
clearInterval(interval);
|
|
2475
2450
|
};
|
|
2476
2451
|
}, [urlExpiresAt, currentPlaybackInfo?.type, refreshPresignedUrl]);
|
|
2477
|
-
|
|
2452
|
+
React2.useEffect(() => {
|
|
2478
2453
|
if (initialPlaybackTypeRef.current === "hls" && currentPlaybackInfo?.type === "hls" && broadcast.broadcastStatus !== 1 && broadcast.recordingMp3Url && broadcast.hash && parseInt(broadcast.mp3Size || "0") > 0) {
|
|
2479
2454
|
const secureUrl = buildPlaybackUrl(broadcast.id, broadcast.hash);
|
|
2480
2455
|
setCurrentPlaybackInfo({ url: secureUrl, type: "mp3" });
|
|
@@ -2510,22 +2485,22 @@ function BroadcastPlayer({
|
|
|
2510
2485
|
setHasEnded(true);
|
|
2511
2486
|
}
|
|
2512
2487
|
};
|
|
2513
|
-
|
|
2488
|
+
React2.useEffect(() => {
|
|
2514
2489
|
if (broadcast.durationSeconds && broadcast.durationSeconds > 0) {
|
|
2515
2490
|
setDuration(broadcast.durationSeconds);
|
|
2516
2491
|
}
|
|
2517
2492
|
}, [broadcast.durationSeconds]);
|
|
2518
|
-
|
|
2493
|
+
React2.useEffect(() => {
|
|
2519
2494
|
if (isLiveStream && !playing) {
|
|
2520
2495
|
setPlaying(true);
|
|
2521
2496
|
}
|
|
2522
2497
|
}, [isLiveStream, playing]);
|
|
2523
|
-
|
|
2498
|
+
React2.useEffect(() => {
|
|
2524
2499
|
if (currentPlaybackInfo && audioElement && !hasInitializedSession.current) {
|
|
2525
2500
|
initializeTrackingSession();
|
|
2526
2501
|
}
|
|
2527
2502
|
}, [currentPlaybackInfo, audioElement, initializeTrackingSession]);
|
|
2528
|
-
|
|
2503
|
+
React2.useEffect(() => {
|
|
2529
2504
|
if (playing && audienceId) {
|
|
2530
2505
|
sendTrackingPing(1);
|
|
2531
2506
|
heartbeatIntervalRef.current = setInterval(() => {
|
|
@@ -2545,7 +2520,7 @@ function BroadcastPlayer({
|
|
|
2545
2520
|
}
|
|
2546
2521
|
}
|
|
2547
2522
|
}, [playing, audienceId, sendTrackingPing]);
|
|
2548
|
-
|
|
2523
|
+
React2.useEffect(() => {
|
|
2549
2524
|
return () => {
|
|
2550
2525
|
if (audienceId && sessionId && sessionToken) {
|
|
2551
2526
|
const payload = {
|
|
@@ -2570,7 +2545,7 @@ function BroadcastPlayer({
|
|
|
2570
2545
|
}
|
|
2571
2546
|
};
|
|
2572
2547
|
}, [audienceId, sessionId, sessionToken, audioElement, duration]);
|
|
2573
|
-
|
|
2548
|
+
React2.useEffect(() => {
|
|
2574
2549
|
if (broadcast.transcriptUrl && broadcast.transcriptStatus === 2 && !transcriptData) {
|
|
2575
2550
|
setIsLoadingTranscript(true);
|
|
2576
2551
|
fetch(broadcast.transcriptUrl).then((res) => {
|
|
@@ -2601,7 +2576,7 @@ function BroadcastPlayer({
|
|
|
2601
2576
|
});
|
|
2602
2577
|
}
|
|
2603
2578
|
}, [broadcast.transcriptUrl, broadcast.transcriptStatus, transcriptData]);
|
|
2604
|
-
|
|
2579
|
+
React2.useEffect(() => {
|
|
2605
2580
|
if (!audioElement) return;
|
|
2606
2581
|
const handleTimeUpdate2 = () => {
|
|
2607
2582
|
setCurrentTime(audioElement.currentTime);
|
|
@@ -2609,7 +2584,7 @@ function BroadcastPlayer({
|
|
|
2609
2584
|
audioElement.addEventListener("timeupdate", handleTimeUpdate2);
|
|
2610
2585
|
return () => audioElement.removeEventListener("timeupdate", handleTimeUpdate2);
|
|
2611
2586
|
}, [audioElement]);
|
|
2612
|
-
|
|
2587
|
+
React2.useEffect(() => {
|
|
2613
2588
|
if (showTranscript && autoScrollEnabled && activeWordRef.current && transcriptContainerRef.current) {
|
|
2614
2589
|
const container = transcriptContainerRef.current;
|
|
2615
2590
|
const activeWord = activeWordRef.current;
|
|
@@ -2624,7 +2599,7 @@ function BroadcastPlayer({
|
|
|
2624
2599
|
}
|
|
2625
2600
|
}
|
|
2626
2601
|
}, [currentTime, showTranscript, autoScrollEnabled]);
|
|
2627
|
-
|
|
2602
|
+
React2.useEffect(() => {
|
|
2628
2603
|
if (!showTranscript || !transcriptContainerRef.current) return;
|
|
2629
2604
|
const container = transcriptContainerRef.current;
|
|
2630
2605
|
const handleScroll = () => {
|
|
@@ -2707,10 +2682,10 @@ function BroadcastPlayer({
|
|
|
2707
2682
|
setAudioElement(internalPlayer);
|
|
2708
2683
|
}
|
|
2709
2684
|
} catch (error) {
|
|
2710
|
-
debug.error("[
|
|
2685
|
+
debug.error("[DialtribePlayer] Error getting internal player:", error);
|
|
2711
2686
|
}
|
|
2712
2687
|
};
|
|
2713
|
-
|
|
2688
|
+
React2.useEffect(() => {
|
|
2714
2689
|
const findAudioElement = () => {
|
|
2715
2690
|
const videoElements = document.querySelectorAll("video, audio");
|
|
2716
2691
|
if (videoElements.length > 0) {
|
|
@@ -2730,7 +2705,7 @@ function BroadcastPlayer({
|
|
|
2730
2705
|
return () => timeouts.forEach(clearTimeout);
|
|
2731
2706
|
}
|
|
2732
2707
|
}, [playbackUrl]);
|
|
2733
|
-
|
|
2708
|
+
React2.useEffect(() => {
|
|
2734
2709
|
if (playing && !audioElement) {
|
|
2735
2710
|
const videoElements = document.querySelectorAll("video, audio");
|
|
2736
2711
|
if (videoElements.length > 0) {
|
|
@@ -2809,7 +2784,7 @@ function BroadcastPlayer({
|
|
|
2809
2784
|
onError(error);
|
|
2810
2785
|
}
|
|
2811
2786
|
};
|
|
2812
|
-
const handleRetry =
|
|
2787
|
+
const handleRetry = React2.useCallback(() => {
|
|
2813
2788
|
setHasError(false);
|
|
2814
2789
|
setErrorMessage("");
|
|
2815
2790
|
setIsLoadingVideo(true);
|
|
@@ -2832,7 +2807,7 @@ function BroadcastPlayer({
|
|
|
2832
2807
|
}
|
|
2833
2808
|
}
|
|
2834
2809
|
};
|
|
2835
|
-
|
|
2810
|
+
React2.useEffect(() => {
|
|
2836
2811
|
if (!enableKeyboardShortcuts) return;
|
|
2837
2812
|
const seekBy = (seconds) => {
|
|
2838
2813
|
if (!audioElement || duration <= 0) return;
|
|
@@ -2915,7 +2890,7 @@ function BroadcastPlayer({
|
|
|
2915
2890
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center p-8", children: /* @__PURE__ */ jsxRuntime.jsx(LoadingSpinner, { variant: "white", text: "Loading..." }) });
|
|
2916
2891
|
}
|
|
2917
2892
|
const hasTranscript = broadcast.transcriptStatus === 2 && transcriptData && (transcriptData.segments && transcriptData.segments.some((s) => s.words && s.words.length > 0) || transcriptData.words && transcriptData.words.length > 0);
|
|
2918
|
-
|
|
2893
|
+
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: [
|
|
2919
2894
|
/* @__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: [
|
|
2920
2895
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2921
2896
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-white", children: broadcast.streamKeyRecord?.foreignName || "Broadcast" }),
|
|
@@ -3447,90 +3422,9 @@ function BroadcastPlayer({
|
|
|
3447
3422
|
}
|
|
3448
3423
|
` })
|
|
3449
3424
|
] });
|
|
3425
|
+
return playerContent;
|
|
3450
3426
|
}
|
|
3451
|
-
|
|
3452
|
-
broadcast,
|
|
3453
|
-
isOpen,
|
|
3454
|
-
onClose,
|
|
3455
|
-
appId,
|
|
3456
|
-
contentId,
|
|
3457
|
-
foreignId,
|
|
3458
|
-
foreignTier,
|
|
3459
|
-
renderClipCreator,
|
|
3460
|
-
className,
|
|
3461
|
-
enableKeyboardShortcuts = false
|
|
3462
|
-
}) {
|
|
3463
|
-
const closeButtonRef = react.useRef(null);
|
|
3464
|
-
const previousActiveElement = react.useRef(null);
|
|
3465
|
-
react.useEffect(() => {
|
|
3466
|
-
if (!isOpen) return;
|
|
3467
|
-
previousActiveElement.current = document.activeElement;
|
|
3468
|
-
setTimeout(() => {
|
|
3469
|
-
closeButtonRef.current?.focus();
|
|
3470
|
-
}, 100);
|
|
3471
|
-
return () => {
|
|
3472
|
-
if (previousActiveElement.current) {
|
|
3473
|
-
previousActiveElement.current.focus();
|
|
3474
|
-
}
|
|
3475
|
-
};
|
|
3476
|
-
}, [isOpen]);
|
|
3477
|
-
react.useEffect(() => {
|
|
3478
|
-
if (!isOpen) return;
|
|
3479
|
-
const handleKeyDown = (e) => {
|
|
3480
|
-
if (e.key === "Escape") {
|
|
3481
|
-
onClose();
|
|
3482
|
-
}
|
|
3483
|
-
};
|
|
3484
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
3485
|
-
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
3486
|
-
}, [isOpen, onClose]);
|
|
3487
|
-
if (!isOpen) return null;
|
|
3488
|
-
const handleBackdropClick = (e) => {
|
|
3489
|
-
if (e.target === e.currentTarget) {
|
|
3490
|
-
onClose();
|
|
3491
|
-
}
|
|
3492
|
-
};
|
|
3493
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3494
|
-
"div",
|
|
3495
|
-
{
|
|
3496
|
-
className: "fixed inset-0 bg-black/70 backdrop-blur-xl flex items-center justify-center z-50 p-2 sm:p-4",
|
|
3497
|
-
onClick: handleBackdropClick,
|
|
3498
|
-
role: "dialog",
|
|
3499
|
-
"aria-modal": "true",
|
|
3500
|
-
"aria-label": "Broadcast player",
|
|
3501
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full max-w-7xl max-h-[95vh] sm:max-h-[90vh] overflow-hidden", children: [
|
|
3502
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3503
|
-
"button",
|
|
3504
|
-
{
|
|
3505
|
-
ref: closeButtonRef,
|
|
3506
|
-
onClick: onClose,
|
|
3507
|
-
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",
|
|
3508
|
-
title: "Close (ESC)",
|
|
3509
|
-
"aria-label": "Close player",
|
|
3510
|
-
children: "\xD7"
|
|
3511
|
-
}
|
|
3512
|
-
),
|
|
3513
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3514
|
-
BroadcastPlayer,
|
|
3515
|
-
{
|
|
3516
|
-
broadcast,
|
|
3517
|
-
appId,
|
|
3518
|
-
contentId,
|
|
3519
|
-
foreignId,
|
|
3520
|
-
foreignTier,
|
|
3521
|
-
renderClipCreator,
|
|
3522
|
-
className,
|
|
3523
|
-
enableKeyboardShortcuts,
|
|
3524
|
-
onError: (error) => {
|
|
3525
|
-
debug.error("[BroadcastPlayerModal] Player error:", error);
|
|
3526
|
-
}
|
|
3527
|
-
}
|
|
3528
|
-
)
|
|
3529
|
-
] })
|
|
3530
|
-
}
|
|
3531
|
-
);
|
|
3532
|
-
}
|
|
3533
|
-
var BroadcastPlayerErrorBoundary = class extends react.Component {
|
|
3427
|
+
var DialtribePlayerErrorBoundary = class extends React2.Component {
|
|
3534
3428
|
constructor(props) {
|
|
3535
3429
|
super(props);
|
|
3536
3430
|
this.handleReset = () => {
|
|
@@ -3656,8 +3550,86 @@ var BroadcastPlayerErrorBoundary = class extends react.Component {
|
|
|
3656
3550
|
return this.props.children;
|
|
3657
3551
|
}
|
|
3658
3552
|
};
|
|
3553
|
+
var overlayStyles = {
|
|
3554
|
+
modal: {
|
|
3555
|
+
backdrop: "bg-black/70 backdrop-blur-xl p-2 sm:p-4",
|
|
3556
|
+
container: "max-w-7xl max-h-[95vh] sm:max-h-[90vh]"
|
|
3557
|
+
},
|
|
3558
|
+
fullscreen: {
|
|
3559
|
+
backdrop: "bg-black",
|
|
3560
|
+
container: "h-full"
|
|
3561
|
+
}
|
|
3562
|
+
};
|
|
3563
|
+
function DialtribeOverlay({
|
|
3564
|
+
isOpen,
|
|
3565
|
+
onClose,
|
|
3566
|
+
mode = "modal",
|
|
3567
|
+
children,
|
|
3568
|
+
ariaLabel = "Dialog",
|
|
3569
|
+
showCloseButton = true,
|
|
3570
|
+
closeOnBackdropClick = true,
|
|
3571
|
+
closeOnEsc = true
|
|
3572
|
+
}) {
|
|
3573
|
+
const closeButtonRef = React2.useRef(null);
|
|
3574
|
+
const previousActiveElement = React2.useRef(null);
|
|
3575
|
+
React2.useEffect(() => {
|
|
3576
|
+
if (!isOpen) return;
|
|
3577
|
+
previousActiveElement.current = document.activeElement;
|
|
3578
|
+
setTimeout(() => {
|
|
3579
|
+
closeButtonRef.current?.focus();
|
|
3580
|
+
}, 100);
|
|
3581
|
+
return () => {
|
|
3582
|
+
if (previousActiveElement.current) {
|
|
3583
|
+
previousActiveElement.current.focus();
|
|
3584
|
+
}
|
|
3585
|
+
};
|
|
3586
|
+
}, [isOpen]);
|
|
3587
|
+
React2.useEffect(() => {
|
|
3588
|
+
if (!isOpen || !closeOnEsc) return;
|
|
3589
|
+
const handleKeyDown = (e) => {
|
|
3590
|
+
if (e.key === "Escape") {
|
|
3591
|
+
onClose();
|
|
3592
|
+
}
|
|
3593
|
+
};
|
|
3594
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
3595
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
3596
|
+
}, [isOpen, onClose, closeOnEsc]);
|
|
3597
|
+
if (!isOpen) {
|
|
3598
|
+
return null;
|
|
3599
|
+
}
|
|
3600
|
+
const handleBackdropClick = (e) => {
|
|
3601
|
+
if (closeOnBackdropClick && e.target === e.currentTarget) {
|
|
3602
|
+
onClose();
|
|
3603
|
+
}
|
|
3604
|
+
};
|
|
3605
|
+
const styles = overlayStyles[mode];
|
|
3606
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3607
|
+
"div",
|
|
3608
|
+
{
|
|
3609
|
+
className: `fixed inset-0 flex items-center justify-center z-50 ${styles.backdrop}`,
|
|
3610
|
+
onClick: handleBackdropClick,
|
|
3611
|
+
role: "dialog",
|
|
3612
|
+
"aria-modal": "true",
|
|
3613
|
+
"aria-label": ariaLabel,
|
|
3614
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `relative w-full overflow-hidden ${styles.container}`, children: [
|
|
3615
|
+
showCloseButton && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3616
|
+
"button",
|
|
3617
|
+
{
|
|
3618
|
+
ref: closeButtonRef,
|
|
3619
|
+
onClick: onClose,
|
|
3620
|
+
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",
|
|
3621
|
+
title: "Close (ESC)",
|
|
3622
|
+
"aria-label": "Close",
|
|
3623
|
+
children: "\xD7"
|
|
3624
|
+
}
|
|
3625
|
+
),
|
|
3626
|
+
children
|
|
3627
|
+
] })
|
|
3628
|
+
}
|
|
3629
|
+
);
|
|
3630
|
+
}
|
|
3659
3631
|
|
|
3660
|
-
// src/utils/
|
|
3632
|
+
// src/utils/dialtribe-popup.ts
|
|
3661
3633
|
function calculatePopupDimensions() {
|
|
3662
3634
|
const screenWidth = window.screen.width;
|
|
3663
3635
|
const screenHeight = window.screen.height;
|
|
@@ -3675,26 +3647,22 @@ function calculatePopupDimensions() {
|
|
|
3675
3647
|
const top = Math.floor((screenHeight - height) / 2);
|
|
3676
3648
|
return { width, height, left, top };
|
|
3677
3649
|
}
|
|
3678
|
-
function
|
|
3650
|
+
function openDialtribeStreamerPopup(options) {
|
|
3679
3651
|
const {
|
|
3680
3652
|
sessionToken,
|
|
3681
3653
|
streamKey,
|
|
3654
|
+
streamerUrl,
|
|
3682
3655
|
appId,
|
|
3683
|
-
|
|
3684
|
-
additionalParams,
|
|
3685
|
-
baseUrl = "/broadcasts/new"
|
|
3656
|
+
additionalParams
|
|
3686
3657
|
} = options;
|
|
3687
3658
|
const { width, height, left, top } = calculatePopupDimensions();
|
|
3688
3659
|
const params = new URLSearchParams();
|
|
3689
|
-
if (mode) {
|
|
3690
|
-
params.append("mode", mode);
|
|
3691
|
-
}
|
|
3692
3660
|
if (additionalParams) {
|
|
3693
3661
|
Object.entries(additionalParams).forEach(([key, value]) => {
|
|
3694
3662
|
params.append(key, value);
|
|
3695
3663
|
});
|
|
3696
3664
|
}
|
|
3697
|
-
const url = `${
|
|
3665
|
+
const url = `${streamerUrl}${params.toString() ? `?${params.toString()}` : ""}`;
|
|
3698
3666
|
const popup = window.open(
|
|
3699
3667
|
url,
|
|
3700
3668
|
"_blank",
|
|
@@ -3724,18 +3692,177 @@ function openBroadcastStreamerPopup(options) {
|
|
|
3724
3692
|
setTimeout(sendMessage, 500);
|
|
3725
3693
|
return popup;
|
|
3726
3694
|
}
|
|
3727
|
-
var openBroadcastPopup =
|
|
3695
|
+
var openBroadcastPopup = openDialtribeStreamerPopup;
|
|
3696
|
+
function useDialtribeStreamerPopup() {
|
|
3697
|
+
const [sessionToken, setSessionToken] = React2.useState(null);
|
|
3698
|
+
const [streamKey, setStreamKey] = React2.useState(null);
|
|
3699
|
+
const [apiBaseUrl, setApiBaseUrl] = React2.useState("");
|
|
3700
|
+
const receivedDataRef = React2.useRef(false);
|
|
3701
|
+
React2.useEffect(() => {
|
|
3702
|
+
const handleMessage = (event) => {
|
|
3703
|
+
if (event.data?.type !== "STREAM_KEY") return;
|
|
3704
|
+
const { sessionToken: token, streamKey: key, apiBaseUrl: url } = event.data;
|
|
3705
|
+
if (token && key) {
|
|
3706
|
+
receivedDataRef.current = true;
|
|
3707
|
+
setSessionToken(token);
|
|
3708
|
+
setStreamKey(key);
|
|
3709
|
+
if (url) {
|
|
3710
|
+
setApiBaseUrl(url);
|
|
3711
|
+
}
|
|
3712
|
+
} else if (key) {
|
|
3713
|
+
receivedDataRef.current = true;
|
|
3714
|
+
setStreamKey(key);
|
|
3715
|
+
}
|
|
3716
|
+
};
|
|
3717
|
+
window.addEventListener("message", handleMessage);
|
|
3718
|
+
const requestCredentials = () => {
|
|
3719
|
+
if (window.opener && !receivedDataRef.current) {
|
|
3720
|
+
window.opener.postMessage({ type: "POPUP_READY" }, "*");
|
|
3721
|
+
}
|
|
3722
|
+
};
|
|
3723
|
+
requestCredentials();
|
|
3724
|
+
const pollInterval = setInterval(() => {
|
|
3725
|
+
if (!receivedDataRef.current) {
|
|
3726
|
+
requestCredentials();
|
|
3727
|
+
} else {
|
|
3728
|
+
clearInterval(pollInterval);
|
|
3729
|
+
}
|
|
3730
|
+
}, 200);
|
|
3731
|
+
const timeout = setTimeout(() => {
|
|
3732
|
+
clearInterval(pollInterval);
|
|
3733
|
+
}, 1e4);
|
|
3734
|
+
return () => {
|
|
3735
|
+
window.removeEventListener("message", handleMessage);
|
|
3736
|
+
clearInterval(pollInterval);
|
|
3737
|
+
clearTimeout(timeout);
|
|
3738
|
+
};
|
|
3739
|
+
}, []);
|
|
3740
|
+
return {
|
|
3741
|
+
sessionToken,
|
|
3742
|
+
streamKey,
|
|
3743
|
+
apiBaseUrl,
|
|
3744
|
+
setStreamKey,
|
|
3745
|
+
isReady: receivedDataRef.current
|
|
3746
|
+
};
|
|
3747
|
+
}
|
|
3748
|
+
function useDialtribeStreamerLauncher(options) {
|
|
3749
|
+
const {
|
|
3750
|
+
sessionToken,
|
|
3751
|
+
streamKey,
|
|
3752
|
+
streamerUrl,
|
|
3753
|
+
apiBaseUrl,
|
|
3754
|
+
fallback = "fullscreen",
|
|
3755
|
+
onPopupBlocked,
|
|
3756
|
+
onDone,
|
|
3757
|
+
onStreamKeyChange
|
|
3758
|
+
} = options;
|
|
3759
|
+
const [showFallback, setShowFallback] = React2.useState(false);
|
|
3760
|
+
const [wasBlocked, setWasBlocked] = React2.useState(false);
|
|
3761
|
+
const popupRef = React2.useRef(null);
|
|
3762
|
+
const sessionTokenRef = React2.useRef(sessionToken);
|
|
3763
|
+
const streamKeyRef = React2.useRef(streamKey);
|
|
3764
|
+
const apiBaseUrlRef = React2.useRef(apiBaseUrl);
|
|
3765
|
+
React2.useEffect(() => {
|
|
3766
|
+
sessionTokenRef.current = sessionToken;
|
|
3767
|
+
}, [sessionToken]);
|
|
3768
|
+
React2.useEffect(() => {
|
|
3769
|
+
streamKeyRef.current = streamKey;
|
|
3770
|
+
}, [streamKey]);
|
|
3771
|
+
React2.useEffect(() => {
|
|
3772
|
+
apiBaseUrlRef.current = apiBaseUrl;
|
|
3773
|
+
}, [apiBaseUrl]);
|
|
3774
|
+
React2.useEffect(() => {
|
|
3775
|
+
const handleMessage = (event) => {
|
|
3776
|
+
if (event.data?.type === "POPUP_READY" && popupRef.current) {
|
|
3777
|
+
popupRef.current.postMessage(
|
|
3778
|
+
{
|
|
3779
|
+
type: "STREAM_KEY",
|
|
3780
|
+
sessionToken: sessionTokenRef.current,
|
|
3781
|
+
streamKey: streamKeyRef.current,
|
|
3782
|
+
apiBaseUrl: apiBaseUrlRef.current
|
|
3783
|
+
},
|
|
3784
|
+
"*"
|
|
3785
|
+
);
|
|
3786
|
+
}
|
|
3787
|
+
};
|
|
3788
|
+
window.addEventListener("message", handleMessage);
|
|
3789
|
+
return () => window.removeEventListener("message", handleMessage);
|
|
3790
|
+
}, []);
|
|
3791
|
+
const launch = React2.useCallback(() => {
|
|
3792
|
+
if (!sessionToken) {
|
|
3793
|
+
console.warn("Cannot launch streamer: no session token");
|
|
3794
|
+
return;
|
|
3795
|
+
}
|
|
3796
|
+
setWasBlocked(false);
|
|
3797
|
+
const popup = openDialtribeStreamerPopup({
|
|
3798
|
+
sessionToken,
|
|
3799
|
+
streamKey,
|
|
3800
|
+
streamerUrl
|
|
3801
|
+
});
|
|
3802
|
+
if (popup) {
|
|
3803
|
+
popupRef.current = popup;
|
|
3804
|
+
return;
|
|
3805
|
+
}
|
|
3806
|
+
setWasBlocked(true);
|
|
3807
|
+
onPopupBlocked?.();
|
|
3808
|
+
switch (fallback) {
|
|
3809
|
+
case "fullscreen":
|
|
3810
|
+
setShowFallback(true);
|
|
3811
|
+
break;
|
|
3812
|
+
case "newTab":
|
|
3813
|
+
window.open(streamerUrl, "_blank");
|
|
3814
|
+
break;
|
|
3815
|
+
}
|
|
3816
|
+
}, [sessionToken, streamKey, streamerUrl, fallback, onPopupBlocked]);
|
|
3817
|
+
const closeFallback = React2.useCallback(() => {
|
|
3818
|
+
setShowFallback(false);
|
|
3819
|
+
onDone?.();
|
|
3820
|
+
}, [onDone]);
|
|
3821
|
+
const Fallback = React2.useCallback(() => {
|
|
3822
|
+
if (fallback !== "fullscreen" || !showFallback) {
|
|
3823
|
+
return null;
|
|
3824
|
+
}
|
|
3825
|
+
if (typeof document === "undefined") {
|
|
3826
|
+
return null;
|
|
3827
|
+
}
|
|
3828
|
+
const streamerElement = React2__default.default.createElement(DialtribeStreamer, {
|
|
3829
|
+
sessionToken: sessionToken || void 0,
|
|
3830
|
+
streamKey: streamKey || void 0,
|
|
3831
|
+
apiBaseUrl,
|
|
3832
|
+
onDone: closeFallback,
|
|
3833
|
+
onStreamKeyChange
|
|
3834
|
+
});
|
|
3835
|
+
const overlayElement = React2__default.default.createElement(
|
|
3836
|
+
DialtribeOverlay,
|
|
3837
|
+
{
|
|
3838
|
+
mode: "fullscreen",
|
|
3839
|
+
isOpen: true,
|
|
3840
|
+
onClose: closeFallback,
|
|
3841
|
+
children: streamerElement
|
|
3842
|
+
}
|
|
3843
|
+
);
|
|
3844
|
+
return reactDom.createPortal(overlayElement, document.body);
|
|
3845
|
+
}, [fallback, showFallback, closeFallback, sessionToken, streamKey, apiBaseUrl, onStreamKeyChange]);
|
|
3846
|
+
return {
|
|
3847
|
+
launch,
|
|
3848
|
+
Fallback,
|
|
3849
|
+
showFallback,
|
|
3850
|
+
closeFallback,
|
|
3851
|
+
popupRef: popupRef.current,
|
|
3852
|
+
wasBlocked
|
|
3853
|
+
};
|
|
3854
|
+
}
|
|
3728
3855
|
|
|
3729
3856
|
exports.AudioWaveform = AudioWaveform;
|
|
3730
|
-
exports.BroadcastPlayer = BroadcastPlayer;
|
|
3731
|
-
exports.BroadcastPlayerErrorBoundary = BroadcastPlayerErrorBoundary;
|
|
3732
|
-
exports.BroadcastPlayerModal = BroadcastPlayerModal;
|
|
3733
|
-
exports.BroadcastStreamer = BroadcastStreamer;
|
|
3734
3857
|
exports.CDN_DOMAIN = CDN_DOMAIN;
|
|
3735
3858
|
exports.DEFAULT_ENCODER_SERVER_URL = DEFAULT_ENCODER_SERVER_URL;
|
|
3736
3859
|
exports.DIALTRIBE_API_BASE = DIALTRIBE_API_BASE;
|
|
3737
|
-
exports.
|
|
3738
|
-
exports.
|
|
3860
|
+
exports.DialtribeClient = DialtribeClient;
|
|
3861
|
+
exports.DialtribeOverlay = DialtribeOverlay;
|
|
3862
|
+
exports.DialtribePlayer = DialtribePlayer;
|
|
3863
|
+
exports.DialtribePlayerErrorBoundary = DialtribePlayerErrorBoundary;
|
|
3864
|
+
exports.DialtribeProvider = DialtribeProvider;
|
|
3865
|
+
exports.DialtribeStreamer = DialtribeStreamer;
|
|
3739
3866
|
exports.ENDPOINTS = ENDPOINTS;
|
|
3740
3867
|
exports.HTTP_STATUS = HTTP_STATUS;
|
|
3741
3868
|
exports.LoadingSpinner = LoadingSpinner;
|
|
@@ -3752,8 +3879,10 @@ exports.formatTime = formatTime;
|
|
|
3752
3879
|
exports.getMediaConstraints = getMediaConstraints;
|
|
3753
3880
|
exports.getMediaRecorderOptions = getMediaRecorderOptions;
|
|
3754
3881
|
exports.openBroadcastPopup = openBroadcastPopup;
|
|
3755
|
-
exports.
|
|
3756
|
-
exports.
|
|
3757
|
-
exports.
|
|
3758
|
-
|
|
3759
|
-
|
|
3882
|
+
exports.openDialtribeStreamerPopup = openDialtribeStreamerPopup;
|
|
3883
|
+
exports.useDialtribe = useDialtribe;
|
|
3884
|
+
exports.useDialtribeOptional = useDialtribeOptional;
|
|
3885
|
+
exports.useDialtribeStreamerLauncher = useDialtribeStreamerLauncher;
|
|
3886
|
+
exports.useDialtribeStreamerPopup = useDialtribeStreamerPopup;
|
|
3887
|
+
//# sourceMappingURL=dialtribe-streamer.js.map
|
|
3888
|
+
//# sourceMappingURL=dialtribe-streamer.js.map
|