sanity-plugin-mux-input 2.11.2 → 2.12.1
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 +49 -5
- package/dist/index.d.mts +36 -2
- package/dist/index.d.ts +36 -2
- package/dist/index.js +169 -34
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +169 -34
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/_exports/index.ts +26 -2
- package/src/actions/upload.ts +1 -1
- package/src/components/Player.tsx +14 -5
- package/src/components/UploadConfiguration.tsx +190 -30
- package/src/hooks/useMuxPolling.ts +20 -4
- package/src/schema.ts +9 -3
- package/src/util/types.ts +47 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sanity-plugin-mux-input",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.1",
|
|
4
4
|
"description": "An input component that integrates Sanity Studio with Mux video encoding/hosting service.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
91
91
|
"husky": "^9.0.11",
|
|
92
92
|
"lint-staged": "^15.2.2",
|
|
93
|
-
"npm-run-all2": "^
|
|
93
|
+
"npm-run-all2": "^6.2.6",
|
|
94
94
|
"prettier": "^3.5.2",
|
|
95
95
|
"prettier-plugin-packagejson": "^2.5.9",
|
|
96
96
|
"react": "^19.0.0",
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"peerDependencies": {
|
|
105
105
|
"react": "^18.3 || ^19",
|
|
106
106
|
"react-is": "^18.3 || ^19",
|
|
107
|
-
"sanity": "^3.42.0 || ^4.0.0-0",
|
|
107
|
+
"sanity": "^3.42.0 || ^4.0.0-0 || ^5.0.0",
|
|
108
108
|
"styled-components": "^5 || ^6"
|
|
109
109
|
},
|
|
110
110
|
"engines": {
|
package/src/_exports/index.ts
CHANGED
|
@@ -3,10 +3,11 @@ import {definePlugin} from 'sanity'
|
|
|
3
3
|
import createStudioTool, {DEFAULT_TOOL_CONFIG} from '../components/StudioTool'
|
|
4
4
|
import {muxVideoCustomRendering} from '../plugin'
|
|
5
5
|
import {muxVideoSchema, schemaTypes} from '../schema'
|
|
6
|
-
import type {PluginConfig} from '../util/types'
|
|
6
|
+
import type {PluginConfig, StaticRenditionResolution} from '../util/types'
|
|
7
7
|
export type {VideoAssetDocument} from '../util/types'
|
|
8
8
|
|
|
9
9
|
export const defaultConfig: PluginConfig = {
|
|
10
|
+
static_renditions: [],
|
|
10
11
|
mp4_support: 'none',
|
|
11
12
|
video_quality: 'plus',
|
|
12
13
|
max_resolution_tier: '1080p',
|
|
@@ -17,6 +18,25 @@ export const defaultConfig: PluginConfig = {
|
|
|
17
18
|
allowedRolesForConfiguration: [],
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Converts legacy mp4_support configuration to static_renditions format
|
|
23
|
+
*/
|
|
24
|
+
function convertLegacyConfig(config: Partial<PluginConfig>): {
|
|
25
|
+
static_renditions: StaticRenditionResolution[]
|
|
26
|
+
} {
|
|
27
|
+
// If static_renditions is already provided, use it
|
|
28
|
+
if (config.static_renditions && config.static_renditions.length > 0) {
|
|
29
|
+
return {static_renditions: config.static_renditions}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Convert legacy mp4_support to static_renditions
|
|
33
|
+
if (config.mp4_support === 'standard') {
|
|
34
|
+
return {static_renditions: ['highest']}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {static_renditions: []}
|
|
38
|
+
}
|
|
39
|
+
|
|
20
40
|
export const muxInput = definePlugin<Partial<PluginConfig> | void>((userConfig) => {
|
|
21
41
|
// TODO: Remove this on next major version when we end support for encoding_tier
|
|
22
42
|
if (typeof userConfig === 'object' && 'encoding_tier' in userConfig) {
|
|
@@ -30,7 +50,11 @@ export const muxInput = definePlugin<Partial<PluginConfig> | void>((userConfig)
|
|
|
30
50
|
}
|
|
31
51
|
}
|
|
32
52
|
}
|
|
33
|
-
const config: PluginConfig = {
|
|
53
|
+
const config: PluginConfig = {
|
|
54
|
+
...defaultConfig,
|
|
55
|
+
...(userConfig || {}),
|
|
56
|
+
...convertLegacyConfig(userConfig || {}),
|
|
57
|
+
}
|
|
34
58
|
return {
|
|
35
59
|
name: 'mux-input',
|
|
36
60
|
schema: {
|
package/src/actions/upload.ts
CHANGED
|
@@ -33,14 +33,23 @@ const Player = ({asset, buttons, readOnly, onChange}: Props) => {
|
|
|
33
33
|
return true
|
|
34
34
|
}, [asset])
|
|
35
35
|
const isPreparingStaticRenditions = useMemo<boolean>(() => {
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
// Legacy: If static_renditions has a status field, it was created with mp4_support (deprecated)
|
|
37
|
+
// We don't process this old format, just return false
|
|
38
|
+
// Note: 'disabled' status is valid in the new format when no renditions were requested
|
|
39
|
+
if (
|
|
40
|
+
asset?.data?.static_renditions?.status &&
|
|
41
|
+
asset?.data?.static_renditions?.status !== 'disabled'
|
|
42
|
+
) {
|
|
43
|
+
return false
|
|
38
44
|
}
|
|
39
|
-
|
|
45
|
+
|
|
46
|
+
// Check if any file in static_renditions is still preparing
|
|
47
|
+
const files = asset?.data?.static_renditions?.files
|
|
48
|
+
if (!files || files.length === 0) {
|
|
40
49
|
return false
|
|
41
50
|
}
|
|
42
|
-
return
|
|
43
|
-
}, [asset?.data?.static_renditions?.status])
|
|
51
|
+
return files.some((file) => file.status === 'preparing')
|
|
52
|
+
}, [asset?.data?.static_renditions?.status, asset?.data?.static_renditions?.files])
|
|
44
53
|
const playRef = useRef<HTMLDivElement>(null)
|
|
45
54
|
const muteRef = useRef<HTMLDivElement>(null)
|
|
46
55
|
const handleCancelUpload = useCancelUpload(asset, onChange)
|
|
@@ -2,7 +2,7 @@ import {DocumentVideoIcon, UploadIcon} from '@sanity/icons'
|
|
|
2
2
|
import {Box, Button, Card, Checkbox, Dialog, Flex, Label, Radio, Stack, Text} from '@sanity/ui'
|
|
3
3
|
import {uuid} from '@sanity/uuid'
|
|
4
4
|
import LanguagesList from 'iso-639-1'
|
|
5
|
-
import {useEffect, useId, useReducer, useRef} from 'react'
|
|
5
|
+
import {useEffect, useId, useMemo, useReducer, useRef, useState} from 'react'
|
|
6
6
|
import {FormField} from 'sanity'
|
|
7
7
|
|
|
8
8
|
import formatBytes from '../util/formatBytes'
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
type MuxNewAssetSettings,
|
|
15
15
|
type PluginConfig,
|
|
16
16
|
type Secrets,
|
|
17
|
+
type StaticRenditionResolution,
|
|
17
18
|
type SupportedMuxLanguage,
|
|
18
19
|
type UploadConfig,
|
|
19
20
|
type UploadTextTrack,
|
|
@@ -25,7 +26,7 @@ import type {StagedUpload} from './Uploader'
|
|
|
25
26
|
export type UploadConfigurationStateAction =
|
|
26
27
|
| {action: 'video_quality'; value: UploadConfig['video_quality']}
|
|
27
28
|
| {action: 'max_resolution_tier'; value: UploadConfig['max_resolution_tier']}
|
|
28
|
-
| {action: '
|
|
29
|
+
| {action: 'static_renditions'; value: UploadConfig['static_renditions']}
|
|
29
30
|
| {action: 'normalize_audio'; value: UploadConfig['normalize_audio']}
|
|
30
31
|
| {action: 'signed_policy'; value: UploadConfig['signed_policy']}
|
|
31
32
|
| {action: 'public_policy'; value: UploadConfig['public_policy']}
|
|
@@ -43,6 +44,34 @@ const RESOLUTION_TIERS = [
|
|
|
43
44
|
{value: '2160p', label: '2160p (4k)'},
|
|
44
45
|
] as const satisfies {value: UploadConfig['max_resolution_tier']; label: string}[]
|
|
45
46
|
|
|
47
|
+
const ADVANCED_RESOLUTIONS: {value: StaticRenditionResolution; label: string}[] = [
|
|
48
|
+
{value: '270p', label: '270p'},
|
|
49
|
+
{value: '360p', label: '360p'},
|
|
50
|
+
{value: '480p', label: '480p'},
|
|
51
|
+
{value: '540p', label: '540p'},
|
|
52
|
+
{value: '720p', label: '720p'},
|
|
53
|
+
{value: '1080p', label: '1080p'},
|
|
54
|
+
{value: '1440p', label: '1440p'},
|
|
55
|
+
{value: '2160p', label: '2160p'},
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Sanitizes static renditions configuration to ensure 'highest' is not mixed with specific resolutions.
|
|
60
|
+
* If both are present, only 'highest' (and 'audio-only' if present) will be kept.
|
|
61
|
+
*/
|
|
62
|
+
function sanitizeStaticRenditions(
|
|
63
|
+
renditions: StaticRenditionResolution[]
|
|
64
|
+
): StaticRenditionResolution[] {
|
|
65
|
+
const hasHighest = renditions.includes('highest')
|
|
66
|
+
const hasSpecificResolutions = renditions.some((r) => r !== 'highest' && r !== 'audio-only')
|
|
67
|
+
|
|
68
|
+
if (hasHighest && hasSpecificResolutions) {
|
|
69
|
+
return renditions.filter((r) => r === 'highest' || r === 'audio-only')
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return renditions
|
|
73
|
+
}
|
|
74
|
+
|
|
46
75
|
/**
|
|
47
76
|
* The modal for configuring a staged upload. Handles triggering of the asset
|
|
48
77
|
* upload, even if no modal needs to be shown.
|
|
@@ -84,7 +113,7 @@ export default function UploadConfiguration({
|
|
|
84
113
|
if (action.value === 'basic') {
|
|
85
114
|
return Object.assign({}, prev, {
|
|
86
115
|
video_quality: action.value,
|
|
87
|
-
|
|
116
|
+
static_renditions: [],
|
|
88
117
|
max_resolution_tier: '1080p',
|
|
89
118
|
text_tracks: prev.text_tracks?.filter(({type}) => type !== 'autogenerated'),
|
|
90
119
|
public_policy: true,
|
|
@@ -94,12 +123,12 @@ export default function UploadConfiguration({
|
|
|
94
123
|
}
|
|
95
124
|
return Object.assign({}, prev, {
|
|
96
125
|
video_quality: action.value,
|
|
97
|
-
|
|
126
|
+
static_renditions: sanitizeStaticRenditions(pluginConfig.static_renditions || []),
|
|
98
127
|
max_resolution_tier: pluginConfig.max_resolution_tier,
|
|
99
128
|
text_tracks: [...autoTextTracks, ...(prev.text_tracks || [])],
|
|
100
129
|
})
|
|
101
130
|
|
|
102
|
-
case '
|
|
131
|
+
case 'static_renditions':
|
|
103
132
|
case 'max_resolution_tier':
|
|
104
133
|
case 'normalize_audio':
|
|
105
134
|
case 'signed_policy':
|
|
@@ -141,7 +170,7 @@ export default function UploadConfiguration({
|
|
|
141
170
|
{
|
|
142
171
|
video_quality: pluginConfig.video_quality,
|
|
143
172
|
max_resolution_tier: pluginConfig.max_resolution_tier,
|
|
144
|
-
|
|
173
|
+
static_renditions: sanitizeStaticRenditions(pluginConfig.static_renditions || []),
|
|
145
174
|
signed_policy: secrets.enableSignedUrls && pluginConfig.defaultSigned,
|
|
146
175
|
public_policy: pluginConfig.defaultPublic,
|
|
147
176
|
normalize_audio: pluginConfig.normalize_audio,
|
|
@@ -149,6 +178,54 @@ export default function UploadConfiguration({
|
|
|
149
178
|
} as UploadConfig
|
|
150
179
|
)
|
|
151
180
|
|
|
181
|
+
// Determine if user is in advanced mode based on selected renditions
|
|
182
|
+
const isAdvancedMode = useMemo(() => {
|
|
183
|
+
const specificResolutions = config.static_renditions.filter(
|
|
184
|
+
(r) => r !== 'highest' && r !== 'audio-only'
|
|
185
|
+
)
|
|
186
|
+
return specificResolutions.length > 0
|
|
187
|
+
}, [config.static_renditions])
|
|
188
|
+
|
|
189
|
+
const [renditionMode, setRenditionMode] = useState<'standard' | 'advanced'>(
|
|
190
|
+
isAdvancedMode ? 'advanced' : 'standard'
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
// Helper to toggle a rendition
|
|
194
|
+
const toggleRendition = (rendition: StaticRenditionResolution) => {
|
|
195
|
+
const current = config.static_renditions
|
|
196
|
+
const hasRendition = current.includes(rendition)
|
|
197
|
+
|
|
198
|
+
if (hasRendition) {
|
|
199
|
+
dispatch({
|
|
200
|
+
action: 'static_renditions',
|
|
201
|
+
value: current.filter((r) => r !== rendition),
|
|
202
|
+
})
|
|
203
|
+
} else {
|
|
204
|
+
dispatch({
|
|
205
|
+
action: 'static_renditions',
|
|
206
|
+
value: [...current, rendition],
|
|
207
|
+
})
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// When switching modes, clear renditions that don't apply
|
|
212
|
+
const handleModeChange = (mode: 'standard' | 'advanced') => {
|
|
213
|
+
setRenditionMode(mode)
|
|
214
|
+
if (mode === 'standard') {
|
|
215
|
+
// Remove specific resolutions, keep only highest and audio-only
|
|
216
|
+
dispatch({
|
|
217
|
+
action: 'static_renditions',
|
|
218
|
+
value: config.static_renditions.filter((r) => r === 'highest' || r === 'audio-only'),
|
|
219
|
+
})
|
|
220
|
+
} else {
|
|
221
|
+
// Remove highest, keep specific resolutions and audio-only
|
|
222
|
+
dispatch({
|
|
223
|
+
action: 'static_renditions',
|
|
224
|
+
value: config.static_renditions.filter((r) => r !== 'highest'),
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
152
229
|
// If user-provided config is disabled, begin the upload immediately with
|
|
153
230
|
// the developer-specified values from the schema or config or defaults.
|
|
154
231
|
// This can include auto-generated subtitles!
|
|
@@ -290,31 +367,111 @@ export default function UploadConfiguration({
|
|
|
290
367
|
|
|
291
368
|
{!basicConfig && (
|
|
292
369
|
<FormField title="Additional Configuration">
|
|
293
|
-
<Stack space={
|
|
370
|
+
<Stack space={3}>
|
|
294
371
|
<PlaybackPolicy id={id} config={config} secrets={secrets} dispatch={dispatch} />
|
|
295
372
|
|
|
296
|
-
{
|
|
297
|
-
<
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
373
|
+
<Stack space={3}>
|
|
374
|
+
<FormField
|
|
375
|
+
title="Static Renditions"
|
|
376
|
+
description="Generate downloadable MP4 or M4A files. Note: Mux will not upscale to produce MP4 renditions - renditions that would cause upscaling are skipped."
|
|
377
|
+
>
|
|
378
|
+
<Stack space={3}>
|
|
379
|
+
{/* Mode Selector */}
|
|
380
|
+
<Flex gap={3}>
|
|
381
|
+
<Flex align="center" gap={2}>
|
|
382
|
+
<Radio
|
|
383
|
+
checked={renditionMode === 'standard'}
|
|
384
|
+
name="rendition-mode"
|
|
385
|
+
onChange={() => handleModeChange('standard')}
|
|
386
|
+
value="standard"
|
|
387
|
+
id={`${id}--mode-standard`}
|
|
388
|
+
/>
|
|
389
|
+
<Text as="label" htmlFor={`${id}--mode-standard`}>
|
|
390
|
+
Standard
|
|
391
|
+
</Text>
|
|
392
|
+
</Flex>
|
|
393
|
+
<Flex align="center" gap={2}>
|
|
394
|
+
<Radio
|
|
395
|
+
checked={renditionMode === 'advanced'}
|
|
396
|
+
name="rendition-mode"
|
|
397
|
+
onChange={() => handleModeChange('advanced')}
|
|
398
|
+
value="advanced"
|
|
399
|
+
id={`${id}--mode-advanced`}
|
|
400
|
+
/>
|
|
401
|
+
<Text as="label" htmlFor={`${id}--mode-advanced`}>
|
|
402
|
+
Advanced
|
|
403
|
+
</Text>
|
|
404
|
+
</Flex>
|
|
405
|
+
</Flex>
|
|
406
|
+
|
|
407
|
+
{/* Standard Mode Options */}
|
|
408
|
+
{renditionMode === 'standard' && (
|
|
409
|
+
<Stack space={2}>
|
|
410
|
+
<Flex align="center" gap={2} padding={[0, 2]}>
|
|
411
|
+
<Checkbox
|
|
412
|
+
id={`${id}--highest`}
|
|
413
|
+
style={{display: 'block'}}
|
|
414
|
+
checked={config.static_renditions.includes('highest')}
|
|
415
|
+
onChange={() => toggleRendition('highest')}
|
|
416
|
+
/>
|
|
417
|
+
<Text as="label" htmlFor={`${id}--highest`}>
|
|
418
|
+
Highest Resolution (up to 4K)
|
|
419
|
+
</Text>
|
|
420
|
+
</Flex>
|
|
421
|
+
<Flex align="center" gap={2} padding={[0, 2]}>
|
|
422
|
+
<Checkbox
|
|
423
|
+
id={`${id}--audio-only-standard`}
|
|
424
|
+
style={{display: 'block'}}
|
|
425
|
+
checked={config.static_renditions.includes('audio-only')}
|
|
426
|
+
onChange={() => toggleRendition('audio-only')}
|
|
427
|
+
/>
|
|
428
|
+
<Text as="label" htmlFor={`${id}--audio-only-standard`}>
|
|
429
|
+
Audio Only (M4A)
|
|
430
|
+
</Text>
|
|
431
|
+
</Flex>
|
|
432
|
+
</Stack>
|
|
433
|
+
)}
|
|
434
|
+
|
|
435
|
+
{/* Advanced Mode Options */}
|
|
436
|
+
{renditionMode === 'advanced' && (
|
|
437
|
+
<Stack space={2}>
|
|
438
|
+
<Label size={1} muted>
|
|
439
|
+
Select specific resolutions:
|
|
440
|
+
</Label>
|
|
441
|
+
<Flex gap={2} wrap="wrap">
|
|
442
|
+
{ADVANCED_RESOLUTIONS.map(({value, label}) => {
|
|
443
|
+
const inputId = `${id}--resolution-${value}`
|
|
444
|
+
return (
|
|
445
|
+
<Flex key={value} align="center" gap={2}>
|
|
446
|
+
<Checkbox
|
|
447
|
+
id={inputId}
|
|
448
|
+
style={{display: 'block'}}
|
|
449
|
+
checked={config.static_renditions.includes(value)}
|
|
450
|
+
onChange={() => toggleRendition(value)}
|
|
451
|
+
/>
|
|
452
|
+
<Text as="label" htmlFor={inputId} size={1}>
|
|
453
|
+
{label}
|
|
454
|
+
</Text>
|
|
455
|
+
</Flex>
|
|
456
|
+
)
|
|
457
|
+
})}
|
|
458
|
+
</Flex>
|
|
459
|
+
<Flex align="center" gap={2} padding={[2, 2, 0, 2]}>
|
|
460
|
+
<Checkbox
|
|
461
|
+
id={`${id}--audio-only-advanced`}
|
|
462
|
+
style={{display: 'block'}}
|
|
463
|
+
checked={config.static_renditions.includes('audio-only')}
|
|
464
|
+
onChange={() => toggleRendition('audio-only')}
|
|
465
|
+
/>
|
|
466
|
+
<Text as="label" htmlFor={`${id}--audio-only-advanced`}>
|
|
467
|
+
Audio Only (M4A)
|
|
468
|
+
</Text>
|
|
469
|
+
</Flex>
|
|
470
|
+
</Stack>
|
|
471
|
+
)}
|
|
472
|
+
</Stack>
|
|
473
|
+
</FormField>
|
|
474
|
+
</Stack>
|
|
318
475
|
</Stack>
|
|
319
476
|
</FormField>
|
|
320
477
|
)}
|
|
@@ -385,7 +542,10 @@ function formatUploadConfig(config: UploadConfig): MuxNewAssetSettings {
|
|
|
385
542
|
[] as NonNullable<MuxNewAssetSettings['input']>
|
|
386
543
|
),
|
|
387
544
|
],
|
|
388
|
-
|
|
545
|
+
static_renditions:
|
|
546
|
+
config.static_renditions.length > 0
|
|
547
|
+
? config.static_renditions.map((resolution) => ({resolution}))
|
|
548
|
+
: undefined,
|
|
389
549
|
playback_policy: setPlaybackPolicy(config),
|
|
390
550
|
max_resolution_tier: config.max_resolution_tier,
|
|
391
551
|
video_quality: config.video_quality,
|
|
@@ -10,11 +10,27 @@ export const useMuxPolling = (asset?: VideoAssetDocument) => {
|
|
|
10
10
|
const client = useClient()
|
|
11
11
|
const projectId = useProjectId()
|
|
12
12
|
const dataset = useDataset()
|
|
13
|
+
const isPreparingStaticRenditions = useMemo(() => {
|
|
14
|
+
// Legacy: If static_renditions has a status field, it was created with mp4_support (deprecated)
|
|
15
|
+
// We don't process this old format, just return false
|
|
16
|
+
// Note: 'disabled' status is valid in the new format when no renditions were requested
|
|
17
|
+
if (
|
|
18
|
+
asset?.data?.static_renditions?.status &&
|
|
19
|
+
asset?.data?.static_renditions?.status !== 'disabled'
|
|
20
|
+
) {
|
|
21
|
+
return false
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const files = asset?.data?.static_renditions?.files
|
|
25
|
+
if (!files || files.length === 0) {
|
|
26
|
+
return false
|
|
27
|
+
}
|
|
28
|
+
return files.some((file) => file.status === 'preparing')
|
|
29
|
+
}, [asset?.data?.static_renditions?.status, asset?.data?.static_renditions?.files])
|
|
30
|
+
|
|
13
31
|
const shouldFetch = useMemo(
|
|
14
|
-
() =>
|
|
15
|
-
|
|
16
|
-
(asset?.status === 'preparing' || asset?.data?.static_renditions?.status === 'preparing'),
|
|
17
|
-
[asset?.assetId, asset?.data?.static_renditions?.status, asset?.status]
|
|
32
|
+
() => !!asset?.assetId && (asset?.status === 'preparing' || isPreparingStaticRenditions),
|
|
33
|
+
[asset?.assetId, asset?.status, isPreparingStaticRenditions]
|
|
18
34
|
)
|
|
19
35
|
return useSWR(
|
|
20
36
|
shouldFetch ? `/${projectId}/addons/mux/assets/${dataset}/data/${asset?.assetId}` : null,
|
package/src/schema.ts
CHANGED
|
@@ -39,12 +39,18 @@ const muxStaticRenditionFile = {
|
|
|
39
39
|
name: 'mux.staticRenditionFile',
|
|
40
40
|
type: 'object',
|
|
41
41
|
fields: [
|
|
42
|
-
{type: 'string', name: 'ext'},
|
|
43
42
|
{type: 'string', name: 'name'},
|
|
43
|
+
{type: 'string', name: 'ext'},
|
|
44
|
+
{type: 'number', name: 'height'},
|
|
44
45
|
{type: 'number', name: 'width'},
|
|
45
46
|
{type: 'number', name: 'bitrate'},
|
|
46
|
-
{type: '
|
|
47
|
-
{type: '
|
|
47
|
+
{type: 'string', name: 'filesize'},
|
|
48
|
+
{type: 'string', name: 'type'},
|
|
49
|
+
{type: 'string', name: 'status'},
|
|
50
|
+
{type: 'string', name: 'resolution_tier'},
|
|
51
|
+
{type: 'string', name: 'resolution'},
|
|
52
|
+
{type: 'string', name: 'id'},
|
|
53
|
+
{type: 'string', name: 'passthrough'},
|
|
48
54
|
],
|
|
49
55
|
}
|
|
50
56
|
|
package/src/util/types.ts
CHANGED
|
@@ -1,8 +1,42 @@
|
|
|
1
1
|
import type {ObjectInputProps, PreviewLayoutKey, PreviewProps, SchemaType} from 'sanity'
|
|
2
2
|
import type {PartialDeep} from 'type-fest'
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Standard static rendition options available for plugin configuration defaults
|
|
6
|
+
*/
|
|
7
|
+
export type StandardRendition = 'highest' | 'audio-only'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* All static rendition resolution options supported by Mux
|
|
11
|
+
*/
|
|
12
|
+
export type StaticRenditionResolution =
|
|
13
|
+
| 'highest'
|
|
14
|
+
| 'audio-only'
|
|
15
|
+
| '270p'
|
|
16
|
+
| '360p'
|
|
17
|
+
| '480p'
|
|
18
|
+
| '540p'
|
|
19
|
+
| '720p'
|
|
20
|
+
| '1080p'
|
|
21
|
+
| '1440p'
|
|
22
|
+
| '2160p'
|
|
23
|
+
|
|
4
24
|
export interface MuxInputConfig {
|
|
5
25
|
/**
|
|
26
|
+
* Enable static renditions by default. Can be overwritten on a per-asset basis.
|
|
27
|
+
* Supports:
|
|
28
|
+
* - Standard mode: 'highest' (up to 4K MP4) and/or 'audio-only' (M4A)
|
|
29
|
+
* - Advanced mode: Specific resolutions ('270p', '360p', '480p', '540p', '720p', '1080p', '1440p', '2160p') and/or 'audio-only'
|
|
30
|
+
*
|
|
31
|
+
* **Important**: 'highest' cannot be mixed with specific resolutions. If both are provided, only 'highest' will be used.
|
|
32
|
+
*
|
|
33
|
+
* @see {@link https://docs.mux.com/guides/video/enable-static-mp4-renditions}
|
|
34
|
+
* @defaultValue []
|
|
35
|
+
*/
|
|
36
|
+
static_renditions: StaticRenditionResolution[]
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @deprecated Use `static_renditions` instead. This field is kept for backward compatibility.
|
|
6
40
|
* Enable static renditions by setting this to 'standard'. Can be overwritten on a per-asset basis.
|
|
7
41
|
* Requires `"video_quality": "plus"`
|
|
8
42
|
* @see {@link https://docs.mux.com/guides/video/enable-static-mp4-renditions#why-enable-mp4-support}
|
|
@@ -182,10 +216,8 @@ export function isAutogeneratedTrack(
|
|
|
182
216
|
export type UploadTextTrack = AutogeneratedTextTrack | CustomTextTrack
|
|
183
217
|
|
|
184
218
|
export interface UploadConfig
|
|
185
|
-
extends Pick<
|
|
186
|
-
|
|
187
|
-
'max_resolution_tier' | 'mp4_support' | 'normalize_audio' | 'video_quality'
|
|
188
|
-
> {
|
|
219
|
+
extends Pick<MuxInputConfig, 'max_resolution_tier' | 'normalize_audio' | 'video_quality'> {
|
|
220
|
+
static_renditions: StaticRenditionResolution[]
|
|
189
221
|
text_tracks: UploadTextTrack[]
|
|
190
222
|
signed_policy: boolean
|
|
191
223
|
public_policy: boolean
|
|
@@ -196,10 +228,9 @@ export interface UploadConfig
|
|
|
196
228
|
* @docs {@link https://docs.mux.com/api-reference#video/operation/create-direct-upload}
|
|
197
229
|
*/
|
|
198
230
|
export interface MuxNewAssetSettings
|
|
199
|
-
extends Pick<
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
> {
|
|
231
|
+
extends Pick<MuxInputConfig, 'max_resolution_tier' | 'normalize_audio' | 'video_quality'> {
|
|
232
|
+
/** Static renditions configuration for downloadable files */
|
|
233
|
+
static_renditions?: {resolution: StaticRenditionResolution}[]
|
|
203
234
|
/** An array of objects that each describe an input file to be used to create the asset.*/
|
|
204
235
|
input?: {
|
|
205
236
|
/** The URL of the file that Mux should download and use. */
|
|
@@ -371,12 +402,18 @@ export interface MuxAsset {
|
|
|
371
402
|
static_renditions?: {
|
|
372
403
|
status: 'ready' | 'preparing' | 'disabled' | 'errored'
|
|
373
404
|
files: {
|
|
374
|
-
name:
|
|
405
|
+
name: string
|
|
375
406
|
ext: 'mp4' | 'm4a'
|
|
376
407
|
height: number
|
|
377
408
|
width: number
|
|
378
409
|
bitrate: number
|
|
379
|
-
filesize:
|
|
410
|
+
filesize: string
|
|
411
|
+
type: 'standard' | 'advanced'
|
|
412
|
+
status: 'ready' | 'preparing' | 'skipped' | 'errored'
|
|
413
|
+
resolution_tier?: string
|
|
414
|
+
resolution?: string
|
|
415
|
+
id: string
|
|
416
|
+
passthrough?: string
|
|
380
417
|
}[]
|
|
381
418
|
}
|
|
382
419
|
recording_times?: {
|