sanity-plugin-mux-input 2.10.1 → 2.11.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/dist/index.d.mts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +57 -34
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +57 -34
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/_exports/index.ts +1 -0
- package/src/components/UploadConfiguration.tsx +1 -1
- package/src/components/UploadProgress.tsx +5 -0
- package/src/components/Uploader.tsx +38 -4
- package/src/components/VideoPlayer.tsx +9 -5
- package/src/util/types.ts +6 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sanity-plugin-mux-input",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"description": "An input component that integrates Sanity Studio with Mux video encoding/hosting service.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"watch": "pkg-utils watch --strict"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@mux/mux-player-react": "^
|
|
55
|
+
"@mux/mux-player-react": "^3.8.0",
|
|
56
56
|
"@mux/upchunk": "^3.4.0",
|
|
57
57
|
"@sanity/icons": "^3.0.0",
|
|
58
58
|
"@sanity/incompatible-plugin": "^1.0.4",
|
package/src/_exports/index.ts
CHANGED
|
@@ -143,7 +143,7 @@ export default function UploadConfiguration({
|
|
|
143
143
|
max_resolution_tier: pluginConfig.max_resolution_tier,
|
|
144
144
|
mp4_support: pluginConfig.mp4_support,
|
|
145
145
|
signed_policy: secrets.enableSignedUrls && pluginConfig.defaultSigned,
|
|
146
|
-
public_policy:
|
|
146
|
+
public_policy: pluginConfig.defaultPublic,
|
|
147
147
|
normalize_audio: pluginConfig.normalize_audio,
|
|
148
148
|
text_tracks: autoTextTracks,
|
|
149
149
|
} as UploadConfig
|
|
@@ -42,6 +42,10 @@ export const UploadProgress = ({
|
|
|
42
42
|
onCancel?: React.MouseEventHandler<HTMLButtonElement>
|
|
43
43
|
text?: React.ReactNode
|
|
44
44
|
}) => {
|
|
45
|
+
// Disable cancel button when upload is 90% or more complete
|
|
46
|
+
// to prevent inconsistency between Mux and Sanity
|
|
47
|
+
const isCancelDisabled = progress >= 90
|
|
48
|
+
|
|
45
49
|
return (
|
|
46
50
|
<CardWrapper tone="primary" padding={4} border height="fill">
|
|
47
51
|
<FlexWrapper align="center" justify="space-between" height="fill" direction="row" gap={2}>
|
|
@@ -67,6 +71,7 @@ export const UploadProgress = ({
|
|
|
67
71
|
mode="ghost"
|
|
68
72
|
tone="critical"
|
|
69
73
|
onClick={onCancel}
|
|
74
|
+
disabled={isCancelDisabled}
|
|
70
75
|
/>
|
|
71
76
|
) : null}
|
|
72
77
|
</FlexWrapper>
|
|
@@ -92,6 +92,7 @@ export default function Uploader(props: Props) {
|
|
|
92
92
|
).current
|
|
93
93
|
|
|
94
94
|
const uploadRef = useRef<Subscription | null>(null)
|
|
95
|
+
const uploadingDocumentId = useRef<string | null>(null)
|
|
95
96
|
const [state, dispatch] = useReducer(
|
|
96
97
|
(prev: State, action: UploaderStateAction) => {
|
|
97
98
|
switch (action.action) {
|
|
@@ -121,11 +122,13 @@ export default function Uploader(props: Props) {
|
|
|
121
122
|
// Clear upload observable on completion
|
|
122
123
|
uploadRef.current?.unsubscribe()
|
|
123
124
|
uploadRef.current = null
|
|
125
|
+
uploadingDocumentId.current = null
|
|
124
126
|
return INITIAL_STATE
|
|
125
127
|
case 'error':
|
|
126
128
|
// Clear upload observable on error
|
|
127
129
|
uploadRef.current?.unsubscribe()
|
|
128
130
|
uploadRef.current = null
|
|
131
|
+
uploadingDocumentId.current = null
|
|
129
132
|
return Object.assign({}, INITIAL_STATE, {error: action.error})
|
|
130
133
|
default:
|
|
131
134
|
return prev
|
|
@@ -139,13 +142,38 @@ export default function Uploader(props: Props) {
|
|
|
139
142
|
)
|
|
140
143
|
|
|
141
144
|
// Make sure we close out the upload observer on dismount
|
|
145
|
+
// and cleanup orphaned documents if upload was in progress
|
|
142
146
|
useEffect(() => {
|
|
143
|
-
|
|
147
|
+
const cleanup = () => {
|
|
148
|
+
// Cancel subscription
|
|
144
149
|
if (uploadRef.current && !uploadRef.current.closed) {
|
|
145
150
|
uploadRef.current.unsubscribe()
|
|
146
151
|
}
|
|
152
|
+
|
|
153
|
+
// Delete orphaned document if upload was in progress and document is different from the saved asset
|
|
154
|
+
if (uploadingDocumentId.current && props.asset?._id !== uploadingDocumentId.current) {
|
|
155
|
+
const docId = uploadingDocumentId.current
|
|
156
|
+
uploadingDocumentId.current = null
|
|
157
|
+
|
|
158
|
+
props.client.delete(docId).catch((err) => {
|
|
159
|
+
console.warn('Failed to cleanup orphaned upload document:', err)
|
|
160
|
+
})
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const handleBeforeUnload = () => {
|
|
165
|
+
cleanup()
|
|
147
166
|
}
|
|
148
|
-
|
|
167
|
+
|
|
168
|
+
window.addEventListener('beforeunload', handleBeforeUnload)
|
|
169
|
+
window.addEventListener('pagehide', handleBeforeUnload)
|
|
170
|
+
|
|
171
|
+
return () => {
|
|
172
|
+
window.removeEventListener('beforeunload', handleBeforeUnload)
|
|
173
|
+
window.removeEventListener('pagehide', handleBeforeUnload)
|
|
174
|
+
cleanup()
|
|
175
|
+
}
|
|
176
|
+
}, [props.client, props.asset?._id])
|
|
149
177
|
|
|
150
178
|
/* -------------------------------------------------------------------------- */
|
|
151
179
|
/* Uploading */
|
|
@@ -183,8 +211,9 @@ export default function Uploader(props: Props) {
|
|
|
183
211
|
takeUntil(
|
|
184
212
|
cancelUploadButton.observable.pipe(
|
|
185
213
|
tap(() => {
|
|
186
|
-
if (
|
|
187
|
-
props.client.delete(
|
|
214
|
+
if (uploadingDocumentId.current) {
|
|
215
|
+
props.client.delete(uploadingDocumentId.current)
|
|
216
|
+
uploadingDocumentId.current = null
|
|
188
217
|
}
|
|
189
218
|
})
|
|
190
219
|
)
|
|
@@ -196,6 +225,10 @@ export default function Uploader(props: Props) {
|
|
|
196
225
|
next: (event) => {
|
|
197
226
|
switch (event.type) {
|
|
198
227
|
case 'uuid':
|
|
228
|
+
// Track the document ID for cleanup on unmount
|
|
229
|
+
uploadingDocumentId.current = event.uuid
|
|
230
|
+
dispatch({action: 'progressInfo', ...event})
|
|
231
|
+
break
|
|
199
232
|
case 'file':
|
|
200
233
|
case 'url':
|
|
201
234
|
dispatch({action: 'progressInfo', ...event})
|
|
@@ -205,6 +238,7 @@ export default function Uploader(props: Props) {
|
|
|
205
238
|
break
|
|
206
239
|
case 'success':
|
|
207
240
|
dispatch({action: 'progress', percent: 100})
|
|
241
|
+
uploadingDocumentId.current = null
|
|
208
242
|
props.onChange(
|
|
209
243
|
PatchEvent.from([
|
|
210
244
|
setIfMissing({asset: {}}),
|
|
@@ -26,19 +26,23 @@ export default function VideoPlayer({
|
|
|
26
26
|
|
|
27
27
|
const isAudio = assetIsAudio(asset)
|
|
28
28
|
const muxPlayer = useRef<MuxPlayerRefAttributes>(null)
|
|
29
|
-
const thumbnail = getPosterSrc({asset, client, width: thumbnailWidth})
|
|
30
29
|
|
|
31
|
-
const {
|
|
30
|
+
const {
|
|
31
|
+
src: videoSrc,
|
|
32
|
+
thumbnail: thumbnailSrc,
|
|
33
|
+
error,
|
|
34
|
+
} = useMemo(() => {
|
|
32
35
|
try {
|
|
36
|
+
const thumbnail = getPosterSrc({asset, client, width: thumbnailWidth})
|
|
33
37
|
const src = asset?.playbackId && getVideoSrc({client, asset})
|
|
34
|
-
if (src) return {src: src}
|
|
38
|
+
if (src) return {src: src, thumbnail}
|
|
35
39
|
|
|
36
40
|
return {error: new TypeError('Asset has no playback ID')}
|
|
37
41
|
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
38
42
|
} catch (error) {
|
|
39
43
|
return {error}
|
|
40
44
|
}
|
|
41
|
-
}, [asset, client])
|
|
45
|
+
}, [asset, client, thumbnailWidth])
|
|
42
46
|
|
|
43
47
|
const signedToken = useMemo(() => {
|
|
44
48
|
try {
|
|
@@ -66,7 +70,7 @@ export default function VideoPlayer({
|
|
|
66
70
|
{videoSrc && (
|
|
67
71
|
<>
|
|
68
72
|
<MuxPlayer
|
|
69
|
-
poster={
|
|
73
|
+
poster={thumbnailSrc}
|
|
70
74
|
ref={muxPlayer}
|
|
71
75
|
{...props}
|
|
72
76
|
playsInline
|
package/src/util/types.ts
CHANGED
|
@@ -48,6 +48,12 @@ export interface MuxInputConfig {
|
|
|
48
48
|
*/
|
|
49
49
|
defaultSigned?: boolean
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Enables public URLs by default.
|
|
53
|
+
* @defaultValue true
|
|
54
|
+
*/
|
|
55
|
+
defaultPublic?: boolean
|
|
56
|
+
|
|
51
57
|
/**
|
|
52
58
|
* Auto-generate captions for these languages by default.
|
|
53
59
|
* Requires `"video_quality": "plus"`
|