@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
|
@@ -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;
|
|
@@ -75,18 +77,19 @@ function getEndpoints(baseUrl = DIALTRIBE_API_BASE) {
|
|
|
75
77
|
broadcast: (id) => `${baseUrl}/broadcasts/${id}`,
|
|
76
78
|
contentPlay: `${baseUrl}/content/play`,
|
|
77
79
|
presignedUrl: `${baseUrl}/media/presigned-url`,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
audienceStart: `${baseUrl}/audiences/start`,
|
|
81
|
+
audiencePing: `${baseUrl}/audiences/ping`,
|
|
82
|
+
sessionPing: `${baseUrl}/sessions/ping`
|
|
80
83
|
};
|
|
81
84
|
}
|
|
82
85
|
var ENDPOINTS = getEndpoints();
|
|
83
|
-
var
|
|
86
|
+
var DialtribeClient = class {
|
|
84
87
|
constructor(config) {
|
|
85
88
|
this.config = config;
|
|
86
89
|
this.endpoints = config.apiBaseUrl ? getEndpoints(config.apiBaseUrl) : ENDPOINTS;
|
|
87
90
|
}
|
|
88
91
|
/**
|
|
89
|
-
* Make an authenticated request to
|
|
92
|
+
* Make an authenticated request to Dialtribe API
|
|
90
93
|
*
|
|
91
94
|
* Automatically:
|
|
92
95
|
* - Adds Authorization header with session token
|
|
@@ -200,7 +203,7 @@ var DialTribeClient = class {
|
|
|
200
203
|
* @returns audienceId and optional resumePosition
|
|
201
204
|
*/
|
|
202
205
|
async startSession(params) {
|
|
203
|
-
const response = await this.fetch(this.endpoints.
|
|
206
|
+
const response = await this.fetch(this.endpoints.audienceStart, {
|
|
204
207
|
method: "POST",
|
|
205
208
|
body: JSON.stringify(params)
|
|
206
209
|
});
|
|
@@ -219,7 +222,7 @@ var DialTribeClient = class {
|
|
|
219
222
|
* - 3: UNMOUNT
|
|
220
223
|
*/
|
|
221
224
|
async sendSessionPing(params) {
|
|
222
|
-
const response = await this.fetch(this.endpoints.
|
|
225
|
+
const response = await this.fetch(this.endpoints.audiencePing, {
|
|
223
226
|
method: "POST",
|
|
224
227
|
body: JSON.stringify(params)
|
|
225
228
|
});
|
|
@@ -530,18 +533,18 @@ function AudioWaveform({
|
|
|
530
533
|
isPlaying = false,
|
|
531
534
|
isLive = false
|
|
532
535
|
}) {
|
|
533
|
-
const canvasRef =
|
|
534
|
-
const animationFrameRef =
|
|
535
|
-
const [setupError, setSetupError] =
|
|
536
|
-
const isPlayingRef =
|
|
537
|
-
const isLiveRef =
|
|
538
|
-
|
|
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(() => {
|
|
539
542
|
isPlayingRef.current = isPlaying;
|
|
540
543
|
}, [isPlaying]);
|
|
541
|
-
|
|
544
|
+
React2.useEffect(() => {
|
|
542
545
|
isLiveRef.current = isLive;
|
|
543
546
|
}, [isLive]);
|
|
544
|
-
|
|
547
|
+
React2.useEffect(() => {
|
|
545
548
|
const canvas = canvasRef.current;
|
|
546
549
|
if (!canvas) return;
|
|
547
550
|
const ctx = canvas.getContext("2d");
|
|
@@ -971,8 +974,8 @@ function StreamKeyDisplay({
|
|
|
971
974
|
layout = "vertical",
|
|
972
975
|
darkMode = false
|
|
973
976
|
}) {
|
|
974
|
-
const [isRevealed, setIsRevealed] =
|
|
975
|
-
const [copySuccess, setCopySuccess] =
|
|
977
|
+
const [isRevealed, setIsRevealed] = React2.useState(false);
|
|
978
|
+
const [copySuccess, setCopySuccess] = React2.useState(false);
|
|
976
979
|
const obscureStreamKey = (key) => {
|
|
977
980
|
if (key.length <= 12) {
|
|
978
981
|
return "\u2022".repeat(key.length);
|
|
@@ -1080,9 +1083,9 @@ function StreamingControls({
|
|
|
1080
1083
|
onAudioDeviceChange,
|
|
1081
1084
|
mediaStream
|
|
1082
1085
|
}) {
|
|
1083
|
-
const [duration, setDuration] =
|
|
1084
|
-
const [showSettings, setShowSettings] =
|
|
1085
|
-
|
|
1086
|
+
const [duration, setDuration] = React2.useState(0);
|
|
1087
|
+
const [showSettings, setShowSettings] = React2.useState(false);
|
|
1088
|
+
React2.useEffect(() => {
|
|
1086
1089
|
if (state !== "live" || !startTime) return;
|
|
1087
1090
|
const interval = setInterval(() => {
|
|
1088
1091
|
const elapsed = Math.floor((Date.now() - startTime.getTime()) / 1e3);
|
|
@@ -1415,8 +1418,8 @@ function StreamingControls({
|
|
|
1415
1418
|
] });
|
|
1416
1419
|
}
|
|
1417
1420
|
function StreamKeyInput({ onSubmit, inline = false }) {
|
|
1418
|
-
const [streamKey, setStreamKey] =
|
|
1419
|
-
const [error, setError] =
|
|
1421
|
+
const [streamKey, setStreamKey] = React2.useState("");
|
|
1422
|
+
const [error, setError] = React2.useState("");
|
|
1420
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";
|
|
1421
1424
|
const validateStreamKey = (key) => {
|
|
1422
1425
|
const pattern = /^[abvw][a-zA-Z0-9]+_.+$/;
|
|
@@ -1482,7 +1485,7 @@ function StreamKeyInput({ onSubmit, inline = false }) {
|
|
|
1482
1485
|
] })
|
|
1483
1486
|
] }) });
|
|
1484
1487
|
}
|
|
1485
|
-
function
|
|
1488
|
+
function DialtribeStreamer({
|
|
1486
1489
|
sessionToken: propSessionToken,
|
|
1487
1490
|
streamKey: initialStreamKey,
|
|
1488
1491
|
onDone,
|
|
@@ -1491,35 +1494,35 @@ function BroadcastStreamer({
|
|
|
1491
1494
|
apiBaseUrl = DIALTRIBE_API_BASE,
|
|
1492
1495
|
inline = false
|
|
1493
1496
|
}) {
|
|
1494
|
-
const containerClass = inline ? "dialtribe-
|
|
1495
|
-
const centeredContainerClass = inline ? "dialtribe-
|
|
1496
|
-
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();
|
|
1497
1500
|
const sessionToken = propSessionToken ?? dialTribeContext?.sessionToken ?? null;
|
|
1498
|
-
const [streamKey, setStreamKey] =
|
|
1499
|
-
const [state, setState] =
|
|
1500
|
-
|
|
1501
|
+
const [streamKey, setStreamKey] = React2.useState(initialStreamKey || null);
|
|
1502
|
+
const [state, setState] = React2.useState("idle");
|
|
1503
|
+
React2.useEffect(() => {
|
|
1501
1504
|
if (initialStreamKey && initialStreamKey !== streamKey) {
|
|
1502
1505
|
setStreamKey(initialStreamKey);
|
|
1503
1506
|
}
|
|
1504
1507
|
}, [initialStreamKey]);
|
|
1505
|
-
const [error, setError] =
|
|
1506
|
-
const [mediaStream, setMediaStream] =
|
|
1507
|
-
const [streamer, setStreamer] =
|
|
1508
|
-
const [bytesSent, setBytesSent] =
|
|
1509
|
-
const [startTime, setStartTime] =
|
|
1510
|
-
const [isMuted, setIsMuted] =
|
|
1511
|
-
const [isVideoEnabled, setIsVideoEnabled] =
|
|
1512
|
-
const [facingMode, setFacingMode] =
|
|
1513
|
-
const [showStopConfirm, setShowStopConfirm] =
|
|
1514
|
-
const [showCloseConfirm, setShowCloseConfirm] =
|
|
1515
|
-
const [hasMultipleCameras, setHasMultipleCameras] =
|
|
1516
|
-
const [videoDevices, setVideoDevices] =
|
|
1517
|
-
const [audioDevices, setAudioDevices] =
|
|
1518
|
-
const [selectedVideoDeviceId, setSelectedVideoDeviceId] =
|
|
1519
|
-
const [selectedAudioDeviceId, setSelectedAudioDeviceId] =
|
|
1520
|
-
const videoRef =
|
|
1521
|
-
const streamerRef =
|
|
1522
|
-
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);
|
|
1523
1526
|
const isVideoKey = streamKey ? streamKey.startsWith("v") || streamKey.startsWith("w") : false;
|
|
1524
1527
|
const handleStreamKeySubmit = (key) => {
|
|
1525
1528
|
setStreamKey(key);
|
|
@@ -1529,7 +1532,7 @@ function BroadcastStreamer({
|
|
|
1529
1532
|
setStreamKey(key);
|
|
1530
1533
|
onStreamKeyChange?.(key);
|
|
1531
1534
|
};
|
|
1532
|
-
|
|
1535
|
+
React2.useEffect(() => {
|
|
1533
1536
|
if (!streamKey) return;
|
|
1534
1537
|
const compat = checkBrowserCompatibility();
|
|
1535
1538
|
if (!compat.compatible) {
|
|
@@ -1567,13 +1570,13 @@ function BroadcastStreamer({
|
|
|
1567
1570
|
setHasMultipleCameras(false);
|
|
1568
1571
|
}
|
|
1569
1572
|
};
|
|
1570
|
-
|
|
1573
|
+
React2.useEffect(() => {
|
|
1571
1574
|
streamerRef.current = streamer;
|
|
1572
1575
|
}, [streamer]);
|
|
1573
|
-
|
|
1576
|
+
React2.useEffect(() => {
|
|
1574
1577
|
mediaStreamRef.current = mediaStream;
|
|
1575
1578
|
}, [mediaStream]);
|
|
1576
|
-
|
|
1579
|
+
React2.useEffect(() => {
|
|
1577
1580
|
return () => {
|
|
1578
1581
|
if (streamerRef.current) {
|
|
1579
1582
|
streamerRef.current.stop();
|
|
@@ -1583,7 +1586,7 @@ function BroadcastStreamer({
|
|
|
1583
1586
|
}
|
|
1584
1587
|
};
|
|
1585
1588
|
}, []);
|
|
1586
|
-
|
|
1589
|
+
React2.useEffect(() => {
|
|
1587
1590
|
if (state === "live") {
|
|
1588
1591
|
const handleBeforeUnload = (e) => {
|
|
1589
1592
|
e.preventDefault();
|
|
@@ -1594,7 +1597,7 @@ function BroadcastStreamer({
|
|
|
1594
1597
|
return () => window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
1595
1598
|
}
|
|
1596
1599
|
}, [state]);
|
|
1597
|
-
|
|
1600
|
+
React2.useEffect(() => {
|
|
1598
1601
|
if (videoRef.current && mediaStream) {
|
|
1599
1602
|
videoRef.current.srcObject = mediaStream;
|
|
1600
1603
|
}
|
|
@@ -1877,36 +1880,9 @@ function BroadcastStreamer({
|
|
|
1877
1880
|
}
|
|
1878
1881
|
};
|
|
1879
1882
|
if (!sessionToken) {
|
|
1880
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: centeredContainerClass, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
1881
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-16 h-16
|
|
1882
|
-
|
|
1883
|
-
{
|
|
1884
|
-
className: "w-8 h-8 text-red-600 dark:text-red-400",
|
|
1885
|
-
fill: "none",
|
|
1886
|
-
stroke: "currentColor",
|
|
1887
|
-
viewBox: "0 0 24 24",
|
|
1888
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1889
|
-
"path",
|
|
1890
|
-
{
|
|
1891
|
-
strokeLinecap: "round",
|
|
1892
|
-
strokeLinejoin: "round",
|
|
1893
|
-
strokeWidth: 2,
|
|
1894
|
-
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"
|
|
1895
|
-
}
|
|
1896
|
-
)
|
|
1897
|
-
}
|
|
1898
|
-
) }),
|
|
1899
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-bold text-black dark:text-white mb-2", children: "Authentication Required" }),
|
|
1900
|
-
/* @__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." }),
|
|
1901
|
-
/* @__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." }),
|
|
1902
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1903
|
-
"button",
|
|
1904
|
-
{
|
|
1905
|
-
onClick: handleDone,
|
|
1906
|
-
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",
|
|
1907
|
-
children: "Close"
|
|
1908
|
-
}
|
|
1909
|
-
)
|
|
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..." })
|
|
1910
1886
|
] }) });
|
|
1911
1887
|
}
|
|
1912
1888
|
if (!streamKey) {
|
|
@@ -2239,7 +2215,7 @@ function getErrorMessage(error) {
|
|
|
2239
2215
|
}
|
|
2240
2216
|
return "Unable to play media. Please try refreshing the page or contact support if the problem persists.";
|
|
2241
2217
|
}
|
|
2242
|
-
function
|
|
2218
|
+
function DialtribePlayer({
|
|
2243
2219
|
broadcast,
|
|
2244
2220
|
appId,
|
|
2245
2221
|
contentId,
|
|
@@ -2250,18 +2226,18 @@ function BroadcastPlayer({
|
|
|
2250
2226
|
className = "",
|
|
2251
2227
|
enableKeyboardShortcuts = false
|
|
2252
2228
|
}) {
|
|
2253
|
-
const { sessionToken, setSessionToken, markExpired, apiBaseUrl } =
|
|
2254
|
-
const clientRef =
|
|
2229
|
+
const { sessionToken, setSessionToken, markExpired, apiBaseUrl } = useDialtribe();
|
|
2230
|
+
const clientRef = React2.useRef(null);
|
|
2255
2231
|
if (!clientRef.current && sessionToken) {
|
|
2256
|
-
clientRef.current = new
|
|
2232
|
+
clientRef.current = new DialtribeClient({
|
|
2257
2233
|
sessionToken,
|
|
2258
2234
|
apiBaseUrl,
|
|
2259
2235
|
onTokenRefresh: (newToken, expiresAt) => {
|
|
2260
|
-
debug.log(`[
|
|
2236
|
+
debug.log(`[DialtribeClient] Token refreshed, expires at ${expiresAt}`);
|
|
2261
2237
|
setSessionToken(newToken, expiresAt);
|
|
2262
2238
|
},
|
|
2263
2239
|
onTokenExpired: () => {
|
|
2264
|
-
debug.error("[
|
|
2240
|
+
debug.error("[DialtribeClient] Token expired");
|
|
2265
2241
|
markExpired();
|
|
2266
2242
|
}
|
|
2267
2243
|
});
|
|
@@ -2269,35 +2245,35 @@ function BroadcastPlayer({
|
|
|
2269
2245
|
clientRef.current.setSessionToken(sessionToken);
|
|
2270
2246
|
}
|
|
2271
2247
|
const client = clientRef.current;
|
|
2272
|
-
const playerRef =
|
|
2273
|
-
const transcriptContainerRef =
|
|
2274
|
-
const activeWordRef =
|
|
2275
|
-
const [audioElement, setAudioElement] =
|
|
2276
|
-
const [playing, setPlaying] =
|
|
2277
|
-
const [played, setPlayed] =
|
|
2278
|
-
const [duration, setDuration] =
|
|
2279
|
-
const [volume, setVolume] =
|
|
2280
|
-
const [muted, setMuted] =
|
|
2281
|
-
const [seeking, setSeeking] =
|
|
2282
|
-
const [hasError, setHasError] =
|
|
2283
|
-
const [errorMessage, setErrorMessage] =
|
|
2284
|
-
const [hasEnded, setHasEnded] =
|
|
2285
|
-
const [hasStreamEnded, setHasStreamEnded] =
|
|
2286
|
-
const [showTranscript, setShowTranscript] =
|
|
2287
|
-
const [transcriptData, setTranscriptData] =
|
|
2288
|
-
const [currentTime, setCurrentTime] =
|
|
2289
|
-
const [isLoadingTranscript, setIsLoadingTranscript] =
|
|
2290
|
-
const [isLoadingVideo, setIsLoadingVideo] =
|
|
2291
|
-
const [autoScrollEnabled, setAutoScrollEnabled] =
|
|
2292
|
-
const isScrollingProgrammatically =
|
|
2293
|
-
const lastActiveWordIndex =
|
|
2294
|
-
const [showClipCreator, setShowClipCreator] =
|
|
2295
|
-
const initialPlaybackTypeRef =
|
|
2296
|
-
const [currentPlaybackInfo, setCurrentPlaybackInfo] =
|
|
2297
|
-
const [urlExpiresAt, setUrlExpiresAt] =
|
|
2298
|
-
const isRefreshingUrl =
|
|
2299
|
-
const [audienceId, setAudienceId] =
|
|
2300
|
-
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(() => {
|
|
2301
2277
|
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
2302
2278
|
return crypto.randomUUID();
|
|
2303
2279
|
}
|
|
@@ -2307,9 +2283,9 @@ function BroadcastPlayer({
|
|
|
2307
2283
|
return v.toString(16);
|
|
2308
2284
|
});
|
|
2309
2285
|
});
|
|
2310
|
-
const heartbeatIntervalRef =
|
|
2311
|
-
const hasInitializedSession =
|
|
2312
|
-
const refreshPresignedUrl =
|
|
2286
|
+
const heartbeatIntervalRef = React2.useRef(null);
|
|
2287
|
+
const hasInitializedSession = React2.useRef(false);
|
|
2288
|
+
const refreshPresignedUrl = React2.useCallback(
|
|
2313
2289
|
async (fileType) => {
|
|
2314
2290
|
if (!broadcast.hash || isRefreshingUrl.current || !client) {
|
|
2315
2291
|
debug.log("[URL Refresh] Skipping refresh - no hash, already refreshing, or no client");
|
|
@@ -2360,7 +2336,7 @@ function BroadcastPlayer({
|
|
|
2360
2336
|
if (width < 1024) return "tablet";
|
|
2361
2337
|
return "desktop";
|
|
2362
2338
|
};
|
|
2363
|
-
const initializeTrackingSession =
|
|
2339
|
+
const initializeTrackingSession = React2.useCallback(async () => {
|
|
2364
2340
|
if (!contentId || !appId || !client) return;
|
|
2365
2341
|
if (currentPlaybackInfo?.type === "hls" && broadcast.broadcastStatus === 1) return;
|
|
2366
2342
|
if (hasInitializedSession.current) return;
|
|
@@ -2395,7 +2371,7 @@ function BroadcastPlayer({
|
|
|
2395
2371
|
}
|
|
2396
2372
|
}
|
|
2397
2373
|
}, [contentId, appId, broadcast.id, broadcast.broadcastStatus, foreignId, foreignTier, sessionId, currentPlaybackInfo?.type, audioElement, client, onError]);
|
|
2398
|
-
const sendTrackingPing =
|
|
2374
|
+
const sendTrackingPing = React2.useCallback(
|
|
2399
2375
|
async (eventType) => {
|
|
2400
2376
|
if (!audienceId || !sessionId || !client) return;
|
|
2401
2377
|
try {
|
|
@@ -2433,7 +2409,7 @@ function BroadcastPlayer({
|
|
|
2433
2409
|
}
|
|
2434
2410
|
return null;
|
|
2435
2411
|
};
|
|
2436
|
-
|
|
2412
|
+
React2.useEffect(() => {
|
|
2437
2413
|
if (!currentPlaybackInfo) {
|
|
2438
2414
|
const info = getPlaybackInfo();
|
|
2439
2415
|
setCurrentPlaybackInfo(info);
|
|
@@ -2449,12 +2425,12 @@ function BroadcastPlayer({
|
|
|
2449
2425
|
}
|
|
2450
2426
|
}
|
|
2451
2427
|
}, [currentPlaybackInfo]);
|
|
2452
|
-
|
|
2428
|
+
React2.useEffect(() => {
|
|
2453
2429
|
if (currentPlaybackInfo?.url) {
|
|
2454
2430
|
setIsLoadingVideo(true);
|
|
2455
2431
|
}
|
|
2456
2432
|
}, [currentPlaybackInfo?.url]);
|
|
2457
|
-
|
|
2433
|
+
React2.useEffect(() => {
|
|
2458
2434
|
if (!urlExpiresAt || !currentPlaybackInfo?.type) return;
|
|
2459
2435
|
const checkExpiration = () => {
|
|
2460
2436
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -2473,7 +2449,7 @@ function BroadcastPlayer({
|
|
|
2473
2449
|
clearInterval(interval);
|
|
2474
2450
|
};
|
|
2475
2451
|
}, [urlExpiresAt, currentPlaybackInfo?.type, refreshPresignedUrl]);
|
|
2476
|
-
|
|
2452
|
+
React2.useEffect(() => {
|
|
2477
2453
|
if (initialPlaybackTypeRef.current === "hls" && currentPlaybackInfo?.type === "hls" && broadcast.broadcastStatus !== 1 && broadcast.recordingMp3Url && broadcast.hash && parseInt(broadcast.mp3Size || "0") > 0) {
|
|
2478
2454
|
const secureUrl = buildPlaybackUrl(broadcast.id, broadcast.hash);
|
|
2479
2455
|
setCurrentPlaybackInfo({ url: secureUrl, type: "mp3" });
|
|
@@ -2509,22 +2485,22 @@ function BroadcastPlayer({
|
|
|
2509
2485
|
setHasEnded(true);
|
|
2510
2486
|
}
|
|
2511
2487
|
};
|
|
2512
|
-
|
|
2488
|
+
React2.useEffect(() => {
|
|
2513
2489
|
if (broadcast.durationSeconds && broadcast.durationSeconds > 0) {
|
|
2514
2490
|
setDuration(broadcast.durationSeconds);
|
|
2515
2491
|
}
|
|
2516
2492
|
}, [broadcast.durationSeconds]);
|
|
2517
|
-
|
|
2493
|
+
React2.useEffect(() => {
|
|
2518
2494
|
if (isLiveStream && !playing) {
|
|
2519
2495
|
setPlaying(true);
|
|
2520
2496
|
}
|
|
2521
2497
|
}, [isLiveStream, playing]);
|
|
2522
|
-
|
|
2498
|
+
React2.useEffect(() => {
|
|
2523
2499
|
if (currentPlaybackInfo && audioElement && !hasInitializedSession.current) {
|
|
2524
2500
|
initializeTrackingSession();
|
|
2525
2501
|
}
|
|
2526
2502
|
}, [currentPlaybackInfo, audioElement, initializeTrackingSession]);
|
|
2527
|
-
|
|
2503
|
+
React2.useEffect(() => {
|
|
2528
2504
|
if (playing && audienceId) {
|
|
2529
2505
|
sendTrackingPing(1);
|
|
2530
2506
|
heartbeatIntervalRef.current = setInterval(() => {
|
|
@@ -2544,7 +2520,7 @@ function BroadcastPlayer({
|
|
|
2544
2520
|
}
|
|
2545
2521
|
}
|
|
2546
2522
|
}, [playing, audienceId, sendTrackingPing]);
|
|
2547
|
-
|
|
2523
|
+
React2.useEffect(() => {
|
|
2548
2524
|
return () => {
|
|
2549
2525
|
if (audienceId && sessionId && sessionToken) {
|
|
2550
2526
|
const payload = {
|
|
@@ -2569,7 +2545,7 @@ function BroadcastPlayer({
|
|
|
2569
2545
|
}
|
|
2570
2546
|
};
|
|
2571
2547
|
}, [audienceId, sessionId, sessionToken, audioElement, duration]);
|
|
2572
|
-
|
|
2548
|
+
React2.useEffect(() => {
|
|
2573
2549
|
if (broadcast.transcriptUrl && broadcast.transcriptStatus === 2 && !transcriptData) {
|
|
2574
2550
|
setIsLoadingTranscript(true);
|
|
2575
2551
|
fetch(broadcast.transcriptUrl).then((res) => {
|
|
@@ -2600,7 +2576,7 @@ function BroadcastPlayer({
|
|
|
2600
2576
|
});
|
|
2601
2577
|
}
|
|
2602
2578
|
}, [broadcast.transcriptUrl, broadcast.transcriptStatus, transcriptData]);
|
|
2603
|
-
|
|
2579
|
+
React2.useEffect(() => {
|
|
2604
2580
|
if (!audioElement) return;
|
|
2605
2581
|
const handleTimeUpdate2 = () => {
|
|
2606
2582
|
setCurrentTime(audioElement.currentTime);
|
|
@@ -2608,7 +2584,7 @@ function BroadcastPlayer({
|
|
|
2608
2584
|
audioElement.addEventListener("timeupdate", handleTimeUpdate2);
|
|
2609
2585
|
return () => audioElement.removeEventListener("timeupdate", handleTimeUpdate2);
|
|
2610
2586
|
}, [audioElement]);
|
|
2611
|
-
|
|
2587
|
+
React2.useEffect(() => {
|
|
2612
2588
|
if (showTranscript && autoScrollEnabled && activeWordRef.current && transcriptContainerRef.current) {
|
|
2613
2589
|
const container = transcriptContainerRef.current;
|
|
2614
2590
|
const activeWord = activeWordRef.current;
|
|
@@ -2623,7 +2599,7 @@ function BroadcastPlayer({
|
|
|
2623
2599
|
}
|
|
2624
2600
|
}
|
|
2625
2601
|
}, [currentTime, showTranscript, autoScrollEnabled]);
|
|
2626
|
-
|
|
2602
|
+
React2.useEffect(() => {
|
|
2627
2603
|
if (!showTranscript || !transcriptContainerRef.current) return;
|
|
2628
2604
|
const container = transcriptContainerRef.current;
|
|
2629
2605
|
const handleScroll = () => {
|
|
@@ -2706,10 +2682,10 @@ function BroadcastPlayer({
|
|
|
2706
2682
|
setAudioElement(internalPlayer);
|
|
2707
2683
|
}
|
|
2708
2684
|
} catch (error) {
|
|
2709
|
-
debug.error("[
|
|
2685
|
+
debug.error("[DialtribePlayer] Error getting internal player:", error);
|
|
2710
2686
|
}
|
|
2711
2687
|
};
|
|
2712
|
-
|
|
2688
|
+
React2.useEffect(() => {
|
|
2713
2689
|
const findAudioElement = () => {
|
|
2714
2690
|
const videoElements = document.querySelectorAll("video, audio");
|
|
2715
2691
|
if (videoElements.length > 0) {
|
|
@@ -2729,7 +2705,7 @@ function BroadcastPlayer({
|
|
|
2729
2705
|
return () => timeouts.forEach(clearTimeout);
|
|
2730
2706
|
}
|
|
2731
2707
|
}, [playbackUrl]);
|
|
2732
|
-
|
|
2708
|
+
React2.useEffect(() => {
|
|
2733
2709
|
if (playing && !audioElement) {
|
|
2734
2710
|
const videoElements = document.querySelectorAll("video, audio");
|
|
2735
2711
|
if (videoElements.length > 0) {
|
|
@@ -2808,7 +2784,7 @@ function BroadcastPlayer({
|
|
|
2808
2784
|
onError(error);
|
|
2809
2785
|
}
|
|
2810
2786
|
};
|
|
2811
|
-
const handleRetry =
|
|
2787
|
+
const handleRetry = React2.useCallback(() => {
|
|
2812
2788
|
setHasError(false);
|
|
2813
2789
|
setErrorMessage("");
|
|
2814
2790
|
setIsLoadingVideo(true);
|
|
@@ -2831,7 +2807,7 @@ function BroadcastPlayer({
|
|
|
2831
2807
|
}
|
|
2832
2808
|
}
|
|
2833
2809
|
};
|
|
2834
|
-
|
|
2810
|
+
React2.useEffect(() => {
|
|
2835
2811
|
if (!enableKeyboardShortcuts) return;
|
|
2836
2812
|
const seekBy = (seconds) => {
|
|
2837
2813
|
if (!audioElement || duration <= 0) return;
|
|
@@ -2914,7 +2890,7 @@ function BroadcastPlayer({
|
|
|
2914
2890
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center p-8", children: /* @__PURE__ */ jsxRuntime.jsx(LoadingSpinner, { variant: "white", text: "Loading..." }) });
|
|
2915
2891
|
}
|
|
2916
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);
|
|
2917
|
-
|
|
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: [
|
|
2918
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: [
|
|
2919
2895
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2920
2896
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-white", children: broadcast.streamKeyRecord?.foreignName || "Broadcast" }),
|
|
@@ -3446,90 +3422,9 @@ function BroadcastPlayer({
|
|
|
3446
3422
|
}
|
|
3447
3423
|
` })
|
|
3448
3424
|
] });
|
|
3425
|
+
return playerContent;
|
|
3449
3426
|
}
|
|
3450
|
-
|
|
3451
|
-
broadcast,
|
|
3452
|
-
isOpen,
|
|
3453
|
-
onClose,
|
|
3454
|
-
appId,
|
|
3455
|
-
contentId,
|
|
3456
|
-
foreignId,
|
|
3457
|
-
foreignTier,
|
|
3458
|
-
renderClipCreator,
|
|
3459
|
-
className,
|
|
3460
|
-
enableKeyboardShortcuts = false
|
|
3461
|
-
}) {
|
|
3462
|
-
const closeButtonRef = react.useRef(null);
|
|
3463
|
-
const previousActiveElement = react.useRef(null);
|
|
3464
|
-
react.useEffect(() => {
|
|
3465
|
-
if (!isOpen) return;
|
|
3466
|
-
previousActiveElement.current = document.activeElement;
|
|
3467
|
-
setTimeout(() => {
|
|
3468
|
-
closeButtonRef.current?.focus();
|
|
3469
|
-
}, 100);
|
|
3470
|
-
return () => {
|
|
3471
|
-
if (previousActiveElement.current) {
|
|
3472
|
-
previousActiveElement.current.focus();
|
|
3473
|
-
}
|
|
3474
|
-
};
|
|
3475
|
-
}, [isOpen]);
|
|
3476
|
-
react.useEffect(() => {
|
|
3477
|
-
if (!isOpen) return;
|
|
3478
|
-
const handleKeyDown = (e) => {
|
|
3479
|
-
if (e.key === "Escape") {
|
|
3480
|
-
onClose();
|
|
3481
|
-
}
|
|
3482
|
-
};
|
|
3483
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
3484
|
-
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
3485
|
-
}, [isOpen, onClose]);
|
|
3486
|
-
if (!isOpen) return null;
|
|
3487
|
-
const handleBackdropClick = (e) => {
|
|
3488
|
-
if (e.target === e.currentTarget) {
|
|
3489
|
-
onClose();
|
|
3490
|
-
}
|
|
3491
|
-
};
|
|
3492
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3493
|
-
"div",
|
|
3494
|
-
{
|
|
3495
|
-
className: "fixed inset-0 bg-black/70 backdrop-blur-xl flex items-center justify-center z-50 p-2 sm:p-4",
|
|
3496
|
-
onClick: handleBackdropClick,
|
|
3497
|
-
role: "dialog",
|
|
3498
|
-
"aria-modal": "true",
|
|
3499
|
-
"aria-label": "Broadcast player",
|
|
3500
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full max-w-7xl max-h-[95vh] sm:max-h-[90vh] overflow-hidden", children: [
|
|
3501
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3502
|
-
"button",
|
|
3503
|
-
{
|
|
3504
|
-
ref: closeButtonRef,
|
|
3505
|
-
onClick: onClose,
|
|
3506
|
-
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",
|
|
3507
|
-
title: "Close (ESC)",
|
|
3508
|
-
"aria-label": "Close player",
|
|
3509
|
-
children: "\xD7"
|
|
3510
|
-
}
|
|
3511
|
-
),
|
|
3512
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3513
|
-
BroadcastPlayer,
|
|
3514
|
-
{
|
|
3515
|
-
broadcast,
|
|
3516
|
-
appId,
|
|
3517
|
-
contentId,
|
|
3518
|
-
foreignId,
|
|
3519
|
-
foreignTier,
|
|
3520
|
-
renderClipCreator,
|
|
3521
|
-
className,
|
|
3522
|
-
enableKeyboardShortcuts,
|
|
3523
|
-
onError: (error) => {
|
|
3524
|
-
debug.error("[BroadcastPlayerModal] Player error:", error);
|
|
3525
|
-
}
|
|
3526
|
-
}
|
|
3527
|
-
)
|
|
3528
|
-
] })
|
|
3529
|
-
}
|
|
3530
|
-
);
|
|
3531
|
-
}
|
|
3532
|
-
var BroadcastPlayerErrorBoundary = class extends react.Component {
|
|
3427
|
+
var DialtribePlayerErrorBoundary = class extends React2.Component {
|
|
3533
3428
|
constructor(props) {
|
|
3534
3429
|
super(props);
|
|
3535
3430
|
this.handleReset = () => {
|
|
@@ -3655,8 +3550,86 @@ var BroadcastPlayerErrorBoundary = class extends react.Component {
|
|
|
3655
3550
|
return this.props.children;
|
|
3656
3551
|
}
|
|
3657
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
|
+
}
|
|
3658
3631
|
|
|
3659
|
-
// src/utils/
|
|
3632
|
+
// src/utils/dialtribe-popup.ts
|
|
3660
3633
|
function calculatePopupDimensions() {
|
|
3661
3634
|
const screenWidth = window.screen.width;
|
|
3662
3635
|
const screenHeight = window.screen.height;
|
|
@@ -3674,26 +3647,22 @@ function calculatePopupDimensions() {
|
|
|
3674
3647
|
const top = Math.floor((screenHeight - height) / 2);
|
|
3675
3648
|
return { width, height, left, top };
|
|
3676
3649
|
}
|
|
3677
|
-
function
|
|
3650
|
+
function openDialtribeStreamerPopup(options) {
|
|
3678
3651
|
const {
|
|
3679
3652
|
sessionToken,
|
|
3680
3653
|
streamKey,
|
|
3654
|
+
streamerUrl,
|
|
3681
3655
|
appId,
|
|
3682
|
-
|
|
3683
|
-
additionalParams,
|
|
3684
|
-
baseUrl = "/broadcasts/new"
|
|
3656
|
+
additionalParams
|
|
3685
3657
|
} = options;
|
|
3686
3658
|
const { width, height, left, top } = calculatePopupDimensions();
|
|
3687
3659
|
const params = new URLSearchParams();
|
|
3688
|
-
if (mode) {
|
|
3689
|
-
params.append("mode", mode);
|
|
3690
|
-
}
|
|
3691
3660
|
if (additionalParams) {
|
|
3692
3661
|
Object.entries(additionalParams).forEach(([key, value]) => {
|
|
3693
3662
|
params.append(key, value);
|
|
3694
3663
|
});
|
|
3695
3664
|
}
|
|
3696
|
-
const url = `${
|
|
3665
|
+
const url = `${streamerUrl}${params.toString() ? `?${params.toString()}` : ""}`;
|
|
3697
3666
|
const popup = window.open(
|
|
3698
3667
|
url,
|
|
3699
3668
|
"_blank",
|
|
@@ -3723,18 +3692,177 @@ function openBroadcastStreamerPopup(options) {
|
|
|
3723
3692
|
setTimeout(sendMessage, 500);
|
|
3724
3693
|
return popup;
|
|
3725
3694
|
}
|
|
3726
|
-
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
|
+
}
|
|
3727
3855
|
|
|
3728
3856
|
exports.AudioWaveform = AudioWaveform;
|
|
3729
|
-
exports.BroadcastPlayer = BroadcastPlayer;
|
|
3730
|
-
exports.BroadcastPlayerErrorBoundary = BroadcastPlayerErrorBoundary;
|
|
3731
|
-
exports.BroadcastPlayerModal = BroadcastPlayerModal;
|
|
3732
|
-
exports.BroadcastStreamer = BroadcastStreamer;
|
|
3733
3857
|
exports.CDN_DOMAIN = CDN_DOMAIN;
|
|
3734
3858
|
exports.DEFAULT_ENCODER_SERVER_URL = DEFAULT_ENCODER_SERVER_URL;
|
|
3735
3859
|
exports.DIALTRIBE_API_BASE = DIALTRIBE_API_BASE;
|
|
3736
|
-
exports.
|
|
3737
|
-
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;
|
|
3738
3866
|
exports.ENDPOINTS = ENDPOINTS;
|
|
3739
3867
|
exports.HTTP_STATUS = HTTP_STATUS;
|
|
3740
3868
|
exports.LoadingSpinner = LoadingSpinner;
|
|
@@ -3751,8 +3879,10 @@ exports.formatTime = formatTime;
|
|
|
3751
3879
|
exports.getMediaConstraints = getMediaConstraints;
|
|
3752
3880
|
exports.getMediaRecorderOptions = getMediaRecorderOptions;
|
|
3753
3881
|
exports.openBroadcastPopup = openBroadcastPopup;
|
|
3754
|
-
exports.
|
|
3755
|
-
exports.
|
|
3756
|
-
exports.
|
|
3757
|
-
|
|
3758
|
-
|
|
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
|