sanity-plugin-mux-input 2.14.0 → 2.15.0
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 +25 -24
- package/dist/index.d.mts +13 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +771 -351
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +773 -353
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/_exports/index.ts +1 -0
- package/src/actions/secrets.ts +6 -1
- package/src/actions/upload.ts +1 -1
- package/src/components/ConfigureApi.tsx +51 -5
- package/src/components/EditCaptionDialog.tsx +2 -2
- package/src/components/InputBrowser.tsx +8 -2
- package/src/components/PageSelector.tsx +4 -7
- package/src/components/Player.styled.tsx +7 -2
- package/src/components/PlayerActionsMenu.tsx +1 -1
- package/src/components/SelectAsset.tsx +9 -3
- package/src/components/StudioTool.tsx +2 -2
- package/src/components/UploadConfiguration.tsx +104 -343
- package/src/components/Uploader.tsx +18 -7
- package/src/components/VideoDetails/VideoDetails.tsx +28 -8
- package/src/components/VideoInBrowser.tsx +53 -6
- package/src/components/VideoPlayer.tsx +120 -47
- package/src/components/VideoThumbnail.tsx +84 -72
- package/src/components/VideosBrowser.tsx +7 -5
- package/src/components/uploadConfiguration/PlaybackPolicy.tsx +95 -6
- package/src/components/uploadConfiguration/PlaybackPolicyOption.tsx +26 -10
- package/src/components/uploadConfiguration/ResolutionTierSelector.tsx +71 -0
- package/src/components/uploadConfiguration/StaticRenditionSelector.tsx +179 -0
- package/src/context/DrmPlaybackWarningContext.tsx +93 -0
- package/src/hooks/useFetchFileSize.ts +54 -0
- package/src/hooks/useMediaMetadata.ts +100 -0
- package/src/hooks/useSaveSecrets.ts +10 -3
- package/src/hooks/useSecretsDocumentValues.ts +9 -1
- package/src/hooks/useSecretsFormState.ts +6 -3
- package/src/util/asserters.ts +14 -0
- package/src/util/createUrlParamsObject.ts +7 -3
- package/src/util/generateJwt.ts +11 -2
- package/src/util/getPlaybackPolicy.ts +63 -4
- package/src/util/getStoryboardSrc.ts +7 -3
- package/src/util/getVideoMetadata.ts +1 -0
- package/src/util/getVideoSrc.ts +9 -9
- package/src/util/readSecrets.ts +3 -1
- package/src/util/textTracks.ts +6 -3
- package/src/util/tryWithSuspend.ts +22 -0
- package/src/util/types.ts +27 -2
- package/src/util/getPlaybackId.ts +0 -9
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useClient as useClient$1, createHookFromObservableFactory, useDocumentStore, collate, useDocumentValues, truncateString, useFormattedDuration, SanityDefaultPreview, useTimeAgo, TextWithTone, isRecord, getPreviewStateObservable, getPreviewValueWithFallback, DocumentPreviewPresence, useDocumentPreviewStore, useSchema, useDocumentPresence, PreviewCard, useCurrentUser, isReference, useProjectId, useDataset, PatchEvent, unset, setIfMissing, set, LinearProgress, FormField as FormField$2, definePlugin } from "sanity";
|
|
2
2
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { ErrorOutlineIcon, InfoOutlineIcon, RetryIcon, CheckmarkCircleIcon, RetrieveIcon, ChevronLeftIcon, ChevronRightIcon, SyncIcon, SortIcon, UploadIcon, TranslateIcon, DownloadIcon, AddIcon, ChevronUpIcon, ChevronDownIcon, TrashIcon, EditIcon, WarningOutlineIcon, PublishIcon, DocumentIcon, RevertIcon, SearchIcon, ClockIcon, CropIcon, CalendarIcon, TagIcon, CheckmarkIcon, LockIcon, PlayIcon, PlugIcon, EllipsisHorizontalIcon, ImageIcon, ResetIcon, WarningFilledIcon, DocumentVideoIcon } from "@sanity/icons";
|
|
4
|
-
import {
|
|
5
|
-
import React, { useState, useMemo, useCallback, useReducer, useId, memo, useRef, useEffect,
|
|
4
|
+
import { Dialog, Stack, Card, Text, Button, useTheme_v2, Flex, Box, TextInput, Checkbox, Code, Inline, Spinner, Heading, Label as Label$1, MenuButton, Menu, MenuItem, useToast, Autocomplete, Tooltip, TabList, Tab, TabPanel, Grid, useClickOutsideEvent, Popover, MenuDivider, Radio, rem } from "@sanity/ui";
|
|
5
|
+
import React, { createContext, useContext, useState, useMemo, useCallback, useReducer, useId, memo, useRef, useEffect, Suspense, isValidElement, PureComponent, createElement, forwardRef } from "react";
|
|
6
6
|
import compact from "lodash/compact.js";
|
|
7
7
|
import toLower from "lodash/toLower.js";
|
|
8
8
|
import trim from "lodash/trim.js";
|
|
@@ -35,7 +35,45 @@ const ToolIcon = () => /* @__PURE__ */ jsx(
|
|
|
35
35
|
xmlns: "http://www.w3.org/2000/svg",
|
|
36
36
|
children: /* @__PURE__ */ jsx("path", { d: "M21 3H3c-1.11 0-2 .89-2 2v12c0 1.1.89 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.11-.9-2-2-2zm0 14H3V5h18v12zm-5-6l-7 4V7z" })
|
|
37
37
|
}
|
|
38
|
-
),
|
|
38
|
+
), LOCAL_STORAGE_HAS_SHOWN_WARNING_KEY = "mux-plugin-has-shown-drm-playback-warning", DrmPlaybackWarningContext = createContext({
|
|
39
|
+
hasShownWarning: !1,
|
|
40
|
+
setHasWarnedAboutDrmPlayback: () => null
|
|
41
|
+
}), DrmPlaybackWarningContextProvider = ({
|
|
42
|
+
config,
|
|
43
|
+
children
|
|
44
|
+
}) => {
|
|
45
|
+
const hasWarned = (config?.disableDrmPlaybackWarning ?? !1) || window.localStorage.getItem(LOCAL_STORAGE_HAS_SHOWN_WARNING_KEY) === "true", [hasWarnedAboutDrmPlayback, setHasWarnedAboutDrmPlayback] = useState(hasWarned), setHasShownWarning = (b) => {
|
|
46
|
+
window.localStorage.setItem(LOCAL_STORAGE_HAS_SHOWN_WARNING_KEY, b.toString()), setHasWarnedAboutDrmPlayback(b);
|
|
47
|
+
};
|
|
48
|
+
return /* @__PURE__ */ jsx(
|
|
49
|
+
DrmPlaybackWarningContext.Provider,
|
|
50
|
+
{
|
|
51
|
+
value: {
|
|
52
|
+
hasShownWarning: hasWarnedAboutDrmPlayback,
|
|
53
|
+
setHasWarnedAboutDrmPlayback: setHasShownWarning
|
|
54
|
+
},
|
|
55
|
+
children
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
}, useDrmPlaybackWarningContext = () => useContext(DrmPlaybackWarningContext), DRMWarningDialog = ({ onClose }) => {
|
|
59
|
+
const { setHasWarnedAboutDrmPlayback } = useDrmPlaybackWarningContext(), _onClose = () => {
|
|
60
|
+
setHasWarnedAboutDrmPlayback(!0), onClose();
|
|
61
|
+
};
|
|
62
|
+
return /* @__PURE__ */ jsx(
|
|
63
|
+
Dialog,
|
|
64
|
+
{
|
|
65
|
+
open: !0,
|
|
66
|
+
id: "drm-playback-warn",
|
|
67
|
+
onClose: _onClose,
|
|
68
|
+
header: "DRM Playback Warning",
|
|
69
|
+
footer: /* @__PURE__ */ jsx(Stack, { padding: 3, children: /* @__PURE__ */ jsx(Button, { mode: "ghost", tone: "primary", onClick: _onClose, text: "Ok" }) }),
|
|
70
|
+
children: /* @__PURE__ */ jsxs(Stack, { space: 3, padding: 3, children: [
|
|
71
|
+
/* @__PURE__ */ jsx(Card, { padding: [3, 3, 3], radius: 2, children: /* @__PURE__ */ jsx(Stack, { space: 3, children: /* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: "DRM-protected playback will generate a license with a small associated cost. The plugin will attempt to play signed or public playback IDs instead whenever possible." }) }) }),
|
|
72
|
+
/* @__PURE__ */ jsx(Card, { padding: [3, 3, 3], radius: 2, tone: "suggest", children: /* @__PURE__ */ jsx(Stack, { space: 3, children: /* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: "This is a one time warning. If it persists, you can disable it from your plugin configuration." }) }) })
|
|
73
|
+
] })
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
}, SANITY_API_VERSION = "2024-03-05";
|
|
39
77
|
function useClient() {
|
|
40
78
|
return useClient$1({ apiVersion: SANITY_API_VERSION });
|
|
41
79
|
}
|
|
@@ -108,7 +146,7 @@ function useAssets() {
|
|
|
108
146
|
function useDialogState() {
|
|
109
147
|
return useState(!1);
|
|
110
148
|
}
|
|
111
|
-
function saveSecrets(client, token, secretKey, enableSignedUrls, signingKeyId, signingKeyPrivate) {
|
|
149
|
+
function saveSecrets(client, token, secretKey, enableSignedUrls, signingKeyId, signingKeyPrivate, drmConfigId) {
|
|
112
150
|
const doc = {
|
|
113
151
|
_id: "secrets.mux",
|
|
114
152
|
_type: "mux.apiKey",
|
|
@@ -116,9 +154,10 @@ function saveSecrets(client, token, secretKey, enableSignedUrls, signingKeyId, s
|
|
|
116
154
|
secretKey,
|
|
117
155
|
enableSignedUrls,
|
|
118
156
|
signingKeyId,
|
|
119
|
-
signingKeyPrivate
|
|
157
|
+
signingKeyPrivate,
|
|
158
|
+
drmConfigId
|
|
120
159
|
};
|
|
121
|
-
return client.createOrReplace(doc);
|
|
160
|
+
return doc.signingKeyId = enableSignedUrls ? signingKeyId : "", doc.signingKeyPrivate = enableSignedUrls ? signingKeyPrivate : "", client.createOrReplace(doc);
|
|
122
161
|
}
|
|
123
162
|
async function createSigningKeys(client) {
|
|
124
163
|
try {
|
|
@@ -171,7 +210,8 @@ const useSaveSecrets = (client, secrets) => useCallback(
|
|
|
171
210
|
async ({
|
|
172
211
|
token,
|
|
173
212
|
secretKey,
|
|
174
|
-
enableSignedUrls
|
|
213
|
+
enableSignedUrls,
|
|
214
|
+
drmConfigId
|
|
175
215
|
}) => {
|
|
176
216
|
let { signingKeyId, signingKeyPrivate } = secrets;
|
|
177
217
|
try {
|
|
@@ -181,7 +221,8 @@ const useSaveSecrets = (client, secrets) => useCallback(
|
|
|
181
221
|
secretKey,
|
|
182
222
|
enableSignedUrls,
|
|
183
223
|
signingKeyId,
|
|
184
|
-
signingKeyPrivate
|
|
224
|
+
signingKeyPrivate,
|
|
225
|
+
drmConfigId
|
|
185
226
|
), !(await testSecrets(client))?.status && token && secretKey)
|
|
186
227
|
throw new Error("Invalid secrets");
|
|
187
228
|
} catch (err) {
|
|
@@ -200,7 +241,8 @@ const useSaveSecrets = (client, secrets) => useCallback(
|
|
|
200
241
|
secretKey,
|
|
201
242
|
enableSignedUrls,
|
|
202
243
|
signingKeyId,
|
|
203
|
-
signingKeyPrivate
|
|
244
|
+
signingKeyPrivate,
|
|
245
|
+
drmConfigId ?? ""
|
|
204
246
|
);
|
|
205
247
|
} catch (err) {
|
|
206
248
|
throw console.log("Error while creating and saving signing key:", err?.message), err;
|
|
@@ -210,11 +252,19 @@ const useSaveSecrets = (client, secrets) => useCallback(
|
|
|
210
252
|
secretKey,
|
|
211
253
|
enableSignedUrls,
|
|
212
254
|
signingKeyId,
|
|
213
|
-
signingKeyPrivate
|
|
255
|
+
signingKeyPrivate,
|
|
256
|
+
drmConfigId
|
|
214
257
|
};
|
|
215
258
|
},
|
|
216
259
|
[client, secrets]
|
|
217
|
-
), name = "mux-input", cacheNs = "sanity-plugin-mux-input", muxSecretsDocumentId = "secrets.mux", DIALOGS_Z_INDEX = 6e4, THUMBNAIL_ASPECT_RATIO = 1.7777777777777777, MIN_ASPECT_RATIO = 5 / 4, AUDIO_ASPECT_RATIO = 5 / 1, path$1 = [
|
|
260
|
+
), name = "mux-input", cacheNs = "sanity-plugin-mux-input", muxSecretsDocumentId = "secrets.mux", DIALOGS_Z_INDEX = 6e4, THUMBNAIL_ASPECT_RATIO = 1.7777777777777777, MIN_ASPECT_RATIO = 5 / 4, AUDIO_ASPECT_RATIO = 5 / 1, path$1 = [
|
|
261
|
+
"token",
|
|
262
|
+
"secretKey",
|
|
263
|
+
"enableSignedUrls",
|
|
264
|
+
"signingKeyId",
|
|
265
|
+
"signingKeyPrivate",
|
|
266
|
+
"drmConfigId"
|
|
267
|
+
], useSecretsDocumentValues = () => {
|
|
218
268
|
const { error, isLoading, value } = useDocumentValues(
|
|
219
269
|
muxSecretsDocumentId,
|
|
220
270
|
path$1
|
|
@@ -224,7 +274,8 @@ const useSaveSecrets = (client, secrets) => useCallback(
|
|
|
224
274
|
secretKey: value?.secretKey || null,
|
|
225
275
|
enableSignedUrls: value?.enableSignedUrls || !1,
|
|
226
276
|
signingKeyId: value?.signingKeyId || null,
|
|
227
|
-
signingKeyPrivate: value?.signingKeyPrivate || null
|
|
277
|
+
signingKeyPrivate: value?.signingKeyPrivate || null,
|
|
278
|
+
drmConfigId: value?.drmConfigId || null
|
|
228
279
|
};
|
|
229
280
|
return {
|
|
230
281
|
isInitialSetup: !exists,
|
|
@@ -234,7 +285,7 @@ const useSaveSecrets = (client, secrets) => useCallback(
|
|
|
234
285
|
}, [value]);
|
|
235
286
|
return { error, isLoading, value: cache };
|
|
236
287
|
};
|
|
237
|
-
function init({ token, secretKey, enableSignedUrls }) {
|
|
288
|
+
function init({ token, secretKey, enableSignedUrls, drmConfigId }) {
|
|
238
289
|
return {
|
|
239
290
|
submitting: !1,
|
|
240
291
|
error: null,
|
|
@@ -242,7 +293,8 @@ function init({ token, secretKey, enableSignedUrls }) {
|
|
|
242
293
|
// This ensures the `dirty` check works correctly
|
|
243
294
|
token: token ?? "",
|
|
244
295
|
secretKey: secretKey ?? "",
|
|
245
|
-
enableSignedUrls: enableSignedUrls ?? !1
|
|
296
|
+
enableSignedUrls: enableSignedUrls ?? !1,
|
|
297
|
+
drmConfigId: drmConfigId ?? ""
|
|
246
298
|
};
|
|
247
299
|
}
|
|
248
300
|
function reducer(state, action) {
|
|
@@ -270,7 +322,8 @@ function readSecrets(client) {
|
|
|
270
322
|
secretKey,
|
|
271
323
|
enableSignedUrls,
|
|
272
324
|
signingKeyId,
|
|
273
|
-
signingKeyPrivate
|
|
325
|
+
signingKeyPrivate,
|
|
326
|
+
drmConfigId
|
|
274
327
|
}`,
|
|
275
328
|
{ _id }
|
|
276
329
|
);
|
|
@@ -279,7 +332,8 @@ function readSecrets(client) {
|
|
|
279
332
|
secretKey: data?.secretKey || null,
|
|
280
333
|
enableSignedUrls: !!data?.enableSignedUrls || !1,
|
|
281
334
|
signingKeyId: data?.signingKeyId || null,
|
|
282
|
-
signingKeyPrivate: data?.signingKeyPrivate || null
|
|
335
|
+
signingKeyPrivate: data?.signingKeyPrivate || null,
|
|
336
|
+
drmConfigId: data?.drmConfigId || null
|
|
283
337
|
};
|
|
284
338
|
}, [cacheNs, _id, projectId, dataset]);
|
|
285
339
|
}
|
|
@@ -342,20 +396,20 @@ function FormField(props) {
|
|
|
342
396
|
] });
|
|
343
397
|
}
|
|
344
398
|
var FormField$1 = memo(FormField);
|
|
345
|
-
const fieldNames = ["token", "secretKey", "enableSignedUrls"];
|
|
399
|
+
const fieldNames = ["token", "secretKey", "enableSignedUrls", "drmConfigId"];
|
|
346
400
|
function ConfigureApiDialog({ secrets, setDialogState }) {
|
|
347
401
|
const client = useClient(), [state, dispatch] = useSecretsFormState(secrets), hasSecretsInitially = useMemo(() => secrets.token && secrets.secretKey, [secrets]), handleClose = useCallback(() => setDialogState(!1), [setDialogState]), dirty = useMemo(
|
|
348
|
-
() => secrets.token !== state.token || secrets.secretKey !== state.secretKey || secrets.enableSignedUrls !== state.enableSignedUrls,
|
|
402
|
+
() => secrets.token !== state.token || secrets.secretKey !== state.secretKey || secrets.enableSignedUrls !== state.enableSignedUrls || secrets.drmConfigId !== state.drmConfigId,
|
|
349
403
|
[secrets, state]
|
|
350
|
-
), id = `ConfigureApi${useId()}`, [tokenId, secretKeyId, enableSignedUrlsId] = useMemo(
|
|
404
|
+
), id = `ConfigureApi${useId()}`, [tokenId, secretKeyId, enableSignedUrlsId, drmConfigIdId] = useMemo(
|
|
351
405
|
() => fieldNames.map((field) => `${id}-${field}`),
|
|
352
406
|
[id]
|
|
353
407
|
), firstField = useRef(null), handleSaveSecrets = useSaveSecrets(client, secrets), saving = useRef(!1), handleSubmit = useCallback(
|
|
354
408
|
(event) => {
|
|
355
409
|
if (event.preventDefault(), !saving.current && event.currentTarget.reportValidity()) {
|
|
356
410
|
saving.current = !0, dispatch({ type: "submit" });
|
|
357
|
-
const { token, secretKey, enableSignedUrls } = state;
|
|
358
|
-
handleSaveSecrets({ token, secretKey, enableSignedUrls }).then((savedSecrets) => {
|
|
411
|
+
const { token, secretKey, enableSignedUrls, drmConfigId } = state;
|
|
412
|
+
handleSaveSecrets({ token, secretKey, enableSignedUrls, drmConfigId }).then((savedSecrets) => {
|
|
359
413
|
const { projectId, dataset } = client.config();
|
|
360
414
|
clear([cacheNs, _id, projectId, dataset]), preload(() => Promise.resolve(savedSecrets), [cacheNs, _id, projectId, dataset]), setDialogState(!1);
|
|
361
415
|
}).catch((err) => dispatch({ type: "error", payload: err.message })).finally(() => {
|
|
@@ -388,6 +442,14 @@ function ConfigureApiDialog({ secrets, setDialogState }) {
|
|
|
388
442
|
});
|
|
389
443
|
},
|
|
390
444
|
[dispatch]
|
|
445
|
+
), handleChangeDrmConfigId = useCallback(
|
|
446
|
+
(event) => {
|
|
447
|
+
dispatch({
|
|
448
|
+
type: "change",
|
|
449
|
+
payload: { name: "drmConfigId", value: event.currentTarget.value }
|
|
450
|
+
});
|
|
451
|
+
},
|
|
452
|
+
[dispatch]
|
|
391
453
|
);
|
|
392
454
|
return useEffect(() => {
|
|
393
455
|
firstField.current && firstField.current.focus();
|
|
@@ -474,6 +536,45 @@ function ConfigureApiDialog({ secrets, setDialogState }) {
|
|
|
474
536
|
] })
|
|
475
537
|
] }) }) : null
|
|
476
538
|
] }),
|
|
539
|
+
/* @__PURE__ */ jsx(FormField$1, { title: "DRM Configuration ID", inputId: drmConfigIdId, children: /* @__PURE__ */ jsx(
|
|
540
|
+
TextInput,
|
|
541
|
+
{
|
|
542
|
+
id: drmConfigIdId,
|
|
543
|
+
onChange: handleChangeDrmConfigId,
|
|
544
|
+
type: "text",
|
|
545
|
+
value: state.drmConfigId ?? "",
|
|
546
|
+
required: !1
|
|
547
|
+
}
|
|
548
|
+
) }),
|
|
549
|
+
/* @__PURE__ */ jsx(Card, { padding: [3, 3, 3], radius: 2, shadow: 1, tone: "neutral", children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
550
|
+
/* @__PURE__ */ jsxs(Text, { size: 1, children: [
|
|
551
|
+
"DRM (Digital Rights Management) provides an extra layer of content security for video content streamed from Mux. For additional information check out our",
|
|
552
|
+
" ",
|
|
553
|
+
/* @__PURE__ */ jsx(
|
|
554
|
+
"a",
|
|
555
|
+
{
|
|
556
|
+
href: "https://www.mux.com/docs/guides/protect-videos-with-drm#play-drm-protected-videos",
|
|
557
|
+
target: "_blank",
|
|
558
|
+
rel: "noopener noreferrer",
|
|
559
|
+
children: "DRM Guide"
|
|
560
|
+
}
|
|
561
|
+
),
|
|
562
|
+
"."
|
|
563
|
+
] }),
|
|
564
|
+
/* @__PURE__ */ jsxs(Text, { size: 1, children: [
|
|
565
|
+
/* @__PURE__ */ jsx(
|
|
566
|
+
"a",
|
|
567
|
+
{
|
|
568
|
+
href: "https://www.mux.com/support/human",
|
|
569
|
+
target: "_blank",
|
|
570
|
+
rel: "noopener noreferrer",
|
|
571
|
+
children: "Contact us"
|
|
572
|
+
}
|
|
573
|
+
),
|
|
574
|
+
" ",
|
|
575
|
+
"to get started using DRM."
|
|
576
|
+
] })
|
|
577
|
+
] }) }),
|
|
477
578
|
/* @__PURE__ */ jsxs(Inline, { space: 2, children: [
|
|
478
579
|
/* @__PURE__ */ jsx(
|
|
479
580
|
Button,
|
|
@@ -777,6 +878,35 @@ function useInView(ref, options = {}) {
|
|
|
777
878
|
};
|
|
778
879
|
}, [options, ref]), inView;
|
|
779
880
|
}
|
|
881
|
+
function getPlaybackId(asset, priority = ["drm", "signed", "public"]) {
|
|
882
|
+
try {
|
|
883
|
+
if (!asset)
|
|
884
|
+
throw new TypeError("Tried to get playback Id with no asset");
|
|
885
|
+
const playbackIds = asset.data?.playback_ids;
|
|
886
|
+
if (playbackIds && playbackIds.length > 0) {
|
|
887
|
+
for (const policy of priority) {
|
|
888
|
+
const match = playbackIds.find((entry) => entry.policy === policy);
|
|
889
|
+
if (match)
|
|
890
|
+
return match.id;
|
|
891
|
+
}
|
|
892
|
+
return playbackIds[0].id;
|
|
893
|
+
}
|
|
894
|
+
throw new TypeError("Missing playbackId");
|
|
895
|
+
} catch (e) {
|
|
896
|
+
throw console.error("Asset is missing a playbackId", { asset }, e), e;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
function getPlaybackPolicy(asset) {
|
|
900
|
+
return asset.data?.playback_ids?.find(
|
|
901
|
+
(playbackId) => getPlaybackId(asset, ["drm", "signed", "public"]) === playbackId.id
|
|
902
|
+
) ?? { id: "", policy: "public" };
|
|
903
|
+
}
|
|
904
|
+
function getPlaybackPolicyById(asset, playbackId) {
|
|
905
|
+
return asset.data?.playback_ids?.find((entry) => playbackId === entry.id);
|
|
906
|
+
}
|
|
907
|
+
function hasPlaybackPolicy(data, policy) {
|
|
908
|
+
return data.advanced_playback_policies && data.advanced_playback_policies.find((p) => p.policy === policy) || data.playback_policy?.find((p) => p === policy);
|
|
909
|
+
}
|
|
780
910
|
function generateJwt(client, playbackId, aud, payload) {
|
|
781
911
|
const { signingKeyId, signingKeyPrivate } = readSecrets(client);
|
|
782
912
|
if (!signingKeyId)
|
|
@@ -797,20 +927,13 @@ function generateJwt(client, playbackId, aud, payload) {
|
|
|
797
927
|
}
|
|
798
928
|
);
|
|
799
929
|
}
|
|
800
|
-
function getPlaybackId(asset) {
|
|
801
|
-
if (!asset?.playbackId)
|
|
802
|
-
throw console.error("Asset is missing a playbackId", { asset }), new TypeError("Missing playbackId");
|
|
803
|
-
return asset.playbackId;
|
|
804
|
-
}
|
|
805
|
-
function getPlaybackPolicy(asset) {
|
|
806
|
-
return asset.data?.playback_ids?.find((playbackId) => asset.playbackId === playbackId.id)?.policy ?? "public";
|
|
807
|
-
}
|
|
808
930
|
function createUrlParamsObject(client, asset, params, audience) {
|
|
809
931
|
const playbackId = getPlaybackId(asset);
|
|
810
932
|
let searchParams = new URLSearchParams(
|
|
811
933
|
JSON.parse(JSON.stringify(params, (_, v) => v ?? void 0))
|
|
812
934
|
);
|
|
813
|
-
|
|
935
|
+
const playbackPolicy = getPlaybackPolicyById(asset, playbackId)?.policy;
|
|
936
|
+
if (playbackPolicy === "signed" || playbackPolicy === "drm") {
|
|
814
937
|
const token = generateJwt(client, playbackId, audience, params);
|
|
815
938
|
searchParams = new URLSearchParams({ token });
|
|
816
939
|
}
|
|
@@ -841,6 +964,15 @@ function getPosterSrc({
|
|
|
841
964
|
const { playbackId, searchParams } = createUrlParamsObject(client, asset, params, "t");
|
|
842
965
|
return `https://image.mux.com/${playbackId}/thumbnail.png?${searchParams}`;
|
|
843
966
|
}
|
|
967
|
+
function tryWithSuspend(block, onError) {
|
|
968
|
+
try {
|
|
969
|
+
return block();
|
|
970
|
+
} catch (errorOrPromise) {
|
|
971
|
+
if (errorOrPromise instanceof Promise)
|
|
972
|
+
throw errorOrPromise;
|
|
973
|
+
return onError ? onError(errorOrPromise) : void 0;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
844
976
|
const Image = styled.img`
|
|
845
977
|
transition: opacity 0.175s ease-out 0s;
|
|
846
978
|
display: block;
|
|
@@ -858,22 +990,22 @@ function VideoThumbnail({
|
|
|
858
990
|
width,
|
|
859
991
|
staticImage = !1
|
|
860
992
|
}) {
|
|
861
|
-
const ref = useRef(null), inView = useInView(ref),
|
|
862
|
-
|
|
993
|
+
const posterWidth = width || 250, client = useClient(), ref = useRef(null), inView = useInView(ref), [status, setStatus] = useState("loading"), [error, setError] = useState(null), thumbnailSrc = useMemo(() => tryWithSuspend(
|
|
994
|
+
() => {
|
|
863
995
|
let thumbnail;
|
|
864
996
|
return staticImage ? thumbnail = getPosterSrc({ asset, client, width: posterWidth }) : thumbnail = getAnimatedPosterSrc({ asset, client, width: posterWidth }), thumbnail;
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
|
|
997
|
+
},
|
|
998
|
+
(err) => {
|
|
999
|
+
handleError(err.message);
|
|
868
1000
|
}
|
|
869
|
-
|
|
1001
|
+
), [asset, client, posterWidth, staticImage]);
|
|
870
1002
|
function handleLoad() {
|
|
871
1003
|
setStatus("loaded");
|
|
872
1004
|
}
|
|
873
|
-
function handleError() {
|
|
874
|
-
setStatus("error");
|
|
1005
|
+
function handleError(err) {
|
|
1006
|
+
setStatus("error"), setError(err || "Failed loading thumbnail");
|
|
875
1007
|
}
|
|
876
|
-
return /* @__PURE__ */ jsx(
|
|
1008
|
+
return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx("span", { children: "Preparing thumbnail" }), children: /* @__PURE__ */ jsx(
|
|
877
1009
|
Card,
|
|
878
1010
|
{
|
|
879
1011
|
style: {
|
|
@@ -914,23 +1046,23 @@ function VideoThumbnail({
|
|
|
914
1046
|
},
|
|
915
1047
|
children: [
|
|
916
1048
|
/* @__PURE__ */ jsx(Text, { size: 4, muted: !0, children: /* @__PURE__ */ jsx(ErrorOutlineIcon, { style: { fontSize: "1.75em" } }) }),
|
|
917
|
-
/* @__PURE__ */ jsx(Text, { muted: !0, align: "center", children:
|
|
1049
|
+
/* @__PURE__ */ jsx(Text, { muted: !0, align: "center", children: error })
|
|
918
1050
|
]
|
|
919
1051
|
}
|
|
920
1052
|
),
|
|
921
1053
|
/* @__PURE__ */ jsx(
|
|
922
1054
|
Image,
|
|
923
1055
|
{
|
|
924
|
-
src,
|
|
1056
|
+
src: thumbnailSrc ?? void 0,
|
|
925
1057
|
alt: `Preview for ${staticImage ? "image" : "video"} ${asset.filename || asset.assetId}`,
|
|
926
1058
|
onLoad: handleLoad,
|
|
927
|
-
onError: handleError,
|
|
1059
|
+
onError: () => handleError(),
|
|
928
1060
|
style: { opacity: status === "loaded" ? 1 : 0 }
|
|
929
1061
|
}
|
|
930
1062
|
)
|
|
931
1063
|
] }) : null
|
|
932
1064
|
}
|
|
933
|
-
);
|
|
1065
|
+
) });
|
|
934
1066
|
}
|
|
935
1067
|
const MissingAssetCheckbox = styled(Checkbox)`
|
|
936
1068
|
position: static !important;
|
|
@@ -1164,7 +1296,7 @@ const PageSelector = (props) => {
|
|
|
1164
1296
|
style: { cursor: "pointer" },
|
|
1165
1297
|
disabled: page <= 0,
|
|
1166
1298
|
onClick: () => {
|
|
1167
|
-
setPage((
|
|
1299
|
+
setPage((p) => Math.min(props.total - 1, Math.max(0, p - 1)));
|
|
1168
1300
|
}
|
|
1169
1301
|
}
|
|
1170
1302
|
),
|
|
@@ -1183,7 +1315,7 @@ const PageSelector = (props) => {
|
|
|
1183
1315
|
style: { cursor: "pointer" },
|
|
1184
1316
|
disabled: page >= props.total - 1,
|
|
1185
1317
|
onClick: () => {
|
|
1186
|
-
setPage((
|
|
1318
|
+
setPage((p) => Math.min(props.total - 1, Math.max(0, p + 1)));
|
|
1187
1319
|
}
|
|
1188
1320
|
}
|
|
1189
1321
|
)
|
|
@@ -1547,9 +1679,9 @@ async function downloadVttFile(client, asset, track) {
|
|
|
1547
1679
|
const playbackId = getPlaybackId(asset);
|
|
1548
1680
|
if (!playbackId)
|
|
1549
1681
|
throw new Error("Playback ID is required");
|
|
1550
|
-
const playbackPolicy = getPlaybackPolicy(asset);
|
|
1682
|
+
const playbackPolicy = getPlaybackPolicy(asset)?.policy;
|
|
1551
1683
|
let downloadUrl = `https://stream.mux.com/${playbackId}/text/${track.id}.vtt`;
|
|
1552
|
-
if (playbackPolicy === "signed") {
|
|
1684
|
+
if (playbackPolicy === "signed" || playbackPolicy === "drm") {
|
|
1553
1685
|
const token = generateJwt(client, playbackId, "v");
|
|
1554
1686
|
downloadUrl += `?token=${token}`;
|
|
1555
1687
|
}
|
|
@@ -2027,7 +2159,7 @@ function EditCaptionDialog({ asset, track, onUpdate, onClose }) {
|
|
|
2027
2159
|
const playbackId = getPlaybackId(asset);
|
|
2028
2160
|
if (!playbackId) return "";
|
|
2029
2161
|
let url = `https://stream.mux.com/${playbackId}/text/${track.id}.vtt`;
|
|
2030
|
-
if (getPlaybackPolicy(asset) === "signed") {
|
|
2162
|
+
if (getPlaybackPolicy(asset)?.policy === "signed") {
|
|
2031
2163
|
const token = generateJwt(client, playbackId, "v");
|
|
2032
2164
|
url += `?token=${token}`;
|
|
2033
2165
|
}
|
|
@@ -2683,13 +2815,13 @@ const DialogStateContext = createContext({
|
|
|
2683
2815
|
setDialogState,
|
|
2684
2816
|
children
|
|
2685
2817
|
}) => /* @__PURE__ */ jsx(DialogStateContext.Provider, { value: { dialogState, setDialogState }, children }), useDialogStateContext = () => useContext(DialogStateContext);
|
|
2686
|
-
function getVideoSrc({
|
|
2687
|
-
const
|
|
2688
|
-
if (
|
|
2689
|
-
const token = generateJwt(client,
|
|
2818
|
+
function getVideoSrc({ client, muxPlaybackId: muxPlaybackId2 }) {
|
|
2819
|
+
const searchParams = new URLSearchParams();
|
|
2820
|
+
if (muxPlaybackId2.policy === "signed" || muxPlaybackId2.policy === "drm") {
|
|
2821
|
+
const token = generateJwt(client, muxPlaybackId2.id, "v");
|
|
2690
2822
|
searchParams.set("token", token);
|
|
2691
2823
|
}
|
|
2692
|
-
return `https://stream.mux.com/${
|
|
2824
|
+
return `https://stream.mux.com/${muxPlaybackId2.id}.m3u8?${searchParams}`;
|
|
2693
2825
|
}
|
|
2694
2826
|
function CaptionsDialog({ asset }) {
|
|
2695
2827
|
const { setDialogState } = useDialogStateContext(), dialogId = `CaptionsDialog${useId()}`;
|
|
@@ -2799,24 +2931,56 @@ function VideoPlayer({
|
|
|
2799
2931
|
hlsConfig,
|
|
2800
2932
|
...props
|
|
2801
2933
|
}) {
|
|
2802
|
-
const client = useClient(), { dialogState } = useDialogStateContext(), isAudio = assetIsAudio(asset), muxPlayer = useRef(null), {
|
|
2803
|
-
src: videoSrc,
|
|
2804
|
-
thumbnail: thumbnailSrc,
|
|
2805
|
-
error
|
|
2806
|
-
} = useMemo(() => {
|
|
2934
|
+
const client = useClient(), { dialogState } = useDialogStateContext(), isAudio = assetIsAudio(asset), muxPlayer = useRef(null), [error, setError] = useState(), playbackId = useMemo(() => {
|
|
2807
2935
|
try {
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
return
|
|
2936
|
+
return getPlaybackId(asset, ["public", "signed", "drm"]);
|
|
2937
|
+
} catch {
|
|
2938
|
+
setError(new TypeError("Asset has no playback ID"));
|
|
2939
|
+
return;
|
|
2812
2940
|
}
|
|
2813
|
-
}, [asset
|
|
2941
|
+
}, [asset]), muxPlaybackId2 = useMemo(() => {
|
|
2942
|
+
if (playbackId)
|
|
2943
|
+
return getPlaybackPolicyById(asset, playbackId);
|
|
2944
|
+
}, [asset, playbackId]), src = useMemo(() => {
|
|
2945
|
+
if (playbackId && muxPlaybackId2)
|
|
2946
|
+
return tryWithSuspend(
|
|
2947
|
+
() => getVideoSrc({ muxPlaybackId: muxPlaybackId2, client }),
|
|
2948
|
+
(e) => {
|
|
2949
|
+
setError(e);
|
|
2950
|
+
}
|
|
2951
|
+
);
|
|
2952
|
+
}, [muxPlaybackId2, playbackId, client]), poster = useMemo(() => tryWithSuspend(
|
|
2953
|
+
() => getPosterSrc({ asset, client, width: thumbnailWidth }),
|
|
2954
|
+
(e) => {
|
|
2955
|
+
setError(e);
|
|
2956
|
+
}
|
|
2957
|
+
), [asset, client, thumbnailWidth]), signedToken = useMemo(() => {
|
|
2814
2958
|
try {
|
|
2815
|
-
return new URL(
|
|
2959
|
+
return new URL(src).searchParams.get("token");
|
|
2816
2960
|
} catch {
|
|
2817
|
-
return
|
|
2961
|
+
return;
|
|
2818
2962
|
}
|
|
2819
|
-
}, [
|
|
2963
|
+
}, [src]), drmToken = useMemo(() => {
|
|
2964
|
+
if (playbackId && muxPlaybackId2?.policy === "drm")
|
|
2965
|
+
return tryWithSuspend(
|
|
2966
|
+
() => generateJwt(client, playbackId, "d"),
|
|
2967
|
+
(e) => {
|
|
2968
|
+
setError(e);
|
|
2969
|
+
}
|
|
2970
|
+
);
|
|
2971
|
+
}, [client, muxPlaybackId2?.policy, playbackId]), tokens = useMemo(() => {
|
|
2972
|
+
try {
|
|
2973
|
+
const partialTokens = {
|
|
2974
|
+
playback: void 0,
|
|
2975
|
+
thumbnail: void 0,
|
|
2976
|
+
storyboard: void 0,
|
|
2977
|
+
drm: void 0
|
|
2978
|
+
};
|
|
2979
|
+
return signedToken && (partialTokens.playback = signedToken, partialTokens.thumbnail = signedToken, partialTokens.storyboard = signedToken), drmToken && (partialTokens.drm = drmToken), { ...partialTokens };
|
|
2980
|
+
} catch {
|
|
2981
|
+
return;
|
|
2982
|
+
}
|
|
2983
|
+
}, [signedToken, drmToken]), [width, height] = (asset?.data?.aspect_ratio ?? "16:9").split(":").map(Number), targetAspectRatio = props.forceAspectRatio || (Number.isNaN(width) ? 16 / 9 : width / height);
|
|
2820
2984
|
let aspectRatio = Math.max(MIN_ASPECT_RATIO, targetAspectRatio);
|
|
2821
2985
|
return isAudio && (aspectRatio = props.forceAspectRatio ? (
|
|
2822
2986
|
// Make it wider when forcing aspect ratio to balance with videos' rendering height (audio players overflow a bit)
|
|
@@ -2832,7 +2996,7 @@ function VideoPlayer({
|
|
|
2832
2996
|
...isAudio && { display: "flex", alignItems: "flex-end" }
|
|
2833
2997
|
},
|
|
2834
2998
|
children: [
|
|
2835
|
-
|
|
2999
|
+
src && poster && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2836
3000
|
isAudio && /* @__PURE__ */ jsx(
|
|
2837
3001
|
AudioIcon,
|
|
2838
3002
|
{
|
|
@@ -2847,34 +3011,36 @@ function VideoPlayer({
|
|
|
2847
3011
|
}
|
|
2848
3012
|
}
|
|
2849
3013
|
),
|
|
2850
|
-
/* @__PURE__ */
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
3014
|
+
/* @__PURE__ */ jsxs(Suspense, { fallback: null, children: [
|
|
3015
|
+
/* @__PURE__ */ jsx(
|
|
3016
|
+
MuxPlayer,
|
|
3017
|
+
{
|
|
3018
|
+
poster: isAudio ? void 0 : poster,
|
|
3019
|
+
ref: muxPlayer,
|
|
3020
|
+
...props,
|
|
3021
|
+
playsInline: !0,
|
|
3022
|
+
playbackId,
|
|
3023
|
+
tokens,
|
|
3024
|
+
preload: "metadata",
|
|
3025
|
+
crossOrigin: "anonymous",
|
|
3026
|
+
metadata: {
|
|
3027
|
+
player_name: "Sanity Admin Dashboard",
|
|
3028
|
+
player_version: "2.15.0",
|
|
3029
|
+
page_type: "Preview Player"
|
|
3030
|
+
},
|
|
3031
|
+
audio: isAudio,
|
|
3032
|
+
_hlsConfig: hlsConfig,
|
|
3033
|
+
style: {
|
|
3034
|
+
...!isAudio && { height: "100%" },
|
|
3035
|
+
width: "100%",
|
|
3036
|
+
display: "block",
|
|
3037
|
+
objectFit: "contain",
|
|
3038
|
+
...isAudio && { alignSelf: "end" }
|
|
3039
|
+
}
|
|
2874
3040
|
}
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
3041
|
+
),
|
|
3042
|
+
children
|
|
3043
|
+
] })
|
|
2878
3044
|
] }),
|
|
2879
3045
|
error ? /* @__PURE__ */ jsx(
|
|
2880
3046
|
"div",
|
|
@@ -3166,6 +3332,7 @@ function getVideoMetadata(doc) {
|
|
|
3166
3332
|
playbackId: doc.playbackId,
|
|
3167
3333
|
createdAt: date,
|
|
3168
3334
|
duration: doc.data?.duration ? formatSeconds(doc.data?.duration) : void 0,
|
|
3335
|
+
playback_ids: doc.data?.playback_ids,
|
|
3169
3336
|
aspect_ratio: doc.data?.aspect_ratio,
|
|
3170
3337
|
max_stored_resolution: doc.data?.max_stored_resolution,
|
|
3171
3338
|
max_stored_frame_rate: doc.data?.max_stored_frame_rate,
|
|
@@ -3468,14 +3635,7 @@ const AssetInput = (props) => /* @__PURE__ */ jsx(FormField$1, { title: props.la
|
|
|
3468
3635
|
),
|
|
3469
3636
|
/* @__PURE__ */ jsx(IconInfo, { text: `Mux ID:
|
|
3470
3637
|
${displayInfo.id}`, icon: TagIcon, size: 2 }),
|
|
3471
|
-
|
|
3472
|
-
IconInfo,
|
|
3473
|
-
{
|
|
3474
|
-
text: `Playback ID: ${displayInfo.playbackId}`,
|
|
3475
|
-
icon: TagIcon,
|
|
3476
|
-
size: 2
|
|
3477
|
-
}
|
|
3478
|
-
)
|
|
3638
|
+
/* @__PURE__ */ jsx(PlaybackIds, { playback_ids: displayInfo.playback_ids })
|
|
3479
3639
|
] })
|
|
3480
3640
|
] })
|
|
3481
3641
|
}
|
|
@@ -3498,6 +3658,25 @@ ${displayInfo.id}`, icon: TagIcon, size: 2 }),
|
|
|
3498
3658
|
]
|
|
3499
3659
|
}
|
|
3500
3660
|
);
|
|
3661
|
+
}, PlaybackIds = ({ playback_ids }) => playback_ids ? playback_ids.map((entry) => /* @__PURE__ */ jsx(
|
|
3662
|
+
IconInfo,
|
|
3663
|
+
{
|
|
3664
|
+
text: `Playback ID [${policyToText(entry.policy)}]: ${entry.id}`,
|
|
3665
|
+
icon: TagIcon,
|
|
3666
|
+
size: 2
|
|
3667
|
+
},
|
|
3668
|
+
entry.id
|
|
3669
|
+
)) : /* @__PURE__ */ jsx(IconInfo, { text: "No Playback ID", icon: TagIcon, size: 2 }), policyToText = (policy) => {
|
|
3670
|
+
switch (policy) {
|
|
3671
|
+
case "drm":
|
|
3672
|
+
return "DRM";
|
|
3673
|
+
case "signed":
|
|
3674
|
+
return "Signed";
|
|
3675
|
+
case "public":
|
|
3676
|
+
return "Public";
|
|
3677
|
+
default:
|
|
3678
|
+
return policy;
|
|
3679
|
+
}
|
|
3501
3680
|
}, VideoMetadata = (props) => {
|
|
3502
3681
|
if (!props.asset)
|
|
3503
3682
|
return null;
|
|
@@ -3591,10 +3770,12 @@ function VideoInBrowser({
|
|
|
3591
3770
|
onEdit,
|
|
3592
3771
|
asset
|
|
3593
3772
|
}) {
|
|
3594
|
-
const [renderVideo, setRenderVideo] = useState(!1), select = React.useCallback(() => onSelect?.(asset), [onSelect, asset]), edit = React.useCallback(() => onEdit?.(asset), [onEdit, asset]);
|
|
3773
|
+
const [renderVideo, setRenderVideo] = useState(!1), select = React.useCallback(() => onSelect?.(asset), [onSelect, asset]), edit = React.useCallback(() => onEdit?.(asset), [onEdit, asset]), { hasShownWarning } = useDrmPlaybackWarningContext();
|
|
3595
3774
|
if (!asset)
|
|
3596
3775
|
return null;
|
|
3597
|
-
const playbackPolicy = getPlaybackPolicy(asset)
|
|
3776
|
+
const playbackPolicy = getPlaybackPolicy(asset), onClickPlay = () => {
|
|
3777
|
+
playbackPolicy?.policy === "drm" && !hasShownWarning ? setRenderVideo("pre-render-warn") : setRenderVideo("render-video");
|
|
3778
|
+
};
|
|
3598
3779
|
return /* @__PURE__ */ jsxs(
|
|
3599
3780
|
Card,
|
|
3600
3781
|
{
|
|
@@ -3606,7 +3787,7 @@ function VideoInBrowser({
|
|
|
3606
3787
|
position: "relative"
|
|
3607
3788
|
},
|
|
3608
3789
|
children: [
|
|
3609
|
-
playbackPolicy === "signed" && /* @__PURE__ */ jsx(
|
|
3790
|
+
playbackPolicy?.policy === "signed" && /* @__PURE__ */ jsx(
|
|
3610
3791
|
Tooltip,
|
|
3611
3792
|
{
|
|
3612
3793
|
animate: !0,
|
|
@@ -3623,7 +3804,7 @@ function VideoInBrowser({
|
|
|
3623
3804
|
position: "absolute",
|
|
3624
3805
|
left: "1em",
|
|
3625
3806
|
top: "1em",
|
|
3626
|
-
zIndex:
|
|
3807
|
+
zIndex: 11
|
|
3627
3808
|
},
|
|
3628
3809
|
padding: 2,
|
|
3629
3810
|
border: !0,
|
|
@@ -3632,6 +3813,32 @@ function VideoInBrowser({
|
|
|
3632
3813
|
)
|
|
3633
3814
|
}
|
|
3634
3815
|
),
|
|
3816
|
+
playbackPolicy?.policy === "drm" && /* @__PURE__ */ jsx(
|
|
3817
|
+
Tooltip,
|
|
3818
|
+
{
|
|
3819
|
+
animate: !0,
|
|
3820
|
+
content: /* @__PURE__ */ jsx(Card, { padding: 2, radius: 2, children: /* @__PURE__ */ jsx(IconInfo, { icon: LockIcon, text: "DRM playback policy", size: 2 }) }),
|
|
3821
|
+
placement: "right",
|
|
3822
|
+
fallbackPlacements: ["top", "bottom"],
|
|
3823
|
+
portal: !0,
|
|
3824
|
+
children: /* @__PURE__ */ jsx(
|
|
3825
|
+
Card,
|
|
3826
|
+
{
|
|
3827
|
+
tone: "caution",
|
|
3828
|
+
style: {
|
|
3829
|
+
borderRadius: "0.25rem",
|
|
3830
|
+
position: "absolute",
|
|
3831
|
+
left: "1em",
|
|
3832
|
+
top: "1em",
|
|
3833
|
+
zIndex: 11
|
|
3834
|
+
},
|
|
3835
|
+
padding: 2,
|
|
3836
|
+
border: !0,
|
|
3837
|
+
children: /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, weight: "semibold", style: { color: "var(--card-icon-color)" }, children: "DRM" })
|
|
3838
|
+
}
|
|
3839
|
+
)
|
|
3840
|
+
}
|
|
3841
|
+
),
|
|
3635
3842
|
/* @__PURE__ */ jsxs(
|
|
3636
3843
|
Stack,
|
|
3637
3844
|
{
|
|
@@ -3641,7 +3848,15 @@ function VideoInBrowser({
|
|
|
3641
3848
|
gridTemplateRows: "min-content min-content 1fr"
|
|
3642
3849
|
},
|
|
3643
3850
|
children: [
|
|
3644
|
-
renderVideo
|
|
3851
|
+
renderVideo === "pre-render-warn" && /* @__PURE__ */ jsx(
|
|
3852
|
+
DRMWarningDialog,
|
|
3853
|
+
{
|
|
3854
|
+
onClose: () => {
|
|
3855
|
+
setRenderVideo("render-video");
|
|
3856
|
+
}
|
|
3857
|
+
}
|
|
3858
|
+
),
|
|
3859
|
+
renderVideo === "render-video" ? /* @__PURE__ */ jsx(VideoPlayer, { asset, autoPlay: !0, forceAspectRatio: THUMBNAIL_ASPECT_RATIO }) : /* @__PURE__ */ jsxs(PlayButton, { onClick: onClickPlay, children: [
|
|
3645
3860
|
/* @__PURE__ */ jsx("div", { "data-play": !0, children: /* @__PURE__ */ jsx(PlayIcon, {}) }),
|
|
3646
3861
|
assetIsAudio(asset) ? /* @__PURE__ */ jsx(
|
|
3647
3862
|
"div",
|
|
@@ -3703,12 +3918,12 @@ function VideoInBrowser({
|
|
|
3703
3918
|
}
|
|
3704
3919
|
);
|
|
3705
3920
|
}
|
|
3706
|
-
function VideosBrowser({ onSelect }) {
|
|
3921
|
+
function VideosBrowser({ onSelect, config }) {
|
|
3707
3922
|
const { assets, isLoading, searchQuery, setSearchQuery, setSort, sort } = useAssets(), [page, setPage] = useState(0), pageLimit = 20, pageTotal = Math.floor(assets.length / pageLimit) + 1, [editedAsset, setEditedAsset] = useState(null), freshEditedAsset = useMemo(
|
|
3708
3923
|
() => assets.find((a2) => a2._id === editedAsset?._id) || editedAsset,
|
|
3709
3924
|
[editedAsset, assets]
|
|
3710
3925
|
), pageStart = page * pageLimit, pageEnd = pageStart + pageLimit;
|
|
3711
|
-
return /* @__PURE__ */ jsxs(
|
|
3926
|
+
return /* @__PURE__ */ jsxs(DrmPlaybackWarningContextProvider, { config, children: [
|
|
3712
3927
|
/* @__PURE__ */ jsxs(Stack, { padding: 4, space: 4, style: { minHeight: "50vh" }, children: [
|
|
3713
3928
|
/* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
|
|
3714
3929
|
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 3, children: [
|
|
@@ -3722,7 +3937,7 @@ function VideosBrowser({ onSelect }) {
|
|
|
3722
3937
|
}
|
|
3723
3938
|
),
|
|
3724
3939
|
/* @__PURE__ */ jsx(SelectSortOptions, { setSort, sort }),
|
|
3725
|
-
/* @__PURE__ */ jsx(PageSelector, { page, setPage, total: pageTotal
|
|
3940
|
+
/* @__PURE__ */ jsx(PageSelector, { page, setPage, total: pageTotal })
|
|
3726
3941
|
] }),
|
|
3727
3942
|
(onSelect ? "input" : "tool") == "tool" && /* @__PURE__ */ jsxs(Inline, { space: 2, children: [
|
|
3728
3943
|
/* @__PURE__ */ jsx(ImportVideosFromMux, {}),
|
|
@@ -3763,7 +3978,7 @@ function VideosBrowser({ onSelect }) {
|
|
|
3763
3978
|
freshEditedAsset && /* @__PURE__ */ jsx(VideoDetails, { closeDialog: () => setEditedAsset(null), asset: freshEditedAsset })
|
|
3764
3979
|
] });
|
|
3765
3980
|
}
|
|
3766
|
-
const StudioTool = () => /* @__PURE__ */ jsx(VideosBrowser, {}), DEFAULT_TOOL_CONFIG = {
|
|
3981
|
+
const StudioTool = (config) => /* @__PURE__ */ jsx(VideosBrowser, { config }), DEFAULT_TOOL_CONFIG = {
|
|
3767
3982
|
icon: ToolIcon,
|
|
3768
3983
|
title: "Videos"
|
|
3769
3984
|
};
|
|
@@ -4121,6 +4336,9 @@ function isValidUrl(url) {
|
|
|
4121
4336
|
return !1;
|
|
4122
4337
|
}
|
|
4123
4338
|
}
|
|
4339
|
+
function isServerError(error) {
|
|
4340
|
+
return "statusCode" in error && typeof error.statusCode == "number" && 500 <= error.statusCode && error.statusCode <= 600;
|
|
4341
|
+
}
|
|
4124
4342
|
function extractDroppedFiles(dataTransfer) {
|
|
4125
4343
|
const files = Array.from(dataTransfer.files || []), items = Array.from(dataTransfer.items || []);
|
|
4126
4344
|
return files && files.length > 0 ? Promise.resolve(files) : normalizeItems(items).then((arr) => arr.flat());
|
|
@@ -4162,7 +4380,12 @@ function walk(entry) {
|
|
|
4162
4380
|
}
|
|
4163
4381
|
return Promise.resolve([]);
|
|
4164
4382
|
}
|
|
4165
|
-
function SelectAssets({
|
|
4383
|
+
function SelectAssets({
|
|
4384
|
+
asset: selectedAsset,
|
|
4385
|
+
onChange,
|
|
4386
|
+
setDialogState,
|
|
4387
|
+
config
|
|
4388
|
+
}) {
|
|
4166
4389
|
const handleSelect = useCallback(
|
|
4167
4390
|
(chosenAsset) => {
|
|
4168
4391
|
chosenAsset?._id || onChange(PatchEvent.from([unset(["asset"])])), chosenAsset._id !== selectedAsset?._id && onChange(
|
|
@@ -4174,7 +4397,7 @@ function SelectAssets({ asset: selectedAsset, onChange, setDialogState }) {
|
|
|
4174
4397
|
},
|
|
4175
4398
|
[onChange, setDialogState, selectedAsset]
|
|
4176
4399
|
);
|
|
4177
|
-
return /* @__PURE__ */ jsx(VideosBrowser, { onSelect: handleSelect });
|
|
4400
|
+
return /* @__PURE__ */ jsx(VideosBrowser, { onSelect: handleSelect, config });
|
|
4178
4401
|
}
|
|
4179
4402
|
const StyledDialog = styled(Dialog)`
|
|
4180
4403
|
> div[data-ui='DialogCard'] > div[data-ui='Card'] {
|
|
@@ -4184,7 +4407,8 @@ const StyledDialog = styled(Dialog)`
|
|
|
4184
4407
|
function InputBrowser({
|
|
4185
4408
|
setDialogState,
|
|
4186
4409
|
asset,
|
|
4187
|
-
onChange
|
|
4410
|
+
onChange,
|
|
4411
|
+
config
|
|
4188
4412
|
}) {
|
|
4189
4413
|
const id = `InputBrowser${useId()}`, handleClose = useCallback(() => setDialogState(!1), [setDialogState]);
|
|
4190
4414
|
return /* @__PURE__ */ jsx(
|
|
@@ -4195,7 +4419,15 @@ function InputBrowser({
|
|
|
4195
4419
|
id,
|
|
4196
4420
|
onClose: handleClose,
|
|
4197
4421
|
width: 2,
|
|
4198
|
-
children: /* @__PURE__ */ jsx(
|
|
4422
|
+
children: /* @__PURE__ */ jsx(
|
|
4423
|
+
SelectAssets,
|
|
4424
|
+
{
|
|
4425
|
+
config,
|
|
4426
|
+
asset,
|
|
4427
|
+
onChange,
|
|
4428
|
+
setDialogState
|
|
4429
|
+
}
|
|
4430
|
+
)
|
|
4199
4431
|
}
|
|
4200
4432
|
);
|
|
4201
4433
|
}
|
|
@@ -4411,7 +4643,7 @@ const FileButton = styled(MenuItem)(({ theme }) => {
|
|
|
4411
4643
|
color: white;
|
|
4412
4644
|
`, isVideoAsset = (asset) => asset._type === "mux.videoAsset";
|
|
4413
4645
|
function PlayerActionsMenu(props) {
|
|
4414
|
-
const { asset, readOnly, dialogState, setDialogState, onChange, onSelect, accept } = props, [open, setOpen] = useState(!1), [menuElement, setMenuRef] = useState(null), isSigned = useMemo(() => getPlaybackPolicy(asset) === "signed", [asset]), { hasConfigAccess } = useAccessControl(props.config), onReset = useCallback(() => onChange(PatchEvent.from(unset([]))), [onChange]);
|
|
4646
|
+
const { asset, readOnly, dialogState, setDialogState, onChange, onSelect, accept } = props, [open, setOpen] = useState(!1), [menuElement, setMenuRef] = useState(null), isSigned = useMemo(() => getPlaybackPolicy(asset)?.policy === "signed", [asset]), { hasConfigAccess } = useAccessControl(props.config), onReset = useCallback(() => onChange(PatchEvent.from(unset([]))), [onChange]);
|
|
4415
4647
|
return useEffect(() => {
|
|
4416
4648
|
open && dialogState && setOpen(!1);
|
|
4417
4649
|
}, [dialogState, open]), useClickOutsideEvent(
|
|
@@ -4512,6 +4744,79 @@ function PlayerActionsMenu(props) {
|
|
|
4512
4744
|
] });
|
|
4513
4745
|
}
|
|
4514
4746
|
var PlayerActionsMenu$1 = memo(PlayerActionsMenu);
|
|
4747
|
+
function useFetchFileSize(stagedUpload, maxFileSize) {
|
|
4748
|
+
const [fileSize, setFileSize] = useState(null), [isLoadingFileSize, setIsLoadingFileSize] = useState(!1), [canSkipFileSizeValidation, setCanSkipFileSizeValidation] = useState(!1);
|
|
4749
|
+
return useEffect(() => {
|
|
4750
|
+
if (stagedUpload.type === "url") {
|
|
4751
|
+
setIsLoadingFileSize(!1), setCanSkipFileSizeValidation(!1), setFileSize(null);
|
|
4752
|
+
const url = stagedUpload.url;
|
|
4753
|
+
(async () => {
|
|
4754
|
+
setIsLoadingFileSize(!0);
|
|
4755
|
+
try {
|
|
4756
|
+
const contentLength = (await fetch(url, { method: "HEAD" })).headers.get("content-length"), newFileSize = contentLength ? parseInt(contentLength, 10) : null;
|
|
4757
|
+
setIsLoadingFileSize(!1), newFileSize && setFileSize(newFileSize), newFileSize === null && maxFileSize !== void 0 && setCanSkipFileSizeValidation(!0);
|
|
4758
|
+
} catch {
|
|
4759
|
+
console.warn("Could not validate file size from URL"), setCanSkipFileSizeValidation(!0), setIsLoadingFileSize(!1);
|
|
4760
|
+
}
|
|
4761
|
+
})();
|
|
4762
|
+
}
|
|
4763
|
+
stagedUpload.type === "file" && setFileSize(stagedUpload.files[0].size);
|
|
4764
|
+
}, [maxFileSize, stagedUpload, stagedUpload.type]), {
|
|
4765
|
+
fileSize,
|
|
4766
|
+
isLoadingFileSize,
|
|
4767
|
+
canSkipFileSizeValidation
|
|
4768
|
+
};
|
|
4769
|
+
}
|
|
4770
|
+
function useMediaMetadata(stagedUpload) {
|
|
4771
|
+
const [videoAssetMetadata, setVideoAssetMetadata] = useState(null), [isLoadingMetadata, setIsLoadingMetadata] = useState(!1);
|
|
4772
|
+
return useEffect(() => {
|
|
4773
|
+
let videoSrc = null;
|
|
4774
|
+
if (stagedUpload.type === "file") {
|
|
4775
|
+
const file = stagedUpload.files[0];
|
|
4776
|
+
videoSrc = URL.createObjectURL(file);
|
|
4777
|
+
}
|
|
4778
|
+
if (stagedUpload.type === "url" && (videoSrc = stagedUpload.url), setVideoAssetMetadata((old) => ({
|
|
4779
|
+
...old,
|
|
4780
|
+
duration: void 0,
|
|
4781
|
+
width: void 0,
|
|
4782
|
+
height: void 0
|
|
4783
|
+
})), !videoSrc) return () => null;
|
|
4784
|
+
setIsLoadingMetadata(!0);
|
|
4785
|
+
const videoElement = document.createElement("video");
|
|
4786
|
+
videoElement.preload = "metadata";
|
|
4787
|
+
const metadataListeners = [
|
|
4788
|
+
() => {
|
|
4789
|
+
setIsLoadingMetadata(!1);
|
|
4790
|
+
},
|
|
4791
|
+
() => {
|
|
4792
|
+
const duration = videoElement.duration, width = videoElement.videoWidth, height = videoElement.videoHeight, isAudioOnly = width <= 0 && height <= 0;
|
|
4793
|
+
setVideoAssetMetadata((old) => ({
|
|
4794
|
+
...old,
|
|
4795
|
+
duration,
|
|
4796
|
+
width,
|
|
4797
|
+
height,
|
|
4798
|
+
isAudioOnly
|
|
4799
|
+
}));
|
|
4800
|
+
}
|
|
4801
|
+
], cleanupVideo = (videoEl) => {
|
|
4802
|
+
const currentVideoSrc = videoEl?.src;
|
|
4803
|
+
videoEl && (metadataListeners.forEach(
|
|
4804
|
+
(listener) => videoEl.removeEventListener("loadedmetadata", listener)
|
|
4805
|
+
), videoEl.onerror = null, videoEl.src = "", videoEl.load()), currentVideoSrc?.startsWith("blob:") && URL.revokeObjectURL(currentVideoSrc);
|
|
4806
|
+
};
|
|
4807
|
+
return metadataListeners.push(() => setTimeout(() => cleanupVideo(videoElement), 0)), videoElement.onerror = () => {
|
|
4808
|
+
setIsLoadingMetadata(!1), console.warn("Could not read video metadata for validation"), cleanupVideo(videoElement);
|
|
4809
|
+
}, metadataListeners.forEach(
|
|
4810
|
+
(listener) => videoElement.addEventListener("loadedmetadata", listener)
|
|
4811
|
+
), videoElement.src = videoSrc, () => {
|
|
4812
|
+
cleanupVideo(videoElement);
|
|
4813
|
+
};
|
|
4814
|
+
}, [stagedUpload.type, stagedUpload]), {
|
|
4815
|
+
videoAssetMetadata,
|
|
4816
|
+
setVideoAssetMetadata,
|
|
4817
|
+
isLoadingMetadata
|
|
4818
|
+
};
|
|
4819
|
+
}
|
|
4515
4820
|
function formatBytes(bytes, si = !1, dp = 1) {
|
|
4516
4821
|
const thresh = si ? 1e3 : 1024;
|
|
4517
4822
|
if (Math.abs(bytes) < thresh)
|
|
@@ -4601,13 +4906,14 @@ function PlaybackPolicyOption({
|
|
|
4601
4906
|
optionName,
|
|
4602
4907
|
description,
|
|
4603
4908
|
dispatch,
|
|
4604
|
-
action
|
|
4909
|
+
action,
|
|
4910
|
+
disabled
|
|
4605
4911
|
}) {
|
|
4606
4912
|
const [scale, setScale] = useState(1), boxStyle = {
|
|
4607
4913
|
outline: "0.01rem solid grey",
|
|
4608
4914
|
transform: `scale(${scale})`,
|
|
4609
4915
|
transition: "transform 0.1s ease-in-out",
|
|
4610
|
-
cursor: "pointer",
|
|
4916
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
4611
4917
|
borderRadius: "0.25rem"
|
|
4612
4918
|
}, triggerAnimation = () => {
|
|
4613
4919
|
setScale(0.98), setTimeout(() => {
|
|
@@ -4615,15 +4921,24 @@ function PlaybackPolicyOption({
|
|
|
4615
4921
|
}, 100);
|
|
4616
4922
|
};
|
|
4617
4923
|
return /* @__PURE__ */ jsx("label", { children: /* @__PURE__ */ jsxs(Flex, { gap: 3, padding: 3, style: boxStyle, children: [
|
|
4618
|
-
/* @__PURE__ */ jsx(
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4924
|
+
/* @__PURE__ */ jsx(
|
|
4925
|
+
Checkbox,
|
|
4926
|
+
{
|
|
4927
|
+
id,
|
|
4928
|
+
required: !0,
|
|
4929
|
+
checked,
|
|
4930
|
+
onChange: () => {
|
|
4931
|
+
action && (triggerAnimation(), dispatch({
|
|
4932
|
+
action,
|
|
4933
|
+
value: !checked
|
|
4934
|
+
}));
|
|
4935
|
+
},
|
|
4936
|
+
disabled
|
|
4937
|
+
}
|
|
4938
|
+
),
|
|
4624
4939
|
/* @__PURE__ */ jsxs(Grid, { gap: 3, children: [
|
|
4625
4940
|
/* @__PURE__ */ jsx(Text, { size: 3, weight: "bold", children: optionName }),
|
|
4626
|
-
/* @__PURE__ */ jsx(Text, { size: 2, muted: !0, children: description })
|
|
4941
|
+
typeof description == "string" ? /* @__PURE__ */ jsx(Text, { size: 2, muted: !0, children: description }) : description
|
|
4627
4942
|
] })
|
|
4628
4943
|
] }) });
|
|
4629
4944
|
}
|
|
@@ -4648,7 +4963,7 @@ function PlaybackPolicy({
|
|
|
4648
4963
|
secrets,
|
|
4649
4964
|
dispatch
|
|
4650
4965
|
}) {
|
|
4651
|
-
const noPolicySelected = !(config.public_policy || config.signed_policy);
|
|
4966
|
+
const noPolicySelected = !(config.public_policy || config.signed_policy || config.drm_policy), drmPolicyDisabled = !secrets.drmConfigId;
|
|
4652
4967
|
return /* @__PURE__ */ jsxs(Grid, { gap: 3, children: [
|
|
4653
4968
|
/* @__PURE__ */ jsx(Text, { weight: "bold", children: "Advanced Playback Policies" }),
|
|
4654
4969
|
/* @__PURE__ */ jsx(
|
|
@@ -4657,7 +4972,10 @@ function PlaybackPolicy({
|
|
|
4657
4972
|
id: `${id}--public`,
|
|
4658
4973
|
checked: config.public_policy,
|
|
4659
4974
|
optionName: "Public",
|
|
4660
|
-
description:
|
|
4975
|
+
description: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4976
|
+
/* @__PURE__ */ jsx(Text, { size: 2, muted: !0, children: "Playback IDs are accessible by constructing an HLS URL like" }),
|
|
4977
|
+
/* @__PURE__ */ jsx(Code, { children: "https://stream.mux.com/{PLAYBACK_ID}" })
|
|
4978
|
+
] }),
|
|
4661
4979
|
dispatch,
|
|
4662
4980
|
action: "public_policy"
|
|
4663
4981
|
}
|
|
@@ -4668,24 +4986,146 @@ function PlaybackPolicy({
|
|
|
4668
4986
|
id: `${id}--signed`,
|
|
4669
4987
|
checked: config.signed_policy,
|
|
4670
4988
|
optionName: "Signed",
|
|
4671
|
-
description:
|
|
4672
|
-
|
|
4989
|
+
description: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4990
|
+
/* @__PURE__ */ jsx(Text, { size: 2, muted: !0, children: "Playback IDs should be used with tokens" }),
|
|
4991
|
+
/* @__PURE__ */ jsx(Code, { children: "https://stream.mux.com/{PLAYBACK_ID}?token={TOKEN}" }),
|
|
4992
|
+
/* @__PURE__ */ jsxs(Text, { size: 2, muted: !0, children: [
|
|
4993
|
+
"See",
|
|
4994
|
+
" ",
|
|
4995
|
+
/* @__PURE__ */ jsx(
|
|
4996
|
+
"a",
|
|
4997
|
+
{
|
|
4998
|
+
href: "https://www.mux.com/docs/guides/secure-video-playback",
|
|
4999
|
+
target: "_blank",
|
|
5000
|
+
rel: "noopener noreferrer",
|
|
5001
|
+
children: "Secure video playback"
|
|
5002
|
+
}
|
|
5003
|
+
),
|
|
5004
|
+
" ",
|
|
5005
|
+
"for details about creating tokens."
|
|
5006
|
+
] })
|
|
5007
|
+
] }),
|
|
4673
5008
|
dispatch,
|
|
4674
5009
|
action: "signed_policy"
|
|
4675
5010
|
}
|
|
4676
5011
|
),
|
|
5012
|
+
drmPolicyDisabled ? /* @__PURE__ */ jsx(
|
|
5013
|
+
PlaybackPolicyOption,
|
|
5014
|
+
{
|
|
5015
|
+
id: `${id}--drm`,
|
|
5016
|
+
checked: !1,
|
|
5017
|
+
optionName: "DRM - Disabled",
|
|
5018
|
+
description: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Text, { size: 2, muted: !0, children: [
|
|
5019
|
+
"To enable DRM add your DRM Configuration Id to your plugin configuration in the API Credentials view.",
|
|
5020
|
+
" ",
|
|
5021
|
+
/* @__PURE__ */ jsx(
|
|
5022
|
+
"a",
|
|
5023
|
+
{
|
|
5024
|
+
href: "https://www.mux.com/support/human",
|
|
5025
|
+
target: "_blank",
|
|
5026
|
+
rel: "noopener noreferrer",
|
|
5027
|
+
children: "Contact us"
|
|
5028
|
+
}
|
|
5029
|
+
),
|
|
5030
|
+
" ",
|
|
5031
|
+
"to get started using DRM."
|
|
5032
|
+
] }) }),
|
|
5033
|
+
dispatch,
|
|
5034
|
+
disabled: !0
|
|
5035
|
+
}
|
|
5036
|
+
) : /* @__PURE__ */ jsx(
|
|
5037
|
+
PlaybackPolicyOption,
|
|
5038
|
+
{
|
|
5039
|
+
id: `${id}--drm`,
|
|
5040
|
+
checked: config.drm_policy,
|
|
5041
|
+
optionName: "DRM",
|
|
5042
|
+
description: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5043
|
+
/* @__PURE__ */ jsx(Text, { size: 2, muted: !0, children: "Playback IDs should be used with tokens as with Signed playback, but require extra configuration." }),
|
|
5044
|
+
/* @__PURE__ */ jsx(Code, { children: "https://stream.mux.com/{PLAYBACK_ID}?token={TOKEN}" }),
|
|
5045
|
+
/* @__PURE__ */ jsxs(Text, { size: 2, muted: !0, children: [
|
|
5046
|
+
"See",
|
|
5047
|
+
" ",
|
|
5048
|
+
/* @__PURE__ */ jsx(
|
|
5049
|
+
"a",
|
|
5050
|
+
{
|
|
5051
|
+
href: "https://www.mux.com/docs/guides/protect-videos-with-drm#play-drm-protected-videos",
|
|
5052
|
+
target: "_blank",
|
|
5053
|
+
rel: "noopener noreferrer",
|
|
5054
|
+
children: "Protect videos with DRM"
|
|
5055
|
+
}
|
|
5056
|
+
),
|
|
5057
|
+
" ",
|
|
5058
|
+
"for details about configuring your player for DRM playback and",
|
|
5059
|
+
" ",
|
|
5060
|
+
/* @__PURE__ */ jsx(
|
|
5061
|
+
"a",
|
|
5062
|
+
{
|
|
5063
|
+
href: "https://www.mux.com/docs/guides/secure-video-playback",
|
|
5064
|
+
target: "_blank",
|
|
5065
|
+
rel: "noopener noreferrer",
|
|
5066
|
+
children: "Secure video playback"
|
|
5067
|
+
}
|
|
5068
|
+
),
|
|
5069
|
+
" ",
|
|
5070
|
+
"for details about creating tokens."
|
|
5071
|
+
] })
|
|
5072
|
+
] }),
|
|
5073
|
+
dispatch,
|
|
5074
|
+
action: "drm_policy"
|
|
5075
|
+
}
|
|
5076
|
+
),
|
|
4677
5077
|
noPolicySelected && /* @__PURE__ */ jsx(PlaybackPolicyWarning, {})
|
|
4678
5078
|
] });
|
|
4679
5079
|
}
|
|
4680
|
-
const
|
|
4681
|
-
{ value: "basic", label: "Basic" },
|
|
4682
|
-
{ value: "plus", label: "Plus" },
|
|
4683
|
-
{ value: "premium", label: "Premium" }
|
|
4684
|
-
], RESOLUTION_TIERS = [
|
|
5080
|
+
const RESOLUTION_TIERS = [
|
|
4685
5081
|
{ value: "1080p", label: "1080p" },
|
|
4686
5082
|
{ value: "1440p", label: "1440p (2k)" },
|
|
4687
5083
|
{ value: "2160p", label: "2160p (4k)" }
|
|
4688
|
-
],
|
|
5084
|
+
], ResolutionTierSelector = ({
|
|
5085
|
+
id,
|
|
5086
|
+
config,
|
|
5087
|
+
dispatch,
|
|
5088
|
+
maxSupportedResolution
|
|
5089
|
+
}) => /* @__PURE__ */ jsx(
|
|
5090
|
+
FormField$2,
|
|
5091
|
+
{
|
|
5092
|
+
title: "Resolution Tier",
|
|
5093
|
+
description: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5094
|
+
"The maximum",
|
|
5095
|
+
" ",
|
|
5096
|
+
/* @__PURE__ */ jsx(
|
|
5097
|
+
"a",
|
|
5098
|
+
{
|
|
5099
|
+
href: "https://docs.mux.com/api-reference#video/operation/create-direct-upload",
|
|
5100
|
+
target: "_blank",
|
|
5101
|
+
rel: "noopener noreferrer",
|
|
5102
|
+
children: "resolution_tier"
|
|
5103
|
+
}
|
|
5104
|
+
),
|
|
5105
|
+
" ",
|
|
5106
|
+
"your asset is encoded, stored, and streamed at."
|
|
5107
|
+
] }),
|
|
5108
|
+
children: /* @__PURE__ */ jsx(Flex, { gap: 3, wrap: "wrap", children: RESOLUTION_TIERS.map(({ value, label }, index) => {
|
|
5109
|
+
const inputId = `${id}--type-${value}`;
|
|
5110
|
+
return index > maxSupportedResolution ? null : /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
5111
|
+
/* @__PURE__ */ jsx(
|
|
5112
|
+
Radio,
|
|
5113
|
+
{
|
|
5114
|
+
checked: config.max_resolution_tier === value,
|
|
5115
|
+
name: "asset-resolutiontier",
|
|
5116
|
+
onChange: (e) => dispatch({
|
|
5117
|
+
action: "max_resolution_tier",
|
|
5118
|
+
value: e.currentTarget.value
|
|
5119
|
+
}),
|
|
5120
|
+
value,
|
|
5121
|
+
id: inputId
|
|
5122
|
+
}
|
|
5123
|
+
),
|
|
5124
|
+
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: inputId, children: label })
|
|
5125
|
+
] }, value);
|
|
5126
|
+
}) })
|
|
5127
|
+
}
|
|
5128
|
+
), ADVANCED_RESOLUTIONS = [
|
|
4689
5129
|
{ value: "270p", label: "270p" },
|
|
4690
5130
|
{ value: "360p", label: "360p" },
|
|
4691
5131
|
{ value: "480p", label: "480p" },
|
|
@@ -4694,6 +5134,130 @@ const VIDEO_QUALITY_LEVELS = [
|
|
|
4694
5134
|
{ value: "1080p", label: "1080p" },
|
|
4695
5135
|
{ value: "1440p", label: "1440p" },
|
|
4696
5136
|
{ value: "2160p", label: "2160p" }
|
|
5137
|
+
], StaticRenditionSelector = ({
|
|
5138
|
+
id,
|
|
5139
|
+
config,
|
|
5140
|
+
dispatch
|
|
5141
|
+
}) => {
|
|
5142
|
+
const isAdvancedMode = useMemo(() => config.static_renditions.filter(
|
|
5143
|
+
(r) => r !== "highest" && r !== "audio-only"
|
|
5144
|
+
).length > 0, [config.static_renditions]), [renditionMode, setRenditionMode] = useState(
|
|
5145
|
+
isAdvancedMode ? "advanced" : "standard"
|
|
5146
|
+
), toggleRendition = (rendition) => {
|
|
5147
|
+
const current = config.static_renditions, hasRendition = current.includes(rendition);
|
|
5148
|
+
dispatch(hasRendition ? {
|
|
5149
|
+
action: "static_renditions",
|
|
5150
|
+
value: current.filter((r) => r !== rendition)
|
|
5151
|
+
} : {
|
|
5152
|
+
action: "static_renditions",
|
|
5153
|
+
value: [...current, rendition]
|
|
5154
|
+
});
|
|
5155
|
+
}, handleModeChange = (mode) => {
|
|
5156
|
+
setRenditionMode(mode), dispatch(mode === "standard" ? {
|
|
5157
|
+
action: "static_renditions",
|
|
5158
|
+
value: config.static_renditions.filter((r) => r === "highest" || r === "audio-only")
|
|
5159
|
+
} : {
|
|
5160
|
+
action: "static_renditions",
|
|
5161
|
+
value: config.static_renditions.filter((r) => r !== "highest")
|
|
5162
|
+
});
|
|
5163
|
+
};
|
|
5164
|
+
return /* @__PURE__ */ jsx(Stack, { space: 3, children: /* @__PURE__ */ jsx(
|
|
5165
|
+
FormField$2,
|
|
5166
|
+
{
|
|
5167
|
+
title: "Static Renditions",
|
|
5168
|
+
description: "Generate downloadable MP4 or M4A files. Note: Mux will not upscale to produce MP4 renditions - renditions that would cause upscaling are skipped.",
|
|
5169
|
+
children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
5170
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 3, children: [
|
|
5171
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
5172
|
+
/* @__PURE__ */ jsx(
|
|
5173
|
+
Radio,
|
|
5174
|
+
{
|
|
5175
|
+
checked: renditionMode === "standard",
|
|
5176
|
+
name: "rendition-mode",
|
|
5177
|
+
onChange: () => handleModeChange("standard"),
|
|
5178
|
+
value: "standard",
|
|
5179
|
+
id: `${id}--mode-standard`
|
|
5180
|
+
}
|
|
5181
|
+
),
|
|
5182
|
+
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: `${id}--mode-standard`, children: "Standard" })
|
|
5183
|
+
] }),
|
|
5184
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
5185
|
+
/* @__PURE__ */ jsx(
|
|
5186
|
+
Radio,
|
|
5187
|
+
{
|
|
5188
|
+
checked: renditionMode === "advanced",
|
|
5189
|
+
name: "rendition-mode",
|
|
5190
|
+
onChange: () => handleModeChange("advanced"),
|
|
5191
|
+
value: "advanced",
|
|
5192
|
+
id: `${id}--mode-advanced`
|
|
5193
|
+
}
|
|
5194
|
+
),
|
|
5195
|
+
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: `${id}--mode-advanced`, children: "Advanced" })
|
|
5196
|
+
] })
|
|
5197
|
+
] }),
|
|
5198
|
+
renditionMode === "standard" && /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
5199
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, padding: [0, 2], children: [
|
|
5200
|
+
/* @__PURE__ */ jsx(
|
|
5201
|
+
Checkbox,
|
|
5202
|
+
{
|
|
5203
|
+
id: `${id}--highest`,
|
|
5204
|
+
style: { display: "block" },
|
|
5205
|
+
checked: config.static_renditions.includes("highest"),
|
|
5206
|
+
onChange: () => toggleRendition("highest")
|
|
5207
|
+
}
|
|
5208
|
+
),
|
|
5209
|
+
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: `${id}--highest`, children: "Highest Resolution (up to 4K)" })
|
|
5210
|
+
] }),
|
|
5211
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, padding: [0, 2], children: [
|
|
5212
|
+
/* @__PURE__ */ jsx(
|
|
5213
|
+
Checkbox,
|
|
5214
|
+
{
|
|
5215
|
+
id: `${id}--audio-only-standard`,
|
|
5216
|
+
style: { display: "block" },
|
|
5217
|
+
checked: config.static_renditions.includes("audio-only"),
|
|
5218
|
+
onChange: () => toggleRendition("audio-only")
|
|
5219
|
+
}
|
|
5220
|
+
),
|
|
5221
|
+
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: `${id}--audio-only-standard`, children: "Audio Only (M4A)" })
|
|
5222
|
+
] })
|
|
5223
|
+
] }),
|
|
5224
|
+
renditionMode === "advanced" && /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
5225
|
+
/* @__PURE__ */ jsx(Label$1, { size: 1, muted: !0, children: "Select specific resolutions:" }),
|
|
5226
|
+
/* @__PURE__ */ jsx(Flex, { gap: 2, wrap: "wrap", children: ADVANCED_RESOLUTIONS.map(({ value, label }) => {
|
|
5227
|
+
const inputId = `${id}--resolution-${value}`;
|
|
5228
|
+
return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
5229
|
+
/* @__PURE__ */ jsx(
|
|
5230
|
+
Checkbox,
|
|
5231
|
+
{
|
|
5232
|
+
id: inputId,
|
|
5233
|
+
style: { display: "block" },
|
|
5234
|
+
checked: config.static_renditions.includes(value),
|
|
5235
|
+
onChange: () => toggleRendition(value)
|
|
5236
|
+
}
|
|
5237
|
+
),
|
|
5238
|
+
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: inputId, size: 1, children: label })
|
|
5239
|
+
] }, value);
|
|
5240
|
+
}) }),
|
|
5241
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, padding: [2, 2, 0, 2], children: [
|
|
5242
|
+
/* @__PURE__ */ jsx(
|
|
5243
|
+
Checkbox,
|
|
5244
|
+
{
|
|
5245
|
+
id: `${id}--audio-only-advanced`,
|
|
5246
|
+
style: { display: "block" },
|
|
5247
|
+
checked: config.static_renditions.includes("audio-only"),
|
|
5248
|
+
onChange: () => toggleRendition("audio-only")
|
|
5249
|
+
}
|
|
5250
|
+
),
|
|
5251
|
+
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: `${id}--audio-only-advanced`, children: "Audio Only (M4A)" })
|
|
5252
|
+
] })
|
|
5253
|
+
] })
|
|
5254
|
+
] })
|
|
5255
|
+
}
|
|
5256
|
+
) });
|
|
5257
|
+
}, VIDEO_QUALITY_LEVELS = [
|
|
5258
|
+
{ value: "basic", label: "Basic" },
|
|
5259
|
+
{ value: "plus", label: "Plus" },
|
|
5260
|
+
{ value: "premium", label: "Premium" }
|
|
4697
5261
|
];
|
|
4698
5262
|
function sanitizeStaticRenditions(renditions) {
|
|
4699
5263
|
const hasHighest = renditions.includes("highest"), hasSpecificResolutions = renditions.some((r) => r !== "highest" && r !== "audio-only");
|
|
@@ -4725,7 +5289,8 @@ function UploadConfiguration({
|
|
|
4725
5289
|
max_resolution_tier: "1080p",
|
|
4726
5290
|
text_tracks: prev.text_tracks?.filter(({ type }) => type !== "autogenerated"),
|
|
4727
5291
|
public_policy: !0,
|
|
4728
|
-
signed_policy: !1
|
|
5292
|
+
signed_policy: !1,
|
|
5293
|
+
drm_policy: !1
|
|
4729
5294
|
}) : Object.assign({}, prev, {
|
|
4730
5295
|
video_quality: action.value,
|
|
4731
5296
|
static_renditions: sanitizeStaticRenditions(pluginConfig.static_renditions || []),
|
|
@@ -4739,6 +5304,8 @@ function UploadConfiguration({
|
|
|
4739
5304
|
return Object.assign({}, prev, { [action.action]: action.value });
|
|
4740
5305
|
case "public_policy":
|
|
4741
5306
|
return Object.assign({}, prev, { [action.action]: action.value });
|
|
5307
|
+
case "drm_policy":
|
|
5308
|
+
return Object.assign({}, prev, { [action.action]: action.value });
|
|
4742
5309
|
// Updating individual tracks
|
|
4743
5310
|
case "track": {
|
|
4744
5311
|
const text_tracks = [...prev.text_tracks], target_track_i = text_tracks.findIndex(({ _id: _id2 }) => _id2 === action.id);
|
|
@@ -4774,75 +5341,41 @@ function UploadConfiguration({
|
|
|
4774
5341
|
static_renditions: sanitizeStaticRenditions(pluginConfig.static_renditions || []),
|
|
4775
5342
|
signed_policy: secrets.enableSignedUrls && pluginConfig.defaultSigned,
|
|
4776
5343
|
public_policy: pluginConfig.defaultPublic,
|
|
5344
|
+
drm_policy: pluginConfig.defaultDrm && !!secrets.drmConfigId,
|
|
4777
5345
|
normalize_audio: pluginConfig.normalize_audio,
|
|
4778
5346
|
text_tracks: autoTextTracks
|
|
4779
5347
|
}
|
|
4780
|
-
),
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
), [videoDuration, setVideoDuration] = useState(null), [urlFileSize, setUrlFileSize] = useState(null), [isLoadingDuration, setIsLoadingDuration] = useState(!1), [isLoadingFileSize, setIsLoadingFileSize] = useState(!1), [validationError, setValidationError] = useState(null), [canSkipFileSizeValidation, setCanSkipFileSizeValidation] = useState(!1), MAX_FILE_SIZE = pluginConfig.maxAssetFileSize, MAX_DURATION_SECONDS = pluginConfig.maxAssetDuration;
|
|
5348
|
+
), [validationError, setValidationError] = useState(null), MAX_FILE_SIZE = pluginConfig.maxAssetFileSize, MAX_DURATION_SECONDS = pluginConfig.maxAssetDuration, { fileSize, isLoadingFileSize, canSkipFileSizeValidation } = useFetchFileSize(
|
|
5349
|
+
stagedUpload,
|
|
5350
|
+
MAX_FILE_SIZE
|
|
5351
|
+
), { videoAssetMetadata, setVideoAssetMetadata, isLoadingMetadata } = useMediaMetadata(stagedUpload);
|
|
4785
5352
|
useEffect(() => {
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
const
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
!MAX_DURATION_SECONDS || MAX_DURATION_SECONDS <= 0 || (setIsLoadingDuration(!0), videoElement = document.createElement("video"), videoElement.preload = "metadata", currentVideoSrc = videoSrc, videoElement.onloadedmetadata = () => {
|
|
4792
|
-
const duration = videoElement.duration;
|
|
4793
|
-
setVideoDuration(duration), setIsLoadingDuration(!1), duration > MAX_DURATION_SECONDS && setValidationError(
|
|
4794
|
-
`Video duration (${formatSeconds(duration)}) exceeds maximum allowed duration of ${formatSeconds(MAX_DURATION_SECONDS)}`
|
|
4795
|
-
), cleanupVideo(shouldRevokeUrl);
|
|
4796
|
-
}, videoElement.onerror = () => {
|
|
4797
|
-
setIsLoadingDuration(!1), console.warn("Could not read video metadata for validation"), cleanupVideo(shouldRevokeUrl);
|
|
4798
|
-
}, videoElement.src = videoSrc);
|
|
4799
|
-
}, validateFileSize = (size) => MAX_FILE_SIZE === void 0 || size <= MAX_FILE_SIZE ? !0 : (setValidationError(
|
|
5353
|
+
fileSize && setVideoAssetMetadata((old) => ({ ...old, size: fileSize }));
|
|
5354
|
+
}, [fileSize, setVideoAssetMetadata]), useEffect(() => {
|
|
5355
|
+
const validateDuration = (duration) => MAX_DURATION_SECONDS && duration > MAX_DURATION_SECONDS ? (setValidationError(
|
|
5356
|
+
`Video duration (${formatSeconds(duration)}) exceeds maximum allowed duration of ${formatSeconds(MAX_DURATION_SECONDS)}`
|
|
5357
|
+
), !1) : !0, validateFileSize = (size) => MAX_FILE_SIZE === void 0 || size <= MAX_FILE_SIZE ? !0 : (setValidationError(
|
|
4800
5358
|
`File size (${formatBytes(size)}) exceeds maximum allowed size of ${formatBytes(MAX_FILE_SIZE)}`
|
|
4801
|
-
), !1);
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
}
|
|
4818
|
-
})();
|
|
4819
|
-
}
|
|
4820
|
-
return () => {
|
|
4821
|
-
cleanupVideo(!0);
|
|
4822
|
-
};
|
|
4823
|
-
}, [stagedUpload, MAX_FILE_SIZE, MAX_DURATION_SECONDS]);
|
|
4824
|
-
const toggleRendition = (rendition) => {
|
|
4825
|
-
const current = config.static_renditions, hasRendition = current.includes(rendition);
|
|
4826
|
-
dispatch(hasRendition ? {
|
|
4827
|
-
action: "static_renditions",
|
|
4828
|
-
value: current.filter((r) => r !== rendition)
|
|
4829
|
-
} : {
|
|
4830
|
-
action: "static_renditions",
|
|
4831
|
-
value: [...current, rendition]
|
|
4832
|
-
});
|
|
4833
|
-
}, handleModeChange = (mode) => {
|
|
4834
|
-
setRenditionMode(mode), dispatch(mode === "standard" ? {
|
|
4835
|
-
action: "static_renditions",
|
|
4836
|
-
value: config.static_renditions.filter((r) => r === "highest" || r === "audio-only")
|
|
4837
|
-
} : {
|
|
4838
|
-
action: "static_renditions",
|
|
4839
|
-
value: config.static_renditions.filter((r) => r !== "highest")
|
|
4840
|
-
});
|
|
4841
|
-
}, { disableTextTrackConfig, disableUploadConfig } = pluginConfig, skipConfig = disableTextTrackConfig && disableUploadConfig;
|
|
5359
|
+
), !1), validateDrmAvailability = (isAudioOnly) => config.drm_policy && isAudioOnly ? (setValidationError("Audio-only asset cannot be DRM protected"), !1) : !0;
|
|
5360
|
+
let valid = !0;
|
|
5361
|
+
videoAssetMetadata?.size && (valid = valid && (canSkipFileSizeValidation || validateFileSize(videoAssetMetadata.size))), videoAssetMetadata?.duration && (valid = valid && validateDuration(videoAssetMetadata.duration)), videoAssetMetadata?.isAudioOnly != null && (valid = valid && validateDrmAvailability(videoAssetMetadata.isAudioOnly)), valid && setValidationError(null);
|
|
5362
|
+
}, [
|
|
5363
|
+
MAX_FILE_SIZE,
|
|
5364
|
+
MAX_DURATION_SECONDS,
|
|
5365
|
+
canSkipFileSizeValidation,
|
|
5366
|
+
videoAssetMetadata?.duration,
|
|
5367
|
+
videoAssetMetadata?.size,
|
|
5368
|
+
videoAssetMetadata?.height,
|
|
5369
|
+
videoAssetMetadata?.width,
|
|
5370
|
+
videoAssetMetadata,
|
|
5371
|
+
config.drm_policy,
|
|
5372
|
+
validationError
|
|
5373
|
+
]);
|
|
5374
|
+
const { disableTextTrackConfig, disableUploadConfig } = pluginConfig, skipConfig = disableTextTrackConfig && disableUploadConfig;
|
|
4842
5375
|
if (useEffect(() => {
|
|
4843
|
-
skipConfig && startUpload(formatUploadConfig(config));
|
|
5376
|
+
skipConfig && startUpload(formatUploadConfig(config, secrets));
|
|
4844
5377
|
}, []), skipConfig) return null;
|
|
4845
|
-
const basicConfig = config.video_quality !== "plus" && config.video_quality !== "premium", maxSupportedResolution = RESOLUTION_TIERS.findIndex(
|
|
5378
|
+
const basicConfig = config.video_quality !== "plus" && config.video_quality !== "premium", playbackPolicySelected = config.public_policy || config.signed_policy || config.drm_policy, maxSupportedResolution = RESOLUTION_TIERS.findIndex(
|
|
4846
5379
|
(rt) => rt.value === pluginConfig.max_resolution_tier
|
|
4847
5380
|
);
|
|
4848
5381
|
return /* @__PURE__ */ jsx(
|
|
@@ -4876,12 +5409,12 @@ function UploadConfiguration({
|
|
|
4876
5409
|
/* @__PURE__ */ jsx(DocumentVideoIcon, { fontSize: "2em" }),
|
|
4877
5410
|
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
4878
5411
|
/* @__PURE__ */ jsx(Text, { textOverflow: "ellipsis", as: "h2", size: 3, children: stagedUpload.type === "file" ? stagedUpload.files[0].name : stagedUpload.url }),
|
|
4879
|
-
/* @__PURE__ */ jsx(Text, { as: "p", size: 1, muted: !0, children: stagedUpload.type === "file" ? `Direct File Upload (${formatBytes(stagedUpload.files[0].size)})` :
|
|
5412
|
+
/* @__PURE__ */ jsx(Text, { as: "p", size: 1, muted: !0, children: stagedUpload.type === "file" ? `Direct File Upload (${formatBytes(stagedUpload.files[0].size)})` : videoAssetMetadata?.size ? `File From URL (${formatBytes(videoAssetMetadata.size)})` : isLoadingFileSize ? "File From URL (Loading size...)" : "File From URL (Unknown size)" }),
|
|
4880
5413
|
stagedUpload.type === "file" && /* @__PURE__ */ jsxs(Stack, { space: 1, children: [
|
|
4881
|
-
|
|
4882
|
-
|
|
5414
|
+
isLoadingMetadata && /* @__PURE__ */ jsx(Text, { as: "p", size: 1, muted: !0, children: "Reading video metadata..." }),
|
|
5415
|
+
videoAssetMetadata?.duration && !validationError && /* @__PURE__ */ jsxs(Text, { as: "p", size: 1, muted: !0, children: [
|
|
4883
5416
|
"Duration: ",
|
|
4884
|
-
formatSeconds(
|
|
5417
|
+
formatSeconds(videoAssetMetadata.duration)
|
|
4885
5418
|
] })
|
|
4886
5419
|
] })
|
|
4887
5420
|
] })
|
|
@@ -4927,160 +5460,37 @@ function UploadConfiguration({
|
|
|
4927
5460
|
}) })
|
|
4928
5461
|
}
|
|
4929
5462
|
),
|
|
4930
|
-
!basicConfig && maxSupportedResolution > 0 && /* @__PURE__ */ jsx(
|
|
4931
|
-
FormField$2,
|
|
4932
|
-
{
|
|
4933
|
-
title: "Resolution Tier",
|
|
4934
|
-
description: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4935
|
-
"The maximum",
|
|
4936
|
-
" ",
|
|
4937
|
-
/* @__PURE__ */ jsx(
|
|
4938
|
-
"a",
|
|
4939
|
-
{
|
|
4940
|
-
href: "https://docs.mux.com/api-reference#video/operation/create-direct-upload",
|
|
4941
|
-
target: "_blank",
|
|
4942
|
-
rel: "noopener noreferrer",
|
|
4943
|
-
children: "resolution_tier"
|
|
4944
|
-
}
|
|
4945
|
-
),
|
|
4946
|
-
" ",
|
|
4947
|
-
"your asset is encoded, stored, and streamed at."
|
|
4948
|
-
] }),
|
|
4949
|
-
children: /* @__PURE__ */ jsx(Flex, { gap: 3, wrap: "wrap", children: RESOLUTION_TIERS.map(({ value, label }, index) => {
|
|
4950
|
-
const inputId = `${id}--type-${value}`;
|
|
4951
|
-
return index > maxSupportedResolution ? null : /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
4952
|
-
/* @__PURE__ */ jsx(
|
|
4953
|
-
Radio,
|
|
4954
|
-
{
|
|
4955
|
-
checked: config.max_resolution_tier === value,
|
|
4956
|
-
name: "asset-resolutiontier",
|
|
4957
|
-
onChange: (e) => dispatch({
|
|
4958
|
-
action: "max_resolution_tier",
|
|
4959
|
-
value: e.currentTarget.value
|
|
4960
|
-
}),
|
|
4961
|
-
value,
|
|
4962
|
-
id: inputId
|
|
4963
|
-
}
|
|
4964
|
-
),
|
|
4965
|
-
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: inputId, children: label })
|
|
4966
|
-
] }, value);
|
|
4967
|
-
}) })
|
|
4968
|
-
}
|
|
4969
|
-
),
|
|
4970
5463
|
!basicConfig && /* @__PURE__ */ jsx(FormField$2, { title: "Additional Configuration", children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
4971
5464
|
/* @__PURE__ */ jsx(PlaybackPolicy, { id, config, secrets, dispatch }),
|
|
4972
|
-
|
|
4973
|
-
|
|
5465
|
+
maxSupportedResolution > 0 && /* @__PURE__ */ jsx(
|
|
5466
|
+
ResolutionTierSelector,
|
|
4974
5467
|
{
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
4980
|
-
/* @__PURE__ */ jsx(
|
|
4981
|
-
Radio,
|
|
4982
|
-
{
|
|
4983
|
-
checked: renditionMode === "standard",
|
|
4984
|
-
name: "rendition-mode",
|
|
4985
|
-
onChange: () => handleModeChange("standard"),
|
|
4986
|
-
value: "standard",
|
|
4987
|
-
id: `${id}--mode-standard`
|
|
4988
|
-
}
|
|
4989
|
-
),
|
|
4990
|
-
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: `${id}--mode-standard`, children: "Standard" })
|
|
4991
|
-
] }),
|
|
4992
|
-
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
4993
|
-
/* @__PURE__ */ jsx(
|
|
4994
|
-
Radio,
|
|
4995
|
-
{
|
|
4996
|
-
checked: renditionMode === "advanced",
|
|
4997
|
-
name: "rendition-mode",
|
|
4998
|
-
onChange: () => handleModeChange("advanced"),
|
|
4999
|
-
value: "advanced",
|
|
5000
|
-
id: `${id}--mode-advanced`
|
|
5001
|
-
}
|
|
5002
|
-
),
|
|
5003
|
-
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: `${id}--mode-advanced`, children: "Advanced" })
|
|
5004
|
-
] })
|
|
5005
|
-
] }),
|
|
5006
|
-
renditionMode === "standard" && /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
5007
|
-
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, padding: [0, 2], children: [
|
|
5008
|
-
/* @__PURE__ */ jsx(
|
|
5009
|
-
Checkbox,
|
|
5010
|
-
{
|
|
5011
|
-
id: `${id}--highest`,
|
|
5012
|
-
style: { display: "block" },
|
|
5013
|
-
checked: config.static_renditions.includes("highest"),
|
|
5014
|
-
onChange: () => toggleRendition("highest")
|
|
5015
|
-
}
|
|
5016
|
-
),
|
|
5017
|
-
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: `${id}--highest`, children: "Highest Resolution (up to 4K)" })
|
|
5018
|
-
] }),
|
|
5019
|
-
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, padding: [0, 2], children: [
|
|
5020
|
-
/* @__PURE__ */ jsx(
|
|
5021
|
-
Checkbox,
|
|
5022
|
-
{
|
|
5023
|
-
id: `${id}--audio-only-standard`,
|
|
5024
|
-
style: { display: "block" },
|
|
5025
|
-
checked: config.static_renditions.includes("audio-only"),
|
|
5026
|
-
onChange: () => toggleRendition("audio-only")
|
|
5027
|
-
}
|
|
5028
|
-
),
|
|
5029
|
-
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: `${id}--audio-only-standard`, children: "Audio Only (M4A)" })
|
|
5030
|
-
] })
|
|
5031
|
-
] }),
|
|
5032
|
-
renditionMode === "advanced" && /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
5033
|
-
/* @__PURE__ */ jsx(Label$1, { size: 1, muted: !0, children: "Select specific resolutions:" }),
|
|
5034
|
-
/* @__PURE__ */ jsx(Flex, { gap: 2, wrap: "wrap", children: ADVANCED_RESOLUTIONS.map(({ value, label }) => {
|
|
5035
|
-
const inputId = `${id}--resolution-${value}`;
|
|
5036
|
-
return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
5037
|
-
/* @__PURE__ */ jsx(
|
|
5038
|
-
Checkbox,
|
|
5039
|
-
{
|
|
5040
|
-
id: inputId,
|
|
5041
|
-
style: { display: "block" },
|
|
5042
|
-
checked: config.static_renditions.includes(value),
|
|
5043
|
-
onChange: () => toggleRendition(value)
|
|
5044
|
-
}
|
|
5045
|
-
),
|
|
5046
|
-
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: inputId, size: 1, children: label })
|
|
5047
|
-
] }, value);
|
|
5048
|
-
}) }),
|
|
5049
|
-
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, padding: [2, 2, 0, 2], children: [
|
|
5050
|
-
/* @__PURE__ */ jsx(
|
|
5051
|
-
Checkbox,
|
|
5052
|
-
{
|
|
5053
|
-
id: `${id}--audio-only-advanced`,
|
|
5054
|
-
style: { display: "block" },
|
|
5055
|
-
checked: config.static_renditions.includes("audio-only"),
|
|
5056
|
-
onChange: () => toggleRendition("audio-only")
|
|
5057
|
-
}
|
|
5058
|
-
),
|
|
5059
|
-
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: `${id}--audio-only-advanced`, children: "Audio Only (M4A)" })
|
|
5060
|
-
] })
|
|
5061
|
-
] })
|
|
5062
|
-
] })
|
|
5468
|
+
id,
|
|
5469
|
+
config,
|
|
5470
|
+
dispatch,
|
|
5471
|
+
maxSupportedResolution
|
|
5063
5472
|
}
|
|
5064
|
-
)
|
|
5473
|
+
),
|
|
5474
|
+
/* @__PURE__ */ jsx(StaticRenditionSelector, { id, config, dispatch }),
|
|
5475
|
+
!disableTextTrackConfig && /* @__PURE__ */ jsx(
|
|
5476
|
+
TextTracksEditor,
|
|
5477
|
+
{
|
|
5478
|
+
tracks: config.text_tracks,
|
|
5479
|
+
dispatch,
|
|
5480
|
+
defaultLang: pluginConfig.defaultAutogeneratedSubtitleLang
|
|
5481
|
+
}
|
|
5482
|
+
)
|
|
5065
5483
|
] }) })
|
|
5066
5484
|
] }),
|
|
5067
|
-
!disableTextTrackConfig && !basicConfig && /* @__PURE__ */ jsx(
|
|
5068
|
-
TextTracksEditor,
|
|
5069
|
-
{
|
|
5070
|
-
tracks: config.text_tracks,
|
|
5071
|
-
dispatch,
|
|
5072
|
-
defaultLang: pluginConfig.defaultAutogeneratedSubtitleLang
|
|
5073
|
-
}
|
|
5074
|
-
),
|
|
5075
5485
|
/* @__PURE__ */ jsx(Box, { marginTop: 4, children: /* @__PURE__ */ jsx(
|
|
5076
5486
|
Button,
|
|
5077
5487
|
{
|
|
5078
|
-
disabled: !basicConfig && !
|
|
5488
|
+
disabled: !basicConfig && !playbackPolicySelected || validationError !== null || isLoadingMetadata || isLoadingFileSize && !canSkipFileSizeValidation,
|
|
5079
5489
|
icon: UploadIcon,
|
|
5080
5490
|
text: "Upload",
|
|
5081
5491
|
tone: "positive",
|
|
5082
5492
|
onClick: () => {
|
|
5083
|
-
validationError || startUpload(formatUploadConfig(config));
|
|
5493
|
+
validationError || startUpload(formatUploadConfig(config, secrets));
|
|
5084
5494
|
}
|
|
5085
5495
|
}
|
|
5086
5496
|
) })
|
|
@@ -5088,11 +5498,14 @@ function UploadConfiguration({
|
|
|
5088
5498
|
}
|
|
5089
5499
|
);
|
|
5090
5500
|
}
|
|
5091
|
-
function
|
|
5092
|
-
const
|
|
5093
|
-
return config.public_policy &&
|
|
5501
|
+
function setAdvancedPlaybackPolicy(config, secrets) {
|
|
5502
|
+
const advanced_playback_policies = [];
|
|
5503
|
+
return config.public_policy && advanced_playback_policies.push({ policy: "public" }), config.signed_policy && advanced_playback_policies.push({ policy: "signed" }), config.drm_policy && (secrets.drmConfigId ? advanced_playback_policies.push({
|
|
5504
|
+
policy: "drm",
|
|
5505
|
+
drm_configuration_id: secrets.drmConfigId ?? void 0
|
|
5506
|
+
}) : console.error("Selected DRM Policy but missing DRM Configuration Id")), advanced_playback_policies;
|
|
5094
5507
|
}
|
|
5095
|
-
function formatUploadConfig(config) {
|
|
5508
|
+
function formatUploadConfig(config, secrets) {
|
|
5096
5509
|
const generated_subtitles = config.text_tracks.filter(isAutogeneratedTrack).map((track) => ({
|
|
5097
5510
|
name: track.name,
|
|
5098
5511
|
language_code: track.language_code
|
|
@@ -5116,7 +5529,7 @@ function formatUploadConfig(config) {
|
|
|
5116
5529
|
)
|
|
5117
5530
|
],
|
|
5118
5531
|
static_renditions: config.static_renditions.length > 0 ? config.static_renditions.map((resolution) => ({ resolution })) : void 0,
|
|
5119
|
-
|
|
5532
|
+
advanced_playback_policies: setAdvancedPlaybackPolicy(config, secrets),
|
|
5120
5533
|
max_resolution_tier: config.max_resolution_tier,
|
|
5121
5534
|
video_quality: config.video_quality,
|
|
5122
5535
|
normalize_audio: config.normalize_audio
|
|
@@ -5328,8 +5741,13 @@ function Uploader(props) {
|
|
|
5328
5741
|
case "reset":
|
|
5329
5742
|
case "complete":
|
|
5330
5743
|
return uploadRef.current?.unsubscribe(), uploadRef.current = null, uploadingDocumentId.current = null, INITIAL_STATE;
|
|
5331
|
-
case "error":
|
|
5332
|
-
|
|
5744
|
+
case "error": {
|
|
5745
|
+
uploadRef.current?.unsubscribe(), uploadRef.current = null, uploadingDocumentId.current = null;
|
|
5746
|
+
let error = action.error;
|
|
5747
|
+
return isServerError(action.error) && hasPlaybackPolicy(action.settings, "drm") && (error = new Error(
|
|
5748
|
+
"Unknown Error while uploading DRM protected content. Make sure your DRM configuration ID is valid and set correctly"
|
|
5749
|
+
)), Object.assign({}, INITIAL_STATE, { error });
|
|
5750
|
+
}
|
|
5333
5751
|
default:
|
|
5334
5752
|
return prev;
|
|
5335
5753
|
}
|
|
@@ -5408,7 +5826,7 @@ function Uploader(props) {
|
|
|
5408
5826
|
}
|
|
5409
5827
|
},
|
|
5410
5828
|
complete: () => dispatch({ action: "complete" }),
|
|
5411
|
-
error: (error) => dispatch({ action: "error", error })
|
|
5829
|
+
error: (error) => dispatch({ action: "error", error, settings })
|
|
5412
5830
|
});
|
|
5413
5831
|
}, invalidFileToast = useCallback(() => {
|
|
5414
5832
|
toast.push({
|
|
@@ -5459,11 +5877,11 @@ function Uploader(props) {
|
|
|
5459
5877
|
idx > -1 && dragEnteredEls.current.splice(idx, 1), dragEnteredEls.current.length === 0 && setDragState(null);
|
|
5460
5878
|
};
|
|
5461
5879
|
if (state.error !== null) {
|
|
5462
|
-
const error =
|
|
5880
|
+
const error = state.error;
|
|
5463
5881
|
return /* @__PURE__ */ jsxs(Flex, { gap: 3, direction: "column", justify: "center", align: "center", children: [
|
|
5464
5882
|
/* @__PURE__ */ jsx(Text, { size: 5, muted: !0, children: /* @__PURE__ */ jsx(ErrorOutlineIcon, {}) }),
|
|
5465
5883
|
/* @__PURE__ */ jsx(Text, { children: "Something went wrong" }),
|
|
5466
|
-
error instanceof Error && error.message && /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: error.message }),
|
|
5884
|
+
error instanceof Error && error.message && /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, weight: "semibold", style: { textAlign: "center" }, children: error.message }),
|
|
5467
5885
|
/* @__PURE__ */ jsx(Button, { text: "Upload another file", onClick: () => dispatch({ action: "reset" }) })
|
|
5468
5886
|
] });
|
|
5469
5887
|
}
|
|
@@ -5548,6 +5966,7 @@ function Uploader(props) {
|
|
|
5548
5966
|
props.dialogState === "select-video" && /* @__PURE__ */ jsx(
|
|
5549
5967
|
InputBrowser,
|
|
5550
5968
|
{
|
|
5969
|
+
config: props.config,
|
|
5551
5970
|
asset: props.asset,
|
|
5552
5971
|
onChange: props.onChange,
|
|
5553
5972
|
setDialogState: props.setDialogState
|
|
@@ -5794,6 +6213,7 @@ const muxVideoSchema = {
|
|
|
5794
6213
|
normalize_audio: !1,
|
|
5795
6214
|
defaultPublic: !0,
|
|
5796
6215
|
defaultSigned: !1,
|
|
6216
|
+
defaultDrm: !1,
|
|
5797
6217
|
tool: DEFAULT_TOOL_CONFIG,
|
|
5798
6218
|
allowedRolesForConfiguration: [],
|
|
5799
6219
|
acceptedMimeTypes: ["video/*", "audio/*"]
|