sanity-plugin-mux-input 2.15.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.
@@ -0,0 +1,110 @@
1
+ import {useToast} from '@sanity/ui'
2
+ import {useCallback, useState} from 'react'
3
+
4
+ import {getAsset} from '../actions/assets'
5
+ import {addKeysToMuxData} from '../util/addKeysToMuxData'
6
+ import type {MuxAsset, VideoAssetDocument} from '../util/types'
7
+ import {useClient} from './useClient'
8
+
9
+ type ResyncAssetState = 'idle' | 'syncing' | 'success' | 'error'
10
+
11
+ interface UseResyncAssetOptions {
12
+ showToast?: boolean
13
+ onSuccess?: (updatedData: MuxAsset) => void
14
+ onError?: (error: unknown) => void
15
+ }
16
+
17
+ interface UseResyncAssetReturn {
18
+ resyncState: ResyncAssetState
19
+ resyncError: unknown
20
+ resyncAsset: (asset: VideoAssetDocument) => Promise<MuxAsset | undefined>
21
+ isResyncing: boolean
22
+ }
23
+
24
+ export function useResyncAsset(options?: UseResyncAssetOptions): UseResyncAssetReturn {
25
+ const client = useClient()
26
+ const toast = useToast()
27
+ const [resyncState, setResyncState] = useState<ResyncAssetState>('idle')
28
+ const [resyncError, setResyncError] = useState<unknown>(null)
29
+
30
+ const showToast = options?.showToast ?? false
31
+
32
+ const resyncAsset = useCallback(
33
+ async (asset: VideoAssetDocument) => {
34
+ if (!asset.assetId) {
35
+ if (showToast) {
36
+ toast.push({
37
+ title: 'Cannot resync',
38
+ description: 'Asset has no Mux ID',
39
+ status: 'error',
40
+ })
41
+ }
42
+ options?.onError?.(new Error('Asset has no Mux ID'))
43
+ return undefined
44
+ }
45
+
46
+ if (!asset._id) {
47
+ if (showToast) {
48
+ toast.push({
49
+ title: 'Cannot resync',
50
+ description: 'Asset has no document ID',
51
+ status: 'error',
52
+ })
53
+ }
54
+ options?.onError?.(new Error('Asset has no document ID'))
55
+ return undefined
56
+ }
57
+
58
+ setResyncState('syncing')
59
+ setResyncError(null)
60
+
61
+ try {
62
+ const response = await getAsset(client, asset.assetId)
63
+ const muxData = response.data
64
+ const dataWithKeys = addKeysToMuxData(muxData)
65
+
66
+ await client
67
+ .patch(asset._id)
68
+ .set({
69
+ status: muxData.status,
70
+ data: dataWithKeys,
71
+ ...(muxData.meta?.title && {filename: muxData.meta.title}),
72
+ })
73
+ .commit({returnDocuments: false})
74
+
75
+ setResyncState('success')
76
+ if (showToast) {
77
+ toast.push({
78
+ title: 'Asset synced',
79
+ description: 'Data has been updated from Mux',
80
+ status: 'success',
81
+ })
82
+ }
83
+
84
+ options?.onSuccess?.(muxData)
85
+ return muxData
86
+ } catch (error) {
87
+ setResyncState('error')
88
+ setResyncError(error)
89
+ console.error('Failed to refresh asset data:', error)
90
+ if (showToast) {
91
+ toast.push({
92
+ title: 'Sync failed',
93
+ description: 'Could not sync asset from Mux',
94
+ status: 'error',
95
+ })
96
+ }
97
+ options?.onError?.(error)
98
+ return undefined
99
+ }
100
+ },
101
+ [client, toast, options, showToast]
102
+ )
103
+
104
+ return {
105
+ resyncState,
106
+ resyncError,
107
+ resyncAsset,
108
+ isResyncing: resyncState === 'syncing',
109
+ }
110
+ }
@@ -6,6 +6,7 @@ import {
6
6
  useDocumentStore,
7
7
  } from 'sanity'
8
8
 
9
+ import {addKeysToMuxData} from '../util/addKeysToMuxData'
9
10
  import {isEmptyOrPlaceholderTitle} from '../util/assetTitlePlaceholder'
10
11
  import type {MuxAsset, VideoAssetDocument} from '../util/types'
11
12
  import {SANITY_API_VERSION} from './useClient'
@@ -115,6 +116,37 @@ export default function useResyncMuxMetadata() {
115
116
  }
116
117
  }
117
118
 
119
+ async function syncFullData() {
120
+ if (!matchedAssets) return
121
+
122
+ setResyncState('syncing')
123
+
124
+ try {
125
+ const tx = client.transaction()
126
+
127
+ matchedAssets.forEach((matched) => {
128
+ if (!matched.muxAsset) return
129
+
130
+ const dataWithKeys = addKeysToMuxData(matched.muxAsset)
131
+
132
+ // Update all fields: filename, status, and full data from Mux
133
+ tx.patch(matched.sanityDoc._id, {
134
+ set: {
135
+ filename: matched.muxTitle || matched.currentTitle || '',
136
+ status: matched.muxAsset.status,
137
+ data: dataWithKeys,
138
+ },
139
+ })
140
+ })
141
+
142
+ await tx.commit({returnDocuments: false})
143
+ setResyncState('done')
144
+ } catch (error) {
145
+ setResyncState('error')
146
+ setResyncError(error)
147
+ }
148
+ }
149
+
118
150
  return {
119
151
  sanityAssetsLoading,
120
152
  closeDialog,
@@ -124,6 +156,7 @@ export default function useResyncMuxMetadata() {
124
156
  hasSecrets,
125
157
  syncAllVideos,
126
158
  syncOnlyEmpty,
159
+ syncFullData,
127
160
  matchedAssets,
128
161
  muxAssets,
129
162
  openDialog,
package/src/schema.ts CHANGED
@@ -23,6 +23,11 @@ const muxTrack = {
23
23
  {type: 'number', name: 'max_frame_rate'},
24
24
  {type: 'number', name: 'duration'},
25
25
  {type: 'number', name: 'max_height'},
26
+ {type: 'string', name: 'language_code'},
27
+ {type: 'string', name: 'name'},
28
+ {type: 'string', name: 'status'},
29
+ {type: 'string', name: 'text_source'},
30
+ {type: 'string', name: 'text_type'},
26
31
  ],
27
32
  }
28
33
 
@@ -0,0 +1,30 @@
1
+ import {uuid} from '@sanity/uuid'
2
+
3
+ import type {MuxAsset} from './types'
4
+
5
+ /**
6
+ * Adds _key to array items in MuxAsset data for Sanity compatibility.
7
+ * Sanity requires _key on array items for proper editing support.
8
+ */
9
+ export function addKeysToMuxData(data: MuxAsset): MuxAsset {
10
+ return {
11
+ ...data,
12
+ tracks: data.tracks?.map((track) => ({
13
+ ...track,
14
+ _key: uuid(),
15
+ })),
16
+ playback_ids: data.playback_ids?.map((playbackId) => ({
17
+ ...playbackId,
18
+ _key: uuid(),
19
+ })),
20
+ static_renditions: data.static_renditions
21
+ ? {
22
+ ...data.static_renditions,
23
+ files: data.static_renditions.files?.map((file) => ({
24
+ ...file,
25
+ _key: uuid(),
26
+ })),
27
+ }
28
+ : undefined,
29
+ }
30
+ }