sanity-plugin-mux-input 2.14.0 → 2.16.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 +1057 -470
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1059 -472
- 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 +15 -1
- package/src/components/ResyncMetadata.tsx +152 -73
- package/src/components/SelectAsset.tsx +9 -3
- package/src/components/StudioTool.tsx +2 -2
- package/src/components/TextTracksManager.tsx +11 -55
- package/src/components/UploadConfiguration.tsx +104 -343
- package/src/components/Uploader.tsx +18 -7
- package/src/components/VideoDetails/VideoDetails.tsx +55 -19
- package/src/components/VideoDetails/useVideoDetails.ts +15 -1
- 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/useResyncAsset.ts +110 -0
- package/src/hooks/useResyncMuxMetadata.ts +33 -0
- package/src/hooks/useSaveSecrets.ts +10 -3
- package/src/hooks/useSecretsDocumentValues.ts +9 -1
- package/src/hooks/useSecretsFormState.ts +6 -3
- package/src/schema.ts +5 -0
- package/src/util/addKeysToMuxData.ts +30 -0
- 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, Radio, MenuButton, Menu, MenuItem, useToast, Autocomplete, Tooltip, TabList, Tab, TabPanel, Grid, useClickOutsideEvent, Popover, MenuDivider, 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,12 +1315,32 @@ 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
|
)
|
|
1190
1322
|
] });
|
|
1191
1323
|
};
|
|
1324
|
+
function addKeysToMuxData(data) {
|
|
1325
|
+
return {
|
|
1326
|
+
...data,
|
|
1327
|
+
tracks: data.tracks?.map((track) => ({
|
|
1328
|
+
...track,
|
|
1329
|
+
_key: uuid()
|
|
1330
|
+
})),
|
|
1331
|
+
playback_ids: data.playback_ids?.map((playbackId) => ({
|
|
1332
|
+
...playbackId,
|
|
1333
|
+
_key: uuid()
|
|
1334
|
+
})),
|
|
1335
|
+
static_renditions: data.static_renditions ? {
|
|
1336
|
+
...data.static_renditions,
|
|
1337
|
+
files: data.static_renditions.files?.map((file) => ({
|
|
1338
|
+
...file,
|
|
1339
|
+
_key: uuid()
|
|
1340
|
+
}))
|
|
1341
|
+
} : void 0
|
|
1342
|
+
};
|
|
1343
|
+
}
|
|
1192
1344
|
function useResyncMuxMetadata() {
|
|
1193
1345
|
const documentStore = useDocumentStore(), client = useClient$1({
|
|
1194
1346
|
apiVersion: SANITY_API_VERSION
|
|
@@ -1237,6 +1389,27 @@ function useResyncMuxMetadata() {
|
|
|
1237
1389
|
}
|
|
1238
1390
|
}
|
|
1239
1391
|
}
|
|
1392
|
+
async function syncFullData() {
|
|
1393
|
+
if (matchedAssets) {
|
|
1394
|
+
setResyncState("syncing");
|
|
1395
|
+
try {
|
|
1396
|
+
const tx = client.transaction();
|
|
1397
|
+
matchedAssets.forEach((matched) => {
|
|
1398
|
+
if (!matched.muxAsset) return;
|
|
1399
|
+
const dataWithKeys = addKeysToMuxData(matched.muxAsset);
|
|
1400
|
+
tx.patch(matched.sanityDoc._id, {
|
|
1401
|
+
set: {
|
|
1402
|
+
filename: matched.muxTitle || matched.currentTitle || "",
|
|
1403
|
+
status: matched.muxAsset.status,
|
|
1404
|
+
data: dataWithKeys
|
|
1405
|
+
}
|
|
1406
|
+
});
|
|
1407
|
+
}), await tx.commit({ returnDocuments: !1 }), setResyncState("done");
|
|
1408
|
+
} catch (error) {
|
|
1409
|
+
setResyncState("error"), setResyncError(error);
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1240
1413
|
return {
|
|
1241
1414
|
sanityAssetsLoading,
|
|
1242
1415
|
closeDialog,
|
|
@@ -1246,6 +1419,7 @@ function useResyncMuxMetadata() {
|
|
|
1246
1419
|
hasSecrets,
|
|
1247
1420
|
syncAllVideos,
|
|
1248
1421
|
syncOnlyEmpty,
|
|
1422
|
+
syncFullData,
|
|
1249
1423
|
matchedAssets,
|
|
1250
1424
|
muxAssets,
|
|
1251
1425
|
openDialog
|
|
@@ -1261,22 +1435,78 @@ const useSanityAssets = createHookFromObservableFactory(
|
|
|
1261
1435
|
}
|
|
1262
1436
|
)
|
|
1263
1437
|
);
|
|
1438
|
+
function OptionCard({
|
|
1439
|
+
id,
|
|
1440
|
+
selected,
|
|
1441
|
+
onSelect,
|
|
1442
|
+
title,
|
|
1443
|
+
count,
|
|
1444
|
+
description,
|
|
1445
|
+
disabled
|
|
1446
|
+
}) {
|
|
1447
|
+
return /* @__PURE__ */ jsx(
|
|
1448
|
+
Card,
|
|
1449
|
+
{
|
|
1450
|
+
as: "label",
|
|
1451
|
+
padding: 3,
|
|
1452
|
+
radius: 2,
|
|
1453
|
+
border: !0,
|
|
1454
|
+
tone: selected ? "primary" : "default",
|
|
1455
|
+
style: {
|
|
1456
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
1457
|
+
opacity: disabled ? 0.5 : 1
|
|
1458
|
+
},
|
|
1459
|
+
children: /* @__PURE__ */ jsxs(Flex, { gap: 3, align: "flex-start", children: [
|
|
1460
|
+
/* @__PURE__ */ jsx(Box, { paddingTop: 1, children: /* @__PURE__ */ jsx(
|
|
1461
|
+
Radio,
|
|
1462
|
+
{
|
|
1463
|
+
checked: selected,
|
|
1464
|
+
onChange: () => onSelect(id),
|
|
1465
|
+
disabled,
|
|
1466
|
+
name: "sync-option"
|
|
1467
|
+
}
|
|
1468
|
+
) }),
|
|
1469
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, flex: 1, children: [
|
|
1470
|
+
/* @__PURE__ */ jsx(Flex, { align: "center", gap: 2, children: /* @__PURE__ */ jsxs(Text, { size: 2, weight: "semibold", children: [
|
|
1471
|
+
title,
|
|
1472
|
+
" (",
|
|
1473
|
+
count,
|
|
1474
|
+
")"
|
|
1475
|
+
] }) }),
|
|
1476
|
+
/* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: description })
|
|
1477
|
+
] })
|
|
1478
|
+
] })
|
|
1479
|
+
}
|
|
1480
|
+
);
|
|
1481
|
+
}
|
|
1264
1482
|
function ResyncMetadataDialog(props) {
|
|
1265
|
-
const { resyncState } = props,
|
|
1483
|
+
const { resyncState } = props, videosToUpdate = props.matchedAssets?.filter((m) => m.muxAsset).length || 0, videosWithEmptyOrPlaceholder = props.matchedAssets?.filter(
|
|
1266
1484
|
(m) => m.muxAsset && m.muxTitle && isEmptyOrPlaceholderTitle(m.currentTitle, m.muxAsset.id)
|
|
1267
|
-
).length || 0
|
|
1485
|
+
).length || 0, hasEmptyTitles = videosWithEmptyOrPlaceholder > 0, defaultOption = hasEmptyTitles ? "fillEmpty" : "syncTitles", [selectedOption, setSelectedOption] = useState(defaultOption), canTriggerResync = resyncState === "idle" || resyncState === "error", isResyncing = resyncState === "syncing", isDone = resyncState === "done", isLoading = props.muxAssets.loading || props.sanityAssetsLoading, handleSync = () => {
|
|
1486
|
+
switch (selectedOption) {
|
|
1487
|
+
case "fillEmpty":
|
|
1488
|
+
props.syncOnlyEmpty();
|
|
1489
|
+
break;
|
|
1490
|
+
case "syncTitles":
|
|
1491
|
+
props.syncAllVideos();
|
|
1492
|
+
break;
|
|
1493
|
+
case "fullResync":
|
|
1494
|
+
props.syncFullData();
|
|
1495
|
+
break;
|
|
1496
|
+
}
|
|
1497
|
+
};
|
|
1268
1498
|
return /* @__PURE__ */ jsx(
|
|
1269
1499
|
Dialog,
|
|
1270
1500
|
{
|
|
1271
1501
|
animate: !0,
|
|
1272
|
-
header: "
|
|
1502
|
+
header: "Sync with Mux",
|
|
1273
1503
|
zOffset: DIALOGS_Z_INDEX,
|
|
1274
1504
|
id: "resync-metadata-dialog",
|
|
1275
1505
|
onClose: props.closeDialog,
|
|
1276
1506
|
onClickOutside: props.closeDialog,
|
|
1277
1507
|
width: 1,
|
|
1278
1508
|
position: "fixed",
|
|
1279
|
-
footer: !isDone && /* @__PURE__ */ jsx(Card, { padding: 3, children: /* @__PURE__ */ jsxs(Flex, { justify: "
|
|
1509
|
+
footer: !isDone && /* @__PURE__ */ jsx(Card, { padding: 3, children: /* @__PURE__ */ jsxs(Flex, { justify: "flex-end", gap: 2, children: [
|
|
1280
1510
|
/* @__PURE__ */ jsx(
|
|
1281
1511
|
Button,
|
|
1282
1512
|
{
|
|
@@ -1284,97 +1514,104 @@ function ResyncMetadataDialog(props) {
|
|
|
1284
1514
|
padding: 3,
|
|
1285
1515
|
mode: "ghost",
|
|
1286
1516
|
text: "Cancel",
|
|
1287
|
-
tone: "critical",
|
|
1288
1517
|
onClick: props.closeDialog,
|
|
1289
1518
|
disabled: isResyncing
|
|
1290
1519
|
}
|
|
1291
1520
|
),
|
|
1292
|
-
/* @__PURE__ */
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
/* @__PURE__ */ jsx(
|
|
1306
|
-
Button,
|
|
1307
|
-
{
|
|
1308
|
-
icon: SyncIcon,
|
|
1309
|
-
fontSize: 2,
|
|
1310
|
-
padding: 3,
|
|
1311
|
-
mode: "ghost",
|
|
1312
|
-
text: `Update all (${videosToUpdate})`,
|
|
1313
|
-
tone: "positive",
|
|
1314
|
-
onClick: props.syncAllVideos,
|
|
1315
|
-
iconRight: isResyncing && Spinner,
|
|
1316
|
-
disabled: !canTriggerResync
|
|
1317
|
-
}
|
|
1318
|
-
)
|
|
1319
|
-
] })
|
|
1521
|
+
/* @__PURE__ */ jsx(
|
|
1522
|
+
Button,
|
|
1523
|
+
{
|
|
1524
|
+
icon: SyncIcon,
|
|
1525
|
+
fontSize: 2,
|
|
1526
|
+
padding: 3,
|
|
1527
|
+
text: "Run sync",
|
|
1528
|
+
tone: "primary",
|
|
1529
|
+
onClick: handleSync,
|
|
1530
|
+
iconRight: isResyncing && Spinner,
|
|
1531
|
+
disabled: !canTriggerResync || isLoading
|
|
1532
|
+
}
|
|
1533
|
+
)
|
|
1320
1534
|
] }) }),
|
|
1321
1535
|
children: /* @__PURE__ */ jsxs(Box, { padding: 4, children: [
|
|
1322
|
-
|
|
1536
|
+
isLoading && /* @__PURE__ */ jsx(Card, { tone: "primary", marginBottom: 4, padding: 3, border: !0, radius: 2, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 4, children: [
|
|
1323
1537
|
/* @__PURE__ */ jsx(Spinner, { muted: !0, size: 4 }),
|
|
1324
1538
|
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
1325
1539
|
/* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "Loading assets from Mux" }),
|
|
1326
|
-
/* @__PURE__ */ jsx(Text, { size: 1, children: "This may take a while." })
|
|
1540
|
+
/* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "This may take a while." })
|
|
1327
1541
|
] })
|
|
1328
1542
|
] }) }),
|
|
1329
|
-
props.muxAssets.error && /* @__PURE__ */ jsx(Card, { tone: "critical", marginBottom:
|
|
1543
|
+
props.muxAssets.error && /* @__PURE__ */ jsx(Card, { tone: "critical", marginBottom: 4, padding: 3, border: !0, radius: 2, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
1330
1544
|
/* @__PURE__ */ jsx(ErrorOutlineIcon, { fontSize: 36 }),
|
|
1331
1545
|
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
1332
1546
|
/* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "There was an error getting data from Mux" }),
|
|
1333
1547
|
/* @__PURE__ */ jsx(Text, { size: 1, children: "Please try again or contact a developer for help." })
|
|
1334
1548
|
] })
|
|
1335
1549
|
] }) }),
|
|
1336
|
-
resyncState === "syncing" && /* @__PURE__ */ jsx(Card, { tone: "primary", marginBottom:
|
|
1550
|
+
resyncState === "syncing" && /* @__PURE__ */ jsx(Card, { tone: "primary", marginBottom: 4, padding: 3, border: !0, radius: 2, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 4, children: [
|
|
1337
1551
|
/* @__PURE__ */ jsx(Spinner, { muted: !0, size: 4 }),
|
|
1338
1552
|
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
1339
|
-
/* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "
|
|
1340
|
-
/* @__PURE__ */ jsx(Text, { size: 1, children: "
|
|
1553
|
+
/* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "Syncing metadata" }),
|
|
1554
|
+
/* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Updating videos from Mux..." })
|
|
1341
1555
|
] })
|
|
1342
1556
|
] }) }),
|
|
1343
|
-
resyncState === "error" && /* @__PURE__ */ jsx(Card, { tone: "critical", marginBottom:
|
|
1557
|
+
resyncState === "error" && /* @__PURE__ */ jsx(Card, { tone: "critical", marginBottom: 4, padding: 3, border: !0, radius: 2, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
1344
1558
|
/* @__PURE__ */ jsx(ErrorOutlineIcon, { fontSize: 36 }),
|
|
1345
1559
|
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
1346
1560
|
/* @__PURE__ */ jsx(Text, { size: 2, weight: "semibold", children: "There was an error syncing metadata" }),
|
|
1347
1561
|
/* @__PURE__ */ jsx(Text, { size: 1, children: props.resyncError ? `Error: ${props.resyncError}` : "Please try again or contact a developer for help." })
|
|
1348
1562
|
] })
|
|
1349
1563
|
] }) }),
|
|
1350
|
-
resyncState === "done" && /* @__PURE__ */ jsxs(Stack, { paddingY: 5,
|
|
1564
|
+
resyncState === "done" && /* @__PURE__ */ jsxs(Stack, { paddingY: 5, space: 3, style: { textAlign: "center" }, children: [
|
|
1351
1565
|
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(CheckmarkCircleIcon, { fontSize: 48 }) }),
|
|
1352
|
-
/* @__PURE__ */ jsx(Heading, { size: 2, children: "
|
|
1353
|
-
/* @__PURE__ */ jsx(Text, { size: 2, children: "
|
|
1566
|
+
/* @__PURE__ */ jsx(Heading, { size: 2, children: "Sync completed" }),
|
|
1567
|
+
/* @__PURE__ */ jsx(Text, { size: 2, muted: !0, children: "Videos have been updated from Mux." })
|
|
1354
1568
|
] }),
|
|
1355
|
-
|
|
1356
|
-
/* @__PURE__ */ jsxs(
|
|
1357
|
-
"
|
|
1358
|
-
videosToUpdate === 1 ? "is" : "are",
|
|
1359
|
-
" ",
|
|
1569
|
+
!isDone && !isLoading && !props.muxAssets.error && /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
|
|
1570
|
+
/* @__PURE__ */ jsxs(Text, { size: 1, muted: !0, children: [
|
|
1571
|
+
"Found ",
|
|
1360
1572
|
videosToUpdate,
|
|
1361
1573
|
" video",
|
|
1362
1574
|
videosToUpdate === 1 ? "" : "s",
|
|
1363
|
-
"
|
|
1575
|
+
" linked to Mux."
|
|
1364
1576
|
] }),
|
|
1365
|
-
/* @__PURE__ */
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
"
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1577
|
+
/* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
1578
|
+
hasEmptyTitles && /* @__PURE__ */ jsx(
|
|
1579
|
+
OptionCard,
|
|
1580
|
+
{
|
|
1581
|
+
id: "fillEmpty",
|
|
1582
|
+
selected: selectedOption === "fillEmpty",
|
|
1583
|
+
onSelect: setSelectedOption,
|
|
1584
|
+
title: "Fill missing titles only",
|
|
1585
|
+
count: videosWithEmptyOrPlaceholder,
|
|
1586
|
+
description: "Updates only videos without a title or with placeholder titles (e.g., 'Asset #123') using the title from Mux.",
|
|
1587
|
+
disabled: isResyncing
|
|
1588
|
+
}
|
|
1589
|
+
),
|
|
1590
|
+
/* @__PURE__ */ jsx(
|
|
1591
|
+
OptionCard,
|
|
1592
|
+
{
|
|
1593
|
+
id: "syncTitles",
|
|
1594
|
+
selected: selectedOption === "syncTitles",
|
|
1595
|
+
onSelect: setSelectedOption,
|
|
1596
|
+
title: "Sync all titles",
|
|
1597
|
+
count: videosToUpdate,
|
|
1598
|
+
description: "Replaces the title in Sanity with the title from Mux for all videos.",
|
|
1599
|
+
disabled: isResyncing
|
|
1600
|
+
}
|
|
1601
|
+
),
|
|
1602
|
+
/* @__PURE__ */ jsx(
|
|
1603
|
+
OptionCard,
|
|
1604
|
+
{
|
|
1605
|
+
id: "fullResync",
|
|
1606
|
+
selected: selectedOption === "fullResync",
|
|
1607
|
+
onSelect: setSelectedOption,
|
|
1608
|
+
title: "Full resync",
|
|
1609
|
+
count: videosToUpdate,
|
|
1610
|
+
description: "Updates all fields from Mux including status, duration, tracks, captions, and renditions.",
|
|
1611
|
+
disabled: isResyncing
|
|
1612
|
+
}
|
|
1613
|
+
)
|
|
1614
|
+
] })
|
|
1378
1615
|
] })
|
|
1379
1616
|
] })
|
|
1380
1617
|
}
|
|
@@ -1383,7 +1620,7 @@ function ResyncMetadataDialog(props) {
|
|
|
1383
1620
|
function ResyncMetadata() {
|
|
1384
1621
|
const resyncMetadata = useResyncMuxMetadata();
|
|
1385
1622
|
if (resyncMetadata.hasSecrets)
|
|
1386
|
-
return resyncMetadata.dialogOpen ? /* @__PURE__ */ jsx(ResyncMetadataDialog, { ...resyncMetadata }) : /* @__PURE__ */ jsx(Button, { mode: "bleed", text: "
|
|
1623
|
+
return resyncMetadata.dialogOpen ? /* @__PURE__ */ jsx(ResyncMetadataDialog, { ...resyncMetadata }) : /* @__PURE__ */ jsx(Button, { mode: "bleed", text: "Sync with Mux", onClick: resyncMetadata.openDialog });
|
|
1387
1624
|
}
|
|
1388
1625
|
const CONTEXT_MENU_POPOVER_PROPS = {
|
|
1389
1626
|
constrainSize: !0,
|
|
@@ -1464,6 +1701,55 @@ function StopWatchIcon(props) {
|
|
|
1464
1701
|
}
|
|
1465
1702
|
);
|
|
1466
1703
|
}
|
|
1704
|
+
function useResyncAsset(options) {
|
|
1705
|
+
const client = useClient(), toast = useToast(), [resyncState, setResyncState] = useState("idle"), [resyncError, setResyncError] = useState(null), showToast = options?.showToast ?? !1, resyncAsset = useCallback(
|
|
1706
|
+
async (asset) => {
|
|
1707
|
+
if (!asset.assetId) {
|
|
1708
|
+
showToast && toast.push({
|
|
1709
|
+
title: "Cannot resync",
|
|
1710
|
+
description: "Asset has no Mux ID",
|
|
1711
|
+
status: "error"
|
|
1712
|
+
}), options?.onError?.(new Error("Asset has no Mux ID"));
|
|
1713
|
+
return;
|
|
1714
|
+
}
|
|
1715
|
+
if (!asset._id) {
|
|
1716
|
+
showToast && toast.push({
|
|
1717
|
+
title: "Cannot resync",
|
|
1718
|
+
description: "Asset has no document ID",
|
|
1719
|
+
status: "error"
|
|
1720
|
+
}), options?.onError?.(new Error("Asset has no document ID"));
|
|
1721
|
+
return;
|
|
1722
|
+
}
|
|
1723
|
+
setResyncState("syncing"), setResyncError(null);
|
|
1724
|
+
try {
|
|
1725
|
+
const muxData = (await getAsset(client, asset.assetId)).data, dataWithKeys = addKeysToMuxData(muxData);
|
|
1726
|
+
return await client.patch(asset._id).set({
|
|
1727
|
+
status: muxData.status,
|
|
1728
|
+
data: dataWithKeys,
|
|
1729
|
+
...muxData.meta?.title && { filename: muxData.meta.title }
|
|
1730
|
+
}).commit({ returnDocuments: !1 }), setResyncState("success"), showToast && toast.push({
|
|
1731
|
+
title: "Asset synced",
|
|
1732
|
+
description: "Data has been updated from Mux",
|
|
1733
|
+
status: "success"
|
|
1734
|
+
}), options?.onSuccess?.(muxData), muxData;
|
|
1735
|
+
} catch (error) {
|
|
1736
|
+
setResyncState("error"), setResyncError(error), console.error("Failed to refresh asset data:", error), showToast && toast.push({
|
|
1737
|
+
title: "Sync failed",
|
|
1738
|
+
description: "Could not sync asset from Mux",
|
|
1739
|
+
status: "error"
|
|
1740
|
+
}), options?.onError?.(error);
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1743
|
+
},
|
|
1744
|
+
[client, toast, options, showToast]
|
|
1745
|
+
);
|
|
1746
|
+
return {
|
|
1747
|
+
resyncState,
|
|
1748
|
+
resyncError,
|
|
1749
|
+
resyncAsset,
|
|
1750
|
+
isResyncing: resyncState === "syncing"
|
|
1751
|
+
};
|
|
1752
|
+
}
|
|
1467
1753
|
function extractErrorMessage(error, defaultMessage = "Failed to process request") {
|
|
1468
1754
|
let message = "";
|
|
1469
1755
|
if (error && typeof error == "object") {
|
|
@@ -1547,9 +1833,9 @@ async function downloadVttFile(client, asset, track) {
|
|
|
1547
1833
|
const playbackId = getPlaybackId(asset);
|
|
1548
1834
|
if (!playbackId)
|
|
1549
1835
|
throw new Error("Playback ID is required");
|
|
1550
|
-
const playbackPolicy = getPlaybackPolicy(asset);
|
|
1836
|
+
const playbackPolicy = getPlaybackPolicy(asset)?.policy;
|
|
1551
1837
|
let downloadUrl = `https://stream.mux.com/${playbackId}/text/${track.id}.vtt`;
|
|
1552
|
-
if (playbackPolicy === "signed") {
|
|
1838
|
+
if (playbackPolicy === "signed" || playbackPolicy === "drm") {
|
|
1553
1839
|
const token = generateJwt(client, playbackId, "v");
|
|
1554
1840
|
downloadUrl += `?token=${token}`;
|
|
1555
1841
|
}
|
|
@@ -2027,7 +2313,7 @@ function EditCaptionDialog({ asset, track, onUpdate, onClose }) {
|
|
|
2027
2313
|
const playbackId = getPlaybackId(asset);
|
|
2028
2314
|
if (!playbackId) return "";
|
|
2029
2315
|
let url = `https://stream.mux.com/${playbackId}/text/${track.id}.vtt`;
|
|
2030
|
-
if (getPlaybackPolicy(asset) === "signed") {
|
|
2316
|
+
if (getPlaybackPolicy(asset)?.policy === "signed") {
|
|
2031
2317
|
const token = generateJwt(client, playbackId, "v");
|
|
2032
2318
|
url += `?token=${token}`;
|
|
2033
2319
|
}
|
|
@@ -2366,20 +2652,7 @@ function TextTracksManager({
|
|
|
2366
2652
|
tracks: propTracks,
|
|
2367
2653
|
collapseTracks = !1
|
|
2368
2654
|
}) {
|
|
2369
|
-
const client = useClient(), toast = useToast(), dialogId = `DeleteCaptionDialog${useId()}`, [downloadingTrackId, setDownloadingTrackId] = useState(null), [deletingTrackId, setDeletingTrackId] = useState(null), [addedTracks, setAddedTracks] = useState([]), [updatedTracks, setUpdatedTracks] = useState(/* @__PURE__ */ new Map()), [trackActivityOrder, setTrackActivityOrder] = useState(/* @__PURE__ */ new Map()), [autogeneratedTrackIds, setAutogeneratedTrackIds] = useState(/* @__PURE__ */ new Set()), [trackToDelete, setTrackToDelete] = useState(null), [trackToEdit, setTrackToEdit] = useState(null), [showAddDialog, setShowAddDialog] = useState(!1), [isExpanded, setIsExpanded] = useState(!1), MAX_VISIBLE_TRACKS = 4
|
|
2370
|
-
useEffect(() => {
|
|
2371
|
-
if (!asset.assetId || !asset._id) return;
|
|
2372
|
-
const assetId = asset.assetId, documentId = asset._id;
|
|
2373
|
-
(async () => {
|
|
2374
|
-
try {
|
|
2375
|
-
const response = await getAsset(client, assetId);
|
|
2376
|
-
await client.patch(documentId).set({ data: response.data, status: response.data.status }).commit();
|
|
2377
|
-
} catch (error) {
|
|
2378
|
-
console.error("Failed to refresh asset data:", error);
|
|
2379
|
-
}
|
|
2380
|
-
})();
|
|
2381
|
-
}, [asset.assetId, asset._id, client]);
|
|
2382
|
-
const activeTracks = (propTracks || asset.data?.tracks?.filter((track) => track.type === "text") || []).filter(
|
|
2655
|
+
const client = useClient(), toast = useToast(), dialogId = `DeleteCaptionDialog${useId()}`, { resyncAsset } = useResyncAsset(), [downloadingTrackId, setDownloadingTrackId] = useState(null), [deletingTrackId, setDeletingTrackId] = useState(null), [addedTracks, setAddedTracks] = useState([]), [updatedTracks, setUpdatedTracks] = useState(/* @__PURE__ */ new Map()), [trackActivityOrder, setTrackActivityOrder] = useState(/* @__PURE__ */ new Map()), [autogeneratedTrackIds, setAutogeneratedTrackIds] = useState(/* @__PURE__ */ new Set()), [trackToDelete, setTrackToDelete] = useState(null), [trackToEdit, setTrackToEdit] = useState(null), [showAddDialog, setShowAddDialog] = useState(!1), [isExpanded, setIsExpanded] = useState(!1), MAX_VISIBLE_TRACKS = 4, activeTracks = (propTracks || asset.data?.tracks?.filter((track) => track.type === "text") || []).filter(
|
|
2383
2656
|
(track) => track.id && (track.status === "ready" || track.status === "preparing" || track.status === "errored")
|
|
2384
2657
|
), allTracks = useMemo(() => {
|
|
2385
2658
|
const tracksWithUpdates = activeTracks.map((track) => updatedTracks.get(track.id) || track), isMockTrackReplaced = (mockTrack, realTracksList) => !mockTrack.id || !mockTrack.id.startsWith("generating-") ? !1 : realTracksList.some((realTrack) => {
|
|
@@ -2410,11 +2683,11 @@ function TextTracksManager({
|
|
|
2410
2683
|
}, [activeTracks, addedTracks]), useEffect(() => {
|
|
2411
2684
|
if (allTracks.filter((track) => track.status === "preparing").length === 0 || !asset.assetId || !asset._id)
|
|
2412
2685
|
return;
|
|
2413
|
-
const
|
|
2686
|
+
const interval = setInterval(async () => {
|
|
2414
2687
|
try {
|
|
2415
|
-
const
|
|
2416
|
-
|
|
2417
|
-
const fetchedTracks =
|
|
2688
|
+
const muxData = await resyncAsset(asset);
|
|
2689
|
+
if (!muxData) return;
|
|
2690
|
+
const fetchedTracks = muxData.tracks?.filter((track) => track.type === "text") || [], isMockTrackReplaced = (mockTrack, fetchedTracksList) => !mockTrack.id || !mockTrack.id.startsWith("generating-") ? !1 : fetchedTracksList.some((realTrack) => {
|
|
2418
2691
|
const nameMatches = realTrack.name === mockTrack.name, languageMatches = realTrack.language_code === mockTrack.language_code;
|
|
2419
2692
|
return !nameMatches || !languageMatches ? !1 : realTrack.status === "ready" ? realTrack.text_source === "generated_live" || realTrack.text_source === "generated_live_final" || realTrack.text_source === "generated_vod" : realTrack.status === "preparing";
|
|
2420
2693
|
}), newAutogeneratedIds = /* @__PURE__ */ new Set();
|
|
@@ -2451,7 +2724,7 @@ function TextTracksManager({
|
|
|
2451
2724
|
}
|
|
2452
2725
|
}, 3e3);
|
|
2453
2726
|
return () => clearInterval(interval);
|
|
2454
|
-
}, [allTracks, asset
|
|
2727
|
+
}, [allTracks, asset, resyncAsset]);
|
|
2455
2728
|
const visibleTracks = allTracks.filter(
|
|
2456
2729
|
(track) => track.status === "ready" || track.status === "preparing" || track.status === "errored"
|
|
2457
2730
|
).sort((a2, b) => {
|
|
@@ -2487,14 +2760,7 @@ function TextTracksManager({
|
|
|
2487
2760
|
try {
|
|
2488
2761
|
if (!asset.assetId)
|
|
2489
2762
|
throw new Error("Asset ID is required");
|
|
2490
|
-
|
|
2491
|
-
try {
|
|
2492
|
-
const response = await getAsset(client, asset.assetId);
|
|
2493
|
-
await client.patch(asset._id).set({ data: response.data, status: response.data.status }).commit();
|
|
2494
|
-
} catch (refreshError) {
|
|
2495
|
-
console.error("Failed to refresh asset data:", refreshError);
|
|
2496
|
-
}
|
|
2497
|
-
toast.push({
|
|
2763
|
+
await deleteTextTrack(client, asset.assetId, track.id), await resyncAsset(asset), toast.push({
|
|
2498
2764
|
title: "Successfully deleted caption track",
|
|
2499
2765
|
status: "success"
|
|
2500
2766
|
}), setAddedTracks((prev) => prev.filter((t) => t.id !== track.id)), setUpdatedTracks((prev) => {
|
|
@@ -2522,7 +2788,7 @@ function TextTracksManager({
|
|
|
2522
2788
|
return newMap.set(track.id, prev.size + 1), newMap;
|
|
2523
2789
|
}), setShowAddDialog(!1);
|
|
2524
2790
|
}, handleUpdateTrack = async (updatedTrack, oldTrackId) => {
|
|
2525
|
-
|
|
2791
|
+
oldTrackId && (setAddedTracks((prev) => prev.filter((t) => t.id !== oldTrackId)), setUpdatedTracks((prev) => {
|
|
2526
2792
|
const newMap = new Map(prev);
|
|
2527
2793
|
return newMap.delete(oldTrackId), newMap;
|
|
2528
2794
|
}), setTrackActivityOrder((prev) => {
|
|
@@ -2537,13 +2803,7 @@ function TextTracksManager({
|
|
|
2537
2803
|
}), setTrackActivityOrder((prev) => {
|
|
2538
2804
|
const newMap = new Map(prev);
|
|
2539
2805
|
return newMap.set(updatedTrack.id, prev.size + 1), newMap;
|
|
2540
|
-
}), setTrackToEdit(null),
|
|
2541
|
-
try {
|
|
2542
|
-
const response = await getAsset(client, asset.assetId);
|
|
2543
|
-
await client.patch(asset._id).set({ data: response.data, status: response.data.status }).commit();
|
|
2544
|
-
} catch (refreshError) {
|
|
2545
|
-
console.error("Failed to refresh asset data:", refreshError);
|
|
2546
|
-
}
|
|
2806
|
+
}), setTrackToEdit(null), await resyncAsset(asset);
|
|
2547
2807
|
}, getTrackSourceLabel = (track) => track.id && track.id.startsWith("generating-") || track.id && autogeneratedTrackIds.has(track.id) || track.text_source === "generated_live_final" || track.text_source === "generated_live" || track.text_source === "generated_vod" ? "Auto-generated" : track.text_source === "uploaded" ? "Uploaded" : "Custom";
|
|
2548
2808
|
if (visibleTracks.length === 0 && !showAddDialog)
|
|
2549
2809
|
return /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
@@ -2683,13 +2943,13 @@ const DialogStateContext = createContext({
|
|
|
2683
2943
|
setDialogState,
|
|
2684
2944
|
children
|
|
2685
2945
|
}) => /* @__PURE__ */ jsx(DialogStateContext.Provider, { value: { dialogState, setDialogState }, children }), useDialogStateContext = () => useContext(DialogStateContext);
|
|
2686
|
-
function getVideoSrc({
|
|
2687
|
-
const
|
|
2688
|
-
if (
|
|
2689
|
-
const token = generateJwt(client,
|
|
2946
|
+
function getVideoSrc({ client, muxPlaybackId: muxPlaybackId2 }) {
|
|
2947
|
+
const searchParams = new URLSearchParams();
|
|
2948
|
+
if (muxPlaybackId2.policy === "signed" || muxPlaybackId2.policy === "drm") {
|
|
2949
|
+
const token = generateJwt(client, muxPlaybackId2.id, "v");
|
|
2690
2950
|
searchParams.set("token", token);
|
|
2691
2951
|
}
|
|
2692
|
-
return `https://stream.mux.com/${
|
|
2952
|
+
return `https://stream.mux.com/${muxPlaybackId2.id}.m3u8?${searchParams}`;
|
|
2693
2953
|
}
|
|
2694
2954
|
function CaptionsDialog({ asset }) {
|
|
2695
2955
|
const { setDialogState } = useDialogStateContext(), dialogId = `CaptionsDialog${useId()}`;
|
|
@@ -2799,24 +3059,56 @@ function VideoPlayer({
|
|
|
2799
3059
|
hlsConfig,
|
|
2800
3060
|
...props
|
|
2801
3061
|
}) {
|
|
2802
|
-
const client = useClient(), { dialogState } = useDialogStateContext(), isAudio = assetIsAudio(asset), muxPlayer = useRef(null), {
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
3062
|
+
const client = useClient(), { dialogState } = useDialogStateContext(), isAudio = assetIsAudio(asset), muxPlayer = useRef(null), [error, setError] = useState(), playbackId = useMemo(() => {
|
|
3063
|
+
try {
|
|
3064
|
+
return getPlaybackId(asset, ["public", "signed", "drm"]);
|
|
3065
|
+
} catch {
|
|
3066
|
+
setError(new TypeError("Asset has no playback ID"));
|
|
3067
|
+
return;
|
|
3068
|
+
}
|
|
3069
|
+
}, [asset]), muxPlaybackId2 = useMemo(() => {
|
|
3070
|
+
if (playbackId)
|
|
3071
|
+
return getPlaybackPolicyById(asset, playbackId);
|
|
3072
|
+
}, [asset, playbackId]), src = useMemo(() => {
|
|
3073
|
+
if (playbackId && muxPlaybackId2)
|
|
3074
|
+
return tryWithSuspend(
|
|
3075
|
+
() => getVideoSrc({ muxPlaybackId: muxPlaybackId2, client }),
|
|
3076
|
+
(e) => {
|
|
3077
|
+
setError(e);
|
|
3078
|
+
}
|
|
3079
|
+
);
|
|
3080
|
+
}, [muxPlaybackId2, playbackId, client]), poster = useMemo(() => tryWithSuspend(
|
|
3081
|
+
() => getPosterSrc({ asset, client, width: thumbnailWidth }),
|
|
3082
|
+
(e) => {
|
|
3083
|
+
setError(e);
|
|
3084
|
+
}
|
|
3085
|
+
), [asset, client, thumbnailWidth]), signedToken = useMemo(() => {
|
|
2807
3086
|
try {
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
return { error: error2 };
|
|
3087
|
+
return new URL(src).searchParams.get("token");
|
|
3088
|
+
} catch {
|
|
3089
|
+
return;
|
|
2812
3090
|
}
|
|
2813
|
-
}, [
|
|
3091
|
+
}, [src]), drmToken = useMemo(() => {
|
|
3092
|
+
if (playbackId && muxPlaybackId2?.policy === "drm")
|
|
3093
|
+
return tryWithSuspend(
|
|
3094
|
+
() => generateJwt(client, playbackId, "d"),
|
|
3095
|
+
(e) => {
|
|
3096
|
+
setError(e);
|
|
3097
|
+
}
|
|
3098
|
+
);
|
|
3099
|
+
}, [client, muxPlaybackId2?.policy, playbackId]), tokens = useMemo(() => {
|
|
2814
3100
|
try {
|
|
2815
|
-
|
|
3101
|
+
const partialTokens = {
|
|
3102
|
+
playback: void 0,
|
|
3103
|
+
thumbnail: void 0,
|
|
3104
|
+
storyboard: void 0,
|
|
3105
|
+
drm: void 0
|
|
3106
|
+
};
|
|
3107
|
+
return signedToken && (partialTokens.playback = signedToken, partialTokens.thumbnail = signedToken, partialTokens.storyboard = signedToken), drmToken && (partialTokens.drm = drmToken), { ...partialTokens };
|
|
2816
3108
|
} catch {
|
|
2817
|
-
return
|
|
3109
|
+
return;
|
|
2818
3110
|
}
|
|
2819
|
-
}, [
|
|
3111
|
+
}, [signedToken, drmToken]), [width, height] = (asset?.data?.aspect_ratio ?? "16:9").split(":").map(Number), targetAspectRatio = props.forceAspectRatio || (Number.isNaN(width) ? 16 / 9 : width / height);
|
|
2820
3112
|
let aspectRatio = Math.max(MIN_ASPECT_RATIO, targetAspectRatio);
|
|
2821
3113
|
return isAudio && (aspectRatio = props.forceAspectRatio ? (
|
|
2822
3114
|
// Make it wider when forcing aspect ratio to balance with videos' rendering height (audio players overflow a bit)
|
|
@@ -2832,7 +3124,7 @@ function VideoPlayer({
|
|
|
2832
3124
|
...isAudio && { display: "flex", alignItems: "flex-end" }
|
|
2833
3125
|
},
|
|
2834
3126
|
children: [
|
|
2835
|
-
|
|
3127
|
+
src && poster && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2836
3128
|
isAudio && /* @__PURE__ */ jsx(
|
|
2837
3129
|
AudioIcon,
|
|
2838
3130
|
{
|
|
@@ -2847,34 +3139,36 @@ function VideoPlayer({
|
|
|
2847
3139
|
}
|
|
2848
3140
|
}
|
|
2849
3141
|
),
|
|
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
|
-
|
|
3142
|
+
/* @__PURE__ */ jsxs(Suspense, { fallback: null, children: [
|
|
3143
|
+
/* @__PURE__ */ jsx(
|
|
3144
|
+
MuxPlayer,
|
|
3145
|
+
{
|
|
3146
|
+
poster: isAudio ? void 0 : poster,
|
|
3147
|
+
ref: muxPlayer,
|
|
3148
|
+
...props,
|
|
3149
|
+
playsInline: !0,
|
|
3150
|
+
playbackId,
|
|
3151
|
+
tokens,
|
|
3152
|
+
preload: "metadata",
|
|
3153
|
+
crossOrigin: "anonymous",
|
|
3154
|
+
metadata: {
|
|
3155
|
+
player_name: "Sanity Admin Dashboard",
|
|
3156
|
+
player_version: "2.16.0",
|
|
3157
|
+
page_type: "Preview Player"
|
|
3158
|
+
},
|
|
3159
|
+
audio: isAudio,
|
|
3160
|
+
_hlsConfig: hlsConfig,
|
|
3161
|
+
style: {
|
|
3162
|
+
...!isAudio && { height: "100%" },
|
|
3163
|
+
width: "100%",
|
|
3164
|
+
display: "block",
|
|
3165
|
+
objectFit: "contain",
|
|
3166
|
+
...isAudio && { alignSelf: "end" }
|
|
3167
|
+
}
|
|
2874
3168
|
}
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
3169
|
+
),
|
|
3170
|
+
children
|
|
3171
|
+
] })
|
|
2878
3172
|
] }),
|
|
2879
3173
|
error ? /* @__PURE__ */ jsx(
|
|
2880
3174
|
"div",
|
|
@@ -3166,6 +3460,7 @@ function getVideoMetadata(doc) {
|
|
|
3166
3460
|
playbackId: doc.playbackId,
|
|
3167
3461
|
createdAt: date,
|
|
3168
3462
|
duration: doc.data?.duration ? formatSeconds(doc.data?.duration) : void 0,
|
|
3463
|
+
playback_ids: doc.data?.playback_ids,
|
|
3169
3464
|
aspect_ratio: doc.data?.aspect_ratio,
|
|
3170
3465
|
max_stored_resolution: doc.data?.max_stored_resolution,
|
|
3171
3466
|
max_stored_frame_rate: doc.data?.max_stored_frame_rate,
|
|
@@ -3175,7 +3470,10 @@ function getVideoMetadata(doc) {
|
|
|
3175
3470
|
function useVideoDetails(props) {
|
|
3176
3471
|
const documentStore = useDocumentStore(), toast = useToast(), client = useClient(), [references, referencesLoading] = useDocReferences(
|
|
3177
3472
|
useMemo(() => ({ documentStore, id: props.asset._id }), [documentStore, props.asset._id])
|
|
3178
|
-
), [originalAsset, setOriginalAsset] = useState(() => props.asset), [filename, setFilename] = useState(props.asset.filename), modified = filename !== originalAsset.filename, displayInfo = getVideoMetadata({ ...props.asset, filename }), [state, setState] = useState("idle");
|
|
3473
|
+
), [originalAsset, setOriginalAsset] = useState(() => props.asset), [filename, setFilename] = useState(props.asset.filename), modified = filename !== originalAsset.filename, displayInfo = getVideoMetadata({ ...props.asset, filename }), [state, setState] = useState("idle"), { resyncAsset, isResyncing } = useResyncAsset({ showToast: !0 });
|
|
3474
|
+
async function handleResync() {
|
|
3475
|
+
state === "idle" && (setState("resyncing"), await resyncAsset(props.asset), setState("idle"));
|
|
3476
|
+
}
|
|
3179
3477
|
function handleClose() {
|
|
3180
3478
|
if (state === "idle") {
|
|
3181
3479
|
if (modified) {
|
|
@@ -3218,7 +3516,9 @@ function useVideoDetails(props) {
|
|
|
3218
3516
|
setState,
|
|
3219
3517
|
handleClose,
|
|
3220
3518
|
confirmClose,
|
|
3221
|
-
saveChanges
|
|
3519
|
+
saveChanges,
|
|
3520
|
+
handleResync,
|
|
3521
|
+
isResyncing
|
|
3222
3522
|
};
|
|
3223
3523
|
}
|
|
3224
3524
|
const AssetInput = (props) => /* @__PURE__ */ jsx(FormField$1, { title: props.label, description: props.description, inputId: props.label, children: /* @__PURE__ */ jsx(
|
|
@@ -3242,7 +3542,9 @@ const AssetInput = (props) => /* @__PURE__ */ jsx(FormField$1, { title: props.la
|
|
|
3242
3542
|
setState,
|
|
3243
3543
|
handleClose,
|
|
3244
3544
|
confirmClose,
|
|
3245
|
-
saveChanges
|
|
3545
|
+
saveChanges,
|
|
3546
|
+
handleResync,
|
|
3547
|
+
isResyncing
|
|
3246
3548
|
} = useVideoDetails(props), isSaving = state === "saving", [containerHeight, setContainerHeight] = useState(null), contentsRef = React.useRef(null);
|
|
3247
3549
|
return useEffect(() => {
|
|
3248
3550
|
!contentsRef.current || !("getBoundingClientRect" in contentsRef.current) || setContainerHeight(contentsRef.current.getBoundingClientRect().height);
|
|
@@ -3258,19 +3560,35 @@ const AssetInput = (props) => /* @__PURE__ */ jsx(FormField$1, { title: props.la
|
|
|
3258
3560
|
width: 2,
|
|
3259
3561
|
position: "fixed",
|
|
3260
3562
|
footer: /* @__PURE__ */ jsx(Card, { padding: 3, children: /* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
|
|
3261
|
-
/* @__PURE__ */
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3563
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
|
3564
|
+
/* @__PURE__ */ jsx(
|
|
3565
|
+
Button,
|
|
3566
|
+
{
|
|
3567
|
+
icon: TrashIcon,
|
|
3568
|
+
fontSize: 2,
|
|
3569
|
+
padding: 3,
|
|
3570
|
+
mode: "bleed",
|
|
3571
|
+
text: "Delete",
|
|
3572
|
+
tone: "critical",
|
|
3573
|
+
onClick: () => setState("deleting"),
|
|
3574
|
+
disabled: isSaving || isResyncing
|
|
3575
|
+
}
|
|
3576
|
+
),
|
|
3577
|
+
/* @__PURE__ */ jsx(
|
|
3578
|
+
Button,
|
|
3579
|
+
{
|
|
3580
|
+
icon: SyncIcon,
|
|
3581
|
+
fontSize: 2,
|
|
3582
|
+
padding: 3,
|
|
3583
|
+
mode: "bleed",
|
|
3584
|
+
text: "Resync",
|
|
3585
|
+
tone: "primary",
|
|
3586
|
+
onClick: handleResync,
|
|
3587
|
+
disabled: isSaving || isResyncing,
|
|
3588
|
+
iconRight: isResyncing && Spinner
|
|
3589
|
+
}
|
|
3590
|
+
)
|
|
3591
|
+
] }),
|
|
3274
3592
|
modified && /* @__PURE__ */ jsx(
|
|
3275
3593
|
Button,
|
|
3276
3594
|
{
|
|
@@ -3282,7 +3600,7 @@ const AssetInput = (props) => /* @__PURE__ */ jsx(FormField$1, { title: props.la
|
|
|
3282
3600
|
tone: "positive",
|
|
3283
3601
|
onClick: saveChanges,
|
|
3284
3602
|
iconRight: isSaving && Spinner,
|
|
3285
|
-
disabled: isSaving
|
|
3603
|
+
disabled: isSaving || isResyncing
|
|
3286
3604
|
}
|
|
3287
3605
|
)
|
|
3288
3606
|
] }) }),
|
|
@@ -3468,14 +3786,7 @@ const AssetInput = (props) => /* @__PURE__ */ jsx(FormField$1, { title: props.la
|
|
|
3468
3786
|
),
|
|
3469
3787
|
/* @__PURE__ */ jsx(IconInfo, { text: `Mux ID:
|
|
3470
3788
|
${displayInfo.id}`, icon: TagIcon, size: 2 }),
|
|
3471
|
-
|
|
3472
|
-
IconInfo,
|
|
3473
|
-
{
|
|
3474
|
-
text: `Playback ID: ${displayInfo.playbackId}`,
|
|
3475
|
-
icon: TagIcon,
|
|
3476
|
-
size: 2
|
|
3477
|
-
}
|
|
3478
|
-
)
|
|
3789
|
+
/* @__PURE__ */ jsx(PlaybackIds, { playback_ids: displayInfo.playback_ids })
|
|
3479
3790
|
] })
|
|
3480
3791
|
] })
|
|
3481
3792
|
}
|
|
@@ -3498,9 +3809,28 @@ ${displayInfo.id}`, icon: TagIcon, size: 2 }),
|
|
|
3498
3809
|
]
|
|
3499
3810
|
}
|
|
3500
3811
|
);
|
|
3501
|
-
},
|
|
3502
|
-
|
|
3503
|
-
|
|
3812
|
+
}, PlaybackIds = ({ playback_ids }) => playback_ids ? playback_ids.map((entry) => /* @__PURE__ */ jsx(
|
|
3813
|
+
IconInfo,
|
|
3814
|
+
{
|
|
3815
|
+
text: `Playback ID [${policyToText(entry.policy)}]: ${entry.id}`,
|
|
3816
|
+
icon: TagIcon,
|
|
3817
|
+
size: 2
|
|
3818
|
+
},
|
|
3819
|
+
entry.id
|
|
3820
|
+
)) : /* @__PURE__ */ jsx(IconInfo, { text: "No Playback ID", icon: TagIcon, size: 2 }), policyToText = (policy) => {
|
|
3821
|
+
switch (policy) {
|
|
3822
|
+
case "drm":
|
|
3823
|
+
return "DRM";
|
|
3824
|
+
case "signed":
|
|
3825
|
+
return "Signed";
|
|
3826
|
+
case "public":
|
|
3827
|
+
return "Public";
|
|
3828
|
+
default:
|
|
3829
|
+
return policy;
|
|
3830
|
+
}
|
|
3831
|
+
}, VideoMetadata = (props) => {
|
|
3832
|
+
if (!props.asset)
|
|
3833
|
+
return null;
|
|
3504
3834
|
const displayInfo = getVideoMetadata(props.asset);
|
|
3505
3835
|
return /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
3506
3836
|
displayInfo.title && /* @__PURE__ */ jsx(
|
|
@@ -3591,10 +3921,12 @@ function VideoInBrowser({
|
|
|
3591
3921
|
onEdit,
|
|
3592
3922
|
asset
|
|
3593
3923
|
}) {
|
|
3594
|
-
const [renderVideo, setRenderVideo] = useState(!1), select = React.useCallback(() => onSelect?.(asset), [onSelect, asset]), edit = React.useCallback(() => onEdit?.(asset), [onEdit, asset]);
|
|
3924
|
+
const [renderVideo, setRenderVideo] = useState(!1), select = React.useCallback(() => onSelect?.(asset), [onSelect, asset]), edit = React.useCallback(() => onEdit?.(asset), [onEdit, asset]), { hasShownWarning } = useDrmPlaybackWarningContext();
|
|
3595
3925
|
if (!asset)
|
|
3596
3926
|
return null;
|
|
3597
|
-
const playbackPolicy = getPlaybackPolicy(asset)
|
|
3927
|
+
const playbackPolicy = getPlaybackPolicy(asset), onClickPlay = () => {
|
|
3928
|
+
playbackPolicy?.policy === "drm" && !hasShownWarning ? setRenderVideo("pre-render-warn") : setRenderVideo("render-video");
|
|
3929
|
+
};
|
|
3598
3930
|
return /* @__PURE__ */ jsxs(
|
|
3599
3931
|
Card,
|
|
3600
3932
|
{
|
|
@@ -3606,7 +3938,7 @@ function VideoInBrowser({
|
|
|
3606
3938
|
position: "relative"
|
|
3607
3939
|
},
|
|
3608
3940
|
children: [
|
|
3609
|
-
playbackPolicy === "signed" && /* @__PURE__ */ jsx(
|
|
3941
|
+
playbackPolicy?.policy === "signed" && /* @__PURE__ */ jsx(
|
|
3610
3942
|
Tooltip,
|
|
3611
3943
|
{
|
|
3612
3944
|
animate: !0,
|
|
@@ -3623,7 +3955,7 @@ function VideoInBrowser({
|
|
|
3623
3955
|
position: "absolute",
|
|
3624
3956
|
left: "1em",
|
|
3625
3957
|
top: "1em",
|
|
3626
|
-
zIndex:
|
|
3958
|
+
zIndex: 11
|
|
3627
3959
|
},
|
|
3628
3960
|
padding: 2,
|
|
3629
3961
|
border: !0,
|
|
@@ -3632,6 +3964,32 @@ function VideoInBrowser({
|
|
|
3632
3964
|
)
|
|
3633
3965
|
}
|
|
3634
3966
|
),
|
|
3967
|
+
playbackPolicy?.policy === "drm" && /* @__PURE__ */ jsx(
|
|
3968
|
+
Tooltip,
|
|
3969
|
+
{
|
|
3970
|
+
animate: !0,
|
|
3971
|
+
content: /* @__PURE__ */ jsx(Card, { padding: 2, radius: 2, children: /* @__PURE__ */ jsx(IconInfo, { icon: LockIcon, text: "DRM playback policy", size: 2 }) }),
|
|
3972
|
+
placement: "right",
|
|
3973
|
+
fallbackPlacements: ["top", "bottom"],
|
|
3974
|
+
portal: !0,
|
|
3975
|
+
children: /* @__PURE__ */ jsx(
|
|
3976
|
+
Card,
|
|
3977
|
+
{
|
|
3978
|
+
tone: "caution",
|
|
3979
|
+
style: {
|
|
3980
|
+
borderRadius: "0.25rem",
|
|
3981
|
+
position: "absolute",
|
|
3982
|
+
left: "1em",
|
|
3983
|
+
top: "1em",
|
|
3984
|
+
zIndex: 11
|
|
3985
|
+
},
|
|
3986
|
+
padding: 2,
|
|
3987
|
+
border: !0,
|
|
3988
|
+
children: /* @__PURE__ */ jsx(Text, { muted: !0, size: 1, weight: "semibold", style: { color: "var(--card-icon-color)" }, children: "DRM" })
|
|
3989
|
+
}
|
|
3990
|
+
)
|
|
3991
|
+
}
|
|
3992
|
+
),
|
|
3635
3993
|
/* @__PURE__ */ jsxs(
|
|
3636
3994
|
Stack,
|
|
3637
3995
|
{
|
|
@@ -3641,7 +3999,15 @@ function VideoInBrowser({
|
|
|
3641
3999
|
gridTemplateRows: "min-content min-content 1fr"
|
|
3642
4000
|
},
|
|
3643
4001
|
children: [
|
|
3644
|
-
renderVideo
|
|
4002
|
+
renderVideo === "pre-render-warn" && /* @__PURE__ */ jsx(
|
|
4003
|
+
DRMWarningDialog,
|
|
4004
|
+
{
|
|
4005
|
+
onClose: () => {
|
|
4006
|
+
setRenderVideo("render-video");
|
|
4007
|
+
}
|
|
4008
|
+
}
|
|
4009
|
+
),
|
|
4010
|
+
renderVideo === "render-video" ? /* @__PURE__ */ jsx(VideoPlayer, { asset, autoPlay: !0, forceAspectRatio: THUMBNAIL_ASPECT_RATIO }) : /* @__PURE__ */ jsxs(PlayButton, { onClick: onClickPlay, children: [
|
|
3645
4011
|
/* @__PURE__ */ jsx("div", { "data-play": !0, children: /* @__PURE__ */ jsx(PlayIcon, {}) }),
|
|
3646
4012
|
assetIsAudio(asset) ? /* @__PURE__ */ jsx(
|
|
3647
4013
|
"div",
|
|
@@ -3703,12 +4069,12 @@ function VideoInBrowser({
|
|
|
3703
4069
|
}
|
|
3704
4070
|
);
|
|
3705
4071
|
}
|
|
3706
|
-
function VideosBrowser({ onSelect }) {
|
|
4072
|
+
function VideosBrowser({ onSelect, config }) {
|
|
3707
4073
|
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
4074
|
() => assets.find((a2) => a2._id === editedAsset?._id) || editedAsset,
|
|
3709
4075
|
[editedAsset, assets]
|
|
3710
4076
|
), pageStart = page * pageLimit, pageEnd = pageStart + pageLimit;
|
|
3711
|
-
return /* @__PURE__ */ jsxs(
|
|
4077
|
+
return /* @__PURE__ */ jsxs(DrmPlaybackWarningContextProvider, { config, children: [
|
|
3712
4078
|
/* @__PURE__ */ jsxs(Stack, { padding: 4, space: 4, style: { minHeight: "50vh" }, children: [
|
|
3713
4079
|
/* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", children: [
|
|
3714
4080
|
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 3, children: [
|
|
@@ -3722,7 +4088,7 @@ function VideosBrowser({ onSelect }) {
|
|
|
3722
4088
|
}
|
|
3723
4089
|
),
|
|
3724
4090
|
/* @__PURE__ */ jsx(SelectSortOptions, { setSort, sort }),
|
|
3725
|
-
/* @__PURE__ */ jsx(PageSelector, { page, setPage, total: pageTotal
|
|
4091
|
+
/* @__PURE__ */ jsx(PageSelector, { page, setPage, total: pageTotal })
|
|
3726
4092
|
] }),
|
|
3727
4093
|
(onSelect ? "input" : "tool") == "tool" && /* @__PURE__ */ jsxs(Inline, { space: 2, children: [
|
|
3728
4094
|
/* @__PURE__ */ jsx(ImportVideosFromMux, {}),
|
|
@@ -3763,7 +4129,7 @@ function VideosBrowser({ onSelect }) {
|
|
|
3763
4129
|
freshEditedAsset && /* @__PURE__ */ jsx(VideoDetails, { closeDialog: () => setEditedAsset(null), asset: freshEditedAsset })
|
|
3764
4130
|
] });
|
|
3765
4131
|
}
|
|
3766
|
-
const StudioTool = () => /* @__PURE__ */ jsx(VideosBrowser, {}), DEFAULT_TOOL_CONFIG = {
|
|
4132
|
+
const StudioTool = (config) => /* @__PURE__ */ jsx(VideosBrowser, { config }), DEFAULT_TOOL_CONFIG = {
|
|
3767
4133
|
icon: ToolIcon,
|
|
3768
4134
|
title: "Videos"
|
|
3769
4135
|
};
|
|
@@ -4121,6 +4487,9 @@ function isValidUrl(url) {
|
|
|
4121
4487
|
return !1;
|
|
4122
4488
|
}
|
|
4123
4489
|
}
|
|
4490
|
+
function isServerError(error) {
|
|
4491
|
+
return "statusCode" in error && typeof error.statusCode == "number" && 500 <= error.statusCode && error.statusCode <= 600;
|
|
4492
|
+
}
|
|
4124
4493
|
function extractDroppedFiles(dataTransfer) {
|
|
4125
4494
|
const files = Array.from(dataTransfer.files || []), items = Array.from(dataTransfer.items || []);
|
|
4126
4495
|
return files && files.length > 0 ? Promise.resolve(files) : normalizeItems(items).then((arr) => arr.flat());
|
|
@@ -4162,7 +4531,12 @@ function walk(entry) {
|
|
|
4162
4531
|
}
|
|
4163
4532
|
return Promise.resolve([]);
|
|
4164
4533
|
}
|
|
4165
|
-
function SelectAssets({
|
|
4534
|
+
function SelectAssets({
|
|
4535
|
+
asset: selectedAsset,
|
|
4536
|
+
onChange,
|
|
4537
|
+
setDialogState,
|
|
4538
|
+
config
|
|
4539
|
+
}) {
|
|
4166
4540
|
const handleSelect = useCallback(
|
|
4167
4541
|
(chosenAsset) => {
|
|
4168
4542
|
chosenAsset?._id || onChange(PatchEvent.from([unset(["asset"])])), chosenAsset._id !== selectedAsset?._id && onChange(
|
|
@@ -4174,7 +4548,7 @@ function SelectAssets({ asset: selectedAsset, onChange, setDialogState }) {
|
|
|
4174
4548
|
},
|
|
4175
4549
|
[onChange, setDialogState, selectedAsset]
|
|
4176
4550
|
);
|
|
4177
|
-
return /* @__PURE__ */ jsx(VideosBrowser, { onSelect: handleSelect });
|
|
4551
|
+
return /* @__PURE__ */ jsx(VideosBrowser, { onSelect: handleSelect, config });
|
|
4178
4552
|
}
|
|
4179
4553
|
const StyledDialog = styled(Dialog)`
|
|
4180
4554
|
> div[data-ui='DialogCard'] > div[data-ui='Card'] {
|
|
@@ -4184,7 +4558,8 @@ const StyledDialog = styled(Dialog)`
|
|
|
4184
4558
|
function InputBrowser({
|
|
4185
4559
|
setDialogState,
|
|
4186
4560
|
asset,
|
|
4187
|
-
onChange
|
|
4561
|
+
onChange,
|
|
4562
|
+
config
|
|
4188
4563
|
}) {
|
|
4189
4564
|
const id = `InputBrowser${useId()}`, handleClose = useCallback(() => setDialogState(!1), [setDialogState]);
|
|
4190
4565
|
return /* @__PURE__ */ jsx(
|
|
@@ -4195,7 +4570,15 @@ function InputBrowser({
|
|
|
4195
4570
|
id,
|
|
4196
4571
|
onClose: handleClose,
|
|
4197
4572
|
width: 2,
|
|
4198
|
-
children: /* @__PURE__ */ jsx(
|
|
4573
|
+
children: /* @__PURE__ */ jsx(
|
|
4574
|
+
SelectAssets,
|
|
4575
|
+
{
|
|
4576
|
+
config,
|
|
4577
|
+
asset,
|
|
4578
|
+
onChange,
|
|
4579
|
+
setDialogState
|
|
4580
|
+
}
|
|
4581
|
+
)
|
|
4199
4582
|
}
|
|
4200
4583
|
);
|
|
4201
4584
|
}
|
|
@@ -4411,7 +4794,9 @@ const FileButton = styled(MenuItem)(({ theme }) => {
|
|
|
4411
4794
|
color: white;
|
|
4412
4795
|
`, isVideoAsset = (asset) => asset._type === "mux.videoAsset";
|
|
4413
4796
|
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])
|
|
4797
|
+
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), { resyncAsset, isResyncing } = useResyncAsset({ showToast: !0 }), onReset = useCallback(() => onChange(PatchEvent.from(unset([]))), [onChange]), handleResync = useCallback(async () => {
|
|
4798
|
+
setOpen(!1), await resyncAsset(asset);
|
|
4799
|
+
}, [resyncAsset, asset]);
|
|
4415
4800
|
return useEffect(() => {
|
|
4416
4801
|
open && dialogState && setOpen(!1);
|
|
4417
4802
|
}, [dialogState, open]), useClickOutsideEvent(
|
|
@@ -4469,6 +4854,15 @@ function PlayerActionsMenu(props) {
|
|
|
4469
4854
|
text: "Captions",
|
|
4470
4855
|
onClick: () => setDialogState("edit-captions")
|
|
4471
4856
|
}
|
|
4857
|
+
),
|
|
4858
|
+
/* @__PURE__ */ jsx(
|
|
4859
|
+
MenuItem,
|
|
4860
|
+
{
|
|
4861
|
+
icon: SyncIcon,
|
|
4862
|
+
text: "Resync from Mux",
|
|
4863
|
+
onClick: handleResync,
|
|
4864
|
+
disabled: readOnly || isResyncing
|
|
4865
|
+
}
|
|
4472
4866
|
)
|
|
4473
4867
|
] }),
|
|
4474
4868
|
/* @__PURE__ */ jsx(MenuDivider, {}),
|
|
@@ -4512,6 +4906,79 @@ function PlayerActionsMenu(props) {
|
|
|
4512
4906
|
] });
|
|
4513
4907
|
}
|
|
4514
4908
|
var PlayerActionsMenu$1 = memo(PlayerActionsMenu);
|
|
4909
|
+
function useFetchFileSize(stagedUpload, maxFileSize) {
|
|
4910
|
+
const [fileSize, setFileSize] = useState(null), [isLoadingFileSize, setIsLoadingFileSize] = useState(!1), [canSkipFileSizeValidation, setCanSkipFileSizeValidation] = useState(!1);
|
|
4911
|
+
return useEffect(() => {
|
|
4912
|
+
if (stagedUpload.type === "url") {
|
|
4913
|
+
setIsLoadingFileSize(!1), setCanSkipFileSizeValidation(!1), setFileSize(null);
|
|
4914
|
+
const url = stagedUpload.url;
|
|
4915
|
+
(async () => {
|
|
4916
|
+
setIsLoadingFileSize(!0);
|
|
4917
|
+
try {
|
|
4918
|
+
const contentLength = (await fetch(url, { method: "HEAD" })).headers.get("content-length"), newFileSize = contentLength ? parseInt(contentLength, 10) : null;
|
|
4919
|
+
setIsLoadingFileSize(!1), newFileSize && setFileSize(newFileSize), newFileSize === null && maxFileSize !== void 0 && setCanSkipFileSizeValidation(!0);
|
|
4920
|
+
} catch {
|
|
4921
|
+
console.warn("Could not validate file size from URL"), setCanSkipFileSizeValidation(!0), setIsLoadingFileSize(!1);
|
|
4922
|
+
}
|
|
4923
|
+
})();
|
|
4924
|
+
}
|
|
4925
|
+
stagedUpload.type === "file" && setFileSize(stagedUpload.files[0].size);
|
|
4926
|
+
}, [maxFileSize, stagedUpload, stagedUpload.type]), {
|
|
4927
|
+
fileSize,
|
|
4928
|
+
isLoadingFileSize,
|
|
4929
|
+
canSkipFileSizeValidation
|
|
4930
|
+
};
|
|
4931
|
+
}
|
|
4932
|
+
function useMediaMetadata(stagedUpload) {
|
|
4933
|
+
const [videoAssetMetadata, setVideoAssetMetadata] = useState(null), [isLoadingMetadata, setIsLoadingMetadata] = useState(!1);
|
|
4934
|
+
return useEffect(() => {
|
|
4935
|
+
let videoSrc = null;
|
|
4936
|
+
if (stagedUpload.type === "file") {
|
|
4937
|
+
const file = stagedUpload.files[0];
|
|
4938
|
+
videoSrc = URL.createObjectURL(file);
|
|
4939
|
+
}
|
|
4940
|
+
if (stagedUpload.type === "url" && (videoSrc = stagedUpload.url), setVideoAssetMetadata((old) => ({
|
|
4941
|
+
...old,
|
|
4942
|
+
duration: void 0,
|
|
4943
|
+
width: void 0,
|
|
4944
|
+
height: void 0
|
|
4945
|
+
})), !videoSrc) return () => null;
|
|
4946
|
+
setIsLoadingMetadata(!0);
|
|
4947
|
+
const videoElement = document.createElement("video");
|
|
4948
|
+
videoElement.preload = "metadata";
|
|
4949
|
+
const metadataListeners = [
|
|
4950
|
+
() => {
|
|
4951
|
+
setIsLoadingMetadata(!1);
|
|
4952
|
+
},
|
|
4953
|
+
() => {
|
|
4954
|
+
const duration = videoElement.duration, width = videoElement.videoWidth, height = videoElement.videoHeight, isAudioOnly = width <= 0 && height <= 0;
|
|
4955
|
+
setVideoAssetMetadata((old) => ({
|
|
4956
|
+
...old,
|
|
4957
|
+
duration,
|
|
4958
|
+
width,
|
|
4959
|
+
height,
|
|
4960
|
+
isAudioOnly
|
|
4961
|
+
}));
|
|
4962
|
+
}
|
|
4963
|
+
], cleanupVideo = (videoEl) => {
|
|
4964
|
+
const currentVideoSrc = videoEl?.src;
|
|
4965
|
+
videoEl && (metadataListeners.forEach(
|
|
4966
|
+
(listener) => videoEl.removeEventListener("loadedmetadata", listener)
|
|
4967
|
+
), videoEl.onerror = null, videoEl.src = "", videoEl.load()), currentVideoSrc?.startsWith("blob:") && URL.revokeObjectURL(currentVideoSrc);
|
|
4968
|
+
};
|
|
4969
|
+
return metadataListeners.push(() => setTimeout(() => cleanupVideo(videoElement), 0)), videoElement.onerror = () => {
|
|
4970
|
+
setIsLoadingMetadata(!1), console.warn("Could not read video metadata for validation"), cleanupVideo(videoElement);
|
|
4971
|
+
}, metadataListeners.forEach(
|
|
4972
|
+
(listener) => videoElement.addEventListener("loadedmetadata", listener)
|
|
4973
|
+
), videoElement.src = videoSrc, () => {
|
|
4974
|
+
cleanupVideo(videoElement);
|
|
4975
|
+
};
|
|
4976
|
+
}, [stagedUpload.type, stagedUpload]), {
|
|
4977
|
+
videoAssetMetadata,
|
|
4978
|
+
setVideoAssetMetadata,
|
|
4979
|
+
isLoadingMetadata
|
|
4980
|
+
};
|
|
4981
|
+
}
|
|
4515
4982
|
function formatBytes(bytes, si = !1, dp = 1) {
|
|
4516
4983
|
const thresh = si ? 1e3 : 1024;
|
|
4517
4984
|
if (Math.abs(bytes) < thresh)
|
|
@@ -4601,13 +5068,14 @@ function PlaybackPolicyOption({
|
|
|
4601
5068
|
optionName,
|
|
4602
5069
|
description,
|
|
4603
5070
|
dispatch,
|
|
4604
|
-
action
|
|
5071
|
+
action,
|
|
5072
|
+
disabled
|
|
4605
5073
|
}) {
|
|
4606
5074
|
const [scale, setScale] = useState(1), boxStyle = {
|
|
4607
5075
|
outline: "0.01rem solid grey",
|
|
4608
5076
|
transform: `scale(${scale})`,
|
|
4609
5077
|
transition: "transform 0.1s ease-in-out",
|
|
4610
|
-
cursor: "pointer",
|
|
5078
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
4611
5079
|
borderRadius: "0.25rem"
|
|
4612
5080
|
}, triggerAnimation = () => {
|
|
4613
5081
|
setScale(0.98), setTimeout(() => {
|
|
@@ -4615,15 +5083,24 @@ function PlaybackPolicyOption({
|
|
|
4615
5083
|
}, 100);
|
|
4616
5084
|
};
|
|
4617
5085
|
return /* @__PURE__ */ jsx("label", { children: /* @__PURE__ */ jsxs(Flex, { gap: 3, padding: 3, style: boxStyle, children: [
|
|
4618
|
-
/* @__PURE__ */ jsx(
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
5086
|
+
/* @__PURE__ */ jsx(
|
|
5087
|
+
Checkbox,
|
|
5088
|
+
{
|
|
5089
|
+
id,
|
|
5090
|
+
required: !0,
|
|
5091
|
+
checked,
|
|
5092
|
+
onChange: () => {
|
|
5093
|
+
action && (triggerAnimation(), dispatch({
|
|
5094
|
+
action,
|
|
5095
|
+
value: !checked
|
|
5096
|
+
}));
|
|
5097
|
+
},
|
|
5098
|
+
disabled
|
|
5099
|
+
}
|
|
5100
|
+
),
|
|
4624
5101
|
/* @__PURE__ */ jsxs(Grid, { gap: 3, children: [
|
|
4625
5102
|
/* @__PURE__ */ jsx(Text, { size: 3, weight: "bold", children: optionName }),
|
|
4626
|
-
/* @__PURE__ */ jsx(Text, { size: 2, muted: !0, children: description })
|
|
5103
|
+
typeof description == "string" ? /* @__PURE__ */ jsx(Text, { size: 2, muted: !0, children: description }) : description
|
|
4627
5104
|
] })
|
|
4628
5105
|
] }) });
|
|
4629
5106
|
}
|
|
@@ -4648,7 +5125,7 @@ function PlaybackPolicy({
|
|
|
4648
5125
|
secrets,
|
|
4649
5126
|
dispatch
|
|
4650
5127
|
}) {
|
|
4651
|
-
const noPolicySelected = !(config.public_policy || config.signed_policy);
|
|
5128
|
+
const noPolicySelected = !(config.public_policy || config.signed_policy || config.drm_policy), drmPolicyDisabled = !secrets.drmConfigId;
|
|
4652
5129
|
return /* @__PURE__ */ jsxs(Grid, { gap: 3, children: [
|
|
4653
5130
|
/* @__PURE__ */ jsx(Text, { weight: "bold", children: "Advanced Playback Policies" }),
|
|
4654
5131
|
/* @__PURE__ */ jsx(
|
|
@@ -4657,7 +5134,10 @@ function PlaybackPolicy({
|
|
|
4657
5134
|
id: `${id}--public`,
|
|
4658
5135
|
checked: config.public_policy,
|
|
4659
5136
|
optionName: "Public",
|
|
4660
|
-
description:
|
|
5137
|
+
description: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5138
|
+
/* @__PURE__ */ jsx(Text, { size: 2, muted: !0, children: "Playback IDs are accessible by constructing an HLS URL like" }),
|
|
5139
|
+
/* @__PURE__ */ jsx(Code, { children: "https://stream.mux.com/{PLAYBACK_ID}" })
|
|
5140
|
+
] }),
|
|
4661
5141
|
dispatch,
|
|
4662
5142
|
action: "public_policy"
|
|
4663
5143
|
}
|
|
@@ -4668,24 +5148,146 @@ function PlaybackPolicy({
|
|
|
4668
5148
|
id: `${id}--signed`,
|
|
4669
5149
|
checked: config.signed_policy,
|
|
4670
5150
|
optionName: "Signed",
|
|
4671
|
-
description:
|
|
4672
|
-
|
|
5151
|
+
description: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5152
|
+
/* @__PURE__ */ jsx(Text, { size: 2, muted: !0, children: "Playback IDs should be used with tokens" }),
|
|
5153
|
+
/* @__PURE__ */ jsx(Code, { children: "https://stream.mux.com/{PLAYBACK_ID}?token={TOKEN}" }),
|
|
5154
|
+
/* @__PURE__ */ jsxs(Text, { size: 2, muted: !0, children: [
|
|
5155
|
+
"See",
|
|
5156
|
+
" ",
|
|
5157
|
+
/* @__PURE__ */ jsx(
|
|
5158
|
+
"a",
|
|
5159
|
+
{
|
|
5160
|
+
href: "https://www.mux.com/docs/guides/secure-video-playback",
|
|
5161
|
+
target: "_blank",
|
|
5162
|
+
rel: "noopener noreferrer",
|
|
5163
|
+
children: "Secure video playback"
|
|
5164
|
+
}
|
|
5165
|
+
),
|
|
5166
|
+
" ",
|
|
5167
|
+
"for details about creating tokens."
|
|
5168
|
+
] })
|
|
5169
|
+
] }),
|
|
4673
5170
|
dispatch,
|
|
4674
5171
|
action: "signed_policy"
|
|
4675
5172
|
}
|
|
4676
5173
|
),
|
|
5174
|
+
drmPolicyDisabled ? /* @__PURE__ */ jsx(
|
|
5175
|
+
PlaybackPolicyOption,
|
|
5176
|
+
{
|
|
5177
|
+
id: `${id}--drm`,
|
|
5178
|
+
checked: !1,
|
|
5179
|
+
optionName: "DRM - Disabled",
|
|
5180
|
+
description: /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Text, { size: 2, muted: !0, children: [
|
|
5181
|
+
"To enable DRM add your DRM Configuration Id to your plugin configuration in the API Credentials view.",
|
|
5182
|
+
" ",
|
|
5183
|
+
/* @__PURE__ */ jsx(
|
|
5184
|
+
"a",
|
|
5185
|
+
{
|
|
5186
|
+
href: "https://www.mux.com/support/human",
|
|
5187
|
+
target: "_blank",
|
|
5188
|
+
rel: "noopener noreferrer",
|
|
5189
|
+
children: "Contact us"
|
|
5190
|
+
}
|
|
5191
|
+
),
|
|
5192
|
+
" ",
|
|
5193
|
+
"to get started using DRM."
|
|
5194
|
+
] }) }),
|
|
5195
|
+
dispatch,
|
|
5196
|
+
disabled: !0
|
|
5197
|
+
}
|
|
5198
|
+
) : /* @__PURE__ */ jsx(
|
|
5199
|
+
PlaybackPolicyOption,
|
|
5200
|
+
{
|
|
5201
|
+
id: `${id}--drm`,
|
|
5202
|
+
checked: config.drm_policy,
|
|
5203
|
+
optionName: "DRM",
|
|
5204
|
+
description: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5205
|
+
/* @__PURE__ */ jsx(Text, { size: 2, muted: !0, children: "Playback IDs should be used with tokens as with Signed playback, but require extra configuration." }),
|
|
5206
|
+
/* @__PURE__ */ jsx(Code, { children: "https://stream.mux.com/{PLAYBACK_ID}?token={TOKEN}" }),
|
|
5207
|
+
/* @__PURE__ */ jsxs(Text, { size: 2, muted: !0, children: [
|
|
5208
|
+
"See",
|
|
5209
|
+
" ",
|
|
5210
|
+
/* @__PURE__ */ jsx(
|
|
5211
|
+
"a",
|
|
5212
|
+
{
|
|
5213
|
+
href: "https://www.mux.com/docs/guides/protect-videos-with-drm#play-drm-protected-videos",
|
|
5214
|
+
target: "_blank",
|
|
5215
|
+
rel: "noopener noreferrer",
|
|
5216
|
+
children: "Protect videos with DRM"
|
|
5217
|
+
}
|
|
5218
|
+
),
|
|
5219
|
+
" ",
|
|
5220
|
+
"for details about configuring your player for DRM playback and",
|
|
5221
|
+
" ",
|
|
5222
|
+
/* @__PURE__ */ jsx(
|
|
5223
|
+
"a",
|
|
5224
|
+
{
|
|
5225
|
+
href: "https://www.mux.com/docs/guides/secure-video-playback",
|
|
5226
|
+
target: "_blank",
|
|
5227
|
+
rel: "noopener noreferrer",
|
|
5228
|
+
children: "Secure video playback"
|
|
5229
|
+
}
|
|
5230
|
+
),
|
|
5231
|
+
" ",
|
|
5232
|
+
"for details about creating tokens."
|
|
5233
|
+
] })
|
|
5234
|
+
] }),
|
|
5235
|
+
dispatch,
|
|
5236
|
+
action: "drm_policy"
|
|
5237
|
+
}
|
|
5238
|
+
),
|
|
4677
5239
|
noPolicySelected && /* @__PURE__ */ jsx(PlaybackPolicyWarning, {})
|
|
4678
5240
|
] });
|
|
4679
5241
|
}
|
|
4680
|
-
const
|
|
4681
|
-
{ value: "basic", label: "Basic" },
|
|
4682
|
-
{ value: "plus", label: "Plus" },
|
|
4683
|
-
{ value: "premium", label: "Premium" }
|
|
4684
|
-
], RESOLUTION_TIERS = [
|
|
5242
|
+
const RESOLUTION_TIERS = [
|
|
4685
5243
|
{ value: "1080p", label: "1080p" },
|
|
4686
5244
|
{ value: "1440p", label: "1440p (2k)" },
|
|
4687
5245
|
{ value: "2160p", label: "2160p (4k)" }
|
|
4688
|
-
],
|
|
5246
|
+
], ResolutionTierSelector = ({
|
|
5247
|
+
id,
|
|
5248
|
+
config,
|
|
5249
|
+
dispatch,
|
|
5250
|
+
maxSupportedResolution
|
|
5251
|
+
}) => /* @__PURE__ */ jsx(
|
|
5252
|
+
FormField$2,
|
|
5253
|
+
{
|
|
5254
|
+
title: "Resolution Tier",
|
|
5255
|
+
description: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5256
|
+
"The maximum",
|
|
5257
|
+
" ",
|
|
5258
|
+
/* @__PURE__ */ jsx(
|
|
5259
|
+
"a",
|
|
5260
|
+
{
|
|
5261
|
+
href: "https://docs.mux.com/api-reference#video/operation/create-direct-upload",
|
|
5262
|
+
target: "_blank",
|
|
5263
|
+
rel: "noopener noreferrer",
|
|
5264
|
+
children: "resolution_tier"
|
|
5265
|
+
}
|
|
5266
|
+
),
|
|
5267
|
+
" ",
|
|
5268
|
+
"your asset is encoded, stored, and streamed at."
|
|
5269
|
+
] }),
|
|
5270
|
+
children: /* @__PURE__ */ jsx(Flex, { gap: 3, wrap: "wrap", children: RESOLUTION_TIERS.map(({ value, label }, index) => {
|
|
5271
|
+
const inputId = `${id}--type-${value}`;
|
|
5272
|
+
return index > maxSupportedResolution ? null : /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
5273
|
+
/* @__PURE__ */ jsx(
|
|
5274
|
+
Radio,
|
|
5275
|
+
{
|
|
5276
|
+
checked: config.max_resolution_tier === value,
|
|
5277
|
+
name: "asset-resolutiontier",
|
|
5278
|
+
onChange: (e) => dispatch({
|
|
5279
|
+
action: "max_resolution_tier",
|
|
5280
|
+
value: e.currentTarget.value
|
|
5281
|
+
}),
|
|
5282
|
+
value,
|
|
5283
|
+
id: inputId
|
|
5284
|
+
}
|
|
5285
|
+
),
|
|
5286
|
+
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: inputId, children: label })
|
|
5287
|
+
] }, value);
|
|
5288
|
+
}) })
|
|
5289
|
+
}
|
|
5290
|
+
), ADVANCED_RESOLUTIONS = [
|
|
4689
5291
|
{ value: "270p", label: "270p" },
|
|
4690
5292
|
{ value: "360p", label: "360p" },
|
|
4691
5293
|
{ value: "480p", label: "480p" },
|
|
@@ -4694,6 +5296,130 @@ const VIDEO_QUALITY_LEVELS = [
|
|
|
4694
5296
|
{ value: "1080p", label: "1080p" },
|
|
4695
5297
|
{ value: "1440p", label: "1440p" },
|
|
4696
5298
|
{ value: "2160p", label: "2160p" }
|
|
5299
|
+
], StaticRenditionSelector = ({
|
|
5300
|
+
id,
|
|
5301
|
+
config,
|
|
5302
|
+
dispatch
|
|
5303
|
+
}) => {
|
|
5304
|
+
const isAdvancedMode = useMemo(() => config.static_renditions.filter(
|
|
5305
|
+
(r) => r !== "highest" && r !== "audio-only"
|
|
5306
|
+
).length > 0, [config.static_renditions]), [renditionMode, setRenditionMode] = useState(
|
|
5307
|
+
isAdvancedMode ? "advanced" : "standard"
|
|
5308
|
+
), toggleRendition = (rendition) => {
|
|
5309
|
+
const current = config.static_renditions, hasRendition = current.includes(rendition);
|
|
5310
|
+
dispatch(hasRendition ? {
|
|
5311
|
+
action: "static_renditions",
|
|
5312
|
+
value: current.filter((r) => r !== rendition)
|
|
5313
|
+
} : {
|
|
5314
|
+
action: "static_renditions",
|
|
5315
|
+
value: [...current, rendition]
|
|
5316
|
+
});
|
|
5317
|
+
}, handleModeChange = (mode) => {
|
|
5318
|
+
setRenditionMode(mode), dispatch(mode === "standard" ? {
|
|
5319
|
+
action: "static_renditions",
|
|
5320
|
+
value: config.static_renditions.filter((r) => r === "highest" || r === "audio-only")
|
|
5321
|
+
} : {
|
|
5322
|
+
action: "static_renditions",
|
|
5323
|
+
value: config.static_renditions.filter((r) => r !== "highest")
|
|
5324
|
+
});
|
|
5325
|
+
};
|
|
5326
|
+
return /* @__PURE__ */ jsx(Stack, { space: 3, children: /* @__PURE__ */ jsx(
|
|
5327
|
+
FormField$2,
|
|
5328
|
+
{
|
|
5329
|
+
title: "Static Renditions",
|
|
5330
|
+
description: "Generate downloadable MP4 or M4A files. Note: Mux will not upscale to produce MP4 renditions - renditions that would cause upscaling are skipped.",
|
|
5331
|
+
children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
5332
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 3, children: [
|
|
5333
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
5334
|
+
/* @__PURE__ */ jsx(
|
|
5335
|
+
Radio,
|
|
5336
|
+
{
|
|
5337
|
+
checked: renditionMode === "standard",
|
|
5338
|
+
name: "rendition-mode",
|
|
5339
|
+
onChange: () => handleModeChange("standard"),
|
|
5340
|
+
value: "standard",
|
|
5341
|
+
id: `${id}--mode-standard`
|
|
5342
|
+
}
|
|
5343
|
+
),
|
|
5344
|
+
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: `${id}--mode-standard`, children: "Standard" })
|
|
5345
|
+
] }),
|
|
5346
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
5347
|
+
/* @__PURE__ */ jsx(
|
|
5348
|
+
Radio,
|
|
5349
|
+
{
|
|
5350
|
+
checked: renditionMode === "advanced",
|
|
5351
|
+
name: "rendition-mode",
|
|
5352
|
+
onChange: () => handleModeChange("advanced"),
|
|
5353
|
+
value: "advanced",
|
|
5354
|
+
id: `${id}--mode-advanced`
|
|
5355
|
+
}
|
|
5356
|
+
),
|
|
5357
|
+
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: `${id}--mode-advanced`, children: "Advanced" })
|
|
5358
|
+
] })
|
|
5359
|
+
] }),
|
|
5360
|
+
renditionMode === "standard" && /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
5361
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, padding: [0, 2], children: [
|
|
5362
|
+
/* @__PURE__ */ jsx(
|
|
5363
|
+
Checkbox,
|
|
5364
|
+
{
|
|
5365
|
+
id: `${id}--highest`,
|
|
5366
|
+
style: { display: "block" },
|
|
5367
|
+
checked: config.static_renditions.includes("highest"),
|
|
5368
|
+
onChange: () => toggleRendition("highest")
|
|
5369
|
+
}
|
|
5370
|
+
),
|
|
5371
|
+
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: `${id}--highest`, children: "Highest Resolution (up to 4K)" })
|
|
5372
|
+
] }),
|
|
5373
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, padding: [0, 2], children: [
|
|
5374
|
+
/* @__PURE__ */ jsx(
|
|
5375
|
+
Checkbox,
|
|
5376
|
+
{
|
|
5377
|
+
id: `${id}--audio-only-standard`,
|
|
5378
|
+
style: { display: "block" },
|
|
5379
|
+
checked: config.static_renditions.includes("audio-only"),
|
|
5380
|
+
onChange: () => toggleRendition("audio-only")
|
|
5381
|
+
}
|
|
5382
|
+
),
|
|
5383
|
+
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: `${id}--audio-only-standard`, children: "Audio Only (M4A)" })
|
|
5384
|
+
] })
|
|
5385
|
+
] }),
|
|
5386
|
+
renditionMode === "advanced" && /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
5387
|
+
/* @__PURE__ */ jsx(Label$1, { size: 1, muted: !0, children: "Select specific resolutions:" }),
|
|
5388
|
+
/* @__PURE__ */ jsx(Flex, { gap: 2, wrap: "wrap", children: ADVANCED_RESOLUTIONS.map(({ value, label }) => {
|
|
5389
|
+
const inputId = `${id}--resolution-${value}`;
|
|
5390
|
+
return /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
5391
|
+
/* @__PURE__ */ jsx(
|
|
5392
|
+
Checkbox,
|
|
5393
|
+
{
|
|
5394
|
+
id: inputId,
|
|
5395
|
+
style: { display: "block" },
|
|
5396
|
+
checked: config.static_renditions.includes(value),
|
|
5397
|
+
onChange: () => toggleRendition(value)
|
|
5398
|
+
}
|
|
5399
|
+
),
|
|
5400
|
+
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: inputId, size: 1, children: label })
|
|
5401
|
+
] }, value);
|
|
5402
|
+
}) }),
|
|
5403
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, padding: [2, 2, 0, 2], children: [
|
|
5404
|
+
/* @__PURE__ */ jsx(
|
|
5405
|
+
Checkbox,
|
|
5406
|
+
{
|
|
5407
|
+
id: `${id}--audio-only-advanced`,
|
|
5408
|
+
style: { display: "block" },
|
|
5409
|
+
checked: config.static_renditions.includes("audio-only"),
|
|
5410
|
+
onChange: () => toggleRendition("audio-only")
|
|
5411
|
+
}
|
|
5412
|
+
),
|
|
5413
|
+
/* @__PURE__ */ jsx(Text, { as: "label", htmlFor: `${id}--audio-only-advanced`, children: "Audio Only (M4A)" })
|
|
5414
|
+
] })
|
|
5415
|
+
] })
|
|
5416
|
+
] })
|
|
5417
|
+
}
|
|
5418
|
+
) });
|
|
5419
|
+
}, VIDEO_QUALITY_LEVELS = [
|
|
5420
|
+
{ value: "basic", label: "Basic" },
|
|
5421
|
+
{ value: "plus", label: "Plus" },
|
|
5422
|
+
{ value: "premium", label: "Premium" }
|
|
4697
5423
|
];
|
|
4698
5424
|
function sanitizeStaticRenditions(renditions) {
|
|
4699
5425
|
const hasHighest = renditions.includes("highest"), hasSpecificResolutions = renditions.some((r) => r !== "highest" && r !== "audio-only");
|
|
@@ -4725,7 +5451,8 @@ function UploadConfiguration({
|
|
|
4725
5451
|
max_resolution_tier: "1080p",
|
|
4726
5452
|
text_tracks: prev.text_tracks?.filter(({ type }) => type !== "autogenerated"),
|
|
4727
5453
|
public_policy: !0,
|
|
4728
|
-
signed_policy: !1
|
|
5454
|
+
signed_policy: !1,
|
|
5455
|
+
drm_policy: !1
|
|
4729
5456
|
}) : Object.assign({}, prev, {
|
|
4730
5457
|
video_quality: action.value,
|
|
4731
5458
|
static_renditions: sanitizeStaticRenditions(pluginConfig.static_renditions || []),
|
|
@@ -4739,6 +5466,8 @@ function UploadConfiguration({
|
|
|
4739
5466
|
return Object.assign({}, prev, { [action.action]: action.value });
|
|
4740
5467
|
case "public_policy":
|
|
4741
5468
|
return Object.assign({}, prev, { [action.action]: action.value });
|
|
5469
|
+
case "drm_policy":
|
|
5470
|
+
return Object.assign({}, prev, { [action.action]: action.value });
|
|
4742
5471
|
// Updating individual tracks
|
|
4743
5472
|
case "track": {
|
|
4744
5473
|
const text_tracks = [...prev.text_tracks], target_track_i = text_tracks.findIndex(({ _id: _id2 }) => _id2 === action.id);
|
|
@@ -4774,75 +5503,41 @@ function UploadConfiguration({
|
|
|
4774
5503
|
static_renditions: sanitizeStaticRenditions(pluginConfig.static_renditions || []),
|
|
4775
5504
|
signed_policy: secrets.enableSignedUrls && pluginConfig.defaultSigned,
|
|
4776
5505
|
public_policy: pluginConfig.defaultPublic,
|
|
5506
|
+
drm_policy: pluginConfig.defaultDrm && !!secrets.drmConfigId,
|
|
4777
5507
|
normalize_audio: pluginConfig.normalize_audio,
|
|
4778
5508
|
text_tracks: autoTextTracks
|
|
4779
5509
|
}
|
|
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;
|
|
5510
|
+
), [validationError, setValidationError] = useState(null), MAX_FILE_SIZE = pluginConfig.maxAssetFileSize, MAX_DURATION_SECONDS = pluginConfig.maxAssetDuration, { fileSize, isLoadingFileSize, canSkipFileSizeValidation } = useFetchFileSize(
|
|
5511
|
+
stagedUpload,
|
|
5512
|
+
MAX_FILE_SIZE
|
|
5513
|
+
), { videoAssetMetadata, setVideoAssetMetadata, isLoadingMetadata } = useMediaMetadata(stagedUpload);
|
|
4785
5514
|
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(
|
|
5515
|
+
fileSize && setVideoAssetMetadata((old) => ({ ...old, size: fileSize }));
|
|
5516
|
+
}, [fileSize, setVideoAssetMetadata]), useEffect(() => {
|
|
5517
|
+
const validateDuration = (duration) => MAX_DURATION_SECONDS && duration > MAX_DURATION_SECONDS ? (setValidationError(
|
|
5518
|
+
`Video duration (${formatSeconds(duration)}) exceeds maximum allowed duration of ${formatSeconds(MAX_DURATION_SECONDS)}`
|
|
5519
|
+
), !1) : !0, validateFileSize = (size) => MAX_FILE_SIZE === void 0 || size <= MAX_FILE_SIZE ? !0 : (setValidationError(
|
|
4800
5520
|
`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;
|
|
5521
|
+
), !1), validateDrmAvailability = (isAudioOnly) => config.drm_policy && isAudioOnly ? (setValidationError("Audio-only asset cannot be DRM protected"), !1) : !0;
|
|
5522
|
+
let valid = !0;
|
|
5523
|
+
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);
|
|
5524
|
+
}, [
|
|
5525
|
+
MAX_FILE_SIZE,
|
|
5526
|
+
MAX_DURATION_SECONDS,
|
|
5527
|
+
canSkipFileSizeValidation,
|
|
5528
|
+
videoAssetMetadata?.duration,
|
|
5529
|
+
videoAssetMetadata?.size,
|
|
5530
|
+
videoAssetMetadata?.height,
|
|
5531
|
+
videoAssetMetadata?.width,
|
|
5532
|
+
videoAssetMetadata,
|
|
5533
|
+
config.drm_policy,
|
|
5534
|
+
validationError
|
|
5535
|
+
]);
|
|
5536
|
+
const { disableTextTrackConfig, disableUploadConfig } = pluginConfig, skipConfig = disableTextTrackConfig && disableUploadConfig;
|
|
4842
5537
|
if (useEffect(() => {
|
|
4843
|
-
skipConfig && startUpload(formatUploadConfig(config));
|
|
5538
|
+
skipConfig && startUpload(formatUploadConfig(config, secrets));
|
|
4844
5539
|
}, []), skipConfig) return null;
|
|
4845
|
-
const basicConfig = config.video_quality !== "plus" && config.video_quality !== "premium", maxSupportedResolution = RESOLUTION_TIERS.findIndex(
|
|
5540
|
+
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
5541
|
(rt) => rt.value === pluginConfig.max_resolution_tier
|
|
4847
5542
|
);
|
|
4848
5543
|
return /* @__PURE__ */ jsx(
|
|
@@ -4876,12 +5571,12 @@ function UploadConfiguration({
|
|
|
4876
5571
|
/* @__PURE__ */ jsx(DocumentVideoIcon, { fontSize: "2em" }),
|
|
4877
5572
|
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
4878
5573
|
/* @__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)})` :
|
|
5574
|
+
/* @__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
5575
|
stagedUpload.type === "file" && /* @__PURE__ */ jsxs(Stack, { space: 1, children: [
|
|
4881
|
-
|
|
4882
|
-
|
|
5576
|
+
isLoadingMetadata && /* @__PURE__ */ jsx(Text, { as: "p", size: 1, muted: !0, children: "Reading video metadata..." }),
|
|
5577
|
+
videoAssetMetadata?.duration && !validationError && /* @__PURE__ */ jsxs(Text, { as: "p", size: 1, muted: !0, children: [
|
|
4883
5578
|
"Duration: ",
|
|
4884
|
-
formatSeconds(
|
|
5579
|
+
formatSeconds(videoAssetMetadata.duration)
|
|
4885
5580
|
] })
|
|
4886
5581
|
] })
|
|
4887
5582
|
] })
|
|
@@ -4927,160 +5622,37 @@ function UploadConfiguration({
|
|
|
4927
5622
|
}) })
|
|
4928
5623
|
}
|
|
4929
5624
|
),
|
|
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
5625
|
!basicConfig && /* @__PURE__ */ jsx(FormField$2, { title: "Additional Configuration", children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
4971
5626
|
/* @__PURE__ */ jsx(PlaybackPolicy, { id, config, secrets, dispatch }),
|
|
4972
|
-
|
|
4973
|
-
|
|
5627
|
+
maxSupportedResolution > 0 && /* @__PURE__ */ jsx(
|
|
5628
|
+
ResolutionTierSelector,
|
|
4974
5629
|
{
|
|
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
|
-
] })
|
|
5630
|
+
id,
|
|
5631
|
+
config,
|
|
5632
|
+
dispatch,
|
|
5633
|
+
maxSupportedResolution
|
|
5063
5634
|
}
|
|
5064
|
-
)
|
|
5635
|
+
),
|
|
5636
|
+
/* @__PURE__ */ jsx(StaticRenditionSelector, { id, config, dispatch }),
|
|
5637
|
+
!disableTextTrackConfig && /* @__PURE__ */ jsx(
|
|
5638
|
+
TextTracksEditor,
|
|
5639
|
+
{
|
|
5640
|
+
tracks: config.text_tracks,
|
|
5641
|
+
dispatch,
|
|
5642
|
+
defaultLang: pluginConfig.defaultAutogeneratedSubtitleLang
|
|
5643
|
+
}
|
|
5644
|
+
)
|
|
5065
5645
|
] }) })
|
|
5066
5646
|
] }),
|
|
5067
|
-
!disableTextTrackConfig && !basicConfig && /* @__PURE__ */ jsx(
|
|
5068
|
-
TextTracksEditor,
|
|
5069
|
-
{
|
|
5070
|
-
tracks: config.text_tracks,
|
|
5071
|
-
dispatch,
|
|
5072
|
-
defaultLang: pluginConfig.defaultAutogeneratedSubtitleLang
|
|
5073
|
-
}
|
|
5074
|
-
),
|
|
5075
5647
|
/* @__PURE__ */ jsx(Box, { marginTop: 4, children: /* @__PURE__ */ jsx(
|
|
5076
5648
|
Button,
|
|
5077
5649
|
{
|
|
5078
|
-
disabled: !basicConfig && !
|
|
5650
|
+
disabled: !basicConfig && !playbackPolicySelected || validationError !== null || isLoadingMetadata || isLoadingFileSize && !canSkipFileSizeValidation,
|
|
5079
5651
|
icon: UploadIcon,
|
|
5080
5652
|
text: "Upload",
|
|
5081
5653
|
tone: "positive",
|
|
5082
5654
|
onClick: () => {
|
|
5083
|
-
validationError || startUpload(formatUploadConfig(config));
|
|
5655
|
+
validationError || startUpload(formatUploadConfig(config, secrets));
|
|
5084
5656
|
}
|
|
5085
5657
|
}
|
|
5086
5658
|
) })
|
|
@@ -5088,11 +5660,14 @@ function UploadConfiguration({
|
|
|
5088
5660
|
}
|
|
5089
5661
|
);
|
|
5090
5662
|
}
|
|
5091
|
-
function
|
|
5092
|
-
const
|
|
5093
|
-
return config.public_policy &&
|
|
5663
|
+
function setAdvancedPlaybackPolicy(config, secrets) {
|
|
5664
|
+
const advanced_playback_policies = [];
|
|
5665
|
+
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({
|
|
5666
|
+
policy: "drm",
|
|
5667
|
+
drm_configuration_id: secrets.drmConfigId ?? void 0
|
|
5668
|
+
}) : console.error("Selected DRM Policy but missing DRM Configuration Id")), advanced_playback_policies;
|
|
5094
5669
|
}
|
|
5095
|
-
function formatUploadConfig(config) {
|
|
5670
|
+
function formatUploadConfig(config, secrets) {
|
|
5096
5671
|
const generated_subtitles = config.text_tracks.filter(isAutogeneratedTrack).map((track) => ({
|
|
5097
5672
|
name: track.name,
|
|
5098
5673
|
language_code: track.language_code
|
|
@@ -5116,7 +5691,7 @@ function formatUploadConfig(config) {
|
|
|
5116
5691
|
)
|
|
5117
5692
|
],
|
|
5118
5693
|
static_renditions: config.static_renditions.length > 0 ? config.static_renditions.map((resolution) => ({ resolution })) : void 0,
|
|
5119
|
-
|
|
5694
|
+
advanced_playback_policies: setAdvancedPlaybackPolicy(config, secrets),
|
|
5120
5695
|
max_resolution_tier: config.max_resolution_tier,
|
|
5121
5696
|
video_quality: config.video_quality,
|
|
5122
5697
|
normalize_audio: config.normalize_audio
|
|
@@ -5328,8 +5903,13 @@ function Uploader(props) {
|
|
|
5328
5903
|
case "reset":
|
|
5329
5904
|
case "complete":
|
|
5330
5905
|
return uploadRef.current?.unsubscribe(), uploadRef.current = null, uploadingDocumentId.current = null, INITIAL_STATE;
|
|
5331
|
-
case "error":
|
|
5332
|
-
|
|
5906
|
+
case "error": {
|
|
5907
|
+
uploadRef.current?.unsubscribe(), uploadRef.current = null, uploadingDocumentId.current = null;
|
|
5908
|
+
let error = action.error;
|
|
5909
|
+
return isServerError(action.error) && hasPlaybackPolicy(action.settings, "drm") && (error = new Error(
|
|
5910
|
+
"Unknown Error while uploading DRM protected content. Make sure your DRM configuration ID is valid and set correctly"
|
|
5911
|
+
)), Object.assign({}, INITIAL_STATE, { error });
|
|
5912
|
+
}
|
|
5333
5913
|
default:
|
|
5334
5914
|
return prev;
|
|
5335
5915
|
}
|
|
@@ -5408,7 +5988,7 @@ function Uploader(props) {
|
|
|
5408
5988
|
}
|
|
5409
5989
|
},
|
|
5410
5990
|
complete: () => dispatch({ action: "complete" }),
|
|
5411
|
-
error: (error) => dispatch({ action: "error", error })
|
|
5991
|
+
error: (error) => dispatch({ action: "error", error, settings })
|
|
5412
5992
|
});
|
|
5413
5993
|
}, invalidFileToast = useCallback(() => {
|
|
5414
5994
|
toast.push({
|
|
@@ -5459,11 +6039,11 @@ function Uploader(props) {
|
|
|
5459
6039
|
idx > -1 && dragEnteredEls.current.splice(idx, 1), dragEnteredEls.current.length === 0 && setDragState(null);
|
|
5460
6040
|
};
|
|
5461
6041
|
if (state.error !== null) {
|
|
5462
|
-
const error =
|
|
6042
|
+
const error = state.error;
|
|
5463
6043
|
return /* @__PURE__ */ jsxs(Flex, { gap: 3, direction: "column", justify: "center", align: "center", children: [
|
|
5464
6044
|
/* @__PURE__ */ jsx(Text, { size: 5, muted: !0, children: /* @__PURE__ */ jsx(ErrorOutlineIcon, {}) }),
|
|
5465
6045
|
/* @__PURE__ */ jsx(Text, { children: "Something went wrong" }),
|
|
5466
|
-
error instanceof Error && error.message && /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: error.message }),
|
|
6046
|
+
error instanceof Error && error.message && /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, weight: "semibold", style: { textAlign: "center" }, children: error.message }),
|
|
5467
6047
|
/* @__PURE__ */ jsx(Button, { text: "Upload another file", onClick: () => dispatch({ action: "reset" }) })
|
|
5468
6048
|
] });
|
|
5469
6049
|
}
|
|
@@ -5548,6 +6128,7 @@ function Uploader(props) {
|
|
|
5548
6128
|
props.dialogState === "select-video" && /* @__PURE__ */ jsx(
|
|
5549
6129
|
InputBrowser,
|
|
5550
6130
|
{
|
|
6131
|
+
config: props.config,
|
|
5551
6132
|
asset: props.asset,
|
|
5552
6133
|
onChange: props.onChange,
|
|
5553
6134
|
setDialogState: props.setDialogState
|
|
@@ -5632,7 +6213,12 @@ const muxVideoSchema = {
|
|
|
5632
6213
|
{ type: "number", name: "max_width" },
|
|
5633
6214
|
{ type: "number", name: "max_frame_rate" },
|
|
5634
6215
|
{ type: "number", name: "duration" },
|
|
5635
|
-
{ type: "number", name: "max_height" }
|
|
6216
|
+
{ type: "number", name: "max_height" },
|
|
6217
|
+
{ type: "string", name: "language_code" },
|
|
6218
|
+
{ type: "string", name: "name" },
|
|
6219
|
+
{ type: "string", name: "status" },
|
|
6220
|
+
{ type: "string", name: "text_source" },
|
|
6221
|
+
{ type: "string", name: "text_type" }
|
|
5636
6222
|
]
|
|
5637
6223
|
}, muxPlaybackId = {
|
|
5638
6224
|
name: "mux.playbackId",
|
|
@@ -5794,6 +6380,7 @@ const muxVideoSchema = {
|
|
|
5794
6380
|
normalize_audio: !1,
|
|
5795
6381
|
defaultPublic: !0,
|
|
5796
6382
|
defaultSigned: !1,
|
|
6383
|
+
defaultDrm: !1,
|
|
5797
6384
|
tool: DEFAULT_TOOL_CONFIG,
|
|
5798
6385
|
allowedRolesForConfiguration: [],
|
|
5799
6386
|
acceptedMimeTypes: ["video/*", "audio/*"]
|