sanity-plugin-mux-input 3.0.4 → 4.0.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.
Files changed (130) hide show
  1. package/README.md +0 -2
  2. package/dist/index.d.ts +134 -193
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +2893 -4417
  5. package/dist/index.js.map +1 -1
  6. package/package.json +33 -43
  7. package/dist/index.cjs +0 -7270
  8. package/dist/index.cjs.map +0 -1
  9. package/dist/index.d.cts +0 -347
  10. package/sanity.json +0 -8
  11. package/src/_exports/index.ts +0 -73
  12. package/src/actions/assets.ts +0 -152
  13. package/src/actions/secrets.ts +0 -111
  14. package/src/actions/upload.ts +0 -310
  15. package/src/clients/upChunkObservable.ts +0 -54
  16. package/src/components/AddCaptionDialog.tsx +0 -440
  17. package/src/components/CaptionsDialog.tsx +0 -23
  18. package/src/components/ConfigureApi.styled.tsx +0 -19
  19. package/src/components/ConfigureApi.tsx +0 -296
  20. package/src/components/DraggableWatermark.tsx +0 -877
  21. package/src/components/EditCaptionDialog.tsx +0 -510
  22. package/src/components/EditThumbnailDialog.tsx +0 -122
  23. package/src/components/ErrorBoundaryCard.tsx +0 -96
  24. package/src/components/FileInputButton.tsx +0 -54
  25. package/src/components/FileInputMenuItem.styled.tsx +0 -36
  26. package/src/components/FileInputMenuItem.tsx +0 -85
  27. package/src/components/FormField.tsx +0 -38
  28. package/src/components/IconInfo.tsx +0 -22
  29. package/src/components/ImportVideosFromMux.tsx +0 -342
  30. package/src/components/Input.styled.tsx +0 -22
  31. package/src/components/Input.tsx +0 -78
  32. package/src/components/InputBrowser.tsx +0 -41
  33. package/src/components/InputError.tsx +0 -17
  34. package/src/components/MuxLogo.tsx +0 -42
  35. package/src/components/Onboard.tsx +0 -65
  36. package/src/components/PageSelector.tsx +0 -54
  37. package/src/components/Player.styled.tsx +0 -55
  38. package/src/components/Player.tsx +0 -117
  39. package/src/components/PlayerActionsMenu.tsx +0 -190
  40. package/src/components/ResyncMetadata.tsx +0 -280
  41. package/src/components/SelectAsset.tsx +0 -39
  42. package/src/components/SelectSortOptions.tsx +0 -45
  43. package/src/components/SpinnerBox.tsx +0 -16
  44. package/src/components/StudioTool.tsx +0 -24
  45. package/src/components/TextTracksEditor.tsx +0 -117
  46. package/src/components/TextTracksManager.tsx +0 -737
  47. package/src/components/UploadConfiguration.tsx +0 -694
  48. package/src/components/UploadPlaceholder.tsx +0 -88
  49. package/src/components/UploadProgress.tsx +0 -80
  50. package/src/components/Uploader.styled.tsx +0 -66
  51. package/src/components/Uploader.tsx +0 -498
  52. package/src/components/VideoDetails/DeleteDialog.tsx +0 -147
  53. package/src/components/VideoDetails/VideoDetails.tsx +0 -358
  54. package/src/components/VideoDetails/VideoReferences.tsx +0 -63
  55. package/src/components/VideoDetails/useVideoDetails.ts +0 -103
  56. package/src/components/VideoInBrowser.tsx +0 -245
  57. package/src/components/VideoMetadata.tsx +0 -45
  58. package/src/components/VideoPlayer.tsx +0 -235
  59. package/src/components/VideoThumbnail.tsx +0 -138
  60. package/src/components/VideosBrowser.tsx +0 -100
  61. package/src/components/documentPreview/DocumentPreview.tsx +0 -83
  62. package/src/components/documentPreview/DraftStatus.tsx +0 -34
  63. package/src/components/documentPreview/MissingSchemaType.tsx +0 -32
  64. package/src/components/documentPreview/PaneItemPreview.tsx +0 -74
  65. package/src/components/documentPreview/PublishedStatus.tsx +0 -35
  66. package/src/components/documentPreview/TimeAgo.tsx +0 -12
  67. package/src/components/documentPreview/paneItemTypes.ts +0 -7
  68. package/src/components/icons/Audio.tsx +0 -13
  69. package/src/components/icons/Resolution.tsx +0 -12
  70. package/src/components/icons/StopWatch.tsx +0 -20
  71. package/src/components/icons/ToolIcon.tsx +0 -19
  72. package/src/components/uploadConfiguration/PlaybackPolicy.tsx +0 -133
  73. package/src/components/uploadConfiguration/PlaybackPolicyOption.tsx +0 -76
  74. package/src/components/uploadConfiguration/PlaybackPolicyWarning.tsx +0 -29
  75. package/src/components/uploadConfiguration/ResolutionTierSelector.tsx +0 -72
  76. package/src/components/uploadConfiguration/StaticRenditionSelector.tsx +0 -180
  77. package/src/components/withFocusRing/helpers.ts +0 -24
  78. package/src/components/withFocusRing/index.ts +0 -1
  79. package/src/components/withFocusRing/withFocusRing.ts +0 -30
  80. package/src/context/DialogStateContext.tsx +0 -36
  81. package/src/context/DrmPlaybackWarningContext.tsx +0 -93
  82. package/src/hooks/useAccessControl.ts +0 -13
  83. package/src/hooks/useAssetDocumentValues.ts +0 -11
  84. package/src/hooks/useAssets.ts +0 -68
  85. package/src/hooks/useCancelUpload.ts +0 -22
  86. package/src/hooks/useClient.ts +0 -8
  87. package/src/hooks/useDialogState.ts +0 -11
  88. package/src/hooks/useDocReferences.ts +0 -21
  89. package/src/hooks/useFetchFileSize.ts +0 -54
  90. package/src/hooks/useImportMuxAssets.ts +0 -132
  91. package/src/hooks/useInView.ts +0 -42
  92. package/src/hooks/useMediaMetadata.ts +0 -103
  93. package/src/hooks/useMuxAssets.ts +0 -179
  94. package/src/hooks/useMuxPolling.ts +0 -49
  95. package/src/hooks/useResyncAsset.ts +0 -110
  96. package/src/hooks/useResyncMuxMetadata.ts +0 -176
  97. package/src/hooks/useSaveSecrets.ts +0 -78
  98. package/src/hooks/useSecretsDocumentValues.ts +0 -38
  99. package/src/hooks/useSecretsFormState.ts +0 -47
  100. package/src/plugin.tsx +0 -31
  101. package/src/sanity-ui.d.ts +0 -5
  102. package/src/schema.ts +0 -196
  103. package/src/util/addKeysToMuxData.ts +0 -30
  104. package/src/util/areSecretsSignable.ts +0 -5
  105. package/src/util/asserters.ts +0 -36
  106. package/src/util/assetTitlePlaceholder.ts +0 -31
  107. package/src/util/constants.ts +0 -15
  108. package/src/util/convertWatermarkToMux.ts +0 -160
  109. package/src/util/createSearchFilter.ts +0 -76
  110. package/src/util/createUrlParamsObject.ts +0 -29
  111. package/src/util/extractFiles.ts +0 -67
  112. package/src/util/formatBytes.ts +0 -32
  113. package/src/util/formatDriveShareLink.ts +0 -64
  114. package/src/util/formatSeconds.ts +0 -49
  115. package/src/util/generateJwt.ts +0 -57
  116. package/src/util/getAnimatedPosterSrc.ts +0 -26
  117. package/src/util/getPlaybackPolicy.ts +0 -69
  118. package/src/util/getPosterSrc.ts +0 -28
  119. package/src/util/getStoryboardSrc.ts +0 -27
  120. package/src/util/getVideoMetadata.ts +0 -23
  121. package/src/util/getVideoSrc.ts +0 -23
  122. package/src/util/isSigned.ts +0 -20
  123. package/src/util/parsers.ts +0 -5
  124. package/src/util/pluginVersion.ts +0 -1
  125. package/src/util/readSecrets.ts +0 -38
  126. package/src/util/roundPxString.ts +0 -16
  127. package/src/util/textTracks.ts +0 -222
  128. package/src/util/tryWithSuspend.ts +0 -22
  129. package/src/util/types.ts +0 -596
  130. package/v2-incompatible.js +0 -11
@@ -1,440 +0,0 @@
1
- import {TranslateIcon, UploadIcon} from '@sanity/icons'
2
- import {
3
- Autocomplete,
4
- Button,
5
- Card,
6
- Checkbox,
7
- Dialog,
8
- Flex,
9
- Label,
10
- Spinner,
11
- Stack,
12
- Text,
13
- TextInput,
14
- useToast,
15
- } from '@sanity/ui'
16
- import LanguagesList from 'iso-639-1'
17
- import {useId, useRef, useState} from 'react'
18
-
19
- import {addTextTrackFromUrl, generateSubtitles, getAsset} from '../actions/assets'
20
- import {useClient} from '../hooks/useClient'
21
- import {addKeysToMuxData} from '../util/addKeysToMuxData'
22
- import {extractErrorMessage, pollTrackStatus} from '../util/textTracks'
23
- import {type MuxTextTrack, SUPPORTED_MUX_LANGUAGES, type VideoAssetDocument} from '../util/types'
24
-
25
- const LANGUAGE_OPTIONS = LanguagesList.getAllCodes().map((code) => ({
26
- value: code,
27
- label: LanguagesList.getNativeName(code),
28
- }))
29
-
30
- const MUX_LANGUAGE_OPTIONS = SUPPORTED_MUX_LANGUAGES.map((lang) => ({
31
- value: lang.code,
32
- label: lang.label,
33
- }))
34
-
35
- export interface Props {
36
- asset: VideoAssetDocument
37
- onAdd: (track: MuxTextTrack) => void
38
- onClose: () => void
39
- }
40
-
41
- export default function AddCaptionDialog({asset, onAdd, onClose}: Props) {
42
- const client = useClient()
43
- const toast = useToast()
44
- const dialogId = `AddCaptionDialog${useId()}`
45
-
46
- const [isAutogenerated, setIsAutogenerated] = useState(false)
47
- const [vttUrl, setVttUrl] = useState('')
48
- const [languageCode, setLanguageCode] = useState('')
49
- const [selectedLanguage, setSelectedLanguage] = useState<{value: string; label: string} | null>(
50
- null
51
- )
52
- const [name, setName] = useState('')
53
- const [isSubmitting, setIsSubmitting] = useState(false)
54
- const [selectedFile, setSelectedFile] = useState<File | null>(null)
55
- const fileInputRef = useRef<HTMLInputElement>(null)
56
-
57
- const uploadVttFile = async (file: File): Promise<string> => {
58
- const assetDocument = await client.assets.upload('file', file, {
59
- filename: file.name,
60
- })
61
- return assetDocument.url
62
- }
63
-
64
- const refreshAssetData = async () => {
65
- if (!asset._id || !asset.assetId) return
66
- try {
67
- const latestAssetData = await getAsset(client, asset.assetId)
68
- const dataWithKeys = addKeysToMuxData(latestAssetData.data)
69
- await client
70
- .patch(asset._id)
71
- .set({data: dataWithKeys, status: latestAssetData.data.status})
72
- .commit({returnDocuments: false})
73
- } catch (refreshError) {
74
- console.error('Failed to refresh asset data:', refreshError)
75
- }
76
- }
77
-
78
- const handleAddTrackFromUrl = async () => {
79
- if (!asset.assetId) {
80
- throw new Error('Asset ID is required')
81
- }
82
-
83
- const trimmedName = name.trim()
84
- const trimmedLanguageCode = languageCode.trim()
85
-
86
- let vttUrlToUse = vttUrl.trim()
87
-
88
- if (selectedFile) {
89
- try {
90
- vttUrlToUse = await uploadVttFile(selectedFile)
91
- } catch (uploadError) {
92
- toast.push({
93
- title: 'Failed to upload caption file',
94
- status: 'error',
95
- description: 'Could not upload the caption file to Sanity. Please try again.',
96
- })
97
- setIsSubmitting(false)
98
- throw uploadError
99
- }
100
- }
101
-
102
- await addTextTrackFromUrl(client, asset.assetId, vttUrlToUse, {
103
- language_code: trimmedLanguageCode,
104
- name: trimmedName,
105
- text_type: 'subtitles',
106
- })
107
-
108
- const result = await pollTrackStatus({
109
- client,
110
- assetId: asset.assetId,
111
- trackName: trimmedName,
112
- trackLanguageCode: trimmedLanguageCode,
113
- onTrackErrored: async (track) => {
114
- const errorMessage =
115
- track.error?.messages?.[0] ||
116
- track.error?.type ||
117
- 'The track failed to download from the provided URL'
118
- toast.push({
119
- title: 'Caption track failed',
120
- status: 'error',
121
- description: errorMessage,
122
- })
123
- await refreshAssetData()
124
- onAdd(track)
125
- onClose()
126
- },
127
- })
128
-
129
- if (!result.found || !result.track) {
130
- toast.push({
131
- title: 'Caption track may have been added',
132
- status: 'warning',
133
- description:
134
- 'The track was created but its status could not be determined. It may still be processing. Please refresh the page to see if it appears.',
135
- })
136
- onClose()
137
- return
138
- }
139
-
140
- if (result.status === 'errored') {
141
- return
142
- }
143
-
144
- if (result.status === 'preparing') {
145
- toast.push({
146
- title: 'Caption track is processing',
147
- status: 'info',
148
- description:
149
- 'The track was created and is being processed. It will appear in the list shortly.',
150
- })
151
- await refreshAssetData()
152
- onAdd(result.track)
153
- onClose()
154
- return
155
- }
156
-
157
- await refreshAssetData()
158
- toast.push({
159
- title: 'Caption track added',
160
- status: 'success',
161
- description: 'Caption track added successfully',
162
- })
163
-
164
- onAdd(result.track)
165
- onClose()
166
- }
167
-
168
- const handleGenerateSubtitles = async () => {
169
- if (!asset.assetId) {
170
- throw new Error('Asset ID is required')
171
- }
172
-
173
- const assetData = await getAsset(client, asset.assetId)
174
- const audioTrack = assetData.data.tracks?.find((track) => track.type === 'audio')
175
-
176
- if (!audioTrack || !audioTrack.id) {
177
- toast.push({
178
- title: 'No audio track found',
179
- status: 'error',
180
- description:
181
- 'The asset does not have an audio track. Auto-generated subtitles require an audio track.',
182
- })
183
- throw new Error('No audio track found')
184
- }
185
-
186
- await generateSubtitles(client, asset.assetId, audioTrack.id, {
187
- language_code: languageCode.trim(),
188
- name: name.trim(),
189
- })
190
-
191
- const mockTrackId = `generating-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`
192
- const mockTrack: MuxTextTrack = {
193
- type: 'text',
194
- id: mockTrackId,
195
- text_type: 'subtitles',
196
- text_source: 'generated_live',
197
- language_code: languageCode.trim(),
198
- name: name.trim(),
199
- status: 'preparing',
200
- }
201
-
202
- toast.push({
203
- title: 'Generating subtitles',
204
- status: 'success',
205
- description: 'This may take a few minutes',
206
- })
207
-
208
- onAdd(mockTrack)
209
- onClose()
210
- }
211
-
212
- const handleSubmit = async () => {
213
- if (!isAutogenerated) {
214
- if (!selectedFile && !vttUrl.trim()) {
215
- toast.push({
216
- title: 'Caption file or URL required',
217
- status: 'error',
218
- description: 'Please select a VTT or SRT file or enter a caption file URL',
219
- })
220
- return
221
- }
222
-
223
- if (vttUrl.trim() && !selectedFile) {
224
- try {
225
- void new URL(vttUrl.trim())
226
- } catch {
227
- toast.push({
228
- title: 'Invalid URL',
229
- status: 'error',
230
- description:
231
- 'Please enter a valid URL (e.g., https://example.com/subtitles.vtt or subtitles.srt)',
232
- })
233
- return
234
- }
235
- }
236
- }
237
-
238
- if (!name.trim()) {
239
- toast.push({
240
- title: 'Audio name required',
241
- status: 'error',
242
- description: 'Please enter an audio name for this caption track',
243
- })
244
- return
245
- }
246
-
247
- if (!languageCode.trim()) {
248
- toast.push({
249
- title: 'Language code required',
250
- status: 'error',
251
- description: 'Please enter a language code (e.g., en, es, fr)',
252
- })
253
- return
254
- }
255
-
256
- setIsSubmitting(true)
257
-
258
- try {
259
- if (isAutogenerated) {
260
- await handleGenerateSubtitles()
261
- } else {
262
- await handleAddTrackFromUrl()
263
- }
264
- } catch (error) {
265
- toast.push({
266
- title: 'Failed to add caption track',
267
- status: 'error',
268
- description: extractErrorMessage(error, 'Failed to add caption track'),
269
- })
270
- } finally {
271
- setIsSubmitting(false)
272
- }
273
- }
274
-
275
- return (
276
- <Dialog
277
- id={dialogId}
278
- header="Add Caption Track"
279
- onClose={onClose}
280
- width={1}
281
- onClickOutside={onClose}
282
- >
283
- <Stack padding={4} space={4}>
284
- <Stack space={2}>
285
- <Flex align="center" marginBottom={3}>
286
- <Checkbox
287
- id="autogenerated-checkbox"
288
- style={{display: 'block'}}
289
- checked={isAutogenerated}
290
- onChange={(e) => {
291
- setIsAutogenerated(e.currentTarget.checked)
292
- if (e.currentTarget.checked) {
293
- setVttUrl('')
294
- }
295
- }}
296
- disabled={isSubmitting}
297
- />
298
- <Flex flex={1} paddingLeft={2}>
299
- <Text>
300
- <label htmlFor="autogenerated-checkbox">Generate captions</label>
301
- </Text>
302
- </Flex>
303
- </Flex>
304
- {!isAutogenerated && (
305
- <Stack space={2}>
306
- <Card padding={3} marginBottom={2} tone="transparent" border radius={2}>
307
- <Flex align="center" justify="space-between">
308
- <Text size={1} muted>
309
- {selectedFile ? `Selected: ${selectedFile.name}` : 'No file selected'}
310
- </Text>
311
- <Button
312
- icon={UploadIcon}
313
- text="Select File"
314
- mode="ghost"
315
- tone="primary"
316
- fontSize={1}
317
- padding={2}
318
- onClick={() => fileInputRef.current?.click()}
319
- disabled={isSubmitting}
320
- />
321
- </Flex>
322
- <input
323
- ref={fileInputRef}
324
- type="file"
325
- accept=".vtt,text/vtt,.srt,application/x-subrip"
326
- style={{display: 'none'}}
327
- onChange={(e) => {
328
- if (e.target.files && e.target.files.length > 0 && !isSubmitting) {
329
- setSelectedFile(e.target.files[0])
330
- setVttUrl('')
331
- }
332
- }}
333
- />
334
- </Card>
335
- <Text size={1} muted style={{textAlign: 'center'}}>
336
- Or enter the caption file URL
337
- </Text>
338
- <Stack space={2}>
339
- <Label htmlFor="vtt-url">Caption File URL (.vtt or .srt)</Label>
340
- <TextInput
341
- id="vtt-url"
342
- placeholder="https://example.com/subtitles.vtt"
343
- value={vttUrl}
344
- onChange={(e) => {
345
- setVttUrl(e.currentTarget.value)
346
- setSelectedFile(null)
347
- }}
348
- disabled={isSubmitting}
349
- />
350
- </Stack>
351
- </Stack>
352
- )}
353
- </Stack>
354
-
355
- <Stack space={2}>
356
- <Label htmlFor="caption-name">Audio name</Label>
357
- <Autocomplete
358
- id="caption-name"
359
- value={selectedLanguage?.value || ''}
360
- onChange={(newValue) => {
361
- const options = isAutogenerated ? MUX_LANGUAGE_OPTIONS : LANGUAGE_OPTIONS
362
- const selected = options.find((opt) => opt.value === newValue)
363
- if (selected) {
364
- setSelectedLanguage(selected)
365
- setLanguageCode(selected.value)
366
- setName(selected.label)
367
- }
368
- }}
369
- options={isAutogenerated ? MUX_LANGUAGE_OPTIONS : LANGUAGE_OPTIONS}
370
- icon={TranslateIcon}
371
- placeholder="Select language"
372
- filterOption={(query, option) =>
373
- option.label.toLowerCase().indexOf(query.toLowerCase()) > -1 ||
374
- option.value.toLowerCase().indexOf(query.toLowerCase()) > -1
375
- }
376
- openButton
377
- renderValue={(value) =>
378
- (isAutogenerated ? MUX_LANGUAGE_OPTIONS : LANGUAGE_OPTIONS).find(
379
- (l) => l.value === value
380
- )?.label || value
381
- }
382
- renderOption={(option) => (
383
- <Card data-as="button" padding={3} radius={2} tone="inherit">
384
- <Text size={2} textOverflow="ellipsis">
385
- {option.label} ({option.value})
386
- </Text>
387
- </Card>
388
- )}
389
- disabled={isSubmitting}
390
- />
391
- </Stack>
392
-
393
- <Stack space={2}>
394
- <Label htmlFor="caption-language">Language Code</Label>
395
- <TextInput
396
- id="caption-language"
397
- placeholder="en-US"
398
- value={languageCode}
399
- onChange={(e) => {
400
- setLanguageCode(e.currentTarget.value)
401
- if (selectedLanguage && selectedLanguage.value !== e.currentTarget.value) {
402
- setSelectedLanguage(null)
403
- if (!name || name === selectedLanguage.label) {
404
- setName('')
405
- }
406
- }
407
- }}
408
- disabled={isSubmitting}
409
- />
410
- </Stack>
411
-
412
- <Flex gap={2} justify="flex-end" marginTop={2}>
413
- <Button text="Cancel" mode="ghost" onClick={onClose} disabled={isSubmitting} />
414
- <Button
415
- text="Add Caption Track"
416
- tone="primary"
417
- icon={
418
- isSubmitting ? (
419
- <Spinner
420
- style={{
421
- verticalAlign: 'middle',
422
- display: 'inline-block',
423
- marginBottom: '-3px',
424
- width: '1em',
425
- height: '1em',
426
- marginRight: '-6px',
427
- }}
428
- />
429
- ) : (
430
- <UploadIcon />
431
- )
432
- }
433
- onClick={handleSubmit}
434
- disabled={isSubmitting}
435
- />
436
- </Flex>
437
- </Stack>
438
- </Dialog>
439
- )
440
- }
@@ -1,23 +0,0 @@
1
- import {Dialog, Stack} from '@sanity/ui'
2
- import {useId} from 'react'
3
-
4
- import {useDialogStateContext} from '../context/DialogStateContext'
5
- import type {VideoAssetDocument} from '../util/types'
6
- import TextTracksManager from './TextTracksManager'
7
-
8
- export interface Props {
9
- asset: VideoAssetDocument
10
- }
11
-
12
- export default function CaptionsDialog({asset}: Props) {
13
- const {setDialogState} = useDialogStateContext()
14
- const dialogId = `CaptionsDialog${useId()}`
15
-
16
- return (
17
- <Dialog id={dialogId} header="Edit Captions" onClose={() => setDialogState(false)} width={1}>
18
- <Stack padding={4}>
19
- <TextTracksManager asset={asset} />
20
- </Stack>
21
- </Dialog>
22
- )
23
- }
@@ -1,19 +0,0 @@
1
- import {styled} from 'styled-components'
2
-
3
- import MuxLogo from './MuxLogo'
4
-
5
- const Logo = styled.span`
6
- display: inline-block;
7
- height: 0.8em;
8
- margin-right: 1em;
9
- transform: translate(0.3em, -0.2em);
10
- `
11
-
12
- export const Header = () => (
13
- <>
14
- <Logo>
15
- <MuxLogo height={13} />
16
- </Logo>
17
- API Credentials
18
- </>
19
- )