sanity-plugin-mux-input 2.5.0 → 2.6.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 +2 -0
- package/dist/index.js +151 -623
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +154 -626
- package/dist/index.mjs.map +1 -1
- package/package.json +13 -13
- package/src/actions/secrets.ts +19 -9
- package/src/components/ConfigureApi.tsx +2 -0
- package/src/components/MuxLogo.tsx +26 -447
- package/src/components/UploadConfiguration.tsx +29 -26
- package/src/components/VideoDetails/useVideoDetails.ts +5 -5
- package/src/components/uploadConfiguration/PlaybackPolicy.tsx +44 -0
- package/src/components/uploadConfiguration/PlaybackPolicyOption.tsx +60 -0
- package/src/components/uploadConfiguration/PlaybackPolicyWarning.tsx +29 -0
- package/src/hooks/useAssets.ts +26 -29
- package/src/util/types.ts +3 -2
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
type UploadTextTrack,
|
|
20
20
|
} from '../util/types'
|
|
21
21
|
import TextTracksEditor, {type TrackAction} from './TextTracksEditor'
|
|
22
|
+
import PlaybackPolicy from './uploadConfiguration/PlaybackPolicy'
|
|
22
23
|
import type {StagedUpload} from './Uploader'
|
|
23
24
|
|
|
24
25
|
export type UploadConfigurationStateAction =
|
|
@@ -26,7 +27,8 @@ export type UploadConfigurationStateAction =
|
|
|
26
27
|
| {action: 'max_resolution_tier'; value: UploadConfig['max_resolution_tier']}
|
|
27
28
|
| {action: 'mp4_support'; value: UploadConfig['mp4_support']}
|
|
28
29
|
| {action: 'normalize_audio'; value: UploadConfig['normalize_audio']}
|
|
29
|
-
| {action: '
|
|
30
|
+
| {action: 'signed_policy'; value: UploadConfig['signed_policy']}
|
|
31
|
+
| {action: 'public_policy'; value: UploadConfig['public_policy']}
|
|
30
32
|
| TrackAction
|
|
31
33
|
|
|
32
34
|
const ENCODING_OPTIONS = [
|
|
@@ -84,6 +86,8 @@ export default function UploadConfiguration({
|
|
|
84
86
|
mp4_support: 'none',
|
|
85
87
|
max_resolution_tier: '1080p',
|
|
86
88
|
text_tracks: prev.text_tracks?.filter(({type}) => type !== 'autogenerated'),
|
|
89
|
+
public_policy: true,
|
|
90
|
+
signed_policy: false,
|
|
87
91
|
})
|
|
88
92
|
// If encoding tier switches to smart, add back in default smart features
|
|
89
93
|
}
|
|
@@ -97,7 +101,9 @@ export default function UploadConfiguration({
|
|
|
97
101
|
case 'mp4_support':
|
|
98
102
|
case 'max_resolution_tier':
|
|
99
103
|
case 'normalize_audio':
|
|
100
|
-
case '
|
|
104
|
+
case 'signed_policy':
|
|
105
|
+
return Object.assign({}, prev, {[action.action]: action.value})
|
|
106
|
+
case 'public_policy':
|
|
101
107
|
return Object.assign({}, prev, {[action.action]: action.value})
|
|
102
108
|
// Updating individual tracks
|
|
103
109
|
case 'track': {
|
|
@@ -135,7 +141,8 @@ export default function UploadConfiguration({
|
|
|
135
141
|
encoding_tier: pluginConfig.encoding_tier,
|
|
136
142
|
max_resolution_tier: pluginConfig.max_resolution_tier,
|
|
137
143
|
mp4_support: pluginConfig.mp4_support,
|
|
138
|
-
|
|
144
|
+
signed_policy: secrets.enableSignedUrls && pluginConfig.defaultSigned,
|
|
145
|
+
public_policy: true,
|
|
139
146
|
normalize_audio: pluginConfig.normalize_audio,
|
|
140
147
|
text_tracks: autoTextTracks,
|
|
141
148
|
} as UploadConfig
|
|
@@ -279,31 +286,13 @@ export default function UploadConfiguration({
|
|
|
279
286
|
</FormField>
|
|
280
287
|
)}
|
|
281
288
|
|
|
282
|
-
{
|
|
289
|
+
{config.encoding_tier === 'smart' && (
|
|
283
290
|
<FormField title="Additional Configuration">
|
|
284
291
|
<Stack space={2}>
|
|
285
|
-
{secrets
|
|
286
|
-
|
|
287
|
-
<Checkbox
|
|
288
|
-
id={`${id}--signed`}
|
|
289
|
-
style={{display: 'block'}}
|
|
290
|
-
name="signed"
|
|
291
|
-
required
|
|
292
|
-
checked={config.signed}
|
|
293
|
-
onChange={(e) =>
|
|
294
|
-
dispatch({
|
|
295
|
-
action: 'signed',
|
|
296
|
-
value: e.currentTarget.checked,
|
|
297
|
-
})
|
|
298
|
-
}
|
|
299
|
-
/>
|
|
300
|
-
<Text>
|
|
301
|
-
<label htmlFor={`${id}--signed`}>Signed playback URL</label>
|
|
302
|
-
</Text>
|
|
303
|
-
</Flex>
|
|
304
|
-
)}
|
|
292
|
+
<PlaybackPolicy id={id} config={config} secrets={secrets} dispatch={dispatch} />
|
|
293
|
+
|
|
305
294
|
{config.encoding_tier === 'smart' && (
|
|
306
|
-
<Flex align="center" gap={2}>
|
|
295
|
+
<Flex align="center" gap={2} padding={[0, 2]}>
|
|
307
296
|
<Checkbox
|
|
308
297
|
id={`${id}--mp4_support`}
|
|
309
298
|
style={{display: 'block'}}
|
|
@@ -340,6 +329,9 @@ export default function UploadConfiguration({
|
|
|
340
329
|
|
|
341
330
|
<Box marginTop={4}>
|
|
342
331
|
<Button
|
|
332
|
+
disabled={
|
|
333
|
+
config.encoding_tier === 'smart' && !config.public_policy && !config.signed_policy
|
|
334
|
+
}
|
|
343
335
|
icon={UploadIcon}
|
|
344
336
|
text="Upload"
|
|
345
337
|
tone="positive"
|
|
@@ -351,6 +343,17 @@ export default function UploadConfiguration({
|
|
|
351
343
|
)
|
|
352
344
|
}
|
|
353
345
|
|
|
346
|
+
function setPlaybackPolicy(config: UploadConfig): MuxNewAssetSettings['playback_policy'] {
|
|
347
|
+
const playback_policy: MuxNewAssetSettings['playback_policy'] = []
|
|
348
|
+
if (config.public_policy) {
|
|
349
|
+
playback_policy.push('public')
|
|
350
|
+
}
|
|
351
|
+
if (config.signed_policy) {
|
|
352
|
+
playback_policy.push('signed')
|
|
353
|
+
}
|
|
354
|
+
return playback_policy
|
|
355
|
+
}
|
|
356
|
+
|
|
354
357
|
function formatUploadConfig(config: UploadConfig): MuxNewAssetSettings {
|
|
355
358
|
const generated_subtitles = config.text_tracks
|
|
356
359
|
.filter<AutogeneratedTextTrack>(isAutogeneratedTrack)
|
|
@@ -383,7 +386,7 @@ function formatUploadConfig(config: UploadConfig): MuxNewAssetSettings {
|
|
|
383
386
|
),
|
|
384
387
|
],
|
|
385
388
|
mp4_support: config.mp4_support,
|
|
386
|
-
playback_policy: config
|
|
389
|
+
playback_policy: setPlaybackPolicy(config),
|
|
387
390
|
max_resolution_tier: config.max_resolution_tier,
|
|
388
391
|
encoding_tier: config.encoding_tier,
|
|
389
392
|
normalize_audio: config.normalize_audio,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {useToast} from '@sanity/ui'
|
|
2
|
-
import {useState} from 'react'
|
|
2
|
+
import {useMemo, useState} from 'react'
|
|
3
3
|
import {useDocumentStore} from 'sanity'
|
|
4
4
|
|
|
5
5
|
import {useClient} from '../../hooks/useClient'
|
|
@@ -17,10 +17,10 @@ export default function useVideoDetails(props: VideoDetailsProps) {
|
|
|
17
17
|
const documentStore = useDocumentStore()
|
|
18
18
|
const toast = useToast()
|
|
19
19
|
const client = useClient()
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
id: props.asset._id
|
|
23
|
-
|
|
20
|
+
|
|
21
|
+
const [references, referencesLoading] = useDocReferences(
|
|
22
|
+
useMemo(() => ({documentStore, id: props.asset._id}), [documentStore, props.asset._id])
|
|
23
|
+
)
|
|
24
24
|
|
|
25
25
|
const [originalAsset, setOriginalAsset] = useState(() => props.asset)
|
|
26
26
|
const [filename, setFilename] = useState(props.asset.filename)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {Grid, Text} from '@sanity/ui'
|
|
2
|
+
|
|
3
|
+
import {Secrets, UploadConfig} from '../../util/types'
|
|
4
|
+
import PlaybackPolicyOption from './PlaybackPolicyOption'
|
|
5
|
+
import PlaybackPolicyWarning from './PlaybackPolicyWarning'
|
|
6
|
+
|
|
7
|
+
export default function PlaybackPolicy({
|
|
8
|
+
id,
|
|
9
|
+
config,
|
|
10
|
+
secrets,
|
|
11
|
+
dispatch,
|
|
12
|
+
}: {
|
|
13
|
+
id: string
|
|
14
|
+
config: UploadConfig
|
|
15
|
+
secrets: Secrets
|
|
16
|
+
dispatch: any
|
|
17
|
+
}) {
|
|
18
|
+
const noPolicySelected = !(config.public_policy || config.signed_policy)
|
|
19
|
+
return (
|
|
20
|
+
<Grid gap={3}>
|
|
21
|
+
<Text weight="bold">Advanced Playback Policies</Text>
|
|
22
|
+
<PlaybackPolicyOption
|
|
23
|
+
id={`${id}--public`}
|
|
24
|
+
checked={config.public_policy}
|
|
25
|
+
optionName="Public"
|
|
26
|
+
description="Playback IDs are accessible by constructing an HLS URL like https://stream.mux.com/{PLAYBACK_ID}"
|
|
27
|
+
dispatch={dispatch}
|
|
28
|
+
action="public_policy"
|
|
29
|
+
/>
|
|
30
|
+
{secrets.enableSignedUrls && (
|
|
31
|
+
<PlaybackPolicyOption
|
|
32
|
+
id={`${id}--signed`}
|
|
33
|
+
checked={config.signed_policy}
|
|
34
|
+
optionName="Signed"
|
|
35
|
+
description="Playback IDs should be used with tokens https://stream.mux.com/{PLAYBACK_ID}?token={TOKEN}.
|
|
36
|
+
// See Secure video playback for details about creating tokens."
|
|
37
|
+
dispatch={dispatch}
|
|
38
|
+
action="signed_policy"
|
|
39
|
+
/>
|
|
40
|
+
)}
|
|
41
|
+
{noPolicySelected && <PlaybackPolicyWarning />}
|
|
42
|
+
</Grid>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {Box, Checkbox, Flex, Grid, Stack, Text} from '@sanity/ui'
|
|
2
|
+
import {CSSProperties, useState} from 'react'
|
|
3
|
+
|
|
4
|
+
import {UploadConfigurationStateAction} from '../UploadConfiguration'
|
|
5
|
+
|
|
6
|
+
export default function PlaybackPolicyOption({
|
|
7
|
+
id,
|
|
8
|
+
checked,
|
|
9
|
+
optionName,
|
|
10
|
+
description,
|
|
11
|
+
dispatch,
|
|
12
|
+
action,
|
|
13
|
+
}: {
|
|
14
|
+
id: string
|
|
15
|
+
checked: boolean
|
|
16
|
+
optionName: string
|
|
17
|
+
description: string
|
|
18
|
+
dispatch: any
|
|
19
|
+
action: UploadConfigurationStateAction['action']
|
|
20
|
+
}) {
|
|
21
|
+
const [scale, setScale] = useState(1)
|
|
22
|
+
|
|
23
|
+
const boxStyle: CSSProperties = {
|
|
24
|
+
outline: '0.01rem solid grey',
|
|
25
|
+
transform: `scale(${scale})`,
|
|
26
|
+
transition: 'transform 0.1s ease-in-out',
|
|
27
|
+
cursor: 'pointer',
|
|
28
|
+
borderRadius: '0.25rem',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const triggerAnimation = () => {
|
|
32
|
+
setScale(0.98)
|
|
33
|
+
setTimeout(() => {
|
|
34
|
+
setScale(1)
|
|
35
|
+
}, 100)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const handleBoxClick = () => {
|
|
39
|
+
triggerAnimation()
|
|
40
|
+
dispatch({
|
|
41
|
+
action,
|
|
42
|
+
value: !checked,
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
return (
|
|
46
|
+
<label>
|
|
47
|
+
<Flex gap={3} padding={3} style={boxStyle}>
|
|
48
|
+
<Checkbox id={id} required checked={checked} onChange={handleBoxClick} />
|
|
49
|
+
<Grid gap={3}>
|
|
50
|
+
<Text size={3} weight="bold">
|
|
51
|
+
{optionName}
|
|
52
|
+
</Text>
|
|
53
|
+
<Text size={2} muted>
|
|
54
|
+
{description}
|
|
55
|
+
</Text>
|
|
56
|
+
</Grid>
|
|
57
|
+
</Flex>
|
|
58
|
+
</label>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {WarningFilledIcon} from '@sanity/icons'
|
|
2
|
+
import {Box, Flex, Text} from '@sanity/ui'
|
|
3
|
+
import {CSSProperties} from 'react'
|
|
4
|
+
|
|
5
|
+
export default function PlaybackPolicyWarning() {
|
|
6
|
+
const textStyle: CSSProperties = {
|
|
7
|
+
color: '#13141A',
|
|
8
|
+
fontWeight: 500,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const boxStyle: CSSProperties = {
|
|
12
|
+
outline: '0.01rem solid grey',
|
|
13
|
+
backgroundColor: '#979cb0',
|
|
14
|
+
borderRadius: '0.5rem',
|
|
15
|
+
width: 'max-content',
|
|
16
|
+
color: '#13141A',
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Box padding={2} style={boxStyle}>
|
|
21
|
+
<Flex align="center" gap={2}>
|
|
22
|
+
<WarningFilledIcon />
|
|
23
|
+
<Text size={1} style={textStyle}>
|
|
24
|
+
Please select at least one Playback Policy
|
|
25
|
+
</Text>
|
|
26
|
+
</Flex>
|
|
27
|
+
</Box>
|
|
28
|
+
)
|
|
29
|
+
}
|
package/src/hooks/useAssets.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {useMemo, useState} from 'react'
|
|
2
|
-
import {
|
|
3
|
-
import {collate, DocumentStore, useDocumentStore} from 'sanity'
|
|
2
|
+
import {collate, createHookFromObservableFactory, DocumentStore, useDocumentStore} from 'sanity'
|
|
4
3
|
|
|
5
4
|
import {SANITY_API_VERSION} from '../hooks/useClient'
|
|
6
5
|
import {createSearchFilter} from '../util/createSearchFilter'
|
|
@@ -15,49 +14,47 @@ export const ASSET_SORT_OPTIONS = {
|
|
|
15
14
|
|
|
16
15
|
export type SortOption = keyof typeof ASSET_SORT_OPTIONS
|
|
17
16
|
|
|
18
|
-
const useAssetDocuments =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
const search = createSearchFilter(searchQuery)
|
|
29
|
-
const filter = [`_type == "mux.videoAsset"`, ...search.filter].filter(Boolean).join(' && ')
|
|
30
|
-
const sortFragment = ASSET_SORT_OPTIONS[sort].groq
|
|
31
|
-
return documentStore.listenQuery(
|
|
32
|
-
/* groq */ `*[${filter}] | order(${sortFragment})`,
|
|
33
|
-
search.params,
|
|
34
|
-
{
|
|
35
|
-
apiVersion: SANITY_API_VERSION,
|
|
36
|
-
}
|
|
37
|
-
)
|
|
38
|
-
}, [documentStore, sort, searchQuery])
|
|
17
|
+
const useAssetDocuments = createHookFromObservableFactory<
|
|
18
|
+
VideoAssetDocument[],
|
|
19
|
+
{
|
|
20
|
+
documentStore: DocumentStore
|
|
21
|
+
sort: SortOption
|
|
22
|
+
searchQuery: string
|
|
23
|
+
}
|
|
24
|
+
>(({documentStore, sort, searchQuery}) => {
|
|
25
|
+
const search = createSearchFilter(searchQuery)
|
|
26
|
+
const filter = [`_type == "mux.videoAsset"`, ...search.filter].filter(Boolean).join(' && ')
|
|
39
27
|
|
|
40
|
-
|
|
41
|
-
|
|
28
|
+
const sortFragment = ASSET_SORT_OPTIONS[sort].groq
|
|
29
|
+
return documentStore.listenQuery(
|
|
30
|
+
/* groq */ `*[${filter}] | order(${sortFragment})`,
|
|
31
|
+
search.params,
|
|
32
|
+
{
|
|
33
|
+
apiVersion: SANITY_API_VERSION,
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
})
|
|
42
37
|
|
|
43
38
|
export default function useAssets() {
|
|
44
39
|
const documentStore = useDocumentStore()
|
|
45
40
|
const [sort, setSort] = useState<SortOption>('createdDesc')
|
|
46
41
|
const [searchQuery, setSearchQuery] = useState('')
|
|
47
42
|
|
|
48
|
-
const
|
|
49
|
-
|
|
43
|
+
const [assetDocuments = [], isLoading] = useAssetDocuments(
|
|
44
|
+
useMemo(() => ({documentStore, sort, searchQuery}), [documentStore, sort, searchQuery])
|
|
45
|
+
)
|
|
46
|
+
|
|
50
47
|
const assets = useMemo(
|
|
51
48
|
() =>
|
|
52
49
|
// Avoid displaying both drafts & published assets by collating them together and giving preference to drafts
|
|
53
|
-
collate<VideoAssetDocument>(
|
|
50
|
+
collate<VideoAssetDocument>(assetDocuments).map(
|
|
54
51
|
(collated) =>
|
|
55
52
|
({
|
|
56
53
|
...(collated.draft || collated.published || {}),
|
|
57
54
|
_id: collated.id,
|
|
58
55
|
}) as VideoAssetDocument
|
|
59
56
|
),
|
|
60
|
-
[
|
|
57
|
+
[assetDocuments]
|
|
61
58
|
)
|
|
62
59
|
|
|
63
60
|
return {
|
package/src/util/types.ts
CHANGED
|
@@ -163,7 +163,8 @@ export interface UploadConfig
|
|
|
163
163
|
'encoding_tier' | 'max_resolution_tier' | 'mp4_support' | 'normalize_audio'
|
|
164
164
|
> {
|
|
165
165
|
text_tracks: UploadTextTrack[]
|
|
166
|
-
|
|
166
|
+
signed_policy: boolean
|
|
167
|
+
public_policy: boolean
|
|
167
168
|
}
|
|
168
169
|
|
|
169
170
|
/**
|
|
@@ -208,7 +209,7 @@ export interface MuxNewAssetSettings
|
|
|
208
209
|
}[]
|
|
209
210
|
|
|
210
211
|
/** An array of playback policy names that you want applied to this asset and available through playback_ids. */
|
|
211
|
-
playback_policy: ('public' | 'signed')[]
|
|
212
|
+
playback_policy: ('public' | 'signed' | 'drm')[]
|
|
212
213
|
|
|
213
214
|
/** Arbitrary user-supplied metadata that will be included in the asset details and related webhooks. */
|
|
214
215
|
passthrough?: string
|