sanity-plugin-mux-input 3.0.5 → 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 (123) hide show
  1. package/dist/index.js +28 -28
  2. package/dist/index.js.map +1 -1
  3. package/package.json +5 -15
  4. package/dist/index.cjs +0 -5746
  5. package/dist/index.cjs.map +0 -1
  6. package/dist/index.d.cts +0 -288
  7. package/dist/index.d.cts.map +0 -1
  8. package/sanity.json +0 -8
  9. package/src/_exports/index.ts +0 -73
  10. package/src/actions/assets.ts +0 -152
  11. package/src/actions/secrets.ts +0 -110
  12. package/src/actions/upload.ts +0 -308
  13. package/src/clients/upChunkObservable.ts +0 -54
  14. package/src/components/AddCaptionDialog.tsx +0 -440
  15. package/src/components/CaptionsDialog.tsx +0 -23
  16. package/src/components/ConfigureApi.styled.tsx +0 -19
  17. package/src/components/ConfigureApi.tsx +0 -296
  18. package/src/components/DraggableWatermark.tsx +0 -885
  19. package/src/components/EditCaptionDialog.tsx +0 -511
  20. package/src/components/EditThumbnailDialog.tsx +0 -121
  21. package/src/components/ErrorBoundaryCard.tsx +0 -97
  22. package/src/components/FileInputButton.tsx +0 -54
  23. package/src/components/FileInputMenuItem.styled.tsx +0 -36
  24. package/src/components/FileInputMenuItem.tsx +0 -85
  25. package/src/components/FormField.tsx +0 -38
  26. package/src/components/IconInfo.tsx +0 -22
  27. package/src/components/ImportVideosFromMux.tsx +0 -339
  28. package/src/components/Input.styled.tsx +0 -22
  29. package/src/components/Input.tsx +0 -78
  30. package/src/components/InputBrowser.tsx +0 -41
  31. package/src/components/MuxLogo.tsx +0 -42
  32. package/src/components/Onboard.tsx +0 -65
  33. package/src/components/PageSelector.tsx +0 -54
  34. package/src/components/Player.styled.tsx +0 -11
  35. package/src/components/Player.tsx +0 -117
  36. package/src/components/PlayerActionsMenu.tsx +0 -191
  37. package/src/components/ResyncMetadata.tsx +0 -278
  38. package/src/components/SelectAsset.tsx +0 -39
  39. package/src/components/SelectSortOptions.tsx +0 -45
  40. package/src/components/SpinnerBox.tsx +0 -16
  41. package/src/components/StudioTool.tsx +0 -24
  42. package/src/components/TextTracksEditor.tsx +0 -117
  43. package/src/components/TextTracksManager.tsx +0 -738
  44. package/src/components/UploadConfiguration.tsx +0 -696
  45. package/src/components/UploadPlaceholder.tsx +0 -88
  46. package/src/components/UploadProgress.tsx +0 -80
  47. package/src/components/Uploader.styled.tsx +0 -65
  48. package/src/components/Uploader.tsx +0 -499
  49. package/src/components/VideoDetails/DeleteDialog.tsx +0 -148
  50. package/src/components/VideoDetails/VideoDetails.tsx +0 -358
  51. package/src/components/VideoDetails/VideoReferences.tsx +0 -63
  52. package/src/components/VideoDetails/useVideoDetails.ts +0 -103
  53. package/src/components/VideoInBrowser.tsx +0 -245
  54. package/src/components/VideoMetadata.tsx +0 -45
  55. package/src/components/VideoPlayer.tsx +0 -241
  56. package/src/components/VideoThumbnail.tsx +0 -139
  57. package/src/components/VideosBrowser.tsx +0 -100
  58. package/src/components/documentPreview/DocumentPreview.tsx +0 -84
  59. package/src/components/documentPreview/DraftStatus.tsx +0 -34
  60. package/src/components/documentPreview/MissingSchemaType.tsx +0 -32
  61. package/src/components/documentPreview/PaneItemPreview.tsx +0 -67
  62. package/src/components/documentPreview/PublishedStatus.tsx +0 -35
  63. package/src/components/documentPreview/TimeAgo.tsx +0 -12
  64. package/src/components/icons/Audio.tsx +0 -13
  65. package/src/components/icons/Resolution.tsx +0 -12
  66. package/src/components/icons/StopWatch.tsx +0 -20
  67. package/src/components/icons/ToolIcon.tsx +0 -19
  68. package/src/components/uploadConfiguration/PlaybackPolicy.tsx +0 -133
  69. package/src/components/uploadConfiguration/PlaybackPolicyOption.tsx +0 -76
  70. package/src/components/uploadConfiguration/PlaybackPolicyWarning.tsx +0 -29
  71. package/src/components/uploadConfiguration/ResolutionTierSelector.tsx +0 -72
  72. package/src/components/uploadConfiguration/StaticRenditionSelector.tsx +0 -180
  73. package/src/components/withFocusRing/helpers.ts +0 -24
  74. package/src/components/withFocusRing/index.ts +0 -1
  75. package/src/components/withFocusRing/withFocusRing.ts +0 -30
  76. package/src/context/DialogStateContext.tsx +0 -33
  77. package/src/context/DrmPlaybackWarningContext.tsx +0 -97
  78. package/src/hooks/useAccessControl.ts +0 -13
  79. package/src/hooks/useAssetDocumentValues.ts +0 -11
  80. package/src/hooks/useAssets.ts +0 -73
  81. package/src/hooks/useCancelUpload.ts +0 -22
  82. package/src/hooks/useClient.ts +0 -8
  83. package/src/hooks/useDialogState.ts +0 -11
  84. package/src/hooks/useDocReferences.ts +0 -21
  85. package/src/hooks/useFetchFileSize.ts +0 -55
  86. package/src/hooks/useImportMuxAssets.ts +0 -132
  87. package/src/hooks/useInView.ts +0 -41
  88. package/src/hooks/useMediaMetadata.ts +0 -104
  89. package/src/hooks/useMuxAssets.ts +0 -179
  90. package/src/hooks/useMuxPolling.ts +0 -52
  91. package/src/hooks/useResyncAsset.ts +0 -110
  92. package/src/hooks/useResyncMuxMetadata.ts +0 -169
  93. package/src/hooks/useSaveSecrets.ts +0 -78
  94. package/src/hooks/useSecretsDocumentValues.ts +0 -38
  95. package/src/hooks/useSecretsFormState.ts +0 -47
  96. package/src/plugin.tsx +0 -31
  97. package/src/sanity-ui.d.ts +0 -5
  98. package/src/schema.ts +0 -196
  99. package/src/util/addKeysToMuxData.ts +0 -30
  100. package/src/util/asserters.ts +0 -23
  101. package/src/util/assetTitlePlaceholder.ts +0 -31
  102. package/src/util/constants.ts +0 -15
  103. package/src/util/convertWatermarkToMux.ts +0 -160
  104. package/src/util/createSearchFilter.ts +0 -76
  105. package/src/util/createUrlParamsObject.ts +0 -29
  106. package/src/util/extractFiles.ts +0 -67
  107. package/src/util/formatBytes.ts +0 -31
  108. package/src/util/formatDriveShareLink.ts +0 -64
  109. package/src/util/formatSeconds.ts +0 -48
  110. package/src/util/generateJwt.ts +0 -57
  111. package/src/util/getAnimatedPosterSrc.ts +0 -26
  112. package/src/util/getPlaybackPolicy.ts +0 -69
  113. package/src/util/getPosterSrc.ts +0 -28
  114. package/src/util/getVideoMetadata.ts +0 -23
  115. package/src/util/getVideoSrc.ts +0 -23
  116. package/src/util/parsers.ts +0 -5
  117. package/src/util/pluginVersion.ts +0 -5
  118. package/src/util/readSecrets.ts +0 -38
  119. package/src/util/roundPxString.ts +0 -16
  120. package/src/util/textTracks.ts +0 -222
  121. package/src/util/tryWithSuspend.ts +0 -22
  122. package/src/util/types.ts +0 -566
  123. package/v2-incompatible.js +0 -11
@@ -1,132 +0,0 @@
1
- import {uuid} from '@sanity/uuid'
2
- import {useMemo, useState} from 'react'
3
- import {
4
- createHookFromObservableFactory,
5
- type DocumentStore,
6
- useClient,
7
- useDocumentStore,
8
- } from 'sanity'
9
-
10
- import {generateAssetPlaceholder} from '../util/assetTitlePlaceholder'
11
- import {parseMuxDate} from '../util/parsers'
12
- import type {MuxAsset, VideoAssetDocument} from '../util/types'
13
- import {SANITY_API_VERSION} from './useClient'
14
- import useMuxAssets from './useMuxAssets'
15
- import {useSecretsDocumentValues} from './useSecretsDocumentValues'
16
-
17
- type ImportState = 'closed' | 'idle' | 'importing' | 'done' | 'error'
18
-
19
- export type AssetInSanity = {
20
- uploadId: string
21
- assetId: string
22
- }
23
-
24
- export default function useImportMuxAssets() {
25
- const documentStore = useDocumentStore()
26
- const client = useClient({
27
- apiVersion: SANITY_API_VERSION,
28
- })
29
-
30
- const [assetsInSanity, assetsInSanityLoading] = useAssetsInSanity(documentStore)
31
-
32
- const secretDocumentValues = useSecretsDocumentValues()
33
- const hasSecrets = !!secretDocumentValues.value.secrets?.secretKey
34
-
35
- const [importError, setImportError] = useState<unknown>()
36
- const [importState, setImportState] = useState<ImportState>('closed')
37
- const dialogOpen = importState !== 'closed'
38
-
39
- const muxAssets = useMuxAssets({
40
- client,
41
- enabled: hasSecrets && dialogOpen,
42
- })
43
-
44
- const missingAssets = useMemo(() => {
45
- return assetsInSanity && muxAssets.data
46
- ? muxAssets.data.filter((a) => !assetExistsInSanity(a, assetsInSanity))
47
- : undefined
48
- }, [assetsInSanity, muxAssets.data])
49
-
50
- const [selectedAssets, setSelectedAssets] = useState<MuxAsset[]>([])
51
-
52
- const closeDialog = () => {
53
- if (importState !== 'importing') setImportState('closed')
54
- }
55
- const openDialog = () => {
56
- if (importState === 'closed') setImportState('idle')
57
- }
58
-
59
- async function importAssets() {
60
- setImportState('importing')
61
- const documents = selectedAssets.flatMap((asset) => muxAssetToSanityDocument(asset) || [])
62
-
63
- const tx = client.transaction()
64
- documents.forEach((doc) => tx.create(doc))
65
-
66
- try {
67
- await tx.commit({returnDocuments: false})
68
- setSelectedAssets([])
69
- setImportState('done')
70
- } catch (error) {
71
- setImportState('error')
72
- setImportError(error)
73
- }
74
- }
75
-
76
- return {
77
- assetsInSanityLoading,
78
- closeDialog,
79
- dialogOpen,
80
- importState,
81
- importError,
82
- hasSecrets,
83
- importAssets,
84
- missingAssets,
85
- muxAssets,
86
- openDialog,
87
- selectedAssets,
88
- setSelectedAssets,
89
- }
90
- }
91
-
92
- function muxAssetToSanityDocument(asset: MuxAsset): VideoAssetDocument | undefined {
93
- const playbackId = (asset.playback_ids || []).find((p) => p.id)?.id
94
-
95
- if (!playbackId) return undefined
96
-
97
- return {
98
- _id: uuid(),
99
- _type: 'mux.videoAsset',
100
- _updatedAt: new Date().toISOString(),
101
- _createdAt: parseMuxDate(asset.created_at).toISOString(),
102
- assetId: asset.id,
103
- playbackId,
104
- filename: asset.meta?.title ?? generateAssetPlaceholder(asset.id),
105
- status: asset.status,
106
- data: asset,
107
- }
108
- }
109
-
110
- const useAssetsInSanity = createHookFromObservableFactory<AssetInSanity[], DocumentStore>(
111
- (documentStore) => {
112
- return documentStore.listenQuery(
113
- /* groq */ `*[_type == "mux.videoAsset"] {
114
- "uploadId": coalesce(uploadId, data.upload_id),
115
- "assetId": coalesce(assetId, data.id),
116
- }`,
117
- {},
118
- {
119
- apiVersion: SANITY_API_VERSION,
120
- },
121
- )
122
- },
123
- )
124
-
125
- function assetExistsInSanity(asset: MuxAsset, existingAssets: AssetInSanity[]) {
126
- // Don't allow importing assets that are not ready
127
- if (asset.status !== 'ready') return false
128
-
129
- return existingAssets.some(
130
- (existing) => existing.assetId === asset.id || existing.uploadId === asset.upload_id,
131
- )
132
- }
@@ -1,41 +0,0 @@
1
- import {useEffect, useState} from 'react'
2
-
3
- type IntersectionOptions = {
4
- root?: Element | null
5
- rootMargin?: string
6
- threshold?: number
7
- onChange?: (inView: boolean) => void
8
- }
9
-
10
- export function useInView(
11
- ref: React.RefObject<HTMLDivElement | null>,
12
- options: IntersectionOptions = {},
13
- ) {
14
- const [inView, setInView] = useState(false)
15
-
16
- useEffect(() => {
17
- if (!ref.current) return
18
-
19
- const observer = new IntersectionObserver(([entry], obs) => {
20
- // ==== from react-intersection-observer ====
21
- // While it would be nice if you could just look at isIntersecting to determine if the component is inside the viewport, browsers can't agree on how to use it.
22
- // -Firefox ignores `threshold` when considering `isIntersecting`, so it will never be false again if `threshold` is > 0
23
- const nowInView =
24
- entry!.isIntersecting &&
25
- obs.thresholds.some((threshold) => entry!.intersectionRatio >= threshold)
26
-
27
- // Update our state when observer callback fires
28
- setInView(nowInView)
29
- options?.onChange?.(nowInView)
30
- }, options)
31
-
32
- const toObserve = ref.current
33
- observer.observe(toObserve)
34
-
35
- return () => {
36
- if (toObserve) observer.unobserve(toObserve)
37
- }
38
- }, [options, ref])
39
-
40
- return inView
41
- }
@@ -1,104 +0,0 @@
1
- import {useEffect, useState} from 'react'
2
-
3
- import {type StagedUpload} from '../components/Uploader'
4
-
5
- export interface VideoAssetMetadata {
6
- width?: number
7
- height?: number
8
- isAudioOnly?: boolean
9
- duration?: number
10
- size?: number
11
- aspectRatio?: number
12
- }
13
-
14
- export function useMediaMetadata(stagedUpload: StagedUpload) {
15
- const [videoAssetMetadata, setVideoAssetMetadata] = useState<VideoAssetMetadata | null>(null)
16
- const [isLoadingMetadata, setIsLoadingMetadata] = useState(false)
17
- useEffect(() => {
18
- let videoSrc = null
19
- // Validate file uploads
20
- if (stagedUpload.type === 'file') {
21
- const file = stagedUpload.files[0]
22
- videoSrc = URL.createObjectURL(file!)
23
- }
24
-
25
- // Validate URL uploads
26
- if (stagedUpload.type === 'url') {
27
- videoSrc = stagedUpload.url
28
- }
29
-
30
- // oxlint-disable-next-line react/react-compiler
31
- setVideoAssetMetadata((old) => ({
32
- ...old,
33
- duration: undefined,
34
- width: undefined,
35
- height: undefined,
36
- }))
37
-
38
- if (!videoSrc) return () => null
39
-
40
- setIsLoadingMetadata(true)
41
- const videoElement = document.createElement('video')
42
- videoElement.preload = 'metadata'
43
-
44
- const metadataListeners = [
45
- () => {
46
- setIsLoadingMetadata(false)
47
- },
48
- () => {
49
- const duration = videoElement.duration
50
- const width = videoElement.videoWidth
51
- const height = videoElement.videoHeight
52
- const isAudioOnly = width <= 0 && height <= 0
53
- const aspectRatio = width / height
54
- setVideoAssetMetadata((old) => {
55
- return {
56
- ...old,
57
- duration: duration,
58
- width: width,
59
- height: height,
60
- isAudioOnly: isAudioOnly,
61
- aspectRatio: aspectRatio,
62
- }
63
- })
64
- },
65
- ]
66
-
67
- const cleanupVideo = (videoEl: HTMLVideoElement) => {
68
- const currentVideoSrc = videoEl?.src
69
- if (videoEl) {
70
- metadataListeners.forEach((listener) =>
71
- videoEl.removeEventListener('loadedmetadata', listener),
72
- )
73
- videoEl.onerror = null
74
- videoEl.src = ''
75
- videoEl.load()
76
- }
77
- if (currentVideoSrc?.startsWith('blob:')) {
78
- URL.revokeObjectURL(currentVideoSrc)
79
- }
80
- }
81
- metadataListeners.push(() => setTimeout(() => cleanupVideo(videoElement), 0))
82
-
83
- videoElement.onerror = () => {
84
- setIsLoadingMetadata(false)
85
- console.warn('Could not read video metadata for validation')
86
- cleanupVideo(videoElement)
87
- }
88
-
89
- metadataListeners.forEach((listener) =>
90
- videoElement.addEventListener('loadedmetadata', listener),
91
- )
92
- videoElement.src = videoSrc
93
-
94
- return () => {
95
- cleanupVideo(videoElement)
96
- }
97
- }, [stagedUpload.type, stagedUpload])
98
-
99
- return {
100
- videoAssetMetadata,
101
- setVideoAssetMetadata,
102
- isLoadingMetadata,
103
- }
104
- }
@@ -1,179 +0,0 @@
1
- import {useEffect, useState} from 'react'
2
- import {defer, of, timer} from 'rxjs'
3
- import {concatMap, expand, tap} from 'rxjs/operators'
4
- import type {SanityClient} from 'sanity'
5
-
6
- import {listAssets} from '../actions/assets'
7
- import type {MuxAsset} from '../util/types'
8
-
9
- const ASSETS_PER_PAGE = 100
10
-
11
- type MuxAssetsState = {
12
- cursor: string | null
13
- loading: boolean
14
- data?: MuxAsset[]
15
- error?: FetchError
16
- hasSkippedAssetsWithoutPlayback?: boolean
17
- }
18
-
19
- type FetchError =
20
- | {
21
- _tag: 'FetchError'
22
- }
23
- | {_tag: 'MuxError'; error: unknown}
24
-
25
- type PageResult = (
26
- | {
27
- data: MuxAsset[]
28
- next_cursor: string | null
29
- }
30
- | {
31
- error: FetchError
32
- }
33
- ) & {
34
- cursor: string | null
35
- }
36
-
37
- /**
38
- * @docs {@link https://docs.mux.com/api-reference#video/operation/list-assets}
39
- */
40
- async function fetchMuxAssetsPage(
41
- client: SanityClient,
42
- cursor: string | null,
43
- ): Promise<PageResult> {
44
- try {
45
- const response = await listAssets(client, {
46
- limit: ASSETS_PER_PAGE,
47
- cursor,
48
- })
49
-
50
- return {
51
- cursor,
52
- data: response.data,
53
- next_cursor: response.next_cursor || null,
54
- }
55
- } catch {
56
- return {
57
- cursor,
58
- error: {_tag: 'FetchError'},
59
- }
60
- }
61
- }
62
-
63
- function accumulateIntermediateState(
64
- currentState: MuxAssetsState,
65
- pageResult: PageResult,
66
- ): MuxAssetsState {
67
- const currentData = ('data' in currentState && currentState.data) || []
68
- const newAssets = ('data' in pageResult && pageResult.data) || []
69
-
70
- // Filter assets and check for skipped items
71
- const {validAssets, skippedInThisPage} = newAssets.reduce<{
72
- validAssets: MuxAsset[]
73
- skippedInThisPage: boolean
74
- }>(
75
- (acc, asset) => {
76
- const hasPlaybackIds = asset.playback_ids && asset.playback_ids.length > 0
77
- const isDuplicate = currentData.some((a) => a.id === asset.id)
78
-
79
- if (!hasPlaybackIds) {
80
- acc.skippedInThisPage = true
81
- }
82
-
83
- if (hasPlaybackIds && !isDuplicate) {
84
- acc.validAssets.push(asset)
85
- }
86
-
87
- return acc
88
- },
89
- {validAssets: [], skippedInThisPage: false},
90
- )
91
-
92
- return {
93
- ...currentState,
94
- data: [...currentData, ...validAssets],
95
- error:
96
- 'error' in pageResult
97
- ? pageResult.error
98
- : // Reset error if current page is successful
99
- undefined,
100
- cursor: 'next_cursor' in pageResult ? pageResult.next_cursor : pageResult.cursor,
101
- loading: true,
102
- hasSkippedAssetsWithoutPlayback:
103
- currentState.hasSkippedAssetsWithoutPlayback || skippedInThisPage,
104
- }
105
- }
106
-
107
- function hasMorePages(pageResult: PageResult) {
108
- return (
109
- typeof pageResult === 'object' && 'next_cursor' in pageResult && pageResult.next_cursor !== null
110
- )
111
- }
112
-
113
- /**
114
- * Fetches all assets from a Mux environment. Rules:
115
- * - One page at a time
116
- * - Uses cursor-based pagination
117
- * - We've finished fetching when `next_cursor` is null
118
- * - Rate limiting to one request per 2 seconds
119
- * - Update state while still fetching to give feedback to users
120
- */
121
- export default function useMuxAssets({client, enabled}: {client: SanityClient; enabled: boolean}) {
122
- const [state, setState] = useState<MuxAssetsState>({loading: true, cursor: null})
123
-
124
- useEffect(() => {
125
- if (!enabled) return
126
-
127
- const subscription = defer(() =>
128
- fetchMuxAssetsPage(
129
- client,
130
- // When we've already successfully loaded before (fully or partially), we start from the next cursor to avoid re-fetching
131
- 'data' in state && state.data && state.data.length > 0 && !state.error
132
- ? state.cursor
133
- : null,
134
- ),
135
- )
136
- .pipe(
137
- // Here we use "expand" to recursively fetch next pages
138
- expand((pageResult) => {
139
- // if fetched page has next_cursor, we continue emitting, requesting the next page
140
- // after 2s to avoid rate limiting
141
- if (hasMorePages(pageResult)) {
142
- return timer(2000).pipe(
143
- concatMap(() =>
144
- defer(() =>
145
- fetchMuxAssetsPage(
146
- client,
147
- 'next_cursor' in pageResult ? pageResult.next_cursor : null,
148
- ),
149
- ),
150
- ),
151
- )
152
- }
153
-
154
- // Else, we stop emitting
155
- return of()
156
- }),
157
-
158
- // On each iteration, persist intermediate states to give feedback to users
159
- tap((pageResult) =>
160
- setState((prevState) => accumulateIntermediateState(prevState, pageResult)),
161
- ),
162
- )
163
- .subscribe({
164
- // Once done, let the user know we've stopped loading
165
- complete: () => {
166
- setState((prev) => ({
167
- ...prev,
168
- loading: false,
169
- }))
170
- },
171
- })
172
-
173
- // Unsubscribe on component unmount to prevent memory leaks or fetching unnecessarily
174
- return () => subscription.unsubscribe()
175
- // eslint-disable-next-line react-hooks/exhaustive-deps
176
- }, [enabled])
177
-
178
- return state
179
- }
@@ -1,52 +0,0 @@
1
- import {useMemo} from 'react'
2
- import {useDataset, useProjectId} from 'sanity'
3
- import useSWR from 'swr'
4
-
5
- import {useClient} from '../hooks/useClient'
6
- import {PLUGIN_VERSION_QUERY} from '../util/pluginVersion'
7
- import type {MuxAsset, VideoAssetDocument} from '../util/types'
8
-
9
- // Poll MUX if it's preparing the main document or its own static renditions
10
- export const useMuxPolling = (asset?: VideoAssetDocument) => {
11
- const client = useClient()
12
- const projectId = useProjectId()
13
- const dataset = useDataset()
14
- const isPreparingStaticRenditions = useMemo(() => {
15
- // Legacy: If static_renditions has a status field, it was created with mp4_support (deprecated)
16
- // We don't process this old format, just return false
17
- // Note: 'disabled' status is valid in the new format when no renditions were requested
18
- if (
19
- asset?.data?.static_renditions?.status &&
20
- asset?.data?.static_renditions?.status !== 'disabled'
21
- ) {
22
- return false
23
- }
24
-
25
- const files = asset?.data?.static_renditions?.files
26
- if (!files || files.length === 0) {
27
- return false
28
- }
29
- return files.some((file) => file.status === 'preparing')
30
- }, [asset?.data?.static_renditions?.status, asset?.data?.static_renditions?.files])
31
-
32
- const shouldFetch = useMemo(
33
- () => !!asset?.assetId && (asset?.status === 'preparing' || isPreparingStaticRenditions),
34
- [asset?.assetId, asset?.status, isPreparingStaticRenditions],
35
- )
36
- return useSWR(
37
- shouldFetch ? `/${projectId}/addons/mux/assets/${dataset}/data/${asset?.assetId}` : null,
38
- async () => {
39
- const {data} = await client.request<{data: MuxAsset}>({
40
- url: `/addons/mux/assets/${dataset}/data/${asset!.assetId}`,
41
- withCredentials: true,
42
- method: 'GET',
43
- query: PLUGIN_VERSION_QUERY,
44
- })
45
- await client
46
- .patch(asset!._id)
47
- .set({status: data.status, data})
48
- .commit({returnDocuments: false})
49
- },
50
- {refreshInterval: 2000, refreshWhenHidden: true, dedupingInterval: 1000},
51
- )
52
- }
@@ -1,110 +0,0 @@
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
- }