sanity-plugin-mux-input
4.1.74.1.8
dist/index.js.map~
dist/index.js.mapModified+1−1
Index: package/dist/index.js.map
===================================================================
--- package/dist/index.js.map
+++ package/dist/index.js.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"index.js","names":["useClient","useSanityClient","path","FormField","useClient","secretsId","FormField","Image","useClient","useClient","useClient","LANGUAGE_OPTIONS","useClient","useClient","useClient","useClient","useClient","useClient","useClient","FormField","useClient","uuid","generateUuid","SelectAsset","useClient","HiddenInput","Label","PlayerActionsMenu","useClient","ErrorBoundaryCard","Input"],"sources":["../src/components/icons/ToolIcon.tsx","../src/util/types.ts","../src/context/DrmPlaybackWarningContext.tsx","../src/hooks/useClient.ts","../src/util/createSearchFilter.ts","../src/hooks/useAssets.ts","../src/hooks/useDialogState.ts","../src/util/pluginVersion.ts","../src/actions/secrets.ts","../src/hooks/useSaveSecrets.ts","../src/util/constants.ts","../src/hooks/useSecretsDocumentValues.ts","../src/hooks/useSecretsFormState.ts","../src/util/readSecrets.ts","../src/components/MuxLogo.tsx","../src/components/ConfigureApi.styled.tsx","../src/components/FormField.tsx","../src/components/ConfigureApi.tsx","../src/util/assetTitlePlaceholder.ts","../src/util/parsers.ts","../src/actions/assets.ts","../src/hooks/useMuxAssets.ts","../src/hooks/useImportMuxAssets.ts","../src/hooks/useInView.ts","../src/util/getPlaybackPolicy.ts","../src/util/generateJwt.ts","../src/util/createUrlParamsObject.ts","../src/util/getAnimatedPosterSrc.ts","../src/util/getPosterSrc.ts","../src/util/tryWithSuspend.ts","../src/components/VideoThumbnail.tsx","../src/components/ImportVideosFromMux.tsx","../src/components/PageSelector.tsx","../src/util/addKeysToMuxData.ts","../src/hooks/useResyncMuxMetadata.ts","../src/components/ResyncMetadata.tsx","../src/components/SelectSortOptions.tsx","../src/components/SpinnerBox.tsx","../src/components/IconInfo.tsx","../src/components/icons/Resolution.tsx","../src/components/icons/StopWatch.tsx","../src/hooks/useMezzanine.ts","../src/components/MezzanineExplanation.tsx","../src/components/Mezzanine.tsx","../src/hooks/useResyncAsset.ts","../src/util/textTracks.ts","../src/components/AddCaptionDialog.tsx","../src/components/EditCaptionDialog.tsx","../src/components/TextTracksManager.tsx","../src/context/DialogStateContext.tsx","../src/util/getVideoSrc.ts","../src/components/CaptionsDialog.tsx","../src/util/formatSeconds.ts","../src/components/EditThumbnailDialog.tsx","../src/components/icons/Audio.tsx","../src/components/MezzanineDialog.tsx","../src/components/VideoPlayer.tsx","../src/components/documentPreview/MissingSchemaType.tsx","../src/components/documentPreview/TimeAgo.tsx","../src/components/documentPreview/DraftStatus.tsx","../src/components/documentPreview/PublishedStatus.tsx","../src/components/documentPreview/PaneItemPreview.tsx","../src/components/documentPreview/DocumentPreview.tsx","../src/components/VideoDetails/VideoReferences.tsx","../src/components/VideoDetails/DeleteDialog.tsx","../src/hooks/useDocReferences.ts","../src/util/getVideoMetadata.ts","../src/components/VideoDetails/useVideoDetails.ts","../src/components/VideoDetails/VideoDetails.tsx","../src/components/VideoMetadata.tsx","../src/components/VideoInBrowser.tsx","../src/components/VideosBrowser.tsx","../src/components/StudioTool.tsx","../src/hooks/useAccessControl.ts","../src/hooks/useAssetDocumentValues.ts","../src/hooks/useMuxPolling.ts","../src/components/ErrorBoundaryCard.tsx","../src/components/Input.styled.tsx","../src/components/Onboard.tsx","../src/clients/upChunkObservable.ts","../src/util/formatDriveShareLink.ts","../src/util/roundPxString.ts","../src/actions/upload.ts","../src/util/asserters.ts","../src/util/extractFiles.ts","../src/components/SelectAsset.tsx","../src/components/InputBrowser.tsx","../src/hooks/useCancelUpload.ts","../src/components/Player.styled.tsx","../src/components/UploadProgress.tsx","../src/components/Player.tsx","../src/components/withFocusRing/helpers.ts","../src/components/FileInputMenuItem.styled.tsx","../src/components/FileInputMenuItem.tsx","../src/components/PlayerActionsMenu.tsx","../src/hooks/useFetchFileSize.ts","../src/hooks/useMediaMetadata.ts","../src/util/convertWatermarkToMux.ts","../src/util/formatBytes.ts","../src/components/DraggableWatermark.tsx","../src/components/TextTracksEditor.tsx","../src/components/uploadConfiguration/PlaybackPolicyOption.tsx","../src/components/uploadConfiguration/PlaybackPolicyWarning.tsx","../src/components/uploadConfiguration/PlaybackPolicy.tsx","../src/components/uploadConfiguration/ResolutionTierSelector.tsx","../src/components/uploadConfiguration/StaticRenditionSelector.tsx","../src/components/UploadConfiguration.tsx","../src/components/withFocusRing/withFocusRing.ts","../src/components/Uploader.styled.tsx","../src/components/FileInputButton.tsx","../src/components/UploadPlaceholder.tsx","../src/components/Uploader.tsx","../src/components/Input.tsx","../src/plugin.tsx","../src/schema.ts","../src/_exports/index.ts"],"sourcesContent":["/**\n * Icon of a monitor with a play button.\n * Credits: material design icons & react-icons\n */\nconst ToolIcon = () => (\n <svg\n stroke=\"currentColor\"\n fill=\"currentColor\"\n strokeWidth=\"0\"\n viewBox=\"0 0 24 24\"\n height=\"1em\"\n width=\"1em\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M21 3H3c-1.11 0-2 .89-2 2v12c0 1.1.89 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.11-.9-2-2-2zm0 14H3V5h18v12zm-5-6l-7 4V7z\" />\n </svg>\n)\n\nexport default ToolIcon\n","import type MuxPlayerElement from '@mux/mux-player'\nimport type {ObjectInputProps} from 'sanity'\nimport type {PartialDeep} from 'type-fest'\n\n/**\n * All static rendition resolution options supported by Mux\n */\nexport type StaticRenditionResolution =\n | 'highest'\n | 'audio-only'\n | '270p'\n | '360p'\n | '480p'\n | '540p'\n | '720p'\n | '1080p'\n | '1440p'\n | '2160p'\n\nexport interface MuxInputConfig {\n /**\n * Enable static renditions by default. Can be overwritten on a per-asset basis.\n * Supports:\n * - Standard mode: 'highest' (up to 4K MP4) and/or 'audio-only' (M4A)\n * - Advanced mode: Specific resolutions ('270p', '360p', '480p', '540p', '720p', '1080p', '1440p', '2160p') and/or 'audio-only'\n *\n * **Important**: 'highest' cannot be mixed with specific resolutions. If both are provided, only 'highest' will be used.\n *\n * @see {@link https://docs.mux.com/guides/video/enable-static-mp4-renditions}\n * @defaultValue []\n */\n static_renditions: StaticRenditionResolution[]\n\n /**\n * @deprecated Use `static_renditions` instead. This field is kept for backward compatibility.\n * Enable static renditions by setting this to 'standard'. Can be overwritten on a per-asset basis.\n * Requires `\"video_quality\": \"plus\"`\n * @see {@link https://docs.mux.com/guides/video/enable-static-mp4-renditions#why-enable-mp4-support}\n * @defaultValue 'none'\n */\n mp4_support: 'none' | 'standard'\n\n /**\n * Max resolution tier can be used to control the maximum resolution_tier your asset is encoded, stored, and streamed at.\n * Requires `\"video_quality\": \"plus\"`\n * @see {@link https://docs.mux.com/guides/stream-videos-in-4k}\n * @defaultValue '1080p'\n */\n max_resolution_tier: '2160p' | '1440p' | '1080p'\n\n /**\n * @deprecated Use {@link video_quality}\n * <br>\n * The encoding tier informs the cost, quality, and available platform features for the asset.\n * @see {@link https://docs.mux.com/guides/use-encoding-tiers}\n * @defaultValue 'smart'\n */\n encoding_tier?: 'baseline' | 'smart'\n\n /**\n * The video quality level informs the cost, quality, and available platform features for the asset.\n * @see {@link https://www.mux.com/docs/guides/use-video-quality-levels}\n * @defaultValue 'plus'\n */\n video_quality: 'basic' | 'plus' | 'premium'\n\n /**\n * Normalize the audio track loudness level.\n * @see {@link https://docs.mux.com/guides/adjust-audio-levels#how-to-turn-on-audio-normalization}\n * @defaultValue false\n */\n normalize_audio: boolean\n\n /**\n * Enables signed URLs by default, if you configured them with your API token.\n * @see {@link https://docs.mux.com/guides/secure-video-playback}\n * @defaultValue false\n */\n defaultSigned?: boolean\n\n /**\n * Enables public URLs by default.\n * @defaultValue true\n */\n defaultPublic?: boolean\n\n /**\n * Enables DRM Protection by default, if you configured your DRM Configuration Id.\n * @see {@link https://www.mux.com/docs/guides/protect-videos-with-drm}\n * @defaultValue true\n */\n defaultDrm?: boolean\n\n /**\n * Auto-generate captions for these languages by default.\n * Requires `\"video_quality\": \"plus\"`\n *\n * @see {@link https://docs.mux.com/guides/add-autogenerated-captions-and-use-transcripts}\n * @deprecated use `defaultAutogeneratedSubtitleLang` instead. Only a single autogenerated\n */\n defaultAutogeneratedSubtitleLangs?: SupportedMuxLanguage[]\n\n /**\n * Auto-generate captions for this language by default. Users can still\n * Requires `\"video_quality\": \"plus\"`\n *\n * @see {@link https://docs.mux.com/guides/add-autogenerated-captions-and-use-transcripts}\n */\n defaultAutogeneratedSubtitleLang?: SupportedMuxLanguage\n\n /**\n * Whether or not to allow content editors to override asset upload\n * configuration settings when uploading a video to Mux.\n *\n * @see {@link https://docs.mux.com/guides/secure-video-playback}\n * @defaultValue false\n */\n disableUploadConfig?: boolean\n\n /**\n * Whether or not to allow content editors to add text tracks alongside their\n * asset when uploading a video to Mux.\n *\n * @see {@link https://docs.mux.com/guides/secure-video-playback}\n * @defaultValue false\n */\n disableTextTrackConfig?: boolean\n\n /**\n * Whether or not to show the playback warning when trying to watch DRM content for the first time.\n *\n * @defaultValue false\n */\n disableDrmPlaybackWarning?: boolean\n\n /**\n * The mime types that are accepted by the input.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/accept}\n * @defaultValue ['video/*','audio/*']\n\n */\n acceptedMimeTypes?: ('audio/*' | 'video/*')[]\n\n /**\n * Maximum file size allowed for video uploads in bytes.\n * If not specified, no file size validation will be performed.\n *\n * @example 1024 * 1024 * 1024 // 1 GB\n * @defaultValue undefined\n */\n maxAssetFileSize?: number\n\n /**\n * Maximum video duration allowed in seconds.\n * If not specified, no duration validation will be performed.\n *\n * @example 2 * 60 * 60 // 2 hours\n * @defaultValue undefined\n */\n maxAssetDuration?: number\n\n /**\n * HLS.js configuration options to be passed to the Mux Player.\n * These options allow you to customize the underlying HLS.js playback engine behavior.\n *\n * @see {@link https://github.com/video-dev/hls.js/blob/master/docs/API.md#fine-tuning}\n * @defaultValue undefined\n * @example\n * ```ts\n * {\n * maxBufferLength: 30,\n * lowLatencyMode: true,\n * capLevelToPlayerSize: true\n * }\n * ```\n */\n hlsConfig?: MuxPlayerElement['_hlsConfig']\n}\n\nexport interface PluginConfig extends MuxInputConfig {\n /**\n * How the videos browser should appear as a studio tool in Sanity's top navigation\n *\n * Pass `false` if you want to disable it.\n * @defaultValue {title: 'Videos', icon: VideoIcon}\n **/\n tool:\n | false\n | {\n title?: string\n icon?: React.ComponentType\n }\n\n /**\n * The roles that are allowed to configure the plugin.\n *\n * If not set, all roles will be allowed to configure the plugin.\n * @defaultValue []\n */\n allowedRolesForConfiguration: string[]\n}\n\nexport const SUPPORTED_MUX_LANGUAGES = [\n {label: 'English', code: 'en', state: 'Stable'},\n {label: 'Spanish', code: 'es', state: 'Stable'},\n {label: 'Italian', code: 'it', state: 'Stable'},\n {label: 'Portuguese', code: 'pt', state: 'Stable'},\n {label: 'German', code: 'de', state: 'Stable'},\n {label: 'French', code: 'fr', state: 'Stable'},\n {label: 'Polish', code: 'pl', state: 'Beta'},\n {label: 'Russian', code: 'ru', state: 'Beta'},\n {label: 'Dutch', code: 'nl', state: 'Beta'},\n {label: 'Catalan', code: 'ca', state: 'Beta'},\n {label: 'Turkish', code: 'tr', state: 'Beta'},\n {label: 'Swedish', code: 'sv', state: 'Beta'},\n {label: 'Ukrainian', code: 'uk', state: 'Beta'},\n {label: 'Norwegian', code: 'no', state: 'Beta'},\n {label: 'Finnish', code: 'fi', state: 'Beta'},\n {label: 'Slovak', code: 'sk', state: 'Beta'},\n {label: 'Greek', code: 'el', state: 'Beta'},\n {label: 'Czech', code: 'cs', state: 'Beta'},\n {label: 'Croatian', code: 'hr', state: 'Beta'},\n {label: 'Danish', code: 'da', state: 'Beta'},\n {label: 'Romanian', code: 'ro', state: 'Beta'},\n {label: 'Bulgarian', code: 'bg', state: 'Beta'},\n] as const\n\nexport const SUPPORTED_MUX_LANGUAGES_VALUES = SUPPORTED_MUX_LANGUAGES.map((l) => l.code)\n\nexport type SupportedMuxLanguage = (typeof SUPPORTED_MUX_LANGUAGES_VALUES)[number]\n\nexport interface TextTrack {\n _id: string\n name: string\n}\n\nexport interface AutogeneratedTextTrack extends TextTrack {\n type: 'autogenerated'\n language_code: SupportedMuxLanguage\n}\n\nexport interface CustomTextTrack extends TextTrack {\n type: 'subtitles' | 'captions'\n language_code: string\n file: {\n contents: string\n type: string\n name: string\n size: number\n }\n}\n\nexport function isCustomTextTrack(track: Partial<UploadTextTrack>): track is CustomTextTrack {\n return track.type !== 'autogenerated'\n}\n\nexport function isAutogeneratedTrack(\n track: Partial<UploadTextTrack>,\n): track is AutogeneratedTextTrack {\n return track.type === 'autogenerated'\n}\n\nexport type UploadTextTrack = AutogeneratedTextTrack | CustomTextTrack\n\n/**\n * Watermark configuration for UI (draggable position)\n */\nexport interface WatermarkConfig {\n enabled: boolean\n imageUrl?: string\n /**\n * Aspect ratio (width / height) of the watermark image.\n * Used to convert between our center-based UI coords and Mux overlay margins.\n */\n imageAspectRatio?: number\n /**\n * Optional explicit Mux `overlay_settings`.\n * When set, these values should be used as-is for the upload request and preview.\n * @see {@link https://www.mux.com/docs/guides/add-watermarks-to-your-videos}\n */\n overlay_settings?: MuxOverlaySettings\n position?: {\n x: number // percentage (0-100)\n y: number // percentage (0-100)\n }\n size?: number // percentage of video width (0-100)\n opacity?: number // 0-1 (converted to percentage string for Mux API)\n}\n\n/**\n * Mux overlay_settings format for watermark API\n * @see {@link https://www.mux.com/docs/guides/add-watermarks-to-your-videos}\n */\nexport interface MuxOverlaySettings {\n vertical_align: 'top' | 'middle' | 'bottom'\n vertical_margin: string // percentage (e.g., \"10%\") or pixels (e.g., \"40px\")\n horizontal_align: 'left' | 'center' | 'right'\n horizontal_margin: string // percentage (e.g., \"10%\") or pixels (e.g., \"40px\")\n width?: string // percentage (e.g., \"25%\") or pixels (e.g., \"80px\")\n height?: string // percentage or pixels\n opacity?: string // percentage string (e.g., \"90%\")\n}\n\nexport interface UploadConfig extends Pick<\n MuxInputConfig,\n 'max_resolution_tier' | 'normalize_audio' | 'video_quality'\n> {\n static_renditions: StaticRenditionResolution[]\n text_tracks: UploadTextTrack[]\n signed_policy: boolean\n public_policy: boolean\n watermark?: WatermarkConfig\n drm_policy: boolean\n}\n\n/**\n * Data sent to Mux to create a new asset.\n * @docs {@link https://docs.mux.com/api-reference#video/operation/create-direct-upload}\n */\nexport interface MuxNewAssetSettings extends Pick<\n MuxInputConfig,\n 'max_resolution_tier' | 'normalize_audio' | 'video_quality'\n> {\n /** Static renditions configuration for downloadable files */\n static_renditions?: {resolution: StaticRenditionResolution}[]\n /** An array of objects that each describe an input file to be used to create the asset.*/\n input?: {\n /** The URL of the file that Mux should download and use. */\n url?: string\n /** Generate subtitle tracks using automatic speech recognition with this configuration. This may only be provided for the first input object (the main input file). */\n generated_subtitles?: {\n /** A name for this subtitle track. */\n name: string\n /** Arbitrary metadata set for the subtitle track. Max 255 characters. */\n passthrough?: string\n /** The language to generate subtitles in. */\n language_code: SupportedMuxLanguage\n }[]\n /** The time offset in seconds from the beginning of the video indicating the clip's starting marker. */\n start_time?: number\n /** The time offset in seconds from the beginning of the video indicating the clip's ending marker. */\n end_time?: number\n /** This parameter is required for text type tracks. */\n type?: 'video' | 'audio' | 'text'\n /** Type of text track. This parameter only supports subtitles value. */\n text_type?: 'subtitles'\n /** The language code value must be a valid BCP 47 specification compliant value. */\n language_code?: string\n /** The name of the track containing a human-readable description. This value must be unique within each group of text or audio track types. */\n name?: string\n /** Indicates the track provides Subtitles for the Deaf or Hard-of-hearing (SDH). */\n closed_captions?: boolean\n /** This optional parameter should be used tracks with type of text and text_type set to subtitles. */\n passthrough?: string\n /** Overlay settings for watermarks. Used when adding a watermark image as a second input. */\n overlay_settings?: MuxOverlaySettings\n }[]\n\n /** An array of playback policy names that you want applied to this asset and available through playback_ids. */\n playback_policy?: PlaybackPolicy[]\n\n /** An array of playback policy objects that you want applied to this asset and available through playback_ids. advanced_playback_policies must be used instead of playback_policies when creating a DRM playback ID. */\n advanced_playback_policies: AdvancedPlaybackPolicy[]\n\n /** Arbitrary user-supplied metadata that will be included in the asset details and related webhooks. */\n passthrough?: string\n}\n\n/** Used by advanced_playback_policies, allows to define DRM config. */\nexport type AdvancedPlaybackPolicy = {\n policy: PlaybackPolicy\n drm_configuration_id?: string\n}\n\nexport interface Secrets {\n token: string | null\n secretKey: string | null\n enableSignedUrls: boolean\n signingKeyId: string | null\n signingKeyPrivate: string | null\n drmConfigId: string | null\n}\n\nexport type MuxImageOrigin = `https://image.mux.com`\nexport type MuxThumbnailUrl = `${MuxImageOrigin}/${string}/thumbnail.png?${string}`\nexport type MuxAnimatedThumbnailUrl = `${MuxImageOrigin}/${string}/animated.gif?${string}`\nexport type MuxVideoOrigin = `https://stream.mux.com`\nexport type MuxVideoUrl = `${MuxVideoOrigin}/${string}.m3u8?${string}`\n\n// 'preserve' by default\n// @url: https://docs.mux.com/guides/video/get-images-from-a-video#thumbnail-query-string-parameters\nexport type FitMode = 'preserve' | 'crop' | 'smartcrop' | 'pad'\n\nexport interface ThumbnailOptions {\n fit_mode?: FitMode\n height?: number\n time?: number\n width?: number\n}\n\nexport interface AnimatedThumbnailOptions {\n // Starting time code for the animation, if no end is set it'll have a 5s duration\n // The start and end timecodes uses `asset.thumbTime` to create an iOS `Live Photo` effect by showing you the 5 secodnds before, and after, the thumb time`\n start?: number\n // End code, can't be longer than 10s after the start code\n end?: number\n // Max 640px, 320px by default\n width?: number\n // Preserves aspect ratio, like width, you can't set both the height and width, max 640\n height?: number\n // The fps is 15 by default, but can go up to 30\n fps?: number\n}\n\nexport interface AssetThumbnailOptions {\n asset: Pick<VideoAssetDocument, 'playbackId' | 'data' | 'thumbTime' | 'filename' | 'assetId'>\n}\n\nexport type PlaybackPolicy = 'signed' | 'public' | 'drm'\n\nexport interface MuxErrors {\n type: string\n messages: string[]\n}\n\nexport interface MuxPlaybackId {\n id: string\n policy: PlaybackPolicy\n}\n\nexport interface MuxVideoTrack {\n type: 'video'\n id: string\n max_width: number\n max_height: number\n // if the fps can't be reliably determined, this will be -1\n max_frame_rate: -1 | number\n // top-level duration is always set, while track level duration is not\n duration?: number\n}\nexport interface MuxAudioTrack {\n type: 'audio'\n id: string\n duration?: number\n max_channels: number\n max_channel_layout: 'stereo' | string\n}\nexport interface MuxTextTrack {\n type: 'text'\n id: string\n text_type?: 'subtitles'\n // https://docs.mux.com/api-reference/video#operation/list-assets:~:text=text%20type%20tracks.-,tracks%5B%5D.,text_source,-string\n text_source?:\n | 'uploaded'\n | 'embedded'\n | 'generated_live'\n | 'generated_live_final'\n | 'generated_vod'\n // BCP 47 language code\n language_code?: 'en' | 'en-US' | string\n // The name of the track containing a human-readable description. The hls manifest will associate a subtitle text track with this value\n name?: 'English' | string\n closed_captions?: boolean\n // Max 255 characters\n passthrough?: string\n status: 'preparing' | 'ready' | 'errored'\n error?: {\n type: string\n messages?: string[]\n }\n}\nexport type MuxTrack = MuxVideoTrack | MuxAudioTrack | MuxTextTrack\n// Typings lifted from https://docs.mux.com/api-reference/video#tag/assets\nexport interface MuxAsset {\n id: string\n /** In seconds (instead of JS's default milliseconds) */\n created_at: string\n status: 'preparing' | 'ready' | 'errored'\n duration: number\n max_stored_resolution: 'Audio only' | 'SD' | 'HD' | 'FHD' | 'UHD'\n max_resolution_tier?: '2160p' | '1440p' | '1080p'\n // if the fps can't be reliably determined, this will be -1\n max_stored_frame_rate: -1 | number\n // The aspect ratio of the asset in the form of width:height, for example 16:9\n aspect_ratio: `${number}:${number}`\n playback_ids: MuxPlaybackId[]\n tracks: MuxTrack[]\n errors?: MuxErrors\n upload_id: string\n is_live?: boolean\n // We use passthrough to set the mux.videoAsset._id of the asset that originally uploaded the video\n passthrough: string\n live_stream_id?: string\n master?: {\n status: 'ready' | 'preparing' | 'errored'\n // Temporary URL to master MP4, expires after 24 hours.\n // Only present once `status` is 'ready'.\n url?: string\n }\n master_access: 'temporary' | 'none'\n mp4_support: 'standard' | 'none'\n // Asset Identifier of the video used as the source for creating the clip.\n source_asset_id?: string\n // Normalize the audio track loudness level. This parameter is only applicable to on-demand (not live) assets., default false\n normalize_audio?: boolean\n // The object does not exist if no static renditions have been requested\n static_renditions?: {\n status: 'ready' | 'preparing' | 'disabled' | 'errored'\n files: {\n name: string\n ext: 'mp4' | 'm4a'\n height: number\n width: number\n bitrate: number\n filesize: string\n type: 'standard' | 'advanced'\n status: 'ready' | 'preparing' | 'skipped' | 'errored'\n resolution_tier?: string\n resolution?: string\n id: string\n passthrough?: string\n }[]\n }\n recording_times?: {\n started_at: string\n duration: number\n type: 'content' | 'slate'\n }[]\n // https://docs.mux.com/guides/video/minimize-processing-time\n non_standard_input_reasons?: {\n video_codec?: string\n audio_codec?: string\n video_gop_size?: 'high'\n video_frame_rate?: string\n video_resolution?: string\n video_bitrate?: 'high'\n pixel_aspect_ratio?: string\n video_edit_list?: 'non-standard'\n audio_edit_list?: 'non-standard'\n unexpected_media_file_parameters?: 'non-standard'\n test?: boolean\n }\n meta?: {\n title?: string\n }\n}\n\nexport interface VideoAssetDocument {\n _id: string\n _type: 'mux.videoAsset'\n _createdAt: string\n _updatedAt?: string\n status?: string\n assetId?: string\n playbackId?: string\n filename?: string\n thumbTime?: number\n // Docs for what goes in `data` https://docs.mux.com/api-reference/video#tag/assets\n data?: PartialDeep<MuxAsset>\n}\n\nexport type Reference = {_type: 'reference'; _ref: string}\n\n// @TODO add Reference, and ReferenceSchemaType in the generic\nexport type MuxInputProps = ObjectInputProps<{\n asset?: Reference\n}>\n","import {Button, Card, Dialog, Stack, Text} from '@sanity/ui'\nimport {createContext, useCallback, useContext, useMemo, useState} from 'react'\n\nimport {type PluginConfig} from '../util/types'\n\nconst LOCAL_STORAGE_HAS_SHOWN_WARNING_KEY = 'mux-plugin-has-shown-drm-playback-warning'\n\ntype DrmPlaybackWarningContextContextProps = {\n hasShownWarning: boolean\n setHasWarnedAboutDrmPlayback: (b: boolean) => void\n}\n\nconst DrmPlaybackWarningContext = createContext<DrmPlaybackWarningContextContextProps>({\n hasShownWarning: false,\n setHasWarnedAboutDrmPlayback: () => {\n return null\n },\n})\n\ninterface DrmPlaybackWarningContextProviderProps {\n config?: PluginConfig\n children: React.ReactNode\n}\n\nexport const DrmPlaybackWarningContextProvider = ({\n config,\n children,\n}: DrmPlaybackWarningContextProviderProps) => {\n const warningDisabled = config?.disableDrmPlaybackWarning ?? false\n const hasWarned: boolean =\n warningDisabled || window.localStorage.getItem(LOCAL_STORAGE_HAS_SHOWN_WARNING_KEY) === 'true'\n const [hasWarnedAboutDrmPlayback, setHasWarnedAboutDrmPlayback] = useState(hasWarned)\n\n const setHasShownWarning = useCallback((b: boolean) => {\n window.localStorage.setItem(LOCAL_STORAGE_HAS_SHOWN_WARNING_KEY, b.toString())\n setHasWarnedAboutDrmPlayback(b)\n }, [])\n\n const value = useMemo(\n () => ({\n hasShownWarning: hasWarnedAboutDrmPlayback,\n setHasWarnedAboutDrmPlayback: setHasShownWarning,\n }),\n [hasWarnedAboutDrmPlayback, setHasShownWarning],\n )\n\n return (\n <DrmPlaybackWarningContext.Provider value={value}>\n {children}\n </DrmPlaybackWarningContext.Provider>\n )\n}\n\nexport const useDrmPlaybackWarningContext = () => {\n const context = useContext(DrmPlaybackWarningContext)\n return context\n}\n\nexport const DRMWarningDialog = ({onClose}: {onClose: () => void}) => {\n const {setHasWarnedAboutDrmPlayback} = useDrmPlaybackWarningContext()\n const _onClose = () => {\n setHasWarnedAboutDrmPlayback(true)\n onClose()\n }\n return (\n <Dialog\n open\n id=\"drm-playback-warn\"\n onClose={_onClose}\n header=\"DRM Playback Warning\"\n footer={\n <Stack padding={3}>\n <Button mode=\"ghost\" tone=\"primary\" onClick={_onClose} text=\"Ok\" />\n </Stack>\n }\n >\n <Stack space={3} padding={3}>\n <Card padding={[3, 3, 3]} radius={2}>\n <Stack space={3}>\n <Text size={1} weight=\"semibold\">\n DRM-protected playback will generate a license with a small associated cost. The\n plugin will attempt to play signed or public playback IDs instead whenever possible.\n </Text>\n </Stack>\n </Card>\n <Card padding={[3, 3, 3]} radius={2} tone=\"suggest\">\n <Stack space={3}>\n <Text size={1} weight=\"semibold\">\n This is a one time warning. If it persists, you can disable it from your plugin\n configuration.\n </Text>\n </Stack>\n </Card>\n </Stack>\n </Dialog>\n )\n}\n","// As it's required to specify the API Version this custom hook ensures it's all using the same version\nimport {useClient as useSanityClient} from 'sanity'\n\nexport const SANITY_API_VERSION = '2024-03-05'\n\nexport function useClient() {\n return useSanityClient({apiVersion: SANITY_API_VERSION})\n}\n","// Adaptation of Sanity's createSearchQuery for our limited use case:\n// https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/core/search/weighted/createSearchQuery.ts\nimport {compact, toLower, trim, uniq, words} from 'lodash'\n\nconst SPECIAL_CHARS = /([^!@#$%^&*(),\\\\/?\";:{}|[\\]+<>\\s-])+/g\nconst STRIP_EDGE_CHARS = /(^[.]+)|([.]+$)/\n\nfunction tokenize(string: string): string[] {\n return (string.match(SPECIAL_CHARS) || []).map((token) => token.replace(STRIP_EDGE_CHARS, ''))\n}\n\nfunction toGroqParams(terms: string[]): Record<string, string> {\n const params: Record<string, string> = {}\n return terms.reduce((acc, term, i) => {\n acc[`t${i}`] = `*${term}*` // \"t\" is short for term\n return acc\n }, params)\n}\n\n/**\n * Convert a string into an array of tokenized terms.\n *\n * Any (multi word) text wrapped in double quotes will be treated as \"phrases\", or separate tokens that\n * will not have its special characters removed.\n * E.g.`\"the\" \"fantastic mr\" fox fox book` =\\> [\"the\", `\"fantastic mr\"`, \"fox\", \"book\"]\n *\n * Phrases wrapped in quotes are assigned relevance scoring differently from regular words.\n *\n * @internal\n */\nfunction extractTermsFromQuery(query: string): string[] {\n const quotedQueries = [] as string[]\n const unquotedQuery = query.replace(/(\"[^\"]*\")/g, (match) => {\n if (words(match).length > 1) {\n quotedQueries.push(match)\n return ''\n }\n return match\n })\n\n // Lowercase and trim quoted queries\n const quotedTerms = quotedQueries.map((str) => trim(toLower(str)))\n\n /**\n * Convert (remaining) search query into an array of deduped, sanitized tokens.\n * All white space and special characters are removed.\n * e.g. \"The saint of Saint-Germain-des-Prés\" =\\> ['the', 'saint', 'of', 'germain', 'des', 'pres']\n */\n const remainingTerms = uniq(compact(tokenize(toLower(unquotedQuery))))\n\n return [...quotedTerms, ...remainingTerms]\n}\n\n/**\n * Create GROQ constraints, given search terms and the full spec of available document types and fields.\n * Essentially a large list of all possible fields (joined by logical OR) to match our search terms against.\n */\nfunction createConstraints(terms: string[], includeAssetId: boolean) {\n const searchPaths = includeAssetId ? ['filename', 'assetId'] : ['filename']\n const constraints = terms\n .map((_term, i) => searchPaths.map((joinedPath) => `${joinedPath} match $t${i}`))\n .filter((constraint) => constraint.length > 0)\n\n return constraints.map((constraint) => `(${constraint.join(' || ')})`)\n}\n\nexport function createSearchFilter(query: string) {\n const terms = extractTermsFromQuery(query)\n\n return {\n filter: createConstraints(terms, query.length >= 8), // if the search is big enough, include the assetId (mux id) in the results\n params: {\n ...toGroqParams(terms),\n },\n }\n}\n","import {useMemo, useState} from 'react'\nimport {\n collate,\n createHookFromObservableFactory,\n type DocumentStore,\n useDocumentStore,\n} from 'sanity'\n\nimport {SANITY_API_VERSION} from '../hooks/useClient'\nimport {createSearchFilter} from '../util/createSearchFilter'\nimport type {VideoAssetDocument} from '../util/types'\n\nexport const ASSET_SORT_OPTIONS = {\n createdDesc: {groq: '_createdAt desc', label: 'Newest first'},\n createdAsc: {groq: '_createdAt asc', label: 'First created (oldest)'},\n filenameAsc: {groq: 'filename asc', label: 'By filename (A-Z)'},\n filenameDesc: {groq: 'filename desc', label: 'By filename (Z-A)'},\n}\n\nexport type SortOption = keyof typeof ASSET_SORT_OPTIONS\n\nconst useAssetDocuments = createHookFromObservableFactory<\n VideoAssetDocument[],\n {\n documentStore: DocumentStore\n sort: SortOption\n searchQuery: string\n }\n>(({documentStore, sort, searchQuery}) => {\n const search = createSearchFilter(searchQuery)\n const filter = [`_type == \"mux.videoAsset\"`, ...search.filter].filter(Boolean).join(' && ')\n\n const sortFragment = ASSET_SORT_OPTIONS[sort].groq\n return documentStore.listenQuery(\n /* groq */ `*[${filter}] | order(${sortFragment})`,\n search.params,\n {\n apiVersion: SANITY_API_VERSION,\n },\n )\n})\n\nexport default function useAssets() {\n const documentStore = useDocumentStore()\n const [sort, setSort] = useState<SortOption>('createdDesc')\n const [searchQuery, setSearchQuery] = useState('')\n\n const [assetDocuments = [], isLoading] = useAssetDocuments(\n useMemo(() => ({documentStore, sort, searchQuery}), [documentStore, sort, searchQuery]),\n )\n\n const assets = useMemo(\n () =>\n // Avoid displaying both drafts & published assets by collating them together and giving preference to drafts\n collate<VideoAssetDocument>(assetDocuments).map(\n (collated) =>\n ({\n ...(collated.draft || collated.published),\n _id: collated.id,\n }) as VideoAssetDocument,\n ),\n [assetDocuments],\n )\n\n return {\n assets,\n isLoading,\n sort,\n searchQuery,\n setSort,\n setSearchQuery,\n }\n}\n","// Handy little state machine to simplify managing which root level dialog to open\n\nimport {useState} from 'react'\n\nexport type DialogState =\n | 'secrets'\n | 'mezzanine'\n | 'select-video'\n | 'edit-thumbnail'\n | 'edit-captions'\n | false\n\nexport function useDialogState() {\n return useState<DialogState>(false)\n}\n\nexport type SetDialogState = ReturnType<typeof useDialogState>[1]\n","export const PLUGIN_VERSION_QUERY = {\n sanityVersion:\n // @ts-expect-error - this constant is search/replaced so must be exact, not accessed with an index signature\n process.env.PKG_VERSION!,\n}\n","import {defer} from 'rxjs'\nimport type {SanityClient} from 'sanity'\n\nimport {PLUGIN_VERSION_QUERY} from '../util/pluginVersion'\n\ninterface SecretsDocument {\n _id: 'secrets.mux'\n _type: 'mux.apiKey'\n token: string\n secretKey: string\n enableSignedUrls: boolean\n signingKeyId: string\n signingKeyPrivate: string\n drmConfigId: string\n}\nexport function saveSecrets(\n client: SanityClient,\n token: string,\n secretKey: string,\n enableSignedUrls: boolean,\n signingKeyId: string,\n signingKeyPrivate: string,\n drmConfigId: string,\n): Promise<SecretsDocument> {\n const doc: SecretsDocument = {\n _id: 'secrets.mux',\n _type: 'mux.apiKey',\n token,\n secretKey,\n enableSignedUrls,\n signingKeyId,\n signingKeyPrivate,\n drmConfigId,\n }\n doc.signingKeyId = enableSignedUrls ? signingKeyId : ''\n doc.signingKeyPrivate = enableSignedUrls ? signingKeyPrivate : ''\n\n return client.createOrReplace(doc)\n}\n\nexport async function createSigningKeys(client: SanityClient) {\n try {\n const {dataset} = client.config()\n const res = await client.request<{\n data: {private_key: string; id: string; created_at: string}\n }>({\n url: `/addons/mux/signing-keys/${dataset}`,\n withCredentials: true,\n method: 'POST',\n query: PLUGIN_VERSION_QUERY,\n })\n return res\n } catch (error: any) {\n console.error('Error creating signing keys', error)\n const message =\n error.response?.statusCode === 401\n ? 'Unauthorized - Failed to create the Signing Key. Please ensure that the token has \"System\" permissions'\n : error.message\n throw new Error(message, {cause: error})\n }\n}\n\nexport function testSecrets(client: SanityClient) {\n const {dataset} = client.config()\n return client.request<{status: boolean}>({\n url: `/addons/mux/secrets/${dataset}/test`,\n withCredentials: true,\n method: 'GET',\n query: PLUGIN_VERSION_QUERY,\n })\n}\n\nexport async function haveValidSigningKeys(\n client: SanityClient,\n signingKeyId: string,\n signingKeyPrivate: string,\n) {\n if (!(signingKeyId && signingKeyPrivate)) {\n return false\n }\n\n const {dataset} = client.config()\n try {\n const res = await client.request<{data: {id: string; created_at: string}}>({\n url: `/addons/mux/signing-keys/${dataset}/${signingKeyId}`,\n withCredentials: true,\n method: 'GET',\n query: PLUGIN_VERSION_QUERY,\n })\n //\n // if this signing key is valid it will return { data: { id: 'xxxx' } }\n //\n return !!(res.data && res.data.id)\n } catch (e) {\n console.error('Error fetching signingKeyId', signingKeyId, 'assuming it is not valid', e)\n return false\n }\n}\n\nexport function testSecretsObservable(client: SanityClient) {\n const {dataset} = client.config()\n return defer(() =>\n client.observable.request<{status: boolean}>({\n url: `/addons/mux/secrets/${dataset}/test`,\n withCredentials: true,\n method: 'GET',\n query: PLUGIN_VERSION_QUERY,\n }),\n )\n}\n","import {useCallback} from 'react'\nimport type {SanityClient} from 'sanity'\n\nimport {createSigningKeys, haveValidSigningKeys, saveSecrets, testSecrets} from '../actions/secrets'\nimport type {Secrets} from '../util/types'\n\nexport const useSaveSecrets = (client: SanityClient, secrets: Secrets) => {\n return useCallback(\n async ({\n token,\n secretKey,\n enableSignedUrls,\n drmConfigId,\n }: Pick<\n Secrets,\n 'token' | 'secretKey' | 'enableSignedUrls' | 'drmConfigId'\n >): Promise<Secrets> => {\n let {signingKeyId, signingKeyPrivate} = secrets\n\n try {\n await saveSecrets(\n client,\n token!,\n secretKey!,\n enableSignedUrls,\n signingKeyId!,\n signingKeyPrivate!,\n drmConfigId!,\n )\n const valid = await testSecrets(client)\n if (!valid?.status && token && secretKey) {\n throw new Error('Invalid secrets')\n }\n } catch (err) {\n console.error('Error while trying to save secrets:', err)\n throw err\n }\n\n if (enableSignedUrls) {\n const hasValidSigningKeys = await haveValidSigningKeys(\n client,\n signingKeyId!,\n signingKeyPrivate!,\n )\n\n if (!hasValidSigningKeys) {\n try {\n const {data} = await createSigningKeys(client)\n signingKeyId = data.id\n signingKeyPrivate = data.private_key\n await saveSecrets(\n client,\n token!,\n secretKey!,\n enableSignedUrls,\n signingKeyId,\n signingKeyPrivate,\n drmConfigId ?? '',\n )\n } catch (err: any) {\n // eslint-disable-next-line no-console\n console.log('Error while creating and saving signing key:', err?.message)\n throw err\n }\n }\n }\n return {\n token,\n secretKey,\n enableSignedUrls,\n signingKeyId,\n signingKeyPrivate,\n drmConfigId,\n }\n },\n [client, secrets],\n )\n}\n","export const name = 'mux-input' as const\n\n// Caching namespace, as suspend-react might be in use by other components on the page we must ensure we don't collide\nexport const cacheNs = 'sanity-plugin-mux-input' as const\n\nexport const muxSecretsDocumentId = 'secrets.mux' as const\n\nexport const DIALOGS_Z_INDEX = 60_000\n\n/** Mux guide explaining the mezzanine (\"master access\") file and how it differs from MP4 renditions. */\nexport const MEZZANINE_LEARN_MORE_URL =\n 'https://www.mux.com/docs/guides/download-for-offline-editing#enable-master-access'\n\nexport const THUMBNAIL_ASPECT_RATIO = 16 / 9\n\n/** To prevent excessive height, thumbnails and input should not go beyond to this aspect ratio. */\nexport const MIN_ASPECT_RATIO = 5 / 4\n\nexport const AUDIO_ASPECT_RATIO = 5 / 1\n","import {useMemo} from 'react'\nimport {useDocumentValues} from 'sanity'\n\nimport {muxSecretsDocumentId} from '../util/constants'\nimport type {Secrets} from '../util/types'\n\nconst path = [\n 'token',\n 'secretKey',\n 'enableSignedUrls',\n 'signingKeyId',\n 'signingKeyPrivate',\n 'drmConfigId',\n]\nexport const useSecretsDocumentValues = () => {\n const {error, isLoading, value} = useDocumentValues<Partial<Secrets> | null | undefined>(\n muxSecretsDocumentId,\n path,\n )\n const cache = useMemo(() => {\n const exists = Boolean(value)\n const secrets: Secrets = {\n token: value?.token || null,\n secretKey: value?.secretKey || null,\n enableSignedUrls: value?.enableSignedUrls || false,\n signingKeyId: value?.signingKeyId || null,\n signingKeyPrivate: value?.signingKeyPrivate || null,\n drmConfigId: value?.drmConfigId || null,\n }\n return {\n isInitialSetup: !exists,\n needsSetup: !secrets?.token || !secrets?.secretKey,\n secrets,\n }\n }, [value])\n\n return {error, isLoading, value: cache}\n}\n","import {useReducer} from 'react'\n\nimport type {Secrets} from '../util/types'\n\nexport interface State extends Pick<\n Secrets,\n 'token' | 'secretKey' | 'enableSignedUrls' | 'drmConfigId'\n> {\n submitting: boolean\n error: string | null\n}\nexport type Action =\n | {type: 'submit'}\n | {type: 'error'; payload: string}\n | {type: 'reset'; payload: Secrets}\n | {type: 'change'; payload: {name: 'token'; value: string}}\n | {type: 'change'; payload: {name: 'secretKey'; value: string}}\n | {type: 'change'; payload: {name: 'enableSignedUrls'; value: boolean}}\n | {type: 'change'; payload: {name: 'drmConfigId'; value: string}}\nfunction init({token, secretKey, enableSignedUrls, drmConfigId}: Secrets): State {\n return {\n submitting: false,\n error: null,\n // Form inputs don't set the state back to null when clearing a field, but uses empty strings\n // This ensures the `dirty` check works correctly\n token: token ?? '',\n secretKey: secretKey ?? '',\n enableSignedUrls: enableSignedUrls ?? false,\n drmConfigId: drmConfigId ?? '',\n }\n}\nfunction reducer(state: State, action: Action) {\n switch (action?.type) {\n case 'submit':\n return {...state, submitting: true, error: null}\n case 'error':\n return {...state, submitting: false, error: action.payload}\n case 'reset':\n return init(action.payload)\n case 'change':\n return {...state, [action.payload.name]: action.payload.value}\n default:\n throw new Error(`Unknown action type: ${(action as unknown as Action)?.type}`)\n }\n}\n\nexport const useSecretsFormState = (secrets: Secrets) => useReducer(reducer, secrets, init)\n","// Utils with a readName prefix are suspendable and should only be called in the render body\n// Not inside event callbacks or a useEffect.\n// They may be called dynamically, unlike useEffect\n\n// @TODO rename to readSigningPair\n\nimport type {SanityClient} from 'sanity'\nimport {suspend} from 'suspend-react'\n\nimport {cacheNs} from '../util/constants'\nimport {type Secrets} from '../util/types'\n\nexport const _id = 'secrets.mux' as const\n\nexport function readSecrets(client: SanityClient): Secrets {\n const {projectId, dataset} = client.config()\n return suspend(async () => {\n const data = await client.fetch(\n /* groq */ `*[_id == $_id][0]{\n token,\n secretKey,\n enableSignedUrls,\n signingKeyId,\n signingKeyPrivate,\n drmConfigId\n }`,\n {_id},\n )\n return {\n token: data?.token || null,\n secretKey: data?.secretKey || null,\n enableSignedUrls: Boolean(data?.enableSignedUrls) || false,\n signingKeyId: data?.signingKeyId || null,\n signingKeyPrivate: data?.signingKeyPrivate || null,\n drmConfigId: data?.drmConfigId || null,\n }\n }, [cacheNs, _id, projectId, dataset])\n}\n","import {useTheme_v2} from '@sanity/ui'\nimport {type CSSProperties, useId, useMemo} from 'react'\n\nexport interface Props {\n height?: number\n}\nexport default function MuxLogo({height = 26}: Props) {\n const id = useId()\n const theme = useTheme_v2()\n const fillColor = theme.color._dark ? 'white' : 'black'\n const titleId = useMemo(() => `${id}-title`, [id])\n\n const pathStyle: CSSProperties = {\n fillRule: 'nonzero',\n }\n\n return (\n <svg\n aria-labelledby={titleId}\n style={{height: `${height}px`}}\n viewBox=\"0 0 1600 500\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlSpace=\"preserve\"\n >\n <g id=\"Layer-1\" fill={fillColor}>\n <path\n d=\"M994.287,93.486c-17.121,-0 -31,-13.879 -31,-31c0,-17.121 13.879,-31 31,-31c17.121,-0 31,13.879 31,31c0,17.121 -13.879,31 -31,31m0,-93.486c-34.509,-0 -62.484,27.976 -62.484,62.486l0,187.511c0,68.943 -56.09,125.033 -125.032,125.033c-68.942,-0 -125.03,-56.09 -125.03,-125.033l0,-187.511c0,-34.51 -27.976,-62.486 -62.485,-62.486c-34.509,-0 -62.484,27.976 -62.484,62.486l0,187.511c0,137.853 112.149,250.003 249.999,250.003c137.851,-0 250.001,-112.15 250.001,-250.003l0,-187.511c0,-34.51 -27.976,-62.486 -62.485,-62.486\"\n style={pathStyle}\n />\n <path\n d=\"M1537.51,468.511c-17.121,-0 -31,-13.879 -31,-31c0,-17.121 13.879,-31 31,-31c17.121,-0 31,13.879 31,31c0,17.121 -13.879,31 -31,31m-275.883,-218.509l-143.33,143.329c-24.402,24.402 -24.402,63.966 0,88.368c24.402,24.402 63.967,24.402 88.369,-0l143.33,-143.329l143.328,143.329c24.402,24.4 63.967,24.402 88.369,-0c24.403,-24.402 24.403,-63.966 0.001,-88.368l-143.33,-143.329l0.001,-0.004l143.329,-143.329c24.402,-24.402 24.402,-63.965 0,-88.367c-24.402,-24.402 -63.967,-24.402 -88.369,-0l-143.329,143.328l-143.329,-143.328c-24.402,-24.401 -63.967,-24.402 -88.369,-0c-24.402,24.402 -24.402,63.965 0,88.367l143.329,143.329l0,0.004Z\"\n style={pathStyle}\n />\n <path\n d=\"M437.511,468.521c-17.121,-0 -31,-13.879 -31,-31c0,-17.121 13.879,-31 31,-31c17.121,-0 31,13.879 31,31c0,17.121 -13.879,31 -31,31m23.915,-463.762c-23.348,-9.672 -50.226,-4.327 -68.096,13.544l-143.331,143.329l-143.33,-143.329c-17.871,-17.871 -44.747,-23.216 -68.096,-13.544c-23.349,9.671 -38.574,32.455 -38.574,57.729l0,375.026c0,34.51 27.977,62.486 62.487,62.486c34.51,-0 62.486,-27.976 62.486,-62.486l0,-224.173l80.843,80.844c24.404,24.402 63.965,24.402 88.369,-0l80.843,-80.844l0,224.173c0,34.51 27.976,62.486 62.486,62.486c34.51,-0 62.486,-27.976 62.486,-62.486l0,-375.026c0,-25.274 -15.224,-48.058 -38.573,-57.729\"\n style={pathStyle}\n />\n </g>\n </svg>\n )\n}\n","import {styled} from 'styled-components'\n\nimport MuxLogo from './MuxLogo'\n\nconst Logo = styled.span`\n display: inline-block;\n height: 0.8em;\n margin-right: 1em;\n transform: translate(0.3em, -0.2em);\n`\n\nexport const Header = () => (\n <>\n <Logo>\n <MuxLogo height={13} />\n </Logo>\n API Credentials\n </>\n)\n","import {Box, Flex, Stack, Text} from '@sanity/ui'\nimport {memo} from 'react'\n\n// @TODO: get rid of this once v3 core is stable\n\nexport interface Props {\n children: React.ReactNode\n title: React.ReactNode\n description?: React.ReactNode\n inputId: string\n}\n\nfunction FormField(props: Props) {\n const {children, title, description, inputId} = props\n\n return (\n <Stack space={1}>\n <Flex align=\"flex-end\">\n <Box flex={1} paddingY={2}>\n <Stack space={2}>\n <Text as=\"label\" htmlFor={inputId} weight=\"semibold\" size={1}>\n {title || <em>Untitled</em>}\n </Text>\n\n {description && (\n <Text muted size={1}>\n {description}\n </Text>\n )}\n </Stack>\n </Box>\n </Flex>\n <div>{children}</div>\n </Stack>\n )\n}\n\nexport default memo(FormField)\n","import {\n Box,\n Button,\n Card,\n Checkbox,\n Code,\n Dialog,\n Flex,\n Inline,\n Stack,\n Text,\n TextInput,\n} from '@sanity/ui'\nimport {useCallback, useEffect, useId, useMemo, useRef} from 'react'\nimport {clear, preload} from 'suspend-react'\n\nimport {useClient} from '../hooks/useClient'\nimport type {SetDialogState} from '../hooks/useDialogState'\nimport {useDialogState} from '../hooks/useDialogState'\nimport {useSaveSecrets} from '../hooks/useSaveSecrets'\nimport {useSecretsDocumentValues} from '../hooks/useSecretsDocumentValues'\nimport {useSecretsFormState} from '../hooks/useSecretsFormState'\nimport {cacheNs, DIALOGS_Z_INDEX} from '../util/constants'\nimport {_id as secretsId} from '../util/readSecrets'\nimport type {Secrets} from '../util/types'\nimport {Header} from './ConfigureApi.styled'\nimport FormField from './FormField'\n\n// Props for the dialog component when used with external state management\nexport interface ConfigureApiDialogProps {\n setDialogState: SetDialogState\n secrets: Secrets\n}\n\nconst fieldNames = ['token', 'secretKey', 'enableSignedUrls', 'drmConfigId'] as const\n\n// Internal dialog component that can be used with external state\nexport function ConfigureApiDialog({secrets, setDialogState}: ConfigureApiDialogProps) {\n const client = useClient()\n const [state, dispatch] = useSecretsFormState(secrets)\n const hasSecretsInitially = useMemo(() => secrets.token && secrets.secretKey, [secrets])\n const handleClose = useCallback(() => setDialogState(false), [setDialogState])\n const dirty = useMemo(\n () =>\n secrets.token !== state.token ||\n secrets.secretKey !== state.secretKey ||\n secrets.enableSignedUrls !== state.enableSignedUrls ||\n secrets.drmConfigId !== state.drmConfigId,\n [secrets, state],\n )\n const id = `ConfigureApi${useId()}`\n const [tokenId, secretKeyId, enableSignedUrlsId, drmConfigIdId] = useMemo<typeof fieldNames>(\n () => fieldNames.map((field) => `${id}-${field}`) as unknown as typeof fieldNames,\n [id],\n )\n const firstField = useRef<HTMLInputElement>(null)\n const handleSaveSecrets = useSaveSecrets(client, secrets)\n const saving = useRef(false)\n\n const handleSubmit = useCallback(\n (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault()\n\n if (!saving.current && event.currentTarget.reportValidity()) {\n saving.current = true\n dispatch({type: 'submit'})\n const {token, secretKey, enableSignedUrls, drmConfigId} = state\n handleSaveSecrets({token, secretKey, enableSignedUrls, drmConfigId})\n .then((savedSecrets) => {\n const {projectId, dataset} = client.config()\n clear([cacheNs, secretsId, projectId, dataset])\n preload(() => Promise.resolve(savedSecrets), [cacheNs, secretsId, projectId, dataset])\n setDialogState(false)\n })\n .catch((err) => dispatch({type: 'error', payload: err.message}))\n .finally(() => {\n saving.current = false\n })\n }\n },\n [client, dispatch, handleSaveSecrets, setDialogState, state],\n )\n const handleChangeToken = useCallback(\n (event: React.FormEvent<HTMLInputElement>) => {\n dispatch({\n type: 'change',\n payload: {name: 'token', value: event.currentTarget.value},\n })\n },\n [dispatch],\n )\n const handleChangeSecretKey = useCallback(\n (event: React.FormEvent<HTMLInputElement>) => {\n dispatch({\n type: 'change',\n payload: {name: 'secretKey', value: event.currentTarget.value},\n })\n },\n [dispatch],\n )\n const handleChangeEnableSignedUrls = useCallback(\n (event: React.FormEvent<HTMLInputElement>) => {\n dispatch({\n type: 'change',\n payload: {name: 'enableSignedUrls', value: event.currentTarget.checked},\n })\n },\n [dispatch],\n )\n const handleChangeDrmConfigId = useCallback(\n (event: React.FormEvent<HTMLInputElement>) => {\n dispatch({\n type: 'change',\n payload: {name: 'drmConfigId', value: event.currentTarget.value},\n })\n },\n [dispatch],\n )\n\n useEffect(() => {\n if (firstField.current) {\n firstField.current.focus()\n }\n }, [firstField])\n\n return (\n <Dialog\n animate\n id={id}\n onClose={handleClose}\n onClickOutside={handleClose}\n header={<Header />}\n zOffset={DIALOGS_Z_INDEX}\n position=\"fixed\"\n width={1}\n >\n <Box padding={3}>\n <form onSubmit={handleSubmit} noValidate>\n <Stack space={4}>\n {!hasSecretsInitially && (\n <Card padding={[3, 3, 3]} radius={2} shadow={1} tone=\"primary\">\n <Stack space={3}>\n <Text size={1}>\n To set up a new access token, go to your{' '}\n <a\n href=\"https://dashboard.mux.com/settings/access-tokens\"\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n >\n account on mux.com\n </a>\n .\n </Text>\n <Text size={1}>\n The access token needs permissions: <strong>Mux Video </strong>\n (Full Access) and <strong>Mux Data</strong> (Read)\n <br />\n To use Signed URLs, the token must also have System permissions.\n <br />\n The credentials will be stored safely in a hidden document only available to\n editors.\n </Text>\n </Stack>\n </Card>\n )}\n <FormField title=\"Access Token\" inputId={tokenId}>\n <TextInput\n id={tokenId}\n ref={firstField}\n onChange={handleChangeToken}\n type=\"text\"\n value={state.token ?? ''}\n required={!!state.secretKey || state.enableSignedUrls}\n />\n </FormField>\n <FormField title=\"Secret Key\" inputId={secretKeyId}>\n <TextInput\n id={secretKeyId}\n onChange={handleChangeSecretKey}\n type=\"text\"\n value={state.secretKey ?? ''}\n required={!!state.token || state.enableSignedUrls}\n />\n </FormField>\n\n <Stack space={4}>\n <Flex align=\"center\">\n <Checkbox\n id={enableSignedUrlsId}\n onChange={handleChangeEnableSignedUrls}\n checked={state.enableSignedUrls}\n style={{display: 'block'}}\n />\n <Box flex={1} paddingLeft={3}>\n <Text>\n <label htmlFor={enableSignedUrlsId}>Enable Signed Urls</label>\n </Text>\n </Box>\n </Flex>\n {secrets.signingKeyId && state.enableSignedUrls ? (\n <Card padding={[3, 3, 3]} radius={2} shadow={1} tone=\"caution\">\n <Stack space={3}>\n <Text size={1}>The signing key ID that Sanity will use is:</Text>\n <Code size={1}>{secrets.signingKeyId}</Code>\n <Text size={1}>\n This key is only used for previewing content in the Sanity UI.\n <br />\n You should generate a different key to use in your application server.\n </Text>\n </Stack>\n </Card>\n ) : null}\n </Stack>\n\n <FormField title=\"DRM Configuration ID\" inputId={drmConfigIdId}>\n <TextInput\n id={drmConfigIdId}\n onChange={handleChangeDrmConfigId}\n type=\"text\"\n value={state.drmConfigId ?? ''}\n required={false}\n />\n </FormField>\n <Card padding={[3, 3, 3]} radius={2} shadow={1} tone=\"neutral\">\n <Stack space={3}>\n <Text size={1}>\n DRM (Digital Rights Management) provides an extra layer of content security for\n video content streamed from Mux. For additional information check out our{' '}\n <a\n href=\"https://www.mux.com/docs/guides/protect-videos-with-drm#play-drm-protected-videos\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n DRM Guide\n </a>\n .\n </Text>\n <Text size={1}>\n <a\n href=\"https://www.mux.com/support/human\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Contact us\n </a>{' '}\n to get started using DRM.\n </Text>\n </Stack>\n </Card>\n\n <Inline space={2}>\n <Button\n text=\"Save\"\n disabled={!dirty}\n loading={state.submitting}\n tone=\"primary\"\n mode=\"default\"\n type=\"submit\"\n />\n <Button\n disabled={state.submitting}\n text=\"Cancel\"\n mode=\"bleed\"\n onClick={handleClose}\n />\n </Inline>\n {state.error && (\n <Card padding={[3, 3, 3]} radius={2} shadow={1} tone=\"critical\">\n <Text>{state.error}</Text>\n </Card>\n )}\n </Stack>\n </form>\n </Box>\n </Dialog>\n )\n}\n\n// Wrapper component that manages its own dialog state (used in VideosBrowser)\nexport default function ConfigureApi() {\n const [dialogOpen, setDialogOpen] = useDialogState()\n const secretDocumentValues = useSecretsDocumentValues()\n\n const openDialog = useCallback(() => setDialogOpen('secrets'), [setDialogOpen])\n\n if (dialogOpen === 'secrets') {\n return (\n <ConfigureApiDialog\n secrets={secretDocumentValues.value.secrets}\n setDialogState={setDialogOpen}\n />\n )\n }\n\n return <Button mode=\"bleed\" text=\"Configure plugin\" onClick={openDialog} />\n}\n","import {truncateString} from 'sanity'\n\n/**\n * Generates a placeholder title for a Mux asset when no title is available.\n * This format is used when importing assets that don't have a title in Mux.\n *\n * @param assetId - The Mux asset ID\n * @returns A placeholder title in the format \"Asset #[truncated-id]\"\n */\nexport function generateAssetPlaceholder(assetId: string): string {\n return `Asset #${truncateString(assetId, 15)}`\n}\n\n/**\n * Checks if a filename is empty or has the placeholder format.\n * This is used to determine if a video title should be updated during metadata sync.\n *\n * @param filename - The current filename/title of the video\n * @param assetId - The Mux asset ID to check against\n * @returns true if the filename is empty or matches the placeholder format\n */\nexport function isEmptyOrPlaceholderTitle(filename: string | undefined, assetId: string): boolean {\n // Check if filename is empty/undefined\n if (!filename || filename.trim() === '') {\n return true\n }\n\n // Check if filename matches the placeholder format for this asset\n const placeholder = generateAssetPlaceholder(assetId)\n return filename === placeholder\n}\n","import type {MuxAsset} from './types'\n\nexport function parseMuxDate(date: MuxAsset['created_at']): Date {\n return new Date(Number(date) * 1000)\n}\n","import type {SanityClient} from 'sanity'\n\nimport {PLUGIN_VERSION_QUERY} from '../util/pluginVersion'\nimport type {MuxAsset, VideoAssetDocument} from '../util/types'\n\nexport function deleteAssetOnMux(client: SanityClient, assetId: string) {\n const {dataset} = client.config()\n return client.request<void>({\n url: `/addons/mux/assets/${dataset}/${assetId}`,\n withCredentials: true,\n method: 'DELETE',\n query: PLUGIN_VERSION_QUERY,\n })\n}\n\nexport async function deleteAsset({\n client,\n asset,\n deleteOnMux,\n}: {\n client: SanityClient\n asset: VideoAssetDocument\n deleteOnMux: boolean\n}) {\n if (!asset?._id) return true\n\n try {\n await client.delete(asset._id)\n } catch {\n return 'failed-sanity'\n }\n\n if (deleteOnMux && asset?.assetId) {\n try {\n await deleteAssetOnMux(client, asset.assetId)\n } catch {\n return 'failed-mux'\n }\n }\n\n return true\n}\n\nexport function getAsset(client: SanityClient, assetId: string) {\n const {dataset} = client.config()\n return client.request<{data: MuxAsset}>({\n url: `/addons/mux/assets/${dataset}/data/${assetId}`,\n withCredentials: true,\n method: 'GET',\n query: PLUGIN_VERSION_QUERY,\n })\n}\n\nexport function listAssets(\n client: SanityClient,\n options: {limit?: number; cursor?: string | null},\n) {\n const {dataset} = client.config()\n const query: {limit?: string; cursor?: string} = {}\n\n if (options.limit) {\n query.limit = options.limit.toString()\n }\n if (options.cursor) {\n query.cursor = options.cursor\n }\n\n return client.request<{data: MuxAsset[]; next_cursor?: string | null}>({\n url: `/addons/mux/assets/${dataset}/data/list`,\n withCredentials: true,\n method: 'GET',\n query: {...query, ...PLUGIN_VERSION_QUERY},\n })\n}\n\n/**\n * Adds a new text track to an existing asset using a VTT file URL\n */\nexport function addTextTrackFromUrl(\n client: SanityClient,\n assetId: string,\n vttUrl: string,\n options: {\n language_code: string\n name: string\n text_type?: 'subtitles'\n },\n) {\n const {dataset} = client.config()\n\n return client.request<{data: MuxAsset}>({\n url: `/addons/mux/assets/${dataset}/${assetId}/tracks`,\n withCredentials: true,\n method: 'POST',\n body: {\n url: vttUrl,\n type: 'text',\n language_code: options.language_code,\n name: options.name,\n text_type: options.text_type || 'subtitles',\n },\n headers: {\n 'Content-Type': 'application/json',\n },\n query: PLUGIN_VERSION_QUERY,\n })\n}\n\n/**\n * Generates subtitles automatically for an audio track\n */\nexport function generateSubtitles(\n client: SanityClient,\n assetId: string,\n audioTrackId: string,\n options: {\n language_code: string\n name: string\n },\n) {\n const {dataset} = client.config()\n return client.request<{data: MuxAsset}>({\n url: `/addons/mux/assets/${dataset}/${assetId}/tracks/${audioTrackId}/generate-subtitles`,\n withCredentials: true,\n method: 'POST',\n body: {\n generated_subtitles: [\n {\n language_code: options.language_code,\n name: options.name,\n },\n ],\n },\n headers: {\n 'Content-Type': 'application/json',\n },\n query: PLUGIN_VERSION_QUERY,\n })\n}\n\n/**\n * Deletes a text track from an asset\n */\nexport function deleteTextTrack(client: SanityClient, assetId: string, trackId: string) {\n const {dataset} = client.config()\n return client.request<{data: MuxAsset}>({\n url: `/addons/mux/assets/${dataset}/${assetId}/tracks/${trackId}`,\n withCredentials: true,\n method: 'DELETE',\n query: PLUGIN_VERSION_QUERY,\n })\n}\n\n/**\n * Updates master access (the \"mezzanine\" file in Mux's docs) on a Mux asset, via the addon proxy.\n * @see {@link https://docs.mux.com/api-reference/video/assets/update-asset-master-access}\n */\nexport function updateMasterAccess(\n client: SanityClient,\n assetId: string,\n masterAccess: 'temporary' | 'none',\n) {\n const {dataset} = client.config()\n return client.request<{data: MuxAsset}>({\n url: `/addons/mux/assets/${dataset}/${assetId}/master-access`,\n withCredentials: true,\n method: 'PUT',\n body: {master_access: masterAccess},\n headers: {\n 'Content-Type': 'application/json',\n },\n query: PLUGIN_VERSION_QUERY,\n })\n}\n","import {useEffect, useState} from 'react'\nimport {defer, of, timer} from 'rxjs'\nimport {concatMap, expand, tap} from 'rxjs/operators'\nimport type {SanityClient} from 'sanity'\n\nimport {listAssets} from '../actions/assets'\nimport type {MuxAsset} from '../util/types'\n\nconst ASSETS_PER_PAGE = 100\n\ntype MuxAssetsState = {\n cursor: string | null\n loading: boolean\n data?: MuxAsset[]\n error?: FetchError\n hasSkippedAssetsWithoutPlayback?: boolean\n}\n\ntype FetchError =\n | {\n _tag: 'FetchError'\n }\n | {_tag: 'MuxError'; error: unknown}\n\ntype PageResult = (\n | {\n data: MuxAsset[]\n next_cursor: string | null\n }\n | {\n error: FetchError\n }\n) & {\n cursor: string | null\n}\n\n/**\n * @docs {@link https://docs.mux.com/api-reference#video/operation/list-assets}\n */\nasync function fetchMuxAssetsPage(\n client: SanityClient,\n cursor: string | null,\n): Promise<PageResult> {\n try {\n const response = await listAssets(client, {\n limit: ASSETS_PER_PAGE,\n cursor,\n })\n\n return {\n cursor,\n data: response.data,\n next_cursor: response.next_cursor || null,\n }\n } catch {\n return {\n cursor,\n error: {_tag: 'FetchError'},\n }\n }\n}\n\nfunction accumulateIntermediateState(\n currentState: MuxAssetsState,\n pageResult: PageResult,\n): MuxAssetsState {\n const currentData = ('data' in currentState && currentState.data) || []\n const newAssets = ('data' in pageResult && pageResult.data) || []\n\n // Filter assets and check for skipped items\n const {validAssets, skippedInThisPage} = newAssets.reduce<{\n validAssets: MuxAsset[]\n skippedInThisPage: boolean\n }>(\n (acc, asset) => {\n const hasPlaybackIds = asset.playback_ids && asset.playback_ids.length > 0\n const isDuplicate = currentData.some((a) => a.id === asset.id)\n\n if (!hasPlaybackIds) {\n acc.skippedInThisPage = true\n }\n\n if (hasPlaybackIds && !isDuplicate) {\n acc.validAssets.push(asset)\n }\n\n return acc\n },\n {validAssets: [], skippedInThisPage: false},\n )\n\n return {\n ...currentState,\n data: [...currentData, ...validAssets],\n error:\n 'error' in pageResult\n ? pageResult.error\n : // Reset error if current page is successful\n undefined,\n cursor: 'next_cursor' in pageResult ? pageResult.next_cursor : pageResult.cursor,\n loading: true,\n hasSkippedAssetsWithoutPlayback:\n currentState.hasSkippedAssetsWithoutPlayback || skippedInThisPage,\n }\n}\n\nfunction hasMorePages(pageResult: PageResult) {\n return (\n typeof pageResult === 'object' && 'next_cursor' in pageResult && pageResult.next_cursor !== null\n )\n}\n\n/**\n * Fetches all assets from a Mux environment. Rules:\n * - One page at a time\n * - Uses cursor-based pagination\n * - We've finished fetching when `next_cursor` is null\n * - Rate limiting to one request per 2 seconds\n * - Update state while still fetching to give feedback to users\n */\nexport default function useMuxAssets({client, enabled}: {client: SanityClient; enabled: boolean}) {\n const [state, setState] = useState<MuxAssetsState>({loading: true, cursor: null})\n\n useEffect(() => {\n if (!enabled) return\n\n const subscription = defer(() =>\n fetchMuxAssetsPage(\n client,\n // When we've already successfully loaded before (fully or partially), we start from the next cursor to avoid re-fetching\n 'data' in state && state.data && state.data.length > 0 && !state.error\n ? state.cursor\n : null,\n ),\n )\n .pipe(\n // Here we use \"expand\" to recursively fetch next pages\n expand((pageResult) => {\n // if fetched page has next_cursor, we continue emitting, requesting the next page\n // after 2s to avoid rate limiting\n if (hasMorePages(pageResult)) {\n return timer(2000).pipe(\n concatMap(() =>\n defer(() =>\n fetchMuxAssetsPage(\n client,\n 'next_cursor' in pageResult ? pageResult.next_cursor : null,\n ),\n ),\n ),\n )\n }\n\n // Else, we stop emitting\n return of()\n }),\n\n // On each iteration, persist intermediate states to give feedback to users\n tap((pageResult) =>\n setState((prevState) => accumulateIntermediateState(prevState, pageResult)),\n ),\n )\n .subscribe({\n // Once done, let the user know we've stopped loading\n complete: () => {\n setState((prev) => ({\n ...prev,\n loading: false,\n }))\n },\n })\n\n // Unsubscribe on component unmount to prevent memory leaks or fetching unnecessarily\n return () => subscription.unsubscribe()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled])\n\n return state\n}\n","import {uuid} from '@sanity/uuid'\nimport {useMemo, useState} from 'react'\nimport {\n createHookFromObservableFactory,\n type DocumentStore,\n useClient,\n useDocumentStore,\n} from 'sanity'\n\nimport {generateAssetPlaceholder} from '../util/assetTitlePlaceholder'\nimport {parseMuxDate} from '../util/parsers'\nimport type {MuxAsset, VideoAssetDocument} from '../util/types'\nimport {SANITY_API_VERSION} from './useClient'\nimport useMuxAssets from './useMuxAssets'\nimport {useSecretsDocumentValues} from './useSecretsDocumentValues'\n\ntype ImportState = 'closed' | 'idle' | 'importing' | 'done' | 'error'\n\nexport type AssetInSanity = {\n uploadId: string\n assetId: string\n}\n\nexport default function useImportMuxAssets() {\n const documentStore = useDocumentStore()\n const client = useClient({\n apiVersion: SANITY_API_VERSION,\n })\n\n const [assetsInSanity, assetsInSanityLoading] = useAssetsInSanity(documentStore)\n\n const secretDocumentValues = useSecretsDocumentValues()\n const hasSecrets = !!secretDocumentValues.value.secrets?.secretKey\n\n const [importError, setImportError] = useState<unknown>()\n const [importState, setImportState] = useState<ImportState>('closed')\n const dialogOpen = importState !== 'closed'\n\n const muxAssets = useMuxAssets({\n client,\n enabled: hasSecrets && dialogOpen,\n })\n\n const missingAssets = useMemo(() => {\n return assetsInSanity && muxAssets.data\n ? muxAssets.data.filter((a) => !assetExistsInSanity(a, assetsInSanity))\n : undefined\n }, [assetsInSanity, muxAssets.data])\n\n const [selectedAssets, setSelectedAssets] = useState<MuxAsset[]>([])\n\n const closeDialog = () => {\n if (importState !== 'importing') setImportState('closed')\n }\n const openDialog = () => {\n if (importState === 'closed') setImportState('idle')\n }\n\n async function importAssets() {\n setImportState('importing')\n const documents = selectedAssets.flatMap((asset) => muxAssetToSanityDocument(asset) || [])\n\n const tx = client.transaction()\n documents.forEach((doc) => tx.create(doc))\n\n try {\n await tx.commit({returnDocuments: false})\n setSelectedAssets([])\n setImportState('done')\n } catch (error) {\n setImportState('error')\n setImportError(error)\n }\n }\n\n return {\n assetsInSanityLoading,\n closeDialog,\n dialogOpen,\n importState,\n importError,\n hasSecrets,\n importAssets,\n missingAssets,\n muxAssets,\n openDialog,\n selectedAssets,\n setSelectedAssets,\n }\n}\n\nfunction muxAssetToSanityDocument(asset: MuxAsset): VideoAssetDocument | undefined {\n const playbackId = (asset.playback_ids || []).find((p) => p.id)?.id\n\n if (!playbackId) return undefined\n\n return {\n _id: uuid(),\n _type: 'mux.videoAsset',\n _updatedAt: new Date().toISOString(),\n _createdAt: parseMuxDate(asset.created_at).toISOString(),\n assetId: asset.id,\n playbackId,\n filename: asset.meta?.title ?? generateAssetPlaceholder(asset.id),\n status: asset.status,\n data: asset,\n }\n}\n\nconst useAssetsInSanity = createHookFromObservableFactory<AssetInSanity[], DocumentStore>(\n (documentStore) => {\n return documentStore.listenQuery(\n /* groq */ `*[_type == \"mux.videoAsset\"] {\n \"uploadId\": coalesce(uploadId, data.upload_id),\n \"assetId\": coalesce(assetId, data.id),\n }`,\n {},\n {\n apiVersion: SANITY_API_VERSION,\n },\n )\n },\n)\n\nfunction assetExistsInSanity(asset: MuxAsset, existingAssets: AssetInSanity[]) {\n // Don't allow importing assets that are not ready\n if (asset.status !== 'ready') return false\n\n return existingAssets.some(\n (existing) => existing.assetId === asset.id || existing.uploadId === asset.upload_id,\n )\n}\n","import {useEffect, useState} from 'react'\n\ntype IntersectionOptions = {\n root?: Element | null\n rootMargin?: string\n threshold?: number\n onChange?: (inView: boolean) => void\n}\n\nexport function useInView(\n ref: React.RefObject<HTMLDivElement | null>,\n options: IntersectionOptions = {},\n) {\n const [inView, setInView] = useState(false)\n\n useEffect(() => {\n if (!ref.current) return\n\n const observer = new IntersectionObserver(([entry], obs) => {\n // ==== from react-intersection-observer ====\n // 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.\n // -Firefox ignores `threshold` when considering `isIntersecting`, so it will never be false again if `threshold` is > 0\n const nowInView =\n entry!.isIntersecting &&\n obs.thresholds.some((threshold) => entry!.intersectionRatio >= threshold)\n\n // Update our state when observer callback fires\n setInView(nowInView)\n options?.onChange?.(nowInView)\n }, options)\n\n const toObserve = ref.current\n observer.observe(toObserve)\n\n return () => {\n if (toObserve) observer.unobserve(toObserve)\n }\n }, [options, ref])\n\n return inView\n}\n","import type {\n AdvancedPlaybackPolicy,\n MuxPlaybackId,\n PlaybackPolicy,\n VideoAssetDocument,\n} from './types'\n\n/* - Returns the playback id of the asset based on the specified priority.\n By default chooses the \"strongest\" policy\n - Otherwise, returns the first playback id in the array.\n */\nexport function getPlaybackId(\n asset: Pick<VideoAssetDocument, 'data'>,\n priority: string[] = ['drm', 'signed', 'public'],\n): string {\n try {\n if (!asset) {\n throw new TypeError('Tried to get playback Id with no asset')\n }\n\n const playbackIds = asset.data?.playback_ids\n if (playbackIds && playbackIds.length > 0) {\n for (const policy of priority) {\n const match = playbackIds.find((entry) => entry.policy === policy)\n if (match) {\n return match.id\n }\n }\n\n return playbackIds[0]!.id\n }\n\n throw new TypeError('Missing playbackId')\n } catch (e) {\n console.error('Asset is missing a playbackId', {asset}, e)\n throw e\n }\n}\n\nexport function getPlaybackPolicy(\n asset: Pick<VideoAssetDocument, 'data' | 'playbackId'>,\n): MuxPlaybackId | undefined {\n return (\n asset.data?.playback_ids?.find(\n (playbackId) => getPlaybackId(asset, ['drm', 'signed', 'public']) === playbackId.id,\n ) ?? {id: '', policy: 'public'}\n )\n}\n\nexport function getPlaybackPolicyById(\n asset: Pick<VideoAssetDocument, 'data'>,\n playbackId: string,\n): MuxPlaybackId | undefined {\n return asset.data?.playback_ids?.find((entry) => playbackId === entry.id)\n}\n\nexport function hasPlaybackPolicy(\n data: Partial<{\n playback_policy?: PlaybackPolicy[]\n advanced_playback_policies: AdvancedPlaybackPolicy[]\n }>,\n policy: PlaybackPolicy,\n) {\n return (\n (data.advanced_playback_policies &&\n data.advanced_playback_policies.find((p) => p.policy === policy)) ||\n data.playback_policy?.find((p) => p === policy)\n )\n}\n","import type {SanityClient} from 'sanity'\nimport {suspend} from 'suspend-react'\n\nimport {readSecrets} from './readSecrets'\nimport type {AnimatedThumbnailOptions, ThumbnailOptions} from './types'\n\nexport type Audience = 'g' | 's' | 't' | 'v' | 'd'\n\nexport type Payload<T extends Audience> = T extends 'g'\n ? AnimatedThumbnailOptions\n : T extends 's'\n ? never\n : T extends 't'\n ? ThumbnailOptions\n : T extends 'v'\n ? never\n : T extends 'd'\n ? never\n : never\n\n/**\n * Uses suspend. Call this with {@link tryWithSuspend} or rethrow the Promise\n */\nexport function generateJwt<T extends Audience>(\n client: SanityClient,\n playbackId: string,\n aud: T,\n payload?: Payload<T>,\n): string {\n const {signingKeyId, signingKeyPrivate} = readSecrets(client)\n if (!signingKeyId) {\n throw new TypeError(\"Missing `signingKeyId`.\\n Check your plugin's configuration\")\n }\n if (!signingKeyPrivate) {\n throw new TypeError(\"Missing `signingKeyPrivate`.\\n Check your plugin's configuration\")\n }\n\n /* Using suspend means we need to use Suspense on parent components.\n Also, this will throw a Promise under the hood (apparently common in React), \n so if we want to catch errors we have to take this into account in catch blocks\n and rethrow promises. */\n // @ts-expect-error - handle missing typings for this package\n const {default: sign} = suspend(() => import('jsonwebtoken-esm/sign'), ['jsonwebtoken-esm/sign'])\n\n return sign(\n payload ? JSON.parse(JSON.stringify(payload, (_, v) => v ?? undefined)) : {},\n atob(signingKeyPrivate),\n {\n algorithm: 'RS256',\n keyid: signingKeyId,\n audience: aud,\n subject: playbackId,\n noTimestamp: true,\n expiresIn: '12h',\n },\n )\n}\n","import type {SanityClient} from 'sanity'\n\nimport {getPlaybackId} from '../util/getPlaybackPolicy'\nimport {type Audience, generateJwt} from './generateJwt'\nimport {getPlaybackPolicyById} from './getPlaybackPolicy'\nimport type {AssetThumbnailOptions} from './types'\n\n/**\n * May throw a Promise. Call this with {@link tryWithSuspend} or rethrow the Promise\n */\nexport function createUrlParamsObject(\n client: SanityClient,\n asset: AssetThumbnailOptions['asset'],\n params: object,\n audience: Audience,\n) {\n const playbackId = getPlaybackId(asset)\n\n let searchParams = new URLSearchParams(\n JSON.parse(JSON.stringify(params, (_, v) => v ?? undefined)),\n )\n const playbackPolicy = getPlaybackPolicyById(asset, playbackId)?.policy\n if (playbackPolicy === 'signed' || playbackPolicy === 'drm') {\n const token = generateJwt(client, playbackId, audience, params)\n searchParams = new URLSearchParams({token})\n }\n\n return {playbackId, searchParams}\n}\n","import type {SanityClient} from 'sanity'\n\nimport {createUrlParamsObject} from './createUrlParamsObject'\nimport type {AnimatedThumbnailOptions, MuxAnimatedThumbnailUrl} from './types'\nimport {type AssetThumbnailOptions} from './types'\n\nexport interface AnimatedPosterSrcOptions extends AnimatedThumbnailOptions {\n asset: AssetThumbnailOptions['asset']\n client: SanityClient\n}\n\nexport function getAnimatedPosterSrc({\n asset,\n client,\n height,\n width,\n start = asset.thumbTime ? Math.max(0, asset.thumbTime - 2.5) : 0,\n end = start + 5,\n fps = 15,\n}: AnimatedPosterSrcOptions): MuxAnimatedThumbnailUrl {\n const params = {height, width, start, end, fps}\n\n const {playbackId, searchParams} = createUrlParamsObject(client, asset, params, 'g')\n\n return `https://image.mux.com/${playbackId}/animated.gif?${searchParams}`\n}\n","import type {SanityClient} from 'sanity'\n\nimport {createUrlParamsObject} from './createUrlParamsObject'\nimport type {MuxThumbnailUrl, ThumbnailOptions} from './types'\nimport {type AssetThumbnailOptions} from './types'\n\nexport interface PosterSrcOptions extends ThumbnailOptions {\n asset: AssetThumbnailOptions['asset']\n client: SanityClient\n}\n\nexport function getPosterSrc({\n asset,\n client,\n fit_mode,\n height,\n time = asset.thumbTime ?? undefined,\n width,\n}: PosterSrcOptions): MuxThumbnailUrl {\n const params = {fit_mode, height, width}\n if (time !== undefined) {\n ;(params as any).time = time\n }\n\n const {playbackId, searchParams} = createUrlParamsObject(client, asset, params, 't')\n\n return `https://image.mux.com/${playbackId}/thumbnail.png?${searchParams}`\n}\n","/**\n * When running `suspend()` from react-suspend a function may throw a Promise\n * causing unexpected behavior when catching.\n * @param block Your block of code that uses suspend\n * @param onError (optional) How to handle a regular Error\n * @returns Whatever is returned by the block if it succeeds, otherwise whatever is resolved by onError if defined\n * @throws rethrows the caught Promise to comply with Suspense logic\n */\nexport function tryWithSuspend<T, E>(\n block: () => T,\n onError?: (error: Error) => E,\n): T | E | undefined {\n try {\n return block()\n } catch (errorOrPromise) {\n if (errorOrPromise instanceof Promise) {\n // react-suspend will throw a Promise\n throw errorOrPromise\n }\n return onError ? onError(errorOrPromise as Error) : undefined\n }\n}\n","import {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {Box, Card, type CardTone, Spinner, Stack, Text} from '@sanity/ui'\nimport {Suspense, useMemo, useRef, useState} from 'react'\nimport {styled} from 'styled-components'\n\nimport {useClient} from '../hooks/useClient'\nimport {useInView} from '../hooks/useInView'\nimport {THUMBNAIL_ASPECT_RATIO} from '../util/constants'\nimport {getAnimatedPosterSrc} from '../util/getAnimatedPosterSrc'\nimport {getPosterSrc} from '../util/getPosterSrc'\nimport {tryWithSuspend} from '../util/tryWithSuspend'\nimport type {AssetThumbnailOptions, MuxAnimatedThumbnailUrl, MuxThumbnailUrl} from '../util/types'\n\nconst Image = styled.img`\n transition: opacity 0.175s ease-out 0s;\n display: block;\n width: 100%;\n height: 100%;\n object-fit: contain;\n object-position: center center;\n`\n\ntype ImageStatus = 'loading' | 'error' | 'loaded'\n\nconst STATUS_TO_TONE: Record<ImageStatus, CardTone> = {\n loading: 'transparent',\n error: 'critical',\n loaded: 'default',\n}\n\n// oxlint-disable-next-line react/react-compiler\nexport default function VideoThumbnail({\n asset,\n width,\n staticImage = false,\n}: {\n asset: AssetThumbnailOptions['asset']\n width?: number\n staticImage?: boolean\n}) {\n const posterWidth = width || 250\n const client = useClient()\n const ref = useRef<HTMLDivElement | null>(null)\n const inView = useInView(ref)\n\n const [status, setStatus] = useState<ImageStatus>('loading')\n const [error, setError] = useState<string | null>(null)\n\n const thumbnailSrc = useMemo(() => {\n return tryWithSuspend(\n () => {\n let thumbnail: MuxAnimatedThumbnailUrl | MuxThumbnailUrl | undefined\n\n if (staticImage) thumbnail = getPosterSrc({asset, client, width: posterWidth})\n else thumbnail = getAnimatedPosterSrc({asset, client, width: posterWidth})\n return thumbnail\n },\n (err: Error) => {\n handleError(err.message)\n return undefined\n },\n )\n }, [asset, client, posterWidth, staticImage])\n\n function handleLoad() {\n setStatus('loaded')\n }\n\n function handleError(err?: string) {\n setStatus('error')\n if (err) {\n setError(err)\n } else {\n setError('Failed loading thumbnail')\n }\n }\n\n return (\n <Suspense fallback={<span>Preparing thumbnail</span>}>\n <Card\n style={{\n aspectRatio: THUMBNAIL_ASPECT_RATIO,\n position: 'relative',\n maxWidth: width ? `${width}px` : undefined,\n width: '100%',\n flex: 1,\n }}\n border\n radius={2}\n ref={ref}\n tone={STATUS_TO_TONE[status]}\n >\n {inView ? (\n <>\n {status === 'loading' && (\n <Box\n style={{\n position: 'absolute',\n left: '50%',\n top: '50%',\n transform: 'translate(-50%, -50%)',\n }}\n >\n <Spinner />\n </Box>\n )}\n {status === 'error' && (\n <Stack\n space={4}\n style={{\n position: 'absolute',\n width: '100%',\n left: 0,\n top: '50%',\n transform: 'translateY(-50%)',\n justifyItems: 'center',\n }}\n >\n <Text size={4} muted>\n <ErrorOutlineIcon style={{fontSize: '1.75em'}} />\n </Text>\n <Text muted align=\"center\">\n {error}\n </Text>\n </Stack>\n )}\n <Image\n src={thumbnailSrc ?? undefined}\n alt={`Preview for ${staticImage ? 'image' : 'video'} ${asset.filename || asset.assetId}`}\n onLoad={handleLoad}\n onError={() => handleError()}\n style={{opacity: status === 'loaded' ? 1 : 0}}\n />\n </>\n ) : null}\n </Card>\n </Suspense>\n )\n}\n","import {CheckmarkCircleIcon} from '@sanity/icons/CheckmarkCircle'\nimport {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {InfoOutlineIcon} from '@sanity/icons/InfoOutline'\nimport {RetrieveIcon} from '@sanity/icons/Retrieve'\nimport {RetryIcon} from '@sanity/icons/Retry'\nimport {\n Box,\n Button,\n Card,\n Checkbox,\n Code,\n Dialog,\n Flex,\n Heading,\n Spinner,\n Stack,\n Text,\n} from '@sanity/ui'\nimport {truncateString, useFormattedDuration} from 'sanity'\nimport {styled} from 'styled-components'\n\nimport useImportMuxAssets from '../hooks/useImportMuxAssets'\nimport {DIALOGS_Z_INDEX} from '../util/constants'\nimport type {MuxAsset} from '../util/types'\nimport VideoThumbnail from './VideoThumbnail'\n\nconst MissingAssetCheckbox = styled(Checkbox)`\n position: static !important;\n\n input::after {\n content: '';\n position: absolute;\n inset: 0;\n display: block;\n cursor: pointer;\n z-index: 1000;\n }\n`\n\nfunction MissingAsset({\n asset,\n selectAsset,\n selected,\n}: {\n asset: MuxAsset\n selectAsset: (selected: boolean) => void\n selected: boolean\n}) {\n const duration = useFormattedDuration(asset.duration * 1000)\n\n return (\n <Card\n key={asset.id}\n tone={selected ? 'positive' : undefined}\n border\n paddingX={2}\n paddingY={3}\n style={{position: 'relative'}}\n radius={1}\n >\n <Flex align=\"center\" gap={2}>\n <MissingAssetCheckbox\n checked={selected}\n onChange={(e) => {\n selectAsset(e.currentTarget.checked)\n }}\n aria-label={selected ? `Import video ${asset.id}` : `Skip import of video ${asset.id}`}\n />\n <VideoThumbnail\n asset={{\n assetId: asset.id,\n data: asset,\n filename: asset.id,\n playbackId: asset.playback_ids.find((p) => p.id)?.id,\n }}\n width={150}\n />\n <Stack space={2}>\n <Flex align=\"center\" gap={1}>\n <Code size={2}>{truncateString(asset.id, 15)}</Code>{' '}\n <Text muted size={2}>\n ({duration.formatted})\n </Text>\n </Flex>\n <Text size={1}>\n Uploaded at{' '}\n {new Date(Number(asset.created_at) * 1000).toLocaleDateString('en', {\n year: 'numeric',\n day: '2-digit',\n month: '2-digit',\n })}\n </Text>\n </Stack>\n </Flex>\n </Card>\n )\n}\n\nfunction ImportVideosDialog(props: ReturnType<typeof useImportMuxAssets>) {\n const {importState} = props\n\n const canTriggerImport =\n (importState === 'idle' || importState === 'error') && props.selectedAssets.length > 0\n const isImporting = importState === 'importing'\n const noAssetsToImport =\n props.missingAssets?.length === 0 && !props.muxAssets.loading && !props.assetsInSanityLoading\n\n return (\n <Dialog\n animate\n header={'Import videos from Mux'}\n zOffset={DIALOGS_Z_INDEX}\n id=\"video-details-dialog\"\n onClose={props.closeDialog}\n onClickOutside={props.closeDialog}\n width={1}\n position=\"fixed\"\n footer={\n importState !== 'done' &&\n !noAssetsToImport && (\n <Card padding={3}>\n <Flex justify=\"space-between\" align=\"center\">\n <Button\n fontSize={2}\n padding={3}\n mode=\"ghost\"\n text=\"Cancel\"\n tone=\"critical\"\n onClick={props.closeDialog}\n disabled={isImporting}\n />\n {props.missingAssets && (\n <Button\n icon={RetrieveIcon}\n fontSize={2}\n padding={3}\n mode=\"ghost\"\n text={\n props.selectedAssets?.length > 0\n ? `Import ${props.selectedAssets.length} video(s)`\n : 'No video(s) selected'\n }\n tone=\"positive\"\n onClick={props.importAssets}\n iconRight={isImporting && Spinner}\n disabled={!canTriggerImport}\n />\n )}\n </Flex>\n </Card>\n )\n }\n >\n <Box padding={3}>\n {/* WARNING: SKIPPED ASSETS WITHOUT PLAYBACK */}\n {props.muxAssets.hasSkippedAssetsWithoutPlayback && (\n <Card tone=\"caution\" marginBottom={5} padding={3} border>\n <Flex align=\"center\" gap={2}>\n <InfoOutlineIcon fontSize={36} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n Some videos were skipped\n </Text>\n <Text size={1}>\n Videos without playback IDs cannot be imported and have been excluded from the\n list.\n </Text>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* LOADING ASSETS STATE */}\n {(props.muxAssets.loading || props.assetsInSanityLoading) && (\n <Card tone=\"primary\" marginBottom={5} padding={3} border>\n <Flex align=\"center\" gap={4}>\n <Spinner muted size={4} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n Loading assets from Mux\n </Text>\n <Text size={1}>\n This may take a while.\n {props.missingAssets &&\n props.missingAssets.length > 0 &&\n ` There are at least ${props.missingAssets.length} video${props.missingAssets.length > 1 ? 's' : ''} currently not in Sanity...`}\n </Text>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* ERROR LOADING MUX */}\n {props.muxAssets.error && (\n <Card tone=\"critical\" marginBottom={5} padding={3} border>\n <Flex align=\"center\" gap={2}>\n <ErrorOutlineIcon fontSize={36} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n There was an error getting all data from Mux\n </Text>\n <Text size={1}>\n {props.missingAssets\n ? `But we've found ${props.missingAssets.length} video${props.missingAssets.length > 1 ? 's' : ''} not in Sanity, which you can start importing now.`\n : 'Please try again or contact a developer for help.'}\n </Text>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* IMPORTING STATE */}\n {importState === 'importing' && (\n <Card tone=\"primary\" marginBottom={5} padding={3} border>\n <Flex align=\"center\" gap={4}>\n <Spinner muted size={4} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n Importing {props.selectedAssets.length} video\n {props.selectedAssets.length > 1 && 's'} from Mux\n </Text>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* ERROR IMPORTING */}\n {importState === 'error' && (\n <Card tone=\"critical\" marginBottom={5} padding={3} border>\n <Flex align=\"center\" gap={2}>\n <ErrorOutlineIcon fontSize={36} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n There was an error importing videos\n </Text>\n <Text size={1}>\n {props.importError\n ? `Error: ${props.importError}`\n : 'Please try again or contact a developer for help.'}\n </Text>\n <Box marginTop={1}>\n <Button\n icon={RetryIcon}\n text=\"Retry\"\n tone=\"primary\"\n onClick={props.importAssets}\n />\n </Box>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* NO ASSETS TO IMPORT or SUCESS STATE */}\n {(noAssetsToImport || importState === 'done') && (\n <Stack paddingY={5} marginBottom={4} space={3} style={{textAlign: 'center'}}>\n <Box>\n <CheckmarkCircleIcon fontSize={48} />\n </Box>\n <Heading size={2}>\n {importState === 'done'\n ? `Videos imported successfully`\n : 'There are no Mux videos to import'}\n </Heading>\n <Text size={2}>\n {importState === 'done'\n ? 'You can now use them in your Sanity content.'\n : \"They're all in Sanity and ready to be used in your content.\"}\n </Text>\n </Stack>\n )}\n\n {/* MISSING ASSETS SELECTOR */}\n {props.missingAssets &&\n props.missingAssets.length > 0 &&\n (importState === 'idle' || importState === 'error') && (\n <Stack space={4}>\n <Heading size={1}>\n There are {props.missingAssets.length}\n {props.muxAssets.loading && '+'} Mux video{props.missingAssets.length > 1 && 's'}{' '}\n not in Sanity\n </Heading>\n {!props.muxAssets.loading && (\n <Flex align=\"center\" paddingX={2}>\n <Checkbox\n id=\"import-all\"\n style={{display: 'block'}}\n onClick={(e) => {\n const selectAll = e.currentTarget.checked\n if (selectAll) {\n // eslint-disable-next-line no-unused-expressions\n props.missingAssets && props.setSelectedAssets(props.missingAssets)\n } else {\n props.setSelectedAssets([])\n }\n }}\n checked={props.selectedAssets.length === props.missingAssets.length}\n />\n <Box flex={1} paddingLeft={3} as=\"label\" htmlFor=\"import-all\">\n <Text>Import all</Text>\n </Box>\n </Flex>\n )}\n {props.missingAssets.map((asset) => (\n <MissingAsset\n key={asset.id}\n asset={asset}\n selectAsset={(selected) => {\n if (selected) {\n props.setSelectedAssets([...props.selectedAssets, asset])\n } else {\n props.setSelectedAssets(props.selectedAssets.filter((a) => a.id !== asset.id))\n }\n }}\n selected={props.selectedAssets.some((a) => a.id === asset.id)}\n />\n ))}\n </Stack>\n )}\n </Box>\n </Dialog>\n )\n}\n\nexport default function ImportVideosFromMux() {\n const importAssets = useImportMuxAssets()\n\n if (!importAssets.hasSecrets) {\n return\n }\n\n if (importAssets.dialogOpen) {\n return <ImportVideosDialog {...importAssets} />\n }\n\n return <Button mode=\"bleed\" text=\"Import from Mux\" onClick={importAssets.openDialog} />\n}\n","import {ChevronLeftIcon} from '@sanity/icons/ChevronLeft'\nimport {ChevronRightIcon} from '@sanity/icons/ChevronRight'\nimport {Button, Label} from '@sanity/ui'\nimport {type Dispatch, type SetStateAction, useEffect} from 'react'\n\nconst PageSelector = (props: {\n page: number\n setPage: Dispatch<SetStateAction<number>>\n total: number\n}) => {\n const page = props.page\n const setPage = props.setPage\n\n useEffect(() => {\n // Constraint in bounds.\n const clamped = Math.min(props.total - 1, Math.max(0, page))\n if (page !== clamped) {\n setPage(clamped)\n }\n }, [page, props.total, setPage])\n\n return (\n <>\n <Button\n icon={ChevronLeftIcon}\n mode=\"bleed\"\n padding={3}\n style={{cursor: 'pointer'}}\n disabled={page <= 0}\n onClick={() => {\n setPage((p) => {\n return Math.min(props.total - 1, Math.max(0, p - 1))\n })\n }}\n />\n <Label muted>\n Page {page + 1}/{props.total}\n </Label>\n <Button\n icon={ChevronRightIcon}\n mode=\"bleed\"\n padding={3}\n style={{cursor: 'pointer'}}\n disabled={page >= props.total - 1}\n onClick={() => {\n setPage((p) => {\n return Math.min(props.total - 1, Math.max(0, p + 1))\n })\n }}\n />\n </>\n )\n}\n\nexport default PageSelector\n","import type {MuxAsset} from './types'\n\n/**\n * Adds a `_key` to array items in MuxAsset data (Sanity requires `_key` on array\n * items). Keys are derived from each item's stable Mux `id`, so repeated calls\n * are idempotent and don't churn the document — important because the asset is\n * persisted on every poll while it prepares.\n */\nexport function addKeysToMuxData(data: MuxAsset): MuxAsset {\n return {\n ...data,\n tracks: data.tracks?.map((track, index) => ({\n ...track,\n _key: track.id || `track-${index}`,\n })),\n playback_ids: data.playback_ids?.map((playbackId, index) => ({\n ...playbackId,\n _key: playbackId.id || `playback-${index}`,\n })),\n static_renditions: data.static_renditions\n ? {\n ...data.static_renditions,\n files: data.static_renditions.files?.map((file, index) => ({\n ...file,\n _key: file.id || `rendition-${index}`,\n })),\n }\n : undefined,\n }\n}\n","import {useMemo, useState} from 'react'\nimport {\n createHookFromObservableFactory,\n type DocumentStore,\n useClient,\n useDocumentStore,\n} from 'sanity'\n\nimport {addKeysToMuxData} from '../util/addKeysToMuxData'\nimport {isEmptyOrPlaceholderTitle} from '../util/assetTitlePlaceholder'\nimport type {VideoAssetDocument} from '../util/types'\nimport {SANITY_API_VERSION} from './useClient'\nimport useMuxAssets from './useMuxAssets'\nimport {useSecretsDocumentValues} from './useSecretsDocumentValues'\n\ntype ResyncState = 'closed' | 'idle' | 'syncing' | 'done' | 'error'\n\nexport default function useResyncMuxMetadata() {\n const documentStore = useDocumentStore()\n const client = useClient({\n apiVersion: SANITY_API_VERSION,\n })\n\n const [sanityAssets, sanityAssetsLoading] = useSanityAssets(documentStore)\n\n const secretDocumentValues = useSecretsDocumentValues()\n const hasSecrets = !!secretDocumentValues.value.secrets?.secretKey\n\n const [resyncError, setResyncError] = useState<unknown>()\n const [resyncState, setResyncState] = useState<ResyncState>('closed')\n const dialogOpen = resyncState !== 'closed'\n\n const muxAssets = useMuxAssets({\n client,\n enabled: hasSecrets && dialogOpen,\n })\n\n const matchedAssets = useMemo(() => {\n return sanityAssets && muxAssets.data\n ? sanityAssets.map((sanityDoc) => {\n const muxAsset = muxAssets.data?.find(\n (m) => m.id === sanityDoc.assetId || m.id === sanityDoc.data?.id,\n )\n return {\n sanityDoc,\n muxAsset,\n muxTitle: muxAsset?.meta?.title,\n currentTitle: sanityDoc.filename,\n }\n })\n : undefined\n }, [sanityAssets, muxAssets.data])\n\n const closeDialog = () => {\n if (resyncState !== 'syncing') setResyncState('closed')\n }\n\n const openDialog = () => {\n if (resyncState === 'closed') setResyncState('idle')\n }\n\n async function syncAllVideos() {\n if (!matchedAssets) return\n\n setResyncState('syncing')\n\n try {\n const tx = client.transaction()\n\n matchedAssets.forEach((matched) => {\n // Update all videos with the Mux title, even if it's undefined/empty\n const newTitle = matched.muxTitle || ''\n tx.patch(matched.sanityDoc._id, {set: {filename: newTitle}})\n })\n\n await tx.commit({returnDocuments: false})\n setResyncState('done')\n } catch (error) {\n setResyncState('error')\n setResyncError(error)\n }\n }\n\n async function syncOnlyEmpty() {\n if (!matchedAssets) return\n\n setResyncState('syncing')\n\n try {\n const tx = client.transaction()\n\n matchedAssets.forEach((matched) => {\n // Only update if the current title is empty or has the placeholder format\n // AND there's a new title available from Mux\n if (\n matched.muxAsset &&\n matched.muxTitle &&\n isEmptyOrPlaceholderTitle(matched.currentTitle, matched.muxAsset.id)\n ) {\n tx.patch(matched.sanityDoc._id, {set: {filename: matched.muxTitle}})\n }\n })\n\n await tx.commit({returnDocuments: false})\n setResyncState('done')\n } catch (error) {\n setResyncState('error')\n setResyncError(error)\n }\n }\n\n async function syncFullData() {\n if (!matchedAssets) return\n\n setResyncState('syncing')\n\n try {\n const tx = client.transaction()\n\n matchedAssets.forEach((matched) => {\n if (!matched.muxAsset) return\n\n const dataWithKeys = addKeysToMuxData(matched.muxAsset)\n\n // Update all fields: filename, status, and full data from Mux\n tx.patch(matched.sanityDoc._id, {\n set: {\n filename: matched.muxTitle || matched.currentTitle || '',\n status: matched.muxAsset.status,\n data: dataWithKeys,\n },\n })\n })\n\n await tx.commit({returnDocuments: false})\n setResyncState('done')\n } catch (error) {\n setResyncState('error')\n setResyncError(error)\n }\n }\n\n return {\n sanityAssetsLoading,\n closeDialog,\n dialogOpen,\n resyncState,\n resyncError,\n hasSecrets,\n syncAllVideos,\n syncOnlyEmpty,\n syncFullData,\n matchedAssets,\n muxAssets,\n openDialog,\n }\n}\n\nconst useSanityAssets = createHookFromObservableFactory<VideoAssetDocument[], DocumentStore>(\n (documentStore) => {\n return documentStore.listenQuery(\n /* groq */ `*[_type == \"mux.videoAsset\"]`,\n {},\n {\n apiVersion: SANITY_API_VERSION,\n },\n )\n },\n)\n","import {CheckmarkCircleIcon} from '@sanity/icons/CheckmarkCircle'\nimport {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {SyncIcon} from '@sanity/icons/Sync'\nimport {Box, Button, Card, Dialog, Flex, Heading, Radio, Spinner, Stack, Text} from '@sanity/ui'\nimport {useState} from 'react'\n\nimport useResyncMuxMetadata from '../hooks/useResyncMuxMetadata'\nimport {isEmptyOrPlaceholderTitle} from '../util/assetTitlePlaceholder'\nimport {DIALOGS_Z_INDEX} from '../util/constants'\n\ntype SyncOption = 'fillEmpty' | 'syncTitles' | 'fullResync'\n\ninterface OptionCardProps {\n id: SyncOption\n selected: boolean\n onSelect: (id: SyncOption) => void\n title: string\n count: number\n description: string\n disabled?: boolean\n}\n\nfunction OptionCard({\n id,\n selected,\n onSelect,\n title,\n count,\n description,\n disabled,\n}: OptionCardProps) {\n return (\n <Card\n as=\"label\"\n padding={3}\n radius={2}\n border\n tone={selected ? 'primary' : 'default'}\n style={{\n cursor: disabled ? 'not-allowed' : 'pointer',\n opacity: disabled ? 0.5 : 1,\n }}\n >\n <Flex gap={3} align=\"flex-start\">\n <Box paddingTop={1}>\n <Radio\n checked={selected}\n onChange={() => onSelect(id)}\n disabled={disabled}\n name=\"sync-option\"\n />\n </Box>\n <Stack space={2} flex={1}>\n <Flex align=\"center\" gap={2}>\n <Text size={2} weight=\"semibold\">\n {title} ({count})\n </Text>\n </Flex>\n <Text size={1} muted>\n {description}\n </Text>\n </Stack>\n </Flex>\n </Card>\n )\n}\n\nfunction ResyncMetadataDialog(props: ReturnType<typeof useResyncMuxMetadata>) {\n const {resyncState} = props\n\n const videosToUpdate = props.matchedAssets?.filter((m) => m.muxAsset).length || 0\n const videosWithEmptyOrPlaceholder =\n props.matchedAssets?.filter(\n (m) => m.muxAsset && m.muxTitle && isEmptyOrPlaceholderTitle(m.currentTitle, m.muxAsset.id),\n ).length || 0\n\n const hasEmptyTitles = videosWithEmptyOrPlaceholder > 0\n const defaultOption: SyncOption = hasEmptyTitles ? 'fillEmpty' : 'syncTitles'\n const [selectedOption, setSelectedOption] = useState<SyncOption>(defaultOption)\n\n const canTriggerResync = resyncState === 'idle' || resyncState === 'error'\n const isResyncing = resyncState === 'syncing'\n const isDone = resyncState === 'done'\n const isLoading = props.muxAssets.loading || props.sanityAssetsLoading\n\n const handleSync = () => {\n switch (selectedOption) {\n case 'fillEmpty':\n void props.syncOnlyEmpty()\n break\n case 'syncTitles':\n void props.syncAllVideos()\n break\n case 'fullResync':\n void props.syncFullData()\n break\n default:\n break\n }\n }\n\n return (\n <Dialog\n animate\n header=\"Sync with Mux\"\n zOffset={DIALOGS_Z_INDEX}\n id=\"resync-metadata-dialog\"\n onClose={props.closeDialog}\n onClickOutside={props.closeDialog}\n width={1}\n position=\"fixed\"\n footer={\n !isDone && (\n <Card padding={3}>\n <Flex justify=\"flex-end\" gap={2}>\n <Button\n fontSize={2}\n padding={3}\n mode=\"ghost\"\n text=\"Cancel\"\n onClick={props.closeDialog}\n disabled={isResyncing}\n />\n <Button\n icon={SyncIcon}\n fontSize={2}\n padding={3}\n text=\"Run sync\"\n tone=\"primary\"\n onClick={handleSync}\n iconRight={isResyncing && Spinner}\n disabled={!canTriggerResync || isLoading}\n />\n </Flex>\n </Card>\n )\n }\n >\n <Box padding={4}>\n {/* LOADING ASSETS STATE */}\n {isLoading && (\n <Card tone=\"primary\" marginBottom={4} padding={3} border radius={2}>\n <Flex align=\"center\" gap={4}>\n <Spinner muted size={4} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n Loading assets from Mux\n </Text>\n <Text size={1} muted>\n This may take a while.\n </Text>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* ERROR LOADING MUX */}\n {props.muxAssets.error && (\n <Card tone=\"critical\" marginBottom={4} padding={3} border radius={2}>\n <Flex align=\"center\" gap={2}>\n <ErrorOutlineIcon fontSize={36} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n There was an error getting data from Mux\n </Text>\n <Text size={1}>Please try again or contact a developer for help.</Text>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* SYNCING STATE */}\n {resyncState === 'syncing' && (\n <Card tone=\"primary\" marginBottom={4} padding={3} border radius={2}>\n <Flex align=\"center\" gap={4}>\n <Spinner muted size={4} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n Syncing metadata\n </Text>\n <Text size={1} muted>\n Updating videos from Mux...\n </Text>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* ERROR SYNCING */}\n {resyncState === 'error' && (\n <Card tone=\"critical\" marginBottom={4} padding={3} border radius={2}>\n <Flex align=\"center\" gap={2}>\n <ErrorOutlineIcon fontSize={36} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n There was an error syncing metadata\n </Text>\n <Text size={1}>\n {props.resyncError\n ? `Error: ${props.resyncError}`\n : 'Please try again or contact a developer for help.'}\n </Text>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* SUCCESS STATE */}\n {resyncState === 'done' && (\n <Stack paddingY={5} space={3} style={{textAlign: 'center'}}>\n <Box>\n <CheckmarkCircleIcon fontSize={48} />\n </Box>\n <Heading size={2}>Sync completed</Heading>\n <Text size={2} muted>\n Videos have been updated from Mux.\n </Text>\n </Stack>\n )}\n\n {/* OPTIONS */}\n {!isDone && !isLoading && !props.muxAssets.error && (\n <Stack space={4}>\n <Text size={1} muted>\n Found {videosToUpdate} video{videosToUpdate === 1 ? '' : 's'} linked to Mux.\n </Text>\n\n <Stack space={3}>\n {hasEmptyTitles && (\n <OptionCard\n id=\"fillEmpty\"\n selected={selectedOption === 'fillEmpty'}\n onSelect={setSelectedOption}\n title=\"Fill missing titles only\"\n count={videosWithEmptyOrPlaceholder}\n description=\"Updates only videos without a title or with placeholder titles (e.g., 'Asset #123') using the title from Mux.\"\n disabled={isResyncing}\n />\n )}\n\n <OptionCard\n id=\"syncTitles\"\n selected={selectedOption === 'syncTitles'}\n onSelect={setSelectedOption}\n title=\"Sync all titles\"\n count={videosToUpdate}\n description=\"Replaces the title in Sanity with the title from Mux for all videos.\"\n disabled={isResyncing}\n />\n\n <OptionCard\n id=\"fullResync\"\n selected={selectedOption === 'fullResync'}\n onSelect={setSelectedOption}\n title=\"Full resync\"\n count={videosToUpdate}\n description=\"Updates all fields from Mux including status, duration, tracks, captions, and renditions.\"\n disabled={isResyncing}\n />\n </Stack>\n </Stack>\n )}\n </Box>\n </Dialog>\n )\n}\n\nexport default function ResyncMetadata() {\n const resyncMetadata = useResyncMuxMetadata()\n\n if (!resyncMetadata.hasSecrets) {\n return\n }\n\n if (resyncMetadata.dialogOpen) {\n return <ResyncMetadataDialog {...resyncMetadata} />\n }\n\n return <Button mode=\"bleed\" text=\"Sync with Mux\" onClick={resyncMetadata.openDialog} />\n}\n","import {SortIcon} from '@sanity/icons/Sort'\nimport {Button, Menu, MenuButton, MenuItem, type PopoverProps} from '@sanity/ui'\nimport {useId} from 'react'\n\nimport {ASSET_SORT_OPTIONS, type SortOption} from '../hooks/useAssets'\n\nconst CONTEXT_MENU_POPOVER_PROPS: PopoverProps = {\n constrainSize: true,\n placement: 'bottom',\n portal: true,\n width: 0,\n}\n\n/**\n * @sanity/ui components adapted from:\n * https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/desk/components/pane/PaneContextMenuButton.tsx#L19\n */\nexport function SelectSortOptions(props: {sort: SortOption; setSort: (s: SortOption) => void}) {\n const id = useId()\n\n return (\n <MenuButton\n button={\n <Button text=\"Sort\" icon={SortIcon} mode=\"bleed\" padding={3} style={{cursor: 'pointer'}} />\n }\n id={id}\n menu={\n <Menu>\n {Object.entries(ASSET_SORT_OPTIONS).map(([type, {label}]) => (\n <MenuItem\n key={type}\n data-as=\"button\"\n onClick={() => props.setSort(type as SortOption)}\n padding={3}\n tone=\"default\"\n text={label}\n pressed={type === props.sort}\n />\n ))}\n </Menu>\n }\n popover={CONTEXT_MENU_POPOVER_PROPS}\n />\n )\n}\n","import {Box, Spinner} from '@sanity/ui'\n\nconst SpinnerBox: React.FC = () => (\n <Box\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: '150px',\n }}\n >\n <Spinner />\n </Box>\n)\n\nexport default SpinnerBox\n","import {Flex, Text} from '@sanity/ui'\n\nconst IconInfo: React.FC<{\n text: string\n icon: React.FC\n size?: number\n muted?: boolean\n}> = (props) => {\n const Icon = props.icon\n return (\n <Flex gap={2} align=\"center\" padding={1}>\n <Text size={(props.size || 1) + 1} muted>\n <Icon />\n </Text>\n <Text size={props.size || 1} muted={props.muted}>\n {props.text}\n </Text>\n </Flex>\n )\n}\n\nexport default IconInfo\n","import type {SVGProps} from 'react'\n\nexport function ResolutionIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1em\" height=\"1em\" viewBox=\"0 0 24 24\" {...props}>\n <path\n fill=\"currentColor\"\n d=\"M20 9V6h-3V4h5v5h-2ZM2 9V4h5v2H4v3H2Zm15 11v-2h3v-3h2v5h-5ZM2 20v-5h2v3h3v2H2Zm4-4V8h12v8H6Zm2-2h8v-4H8v4Zm0 0v-4v4Z\"\n />\n </svg>\n )\n}\n","import type {SVGProps} from 'react'\n\nexport function StopWatchIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"1em\"\n height=\"1em\"\n viewBox=\"0 0 512 512\"\n {...props}\n >\n <path d=\"M232 306.667h48V176h-48v130.667z\" fill=\"currentColor\" />\n <path\n d=\"M407.67 170.271l30.786-30.786-33.942-33.941-30.785 30.786C341.217 111.057 300.369 96 256 96 149.961 96 64 181.961 64 288s85.961 192 192 192 192-85.961 192-192c0-44.369-15.057-85.217-40.33-117.729zm-45.604 223.795C333.734 422.398 296.066 438 256 438s-77.735-15.602-106.066-43.934C121.602 365.735 106 328.066 106 288s15.602-77.735 43.934-106.066C178.265 153.602 215.934 138 256 138s77.734 15.602 106.066 43.934C390.398 210.265 406 247.934 406 288s-15.602 77.735-43.934 106.066z\"\n fill=\"currentColor\"\n />\n <path d=\"M192 32h128v48H192z\" fill=\"currentColor\" />\n </svg>\n )\n}\n","import {useToast} from '@sanity/ui'\nimport {useCallback, useEffect, useMemo, useState} from 'react'\n\nimport {getAsset, updateMasterAccess} from '../actions/assets'\nimport {addKeysToMuxData} from '../util/addKeysToMuxData'\nimport type {MuxAsset, VideoAssetDocument} from '../util/types'\nimport {useClient} from './useClient'\n\n/**\n * UI status for the mezzanine (\"master access\") file of a Mux asset, derived\n * solely from the stored `master` object.\n * - `disabled`: master access is not enabled (or reverted to `none`).\n * - `preparing`: Mux is preparing the file (we poll until it's ready).\n * - `ready`: the file is ready to download.\n * - `errored`: Mux failed to prepare the file.\n */\nexport type MezzanineStatus = 'disabled' | 'preparing' | 'ready' | 'errored'\n\n// Poll cadence while the mezzanine is preparing.\nconst POLL_INTERVAL_MS = 3000\n\nexport interface UseMezzanineReturn {\n status: MezzanineStatus\n /** `true` while an enable or pre-download check request is in flight. */\n busy: boolean\n /**\n * `true` when the last download attempt found the file gone (the 24h window\n * elapsed). Used to show a \"enable it again\" hint; the button state still\n * comes from `status`.\n */\n expired: boolean\n /** Mezzanine resolution label (e.g. `1080p`), when known. */\n resolution?: string\n /** Enables master access and starts polling until the file is ready. */\n enable: () => Promise<void>\n /** Re-fetches the asset and, if the file is still alive, triggers the download. */\n download: () => Promise<void>\n}\n\n/** Derives the mezzanine status from the persisted asset data alone (no polling or local state). */\nexport function getMezzanineStatus(\n asset: VideoAssetDocument,\n): 'disabled' | 'preparing' | 'ready' | 'errored' {\n const master = asset.data?.master\n if (master?.status === 'preparing') return 'preparing'\n if (master?.status === 'ready' && master.url) return 'ready'\n if (master?.status === 'errored') return 'errored'\n return 'disabled'\n}\n\n/**\n * Encapsulates the mezzanine (Mux \"master access\") lifecycle for an asset:\n * enabling it through the Mux addon proxy, persisting the result on the Sanity\n * document, polling until it's ready, and downloading by redirecting to the\n * fresh, short-lived Mux URL.\n *\n * The full Mux asset `data` (including the `master` object) is stored on the\n * Sanity document via `client.patch`, so the status survives reloads and is\n * already present for assets imported from Mux.\n */\nexport function useMezzanine(asset: VideoAssetDocument): UseMezzanineReturn {\n const client = useClient()\n const toast = useToast()\n\n const master = asset.data?.master\n const [busy, setBusy] = useState(false)\n const [expired, setExpired] = useState(false)\n // Track the previous assetId so we can reset transient flags during render\n // when the asset changes, without triggering a cascading setState-in-effect.\n const [prevAssetId, setPrevAssetId] = useState(asset.assetId)\n if (prevAssetId !== asset.assetId) {\n setPrevAssetId(asset.assetId)\n setExpired(false)\n }\n\n const resolution = useMemo(\n () => asset.data?.max_resolution_tier || asset.data?.max_stored_resolution || undefined,\n [asset.data?.max_resolution_tier, asset.data?.max_stored_resolution],\n )\n\n const status: MezzanineStatus = getMezzanineStatus(asset)\n\n // Persist a Mux asset payload on the Sanity document.\n const persist = useCallback(\n async (data: MuxAsset) => {\n if (!asset._id) return\n await client\n .patch(asset._id)\n .set({status: data.status, data: addKeysToMuxData(data)})\n .commit({returnDocuments: false})\n },\n [asset._id, client],\n )\n\n // Fetch the latest asset from Mux (through the proxy) and persist it on the Sanity document.\n const refresh = useCallback(async (): Promise<MuxAsset | undefined> => {\n if (!asset.assetId || !asset._id) return undefined\n const {data} = await getAsset(client, asset.assetId)\n await persist(data)\n return data\n }, [asset.assetId, asset._id, client, persist])\n\n // Poll while the mezzanine is preparing; stop once it's ready or no longer preparing.\n useEffect(() => {\n if (master?.status !== 'preparing' || !asset.assetId || !asset._id) return undefined\n\n let cancelled = false\n let running = false\n const interval = setInterval(async () => {\n // Skip this tick if the previous refresh hasn't finished, so a slow\n // request can't pile up overlapping reads/writes.\n if (running) return\n running = true\n try {\n const data = await refresh()\n if (cancelled) return\n if (!data || data.master?.status !== 'preparing') {\n clearInterval(interval)\n }\n } catch (error) {\n console.error('Failed to poll mezzanine status:', error)\n } finally {\n running = false\n }\n }, POLL_INTERVAL_MS)\n\n return () => {\n cancelled = true\n clearInterval(interval)\n }\n }, [master?.status, asset.assetId, asset._id, refresh])\n\n const enable = useCallback(async () => {\n if (!asset.assetId || !asset._id) return\n\n setBusy(true)\n setExpired(false)\n try {\n const {data} = await updateMasterAccess(client, asset.assetId, 'temporary')\n // Persist the PUT response directly — it already reports master.status\n // 'preparing', so polling starts without relying on a follow-up GET that\n // could read stale data and miss it.\n await persist(data)\n } catch (error) {\n toast.push({\n status: 'error',\n title: 'Could not enable the mezzanine file',\n description: error instanceof Error ? error.message : 'Please try again',\n })\n } finally {\n setBusy(false)\n }\n }, [asset.assetId, asset._id, client, persist, toast])\n\n const download = useCallback(async () => {\n if (!asset.assetId) return\n\n setBusy(true)\n try {\n // The Mux URL is short-lived (24h), so re-fetch the asset right before\n // downloading and only redirect if the file is still alive.\n const data = await refresh()\n const url = data?.master?.status === 'ready' ? data.master.url : undefined\n\n if (url) {\n setExpired(false)\n triggerMezzanineDownload(url)\n } else {\n // The window elapsed and master_access reverted: prompt to re-enable.\n setExpired(true)\n }\n } catch (error) {\n toast.push({\n status: 'error',\n title: 'Could not download the mezzanine file',\n description: error instanceof Error ? error.message : 'Please try again',\n })\n } finally {\n setBusy(false)\n }\n }, [asset.assetId, refresh, toast])\n\n return {status, busy, expired, resolution, enable, download}\n}\n\n/**\n * Redirects the browser to the Mux mezzanine URL to start the download. The URL\n * already serves the file with its default name (`mezzanine.mp4`).\n * @see {@link https://www.mux.com/docs/guides/download-for-offline-editing}\n */\nfunction triggerMezzanineDownload(masterUrl: string): void {\n if (typeof window === 'undefined') return\n\n const anchor = document.createElement('a')\n anchor.href = masterUrl\n anchor.target = '_blank'\n anchor.rel = 'noopener noreferrer'\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n}\n","import {Stack, Text} from '@sanity/ui'\n\n/** Explains what the mezzanine file is and how it differs from the streamable MP4 renditions. */\nexport default function MezzanineExplanation() {\n return (\n <Stack space={3}>\n <Text size={1} muted>\n When you enable the mezzanine file, Mux creates a copy equivalent in quality to your\n original video — ideal for offline editing or archiving. Unlike the streamable MP4 (static)\n renditions, it is not meant for streaming.\n </Text>\n <Text size={1} muted>\n The file is prepared in the background and may take a few minutes depending on the\n asset's duration and resolution. Enabling is free and the download stays available for\n 24 hours.\n </Text>\n </Stack>\n )\n}\n","import {DownloadIcon} from '@sanity/icons/Download'\nimport {Button, Card, Flex, Label, Spinner, Stack, Text} from '@sanity/ui'\n\nimport {useMezzanine} from '../hooks/useMezzanine'\nimport {MEZZANINE_LEARN_MORE_URL} from '../util/constants'\nimport type {VideoAssetDocument} from '../util/types'\nimport MezzanineExplanation from './MezzanineExplanation'\n\nexport interface Props {\n asset: VideoAssetDocument\n /**\n * Render the mezzanine explanation copy inside the card.\n * @defaultValue true\n */\n withExplanation?: boolean\n}\n\n/**\n * \"Mezzanine\" panel, modeled after Mux's dashboard card: enable the\n * master-access copy, watch it prepare, then download it.\n */\nexport default function Mezzanine({asset, withExplanation = true}: Props) {\n const {status, busy, expired, resolution, enable, download} = useMezzanine(asset)\n\n const assetReady = asset.status === 'ready' || asset.data?.status === 'ready'\n // Once a download finds the file gone, treat it as not-ready even if the\n // (stale) asset prop still reports `ready`, so we show the re-enable path\n // instead of a dead Download button.\n const isReady = status === 'ready' && !expired\n const isPreparing = status === 'preparing'\n const showExplanation = !isReady && !isPreparing\n\n return (\n <Card padding={3} radius={2} tone=\"transparent\" border>\n <Stack space={4}>\n <Flex align=\"center\" justify=\"space-between\" gap={3}>\n <Label muted size={1}>\n Mezzanine\n </Label>\n <Text size={1}>\n <a href={MEZZANINE_LEARN_MORE_URL} target=\"_blank\" rel=\"noopener noreferrer\">\n Learn more\n </a>\n </Text>\n </Flex>\n\n <Stack space={2}>\n <Text size={1} muted={!isReady}>\n mezzanine.mp4\n </Text>\n {resolution && (\n <Text size={1} muted>\n {resolution}\n </Text>\n )}\n </Stack>\n\n {withExplanation && showExplanation && <MezzanineExplanation />}\n\n {showExplanation && (expired || status === 'errored') && (\n <Stack space={2}>\n {expired && (\n <Text size={1} muted>\n The previous mezzanine file expired. Enable it again to download.\n </Text>\n )}\n {status === 'errored' && (\n <Text size={1} style={{color: 'var(--card-critical-color)'}}>\n Mux could not prepare the mezzanine file. Please try again.\n </Text>\n )}\n </Stack>\n )}\n\n {isPreparing && (\n <Text size={1} muted>\n Preparing the mezzanine file… this can take a few minutes. You can close this and come\n back later.\n </Text>\n )}\n\n {isReady && (\n <Text size={1} muted>\n Ready to download. The link stays available for about 24 hours.\n </Text>\n )}\n\n <Flex justify=\"flex-end\" gap={2}>\n {isPreparing ? (\n <Flex align=\"center\" gap={2}>\n <Spinner muted size={1} />\n <Text size={1} muted>\n Preparing…\n </Text>\n </Flex>\n ) : isReady ? (\n <Button\n icon={DownloadIcon}\n text=\"Download\"\n tone=\"positive\"\n fontSize={1}\n padding={3}\n loading={busy}\n disabled={busy}\n onClick={() => void download()}\n />\n ) : (\n <Button\n text={status === 'errored' ? 'Try again' : 'Enable'}\n tone=\"primary\"\n fontSize={1}\n padding={3}\n loading={busy}\n disabled={busy || !assetReady}\n onClick={() => void enable()}\n />\n )}\n </Flex>\n </Stack>\n </Card>\n )\n}\n","import {useToast} from '@sanity/ui'\nimport {useCallback, useState} from 'react'\n\nimport {getAsset} from '../actions/assets'\nimport {addKeysToMuxData} from '../util/addKeysToMuxData'\nimport type {MuxAsset, VideoAssetDocument} from '../util/types'\nimport {useClient} from './useClient'\n\ntype ResyncAssetState = 'idle' | 'syncing' | 'success' | 'error'\n\ninterface UseResyncAssetOptions {\n showToast?: boolean\n onSuccess?: (updatedData: MuxAsset) => void\n onError?: (error: unknown) => void\n}\n\ninterface UseResyncAssetReturn {\n resyncState: ResyncAssetState\n resyncError: unknown\n resyncAsset: (asset: VideoAssetDocument) => Promise<MuxAsset | undefined>\n isResyncing: boolean\n}\n\nexport function useResyncAsset(options?: UseResyncAssetOptions): UseResyncAssetReturn {\n const client = useClient()\n const toast = useToast()\n const [resyncState, setResyncState] = useState<ResyncAssetState>('idle')\n const [resyncError, setResyncError] = useState<unknown>(null)\n\n const showToast = options?.showToast ?? false\n\n const resyncAsset = useCallback(\n async (asset: VideoAssetDocument) => {\n if (!asset.assetId) {\n if (showToast) {\n toast.push({\n title: 'Cannot resync',\n description: 'Asset has no Mux ID',\n status: 'error',\n })\n }\n options?.onError?.(new Error('Asset has no Mux ID'))\n return undefined\n }\n\n if (!asset._id) {\n if (showToast) {\n toast.push({\n title: 'Cannot resync',\n description: 'Asset has no document ID',\n status: 'error',\n })\n }\n options?.onError?.(new Error('Asset has no document ID'))\n return undefined\n }\n\n setResyncState('syncing')\n setResyncError(null)\n\n try {\n const response = await getAsset(client, asset.assetId)\n const muxData = response.data\n const dataWithKeys = addKeysToMuxData(muxData)\n\n await client\n .patch(asset._id)\n .set({\n status: muxData.status,\n data: dataWithKeys,\n ...(muxData.meta?.title && {filename: muxData.meta.title}),\n })\n .commit({returnDocuments: false})\n\n setResyncState('success')\n if (showToast) {\n toast.push({\n title: 'Asset synced',\n description: 'Data has been updated from Mux',\n status: 'success',\n })\n }\n\n options?.onSuccess?.(muxData)\n return muxData\n } catch (error) {\n setResyncState('error')\n setResyncError(error)\n console.error('Failed to refresh asset data:', error)\n if (showToast) {\n toast.push({\n title: 'Sync failed',\n description: 'Could not sync asset from Mux',\n status: 'error',\n })\n }\n options?.onError?.(error)\n return undefined\n }\n },\n [client, toast, options, showToast],\n )\n\n return {\n resyncState,\n resyncError,\n resyncAsset,\n isResyncing: resyncState === 'syncing',\n }\n}\n","import type {SanityClient} from '@sanity/client'\n\nimport {getAsset} from '../actions/assets'\nimport {generateJwt} from './generateJwt'\nimport {getPlaybackId} from './getPlaybackPolicy'\nimport {getPlaybackPolicy} from './getPlaybackPolicy'\nimport type {MuxTextTrack, VideoAssetDocument} from './types'\n\nexport function extractErrorMessage(\n error: unknown,\n defaultMessage = 'Failed to process request',\n): string {\n let message = ''\n\n if (error && typeof error === 'object') {\n const err = error as {response?: {body?: {message?: string}}; message?: string}\n message = err.response?.body?.message || err.message || ''\n } else if (typeof error === 'string') {\n message = error\n }\n\n if (!message) {\n return defaultMessage\n }\n\n const match = message.match(/\\(([^)]+)\\)/)\n if (match && match[1]) {\n return match[1]\n }\n\n if (message.includes('responded with')) {\n const parts = message.split('(')\n if (parts.length > 1) {\n return parts[parts.length - 1]!.replace(')', '').trim()\n }\n }\n\n return message\n}\n\nexport interface PollTrackStatusOptions {\n client: SanityClient\n assetId: string\n trackName: string\n trackLanguageCode: string\n maxAttempts?: number\n onTrackFound?: (track: MuxTextTrack) => void\n onTrackErrored?: (track: MuxTextTrack) => void\n onTrackReady?: (track: MuxTextTrack) => void\n}\n\nexport interface PollTrackStatusResult {\n track: MuxTextTrack | undefined\n found: boolean\n status: 'ready' | 'preparing' | 'errored' | 'not-found'\n}\n\n/**\n * Polls Mux API to find and track the status of a newly added text track.\n * The track may be in \"preparing\" state initially, then become \"ready\" or \"errored\".\n *\n * @param options - Configuration options for polling\n * @returns Promise resolving to the poll result\n */\nexport async function pollTrackStatus(\n options: PollTrackStatusOptions,\n): Promise<PollTrackStatusResult> {\n const {\n client,\n assetId,\n trackName,\n trackLanguageCode,\n maxAttempts = 10,\n onTrackFound,\n onTrackErrored,\n onTrackReady,\n } = options\n\n const trimmedName = trackName.trim()\n const trimmedLanguageCode = trackLanguageCode.trim()\n let newTrack: MuxTextTrack | undefined\n let attempts = 0\n let trackFound = false\n\n const findTrack = (textTracks: MuxTextTrack[]): MuxTextTrack | undefined => {\n let foundTrack = textTracks.find(\n (track) => track.name === trimmedName && track.language_code === trimmedLanguageCode,\n )\n\n if (!foundTrack) {\n foundTrack = textTracks.find((track) => track.language_code === trimmedLanguageCode)\n }\n\n if (!foundTrack && textTracks.length > 0) {\n foundTrack = textTracks[textTracks.length - 1]\n }\n\n return foundTrack\n }\n\n while (attempts < maxAttempts) {\n try {\n if (attempts > 0) {\n await new Promise((resolve) => setTimeout(resolve, 1000))\n }\n\n const assetData = await getAsset(client, assetId)\n const textTracks =\n assetData.data.tracks?.filter((track): track is MuxTextTrack => track.type === 'text') || []\n\n const foundTrack = findTrack(textTracks)\n\n if (!foundTrack) {\n attempts++\n continue\n }\n\n trackFound = true\n newTrack = foundTrack\n\n if (onTrackFound) {\n onTrackFound(foundTrack)\n }\n\n if (foundTrack.status === 'ready') {\n if (onTrackReady) {\n onTrackReady(foundTrack)\n }\n break\n }\n\n if (foundTrack.status === 'errored') {\n if (onTrackErrored) {\n onTrackErrored(foundTrack)\n }\n return {\n track: foundTrack,\n found: true,\n status: 'errored',\n }\n }\n } catch (error) {\n console.error('Failed to fetch updated asset:', error)\n }\n\n attempts++\n }\n\n if (!newTrack || !trackFound) {\n return {\n track: undefined,\n found: false,\n status: 'not-found',\n }\n }\n\n if (newTrack.status === 'preparing') {\n return {\n track: newTrack,\n found: true,\n status: 'preparing',\n }\n }\n\n return {\n track: newTrack,\n found: true,\n status: 'ready',\n }\n}\n\n/**\n * May throw a Promise. Call this with {@link tryWithSuspend} or rethrow the Promise\n */\nexport async function downloadVttFile(\n client: SanityClient,\n asset: VideoAssetDocument,\n track: MuxTextTrack,\n): Promise<void> {\n if (!track.id) {\n throw new Error('Track ID is missing')\n }\n\n if (track.status !== 'ready') {\n throw new Error(`Track is not ready yet. Status: ${track.status}`)\n }\n\n if (!asset.assetId) {\n throw new Error('Asset ID is required')\n }\n\n const playbackId = getPlaybackId(asset)\n if (!playbackId) {\n throw new Error('Playback ID is required')\n }\n\n const playbackPolicy = getPlaybackPolicy(asset)?.policy\n\n let downloadUrl = `https://stream.mux.com/${playbackId}/text/${track.id}.vtt`\n\n if (playbackPolicy === 'signed' || playbackPolicy === 'drm') {\n const token = generateJwt(client, playbackId, 'v')\n downloadUrl += `?token=${token}`\n }\n\n const response = await fetch(downloadUrl)\n if (!response.ok) {\n throw new Error(`Failed to download file: ${response.statusText}`)\n }\n\n const blob = await response.blob()\n const blobUrl = URL.createObjectURL(blob)\n\n const link = document.createElement('a')\n link.href = blobUrl\n link.download = `${asset.filename || 'captions'}-${track.language_code || 'en'}.vtt`\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n\n URL.revokeObjectURL(blobUrl)\n}\n","import {TranslateIcon} from '@sanity/icons/Translate'\nimport {UploadIcon} from '@sanity/icons/Upload'\nimport {\n Autocomplete,\n Button,\n Card,\n Checkbox,\n Dialog,\n Flex,\n Label,\n Spinner,\n Stack,\n Text,\n TextInput,\n useToast,\n} from '@sanity/ui'\nimport LanguagesList from 'iso-639-1'\nimport {useId, useRef, useState} from 'react'\n\nimport {addTextTrackFromUrl, generateSubtitles, getAsset} from '../actions/assets'\nimport {useClient} from '../hooks/useClient'\nimport {addKeysToMuxData} from '../util/addKeysToMuxData'\nimport {extractErrorMessage, pollTrackStatus} from '../util/textTracks'\nimport {type MuxTextTrack, SUPPORTED_MUX_LANGUAGES, type VideoAssetDocument} from '../util/types'\n\nconst LANGUAGE_OPTIONS = LanguagesList.getAllCodes().map((code) => ({\n value: code,\n label: LanguagesList.getNativeName(code),\n}))\n\nconst MUX_LANGUAGE_OPTIONS = SUPPORTED_MUX_LANGUAGES.map((lang) => ({\n value: lang.code,\n label: lang.label,\n}))\n\nexport interface Props {\n asset: VideoAssetDocument\n onAdd: (track: MuxTextTrack) => void\n onClose: () => void\n}\n\nexport default function AddCaptionDialog({asset, onAdd, onClose}: Props) {\n const client = useClient()\n const toast = useToast()\n const dialogId = `AddCaptionDialog${useId()}`\n\n const [isAutogenerated, setIsAutogenerated] = useState(false)\n const [vttUrl, setVttUrl] = useState('')\n const [languageCode, setLanguageCode] = useState('')\n const [selectedLanguage, setSelectedLanguage] = useState<{value: string; label: string} | null>(\n null,\n )\n const [name, setName] = useState('')\n const [isSubmitting, setIsSubmitting] = useState(false)\n const [selectedFile, setSelectedFile] = useState<File | null>(null)\n const fileInputRef = useRef<HTMLInputElement>(null)\n\n const uploadVttFile = async (file: File): Promise<string> => {\n const assetDocument = await client.assets.upload('file', file, {\n filename: file.name,\n })\n return assetDocument.url\n }\n\n const refreshAssetData = async () => {\n if (!asset._id || !asset.assetId) return\n try {\n const latestAssetData = await getAsset(client, asset.assetId)\n const dataWithKeys = addKeysToMuxData(latestAssetData.data)\n await client\n .patch(asset._id)\n .set({data: dataWithKeys, status: latestAssetData.data.status})\n .commit({returnDocuments: false})\n } catch (refreshError) {\n console.error('Failed to refresh asset data:', refreshError)\n }\n }\n\n const handleAddTrackFromUrl = async () => {\n if (!asset.assetId) {\n throw new Error('Asset ID is required')\n }\n\n const trimmedName = name.trim()\n const trimmedLanguageCode = languageCode.trim()\n\n let vttUrlToUse = vttUrl.trim()\n\n if (selectedFile) {\n try {\n vttUrlToUse = await uploadVttFile(selectedFile)\n } catch (uploadError) {\n toast.push({\n title: 'Failed to upload caption file',\n status: 'error',\n description: 'Could not upload the caption file to Sanity. Please try again.',\n })\n setIsSubmitting(false)\n throw uploadError\n }\n }\n\n await addTextTrackFromUrl(client, asset.assetId, vttUrlToUse, {\n language_code: trimmedLanguageCode,\n name: trimmedName,\n text_type: 'subtitles',\n })\n\n const result = await pollTrackStatus({\n client,\n assetId: asset.assetId,\n trackName: trimmedName,\n trackLanguageCode: trimmedLanguageCode,\n onTrackErrored: async (track) => {\n const errorMessage =\n track.error?.messages?.[0] ||\n track.error?.type ||\n 'The track failed to download from the provided URL'\n toast.push({\n title: 'Caption track failed',\n status: 'error',\n description: errorMessage,\n })\n await refreshAssetData()\n onAdd(track)\n onClose()\n },\n })\n\n if (!result.found || !result.track) {\n toast.push({\n title: 'Caption track may have been added',\n status: 'warning',\n description:\n '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.',\n })\n onClose()\n return\n }\n\n if (result.status === 'errored') {\n return\n }\n\n if (result.status === 'preparing') {\n toast.push({\n title: 'Caption track is processing',\n status: 'info',\n description:\n 'The track was created and is being processed. It will appear in the list shortly.',\n })\n await refreshAssetData()\n onAdd(result.track)\n onClose()\n return\n }\n\n await refreshAssetData()\n toast.push({\n title: 'Caption track added',\n status: 'success',\n description: 'Caption track added successfully',\n })\n\n onAdd(result.track)\n onClose()\n }\n\n const handleGenerateSubtitles = async () => {\n if (!asset.assetId) {\n throw new Error('Asset ID is required')\n }\n\n const assetData = await getAsset(client, asset.assetId)\n const audioTrack = assetData.data.tracks?.find((track) => track.type === 'audio')\n\n if (!audioTrack || !audioTrack.id) {\n toast.push({\n title: 'No audio track found',\n status: 'error',\n description:\n 'The asset does not have an audio track. Auto-generated subtitles require an audio track.',\n })\n throw new Error('No audio track found')\n }\n\n await generateSubtitles(client, asset.assetId, audioTrack.id, {\n language_code: languageCode.trim(),\n name: name.trim(),\n })\n\n const mockTrackId = `generating-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`\n const mockTrack: MuxTextTrack = {\n type: 'text',\n id: mockTrackId,\n text_type: 'subtitles',\n text_source: 'generated_live',\n language_code: languageCode.trim(),\n name: name.trim(),\n status: 'preparing',\n }\n\n toast.push({\n title: 'Generating subtitles',\n status: 'success',\n description: 'This may take a few minutes',\n })\n\n onAdd(mockTrack)\n onClose()\n }\n\n const handleSubmit = async () => {\n if (!isAutogenerated) {\n if (!selectedFile && !vttUrl.trim()) {\n toast.push({\n title: 'Caption file or URL required',\n status: 'error',\n description: 'Please select a VTT or SRT file or enter a caption file URL',\n })\n return\n }\n\n if (vttUrl.trim() && !selectedFile) {\n try {\n void new URL(vttUrl.trim())\n } catch {\n toast.push({\n title: 'Invalid URL',\n status: 'error',\n description:\n 'Please enter a valid URL (e.g., https://example.com/subtitles.vtt or subtitles.srt)',\n })\n return\n }\n }\n }\n\n if (!name.trim()) {\n toast.push({\n title: 'Audio name required',\n status: 'error',\n description: 'Please enter an audio name for this caption track',\n })\n return\n }\n\n if (!languageCode.trim()) {\n toast.push({\n title: 'Language code required',\n status: 'error',\n description: 'Please enter a language code (e.g., en, es, fr)',\n })\n return\n }\n\n setIsSubmitting(true)\n\n try {\n if (isAutogenerated) {\n await handleGenerateSubtitles()\n } else {\n await handleAddTrackFromUrl()\n }\n } catch (error) {\n toast.push({\n title: 'Failed to add caption track',\n status: 'error',\n description: extractErrorMessage(error, 'Failed to add caption track'),\n })\n } finally {\n setIsSubmitting(false)\n }\n }\n\n return (\n <Dialog\n id={dialogId}\n header=\"Add Caption Track\"\n onClose={onClose}\n width={1}\n onClickOutside={onClose}\n >\n <Stack padding={4} space={4}>\n <Stack space={2}>\n <Flex align=\"center\" marginBottom={3}>\n <Checkbox\n id=\"autogenerated-checkbox\"\n style={{display: 'block'}}\n checked={isAutogenerated}\n onChange={(e) => {\n setIsAutogenerated(e.currentTarget.checked)\n if (e.currentTarget.checked) {\n setVttUrl('')\n }\n }}\n disabled={isSubmitting}\n />\n <Flex flex={1} paddingLeft={2}>\n <Text>\n <label htmlFor=\"autogenerated-checkbox\">Generate captions</label>\n </Text>\n </Flex>\n </Flex>\n {!isAutogenerated && (\n <Stack space={2}>\n <Card padding={3} marginBottom={2} tone=\"transparent\" border radius={2}>\n <Flex align=\"center\" justify=\"space-between\">\n <Text size={1} muted>\n {selectedFile ? `Selected: ${selectedFile.name}` : 'No file selected'}\n </Text>\n <Button\n icon={UploadIcon}\n text=\"Select File\"\n mode=\"ghost\"\n tone=\"primary\"\n fontSize={1}\n padding={2}\n onClick={() => fileInputRef.current?.click()}\n disabled={isSubmitting}\n />\n </Flex>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".vtt,text/vtt,.srt,application/x-subrip\"\n style={{display: 'none'}}\n onChange={(e) => {\n if (e.target.files && e.target.files.length > 0 && !isSubmitting) {\n setSelectedFile(e.target.files[0]!)\n setVttUrl('')\n }\n }}\n />\n </Card>\n <Text size={1} muted style={{textAlign: 'center'}}>\n Or enter the caption file URL\n </Text>\n <Stack space={2}>\n <Label as=\"label\" htmlFor=\"vtt-url\">\n Caption File URL (.vtt or .srt)\n </Label>\n <TextInput\n id=\"vtt-url\"\n placeholder=\"https://example.com/subtitles.vtt\"\n value={vttUrl}\n onChange={(e) => {\n setVttUrl(e.currentTarget.value)\n setSelectedFile(null)\n }}\n disabled={isSubmitting}\n />\n </Stack>\n </Stack>\n )}\n </Stack>\n\n <Stack space={2}>\n <Label as=\"label\" htmlFor=\"caption-name\">\n Audio name\n </Label>\n <Autocomplete\n id=\"caption-name\"\n value={selectedLanguage?.value || ''}\n onChange={(newValue) => {\n const options = isAutogenerated ? MUX_LANGUAGE_OPTIONS : LANGUAGE_OPTIONS\n const selected = options.find((opt) => opt.value === newValue)\n if (selected) {\n setSelectedLanguage(selected)\n setLanguageCode(selected.value)\n setName(selected.label)\n }\n }}\n options={isAutogenerated ? MUX_LANGUAGE_OPTIONS : LANGUAGE_OPTIONS}\n icon={TranslateIcon}\n placeholder=\"Select language\"\n filterOption={(query, option) =>\n option.label.toLowerCase().indexOf(query.toLowerCase()) > -1 ||\n option.value.toLowerCase().indexOf(query.toLowerCase()) > -1\n }\n openButton\n renderValue={(value) =>\n (isAutogenerated ? MUX_LANGUAGE_OPTIONS : LANGUAGE_OPTIONS).find(\n (l) => l.value === value,\n )?.label || value\n }\n renderOption={(option) => (\n <Card data-as=\"button\" padding={3} radius={2} tone=\"inherit\">\n <Text size={2} textOverflow=\"ellipsis\">\n {option.label} ({option.value})\n </Text>\n </Card>\n )}\n disabled={isSubmitting}\n />\n </Stack>\n\n <Stack space={2}>\n <Label as=\"label\" htmlFor=\"caption-language\">\n Language Code\n </Label>\n <TextInput\n id=\"caption-language\"\n placeholder=\"en-US\"\n value={languageCode}\n onChange={(e) => {\n setLanguageCode(e.currentTarget.value)\n if (selectedLanguage && selectedLanguage.value !== e.currentTarget.value) {\n setSelectedLanguage(null)\n if (!name || name === selectedLanguage.label) {\n setName('')\n }\n }\n }}\n disabled={isSubmitting}\n />\n </Stack>\n\n <Flex gap={2} justify=\"flex-end\" marginTop={2}>\n <Button text=\"Cancel\" mode=\"ghost\" onClick={onClose} disabled={isSubmitting} />\n <Button\n text=\"Add Caption Track\"\n tone=\"primary\"\n icon={\n isSubmitting ? (\n <Spinner\n style={{\n verticalAlign: 'middle',\n display: 'inline-block',\n marginBottom: '-3px',\n width: '1em',\n height: '1em',\n marginRight: '-6px',\n }}\n />\n ) : (\n <UploadIcon />\n )\n }\n onClick={handleSubmit}\n disabled={isSubmitting}\n />\n </Flex>\n </Stack>\n </Dialog>\n )\n}\n","import {DownloadIcon} from '@sanity/icons/Download'\nimport {TranslateIcon} from '@sanity/icons/Translate'\nimport {UploadIcon} from '@sanity/icons/Upload'\nimport {\n Autocomplete,\n Button,\n Card,\n Dialog,\n Flex,\n Label,\n Spinner,\n Stack,\n Text,\n TextInput,\n useToast,\n} from '@sanity/ui'\nimport LanguagesList from 'iso-639-1'\nimport {useEffect, useId, useRef, useState} from 'react'\n\nimport {addTextTrackFromUrl, deleteTextTrack, getAsset} from '../actions/assets'\nimport {useClient} from '../hooks/useClient'\nimport {addKeysToMuxData} from '../util/addKeysToMuxData'\nimport {generateJwt} from '../util/generateJwt'\nimport {getPlaybackId} from '../util/getPlaybackPolicy'\nimport {getPlaybackPolicy} from '../util/getPlaybackPolicy'\nimport {downloadVttFile, extractErrorMessage, pollTrackStatus} from '../util/textTracks'\nimport type {MuxTextTrack, VideoAssetDocument} from '../util/types'\n\nconst LANGUAGE_OPTIONS = LanguagesList.getAllCodes().map((code) => ({\n value: code,\n label: LanguagesList.getNativeName(code),\n}))\n\nexport interface Props {\n asset: VideoAssetDocument\n track: MuxTextTrack\n onUpdate: (track: MuxTextTrack, oldTrackId?: string) => void\n onClose: () => void\n}\n\nexport default function EditCaptionDialog({asset, track, onUpdate, onClose}: Props) {\n const client = useClient()\n const toast = useToast()\n const dialogId = `EditCaptionDialog${useId()}`\n\n const isAutogenerated =\n track.text_source === 'generated_live' ||\n track.text_source === 'generated_live_final' ||\n track.text_source === 'generated_vod'\n\n const [vttUrl, setVttUrl] = useState('')\n const [languageCode, setLanguageCode] = useState(track.language_code || '')\n const [selectedLanguage, setSelectedLanguage] = useState<{value: string; label: string} | null>(\n () => {\n const baseCode = track.language_code?.split('-')[0]\n const found = LANGUAGE_OPTIONS.find(\n (opt) => opt.value === track.language_code || opt.value === baseCode,\n )\n if (found) return found\n if (track.name) {\n const foundByName = LANGUAGE_OPTIONS.find((opt) => opt.label === track.name)\n if (foundByName) return foundByName\n }\n return null\n },\n )\n const [name, setName] = useState(track.name || '')\n const [isSubmitting, setIsSubmitting] = useState(false)\n const [downloading, setDownloading] = useState(false)\n const [selectedFile, setSelectedFile] = useState<File | null>(null)\n const fileInputRef = useRef<HTMLInputElement>(null)\n\n useEffect(() => {\n // oxlint-disable-next-line react/react-compiler\n setLanguageCode(track.language_code || '')\n setName(track.name || '')\n setVttUrl('')\n const baseCode = track.language_code?.split('-')[0]\n const foundByCode = LANGUAGE_OPTIONS.find(\n (opt) => opt.value === track.language_code || opt.value === baseCode,\n )\n const foundByName = track.name ? LANGUAGE_OPTIONS.find((opt) => opt.label === track.name) : null\n setSelectedLanguage(foundByCode || foundByName || null)\n }, [track, asset, client])\n\n const handleDownloadCurrentFile = async () => {\n setDownloading(true)\n try {\n await downloadVttFile(client, asset, track)\n } catch (error) {\n let errorMessage = 'Please try again'\n let title = 'Failed to download VTT file'\n\n if (error instanceof Error) {\n errorMessage = error.message\n if (error.message.includes('Track')) {\n title = 'Cannot download'\n }\n } else if (error === 'Track ID is missing' || error === 'Track is not ready yet') {\n errorMessage = error\n title = 'Cannot download'\n }\n\n toast.push({\n title,\n status: 'error',\n description: errorMessage,\n })\n } finally {\n setDownloading(false)\n }\n }\n\n const getCurrentFileName = () => {\n if (track.id && asset.filename) {\n return `${asset.filename}-${track.language_code || 'en'}.vtt`\n }\n return `captions-${track.language_code || 'en'}.vtt`\n }\n\n const uploadVttFile = async (file: File): Promise<string> => {\n const assetDocument = await client.assets.upload('file', file, {\n filename: file.name,\n })\n return assetDocument.url\n }\n\n const refreshAssetData = async () => {\n if (!asset._id || !asset.assetId) return\n try {\n const latestAssetData = await getAsset(client, asset.assetId)\n const dataWithKeys = addKeysToMuxData(latestAssetData.data)\n await client\n .patch(asset._id)\n .set({data: dataWithKeys, status: latestAssetData.data.status})\n .commit({returnDocuments: false})\n } catch (refreshError) {\n console.error('Failed to refresh asset data:', refreshError)\n }\n }\n\n const handleUpdateTrackWithNewUrl = async () => {\n if (!asset.assetId) {\n throw new Error('Asset ID is required')\n }\n\n const trimmedName = name.trim()\n const trimmedLanguageCode = languageCode.trim()\n\n const oldTrackId = track.id\n\n try {\n await deleteTextTrack(client, asset.assetId, oldTrackId)\n } catch (deleteError) {\n toast.push({\n title: 'Failed to delete old track',\n status: 'error',\n description: 'Could not delete the old track. Please try again or delete it manually.',\n })\n setIsSubmitting(false)\n throw deleteError\n }\n\n let vttUrlToUse = vttUrl.trim()\n\n if (selectedFile) {\n try {\n vttUrlToUse = await uploadVttFile(selectedFile)\n } catch (uploadError) {\n toast.push({\n title: 'Failed to upload VTT file',\n status: 'error',\n description: 'Could not upload the VTT file to Sanity. Please try again.',\n })\n setIsSubmitting(false)\n throw uploadError\n }\n }\n\n try {\n await addTextTrackFromUrl(client, asset.assetId, vttUrlToUse, {\n language_code: trimmedLanguageCode,\n name: trimmedName,\n text_type: 'subtitles',\n })\n } catch (error: unknown) {\n toast.push({\n title: 'Failed to update caption track',\n status: 'error',\n description: extractErrorMessage(error, 'Failed to update caption track'),\n })\n setIsSubmitting(false)\n throw error\n }\n\n const result = await pollTrackStatus({\n client,\n assetId: asset.assetId,\n trackName: trimmedName,\n trackLanguageCode: trimmedLanguageCode,\n onTrackErrored: async (erroredTrack) => {\n const errorMessage =\n erroredTrack.error?.messages?.[0] ||\n erroredTrack.error?.type ||\n 'The track failed to download from the provided URL'\n toast.push({\n title: 'Caption track failed',\n status: 'error',\n description: errorMessage,\n })\n await refreshAssetData()\n onUpdate(erroredTrack, oldTrackId)\n setIsSubmitting(false)\n },\n })\n\n if (!result.found || !result.track) {\n toast.push({\n title: 'Caption track may have been updated',\n status: 'warning',\n description:\n 'The track was updated but its status could not be determined. It may still be processing. Please refresh the page to see if it appears.',\n })\n setIsSubmitting(false)\n return\n }\n\n if (result.status === 'errored') {\n return\n }\n\n await refreshAssetData()\n\n if (result.status === 'preparing') {\n toast.push({\n title: 'Caption track is processing',\n status: 'info',\n description:\n 'The track was updated and is being processed. It will appear in the list shortly.',\n })\n } else {\n toast.push({\n title: 'Caption track updated',\n status: 'success',\n description: 'Caption track updated successfully',\n })\n }\n\n onUpdate(result.track, oldTrackId)\n setIsSubmitting(false)\n }\n\n const handleSubmit = async () => {\n if (!name.trim()) {\n toast.push({\n title: 'Audio name required',\n status: 'error',\n description: 'Please enter an audio name for this caption track',\n })\n return\n }\n\n if (!languageCode.trim()) {\n toast.push({\n title: 'Language code required',\n status: 'error',\n description: 'Please enter a language code (e.g., en, es, fr)',\n })\n return\n }\n\n setIsSubmitting(true)\n\n try {\n if (!asset.assetId) {\n throw new Error('Asset ID is required')\n }\n\n const originalVttUrl = (() => {\n if (isAutogenerated || !track.id) return ''\n const playbackId = getPlaybackId(asset)\n if (!playbackId) return ''\n let url = `https://stream.mux.com/${playbackId}/text/${track.id}.vtt`\n if (getPlaybackPolicy(asset)?.policy === 'signed') {\n const token = generateJwt(client, playbackId, 'v')\n url += `?token=${token}`\n }\n return url\n })()\n\n const urlChanged =\n selectedFile !== null || (vttUrl.trim() && vttUrl.trim() !== originalVttUrl)\n\n if (!urlChanged) {\n toast.push({\n title: 'No changes',\n status: 'info',\n description:\n 'Please provide a new VTT file or URL using the \"Replace\" button or URL field to update the track.',\n })\n setIsSubmitting(false)\n return\n }\n\n if (urlChanged) {\n if (!selectedFile && vttUrl.trim()) {\n try {\n void new URL(vttUrl.trim())\n } catch {\n toast.push({\n title: 'Invalid URL',\n status: 'error',\n description: 'Please enter a valid URL (e.g., https://example.com/subtitles.vtt)',\n })\n setIsSubmitting(false)\n return\n }\n }\n\n if (!selectedFile && !vttUrl.trim()) {\n toast.push({\n title: 'VTT file or URL required',\n status: 'error',\n description: 'Please select a VTT file or enter a VTT file URL',\n })\n setIsSubmitting(false)\n return\n }\n\n await handleUpdateTrackWithNewUrl()\n }\n\n onClose()\n } catch (error) {\n toast.push({\n title: 'Failed to update caption track',\n status: 'error',\n description: error instanceof Error ? error.message : 'Please try again',\n })\n } finally {\n setIsSubmitting(false)\n }\n }\n\n return (\n <Dialog\n id={dialogId}\n header=\"Edit Caption Track\"\n onClose={onClose}\n width={1}\n onClickOutside={onClose}\n >\n <Stack padding={4} space={4}>\n <Stack space={2}>\n <Card padding={3} marginBottom={2} tone=\"transparent\" border radius={2}>\n <Flex align=\"center\" justify=\"space-between\">\n <Text>{getCurrentFileName()}</Text>\n <Flex gap={2}>\n {track.status !== 'errored' && (\n <Button\n icon={\n downloading ? (\n <Spinner\n style={{\n verticalAlign: 'middle',\n display: 'inline-block',\n marginTop: '-2px',\n width: '0.5em',\n height: '0.5em',\n }}\n />\n ) : (\n <DownloadIcon />\n )\n }\n text=\"Download\"\n mode=\"ghost\"\n tone=\"primary\"\n fontSize={1}\n padding={2}\n onClick={handleDownloadCurrentFile}\n disabled={downloading || isSubmitting}\n />\n )}\n <Button\n icon={UploadIcon}\n text=\"Replace\"\n mode=\"ghost\"\n tone=\"primary\"\n fontSize={1}\n padding={2}\n onClick={() => fileInputRef.current?.click()}\n disabled={isSubmitting}\n />\n </Flex>\n </Flex>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".vtt,text/vtt\"\n style={{display: 'none'}}\n onChange={(e) => {\n if (e.target.files && e.target.files.length > 0 && !isSubmitting) {\n setSelectedFile(e.target.files[0]!)\n setVttUrl('')\n }\n }}\n />\n {selectedFile && (\n <Text size={1} muted style={{marginTop: 8}}>\n Selected: {selectedFile.name}\n </Text>\n )}\n </Card>\n <Stack space={2}>\n <Label as=\"label\" htmlFor=\"vtt-url\">\n VTT File URL\n </Label>\n <TextInput\n id=\"vtt-url\"\n placeholder=\"https://example.com/subtitles.vtt\"\n value={vttUrl}\n onChange={(e) => {\n setVttUrl(e.currentTarget.value)\n setSelectedFile(null)\n }}\n disabled={isSubmitting}\n />\n <Text size={1} muted>\n Add a URL to replace the existing VTT file with a new one\n </Text>\n </Stack>\n </Stack>\n\n <Stack space={2}>\n <Label as=\"label\" htmlFor=\"caption-name\">\n Audio name\n </Label>\n <Autocomplete\n id=\"caption-name\"\n value={selectedLanguage?.value || ''}\n onChange={(newValue) => {\n const selected = LANGUAGE_OPTIONS.find((opt) => opt.value === newValue)\n if (selected) {\n setSelectedLanguage(selected)\n setLanguageCode(selected.value)\n setName(selected.label)\n }\n }}\n options={LANGUAGE_OPTIONS}\n icon={TranslateIcon}\n placeholder=\"Select language\"\n filterOption={(query, option) =>\n option.label.toLowerCase().indexOf(query.toLowerCase()) > -1 ||\n option.value.toLowerCase().indexOf(query.toLowerCase()) > -1\n }\n openButton\n renderValue={(value) => LANGUAGE_OPTIONS.find((l) => l.value === value)?.label || value}\n renderOption={(option) => (\n <Card data-as=\"button\" padding={3} radius={2} tone=\"inherit\">\n <Text size={2} textOverflow=\"ellipsis\">\n {option.label} ({option.value})\n </Text>\n </Card>\n )}\n disabled={isSubmitting}\n />\n </Stack>\n\n <Stack space={2}>\n <Label as=\"label\" htmlFor=\"caption-language\">\n Language Code\n </Label>\n <TextInput\n id=\"caption-language\"\n placeholder=\"en-US\"\n value={languageCode}\n onChange={(e) => {\n setLanguageCode(e.currentTarget.value)\n if (selectedLanguage && selectedLanguage.value !== e.currentTarget.value) {\n setSelectedLanguage(null)\n if (!name || name === selectedLanguage.label) {\n setName('')\n }\n }\n }}\n disabled={isSubmitting}\n />\n </Stack>\n\n <Flex gap={2} justify=\"flex-end\" marginTop={2}>\n <Button text=\"Cancel\" mode=\"ghost\" onClick={onClose} disabled={isSubmitting} />\n <Button\n text=\"Update Caption Track\"\n tone=\"primary\"\n icon={\n isSubmitting ? (\n <Spinner\n style={{\n verticalAlign: 'middle',\n display: 'inline-block',\n marginBottom: '-3px',\n width: '1em',\n height: '1em',\n marginRight: '-6px',\n }}\n />\n ) : (\n UploadIcon\n )\n }\n onClick={handleSubmit}\n disabled={isSubmitting}\n />\n </Flex>\n </Stack>\n </Dialog>\n )\n}\n","import {AddIcon} from '@sanity/icons/Add'\nimport {ChevronDownIcon} from '@sanity/icons/ChevronDown'\nimport {ChevronUpIcon} from '@sanity/icons/ChevronUp'\nimport {DownloadIcon} from '@sanity/icons/Download'\nimport {EditIcon} from '@sanity/icons/Edit'\nimport {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {TrashIcon} from '@sanity/icons/Trash'\nimport {Box, Button, Card, Dialog, Flex, Heading, Spinner, Stack, Text, useToast} from '@sanity/ui'\nimport {useEffect, useId, useMemo, useState} from 'react'\n\nimport {deleteTextTrack} from '../actions/assets'\nimport {useClient} from '../hooks/useClient'\nimport {useResyncAsset} from '../hooks/useResyncAsset'\nimport {downloadVttFile} from '../util/textTracks'\nimport type {MuxTextTrack, VideoAssetDocument} from '../util/types'\nimport AddCaptionDialog from './AddCaptionDialog'\nimport EditCaptionDialog from './EditCaptionDialog'\n\ninterface TrackCardProps {\n track: MuxTextTrack\n iconOnly: boolean\n downloadingTrackId: string | null\n deletingTrackId: string | null\n trackToEdit: MuxTextTrack | null\n getTrackSourceLabel: (track: MuxTextTrack) => string\n handleDownload: (track: MuxTextTrack) => void\n setTrackToEdit: (track: MuxTextTrack) => void\n setTrackToDelete: (track: MuxTextTrack) => void\n}\n\nfunction TrackCard({\n track,\n iconOnly,\n downloadingTrackId,\n deletingTrackId,\n trackToEdit,\n getTrackSourceLabel,\n handleDownload,\n setTrackToEdit,\n setTrackToDelete,\n}: TrackCardProps) {\n const isDisabled = (action: 'download' | 'edit' | 'delete') => {\n if (action === 'download') {\n return (\n downloadingTrackId !== null || deletingTrackId === track.id || trackToEdit?.id === track.id\n )\n }\n if (action === 'edit') {\n return (\n downloadingTrackId === track.id ||\n deletingTrackId === track.id ||\n trackToEdit?.id === track.id\n )\n }\n return (\n downloadingTrackId === track.id || deletingTrackId !== null || trackToEdit?.id === track.id\n )\n }\n\n const renderActionButtons = () => {\n if (track.status === 'preparing') {\n return (\n <Flex align=\"center\" gap={2}>\n <Spinner\n muted\n style={{\n width: '0.75em',\n height: '0.75em',\n verticalAlign: 'middle',\n display: 'inline-block',\n marginBottom: '-2px',\n }}\n />\n <Text size={1} muted>\n Processing...\n </Text>\n </Flex>\n )\n }\n\n return (\n <Flex gap={2}>\n {track.status !== 'errored' && (\n <Button\n icon={\n downloadingTrackId === track.id ? (\n <Spinner\n style={{\n verticalAlign: 'middle',\n display: 'inline-block',\n marginTop: '-2px',\n width: '0.5em',\n height: '0.5em',\n }}\n />\n ) : (\n <DownloadIcon />\n )\n }\n text={iconOnly ? undefined : 'Download'}\n mode=\"ghost\"\n tone=\"primary\"\n fontSize={1}\n padding={2}\n onClick={() => handleDownload(track)}\n disabled={isDisabled('download')}\n title=\"Download\"\n />\n )}\n <Button\n icon={<EditIcon />}\n text={iconOnly ? undefined : 'Edit'}\n mode=\"ghost\"\n tone=\"primary\"\n fontSize={1}\n padding={2}\n disabled={isDisabled('edit')}\n onClick={() => setTrackToEdit(track)}\n title=\"Edit\"\n />\n <Button\n icon={\n deletingTrackId === track.id ? (\n <Spinner\n style={{\n verticalAlign: 'middle',\n display: 'inline-block',\n marginTop: '-2px',\n width: '0.5em',\n height: '0.5em',\n }}\n />\n ) : (\n <TrashIcon />\n )\n }\n text={iconOnly ? undefined : 'Delete'}\n mode=\"ghost\"\n tone=\"critical\"\n fontSize={1}\n padding={2}\n disabled={isDisabled('delete')}\n onClick={() => setTrackToDelete(track)}\n title=\"Delete\"\n />\n </Flex>\n )\n }\n\n return (\n <Card\n padding={3}\n radius={2}\n tone={track.status === 'errored' ? 'caution' : 'transparent'}\n border\n >\n <Flex align=\"center\" justify=\"space-between\" gap={3}>\n <Stack space={2} flex={1}>\n <Flex align=\"center\" gap={2}>\n <Text weight=\"semibold\">{track.name || 'Untitled'}</Text>\n <Text size={1} muted>\n ({getTrackSourceLabel(track)})\n </Text>\n {track.status === 'errored' && (\n <ErrorOutlineIcon\n style={{color: 'var(--card-critical-color)'}}\n aria-label=\"Error\"\n fontSize={20}\n />\n )}\n </Flex>\n {track.language_code && (\n <Text size={1} muted>\n Language: {track.language_code}\n </Text>\n )}\n {track.status === 'errored' && track.error && (\n <Text size={1} style={{color: 'var(--card-critical-color)'}}>\n {track.error.messages?.[0] || track.error.type || 'Failed to process track'}\n </Text>\n )}\n </Stack>\n {renderActionButtons()}\n </Flex>\n </Card>\n )\n}\n\ninterface TextTracksManagerProps {\n asset: VideoAssetDocument\n iconOnly?: boolean\n tracks?: MuxTextTrack[]\n collapseTracks?: boolean\n}\n\nexport default function TextTracksManager({\n asset,\n iconOnly = false,\n tracks: propTracks,\n collapseTracks = false,\n}: TextTracksManagerProps) {\n const client = useClient()\n const toast = useToast()\n const dialogId = `DeleteCaptionDialog${useId()}`\n const {resyncAsset} = useResyncAsset()\n const [downloadingTrackId, setDownloadingTrackId] = useState<string | null>(null)\n const [deletingTrackId, setDeletingTrackId] = useState<string | null>(null)\n const [addedTracks, setAddedTracks] = useState<MuxTextTrack[]>([])\n const [updatedTracks, setUpdatedTracks] = useState<Map<string, MuxTextTrack>>(new Map())\n const [trackActivityOrder, setTrackActivityOrder] = useState<Map<string, number>>(new Map())\n const [autogeneratedTrackIds, setAutogeneratedTrackIds] = useState<Set<string>>(new Set())\n const [trackToDelete, setTrackToDelete] = useState<MuxTextTrack | null>(null)\n const [trackToEdit, setTrackToEdit] = useState<MuxTextTrack | null>(null)\n const [showAddDialog, setShowAddDialog] = useState(false)\n const [isExpanded, setIsExpanded] = useState(false)\n\n const MAX_VISIBLE_TRACKS = 4\n\n const realTracks: MuxTextTrack[] = propTracks\n ? propTracks\n : asset.data?.tracks?.filter((track): track is MuxTextTrack => track.type === 'text') || []\n\n const activeTracks = realTracks.filter(\n (track) =>\n track.id &&\n (track.status === 'ready' || track.status === 'preparing' || track.status === 'errored'),\n )\n\n const allTracks = useMemo(() => {\n const tracksWithUpdates = activeTracks.map((track) => {\n const updated = updatedTracks.get(track.id)\n return updated || track\n })\n\n const isMockTrackReplaced = (mockTrack: MuxTextTrack, realTracksList: MuxTextTrack[]) => {\n if (!mockTrack.id || !mockTrack.id.startsWith('generating-')) {\n return false\n }\n return realTracksList.some((realTrack) => {\n const nameMatches = realTrack.name === mockTrack.name\n const languageMatches = realTrack.language_code === mockTrack.language_code\n if (!nameMatches || !languageMatches) {\n return false\n }\n if (realTrack.status === 'ready') {\n const isGenerated =\n realTrack.text_source === 'generated_live' ||\n realTrack.text_source === 'generated_live_final' ||\n realTrack.text_source === 'generated_vod'\n return isGenerated\n }\n if (realTrack.status === 'preparing') {\n return true\n }\n return false\n })\n }\n\n const isTrackAlreadyInRealTracks = (\n addedTrack: MuxTextTrack,\n realTracksList: MuxTextTrack[],\n ) => {\n if (!addedTrack.id) return false\n if (addedTrack.id.startsWith('generating-')) {\n return isMockTrackReplaced(addedTrack, realTracksList)\n }\n return realTracksList.some((realTrack) => realTrack.id === addedTrack.id)\n }\n\n const tracksToKeep = addedTracks.filter((addedTrack) => {\n if (addedTrack.id && addedTrack.id.startsWith('generating-')) {\n return !isMockTrackReplaced(addedTrack, tracksWithUpdates)\n }\n return !isTrackAlreadyInRealTracks(addedTrack, tracksWithUpdates)\n })\n\n return [...tracksWithUpdates, ...tracksToKeep]\n }, [activeTracks, addedTracks, updatedTracks])\n\n useEffect(() => {\n const newAutogeneratedIds = new Set<string>()\n\n activeTracks.forEach((track) => {\n if (\n track.id &&\n (track.text_source === 'generated_live' ||\n track.text_source === 'generated_live_final' ||\n track.text_source === 'generated_vod')\n ) {\n newAutogeneratedIds.add(track.id)\n }\n })\n\n addedTracks.forEach((mockTrack) => {\n if (mockTrack.id && mockTrack.id.startsWith('generating-')) {\n const realTrack = activeTracks.find((rt) => {\n const nameMatches = rt.name === mockTrack.name\n const languageMatches = rt.language_code === mockTrack.language_code\n return nameMatches && languageMatches\n })\n if (realTrack?.id) {\n newAutogeneratedIds.add(realTrack.id)\n }\n }\n })\n\n // oxlint-disable-next-line react/react-compiler\n setAutogeneratedTrackIds((prev) => {\n let hasNew = false\n const updated = new Set(prev)\n newAutogeneratedIds.forEach((id) => {\n if (!prev.has(id)) {\n updated.add(id)\n hasNew = true\n }\n })\n return hasNew ? updated : prev\n })\n }, [activeTracks, addedTracks])\n\n useEffect(() => {\n const preparingTracks = allTracks.filter((track) => track.status === 'preparing')\n if (preparingTracks.length === 0 || !asset.assetId || !asset._id) {\n return undefined\n }\n\n const interval = setInterval(async () => {\n try {\n const muxData = await resyncAsset(asset)\n if (!muxData) return\n\n const fetchedTracks =\n muxData.tracks?.filter((track): track is MuxTextTrack => track.type === 'text') || []\n\n const isMockTrackReplaced = (\n mockTrack: MuxTextTrack,\n fetchedTracksList: MuxTextTrack[],\n ) => {\n if (!mockTrack.id || !mockTrack.id.startsWith('generating-')) {\n return false\n }\n return fetchedTracksList.some((realTrack) => {\n const nameMatches = realTrack.name === mockTrack.name\n const languageMatches = realTrack.language_code === mockTrack.language_code\n if (!nameMatches || !languageMatches) {\n return false\n }\n if (realTrack.status === 'ready') {\n const isGenerated =\n realTrack.text_source === 'generated_live' ||\n realTrack.text_source === 'generated_live_final' ||\n realTrack.text_source === 'generated_vod'\n return isGenerated\n }\n if (realTrack.status === 'preparing') {\n return true\n }\n return false\n })\n }\n\n const newAutogeneratedIds = new Set<string>()\n fetchedTracks.forEach((track) => {\n if (\n track.id &&\n (track.text_source === 'generated_live' ||\n track.text_source === 'generated_live_final' ||\n track.text_source === 'generated_vod')\n ) {\n newAutogeneratedIds.add(track.id)\n }\n })\n\n const findMatchingRealTrack = (mockTrack: MuxTextTrack, tracksList: MuxTextTrack[]) => {\n return tracksList.find((rt) => {\n const nameMatches = rt.name === mockTrack.name\n const languageMatches = rt.language_code === mockTrack.language_code\n return nameMatches && languageMatches\n })\n }\n\n setAddedTracks((prev) => {\n return prev.filter((mockTrack) => {\n if (mockTrack.id && mockTrack.id.startsWith('generating-')) {\n const replaced = isMockTrackReplaced(mockTrack, fetchedTracks)\n if (replaced) {\n const realTrack = findMatchingRealTrack(mockTrack, fetchedTracks)\n if (realTrack?.id) {\n newAutogeneratedIds.add(realTrack.id)\n setTrackActivityOrder((prevOrder) => {\n const mockOrder = prevOrder.get(mockTrack.id)\n if (mockOrder) {\n const newMap = new Map(prevOrder)\n newMap.set(realTrack.id, mockOrder)\n return newMap\n }\n return prevOrder\n })\n }\n }\n return !replaced\n }\n return true\n })\n })\n\n if (newAutogeneratedIds.size > 0) {\n setAutogeneratedTrackIds((prevIds) => {\n const updated = new Set(prevIds)\n newAutogeneratedIds.forEach((id) => updated.add(id))\n return updated\n })\n }\n } catch (error) {\n console.error('Failed to refresh asset data:', error)\n }\n }, 3000) // Poll every 3 seconds\n\n return () => clearInterval(interval)\n }, [allTracks, asset, resyncAsset])\n\n const visibleTracks = allTracks\n .filter(\n (track) =>\n track.status === 'ready' || track.status === 'preparing' || track.status === 'errored',\n )\n .sort((a, b) => {\n const orderA = trackActivityOrder.get(a.id) || 0\n const orderB = trackActivityOrder.get(b.id) || 0\n\n if (orderA > 0 && orderB > 0) {\n return orderB - orderA\n }\n\n if (orderA > 0) return -1\n if (orderB > 0) return 1\n\n const aIsPreparing = a.status === 'preparing'\n const bIsPreparing = b.status === 'preparing'\n if (aIsPreparing && !bIsPreparing) return -1\n if (!aIsPreparing && bIsPreparing) return 1\n\n const aIsAutogenerated =\n (a.id && a.id.startsWith('generating-')) || (a.id && autogeneratedTrackIds.has(a.id))\n const bIsAutogenerated =\n (b.id && b.id.startsWith('generating-')) || (b.id && autogeneratedTrackIds.has(b.id))\n if (aIsAutogenerated && !bIsAutogenerated) return -1\n if (!aIsAutogenerated && bIsAutogenerated) return 1\n\n return 0\n })\n\n const handleDownload = async (track: MuxTextTrack) => {\n if (!track.id) return\n\n setDownloadingTrackId(track.id)\n try {\n await downloadVttFile(client, asset, track)\n } catch (error) {\n toast.push({\n title: 'Failed to download VTT file',\n status: 'error',\n description: error instanceof Error ? error.message : 'Please try again',\n })\n } finally {\n setDownloadingTrackId(null)\n }\n }\n\n const confirmDelete = async () => {\n if (!trackToDelete || !trackToDelete.id) return\n\n const track = trackToDelete\n setTrackToDelete(null)\n setDeletingTrackId(track.id)\n try {\n if (!asset.assetId) {\n throw new Error('Asset ID is required')\n }\n await deleteTextTrack(client, asset.assetId, track.id)\n\n // Refresh asset data after deletion\n await resyncAsset(asset)\n\n toast.push({\n title: 'Successfully deleted caption track',\n status: 'success',\n })\n\n setAddedTracks((prev) => prev.filter((t) => t.id !== track.id))\n setUpdatedTracks((prev) => {\n const newMap = new Map(prev)\n newMap.delete(track.id)\n return newMap\n })\n setTrackActivityOrder((prev) => {\n const newMap = new Map(prev)\n newMap.delete(track.id)\n return newMap\n })\n setAutogeneratedTrackIds((prev) => {\n const updated = new Set(prev)\n updated.delete(track.id)\n return updated\n })\n } catch (error) {\n toast.push({\n title: 'Failed to delete caption track',\n status: 'error',\n description: error instanceof Error ? error.message : 'Please try again',\n })\n } finally {\n setDeletingTrackId(null)\n }\n }\n\n const handleAddTrack = (track: MuxTextTrack) => {\n setAddedTracks((prev) => [...prev, track])\n setTrackActivityOrder((prev) => {\n const newMap = new Map(prev)\n newMap.set(track.id, prev.size + 1)\n return newMap\n })\n setShowAddDialog(false)\n }\n\n const handleUpdateTrack = async (updatedTrack: MuxTextTrack, oldTrackId?: string) => {\n if (oldTrackId) {\n setAddedTracks((prev) => prev.filter((t) => t.id !== oldTrackId))\n setUpdatedTracks((prev) => {\n const newMap = new Map(prev)\n newMap.delete(oldTrackId)\n return newMap\n })\n setTrackActivityOrder((prev) => {\n const newMap = new Map(prev)\n newMap.delete(oldTrackId)\n return newMap\n })\n setAutogeneratedTrackIds((prev) => {\n const updated = new Set(prev)\n updated.delete(oldTrackId)\n return updated\n })\n }\n\n const isAddedTrack = addedTracks.some((t) => t.id === updatedTrack.id)\n\n if (isAddedTrack) {\n setAddedTracks((prev) => prev.map((t) => (t.id === updatedTrack.id ? updatedTrack : t)))\n } else {\n setUpdatedTracks((prev) => {\n const newMap = new Map(prev)\n newMap.set(updatedTrack.id, updatedTrack)\n return newMap\n })\n }\n\n setTrackActivityOrder((prev) => {\n const newMap = new Map(prev)\n newMap.set(updatedTrack.id, prev.size + 1)\n return newMap\n })\n\n setTrackToEdit(null)\n\n // Refresh asset data after update\n await resyncAsset(asset)\n }\n\n const getTrackSourceLabel = (track: MuxTextTrack) => {\n if (track.id && track.id.startsWith('generating-')) {\n return 'Auto-generated'\n }\n if (track.id && autogeneratedTrackIds.has(track.id)) {\n return 'Auto-generated'\n }\n if (\n track.text_source === 'generated_live_final' ||\n track.text_source === 'generated_live' ||\n track.text_source === 'generated_vod'\n ) {\n return 'Auto-generated'\n }\n if (track.text_source === 'uploaded') {\n return 'Uploaded'\n }\n return 'Custom'\n }\n\n if (visibleTracks.length === 0 && !showAddDialog) {\n return (\n <Stack space={3}>\n <Flex justify=\"flex-end\">\n <Button\n icon={AddIcon}\n text=\"Add Caption\"\n tone=\"primary\"\n onClick={() => setShowAddDialog(true)}\n />\n </Flex>\n <Card padding={4} radius={2} tone=\"transparent\" border>\n <Text size={1} muted>\n No captions available. Add captions when uploading a video or add them manually.\n </Text>\n </Card>\n {showAddDialog && (\n <AddCaptionDialog\n asset={asset}\n onAdd={handleAddTrack}\n onClose={() => setShowAddDialog(false)}\n />\n )}\n </Stack>\n )\n }\n\n const displayedTracks =\n collapseTracks && !isExpanded ? visibleTracks.slice(0, MAX_VISIBLE_TRACKS) : visibleTracks\n const hasMoreTracks = collapseTracks && visibleTracks.length > MAX_VISIBLE_TRACKS\n\n return (\n <Stack space={3}>\n <Flex justify=\"flex-end\">\n <Button\n icon={AddIcon}\n text=\"Add Caption\"\n tone=\"primary\"\n onClick={() => setShowAddDialog(true)}\n />\n </Flex>\n\n {displayedTracks.map((track) => (\n <TrackCard\n key={track.id}\n track={track}\n iconOnly={iconOnly}\n downloadingTrackId={downloadingTrackId}\n deletingTrackId={deletingTrackId}\n trackToEdit={trackToEdit}\n getTrackSourceLabel={getTrackSourceLabel}\n handleDownload={handleDownload}\n setTrackToEdit={setTrackToEdit}\n setTrackToDelete={setTrackToDelete}\n />\n ))}\n\n {hasMoreTracks && (\n <Flex justify=\"center\">\n <Button\n icon={isExpanded ? ChevronUpIcon : ChevronDownIcon}\n text={\n isExpanded ? 'Show less' : `Show ${visibleTracks.length - MAX_VISIBLE_TRACKS} more`\n }\n mode=\"ghost\"\n tone=\"primary\"\n onClick={() => setIsExpanded(!isExpanded)}\n />\n </Flex>\n )}\n\n {trackToDelete && (\n <Dialog\n animate\n id={dialogId}\n header=\"Delete track\"\n onClose={() => setTrackToDelete(null)}\n onClickOutside={() => setTrackToDelete(null)}\n width={1}\n >\n <Card\n padding={3}\n style={{\n minHeight: '150px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <Stack space={3}>\n <Heading size={2}>\n Are you sure you want to delete "\n {trackToDelete.name || trackToDelete.language_code || 'Untitled'}"?\n </Heading>\n <Text size={2}>This action is irreversible</Text>\n <Stack space={4} marginY={4}>\n <Box>\n <Button\n icon={\n deletingTrackId === trackToDelete.id ? (\n <Spinner\n style={{\n verticalAlign: 'middle',\n display: 'inline-block',\n marginTop: '-2px',\n width: '0.5em',\n height: '0.5em',\n }}\n />\n ) : (\n <TrashIcon />\n )\n }\n fontSize={2}\n padding={3}\n text=\"Delete track\"\n tone=\"critical\"\n onClick={confirmDelete}\n disabled={deletingTrackId !== null}\n />\n </Box>\n </Stack>\n </Stack>\n </Card>\n </Dialog>\n )}\n\n {showAddDialog && (\n <AddCaptionDialog\n asset={asset}\n onAdd={handleAddTrack}\n onClose={() => setShowAddDialog(false)}\n />\n )}\n\n {trackToEdit && (\n <EditCaptionDialog\n asset={asset}\n track={trackToEdit}\n onUpdate={handleUpdateTrack}\n onClose={() => setTrackToEdit(null)}\n />\n )}\n </Stack>\n )\n}\n","import {createContext, useContext, useMemo} from 'react'\n\nimport {type DialogState, type SetDialogState} from '../hooks/useDialogState'\n\ntype DialogStateContextProps = {\n dialogState: DialogState\n setDialogState: SetDialogState\n}\n\nconst DialogStateContext = createContext<DialogStateContextProps>({\n dialogState: false,\n setDialogState: () => {\n return null\n },\n})\n\ninterface DialogStateProviderProps extends DialogStateContextProps {\n children: React.ReactNode\n}\n\nexport const DialogStateProvider = ({\n dialogState,\n setDialogState,\n children,\n}: DialogStateProviderProps) => {\n const value = useMemo(() => ({dialogState, setDialogState}), [dialogState, setDialogState])\n return <DialogStateContext.Provider value={value}>{children}</DialogStateContext.Provider>\n}\n\nexport const useDialogStateContext = () => {\n const context = useContext(DialogStateContext)\n return context\n}\n","import type {SanityClient} from 'sanity'\n\nimport {generateJwt} from './generateJwt'\nimport type {MuxPlaybackId, MuxVideoUrl} from './types'\n\ninterface VideoSrcOptions {\n muxPlaybackId: MuxPlaybackId\n client: SanityClient\n}\n\n/**\n * May throw a Promise. Call this with {@link tryWithSuspend} or rethrow the Promise\n */\nexport function getVideoSrc({client, muxPlaybackId}: VideoSrcOptions): MuxVideoUrl {\n const searchParams = new URLSearchParams()\n\n if (muxPlaybackId.policy === 'signed' || muxPlaybackId.policy === 'drm') {\n const token = generateJwt(client, muxPlaybackId.id, 'v')\n searchParams.set('token', token)\n }\n\n return `https://stream.mux.com/${muxPlaybackId.id}.m3u8?${searchParams}`\n}\n","import {Dialog, Stack} from '@sanity/ui'\nimport {useId} from 'react'\n\nimport {useDialogStateContext} from '../context/DialogStateContext'\nimport type {VideoAssetDocument} from '../util/types'\nimport TextTracksManager from './TextTracksManager'\n\nexport interface Props {\n asset: VideoAssetDocument\n}\n\nexport default function CaptionsDialog({asset}: Props) {\n const {setDialogState} = useDialogStateContext()\n const dialogId = `CaptionsDialog${useId()}`\n\n return (\n <Dialog id={dialogId} header=\"Edit Captions\" onClose={() => setDialogState(false)} width={1}>\n <Stack padding={4}>\n <TextTracksManager asset={asset} />\n </Stack>\n </Dialog>\n )\n}\n","// From: https://stackoverflow.com/a/11486026/10433647\nexport function formatSeconds(seconds: number): string {\n if (typeof seconds !== 'number' || Number.isNaN(seconds)) {\n return ''\n }\n // Hours, minutes and seconds\n const hrs = ~~(seconds / 3600)\n const mins = ~~((seconds % 3600) / 60)\n const secs = ~~seconds % 60\n\n // Output like \"1:01\" or \"4:03:59\" or \"123:03:59\"\n let ret = ''\n\n if (hrs > 0) {\n ret += '' + hrs + ':' + (mins < 10 ? '0' : '')\n }\n\n ret += '' + mins + ':' + (secs < 10 ? '0' : '')\n ret += '' + secs\n return ret\n}\n\n// Output like \"05:14:01\"\nexport function formatSecondsToHHMMSS(seconds: number): string {\n const hrs = Math.floor(seconds / 3600)\n .toString()\n .padStart(2, '0')\n const mins = Math.floor((seconds % 3600) / 60)\n .toString()\n .padStart(2, '0')\n const secs = Math.floor(seconds % 60)\n .toString()\n .padStart(2, '0')\n\n return `${hrs}:${mins}:${secs}`\n}\n\n// Checks if time has a HH:MM:SS format like \"05:14:01\"\nexport function isValidTimeFormat(time: string) {\n const regex = /^([0-1]?[0-9]|2[0-3]):([0-5]?[0-9]):([0-5]?[0-9])$/\n return regex.test(time) || time === ''\n}\n\n// Converts a time like \"05:14:01\" to seconds\nexport function getSecondsFromTimeFormat(time: string): number {\n const [hh = 0, mm = 0, ss = 0] = time.split(':').map(Number)\n return hh * 3600 + mm * 60 + ss\n}\n","import {Button, Dialog, Flex, Stack, Text, TextInput} from '@sanity/ui'\nimport {useId, useMemo, useState} from 'react'\nimport {getDevicePixelRatio} from 'use-device-pixel-ratio'\n\nimport {useDialogStateContext} from '../context/DialogStateContext'\nimport {useClient} from '../hooks/useClient'\nimport {\n formatSecondsToHHMMSS,\n getSecondsFromTimeFormat,\n isValidTimeFormat,\n} from '../util/formatSeconds'\nimport type {VideoAssetDocument} from '../util/types'\nimport VideoThumbnail from './VideoThumbnail'\n\nexport interface Props {\n asset: VideoAssetDocument\n currentTime?: number\n}\n\nexport default function EditThumbnailDialog({asset, currentTime = 0}: Props) {\n const client = useClient()\n\n const {setDialogState} = useDialogStateContext()\n const dialogId = `EditThumbnailDialog${useId()}`\n\n const [timeFormatted, setTimeFormatted] = useState<string>(() =>\n formatSecondsToHHMMSS(currentTime),\n )\n const [nextTime, setNextTime] = useState<number>(currentTime)\n const [inputError, setInputError] = useState<string>('')\n\n const assetWithNewThumbnail = useMemo(() => ({...asset, thumbTime: nextTime}), [asset, nextTime])\n const [saving, setSaving] = useState(false)\n const [saveThumbnailError, setSaveThumbnailError] = useState<Error | null>(null)\n const handleSave = () => {\n setSaving(true)\n client\n .patch(asset._id)\n .set({thumbTime: nextTime})\n .commit({returnDocuments: false})\n .then(() => setDialogState(false))\n .catch(setSaveThumbnailError)\n .finally(() => setSaving(false))\n }\n const width = 300 * getDevicePixelRatio({maxDpr: 2})\n\n if (saveThumbnailError) {\n // @TODO handle errors more gracefully\n throw saveThumbnailError\n }\n\n const handleInputChange = (event: React.FormEvent<HTMLInputElement>) => {\n const value = event.currentTarget.value\n setTimeFormatted(value)\n\n if (isValidTimeFormat(value)) {\n setInputError('')\n const totalSeconds = getSecondsFromTimeFormat(value)\n setNextTime(totalSeconds)\n } else {\n setInputError('Invalid time format')\n }\n }\n\n return (\n <Dialog\n id={dialogId}\n header=\"Edit thumbnail\"\n onClose={() => setDialogState(false)}\n footer={\n <Stack padding={3}>\n <Button\n key=\"thumbnail\"\n disabled={inputError !== ''}\n mode=\"ghost\"\n tone=\"primary\"\n loading={saving}\n onClick={handleSave}\n text=\"Set new thumbnail\"\n />\n </Stack>\n }\n >\n <Stack space={3} padding={3}>\n <Stack space={2}>\n <Text size={1} weight=\"semibold\">\n Current:\n </Text>\n <VideoThumbnail asset={asset} width={width} staticImage />\n </Stack>\n <Stack space={2}>\n <Text size={1} weight=\"semibold\">\n New:\n </Text>\n <VideoThumbnail asset={assetWithNewThumbnail} width={width} staticImage />\n </Stack>\n\n <Stack space={2}>\n <Flex align={'center'} justify={'center'}>\n <Text size={5} weight=\"semibold\">\n Or\n </Text>\n </Flex>\n </Stack>\n\n <Stack space={2}>\n <Text size={1} weight=\"semibold\">\n Selected time for thumbnail (hh:mm:ss):\n </Text>\n <TextInput\n size={1}\n value={timeFormatted}\n placeholder=\"hh:mm:ss\"\n onChange={handleInputChange}\n customValidity={inputError}\n />\n </Stack>\n </Stack>\n </Dialog>\n )\n}\n","import type {SVGProps} from 'react'\n\nexport function AudioIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1em\" height=\"1em\" viewBox=\"0 0 24 24\" {...props}>\n <path\n fill=\"currentColor\"\n style={{opacity: '0.65'}}\n d=\"M10.75 19q.95 0 1.6-.65t.65-1.6V13h3v-2h-4v3.875q-.275-.2-.587-.288t-.663-.087q-.95 0-1.6.65t-.65 1.6t.65 1.6t1.6.65M6 22q-.825 0-1.412-.587T4 20V4q0-.825.588-1.412T6 2h8l6 6v12q0 .825-.587 1.413T18 22zm7-13V4H6v16h12V9zM6 4v5zv16z\"\n />\n </svg>\n )\n}\n","import {Box, Dialog, Stack} from '@sanity/ui'\nimport {useId} from 'react'\n\nimport {useDialogStateContext} from '../context/DialogStateContext'\nimport {getMezzanineStatus} from '../hooks/useMezzanine'\nimport {DIALOGS_Z_INDEX} from '../util/constants'\nimport type {VideoAssetDocument} from '../util/types'\nimport Mezzanine from './Mezzanine'\nimport MezzanineExplanation from './MezzanineExplanation'\n\nexport interface Props {\n asset: VideoAssetDocument\n onClose?: () => void\n}\n\n/**\n * Player actions menu entry point: the explanation in the dialog body (until the\n * file is enabled) with the {@link Mezzanine} card below for the action/status.\n */\nexport default function MezzanineDialog({asset, onClose}: Props) {\n const {setDialogState} = useDialogStateContext()\n const dialogId = `MezzanineDialog${useId()}`\n\n const closing = () => {\n onClose?.()\n setDialogState(false)\n }\n\n const status = getMezzanineStatus(asset)\n const showExplanation = status !== 'preparing' && status !== 'ready'\n\n return (\n <Dialog\n id={dialogId}\n header=\"Mezzanine file\"\n onClose={closing}\n zOffset={DIALOGS_Z_INDEX}\n width={1}\n >\n <Box padding={4}>\n <Stack space={4}>\n {showExplanation && <MezzanineExplanation />}\n <Mezzanine asset={asset} withExplanation={false} />\n </Stack>\n </Box>\n </Dialog>\n )\n}\n","import {type MuxPlayerProps, type MuxPlayerRefAttributes} from '@mux/mux-player-react'\nimport MuxPlayer from '@mux/mux-player-react/lazy'\nimport {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {Card, Text} from '@sanity/ui'\nimport {type PropsWithChildren, Suspense, useMemo, useRef, useState} from 'react'\n\nimport {useDialogStateContext} from '../context/DialogStateContext'\nimport {useClient} from '../hooks/useClient'\nimport {AUDIO_ASPECT_RATIO, MIN_ASPECT_RATIO} from '../util/constants'\nimport {generateJwt} from '../util/generateJwt'\nimport {getPlaybackId} from '../util/getPlaybackPolicy'\nimport {getPlaybackPolicyById} from '../util/getPlaybackPolicy'\nimport {getPosterSrc} from '../util/getPosterSrc'\nimport {getVideoSrc} from '../util/getVideoSrc'\nimport {tryWithSuspend} from '../util/tryWithSuspend'\nimport type {VideoAssetDocument} from '../util/types'\nimport CaptionsDialog from './CaptionsDialog'\nimport EditThumbnailDialog from './EditThumbnailDialog'\nimport {AudioIcon} from './icons/Audio'\nimport MezzanineDialog from './MezzanineDialog'\n\nexport default function VideoPlayer({\n asset,\n thumbnailWidth = 250,\n children,\n hlsConfig,\n ...props\n}: PropsWithChildren<\n {\n asset: VideoAssetDocument\n thumbnailWidth?: number\n forceAspectRatio?: number\n hlsConfig?: MuxPlayerProps['_hlsConfig']\n } & Partial<Pick<MuxPlayerProps, 'autoPlay'>>\n>) {\n const client = useClient()\n const {dialogState} = useDialogStateContext()\n\n const isAudio = assetIsAudio(asset)\n const muxPlayer = useRef<MuxPlayerRefAttributes>(null)\n const playerContainerRef = useRef<HTMLDivElement>(null)\n const [error, setError] = useState<Error>()\n\n /* Playback ID that will be used to play the video */\n const playbackId = useMemo(() => {\n try {\n return getPlaybackId(asset, ['public', 'signed', 'drm'])\n } catch (e) {\n // oxlint-disable-next-line react/react-compiler\n setError(new TypeError('Asset has no playback ID', {cause: e}))\n return undefined\n }\n }, [asset])\n\n const muxPlaybackId = useMemo(() => {\n if (!playbackId) return undefined\n return getPlaybackPolicyById(asset, playbackId)\n }, [asset, playbackId])\n\n const src = useMemo(() => {\n if (!playbackId) return undefined\n if (!muxPlaybackId) return undefined\n return tryWithSuspend(\n () => getVideoSrc({muxPlaybackId, client}),\n (e: Error) => {\n setError(e)\n return undefined\n },\n )\n }, [muxPlaybackId, playbackId, client])\n\n const poster = useMemo(() => {\n return tryWithSuspend(\n () => getPosterSrc({asset, client, width: thumbnailWidth}),\n (e: Error) => {\n setError(e)\n return undefined\n },\n )\n }, [asset, client, thumbnailWidth])\n\n const signedToken = useMemo(() => {\n try {\n const url = new URL(src!)\n return url.searchParams.get('token')\n } catch {\n return undefined\n }\n }, [src])\n const drmToken = useMemo(() => {\n if (!playbackId) return undefined\n if (muxPlaybackId?.policy !== 'drm') return undefined\n\n return tryWithSuspend(\n () => generateJwt(client, playbackId, 'd'),\n (e: Error) => {\n setError(e)\n return undefined\n },\n )\n }, [client, muxPlaybackId?.policy, playbackId])\n const tokens:\n | Partial<{\n playback?: string\n thumbnail?: string\n storyboard?: string\n drm?: string\n }>\n | undefined = useMemo(() => {\n try {\n const partialTokens: {\n playback?: string\n thumbnail?: string\n storyboard?: string\n drm?: string\n } = {\n playback: undefined,\n thumbnail: undefined,\n storyboard: undefined,\n drm: undefined,\n }\n\n if (signedToken) {\n partialTokens.playback = signedToken\n partialTokens.thumbnail = signedToken\n partialTokens.storyboard = signedToken\n }\n\n if (drmToken) {\n partialTokens.drm = drmToken\n }\n\n return {...partialTokens}\n } catch {\n return undefined\n }\n }, [signedToken, drmToken])\n\n const [width, height] = (asset?.data?.aspect_ratio ?? '16:9').split(':').map(Number)\n const targetAspectRatio =\n props.forceAspectRatio || (Number.isNaN(width) ? 16 / 9 : width! / height!)\n let aspectRatio = Math.max(MIN_ASPECT_RATIO, targetAspectRatio)\n if (isAudio) {\n aspectRatio = props.forceAspectRatio\n ? // Make it wider when forcing aspect ratio to balance with videos' rendering height (audio players overflow a bit)\n props.forceAspectRatio * 1.2\n : AUDIO_ASPECT_RATIO\n }\n\n /* We use Suspense here because `generateJwt` and related functions use suspend()\n under the hood */\n return (\n <>\n <Card\n ref={playerContainerRef}\n tone=\"transparent\"\n style={{\n aspectRatio: aspectRatio,\n position: 'relative',\n ...(isAudio && {display: 'flex', alignItems: 'flex-end'}),\n }}\n >\n {src && poster && (\n <>\n {isAudio && (\n <AudioIcon\n style={{\n padding: '0.5em',\n width: '2.2em',\n height: '2.2em',\n position: 'absolute',\n top: 0,\n left: 0,\n zIndex: 1,\n }}\n />\n )}\n <Suspense fallback={null}>\n <MuxPlayer\n poster={isAudio ? undefined : poster}\n ref={muxPlayer}\n {...props}\n playsInline\n playbackId={playbackId}\n tokens={tokens}\n preload=\"metadata\"\n crossOrigin=\"anonymous\"\n metadata={{\n player_name: 'Sanity Admin Dashboard',\n // @ts-expect-error - this constant is search/replaced so must be exact, not accessed with an index signature\n player_version: process.env.PKG_VERSION,\n page_type: 'Preview Player',\n }}\n audio={isAudio}\n _hlsConfig={hlsConfig}\n style={{\n ...(!isAudio && {height: '100%'}),\n width: '100%',\n display: 'block',\n objectFit: 'contain',\n ...(isAudio && {alignSelf: 'end'}),\n }}\n />\n {children}\n </Suspense>\n </>\n )}\n {error ? (\n <div\n style={{\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n }}\n >\n <Text muted>\n <ErrorOutlineIcon style={{marginRight: '0.15em'}} />\n {typeof error === 'object' && 'message' in error && typeof error.message === 'string'\n ? error.message\n : 'Error loading video'}\n </Text>\n </div>\n ) : null}\n {children}\n </Card>\n\n {dialogState === 'edit-thumbnail' && (\n <EditThumbnailDialog\n asset={asset}\n // oxlint-disable-next-line react/react-compiler\n currentTime={muxPlayer?.current?.currentTime}\n />\n )}\n {dialogState === 'edit-captions' && <CaptionsDialog asset={asset} />}\n {dialogState === 'mezzanine' && <MezzanineDialog asset={asset} />}\n </>\n )\n}\n\nexport function assetIsAudio(asset: VideoAssetDocument) {\n return asset.data?.max_stored_resolution === 'Audio only'\n}\n","// Adapted from https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/desk/components/MissingSchemaType.tsx\nimport {WarningOutlineIcon} from '@sanity/icons/WarningOutline'\nimport type {SanityDocument} from 'sanity'\nimport type {GeneralPreviewLayoutKey} from 'sanity'\nimport {SanityDefaultPreview} from 'sanity'\n\nexport interface MissingSchemaTypeProps {\n layout?: GeneralPreviewLayoutKey\n value: SanityDocument\n}\n\nconst getUnknownTypeFallback = (id: string, typeName: string) => ({\n title: (\n <em>\n No schema found for type <code>{typeName}</code>\n </em>\n ),\n subtitle: (\n <em>\n Document: <code>{id}</code>\n </em>\n ),\n media: () => <WarningOutlineIcon />,\n})\n\nexport function MissingSchemaType(props: MissingSchemaTypeProps) {\n const {layout, value} = props\n\n return (\n <SanityDefaultPreview {...getUnknownTypeFallback(value._id, value._type)} layout={layout} />\n )\n}\n","// Adapted from https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/desk/components/TimeAgo.tsx\nimport {useTimeAgo} from 'sanity'\n\nexport interface TimeAgoProps {\n time: string | Date\n}\n\nexport function TimeAgo({time}: TimeAgoProps) {\n const timeAgo = useTimeAgo(time)\n\n return <span title={timeAgo}>{timeAgo} ago</span>\n}\n","// Adapted from https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/desk/components/DraftStatus.tsx\nimport {EditIcon} from '@sanity/icons/Edit'\nimport {Box, Text, Tooltip} from '@sanity/ui'\nimport type {PreviewValue, SanityDocument} from 'sanity'\nimport {TextWithTone} from 'sanity'\n\nimport {TimeAgo} from './TimeAgo'\n\nexport function DraftStatus(props: {document?: PreviewValue | Partial<SanityDocument> | null}) {\n const {document} = props\n const updatedAt = document && '_updatedAt' in document && document._updatedAt\n\n return (\n <Tooltip\n animate\n portal\n content={\n <Box padding={2}>\n <Text size={1}>\n {document ? (\n <>Edited {updatedAt && <TimeAgo time={updatedAt} />}</>\n ) : (\n <>No unpublished edits</>\n )}\n </Text>\n </Box>\n }\n >\n <TextWithTone tone=\"caution\" dimmed={!document} muted={!document} size={1}>\n <EditIcon />\n </TextWithTone>\n </Tooltip>\n )\n}\n","// Adapted from https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/desk/components/PublishedStatus.tsx\n\nimport {PublishIcon} from '@sanity/icons/Publish'\nimport {Box, Text, Tooltip} from '@sanity/ui'\nimport type {PreviewValue, SanityDocument} from 'sanity'\nimport {TextWithTone} from 'sanity'\n\nimport {TimeAgo} from './TimeAgo'\n\nexport function PublishedStatus(props: {document?: PreviewValue | Partial<SanityDocument> | null}) {\n const {document} = props\n const updatedAt = document && '_updatedAt' in document && document._updatedAt\n\n return (\n <Tooltip\n animate\n portal\n content={\n <Box padding={2}>\n <Text size={1}>\n {document ? (\n <>Published {updatedAt && <TimeAgo time={updatedAt} />}</>\n ) : (\n <>Not published</>\n )}\n </Text>\n </Box>\n }\n >\n <TextWithTone tone=\"positive\" dimmed={!document} muted={!document} size={1}>\n <PublishIcon />\n </TextWithTone>\n </Tooltip>\n )\n}\n","// Adapted from:\n// https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/desk/components/paneItem/PaneItemPreview.tsx\nimport {Inline} from '@sanity/ui'\nimport {isNumber, isString} from 'lodash'\nimport {isValidElement, useMemo} from 'react'\nimport {useObservable} from 'react-rx'\nimport type {SanityDocument, SchemaType} from 'sanity'\nimport {\n type DocumentPresence,\n DocumentPreviewPresence,\n type DocumentPreviewStore,\n type GeneralPreviewLayoutKey,\n getPreviewStateObservable,\n getPreviewValueWithFallback,\n isRecord,\n SanityDefaultPreview,\n} from 'sanity'\n\nimport {DraftStatus} from './DraftStatus'\nimport {PublishedStatus} from './PublishedStatus'\n\nexport interface PaneItemPreviewProps {\n documentPreviewStore: DocumentPreviewStore\n icon: React.ComponentType | false\n layout: GeneralPreviewLayoutKey\n presence?: DocumentPresence[]\n schemaType: SchemaType\n value: SanityDocument\n}\n\nexport function PaneItemPreview(props: PaneItemPreviewProps) {\n const {icon, layout, presence, schemaType, value} = props\n const title =\n (isRecord(value['title']) && isValidElement(value['title'])) ||\n isString(value['title']) ||\n isNumber(value['title'])\n ? value['title']\n : null\n\n const observable = useMemo(\n () => getPreviewStateObservable(props.documentPreviewStore, schemaType, value._id),\n [props.documentPreviewStore, schemaType, value._id],\n )\n const {snapshot, original, isLoading} = useObservable(observable, {\n isLoading: true,\n snapshot: null,\n original: null,\n })\n\n const status = isLoading ? null : (\n <Inline space={4}>\n {presence && presence.length > 0 && <DocumentPreviewPresence presence={presence} />}\n <PublishedStatus document={original} />\n <DraftStatus document={snapshot} />\n </Inline>\n )\n\n return (\n <SanityDefaultPreview\n {...(getPreviewValueWithFallback({snapshot, original, fallback: {title}}) as any)}\n isPlaceholder={isLoading}\n icon={icon}\n layout={layout}\n status={status}\n />\n )\n}\n","// Adapted from https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/desk/components/paneItem/PaneItem.tsx\n\nimport {DocumentIcon} from '@sanity/icons/Document'\nimport type {PropsWithChildren} from 'react'\nimport {useMemo} from 'react'\nimport type {CollatedHit, FIXME, SanityDocument, SchemaType} from 'sanity'\nimport {PreviewCard, useDocumentPresence, useDocumentPreviewStore, useSchema} from 'sanity'\nimport {IntentLink} from 'sanity/router'\n\nimport {MissingSchemaType} from './MissingSchemaType'\nimport {PaneItemPreview} from './PaneItemPreview'\n\ninterface DocumentPreviewProps {\n schemaType?: SchemaType\n documentPair: CollatedHit<SanityDocument>\n}\n\n/**\n * Return `false` if we explicitly disable the icon.\n * Otherwise return the passed icon or the schema type icon as a backup.\n */\nfunction getIconWithFallback(\n icon: React.ComponentType<any> | false | undefined,\n schemaType: SchemaType | undefined,\n defaultIcon: React.ComponentType<any>,\n): React.ComponentType<any> | false {\n if (icon === false) {\n return false\n }\n\n return icon || ((schemaType && schemaType.icon) as any) || defaultIcon || false\n}\n\nfunction DocumentPreviewLink(props: DocumentPreviewProps) {\n return (linkProps: PropsWithChildren) => (\n <IntentLink intent=\"edit\" params={{id: props.documentPair.id}}>\n {linkProps.children}\n </IntentLink>\n )\n}\n\nexport function DocumentPreview(props: DocumentPreviewProps) {\n const {schemaType, documentPair} = props\n const doc = documentPair?.draft || documentPair?.published\n const id = documentPair.id || ''\n const documentPreviewStore = useDocumentPreviewStore()\n const schema = useSchema()\n const documentPresence = useDocumentPresence(id)\n const hasSchemaType = Boolean(schemaType && schemaType.name && schema.get(schemaType.name))\n\n const PreviewComponent = useMemo(() => {\n if (!doc) return null\n\n if (!schemaType || !hasSchemaType) {\n return <MissingSchemaType value={doc} />\n }\n\n return (\n <PaneItemPreview\n documentPreviewStore={documentPreviewStore}\n icon={getIconWithFallback(undefined, schemaType, DocumentIcon)}\n schemaType={schemaType}\n layout=\"default\"\n value={doc}\n presence={documentPresence}\n />\n )\n }, [hasSchemaType, schemaType, documentPresence, doc, documentPreviewStore])\n\n return (\n <PreviewCard\n __unstable_focusRing\n // oxlint-disable-next-line react/react-compiler\n as={DocumentPreviewLink(props) as FIXME}\n data-as=\"a\"\n data-ui=\"PaneItem\"\n padding={2}\n radius={2}\n tone=\"inherit\"\n >\n {PreviewComponent}\n </PreviewCard>\n )\n}\n","import type {SanityDocument} from '@sanity/client'\nimport {Box, Card, Text} from '@sanity/ui'\nimport {collate, useSchema} from 'sanity'\nimport {styled} from 'styled-components'\n\nimport {DocumentPreview} from '../documentPreview/DocumentPreview'\nimport SpinnerBox from '../SpinnerBox'\n\nconst Container = styled(Box)`\n * {\n color: ${(props: any) => props.theme.sanity.color.base.fg};\n }\n a {\n text-decoration: none;\n }\n h2 {\n font-size: ${(props: any) => props.theme.sanity.fonts.text.sizes[1]};\n }\n`\n\nconst VideoReferences: React.FC<{\n references?: SanityDocument[]\n isLoaded: boolean\n}> = (props) => {\n const schema = useSchema()\n if (!props.isLoaded) {\n return <SpinnerBox />\n }\n\n if (!props.references?.length) {\n return (\n <Card border radius={3} padding={3}>\n <Text size={2}>No documents are using this video</Text>\n </Card>\n )\n }\n\n const documentPairs = collate(props.references || [])\n return (\n <Container>\n {documentPairs?.map((documentPair) => {\n const schemaType = schema.get(documentPair.type)\n\n return (\n <Card\n key={documentPair.id}\n marginBottom={2}\n padding={2}\n radius={2}\n shadow={1}\n style={{overflow: 'hidden'}}\n >\n <Box>\n <DocumentPreview documentPair={documentPair} schemaType={schemaType} />\n </Box>\n </Card>\n )\n })}\n </Container>\n )\n}\n\nexport default VideoReferences\n","import {TrashIcon} from '@sanity/icons/Trash'\nimport {Box, Button, Card, Checkbox, Dialog, Flex, Heading, Stack, Text, useToast} from '@sanity/ui'\nimport {useEffect, useState} from 'react'\nimport type {SanityDocument} from 'sanity'\n\nimport {deleteAsset} from '../../actions/assets'\nimport {useClient} from '../../hooks/useClient'\nimport {DIALOGS_Z_INDEX} from '../../util/constants'\nimport type {VideoAssetDocument} from '../../util/types'\nimport SpinnerBox from '../SpinnerBox'\nimport VideoReferences from './VideoReferences'\n\nexport default function DeleteDialog({\n asset,\n references,\n referencesLoading,\n cancelDelete,\n succeededDeleting,\n}: {\n asset: VideoAssetDocument\n references?: SanityDocument[]\n referencesLoading: boolean\n cancelDelete: () => void\n succeededDeleting: () => void\n}) {\n const client = useClient()\n const [state, setState] = useState<\n 'processing_deletion' | 'checkingReferences' | 'error_deleting' | 'cantDelete' | 'confirm'\n >('checkingReferences')\n const [deleteOnMux, setDeleteOnMux] = useState(true)\n const toast = useToast()\n\n useEffect(() => {\n if (state !== 'checkingReferences' || referencesLoading) return\n\n // oxlint-disable-next-line react/react-compiler\n setState(references?.length ? 'cantDelete' : 'confirm')\n }, [state, references, referencesLoading])\n\n async function confirmDelete() {\n if (state !== 'confirm') return\n\n setState('processing_deletion')\n const worked = await deleteAsset({client, asset, deleteOnMux})\n if (worked === true) {\n toast.push({title: 'Successfully deleted video', status: 'success'})\n succeededDeleting()\n } else if (worked === 'failed-mux') {\n toast.push({\n title: 'Deleted video in Sanity',\n description: \"But it wasn't deleted in Mux\",\n status: 'warning',\n })\n succeededDeleting()\n } else {\n toast.push({title: 'Failed deleting video', status: 'error'})\n\n setState('error_deleting')\n }\n }\n\n return (\n <Dialog\n animate\n header={'Delete video'}\n zOffset={DIALOGS_Z_INDEX}\n id=\"deleting-video-details-dialog\"\n onClose={cancelDelete}\n onClickOutside={cancelDelete}\n width={1}\n position=\"fixed\"\n >\n <Card\n padding={3}\n style={{\n minHeight: '150px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <Stack space={3}>\n {state === 'checkingReferences' && (\n <>\n <Heading size={2}>Checking if video can be deleted</Heading>\n <SpinnerBox />\n </>\n )}\n {state === 'cantDelete' && (\n <>\n <Heading size={2}>Video can't be deleted</Heading>\n <Text size={2} style={{marginBottom: '2rem'}}>\n There are {references?.length} document{references && references.length > 0 && 's'}{' '}\n pointing to this video. Remove their references to this file or delete them before\n proceeding.\n </Text>\n <VideoReferences references={references} isLoaded={!referencesLoading} />\n </>\n )}\n {state === 'confirm' && (\n <>\n <Heading size={2}>Are you sure you want to delete this video?</Heading>\n <Text size={2}>This action is irreversible</Text>\n <Stack space={4} marginY={4}>\n <Flex align=\"center\" as=\"label\">\n <Checkbox\n checked={deleteOnMux}\n onChange={() => setDeleteOnMux((prev) => !prev)}\n />\n <Text style={{margin: '0 10px'}}>Delete asset on Mux</Text>\n </Flex>\n <Flex align=\"center\" as=\"label\">\n <Checkbox disabled checked />\n <Text style={{margin: '0 10px'}}>Delete video from dataset</Text>\n </Flex>\n <Box>\n <Button\n icon={TrashIcon}\n fontSize={2}\n padding={3}\n text=\"Delete video\"\n tone=\"critical\"\n onClick={confirmDelete}\n disabled={['processing_deletion', 'checkingReferences', 'cantDelete'].some(\n (s) => s === state,\n )}\n />\n </Box>\n </Stack>\n </>\n )}\n {state === 'processing_deletion' && (\n <>\n <Heading size={2}>Deleting video...</Heading>\n <SpinnerBox />\n </>\n )}\n {state === 'error_deleting' && (\n <>\n <Heading size={2}>Something went wrong!</Heading>\n <Text size={2}>Try deleting the video again by clicking the button below</Text>\n </>\n )}\n </Stack>\n </Card>\n </Dialog>\n )\n}\n","import {createHookFromObservableFactory, type DocumentStore, type SanityDocument} from 'sanity'\n\nimport {SANITY_API_VERSION} from './useClient'\n\nconst useDocReferences = createHookFromObservableFactory<\n SanityDocument[],\n {\n documentStore: DocumentStore\n id: string\n }\n>(({documentStore, id}) => {\n return documentStore.listenQuery(\n /* groq */ '*[references($id)]{_id, _type, _rev, _updatedAt, _createdAt}',\n {id},\n {\n apiVersion: SANITY_API_VERSION,\n },\n )\n})\n\nexport default useDocReferences\n","import {formatSeconds} from './formatSeconds'\nimport type {MuxTextTrack, VideoAssetDocument} from './types'\n\nexport default function getVideoMetadata(doc: VideoAssetDocument) {\n const id = doc.assetId || doc._id || ''\n const date = doc.data?.created_at\n ? new Date(Number(doc.data.created_at) * 1000)\n : new Date(doc._createdAt || doc._updatedAt || Date.now())\n\n return {\n title: doc.filename || id.slice(0, 12),\n id: id,\n playbackId: doc.playbackId,\n createdAt: date,\n duration: doc.data?.duration ? formatSeconds(doc.data?.duration) : undefined,\n playback_ids: doc.data?.playback_ids,\n aspect_ratio: doc.data?.aspect_ratio,\n max_stored_resolution: doc.data?.max_stored_resolution,\n max_stored_frame_rate: doc.data?.max_stored_frame_rate,\n text_tracks:\n doc.data?.tracks?.filter((track): track is MuxTextTrack => track.type === 'text') || [],\n }\n}\n","import {useToast} from '@sanity/ui'\nimport {useMemo, useState} from 'react'\nimport {useDocumentStore} from 'sanity'\n\nimport {useClient} from '../../hooks/useClient'\nimport useDocReferences from '../../hooks/useDocReferences'\nimport {useResyncAsset} from '../../hooks/useResyncAsset'\nimport getVideoMetadata from '../../util/getVideoMetadata'\nimport {type VideoAssetDocument} from '../../util/types'\n\ntype VideoDetailsState = 'idle' | 'saving' | 'deleting' | 'closing' | 'resyncing'\n\nexport interface VideoDetailsProps {\n closeDialog: () => void\n asset: VideoAssetDocument & {autoPlay?: boolean}\n}\n\nexport default function useVideoDetails(props: VideoDetailsProps) {\n const documentStore = useDocumentStore()\n const toast = useToast()\n const client = useClient()\n\n const [references, referencesLoading] = useDocReferences(\n useMemo(() => ({documentStore, id: props.asset._id}), [documentStore, props.asset._id]),\n )\n\n const [originalAsset, setOriginalAsset] = useState(() => props.asset)\n const [filename, setFilename] = useState(props.asset.filename)\n const modified = filename !== originalAsset.filename\n\n const displayInfo = getVideoMetadata({...props.asset, filename})\n\n const [state, setState] = useState<VideoDetailsState>('idle')\n\n const {resyncAsset, isResyncing} = useResyncAsset({showToast: true})\n\n async function handleResync() {\n if (state !== 'idle') return\n setState('resyncing')\n await resyncAsset(props.asset)\n setState('idle')\n }\n\n function handleClose() {\n if (state !== 'idle') return\n\n if (modified) {\n setState('closing')\n return\n }\n\n props.closeDialog()\n }\n\n function confirmClose(shouldClose: boolean) {\n if (state !== 'closing') return\n\n if (shouldClose) props.closeDialog()\n\n setState('idle')\n }\n\n async function saveChanges() {\n if (state !== 'idle') return\n setState('saving')\n\n try {\n await client.patch(props.asset._id).set({filename}).commit()\n setOriginalAsset((prev) => ({...prev, filename}))\n toast.push({\n title: 'Video title updated',\n description: `New title: ${filename}`,\n status: 'success',\n })\n props.closeDialog()\n } catch (error) {\n toast.push({\n title: 'Failed updating file name',\n status: 'error',\n description: typeof error === 'string' ? error : 'Please try again',\n })\n setFilename(originalAsset.filename)\n }\n\n setState('idle')\n }\n\n return {\n references,\n referencesLoading,\n modified,\n filename,\n setFilename,\n displayInfo,\n state,\n setState,\n handleClose,\n confirmClose,\n saveChanges,\n handleResync,\n isResyncing,\n }\n}\n","import {CalendarIcon} from '@sanity/icons/Calendar'\nimport {CheckmarkIcon} from '@sanity/icons/Checkmark'\nimport {ClockIcon} from '@sanity/icons/Clock'\nimport {CropIcon} from '@sanity/icons/Crop'\nimport {EditIcon} from '@sanity/icons/Edit'\nimport {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {RevertIcon} from '@sanity/icons/Revert'\nimport {SearchIcon} from '@sanity/icons/Search'\nimport {SyncIcon} from '@sanity/icons/Sync'\nimport {TagIcon} from '@sanity/icons/Tag'\nimport {TrashIcon} from '@sanity/icons/Trash'\nimport {\n Button,\n Card,\n Dialog,\n Flex,\n Heading,\n Spinner,\n Stack,\n Tab,\n TabList,\n TabPanel,\n Text,\n TextInput,\n} from '@sanity/ui'\nimport {useEffect, useRef, useState} from 'react'\n\nimport {DIALOGS_Z_INDEX} from '../../util/constants'\nimport type {MuxPlaybackId, MuxTextTrack, PlaybackPolicy} from '../../util/types'\nimport FormField from '../FormField'\nimport IconInfo from '../IconInfo'\nimport {ResolutionIcon} from '../icons/Resolution'\nimport {StopWatchIcon} from '../icons/StopWatch'\nimport Mezzanine from '../Mezzanine'\nimport TextTracksManager from '../TextTracksManager'\nimport VideoPlayer from '../VideoPlayer'\nimport DeleteDialog from './DeleteDialog'\nimport useVideoDetails, {type VideoDetailsProps} from './useVideoDetails'\nimport VideoReferences from './VideoReferences'\n\nconst AssetInput: React.FC<{\n label: string\n description?: string\n placeholder?: string\n value: string\n onInput: (e: React.FormEvent<HTMLInputElement>) => void\n disabled?: boolean\n}> = (props) => (\n <FormField title={props.label} description={props.description} inputId={props.label}>\n <TextInput\n id={props.label}\n value={props.value}\n placeholder={props.placeholder}\n onInput={props.onInput}\n disabled={props.disabled}\n />\n </FormField>\n)\n\nconst VideoDetails: React.FC<VideoDetailsProps> = (props) => {\n const [tab, setTab] = useState<'details' | 'references'>('details')\n const {\n displayInfo,\n filename,\n modified,\n references,\n referencesLoading,\n setFilename,\n state,\n setState,\n handleClose,\n confirmClose,\n saveChanges,\n handleResync,\n isResyncing,\n } = useVideoDetails(props)\n\n const isSaving = state === 'saving'\n\n // Avoid layout shifts in large screens' 2-column dialog by setting their `minHeight` to the container's\n const [containerHeight, setContainerHeight] = useState<number | null>(null)\n const contentsRef = useRef<HTMLDivElement>(null)\n useEffect(() => {\n if (!contentsRef.current || !('getBoundingClientRect' in contentsRef.current)) return\n\n setContainerHeight(contentsRef.current.getBoundingClientRect().height)\n }, [])\n\n return (\n <Dialog\n animate\n header={displayInfo.title}\n zOffset={DIALOGS_Z_INDEX}\n id=\"video-details-dialog\"\n onClose={handleClose}\n onClickOutside={handleClose}\n width={2}\n position=\"fixed\"\n footer={\n <Card padding={3}>\n <Flex justify=\"space-between\" align=\"center\">\n <Flex gap={2}>\n <Button\n icon={TrashIcon}\n fontSize={2}\n padding={3}\n mode=\"bleed\"\n text=\"Delete\"\n tone=\"critical\"\n onClick={() => setState('deleting')}\n disabled={isSaving || isResyncing}\n />\n <Button\n icon={SyncIcon}\n fontSize={2}\n padding={3}\n mode=\"bleed\"\n text=\"Resync\"\n tone=\"primary\"\n onClick={handleResync}\n disabled={isSaving || isResyncing}\n iconRight={isResyncing && Spinner}\n />\n </Flex>\n {modified && (\n <Button\n icon={CheckmarkIcon}\n fontSize={2}\n padding={3}\n mode=\"ghost\"\n text=\"Save and close\"\n tone=\"positive\"\n onClick={saveChanges}\n iconRight={isSaving && Spinner}\n disabled={isSaving || isResyncing}\n />\n )}\n </Flex>\n </Card>\n }\n >\n {/* DELETION DIALOG */}\n {state === 'deleting' && (\n <DeleteDialog\n asset={props.asset}\n cancelDelete={() => setState('idle')}\n referencesLoading={referencesLoading}\n references={references}\n succeededDeleting={() => {\n props.closeDialog()\n }}\n />\n )}\n\n {/* CONFIRM CLOSING DIALOG */}\n {state === 'closing' && (\n <Dialog\n animate\n header={'You have unsaved changes'}\n zOffset={DIALOGS_Z_INDEX}\n id=\"closing-video-details-dialog\"\n onClose={() => confirmClose(false)}\n onClickOutside={() => confirmClose(false)}\n width={1}\n position=\"fixed\"\n footer={\n <Card padding={3}>\n <Flex justify=\"space-between\" align=\"center\">\n <Button\n icon={ErrorOutlineIcon}\n fontSize={2}\n padding={3}\n text=\"Discard changes\"\n tone=\"critical\"\n onClick={() => confirmClose(true)}\n />\n {modified && (\n <Button\n icon={RevertIcon}\n fontSize={2}\n padding={3}\n mode=\"ghost\"\n text=\"Keep editing\"\n tone=\"primary\"\n onClick={() => confirmClose(false)}\n />\n )}\n </Flex>\n </Card>\n }\n >\n <Card padding={5}>\n <Stack style={{textAlign: 'center'}} space={3}>\n <Heading size={2}>Unsaved changes will be lost</Heading>\n <Text size={2}>Are you sure you want to discard them?</Text>\n </Stack>\n </Card>\n </Dialog>\n )}\n <Card\n padding={4}\n sizing=\"border\"\n style={{\n containerType: 'inline-size',\n }}\n >\n <Flex\n sizing=\"border\"\n gap={4}\n direction={['column', 'column', 'row']}\n align=\"flex-start\"\n ref={contentsRef}\n style={\n typeof containerHeight === 'number'\n ? {\n minHeight: containerHeight,\n }\n : undefined\n }\n >\n <Stack space={4} flex={1} sizing=\"border\">\n <VideoPlayer asset={props.asset} autoPlay={props.asset.autoPlay || false} />\n {tab === 'details' && (\n <>\n <TextTracksManager\n asset={props.asset}\n iconOnly\n collapseTracks\n tracks={\n displayInfo?.text_tracks ||\n props.asset.data?.tracks?.filter(\n (track): track is MuxTextTrack => track.type === 'text',\n ) ||\n []\n }\n />\n <Mezzanine asset={props.asset} />\n </>\n )}\n </Stack>\n <Stack space={4} flex={1} sizing=\"border\">\n <TabList space={2}>\n <Tab\n aria-controls=\"details-panel\"\n icon={EditIcon}\n id=\"details-tab\"\n label=\"Details\"\n onClick={() => setTab('details')}\n selected={tab === 'details'}\n />\n <Tab\n aria-controls=\"references-panel\"\n icon={SearchIcon}\n id=\"references-tab\"\n label={`Used by ${references ? `(${references.length})` : ''}`}\n onClick={() => setTab('references')}\n selected={tab === 'references'}\n />\n </TabList>\n <TabPanel\n aria-labelledby=\"details-tab\"\n id=\"details-panel\"\n hidden={tab !== 'details'}\n style={{wordBreak: 'break-word'}}\n >\n <Stack space={4}>\n <AssetInput\n label=\"Video title or file name\"\n description=\"Not visible to users. Useful for finding videos later.\"\n value={filename || ''}\n onInput={(e) => setFilename(e.currentTarget.value)}\n disabled={state !== 'idle'}\n />\n <Stack space={3}>\n {displayInfo?.duration && (\n <IconInfo\n text={`Duration: ${displayInfo.duration}`}\n icon={ClockIcon}\n size={2}\n />\n )}\n {displayInfo?.max_stored_resolution && (\n <IconInfo\n text={`Max Resolution: ${displayInfo.max_stored_resolution}`}\n icon={ResolutionIcon}\n size={2}\n />\n )}\n {displayInfo?.max_stored_frame_rate && (\n <IconInfo\n text={`Frame rate: ${displayInfo.max_stored_frame_rate}`}\n icon={StopWatchIcon}\n size={2}\n />\n )}\n {displayInfo?.aspect_ratio && (\n <IconInfo\n text={`Aspect Ratio: ${displayInfo.aspect_ratio}`}\n icon={CropIcon}\n size={2}\n />\n )}\n <IconInfo\n text={`Uploaded on: ${displayInfo.createdAt.toLocaleDateString('en', {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n hour12: true,\n })}`}\n icon={CalendarIcon}\n size={2}\n />\n <IconInfo text={`Mux ID: \\n${displayInfo.id}`} icon={TagIcon} size={2} />\n <PlaybackIds playback_ids={displayInfo.playback_ids} />\n </Stack>\n </Stack>\n </TabPanel>\n <TabPanel\n aria-labelledby=\"references-tab\"\n id=\"references-panel\"\n hidden={tab !== 'references'}\n >\n <VideoReferences references={references} isLoaded={!referencesLoading} />\n </TabPanel>\n </Stack>\n </Flex>\n </Card>\n </Dialog>\n )\n}\n\nconst PlaybackIds = ({playback_ids}: {playback_ids?: MuxPlaybackId[]}) => {\n if (playback_ids) {\n return playback_ids.map((entry) => (\n <IconInfo\n key={entry.id}\n text={`Playback ID [${policyToText(entry.policy)}]: ${entry.id}`}\n icon={TagIcon}\n size={2}\n />\n ))\n }\n return <IconInfo text={'No Playback ID'} icon={TagIcon} size={2} />\n}\n\nconst policyToText = (policy: PlaybackPolicy) => {\n switch (policy) {\n case 'drm':\n return 'DRM'\n case 'signed':\n return 'Signed'\n case 'public':\n return 'Public'\n default:\n return policy\n }\n}\nexport default VideoDetails\n","import {CalendarIcon} from '@sanity/icons/Calendar'\nimport {ClockIcon} from '@sanity/icons/Clock'\nimport {TagIcon} from '@sanity/icons/Tag'\nimport {Inline, Stack, Text} from '@sanity/ui'\n\nimport getVideoMetadata from '../util/getVideoMetadata'\nimport type {VideoAssetDocument} from '../util/types'\nimport IconInfo from './IconInfo'\n\nconst VideoMetadata = (props: {asset: VideoAssetDocument}) => {\n if (!props.asset) {\n return null\n }\n\n const displayInfo = getVideoMetadata(props.asset)\n return (\n <Stack space={2}>\n {displayInfo.title && (\n <Text\n size={1}\n weight=\"semibold\"\n style={{\n wordWrap: 'break-word',\n }}\n >\n {displayInfo.title}\n </Text>\n )}\n <Inline space={3}>\n {displayInfo?.duration && (\n <IconInfo text={displayInfo.duration} icon={ClockIcon} size={1} muted />\n )}\n <IconInfo\n text={displayInfo.createdAt.toISOString().split('T')[0]!}\n icon={CalendarIcon}\n size={1}\n muted\n />\n {displayInfo.title != displayInfo.id.slice(0, 12) && (\n <IconInfo text={displayInfo.id.slice(0, 12)} icon={TagIcon} size={1} muted />\n )}\n </Inline>\n </Stack>\n )\n}\n\nexport default VideoMetadata\n","import {CheckmarkIcon} from '@sanity/icons/Checkmark'\nimport {EditIcon} from '@sanity/icons/Edit'\nimport {LockIcon} from '@sanity/icons/Lock'\nimport {PlayIcon} from '@sanity/icons/Play'\nimport {Button, Card, Stack, Text, Tooltip} from '@sanity/ui'\nimport {useCallback, useState} from 'react'\nimport {styled} from 'styled-components'\n\nimport {DRMWarningDialog, useDrmPlaybackWarningContext} from '../context/DrmPlaybackWarningContext'\nimport {THUMBNAIL_ASPECT_RATIO} from '../util/constants'\nimport {getPlaybackPolicy} from '../util/getPlaybackPolicy'\nimport {type VideoAssetDocument} from '../util/types'\nimport IconInfo from './IconInfo'\nimport {AudioIcon} from './icons/Audio'\nimport VideoMetadata from './VideoMetadata'\nimport VideoPlayer, {assetIsAudio} from './VideoPlayer'\nimport VideoThumbnail from './VideoThumbnail'\n\nconst PlayButton = styled.button`\n display: block;\n padding: 0;\n margin: 0;\n border: none;\n border-radius: 0.1875rem;\n position: relative;\n cursor: pointer;\n\n &::after {\n content: '';\n background: var(--card-fg-color);\n opacity: 0;\n display: block;\n position: absolute;\n inset: 0;\n z-index: 10;\n transition: 0.15s ease-out;\n border-radius: inherit;\n }\n\n > div[data-play] {\n z-index: 11;\n opacity: 0;\n transition: 0.15s 0.05s ease-out;\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n color: var(--card-fg-color);\n background: var(--card-bg-color);\n width: auto;\n height: 30%;\n aspect-ratio: 1;\n border-radius: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n box-sizing: border-box;\n > svg {\n display: block;\n width: 70%;\n height: auto;\n // Visual balance to center-align the icon\n transform: translateX(5%);\n }\n }\n\n &:hover,\n &:focus {\n &::after {\n opacity: 0.3;\n }\n > div[data-play] {\n opacity: 1;\n }\n }\n`\n\ntype RenderState = 'render-video' | 'pre-render-warn' | false\n\nexport default function VideoInBrowser({\n onSelect,\n onEdit,\n asset,\n}: {\n onSelect?: (asset: VideoAssetDocument) => void\n onEdit?: (asset: VideoAssetDocument) => void\n asset: VideoAssetDocument\n}) {\n const [renderVideo, setRenderVideo] = useState<RenderState>(false)\n const select = useCallback(() => onSelect?.(asset), [onSelect, asset])\n const edit = useCallback(() => onEdit?.(asset), [onEdit, asset])\n const {hasShownWarning} = useDrmPlaybackWarningContext()\n\n if (!asset) {\n return null\n }\n\n const playbackPolicy = getPlaybackPolicy(asset)\n const onClickPlay = () => {\n if (playbackPolicy?.policy === 'drm' && !hasShownWarning) {\n setRenderVideo('pre-render-warn')\n } else {\n setRenderVideo('render-video')\n }\n }\n return (\n <Card\n border\n padding={2}\n sizing=\"border\"\n radius={2}\n style={{\n position: 'relative',\n }}\n >\n {playbackPolicy?.policy === 'signed' && (\n <Tooltip\n animate\n content={\n <Card padding={2} radius={2}>\n <IconInfo icon={LockIcon} text=\"Signed playback policy\" size={2} />\n </Card>\n }\n placement=\"right\"\n fallbackPlacements={['top', 'bottom']}\n portal\n >\n <Card\n tone=\"caution\"\n style={{\n borderRadius: '100%',\n position: 'absolute',\n left: '1em',\n top: '1em',\n zIndex: 11,\n }}\n padding={2}\n border\n >\n <Text muted size={1}>\n <LockIcon />\n </Text>\n </Card>\n </Tooltip>\n )}\n {playbackPolicy?.policy === 'drm' && (\n <Tooltip\n animate\n content={\n <Card padding={2} radius={2}>\n <IconInfo icon={LockIcon} text=\"DRM playback policy\" size={2} />\n </Card>\n }\n placement=\"right\"\n fallbackPlacements={['top', 'bottom']}\n portal\n >\n <Card\n tone=\"caution\"\n style={{\n borderRadius: '0.25rem',\n position: 'absolute',\n left: '1em',\n top: '1em',\n zIndex: 11,\n }}\n padding={2}\n border\n >\n <Text muted size={1} weight=\"semibold\" style={{color: 'var(--card-icon-color)'}}>\n DRM\n </Text>\n </Card>\n </Tooltip>\n )}\n <Stack\n space={3}\n height=\"fill\"\n style={{\n gridTemplateRows: 'min-content min-content 1fr',\n }}\n >\n {renderVideo === 'pre-render-warn' && (\n <DRMWarningDialog\n onClose={() => {\n setRenderVideo('render-video')\n }}\n />\n )}\n {renderVideo === 'render-video' ? (\n <VideoPlayer asset={asset} autoPlay forceAspectRatio={THUMBNAIL_ASPECT_RATIO} />\n ) : (\n <PlayButton onClick={onClickPlay}>\n <div data-play>\n <PlayIcon />\n </div>\n {assetIsAudio(asset) ? (\n <div\n style={{\n aspectRatio: THUMBNAIL_ASPECT_RATIO,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <AudioIcon width=\"3em\" height=\"3em\" />\n </div>\n ) : (\n <VideoThumbnail asset={asset} />\n )}\n </PlayButton>\n )}\n <VideoMetadata asset={asset} />\n <div\n style={{\n display: 'flex',\n width: '100%',\n alignItems: 'flex-end',\n justifyContent: 'flex-start',\n gap: '.35rem',\n }}\n >\n {onSelect && (\n <Button\n icon={CheckmarkIcon}\n fontSize={2}\n padding={2}\n mode=\"ghost\"\n text=\"Select\"\n style={{flex: 1}}\n tone=\"positive\"\n onClick={select}\n />\n )}\n <Button\n icon={EditIcon}\n fontSize={2}\n padding={2}\n mode=\"ghost\"\n text=\"Details\"\n style={{flex: 1}}\n onClick={edit}\n />\n </div>\n </Stack>\n </Card>\n )\n}\n","import {SearchIcon} from '@sanity/icons/Search'\nimport {Card, Flex, Grid, Inline, Label, Stack, Text, TextInput} from '@sanity/ui'\nimport {useMemo, useState} from 'react'\n\nimport {DrmPlaybackWarningContextProvider} from '../context/DrmPlaybackWarningContext'\nimport useAssets from '../hooks/useAssets'\nimport type {PluginConfig, VideoAssetDocument} from '../util/types'\nimport ConfigureApi from './ConfigureApi'\nimport ImportVideosFromMux from './ImportVideosFromMux'\nimport PageSelector from './PageSelector'\nimport ResyncMetadata from './ResyncMetadata'\nimport {SelectSortOptions} from './SelectSortOptions'\nimport SpinnerBox from './SpinnerBox'\nimport type {VideoDetailsProps} from './VideoDetails/useVideoDetails'\nimport VideoDetails from './VideoDetails/VideoDetails'\nimport VideoInBrowser from './VideoInBrowser'\n\nexport interface VideosBrowserProps {\n config: PluginConfig\n onSelect?: (asset: VideoAssetDocument) => void\n}\n\nexport default function VideosBrowser({onSelect, config}: VideosBrowserProps) {\n const {assets, isLoading, searchQuery, setSearchQuery, setSort, sort} = useAssets()\n const [page, setPage] = useState<number>(0)\n const pageLimit = 20\n const pageTotal = Math.floor(assets.length / pageLimit) + 1\n const [editedAsset, setEditedAsset] = useState<VideoDetailsProps['asset'] | null>(null)\n const freshEditedAsset = useMemo(\n () => assets.find((a) => a._id === editedAsset?._id) || editedAsset,\n [editedAsset, assets],\n )\n\n const pageStart = page * pageLimit\n const pageEnd = pageStart + pageLimit\n\n const placement = onSelect ? 'input' : 'tool'\n return (\n <DrmPlaybackWarningContextProvider config={config}>\n <Stack padding={4} space={4} style={{minHeight: '50vh'}}>\n <Flex justify=\"space-between\" align=\"center\">\n <Flex align=\"center\" gap={3}>\n <TextInput\n value={searchQuery}\n icon={SearchIcon}\n onInput={(e: React.FormEvent<HTMLInputElement>) =>\n setSearchQuery(e.currentTarget.value)\n }\n placeholder=\"Search videos\"\n />\n <SelectSortOptions setSort={setSort} sort={sort} />\n <PageSelector page={page} setPage={setPage} total={pageTotal} />\n </Flex>\n {placement === 'tool' && (\n <Inline space={2}>\n <ImportVideosFromMux />\n <ResyncMetadata />\n <ConfigureApi />\n </Inline>\n )}\n </Flex>\n <Stack space={3}>\n {assets?.length > 0 && (\n <Label muted>\n {assets.length} video{assets.length > 1 ? 's' : null}{' '}\n {searchQuery ? `matching \"${searchQuery}\"` : 'found'}\n </Label>\n )}\n <Grid\n gap={2}\n style={{\n gridTemplateColumns: 'repeat(auto-fill, minmax(250px, 1fr))',\n }}\n >\n {assets.slice(pageStart, pageEnd).map((asset) => (\n <VideoInBrowser\n key={asset._id}\n asset={asset}\n onEdit={setEditedAsset}\n onSelect={onSelect}\n />\n ))}\n </Grid>\n </Stack>\n {isLoading && <SpinnerBox />}\n\n {!isLoading && assets.length === 0 && (\n <Card marginY={4} paddingX={4} paddingY={6} border radius={2} tone=\"transparent\">\n <Text align=\"center\" muted size={3}>\n {searchQuery ? `No videos found for \"${searchQuery}\"` : 'No videos in this dataset'}\n </Text>\n </Card>\n )}\n </Stack>\n {freshEditedAsset && (\n <VideoDetails closeDialog={() => setEditedAsset(null)} asset={freshEditedAsset} />\n )}\n </DrmPlaybackWarningContextProvider>\n )\n}\n","import type {Tool} from 'sanity'\n\nimport type {PluginConfig} from '../util/types'\nimport ToolIcon from './icons/ToolIcon'\nimport VideosBrowser from './VideosBrowser'\n\nconst StudioTool: React.FC<PluginConfig> = (config) => {\n return <VideosBrowser config={config} />\n}\n\nexport const DEFAULT_TOOL_CONFIG = {\n icon: ToolIcon,\n title: 'Videos',\n}\n\nexport default function createStudioTool(config: PluginConfig): Tool {\n const toolConfig = typeof config.tool === 'object' ? config.tool : DEFAULT_TOOL_CONFIG\n return {\n name: 'mux',\n icon: toolConfig.icon || DEFAULT_TOOL_CONFIG.icon,\n title: toolConfig.title || DEFAULT_TOOL_CONFIG.title,\n component: (props: any) => <StudioTool {...config} {...props} />,\n }\n}\n","import {useCurrentUser} from 'sanity'\n\nimport {type PluginConfig} from '../util/types'\n\nexport const useAccessControl = (config: PluginConfig) => {\n const user = useCurrentUser()\n\n const hasConfigAccess =\n !config?.allowedRolesForConfiguration?.length ||\n user?.roles?.some((role) => config.allowedRolesForConfiguration.includes(role.name))\n\n return {hasConfigAccess}\n}\n","import {isReference} from 'sanity'\nimport {useDocumentValues} from 'sanity'\n\nimport type {Reference, VideoAssetDocument} from '../util/types'\n\nconst path = ['assetId', 'data', 'playbackId', 'status', 'thumbTime', 'filename']\nexport const useAssetDocumentValues = (asset: Reference | null | undefined) =>\n useDocumentValues<VideoAssetDocument | null | undefined>(\n isReference(asset) ? asset._ref : '',\n path,\n )\n","import {useMemo, useRef} from 'react'\nimport {useDataset, useProjectId} from 'sanity'\nimport useSWR from 'swr'\n\nimport {useClient} from '../hooks/useClient'\nimport {addKeysToMuxData} from '../util/addKeysToMuxData'\nimport {PLUGIN_VERSION_QUERY} from '../util/pluginVersion'\nimport type {MuxAsset, VideoAssetDocument} from '../util/types'\n\n// Poll MUX if it's preparing the main document or its own static renditions\nexport const useMuxPolling = (asset?: VideoAssetDocument) => {\n const client = useClient()\n const projectId = useProjectId()\n const dataset = useDataset()\n const isPreparingStaticRenditions = useMemo(() => {\n // Legacy: If static_renditions has a status field, it was created with mp4_support (deprecated)\n // We don't process this old format, just return false\n // Note: 'disabled' status is valid in the new format when no renditions were requested\n if (\n asset?.data?.static_renditions?.status &&\n asset?.data?.static_renditions?.status !== 'disabled'\n ) {\n return false\n }\n\n const files = asset?.data?.static_renditions?.files\n if (!files || files.length === 0) {\n return false\n }\n return files.some((file) => file.status === 'preparing')\n }, [asset?.data?.static_renditions?.status, asset?.data?.static_renditions?.files])\n\n const shouldFetch = useMemo(\n () => !!asset?.assetId && (asset?.status === 'preparing' || isPreparingStaticRenditions),\n [asset?.assetId, asset?.status, isPreparingStaticRenditions],\n )\n // Only log the first failure of a streak so a persistent error doesn't flood\n // the console on every interval.\n const errorLoggedRef = useRef(false)\n return useSWR(\n shouldFetch ? `/${projectId}/addons/mux/assets/${dataset}/data/${asset?.assetId}` : null,\n async () => {\n try {\n const {data} = await client.request<{data: MuxAsset}>({\n url: `/addons/mux/assets/${dataset}/data/${asset!.assetId}`,\n withCredentials: true,\n method: 'GET',\n query: PLUGIN_VERSION_QUERY,\n })\n if (!asset?._id || !data) return\n await client\n .patch(asset._id)\n .set({status: data.status, data: addKeysToMuxData(data)})\n .commit({returnDocuments: false})\n errorLoggedRef.current = false\n } catch (error) {\n // Input re-throws `poll.error`, so a background polling failure would\n // crash the whole field. Swallow it instead.\n if (!errorLoggedRef.current) {\n errorLoggedRef.current = true\n console.error('[sanity-plugin-mux-input] Mux polling failed', {\n assetId: asset?.assetId,\n documentId: asset?._id,\n error,\n })\n }\n }\n },\n {refreshInterval: 2000, refreshWhenHidden: true, dedupingInterval: 1000},\n )\n}\n","/* eslint-disable no-console */\nimport {Button, Card, Flex, Grid, Heading, Inline, Text, useToast} from '@sanity/ui'\nimport {memo, useCallback, useRef} from 'react'\nimport scrollIntoView from 'scroll-into-view-if-needed'\nimport {clear} from 'suspend-react'\nimport {useErrorBoundary} from 'use-error-boundary'\n\nimport {name} from '../util/constants'\nimport {type MuxInputProps} from '../util/types'\n\nexport interface Props extends Pick<MuxInputProps, 'schemaType'> {\n children: React.ReactNode\n}\nfunction ErrorBoundaryCard(props: Props) {\n const {children, schemaType} = props\n const {push: pushToast} = useToast()\n const errorRef = useRef(null)\n const {ErrorBoundary, didCatch, error, reset} = useErrorBoundary({\n // oxlint-disable-next-line no-unstable-nested-components\n onDidCatch: (err, errorInfo) => {\n console.group(err.toString())\n console.groupCollapsed('console.error')\n console.error(err)\n console.groupEnd()\n if (err.stack) {\n console.groupCollapsed('error.stack')\n console.log(err.stack)\n console.groupEnd()\n }\n if (errorInfo?.componentStack) {\n console.groupCollapsed('errorInfo.componentStack')\n console.log(errorInfo.componentStack)\n console.groupEnd()\n }\n console.groupEnd()\n pushToast({\n status: 'error',\n title: 'Plugin crashed',\n description: (\n <Flex align=\"center\">\n <Inline space={1}>\n An error happened while rendering\n <Button\n padding={1}\n fontSize={1}\n style={{transform: 'translateY(1px)'}}\n mode=\"ghost\"\n text={schemaType.title}\n onClick={() => {\n if (errorRef.current) {\n scrollIntoView(errorRef.current, {\n behavior: 'smooth',\n scrollMode: 'if-needed',\n block: 'center',\n })\n }\n }}\n />\n </Inline>\n </Flex>\n ),\n })\n },\n })\n const handleRetry = useCallback(() => {\n // Purge request cache before retrying, otherwise the cached errors will rethrow\n clear([name])\n\n reset()\n }, [reset])\n\n if (didCatch) {\n return (\n <Card ref={errorRef} paddingX={[2, 3, 4, 4]} height=\"fill\" shadow={1} overflow=\"auto\">\n <Flex justify=\"flex-start\" align=\"center\" height=\"fill\">\n <Grid columns={1} gap={[2, 3, 4, 4]}>\n <Heading as=\"h1\">\n The <code>{name}</code> plugin crashed\n </Heading>\n {error?.message && (\n <Card padding={3} tone=\"critical\" shadow={1} radius={2}>\n <Text>{error.message}</Text>\n </Card>\n )}\n <Inline>\n <Button onClick={handleRetry} text=\"Retry\" />\n </Inline>\n </Grid>\n </Flex>\n </Card>\n )\n }\n\n return <ErrorBoundary>{children}</ErrorBoundary>\n}\n\nexport default memo(ErrorBoundaryCard)\n","import {Box, Card, Flex, Spinner, Text} from '@sanity/ui'\n\nexport const InputFallback = () => {\n return (\n <div style={{padding: 1}}>\n <Card\n shadow={1}\n sizing=\"border\"\n style={{aspectRatio: '16/9', width: '100%', borderRadius: '1px'}}\n >\n <Flex align=\"center\" direction=\"column\" height=\"fill\" justify=\"center\">\n <Spinner muted />\n <Box marginTop={3}>\n <Text align=\"center\" muted size={1}>\n Loading…\n </Text>\n </Box>\n </Flex>\n </Card>\n </div>\n )\n}\n","import {PlugIcon} from '@sanity/icons/Plug'\nimport {Button, Card, Flex, Grid, Heading, Inline, Text} from '@sanity/ui'\nimport {useCallback} from 'react'\n\nimport {useAccessControl} from '../hooks/useAccessControl'\nimport type {SetDialogState} from '../hooks/useDialogState'\nimport {type PluginConfig} from '../util/types'\nimport MuxLogo from './MuxLogo'\n\ninterface OnboardProps {\n setDialogState: SetDialogState\n config: PluginConfig\n}\n\nexport default function Onboard(props: OnboardProps) {\n const {setDialogState} = props\n const handleOpen = useCallback(() => setDialogState('secrets'), [setDialogState])\n const {hasConfigAccess} = useAccessControl(props.config)\n\n return (\n <>\n <div style={{padding: 2}}>\n <Card\n display=\"flex\"\n sizing=\"border\"\n style={{\n aspectRatio: '16/9',\n width: '100%',\n boxShadow: 'var(--card-bg-color) 0 0 0 2px',\n }}\n paddingX={[2, 3, 4, 4]}\n radius={1}\n tone=\"transparent\"\n >\n <Flex justify=\"flex-start\" align=\"center\">\n <Grid columns={1} gap={[2, 3, 4, 4]}>\n <Inline paddingY={1}>\n <div style={{height: '32px'}}>\n <MuxLogo />\n </div>\n </Inline>\n <Inline paddingY={1}>\n <Heading size={[0, 1, 2, 2]}>\n Upload and preview videos directly from your studio.\n </Heading>\n </Inline>\n <Inline paddingY={1}>\n {hasConfigAccess ? (\n <Button mode=\"ghost\" icon={PlugIcon} text=\"Configure API\" onClick={handleOpen} />\n ) : (\n <Card padding={[3, 3, 3]} radius={2} shadow={1} tone=\"critical\">\n <Text>\n You do not have access to configure the Mux API. Please contact your\n administrator.\n </Text>\n </Card>\n )}\n </Inline>\n </Grid>\n </Flex>\n </Card>\n </div>\n </>\n )\n}\n","import {UpChunk} from '@mux/upchunk'\nimport {Observable} from 'rxjs'\n\nexport function createUpChunkObservable(uuid: string, uploadUrl: string, source: File) {\n return new Observable<\n | {type: 'pause' | 'resume'; id: string}\n | {type: 'success'; id: string}\n | {type: 'progress'; percent: number}\n >((subscriber) => {\n const upchunk = UpChunk.createUpload({\n endpoint: uploadUrl,\n file: source,\n dynamicChunkSize: true, // changes the chunk size based on network speeds\n })\n\n const successHandler = () => {\n subscriber.next({\n type: 'success',\n id: uuid,\n })\n subscriber.complete()\n }\n\n const errorHandler = (data: CustomEvent) => subscriber.error(new Error(data.detail.message))\n\n const progressHandler = (data: CustomEvent) => {\n return subscriber.next({type: 'progress', percent: data.detail})\n }\n\n const offlineHandler = () => {\n upchunk.pause()\n subscriber.next({\n type: 'pause',\n id: uuid,\n })\n }\n\n const onlineHandler = () => {\n upchunk.resume()\n subscriber.next({\n type: 'resume',\n id: uuid,\n })\n }\n\n upchunk.on('success', successHandler)\n upchunk.on('error', errorHandler)\n upchunk.on('progress', progressHandler)\n upchunk.on('offline', offlineHandler)\n upchunk.on('online', onlineHandler)\n\n return () => upchunk.abort()\n })\n}\n","/**\n * Format Google Drive share links as Google Drive export links.\n * Supported formats:\n * - https://drive.google.com/uc?id=<ID>...\n * - https://drive.google.com/open?id=<ID>...\n * - https://drive.google.com/file/d/<ID>...\n * - https://drive.google.com/folder/<ID>...\n *\n * @param url Google Drive share link to format.\n * @returns Google Drive export link (URL passthrough if not share link).\n */\nexport function formatDriveShareLink(url: string): string {\n // Export link formatter.\n const formatExportLink = (id: string) => {\n return `https://drive.google.com/uc?export=download&id=${id}`\n }\n\n // URL formatting.\n try {\n // Parse URL.\n const trimmed = url.trim()\n const parsed = new URL(trimmed)\n\n // Enforce strict host name.\n if (parsed.hostname !== 'drive.google.com') {\n throw new Error('URL is not from Google Drive.')\n }\n\n // Look for ID in search parameters.\n const id = parsed.searchParams.get('id') || ''\n if (id.length) {\n return formatExportLink(id)\n }\n\n // Look for ID in path name.\n const path = parsed.pathname.split('/') || []\n\n // Path is /file/d/<ID>...\n if (path.includes('file') && path.includes('d')) {\n const index =\n path.findIndex((value: string) => {\n return value === 'd'\n }) + 1\n const fileId = path.at(index) || ''\n return formatExportLink(fileId)\n }\n\n // Path is /folder/<ID>...\n if (path.includes('folders')) {\n const index =\n path.findIndex((value: string) => {\n return value === 'folders'\n }) + 1\n const folderId = path.at(index) || ''\n return formatExportLink(folderId)\n }\n\n // URL not recognized.\n throw new Error('URL was not recognized.')\n } catch {\n // URL passthrough by default.\n return url\n }\n}\n","/**\n * Rounds the numeric part of a px string to the nearest integer.\n * Returns undefined if the value is not a valid px string or not a finite number.\n * Avoids sending 0px (and JS -0); snaps to ±1 instead.\n */\nexport function roundPxString(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.endsWith('px')) return undefined\n const n = Number(trimmed.slice(0, -2))\n if (!Number.isFinite(n)) return undefined\n let rounded = Math.round(n)\n // Avoid sending 0px (and JS -0); keep sign when negative.\n if (rounded === 0) rounded = n < 0 ? -1 : 1\n return `${rounded}px`\n}\n","import {uuid as generateUuid} from '@sanity/uuid'\nimport {concat, defer, from, type Observable, of, throwError} from 'rxjs'\nimport {catchError, mergeMap, mergeMapTo, switchMap} from 'rxjs/operators'\nimport type {SanityClient} from 'sanity'\n\nimport {createUpChunkObservable} from '../clients/upChunkObservable'\nimport {formatDriveShareLink} from '../util/formatDriveShareLink'\nimport {PLUGIN_VERSION_QUERY} from '../util/pluginVersion'\nimport {roundPxString} from '../util/roundPxString'\nimport type {MuxAsset, MuxNewAssetSettings, WatermarkConfig} from '../util/types'\nimport {getAsset} from './assets'\nimport {testSecretsObservable} from './secrets'\n\nfunction sanitizeOverlaySettingsInPlace(settings: MuxNewAssetSettings) {\n const inputs = settings.input\n if (!inputs) return\n for (const input of inputs) {\n const overlay = (input as {overlay_settings?: Record<string, unknown>}).overlay_settings\n if (!overlay) continue\n\n const hm = roundPxString(overlay['horizontal_margin'])\n const vm = roundPxString(overlay['vertical_margin'])\n const w = roundPxString(overlay['width'])\n\n if (hm) overlay['horizontal_margin'] = hm\n if (vm) overlay['vertical_margin'] = vm\n if (w) overlay['width'] = w\n }\n}\n\nfunction sanitizePxStringsInJson(json: string): string {\n return json.replace(/\"(-?\\d+(?:\\.\\d+)?)px\"/g, (_match, num) => {\n const n = Number(num)\n if (!Number.isFinite(n)) return _match\n let rounded = Math.round(n)\n if (rounded === 0) rounded = n < 0 ? -1 : 1\n return `\"${rounded}px\"`\n })\n}\n\nfunction cancelUpload(client: SanityClient, uuid: string) {\n return client.observable.request({\n url: `/addons/mux/uploads/${client.config().dataset}/${uuid}`,\n withCredentials: true,\n method: 'DELETE',\n query: PLUGIN_VERSION_QUERY,\n })\n}\n\nexport function uploadUrl({\n url,\n settings,\n client,\n}: {\n url: string\n settings: MuxNewAssetSettings\n client: SanityClient\n watermark?: WatermarkConfig\n}) {\n return testUrl(url).pipe(\n switchMap((validUrl) => {\n return concat(\n of({type: 'url' as const, url: validUrl}),\n testSecretsObservable(client).pipe(\n switchMap((json) => {\n if (!json || !json.status) {\n return throwError(new Error('Invalid credentials'))\n }\n const uuid = generateUuid()\n const muxBody = settings\n if (!muxBody.input) muxBody.input = [{type: 'video'}]\n muxBody.input[0]!.url = validUrl\n sanitizeOverlaySettingsInPlace(muxBody)\n\n const query: Record<string, string> = {\n muxBody: sanitizePxStringsInJson(JSON.stringify(muxBody)),\n }\n const filename = validUrl.split('/').slice(-1)[0]\n if (filename) {\n query['filename'] = filename\n }\n\n const dataset = client.config().dataset\n return defer(() =>\n client.observable.request({\n url: `/addons/mux/assets/${dataset}`,\n withCredentials: true,\n method: 'POST',\n headers: {\n 'MUX-Proxy-UUID': uuid,\n 'Content-Type': 'application/json',\n },\n query: {...query, ...PLUGIN_VERSION_QUERY},\n }),\n ).pipe(\n mergeMap((result) => {\n const asset =\n (result && result.results && result.results[0] && result.results[0].document) ||\n null\n\n if (!asset) {\n return throwError(new Error('No asset document returned'))\n }\n return of({type: 'success' as const, id: uuid, asset})\n }),\n )\n }),\n ),\n )\n }),\n )\n}\n\nexport function uploadFile({\n settings,\n client,\n file,\n watermark,\n}: {\n settings: MuxNewAssetSettings\n client: SanityClient\n file: File\n watermark?: WatermarkConfig\n}) {\n return testFile(file).pipe(\n switchMap((fileOptions) => {\n return concat(\n of({type: 'file' as const, file: fileOptions}),\n testSecretsObservable(client).pipe(\n switchMap((json) => {\n if (!json || !json.status) {\n return throwError(() => new Error('Invalid credentials'))\n }\n const uuid = generateUuid()\n const body = settings\n sanitizeOverlaySettingsInPlace(body)\n\n return concat(\n of({type: 'uuid' as const, uuid}),\n defer(() =>\n client.observable.request<{\n sanityAssetId: string\n upload: {\n cors_origin: string\n id: string\n new_asset_settings: MuxNewAssetSettings\n status: 'waiting'\n timeout: number\n url: string\n }\n }>({\n url: `/addons/mux/uploads/${client.config().dataset}`,\n withCredentials: true,\n method: 'POST',\n headers: {\n 'MUX-Proxy-UUID': uuid,\n 'Content-Type': 'application/json',\n },\n body,\n query: PLUGIN_VERSION_QUERY,\n }),\n ).pipe(\n mergeMap((result) => {\n return createUpChunkObservable(uuid, result.upload.url, file).pipe(\n // @TODO type the observable events\n mergeMap((event) => {\n if (event.type !== 'success') {\n return of(event)\n }\n return from(updateAssetDocumentFromUpload(client, uuid, watermark)).pipe(\n mergeMap((doc) => of({...event, asset: doc})),\n )\n }),\n catchError((err) => {\n // Delete asset document\n return cancelUpload(client, uuid).pipe(mergeMapTo(throwError(err)))\n }),\n )\n }),\n ),\n )\n }),\n ),\n )\n }),\n )\n}\n\ntype UploadResponse = {\n data: {\n asset_id: string\n cors_origin: string\n id: string\n new_asset_settings: {\n static_renditions?: {resolution: string}[]\n passthrough: string\n playback_policies: ['public' | 'signed' | 'drm']\n }\n status: string\n timeout: number\n }\n}\nfunction getUpload(client: SanityClient, assetId: string) {\n const {dataset} = client.config()\n return client.request<UploadResponse>({\n url: `/addons/mux/uploads/${dataset}/${assetId}`,\n withCredentials: true,\n method: 'GET',\n query: PLUGIN_VERSION_QUERY,\n })\n}\n\nfunction pollUpload(client: SanityClient, uuid: string): Promise<UploadResponse> {\n const maxTries = 10\n let pollInterval: number\n let tries = 0\n let assetId: string\n let upload: UploadResponse\n return new Promise((resolve, reject) => {\n pollInterval = (setInterval as typeof window.setInterval)(async () => {\n try {\n upload = await getUpload(client, uuid)\n } catch (err) {\n reject(err)\n return\n }\n assetId = upload && upload.data && upload.data.asset_id\n if (assetId) {\n clearInterval(pollInterval)\n resolve(upload)\n }\n if (tries > maxTries) {\n clearInterval(pollInterval)\n reject(new Error('Upload did not finish'))\n }\n tries++\n }, 2000)\n })\n}\n\nasync function updateAssetDocumentFromUpload(\n client: SanityClient,\n uuid: string,\n _watermark?: WatermarkConfig,\n) {\n let upload: UploadResponse\n let asset: {data: MuxAsset}\n try {\n upload = await pollUpload(client, uuid)\n } catch (err) {\n return Promise.reject(err)\n }\n try {\n asset = await getAsset(client, upload.data.asset_id)\n } catch (err) {\n return Promise.reject(err)\n }\n\n const doc = {\n _id: uuid,\n _type: 'mux.videoAsset',\n status: asset.data.status,\n data: asset.data,\n assetId: asset.data.id,\n playbackId: asset.data.playback_ids[0]?.id,\n uploadId: upload.data.id,\n }\n return client.createOrReplace(doc).then(() => {\n return doc\n })\n}\n\nfunction testFile(file: File) {\n if (typeof window !== 'undefined' && file instanceof window.File) {\n const fileOptions = optionsFromFile({}, file)\n return of(fileOptions)\n }\n return throwError(new Error('Invalid file'))\n}\n\nfunction testUrl(url: string): Observable<string> {\n const error = new Error('Invalid URL')\n if (typeof url !== 'string') {\n return throwError(error)\n }\n let formattedUrl = url.trim()\n formattedUrl = formatDriveShareLink(formattedUrl)\n let parsed\n try {\n parsed = new URL(formattedUrl)\n } catch {\n return throwError(error)\n }\n if (parsed && !parsed.protocol.match(/http:|https:/)) {\n return throwError(error)\n }\n return of(formattedUrl)\n}\n\nfunction optionsFromFile(opts: {preserveFilename?: boolean}, file: File) {\n if (typeof window === 'undefined' || !(file instanceof window.File)) {\n return undefined\n }\n return {\n name: opts.preserveFilename === false ? undefined : file.name,\n type: file.type,\n }\n}\n","import type {ServerError} from '@sanity/client'\n\nexport function isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url)\n return parsed && !!parsed.protocol.match(/http:|https:/)\n } catch {\n return false\n }\n}\n\n/**\n * We consider a server error one with status code 5XX.\n * Used mainly to handle unknown Proxy issues.\n */\nexport function isServerError(error: Error): error is ServerError {\n return (\n 'statusCode' in error &&\n typeof error.statusCode === 'number' &&\n 500 <= error.statusCode &&\n error.statusCode <= 600\n )\n}\n","/**\n * Utilities for extracting files from dataTransfer in a predictable cross-browser fashion.\n * Also recursively extracts files from a directory\n * Inspired by https://github.com/component/normalized-upload\n */\n\nexport function extractDroppedFiles(dataTransfer: DataTransfer) {\n const files = Array.from(dataTransfer.files || [])\n const items = Array.from(dataTransfer.items || [])\n if (files && files.length > 0) {\n return Promise.resolve(files)\n }\n return normalizeItems(items).then((arr) => arr.flat())\n}\n\nfunction normalizeItems(items: DataTransferItem[]) {\n return Promise.all(\n items.map((item) => {\n // directory\n if (item.kind === 'file' && item.webkitGetAsEntry) {\n let entry: FileSystemEntry | File[] | null\n // Edge throws\n try {\n entry = item.webkitGetAsEntry()\n } catch {\n return [item.getAsFile()]\n }\n if (!entry) {\n return []\n }\n return entry.isDirectory ? walk(entry) : [item.getAsFile()]\n }\n\n // file\n if (item.kind === 'file') {\n const file = item.getAsFile()\n return Promise.resolve(file ? [file] : [])\n }\n\n // others\n return new Promise((resolve) => item.getAsString(resolve)).then((str?: any) =>\n str ? [new File([str], 'unknown.txt', {type: item.type})] : [],\n )\n }),\n )\n}\n\nfunction isFile(entry: FileSystemEntry): entry is FileSystemFileEntry {\n return entry.isFile\n}\nfunction isDirectory(entry: FileSystemEntry): entry is FileSystemDirectoryEntry {\n return entry.isDirectory\n}\n\nfunction walk(entry: FileSystemEntry): any {\n if (isFile(entry)) {\n return new Promise((resolve) => entry.file(resolve)).then((file) => [file])\n }\n\n if (isDirectory(entry)) {\n const dir = entry.createReader()\n return new Promise<any>((resolve) => dir.readEntries(resolve))\n .then((entries: FileSystemEntry[]) => entries.filter((entr) => !entr.name.startsWith('.')))\n .then((entries) => Promise.all(entries.map(walk)).then((arr) => arr.flat()))\n }\n return Promise.resolve([])\n}\n","import {useCallback} from 'react'\nimport {PatchEvent, set, setIfMissing, unset} from 'sanity'\n\nimport type {SetDialogState} from '../hooks/useDialogState'\nimport type {MuxInputProps, PluginConfig, VideoAssetDocument} from '../util/types'\nimport VideosBrowser, {type VideosBrowserProps} from './VideosBrowser'\n\nexport interface Props extends Pick<MuxInputProps, 'onChange'> {\n asset?: VideoAssetDocument | null | undefined\n setDialogState: SetDialogState\n config: PluginConfig\n}\n\nexport default function SelectAssets({\n asset: selectedAsset,\n onChange,\n setDialogState,\n config,\n}: Props) {\n const handleSelect = useCallback<Required<VideosBrowserProps>['onSelect']>(\n (chosenAsset) => {\n if (!chosenAsset?._id) {\n onChange(PatchEvent.from([unset(['asset'])]))\n }\n if (chosenAsset._id !== selectedAsset?._id) {\n onChange(\n PatchEvent.from([\n setIfMissing({asset: {}, _type: 'mux.video'}),\n set({_type: 'reference', _weak: true, _ref: chosenAsset._id}, ['asset']),\n ]),\n )\n }\n setDialogState(false)\n },\n [onChange, setDialogState, selectedAsset],\n )\n\n return <VideosBrowser onSelect={handleSelect} config={config} />\n}\n","import {Dialog} from '@sanity/ui'\nimport {useCallback, useId} from 'react'\nimport {styled} from 'styled-components'\n\nimport type {SetDialogState} from '../hooks/useDialogState'\nimport SelectAsset, {type Props as SelectAssetProps} from './SelectAsset'\n\n/** To prevent Content Layout Shift (CLS), ensure that the dialog always occupies the entire available height. */\nconst StyledDialog = styled(Dialog)`\n > div[data-ui='DialogCard'] > div[data-ui='Card'] {\n height: 100%;\n }\n`\n\nexport default function InputBrowser({\n setDialogState,\n asset,\n onChange,\n config,\n}: Pick<SelectAssetProps, 'onChange' | 'asset' | 'config'> & {\n setDialogState: SetDialogState\n}) {\n const id = `InputBrowser${useId()}`\n const handleClose = useCallback(() => setDialogState(false), [setDialogState])\n return (\n <StyledDialog\n __unstable_autoFocus\n header=\"Select video\"\n id={id}\n onClose={handleClose}\n width={2}\n >\n <SelectAsset\n config={config}\n asset={asset}\n onChange={onChange}\n setDialogState={setDialogState}\n />\n </StyledDialog>\n )\n}\n","import {useCallback} from 'react'\nimport {PatchEvent, unset} from 'sanity'\n\nimport {deleteAssetOnMux} from '../actions/assets'\nimport {useClient} from '../hooks/useClient'\nimport type {MuxInputProps, VideoAssetDocument} from '../util/types'\n\nexport const useCancelUpload = (asset: VideoAssetDocument, onChange: MuxInputProps['onChange']) => {\n const client = useClient()\n return useCallback(() => {\n if (!asset) {\n return\n }\n onChange(PatchEvent.from(unset()))\n if (asset.assetId) {\n void deleteAssetOnMux(client, asset.assetId)\n }\n if (asset._id) {\n void client.delete(asset._id)\n }\n }, [asset, client, onChange])\n}\n","import {styled} from 'styled-components'\n\nexport const TopControls = styled.div`\n position: absolute;\n top: 0;\n right: 0;\n justify-content: flex-end;\n button {\n height: auto;\n }\n`\n","// Lifted from sanity/form/inputs/files/common/UploadProgress\n\nimport {Button, Card, Code, Flex, Inline, Stack, Text} from '@sanity/ui'\nimport {LinearProgress} from 'sanity'\nimport {styled} from 'styled-components'\n\nconst CardWrapper = styled(Card)`\n min-height: 82px;\n box-sizing: border-box;\n`\n\nconst FlexWrapper = styled(Flex)`\n text-overflow: ellipsis;\n overflow: hidden;\n`\n\nconst LeftSection = styled(Stack)`\n position: relative;\n width: 60%;\n`\n\nconst CodeWrapper = styled(Code)`\n position: relative;\n width: 100%;\n\n code {\n overflow: hidden;\n text-overflow: ellipsis;\n position: relative;\n max-width: 200px;\n }\n`\n\nexport const UploadProgress = ({\n progress = 100,\n onCancel,\n filename,\n text = 'Uploading',\n}: {\n progress: number\n filename?: React.ReactNode\n onCancel?: React.MouseEventHandler<HTMLButtonElement>\n text?: React.ReactNode\n}) => {\n // Disable cancel button when upload is 90% or more complete\n // to prevent inconsistency between Mux and Sanity\n const isCancelDisabled = progress >= 90\n\n return (\n <CardWrapper tone=\"primary\" padding={4} border height=\"fill\">\n <FlexWrapper align=\"center\" justify=\"space-between\" height=\"fill\" direction=\"row\" gap={2}>\n <LeftSection>\n <Flex justify=\"center\" gap={[3, 3, 2, 2]} direction={['column', 'column', 'row']}>\n <Text size={1}>\n <Inline space={2}>\n {text}\n <CodeWrapper size={1}>{filename ? filename : '...'}</CodeWrapper>\n </Inline>\n </Text>\n </Flex>\n\n <Card marginTop={3} radius={5} shadow={1}>\n <LinearProgress value={progress} />\n </Card>\n </LeftSection>\n\n {onCancel ? (\n <Button\n fontSize={2}\n text=\"Cancel upload\"\n mode=\"ghost\"\n tone=\"critical\"\n onClick={onCancel}\n disabled={isCancelDisabled}\n />\n ) : null}\n </FlexWrapper>\n </CardWrapper>\n )\n}\n","import {Card, Text} from '@sanity/ui'\nimport {useEffect, useMemo, useRef} from 'react'\n\nimport {useCancelUpload} from '../hooks/useCancelUpload'\nimport type {MuxInputProps, PluginConfig, VideoAssetDocument} from '../util/types'\nimport {TopControls} from './Player.styled'\nimport {UploadProgress} from './UploadProgress'\nimport VideoPlayer from './VideoPlayer'\n\ninterface Props extends Pick<MuxInputProps, 'onChange' | 'readOnly'> {\n buttons?: React.ReactNode\n asset: VideoAssetDocument\n config?: PluginConfig\n}\n\nconst Player = ({asset, buttons, readOnly, onChange, config}: Props) => {\n const isLoading = useMemo<boolean | string>(() => {\n if (asset?.status === 'preparing') {\n return 'Preparing the video'\n }\n if (asset?.status === 'waiting_for_upload') {\n return 'Waiting for upload to start'\n }\n if (asset?.status === 'waiting') {\n return 'Processing upload'\n }\n if (asset?.status === 'ready') {\n return false\n }\n if (typeof asset?.status === 'undefined') {\n return false\n }\n\n return true\n }, [asset])\n // oxlint-disable-next-line react/react-compiler\n const isPreparingStaticRenditions = useMemo<boolean>(() => {\n // Legacy: If static_renditions has a status field, it was created with mp4_support (deprecated)\n // We don't process this old format, just return false\n // Note: 'disabled' status is valid in the new format when no renditions were requested\n if (\n asset?.data?.static_renditions?.status &&\n asset?.data?.static_renditions?.status !== 'disabled'\n ) {\n return false\n }\n\n // Check if any file in static_renditions is still preparing\n const files = asset?.data?.static_renditions?.files\n if (!files || files.length === 0) {\n return false\n }\n return files.some((file) => file.status === 'preparing')\n }, [asset?.data?.static_renditions?.status, asset?.data?.static_renditions?.files])\n const playRef = useRef<HTMLDivElement>(null)\n const muteRef = useRef<HTMLDivElement>(null)\n const handleCancelUpload = useCancelUpload(asset, onChange)\n\n useEffect(() => {\n const style = document.createElement('style')\n style.innerHTML = 'button svg { vertical-align: middle; }'\n\n if (playRef.current?.shadowRoot) {\n playRef.current.shadowRoot.appendChild(style)\n }\n if (muteRef?.current?.shadowRoot) {\n muteRef.current.shadowRoot.appendChild(style.cloneNode(true))\n }\n }, [])\n\n useEffect(() => {\n if (asset?.status === 'errored') {\n handleCancelUpload()\n // @TODO use better error handling\n throw new Error(asset.data?.errors?.messages?.join(' '))\n }\n }, [asset.data?.errors?.messages, asset?.status, handleCancelUpload])\n\n if (!asset || !asset.status) {\n return null\n }\n\n if (isLoading) {\n return (\n <UploadProgress\n progress={100}\n filename={asset?.filename}\n text={(isLoading !== true && isLoading) || 'Waiting for Mux to complete the upload'}\n onCancel={readOnly ? undefined : () => handleCancelUpload()}\n />\n )\n }\n\n return (\n <VideoPlayer asset={asset} hlsConfig={config?.hlsConfig}>\n {buttons && <TopControls slot=\"top-chrome\">{buttons}</TopControls>}\n {isPreparingStaticRenditions && (\n <Card\n padding={2}\n radius={1}\n style={{\n background: 'var(--card-fg-color)',\n position: 'absolute',\n top: '0.5em',\n left: '0.5em',\n }}\n >\n <Text size={1} style={{color: 'var(--card-bg-color)'}}>\n MUX is preparing static renditions, please stand by\n </Text>\n </Card>\n )}\n </VideoPlayer>\n )\n}\n\nexport default Player\n","// todo: get these utils from @sanity/ui instead\nexport function focusRingBorderStyle(border: {color: string; width: number}): string {\n return `inset 0 0 0 ${border.width}px ${border.color}`\n}\n\nexport function focusRingStyle(opts: {\n base?: {bg: string}\n border?: {color: string; width: number}\n focusRing: {offset: number; width: number}\n}): string {\n const {base, border, focusRing} = opts\n const focusRingOutsetWidth = focusRing.offset + focusRing.width\n const focusRingInsetWidth = 0 - focusRing.offset\n const bgColor = base ? base.bg : 'var(--card-bg-color)'\n\n return [\n focusRingInsetWidth > 0 && `inset 0 0 0 ${focusRingInsetWidth}px var(--card-focus-ring-color)`,\n border && focusRingBorderStyle(border),\n focusRingInsetWidth < 0 && `0 0 0 ${0 - focusRingInsetWidth}px ${bgColor}`,\n focusRingOutsetWidth > 0 && `0 0 0 ${focusRingOutsetWidth}px var(--card-focus-ring-color)`,\n ]\n .filter(Boolean)\n .join(',')\n}\n","import {MenuItem} from '@sanity/ui'\nimport {css, styled} from 'styled-components'\n\nimport {focusRingStyle} from './withFocusRing/helpers'\n\nexport const FileButton = styled(MenuItem)(({theme}) => {\n const {focusRing} = theme.sanity\n const base = theme.sanity.color.base\n const border = {width: 1, color: 'var(--card-border-color)'}\n\n return css`\n position: relative;\n\n &:not([data-disabled='true']) {\n &:focus-within {\n box-shadow: ${focusRingStyle({base, border, focusRing})};\n }\n }\n\n & input {\n overflow: hidden;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n position: absolute;\n min-width: 0;\n display: block;\n appearance: none;\n padding: 0;\n margin: 0;\n border: 0;\n opacity: 0;\n }\n `\n})\n","import {Box, type ButtonProps, Flex, Text} from '@sanity/ui'\nimport {isValidElement, useId, useCallback} from 'react'\nimport {isValidElementType} from 'react-is'\n\nimport {FileButton} from './FileInputMenuItem.styled'\n\nexport interface FileInputMenuItemProps extends Omit<ButtonProps, 'onSelect'> {\n accept?: string\n capture?: 'user' | 'environment'\n multiple?: boolean\n onSelect?: (files: File[]) => void\n disabled?: boolean\n}\n\nexport function FileInputMenuItem(\n props: FileInputMenuItemProps &\n Omit<React.HTMLProps<HTMLButtonElement>, 'as' | 'ref' | 'type' | 'value' | 'onSelect'> & {\n ref?: React.Ref<HTMLInputElement>\n },\n) {\n const {\n icon: Icon,\n id: idProp,\n accept,\n capture,\n fontSize,\n multiple,\n onSelect,\n space = 3,\n textAlign,\n text,\n disabled,\n ref,\n ...rest\n } = props\n const idHook = useId()\n const id = idProp || idHook\n\n const handleChange = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n if (onSelect && event.target.files) {\n onSelect(Array.from(event.target.files))\n }\n },\n [onSelect],\n )\n\n const content = (\n <Flex align=\"center\" justify=\"flex-start\">\n {/* Icon */}\n {Icon && (\n <Box marginRight={text ? space : undefined}>\n <Text size={fontSize}>\n {isValidElement(Icon) && Icon}\n {isValidElementType(Icon) && <Icon />}\n </Text>\n </Box>\n )}\n\n {/* Text */}\n {text && (\n <Text align={textAlign} size={fontSize} textOverflow=\"ellipsis\">\n {text}\n </Text>\n )}\n </Flex>\n )\n\n return (\n <FileButton {...rest} htmlFor={id} disabled={disabled} ref={ref}>\n {content}\n\n {/* Visibly hidden input */}\n <input\n data-testid=\"file-button-input\"\n accept={accept}\n capture={capture}\n id={id}\n multiple={multiple}\n onChange={handleChange}\n type=\"file\"\n value=\"\"\n disabled={disabled}\n />\n </FileButton>\n )\n}\n","import {DownloadIcon} from '@sanity/icons/Download'\nimport {EllipsisHorizontalIcon} from '@sanity/icons/EllipsisHorizontal'\nimport {ImageIcon} from '@sanity/icons/Image'\nimport {LockIcon} from '@sanity/icons/Lock'\nimport {PlugIcon} from '@sanity/icons/Plug'\nimport {ResetIcon} from '@sanity/icons/Reset'\nimport {SearchIcon} from '@sanity/icons/Search'\nimport {SyncIcon} from '@sanity/icons/Sync'\nimport {TranslateIcon} from '@sanity/icons/Translate'\nimport {UploadIcon} from '@sanity/icons/Upload'\nimport {\n Box,\n Button,\n Card,\n Inline,\n Label,\n Menu,\n MenuDivider,\n MenuItem,\n Popover,\n Text,\n Tooltip,\n useClickOutsideEvent,\n} from '@sanity/ui'\nimport {memo, useCallback, useEffect, useMemo, useState} from 'react'\nimport {PatchEvent, unset} from 'sanity'\nimport {styled} from 'styled-components'\n\nimport {useAccessControl} from '../hooks/useAccessControl'\nimport {type DialogState, type SetDialogState} from '../hooks/useDialogState'\nimport {useResyncAsset} from '../hooks/useResyncAsset'\nimport {getPlaybackPolicy} from '../util/getPlaybackPolicy'\nimport type {MuxInputProps, PluginConfig, VideoAssetDocument} from '../util/types'\nimport {FileInputMenuItem} from './FileInputMenuItem'\n\nconst LockCard = styled(Card)`\n position: absolute;\n top: 0;\n left: 0;\n opacity: 0.6;\n mix-blend-mode: screen;\n background: transparent;\n`\n\nconst LockButton = styled(Button)`\n background: transparent;\n color: white;\n`\n\n// @TODO: add support for audio type (asset._type) when uploading an audio file so we can hide the thumbnail option.\nconst isVideoAsset = (asset: VideoAssetDocument) => {\n return asset._type === 'mux.videoAsset'\n}\n\nfunction PlayerActionsMenu(\n props: Pick<MuxInputProps, 'onChange' | 'readOnly'> & {\n asset: VideoAssetDocument\n onSelect: (files: File[]) => void\n dialogState: DialogState\n setDialogState: SetDialogState\n config: PluginConfig\n accept: string\n },\n) {\n const {asset, readOnly, dialogState, setDialogState, onChange, onSelect, accept} = props\n const [open, setOpen] = useState(false)\n const [menuElement, setMenuRef] = useState<HTMLDivElement | null>(null)\n const isSigned = useMemo(() => getPlaybackPolicy(asset)?.policy === 'signed', [asset])\n const {hasConfigAccess} = useAccessControl(props.config)\n const {resyncAsset, isResyncing} = useResyncAsset({showToast: true})\n\n const onReset = useCallback(() => onChange(PatchEvent.from(unset([]))), [onChange])\n\n const handleResync = useCallback(async () => {\n setOpen(false)\n await resyncAsset(asset)\n }, [resyncAsset, asset])\n\n useEffect(() => {\n if (open && dialogState) {\n // oxlint-disable-next-line react/react-compiler\n setOpen(false)\n }\n }, [dialogState, open])\n\n useClickOutsideEvent(\n () => setOpen(false),\n () => [menuElement],\n )\n\n return (\n <Inline space={1} padding={2}>\n {isSigned && (\n <Tooltip\n animate\n content={\n <Box padding={2}>\n <Text muted size={1}>\n Signed playback policy\n </Text>\n </Box>\n }\n placement=\"right\"\n portal\n >\n <LockCard radius={2} margin={2} scheme=\"dark\" tone=\"positive\">\n <LockButton icon={LockIcon} mode=\"bleed\" tone=\"positive\" />\n </LockCard>\n </Tooltip>\n )}\n <Popover\n animate\n content={\n <Menu ref={setMenuRef}>\n <Box padding={2}>\n <Label muted size={1}>\n Replace\n </Label>\n </Box>\n <FileInputMenuItem\n accept={accept}\n icon={UploadIcon}\n onSelect={onSelect}\n text=\"Upload\"\n disabled={readOnly}\n fontSize={1}\n />\n <MenuItem\n icon={SearchIcon}\n text=\"Browse\"\n onClick={() => setDialogState('select-video')}\n />\n {isVideoAsset(asset) && (\n <>\n <MenuItem\n icon={ImageIcon}\n text=\"Thumbnail\"\n onClick={() => setDialogState('edit-thumbnail')}\n />\n <MenuItem\n icon={TranslateIcon}\n text=\"Captions\"\n onClick={() => setDialogState('edit-captions')}\n />\n <MenuItem\n icon={SyncIcon}\n text=\"Resync from Mux\"\n onClick={handleResync}\n disabled={readOnly || isResyncing}\n />\n </>\n )}\n <MenuDivider />\n <MenuItem\n icon={DownloadIcon}\n text=\"Mezzanine\"\n onClick={() => setDialogState('mezzanine')}\n />\n <MenuDivider />\n {hasConfigAccess && (\n <>\n <MenuItem\n icon={PlugIcon}\n text=\"Configure API\"\n onClick={() => setDialogState('secrets')}\n />\n <MenuDivider />\n </>\n )}\n <MenuItem\n tone=\"critical\"\n icon={ResetIcon}\n text=\"Clear field\"\n onClick={onReset}\n disabled={readOnly}\n />\n </Menu>\n }\n portal\n open={open}\n >\n <Button\n icon={EllipsisHorizontalIcon}\n mode=\"ghost\"\n fontSize={1}\n onClick={() => {\n setDialogState(false)\n setOpen(true)\n }}\n />\n </Popover>\n </Inline>\n )\n}\n\nexport default memo(PlayerActionsMenu)\n","import {useEffect, useState} from 'react'\n\nimport {type StagedUpload} from '../components/Uploader'\n\nexport function useFetchFileSize(stagedUpload: StagedUpload, maxFileSize?: number) {\n const [fileSize, setFileSize] = useState<number | null>(null)\n const [isLoadingFileSize, setIsLoadingFileSize] = useState(false)\n const [canSkipFileSizeValidation, setCanSkipFileSizeValidation] = useState(false)\n\n useEffect(() => {\n // Fetch URL Upload file size\n if (stagedUpload.type === 'url') {\n // oxlint-disable-next-line react/react-compiler\n setIsLoadingFileSize(false)\n setCanSkipFileSizeValidation(false)\n setFileSize(null)\n const url = stagedUpload.url\n\n // Get file size from URL\n const fetchFileSize = async () => {\n setIsLoadingFileSize(true)\n try {\n const response = await fetch(url, {method: 'HEAD'})\n const contentLength = response.headers.get('content-length')\n const newFileSize = contentLength ? parseInt(contentLength, 10) : null\n\n setIsLoadingFileSize(false)\n if (newFileSize) {\n setFileSize(newFileSize)\n }\n if (newFileSize === null && maxFileSize !== undefined) {\n // Size unknown but size limit is configured - skip file size validation\n setCanSkipFileSizeValidation(true)\n }\n } catch {\n console.warn('Could not validate file size from URL')\n // Skip validation of file size, but still validate duration\n setCanSkipFileSizeValidation(true)\n setIsLoadingFileSize(false)\n }\n }\n\n void fetchFileSize()\n }\n if (stagedUpload.type === 'file') {\n setFileSize(stagedUpload.files[0]!.size)\n }\n }, [maxFileSize, stagedUpload, stagedUpload.type])\n\n return {\n fileSize,\n isLoadingFileSize,\n canSkipFileSizeValidation,\n }\n}\n","import {useEffect, useState} from 'react'\n\nimport {type StagedUpload} from '../components/Uploader'\n\nexport interface VideoAssetMetadata {\n width?: number\n height?: number\n isAudioOnly?: boolean\n duration?: number\n size?: number\n aspectRatio?: number\n}\n\nexport function useMediaMetadata(stagedUpload: StagedUpload) {\n const [videoAssetMetadata, setVideoAssetMetadata] = useState<VideoAssetMetadata | null>(null)\n const [isLoadingMetadata, setIsLoadingMetadata] = useState(false)\n useEffect(() => {\n let videoSrc = null\n // Validate file uploads\n if (stagedUpload.type === 'file') {\n const file = stagedUpload.files[0]\n videoSrc = URL.createObjectURL(file!)\n }\n\n // Validate URL uploads\n if (stagedUpload.type === 'url') {\n videoSrc = stagedUpload.url\n }\n\n // oxlint-disable-next-line react/react-compiler\n setVideoAssetMetadata((old) => ({\n ...old,\n duration: undefined,\n width: undefined,\n height: undefined,\n }))\n\n if (!videoSrc) return () => null\n\n setIsLoadingMetadata(true)\n const videoElement = document.createElement('video')\n videoElement.preload = 'metadata'\n\n const metadataListeners = [\n () => {\n setIsLoadingMetadata(false)\n },\n () => {\n const duration = videoElement.duration\n const width = videoElement.videoWidth\n const height = videoElement.videoHeight\n const isAudioOnly = width <= 0 && height <= 0\n const aspectRatio = width / height\n setVideoAssetMetadata((old) => {\n return {\n ...old,\n duration: duration,\n width: width,\n height: height,\n isAudioOnly: isAudioOnly,\n aspectRatio: aspectRatio,\n }\n })\n },\n ]\n\n const cleanupVideo = (videoEl: HTMLVideoElement) => {\n const currentVideoSrc = videoEl?.src\n if (videoEl) {\n metadataListeners.forEach((listener) =>\n videoEl.removeEventListener('loadedmetadata', listener),\n )\n videoEl.onerror = null\n videoEl.src = ''\n videoEl.load()\n }\n if (currentVideoSrc?.startsWith('blob:')) {\n URL.revokeObjectURL(currentVideoSrc)\n }\n }\n metadataListeners.push(() => setTimeout(() => cleanupVideo(videoElement), 0))\n\n videoElement.onerror = () => {\n setIsLoadingMetadata(false)\n console.warn('Could not read video metadata for validation')\n cleanupVideo(videoElement)\n }\n\n metadataListeners.forEach((listener) =>\n videoElement.addEventListener('loadedmetadata', listener),\n )\n videoElement.src = videoSrc\n\n return () => {\n cleanupVideo(videoElement)\n }\n }, [stagedUpload.type, stagedUpload])\n\n return {\n videoAssetMetadata,\n setVideoAssetMetadata,\n isLoadingMetadata,\n }\n}\n","import {roundPxString} from './roundPxString'\nimport type {MuxOverlaySettings, WatermarkConfig} from './types'\n\n/**\n * Converts a draggable watermark position (x, y percentages) to Mux's overlay_settings format.\n *\n * @param watermark - The watermark configuration with position, size, and opacity\n * @returns Mux overlay_settings object\n * @see {@link https://www.mux.com/docs/guides/add-watermarks-to-your-videos}\n */\nexport function convertWatermarkToMuxOverlay(\n watermark: WatermarkConfig,\n options?: {\n /**\n * Video aspect ratio (width / height). Needed for correct vertical positioning,\n * especially on vertical videos.\n */\n videoAspectRatio?: number\n /**\n * Unit to emit for margins/width when generating overlay_settings from Canvas mode.\n * - 'px' will generate pixel strings according to Mux's scaling rules:\n * values are applied as if the video were scaled to 1920x1080 (horizontal)\n * or 1080x1920 (vertical).\n * - '%' preserves existing behavior.\n */\n units?: '%' | 'px'\n },\n): MuxOverlaySettings | null {\n if (!watermark.enabled || !watermark.imageUrl) {\n return null\n }\n\n const size = watermark.size || 20\n const opacity = watermark.opacity ?? 0.7\n\n /**\n * Convert a percentage to whole-pixel string, using Mux's base dimensions:\n * - Horizontal video: 1920x1080\n * - Vertical video: 1080x1920\n */\n const toPxString = (valuePercent: number, axis: 'x' | 'y') => {\n const videoAspectRatio = options?.videoAspectRatio ?? 16 / 9\n const isVertical = videoAspectRatio > 0 && videoAspectRatio < 1\n const baseW = isVertical ? 1080 : 1920\n const baseH = isVertical ? 1920 : 1080\n const base = axis === 'x' ? baseW : baseH\n const px = (valuePercent / 100) * base\n let rounded = Math.round(px)\n // Avoid sending 0px (and JS -0); keep sign for negative margins.\n if (rounded === 0) rounded = px < 0 ? -1 : 1\n return `${rounded}px`\n }\n\n const normalizeToPixels = (value: string | undefined, axis: 'x' | 'y'): string | undefined => {\n if (!value) return value\n const trimmed = value.trim()\n if (trimmed.endsWith('px')) {\n return roundPxString(trimmed)\n }\n if (trimmed.endsWith('%')) {\n const n = Number(trimmed.slice(0, -1))\n if (!Number.isFinite(n)) return value\n return toPxString(n, axis)\n }\n return value\n }\n\n // If user provided explicit overlay settings, use them (Mux-documented format).\n // When `options.units === 'px'`, we normalize both % and px to whole-pixel strings,\n // honoring vertical vs horizontal video bases.\n if (watermark.overlay_settings) {\n const widthValue = watermark.overlay_settings.width\n const widthNormalized =\n options?.units === 'px' ? normalizeToPixels(widthValue, 'x') : widthValue\n return {\n ...watermark.overlay_settings,\n horizontal_margin:\n options?.units === 'px'\n ? (normalizeToPixels(watermark.overlay_settings.horizontal_margin, 'x') ??\n watermark.overlay_settings.horizontal_margin)\n : watermark.overlay_settings.horizontal_margin,\n vertical_margin:\n options?.units === 'px'\n ? (normalizeToPixels(watermark.overlay_settings.vertical_margin, 'y') ??\n watermark.overlay_settings.vertical_margin)\n : watermark.overlay_settings.vertical_margin,\n width: widthNormalized ?? `${size}%`,\n opacity: watermark.overlay_settings.opacity ?? `${Math.round(opacity * 100)}%`,\n }\n }\n\n const position = watermark.position || {x: 50, y: 50}\n\n /**\n * Our UI stores watermark position as the *center point* in percentages.\n * Mux margins are interpreted relative to an *edge* (based on align).\n *\n * To make \"corner\" placements match what the user dragged, we convert from\n * center-position to top-left margins by subtracting half the watermark size.\n *\n * Note: `size` is a percentage of video width. Mux `width` is also expressed\n * as a percentage of the video width, so we can reuse it for horizontal math.\n * For vertical math, we approximate using the same percentage to keep behavior\n * consistent with the current draggable UI (which also uses `size` in both axes\n * for bounds).\n */\n // Allow negative margins to compensate for rounding / letterboxing edge-cases.\n // We still clamp to a sane range so values don't explode.\n const clampPercent = (value: number) => Math.max(-100, Math.min(100, value))\n\n // Mux accepts percentage strings; avoid sending an exact \"0%\" by nudging to 0.01%.\n // This also handles the JS -0 edge case and tiny floating point remnants.\n const toPercentString = (value: number) => {\n const epsilon = 1e-9\n const isZeroish = value === 0 || Object.is(value, -0) || Math.abs(value) < epsilon\n return `${isZeroish ? 0.01 : value}%`\n }\n\n const watermarkWidthPercentOfVideoWidth = size\n\n /**\n * Convert watermark height into % of video height.\n * height% = (watermarkWidthPx / imageAspectRatio) / videoHeightPx\n * = (size% * videoWidthPx / imageAspectRatio) / videoHeightPx\n * = size% * (videoWidthPx/videoHeightPx) / imageAspectRatio\n * = size% * videoAspectRatio / imageAspectRatio\n */\n const videoAspectRatio = options?.videoAspectRatio ?? 16 / 9\n const imageAspectRatio = watermark.imageAspectRatio ?? 1\n const watermarkHeightPercentOfVideoHeight = Math.max(\n 0,\n Math.min(100, (size * videoAspectRatio) / imageAspectRatio),\n )\n\n const halfWidth = watermarkWidthPercentOfVideoWidth / 2\n const halfHeight = watermarkHeightPercentOfVideoHeight / 2\n\n const leftMargin = clampPercent(\n Math.min(position.x - halfWidth, 100 - watermarkWidthPercentOfVideoWidth),\n )\n const topMargin = clampPercent(\n Math.min(position.y - halfHeight, 100 - watermarkHeightPercentOfVideoHeight),\n )\n\n const units = options?.units ?? '%'\n const marginX = units === 'px' ? toPxString(leftMargin, 'x') : toPercentString(leftMargin)\n const marginY = units === 'px' ? toPxString(topMargin, 'y') : toPercentString(topMargin)\n const width = units === 'px' ? toPxString(size, 'x') : `${size}%`\n\n const overlaySettings: MuxOverlaySettings = {\n vertical_align: 'top',\n vertical_margin: marginY,\n horizontal_align: 'left',\n horizontal_margin: marginX,\n width,\n opacity: `${Math.round(opacity * 100)}%`,\n }\n\n return overlaySettings\n}\n","// From: https://stackoverflow.com/questions/10420352/converting-file-size-in-bytes-to-human-readable-string\n/**\n * Format bytes as human-readable text.\n *\n * @param bytes Number of bytes.\n * @param si True to use metric (SI) units, aka powers of 1000. False to use\n * binary (IEC), aka powers of 1024.\n * @param dp Number of decimal places to display.\n *\n * @return Formatted string.\n */\nexport default function formatBytes(bytes: number, si = false, dp = 1) {\n const thresh = si ? 1000 : 1024\n\n if (Math.abs(bytes) < thresh) {\n return bytes + ' B'\n }\n\n const units = si\n ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']\n : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']\n let u = -1\n const r = 10 ** dp\n\n do {\n bytes /= thresh\n ++u\n } while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1)\n\n return bytes.toFixed(dp) + ' ' + units[u]\n}\n","import {CheckmarkCircleIcon} from '@sanity/icons/CheckmarkCircle'\nimport {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {Box, Button, Card, Flex, Grid, Stack, Text, TextInput} from '@sanity/ui'\nimport {useCallback, useEffect, useRef, useState} from 'react'\nimport {styled} from 'styled-components'\n\nimport {convertWatermarkToMuxOverlay} from '../util/convertWatermarkToMux'\nimport type {MuxOverlaySettings, WatermarkConfig} from '../util/types'\n\nconst RangeInput = styled.input`\n width: 100%;\n height: 4px;\n border-radius: 2px;\n background: var(--card-border-color);\n outline: none;\n -webkit-appearance: none;\n appearance: none;\n\n &::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--card-focus-ring-color, #2276fc);\n cursor: pointer;\n border: 2px solid white;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n }\n\n &::-moz-range-thumb {\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--card-focus-ring-color, #2276fc);\n cursor: pointer;\n border: 2px solid white;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n }\n\n &:hover::-webkit-slider-thumb {\n background: var(--card-focus-ring-color, #1a5fc7);\n }\n\n &:hover::-moz-range-thumb {\n background: var(--card-focus-ring-color, #1a5fc7);\n }\n`\n\nconst WatermarkOverlay = styled.div<{$opacity: number}>`\n position: absolute;\n max-width: 200px;\n opacity: ${(props) => props.$opacity};\n cursor: move;\n user-select: none;\n z-index: 10;\n pointer-events: auto;\n\n img {\n width: 100%;\n height: auto;\n display: block;\n pointer-events: none;\n }\n\n &:hover {\n outline: 2px dashed rgba(255, 255, 255, 0.8);\n outline-offset: 4px;\n }\n`\n\ninterface DraggableWatermarkProps {\n watermark: WatermarkConfig\n onChange: (watermark: WatermarkConfig) => void\n containerRef?: React.RefObject<HTMLDivElement>\n videoElementRef?: React.RefObject<HTMLVideoElement>\n}\n\nexport default function DraggableWatermark({\n watermark,\n onChange,\n containerRef,\n videoElementRef,\n}: DraggableWatermarkProps) {\n const [isDragging, setIsDragging] = useState(false)\n const [dragStart, setDragStart] = useState({x: 0, y: 0})\n const [startPosition, setStartPosition] = useState({x: 0, y: 0})\n const watermarkRef = useRef<HTMLDivElement>(null)\n const debounceTimeoutRef = useRef<NodeJS.Timeout | null>(null)\n const [localPosition, setLocalPosition] = useState(watermark.position || {x: 50, y: 50})\n\n const position = localPosition\n const size = watermark.size || 20\n const opacity = watermark.opacity ?? 0.7\n\n const parseOpacityPercent = (value: string | undefined): number | null => {\n if (!value) return null\n const trimmed = value.trim()\n if (!trimmed.endsWith('%')) return null\n const num = Number(trimmed.slice(0, -1))\n if (!Number.isFinite(num)) return null\n return Math.max(0, Math.min(1, num / 100))\n }\n\n const getVideoContentBox = useCallback(() => {\n const container = containerRef?.current\n if (!container) return {x: 0, y: 0, width: 0, height: 0}\n\n const rect = container.getBoundingClientRect()\n const containerW = rect.width\n const containerH = rect.height\n\n const videoEl = videoElementRef?.current\n const videoW = videoEl?.videoWidth || 0\n const videoH = videoEl?.videoHeight || 0\n\n if (!videoW || !videoH || !containerW || !containerH) {\n return {x: 0, y: 0, width: containerW, height: containerH}\n }\n\n // object-fit: contain sizing\n const scale = Math.min(containerW / videoW, containerH / videoH)\n const contentW = videoW * scale\n const contentH = videoH * scale\n const offsetX = (containerW - contentW) / 2\n const offsetY = (containerH - contentH) / 2\n\n return {x: offsetX, y: offsetY, width: contentW, height: contentH}\n }, [containerRef, videoElementRef])\n\n const parseOverlayValue = (value: string | undefined): {n: number; unit: '%' | 'px'} | null => {\n if (!value) return null\n const trimmed = value.trim()\n const px = trimmed.endsWith('px')\n const pct = trimmed.endsWith('%')\n const num = Number(trimmed.replace(/px|%/g, ''))\n if (!Number.isFinite(num)) return null\n if (px) return {n: num, unit: 'px'}\n if (pct) return {n: num, unit: '%'}\n return null\n }\n\n const computeManualStyle = (overlay: MuxOverlaySettings) => {\n const rect = containerRef?.current?.getBoundingClientRect()\n const w = rect?.width ?? 0\n const h = rect?.height ?? 0\n const isVertical = h > w\n const baseW = isVertical ? 1080 : 1920\n const baseH = isVertical ? 1920 : 1080\n\n const hm = parseOverlayValue(overlay.horizontal_margin)\n const vm = parseOverlayValue(overlay.vertical_margin)\n const ww = parseOverlayValue(overlay.width)\n const manualOpacity = parseOpacityPercent(overlay.opacity)\n\n const toCss = (v: {n: number; unit: '%' | 'px'} | null, axis: 'x' | 'y') => {\n if (!v) return undefined\n if (v.unit === '%') return `${v.n}%`\n if (axis === 'x') return `${(v.n * w) / baseW}px`\n return `${(v.n * h) / baseH}px`\n }\n\n const computeHorizontalStyle = () => {\n if (overlay.horizontal_align === 'left') {\n return {left: toCss(hm, 'x'), right: undefined, transform: 'translate(0, 0)'}\n }\n if (overlay.horizontal_align === 'right') {\n return {right: toCss(hm, 'x'), left: undefined, transform: 'translate(0, 0)'}\n }\n return {left: '50%', right: undefined, transform: 'translate(-50%, 0)'}\n }\n\n const computeVerticalStyle = () => {\n if (overlay.vertical_align === 'top') {\n return {top: toCss(vm, 'y'), bottom: undefined}\n }\n if (overlay.vertical_align === 'bottom') {\n return {bottom: toCss(vm, 'y'), top: undefined}\n }\n return {top: '50%', bottom: undefined}\n }\n\n const hStyle = computeHorizontalStyle()\n const vStyle = computeVerticalStyle()\n\n let transform = hStyle.transform\n if (overlay.vertical_align === 'middle') {\n transform =\n overlay.horizontal_align === 'center' ? 'translate(-50%, -50%)' : 'translate(0, -50%)'\n }\n\n return {\n position: 'absolute' as const,\n ...hStyle,\n ...vStyle,\n transform,\n width: ww ? toCss(ww, 'x') : `${size}%`,\n opacity: manualOpacity ?? opacity,\n cursor: 'default',\n }\n }\n\n const debouncedOnChange = useCallback(\n (newWatermark: WatermarkConfig) => {\n if (debounceTimeoutRef.current) {\n clearTimeout(debounceTimeoutRef.current)\n }\n debounceTimeoutRef.current = setTimeout(() => {\n onChange(newWatermark)\n }, 300)\n },\n [onChange],\n )\n\n useEffect(() => {\n return () => {\n if (debounceTimeoutRef.current) {\n clearTimeout(debounceTimeoutRef.current)\n }\n }\n }, [])\n\n useEffect(() => {\n if (!isDragging && watermark.position) {\n // oxlint-disable-next-line react/react-compiler\n setLocalPosition(watermark.position)\n }\n }, [watermark.position, isDragging])\n\n const handleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault()\n setIsDragging(true)\n setDragStart({x: e.clientX, y: e.clientY})\n setStartPosition({x: position.x, y: position.y})\n },\n [position],\n )\n\n const handleMouseMove = useCallback(\n (e: MouseEvent) => {\n if (!isDragging || !containerRef?.current) return\n\n const container = containerRef.current\n const rect = container.getBoundingClientRect()\n const content = getVideoContentBox()\n const contentW = content.width || rect.width\n const contentH = content.height || rect.height\n const dx = e.clientX - dragStart.x\n const dy = e.clientY - dragStart.y\n\n const deltaXPercent = (dx / contentW) * 100\n const deltaYPercent = (dy / contentH) * 100\n\n let newX = startPosition.x + deltaXPercent\n let newY = startPosition.y + deltaYPercent\n\n newX = Math.max(0, Math.min(100, newX))\n newY = Math.max(0, Math.min(100, newY))\n\n setLocalPosition({x: newX, y: newY})\n\n debouncedOnChange({\n ...watermark,\n position: {x: newX, y: newY},\n })\n },\n [\n isDragging,\n dragStart,\n startPosition,\n containerRef,\n watermark,\n debouncedOnChange,\n getVideoContentBox,\n ],\n )\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false)\n if (debounceTimeoutRef.current) {\n clearTimeout(debounceTimeoutRef.current)\n debounceTimeoutRef.current = null\n }\n onChange({\n ...watermark,\n position: localPosition,\n })\n }, [watermark, localPosition, onChange])\n\n useEffect(() => {\n if (isDragging) {\n document.addEventListener('mousemove', handleMouseMove)\n document.addEventListener('mouseup', handleMouseUp)\n return () => {\n document.removeEventListener('mousemove', handleMouseMove)\n document.removeEventListener('mouseup', handleMouseUp)\n }\n }\n return undefined\n }, [isDragging, handleMouseMove, handleMouseUp])\n\n if (!watermark.imageUrl) {\n return null\n }\n\n const hasManualOverlay = Boolean(watermark.overlay_settings)\n const opacityForRender = hasManualOverlay\n ? (parseOpacityPercent(watermark.overlay_settings?.opacity) ?? opacity)\n : opacity\n // oxlint-disable-next-line react/react-compiler\n const contentBox = getVideoContentBox()\n const hasContentBox = contentBox.width > 0 && contentBox.height > 0\n\n const computeWatermarkStyle = () => {\n if (hasManualOverlay) {\n return computeManualStyle(watermark.overlay_settings!)\n }\n if (hasContentBox) {\n return {\n left: `${contentBox.x + (position.x / 100) * contentBox.width}px`,\n top: `${contentBox.y + (position.y / 100) * contentBox.height}px`,\n transform: 'translate(-50%, -50%)',\n width: `${Math.max(1, (size / 100) * contentBox.width)}px`,\n cursor: isDragging ? 'grabbing' : 'grab',\n }\n }\n return {\n left: `${position.x}%`,\n top: `${position.y}%`,\n transform: 'translate(-50%, -50%)',\n width: `${size}%`,\n cursor: isDragging ? 'grabbing' : 'grab',\n }\n }\n\n return (\n <WatermarkOverlay\n ref={watermarkRef}\n $opacity={opacityForRender}\n onMouseDown={hasManualOverlay ? undefined : handleMouseDown}\n // oxlint-disable-next-line react/react-compiler\n style={computeWatermarkStyle()}\n >\n <img src={watermark.imageUrl} alt=\"Watermark\" draggable={false} />\n </WatermarkOverlay>\n )\n}\n\ninterface WatermarkControlsProps {\n watermark: WatermarkConfig\n onChange: (watermark: WatermarkConfig) => void\n onValidationChange?: (error: string | null) => void\n previewContainerRef?: React.RefObject<HTMLDivElement | null>\n previewVideoRef?: React.RefObject<HTMLVideoElement | null>\n}\n\nexport function WatermarkControls({\n watermark,\n onChange,\n onValidationChange,\n previewContainerRef,\n previewVideoRef,\n}: WatermarkControlsProps) {\n const [urlInput, setUrlInput] = useState(watermark.imageUrl || '')\n const [urlError, setUrlError] = useState<string | null>(null)\n const [isValidating, setIsValidating] = useState(false)\n const [isValid, setIsValid] = useState<boolean | null>(null)\n const validationTimeoutRef = useRef<NodeJS.Timeout | null>(null)\n const [mode, setMode] = useState<'canvas' | 'manual'>(\n watermark.overlay_settings ? 'manual' : 'canvas',\n )\n\n const isUpdatingRef = useRef(false)\n\n const isValidExtension = useCallback((extension: string) => {\n return extension.endsWith('.png') || extension.endsWith('.jpg') || extension.endsWith('.jpeg')\n }, [])\n\n const validateUrl = useCallback(\n (url: string) => {\n if (validationTimeoutRef.current) {\n clearTimeout(validationTimeoutRef.current)\n }\n\n if (!url) {\n setUrlError(null)\n setIsValid(null)\n setIsValidating(false)\n onValidationChange?.(null)\n isUpdatingRef.current = true\n onChange({\n ...watermark,\n enabled: false,\n imageUrl: undefined,\n overlay_settings: undefined,\n })\n return\n }\n\n setIsValidating(true)\n setIsValid(null)\n setUrlError(null)\n\n validationTimeoutRef.current = setTimeout(() => {\n try {\n const urlObj = new URL(url)\n const pathname = urlObj.pathname.toLowerCase()\n if (isValidExtension(pathname)) {\n setIsValid(true)\n setUrlError(null)\n onValidationChange?.(null)\n const img = new Image()\n img.onload = () => {\n const imageAspectRatio =\n img.naturalWidth && img.naturalHeight ? img.naturalWidth / img.naturalHeight : 1\n isUpdatingRef.current = true\n onChange({\n ...watermark,\n enabled: true,\n imageUrl: url,\n imageAspectRatio,\n })\n }\n img.onerror = () => {\n isUpdatingRef.current = true\n onChange({\n ...watermark,\n enabled: true,\n imageUrl: url,\n imageAspectRatio: watermark.imageAspectRatio,\n })\n }\n img.src = url\n } else {\n const errorMsg =\n 'Mux only supports PNG and JPG watermark images. Please use a .png or .jpg file.'\n setIsValid(false)\n setUrlError(errorMsg)\n onValidationChange?.(errorMsg)\n isUpdatingRef.current = true\n onChange({\n ...watermark,\n enabled: false,\n imageUrl: undefined,\n imageAspectRatio: undefined,\n overlay_settings: undefined,\n })\n }\n } catch {\n setIsValid(false)\n const errorMsg = 'Please enter a valid URL (e.g., https://example.com/watermark.png)'\n setUrlError(errorMsg)\n onValidationChange?.(errorMsg)\n isUpdatingRef.current = true\n onChange({\n ...watermark,\n enabled: false,\n imageUrl: undefined,\n imageAspectRatio: undefined,\n overlay_settings: undefined,\n })\n } finally {\n setIsValidating(false)\n }\n }, 500)\n },\n [watermark, onChange, onValidationChange, isValidExtension],\n )\n\n useEffect(() => {\n return () => {\n if (validationTimeoutRef.current) {\n clearTimeout(validationTimeoutRef.current)\n }\n }\n }, [])\n\n useEffect(() => {\n // oxlint-disable-next-line react/react-compiler\n setMode(watermark.overlay_settings ? 'manual' : 'canvas')\n }, [watermark.overlay_settings])\n\n const handleUrlChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const url = e.target.value\n setUrlInput(url)\n\n if (watermark.imageUrl && url !== watermark.imageUrl) {\n isUpdatingRef.current = true\n onChange({\n ...watermark,\n enabled: false,\n imageUrl: undefined,\n imageAspectRatio: undefined,\n overlay_settings: undefined,\n })\n }\n\n validateUrl(url)\n }\n\n const normalizeZeroPercent = (value: string | undefined) => {\n if (!value) return value\n const trimmed = value.trim()\n if (!trimmed.endsWith('%')) return value\n const n = Number(trimmed.slice(0, -1))\n if (!Number.isFinite(n)) return value\n const epsilon = 1e-9\n if (n === 0 || Object.is(n, -0) || Math.abs(n) < epsilon) return '0.01%'\n return `${n}%`\n }\n\n const updateOverlaySettings = (next: Partial<MuxOverlaySettings>) => {\n const prev = watermark.overlay_settings\n const base: MuxOverlaySettings = prev ?? {\n vertical_align: 'bottom',\n vertical_margin: '2%',\n horizontal_align: 'right',\n horizontal_margin: '2%',\n width: `${watermark.size ?? 20}%`,\n opacity: `${Math.round((watermark.opacity ?? 0.7) * 100)}%`,\n }\n\n const merged: MuxOverlaySettings = {\n ...base,\n ...next,\n }\n\n onChange({\n ...watermark,\n enabled: true,\n overlay_settings: {\n ...merged,\n horizontal_margin:\n normalizeZeroPercent(merged.horizontal_margin) || merged.horizontal_margin,\n vertical_margin: normalizeZeroPercent(merged.vertical_margin) || merged.vertical_margin,\n },\n })\n }\n\n const getVideoContentBox = () => {\n const container = previewContainerRef?.current\n if (!container) return {x: 0, y: 0, width: 0, height: 0}\n\n const rect = container.getBoundingClientRect()\n const containerW = rect.width\n const containerH = rect.height\n\n const videoEl = previewVideoRef?.current\n const videoW = videoEl?.videoWidth || 0\n const videoH = videoEl?.videoHeight || 0\n\n if (!videoW || !videoH || !containerW || !containerH) {\n return {x: 0, y: 0, width: containerW, height: containerH}\n }\n\n const scale = Math.min(containerW / videoW, containerH / videoH)\n const contentW = videoW * scale\n const contentH = videoH * scale\n const offsetX = (containerW - contentW) / 2\n const offsetY = (containerH - contentH) / 2\n\n return {x: offsetX, y: offsetY, width: contentW, height: contentH}\n }\n\n return (\n <Stack space={3}>\n <Stack space={2}>\n <Text size={1} weight=\"medium\">\n Watermark Image URL\n </Text>\n <Text size={0} muted>\n Enter a URL to a PNG or JPG image. Mux will download this image and overlay it on your\n video.\n </Text>\n <Box style={{position: 'relative', width: '100%'}}>\n <input\n type=\"url\"\n value={urlInput}\n onChange={handleUrlChange}\n placeholder=\"https://example.com/watermark.png\"\n style={{\n padding: '8px 12px',\n paddingRight: (() => {\n if (urlInput) return '96px'\n if (isValid !== null) return '36px'\n return '12px'\n })(),\n border: (() => {\n if (urlError || isValid === false) return '1px solid #e74c3c'\n if (isValid === true) return '1px solid #4caf50'\n return '1px solid #ccc'\n })(),\n borderRadius: '4px',\n width: '100%',\n maxWidth: '100%',\n boxSizing: 'border-box',\n fontSize: '14px',\n }}\n />\n {(urlInput || isValidating || isValid !== null) && (\n <Box\n style={{\n position: 'absolute',\n right: '8px',\n top: '50%',\n transform: 'translateY(-50%)',\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n }}\n >\n {urlInput && (\n <Button\n text=\"Clear\"\n mode=\"bleed\"\n tone=\"critical\"\n onClick={() => {\n setUrlInput('')\n validateUrl('')\n }}\n disabled={isValidating}\n style={{fontSize: '11px', height: '24px'}}\n />\n )}\n {isValidating && (\n <Text size={0} muted>\n Validating...\n </Text>\n )}\n {isValid === true && !isValidating && (\n <CheckmarkCircleIcon style={{color: '#4caf50', fontSize: '18px'}} />\n )}\n {isValid === false && !isValidating && (\n <ErrorOutlineIcon style={{color: '#e74c3c', fontSize: '18px'}} />\n )}\n </Box>\n )}\n </Box>\n {urlError && (\n <Card padding={2} tone=\"critical\" radius={2}>\n <Flex align=\"center\" gap={2}>\n <ErrorOutlineIcon style={{color: '#e74c3c', flexShrink: 0}} />\n <Text size={0} style={{color: '#e74c3c'}}>\n {urlError}\n </Text>\n </Flex>\n </Card>\n )}\n </Stack>\n\n {watermark.imageUrl && (\n <Stack space={2}>\n <Card padding={3} tone=\"transparent\" border radius={2}>\n <Flex\n align=\"center\"\n justify=\"space-between\"\n gap={3}\n style={{flexWrap: 'wrap', alignItems: 'flex-start'}}\n >\n <Stack space={2} style={{minWidth: 240, flex: 1}}>\n <Text size={1} weight=\"medium\">\n Positioning mode\n </Text>\n <Text size={0} muted>\n Choose between dragging on the canvas or manually editing the Mux{' '}\n <code>overlay_settings</code> fields (as in{' '}\n <a\n href=\"https://www.mux.com/docs/guides/add-watermarks-to-your-videos\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n the docs\n </a>\n ).\n </Text>\n </Stack>\n <Flex gap={2} style={{flexWrap: 'wrap'}}>\n <Button\n text=\"Canvas\"\n mode={mode === 'canvas' ? 'default' : 'ghost'}\n onClick={() => {\n setMode('canvas')\n onChange({...watermark, enabled: true, overlay_settings: undefined})\n }}\n />\n <Button\n text=\"Manual\"\n mode={mode === 'manual' ? 'default' : 'ghost'}\n onClick={() => {\n setMode('manual')\n const overlay = convertWatermarkToMuxOverlay({...watermark, enabled: true})\n updateOverlaySettings(overlay ?? {})\n }}\n />\n </Flex>\n </Flex>\n </Card>\n\n {mode === 'manual' && (\n <Card padding={3} tone=\"transparent\" border radius={2}>\n <Stack space={3}>\n <Text size={1} weight=\"medium\">\n Mux overlay_settings\n </Text>\n <Grid columns={[1, 2]} gap={3} style={{width: '100%'}}>\n <Stack space={2} style={{minWidth: 0}}>\n <Text size={0} muted>\n horizontal_align\n </Text>\n <select\n value={watermark.overlay_settings?.horizontal_align || 'right'}\n onChange={(e) =>\n updateOverlaySettings({\n horizontal_align: (e.target.value ||\n 'right') as MuxOverlaySettings['horizontal_align'],\n })\n }\n style={{\n width: '100%',\n padding: '8px 10px',\n border: '1px solid #ccc',\n borderRadius: 4,\n }}\n >\n <option value=\"left\">left</option>\n <option value=\"center\">center</option>\n <option value=\"right\">right</option>\n </select>\n </Stack>\n <Stack space={2} style={{minWidth: 0}}>\n <Text size={0} muted>\n horizontal_margin (e.g. 2% or 40px)\n </Text>\n <TextInput\n value={watermark.overlay_settings?.horizontal_margin || '2%'}\n onChange={(e) =>\n updateOverlaySettings({horizontal_margin: e.currentTarget.value})\n }\n />\n </Stack>\n <Stack space={2} style={{minWidth: 0}}>\n <Text size={0} muted>\n vertical_align\n </Text>\n <select\n value={watermark.overlay_settings?.vertical_align || 'bottom'}\n onChange={(e) =>\n updateOverlaySettings({\n vertical_align: (e.target.value ||\n 'bottom') as MuxOverlaySettings['vertical_align'],\n })\n }\n style={{\n width: '100%',\n padding: '8px 10px',\n border: '1px solid #ccc',\n borderRadius: 4,\n }}\n >\n <option value=\"top\">top</option>\n <option value=\"middle\">middle</option>\n <option value=\"bottom\">bottom</option>\n </select>\n </Stack>\n <Stack space={2} style={{minWidth: 0}}>\n <Text size={0} muted>\n vertical_margin (e.g. 2% or 40px)\n </Text>\n <TextInput\n value={watermark.overlay_settings?.vertical_margin || '2%'}\n onChange={(e) =>\n updateOverlaySettings({vertical_margin: e.currentTarget.value})\n }\n />\n </Stack>\n <Stack space={2} style={{minWidth: 0}}>\n <Text size={0} muted>\n width (e.g. 25% or 80px)\n </Text>\n <TextInput\n value={watermark.overlay_settings?.width || `${watermark.size ?? 20}%`}\n onChange={(e) => updateOverlaySettings({width: e.currentTarget.value})}\n />\n </Stack>\n <Stack space={2} style={{minWidth: 0}}>\n <Text size={0} muted>\n opacity (e.g. 90%)\n </Text>\n <TextInput\n value={\n watermark.overlay_settings?.opacity ||\n `${Math.round((watermark.opacity ?? 0.7) * 100)}%`\n }\n onChange={(e) => updateOverlaySettings({opacity: e.currentTarget.value})}\n />\n </Stack>\n </Grid>\n <Text size={0} muted>\n Margins and width accept either percentages or pixels, per the Mux guide.\n </Text>\n </Stack>\n </Card>\n )}\n\n {mode === 'canvas' && (\n <>\n <Box>\n <Text size={1} weight=\"medium\">\n {/* oxlint-disable-next-line react/react-compiler */}\n {(() => {\n const sizePct = watermark.size || 20\n const contentW = getVideoContentBox().width\n if (!contentW) return `Size: ${sizePct}%`\n const px = Math.max(1, Math.round((sizePct / 100) * contentW))\n return `Size: ${px}px`\n })()}\n </Text>\n <RangeInput\n type=\"range\"\n // oxlint-disable-next-line react/react-compiler\n value={(() => {\n const sizePct = watermark.size || 20\n const contentW = getVideoContentBox().width\n if (!contentW) return sizePct\n return Math.max(1, Math.round((sizePct / 100) * contentW))\n })()}\n // oxlint-disable-next-line react/react-compiler\n min={(() => {\n const contentW = getVideoContentBox().width\n if (!contentW) return 5\n return Math.max(1, Math.round(contentW * 0.05))\n })()}\n // oxlint-disable-next-line react/react-compiler\n max={(() => {\n const contentW = getVideoContentBox().width\n if (!contentW) return 50\n return Math.max(1, Math.round(contentW * 0.5))\n })()}\n step={1}\n onChange={(e) => {\n const raw = Number(e.target.value)\n const contentW = getVideoContentBox().width\n const nextPct = contentW ? (raw / contentW) * 100 : raw\n const clampedPct = Math.max(5, Math.min(50, nextPct))\n onChange({\n ...watermark,\n size: clampedPct,\n })\n }}\n />\n </Box>\n\n <Box>\n <Text size={1} weight=\"medium\">\n Opacity: {Math.round((watermark.opacity ?? 0.7) * 100)}%\n </Text>\n <RangeInput\n type=\"range\"\n value={watermark.opacity ?? 0.7}\n min={0}\n max={1}\n step={0.05}\n onChange={(e) =>\n onChange({\n ...watermark,\n opacity: Number(e.target.value),\n })\n }\n />\n </Box>\n </>\n )}\n\n <Card padding={2} tone=\"transparent\" border radius={2}>\n <Text size={0} muted>\n {mode === 'manual'\n ? 'Manual mode: edit the overlay_settings fields above'\n : '💡 Drag the watermark on the preview to position it'}\n </Text>\n </Card>\n </Stack>\n )}\n </Stack>\n )\n}\n","import {TranslateIcon} from '@sanity/icons/Translate'\nimport {Autocomplete, Box, Card, Checkbox, Flex, Stack, Text} from '@sanity/ui'\nimport {uuid} from '@sanity/uuid'\nimport LanguagesList from 'iso-639-1'\nimport {type Dispatch} from 'react'\nimport {FormField} from 'sanity'\n\nimport {type PluginConfig, SUPPORTED_MUX_LANGUAGES, type UploadTextTrack} from '../util/types'\n\nconst ALL_LANGUAGE_CODES = LanguagesList.getAllCodes().map((code) => ({\n value: code,\n label: LanguagesList.getNativeName(code),\n}))\n\nconst SUBTITLE_LANGUAGES: Record<\n Extract<UploadTextTrack, {language_code: any}>['type'],\n {value: string; label: string}[]\n> = {\n autogenerated: SUPPORTED_MUX_LANGUAGES.map((lang) => ({\n value: lang.code,\n label: lang.label,\n })),\n subtitles: ALL_LANGUAGE_CODES,\n captions: ALL_LANGUAGE_CODES,\n}\n\ntype TrackSubAction =\n | {subAction: 'add'; value: Partial<UploadTextTrack>}\n | {subAction: 'update'; value: Partial<UploadTextTrack>}\n | {subAction: 'delete'}\n\nexport type TrackAction = {action: 'track'; id: string} & TrackSubAction\n\nexport default function TextTracksEditor({\n tracks,\n dispatch,\n defaultLang,\n}: {\n /**\n * Although the schema for tracks is an array, which we'll eventually support to allow uploading\n * multiple custom subtitles, for now we only support a single auto-generated track.\n */\n tracks: (Partial<UploadTextTrack> & {_id: string})[]\n dispatch: Dispatch<TrackAction>\n defaultLang: PluginConfig['defaultAutogeneratedSubtitleLang']\n}) {\n const track = tracks[0]\n return (\n <FormField title=\"Auto-generated subtitle or caption\" path={[]}>\n <Stack space={2}>\n <Flex align=\"center\">\n <Checkbox\n id=\"include-autogenerated-track\"\n style={{display: 'block'}}\n checked={!!track?.language_code}\n onChange={() => {\n if (track) {\n dispatch({action: 'track', id: track._id, subAction: 'delete'})\n } else {\n dispatch({\n action: 'track',\n id: uuid(),\n subAction: 'add',\n value: {\n type: 'autogenerated',\n name: defaultLang || undefined,\n language_code: defaultLang || undefined,\n },\n })\n }\n }}\n />\n <Box flex={1} paddingLeft={3}>\n <Text>\n <label htmlFor=\"checkbox\">Generate captions</label>\n </Text>\n </Box>\n </Flex>\n {track && (\n <Autocomplete\n id={`text-tract-editor--language`}\n value={track.language_code}\n onChange={(newValue) =>\n dispatch({\n action: 'track',\n id: track._id,\n subAction: 'update',\n value: {\n language_code: newValue,\n name: LanguagesList.getNativeName(newValue),\n },\n })\n }\n options={SUBTITLE_LANGUAGES[track.type!]}\n icon={TranslateIcon}\n placeholder=\"Select language\"\n filterOption={(query, option) =>\n option.label.toLowerCase().indexOf(query.toLowerCase()) > -1 ||\n option.value.toLowerCase().indexOf(query.toLowerCase()) > -1\n }\n openButton\n renderValue={(value) =>\n SUBTITLE_LANGUAGES[track.type!].find((l) => l.value === value)?.label || value\n }\n renderOption={(option) => (\n <Card data-as=\"button\" padding={3} radius={2} tone=\"inherit\">\n <Text size={2} textOverflow=\"ellipsis\">\n {option.label} ({option.value})\n </Text>\n </Card>\n )}\n />\n )}\n </Stack>\n </FormField>\n )\n}\n","import {Checkbox, Flex, Grid, Text} from '@sanity/ui'\nimport {type ActionDispatch, type CSSProperties, type ReactNode, useState} from 'react'\n\nimport {type UploadConfigurationStateAction} from '../UploadConfiguration'\n\nexport default function PlaybackPolicyOption({\n id,\n checked,\n optionName,\n description,\n dispatch,\n action,\n disabled,\n}: {\n id: string\n checked: boolean\n optionName: string\n description: string | ReactNode\n dispatch: ActionDispatch<[action: UploadConfigurationStateAction]>\n action?: 'public_policy' | 'signed_policy' | 'drm_policy'\n disabled?: boolean\n}) {\n const [scale, setScale] = useState(1)\n\n const boxStyle: CSSProperties = {\n outline: '0.01rem solid grey',\n transform: `scale(${scale})`,\n transition: 'transform 0.1s ease-in-out',\n cursor: disabled ? 'not-allowed' : 'pointer',\n borderRadius: '0.25rem',\n }\n\n const triggerAnimation = () => {\n setScale(0.98)\n setTimeout(() => {\n setScale(1)\n }, 100)\n }\n\n const handleBoxClick = () => {\n if (!action) return\n triggerAnimation()\n dispatch({\n action,\n value: !checked,\n })\n }\n\n const descriptionJsx =\n typeof description === 'string' ? (\n <Text size={2} muted>\n {description}\n </Text>\n ) : (\n description\n )\n return (\n <label>\n <Flex gap={3} padding={3} style={boxStyle}>\n <Checkbox\n id={id}\n required\n checked={checked}\n onChange={handleBoxClick}\n disabled={disabled}\n />\n <Grid gap={3}>\n <Text size={3} weight=\"bold\">\n {optionName}\n </Text>\n {descriptionJsx}\n </Grid>\n </Flex>\n </label>\n )\n}\n","import {WarningFilledIcon} from '@sanity/icons/WarningFilled'\nimport {Box, Flex, Text} from '@sanity/ui'\nimport {type CSSProperties} from 'react'\n\nexport default function PlaybackPolicyWarning() {\n const textStyle: CSSProperties = {\n color: '#13141A',\n fontWeight: 500,\n }\n\n const boxStyle: CSSProperties = {\n outline: '0.01rem solid grey',\n backgroundColor: '#979cb0',\n borderRadius: '0.5rem',\n width: 'max-content',\n color: '#13141A',\n }\n\n return (\n <Box padding={2} style={boxStyle}>\n <Flex align=\"center\" gap={2}>\n <WarningFilledIcon />\n <Text size={1} style={textStyle}>\n Please select at least one Playback Policy\n </Text>\n </Flex>\n </Box>\n )\n}\n","import {Code, Grid, Text} from '@sanity/ui'\nimport {type ActionDispatch} from 'react'\n\nimport {type Secrets, type UploadConfig} from '../../util/types'\nimport {type UploadConfigurationStateAction} from '../UploadConfiguration'\nimport PlaybackPolicyOption from './PlaybackPolicyOption'\nimport PlaybackPolicyWarning from './PlaybackPolicyWarning'\n\nexport default function PlaybackPolicy({\n id,\n config,\n secrets,\n dispatch,\n}: {\n id: string\n config: UploadConfig\n secrets: Secrets\n dispatch: ActionDispatch<[action: UploadConfigurationStateAction]>\n}) {\n const noPolicySelected = !(config.public_policy || config.signed_policy || config.drm_policy)\n const drmPolicyDisabled = !secrets.drmConfigId\n return (\n <Grid gap={3}>\n <Text weight=\"bold\">Advanced Playback Policies</Text>\n <PlaybackPolicyOption\n id={`${id}--public`}\n checked={config.public_policy}\n optionName=\"Public\"\n description={\n <>\n <Text size={2} muted>\n Playback IDs are accessible by constructing an HLS URL like\n </Text>\n <Code>{'https://stream.mux.com/{PLAYBACK_ID}'}</Code>\n </>\n }\n dispatch={dispatch}\n action=\"public_policy\"\n />\n {secrets.enableSignedUrls && (\n <PlaybackPolicyOption\n id={`${id}--signed`}\n checked={config.signed_policy}\n optionName=\"Signed\"\n description={\n <>\n <Text size={2} muted>\n Playback IDs should be used with tokens\n </Text>\n <Code>{'https://stream.mux.com/{PLAYBACK_ID}?token={TOKEN}'}</Code>\n <Text size={2} muted>\n See{' '}\n <a\n href=\"https://www.mux.com/docs/guides/secure-video-playback\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Secure video playback\n </a>{' '}\n for details about creating tokens.\n </Text>\n </>\n }\n // See Secure video playback for details about creating tokens.\"\n dispatch={dispatch}\n action=\"signed_policy\"\n />\n )}\n {drmPolicyDisabled ? (\n <PlaybackPolicyOption\n id={`${id}--drm`}\n checked={false}\n optionName=\"DRM - Disabled\"\n description={\n <>\n <Text size={2} muted>\n To enable DRM add your DRM Configuration Id to your plugin configuration in the API\n Credentials view.{' '}\n <a\n href=\"https://www.mux.com/support/human\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Contact us\n </a>{' '}\n to get started using DRM.\n </Text>\n </>\n }\n dispatch={dispatch}\n disabled\n />\n ) : (\n <PlaybackPolicyOption\n id={`${id}--drm`}\n checked={config.drm_policy}\n optionName=\"DRM\"\n description={\n <>\n <Text size={2} muted>\n Playback IDs should be used with tokens as with Signed playback, but require extra\n configuration.\n </Text>\n <Code>{'https://stream.mux.com/{PLAYBACK_ID}?token={TOKEN}'}</Code>\n <Text size={2} muted>\n See{' '}\n <a\n href=\"https://www.mux.com/docs/guides/protect-videos-with-drm#play-drm-protected-videos\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Protect videos with DRM\n </a>{' '}\n for details about configuring your player for DRM playback and{' '}\n <a\n href=\"https://www.mux.com/docs/guides/secure-video-playback\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Secure video playback\n </a>{' '}\n for details about creating tokens.\n </Text>\n </>\n }\n dispatch={dispatch}\n action=\"drm_policy\"\n />\n )}\n {noPolicySelected && <PlaybackPolicyWarning />}\n </Grid>\n )\n}\n","import {Flex, Radio, Text} from '@sanity/ui'\nimport {type ActionDispatch} from 'react'\nimport {FormField} from 'sanity'\n\nimport {type UploadConfig} from '../../util/types'\nimport {type UploadConfigurationStateAction} from '../UploadConfiguration'\n\nexport const RESOLUTION_TIERS = [\n {value: '1080p', label: '1080p'},\n {value: '1440p', label: '1440p (2k)'},\n {value: '2160p', label: '2160p (4k)'},\n] as const satisfies {value: UploadConfig['max_resolution_tier']; label: string}[]\n\nexport const ResolutionTierSelector = ({\n id,\n config,\n dispatch,\n maxSupportedResolution,\n}: {\n id: string\n config: UploadConfig\n dispatch: ActionDispatch<[action: UploadConfigurationStateAction]>\n maxSupportedResolution: number\n}) => {\n return (\n <FormField\n path={[]}\n title=\"Resolution Tier\"\n description={\n <>\n The maximum{' '}\n <a\n href=\"https://docs.mux.com/api-reference#video/operation/create-direct-upload\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n resolution_tier\n </a>{' '}\n your asset is encoded, stored, and streamed at.\n </>\n }\n >\n <Flex gap={3} wrap={'wrap'}>\n {RESOLUTION_TIERS.map(({value, label}, index) => {\n const inputId = `${id}--type-${value}`\n\n if (index > maxSupportedResolution) return null\n\n return (\n <Flex key={value} align=\"center\" gap={2}>\n <Radio\n checked={config.max_resolution_tier === value}\n name=\"asset-resolutiontier\"\n onChange={(e) =>\n dispatch({\n action: 'max_resolution_tier',\n value: e.currentTarget.value as UploadConfig['max_resolution_tier'],\n })\n }\n value={value}\n id={inputId}\n />\n <Text as=\"label\" htmlFor={inputId}>\n {label}\n </Text>\n </Flex>\n )\n })}\n </Flex>\n </FormField>\n )\n}\n","import {Checkbox, Flex, Label, Radio, Stack, Text} from '@sanity/ui'\nimport {type ActionDispatch, useMemo, useState} from 'react'\nimport {FormField} from 'sanity'\n\nimport {type StaticRenditionResolution, type UploadConfig} from '../../util/types'\nimport {type UploadConfigurationStateAction} from '../UploadConfiguration'\n\nconst ADVANCED_RESOLUTIONS: {value: StaticRenditionResolution; label: string}[] = [\n {value: '270p', label: '270p'},\n {value: '360p', label: '360p'},\n {value: '480p', label: '480p'},\n {value: '540p', label: '540p'},\n {value: '720p', label: '720p'},\n {value: '1080p', label: '1080p'},\n {value: '1440p', label: '1440p'},\n {value: '2160p', label: '2160p'},\n]\n\nexport const StaticRenditionSelector = ({\n id,\n config,\n dispatch,\n}: {\n id: string\n config: UploadConfig\n dispatch: ActionDispatch<[action: UploadConfigurationStateAction]>\n}) => {\n // Determine if user is in advanced mode based on selected renditions\n const isAdvancedMode = useMemo(() => {\n const specificResolutions = config.static_renditions.filter(\n (r) => r !== 'highest' && r !== 'audio-only',\n )\n return specificResolutions.length > 0\n }, [config.static_renditions])\n\n const [renditionMode, setRenditionMode] = useState<'standard' | 'advanced'>(\n isAdvancedMode ? 'advanced' : 'standard',\n )\n\n // Helper to toggle a rendition\n const toggleRendition = (rendition: StaticRenditionResolution) => {\n const current = config.static_renditions\n const hasRendition = current.includes(rendition)\n\n if (hasRendition) {\n dispatch({\n action: 'static_renditions',\n value: current.filter((r) => r !== rendition),\n })\n } else {\n dispatch({\n action: 'static_renditions',\n value: [...current, rendition],\n })\n }\n }\n\n // When switching modes, clear renditions that don't apply\n const handleModeChange = (mode: 'standard' | 'advanced') => {\n setRenditionMode(mode)\n if (mode === 'standard') {\n // Remove specific resolutions, keep only highest and audio-only\n dispatch({\n action: 'static_renditions',\n value: config.static_renditions.filter((r) => r === 'highest' || r === 'audio-only'),\n })\n } else {\n // Remove highest, keep specific resolutions and audio-only\n dispatch({\n action: 'static_renditions',\n value: config.static_renditions.filter((r) => r !== 'highest'),\n })\n }\n }\n return (\n <Stack space={3}>\n <FormField\n path={[]}\n title=\"Static Renditions\"\n description=\"Generate downloadable MP4 or M4A files. Note: Mux will not upscale to produce MP4 renditions - renditions that would cause upscaling are skipped.\"\n >\n <Stack space={3}>\n {/* Mode Selector */}\n <Flex gap={3}>\n <Flex align=\"center\" gap={2}>\n <Radio\n checked={renditionMode === 'standard'}\n name=\"rendition-mode\"\n onChange={() => handleModeChange('standard')}\n value=\"standard\"\n id={`${id}--mode-standard`}\n />\n <Text as=\"label\" htmlFor={`${id}--mode-standard`}>\n Standard\n </Text>\n </Flex>\n <Flex align=\"center\" gap={2}>\n <Radio\n checked={renditionMode === 'advanced'}\n name=\"rendition-mode\"\n onChange={() => handleModeChange('advanced')}\n value=\"advanced\"\n id={`${id}--mode-advanced`}\n />\n <Text as=\"label\" htmlFor={`${id}--mode-advanced`}>\n Advanced\n </Text>\n </Flex>\n </Flex>\n\n {/* Standard Mode Options */}\n {renditionMode === 'standard' && (\n <Stack space={2}>\n <Flex align=\"center\" gap={2} padding={[0, 2]}>\n <Checkbox\n id={`${id}--highest`}\n style={{display: 'block'}}\n checked={config.static_renditions.includes('highest')}\n onChange={() => toggleRendition('highest')}\n />\n <Text as=\"label\" htmlFor={`${id}--highest`}>\n Highest Resolution (up to 4K)\n </Text>\n </Flex>\n <Flex align=\"center\" gap={2} padding={[0, 2]}>\n <Checkbox\n id={`${id}--audio-only-standard`}\n style={{display: 'block'}}\n checked={config.static_renditions.includes('audio-only')}\n onChange={() => toggleRendition('audio-only')}\n />\n <Text as=\"label\" htmlFor={`${id}--audio-only-standard`}>\n Audio Only (M4A)\n </Text>\n </Flex>\n </Stack>\n )}\n\n {/* Advanced Mode Options */}\n {renditionMode === 'advanced' && (\n <Stack space={2}>\n <Label size={1} muted>\n Select specific resolutions:\n </Label>\n <Flex gap={2} wrap=\"wrap\">\n {ADVANCED_RESOLUTIONS.map(({value, label}) => {\n const inputId = `${id}--resolution-${value}`\n return (\n <Flex key={value} align=\"center\" gap={2}>\n <Checkbox\n id={inputId}\n style={{display: 'block'}}\n checked={config.static_renditions.includes(value)}\n onChange={() => toggleRendition(value)}\n />\n <Text as=\"label\" htmlFor={inputId} size={1}>\n {label}\n </Text>\n </Flex>\n )\n })}\n </Flex>\n <Flex align=\"center\" gap={2} padding={[2, 2, 0, 2]}>\n <Checkbox\n id={`${id}--audio-only-advanced`}\n style={{display: 'block'}}\n checked={config.static_renditions.includes('audio-only')}\n onChange={() => toggleRendition('audio-only')}\n />\n <Text as=\"label\" htmlFor={`${id}--audio-only-advanced`}>\n Audio Only (M4A)\n </Text>\n </Flex>\n </Stack>\n )}\n </Stack>\n </FormField>\n </Stack>\n )\n}\n","import {DocumentVideoIcon} from '@sanity/icons/DocumentVideo'\nimport {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {UploadIcon} from '@sanity/icons/Upload'\nimport {Box, Button, Card, Dialog, Flex, Label, Radio, Stack, Text} from '@sanity/ui'\nimport {uuid} from '@sanity/uuid'\nimport LanguagesList from 'iso-639-1'\nimport {memo, useEffect, useId, useReducer, useRef, useState} from 'react'\nimport {FormField} from 'sanity'\n\nimport {useFetchFileSize} from '../hooks/useFetchFileSize'\nimport {useMediaMetadata, type VideoAssetMetadata} from '../hooks/useMediaMetadata'\nimport {convertWatermarkToMuxOverlay} from '../util/convertWatermarkToMux'\nimport formatBytes from '../util/formatBytes'\nimport {formatSeconds} from '../util/formatSeconds'\nimport {\n type AutogeneratedTextTrack,\n type CustomTextTrack,\n isAutogeneratedTrack,\n isCustomTextTrack,\n type MuxNewAssetSettings,\n type PluginConfig,\n type Secrets,\n type StaticRenditionResolution,\n type SupportedMuxLanguage,\n type UploadConfig,\n type UploadTextTrack,\n type WatermarkConfig,\n} from '../util/types'\nimport DraggableWatermark, {WatermarkControls} from './DraggableWatermark'\nimport TextTracksEditor, {type TrackAction} from './TextTracksEditor'\nimport PlaybackPolicy from './uploadConfiguration/PlaybackPolicy'\nimport {\n RESOLUTION_TIERS,\n ResolutionTierSelector,\n} from './uploadConfiguration/ResolutionTierSelector'\nimport {StaticRenditionSelector} from './uploadConfiguration/StaticRenditionSelector'\nimport type {StagedUpload} from './Uploader'\n\nexport type UploadConfigurationStateAction =\n | {action: 'video_quality'; value: UploadConfig['video_quality']}\n | {action: 'max_resolution_tier'; value: UploadConfig['max_resolution_tier']}\n | {action: 'static_renditions'; value: UploadConfig['static_renditions']}\n | {action: 'normalize_audio'; value: UploadConfig['normalize_audio']}\n | {action: 'signed_policy'; value: UploadConfig['signed_policy']}\n | {action: 'public_policy'; value: UploadConfig['public_policy']}\n | {action: 'drm_policy'; value: UploadConfig['drm_policy']}\n | {action: 'watermark'; value: WatermarkConfig}\n | TrackAction\n\nconst VIDEO_QUALITY_LEVELS = [\n {value: 'basic', label: 'Basic'},\n {value: 'plus', label: 'Plus'},\n {value: 'premium', label: 'Premium'},\n] as const satisfies {value: UploadConfig['video_quality']; label: string}[]\n\n/**\n * Sanitizes static renditions configuration to ensure 'highest' is not mixed with specific resolutions.\n * If both are present, only 'highest' (and 'audio-only' if present) will be kept.\n */\nfunction sanitizeStaticRenditions(\n renditions: StaticRenditionResolution[],\n): StaticRenditionResolution[] {\n const hasHighest = renditions.includes('highest')\n const hasSpecificResolutions = renditions.some((r) => r !== 'highest' && r !== 'audio-only')\n\n if (hasHighest && hasSpecificResolutions) {\n return renditions.filter((r) => r === 'highest' || r === 'audio-only')\n }\n\n return renditions\n}\n\n/**\n * The modal for configuring a staged upload. Handles triggering of the asset\n * upload, even if no modal needs to be shown.\n *\n * @returns\n */\nexport default function UploadConfiguration({\n stagedUpload,\n secrets,\n pluginConfig,\n startUpload,\n onClose,\n}: {\n stagedUpload: StagedUpload\n secrets: Secrets\n pluginConfig: PluginConfig\n startUpload: (settings: MuxNewAssetSettings, watermark: WatermarkConfig | undefined) => void\n onClose: () => void\n}) {\n const id = useId()\n const [watermarkValidationError, setWatermarkValidationError] = useState<string | null>(null)\n const watermarkPreviewContainerRef = useRef<HTMLDivElement>(null)\n const watermarkPreviewVideoRef = useRef<HTMLVideoElement>(null)\n // oxlint-disable-next-line react/react-compiler\n const autoTextTracks = useRef<NonNullable<UploadConfig['text_tracks']>>(\n pluginConfig.video_quality === 'plus' && pluginConfig.defaultAutogeneratedSubtitleLang\n ? [\n {\n _id: uuid(),\n type: 'autogenerated',\n language_code: pluginConfig.defaultAutogeneratedSubtitleLang,\n name: LanguagesList.getNativeName(pluginConfig.defaultAutogeneratedSubtitleLang),\n } satisfies AutogeneratedTextTrack,\n ]\n : [],\n ).current\n\n const [config, dispatch] = useReducer(\n // oxlint-disable-next-line react/react-compiler\n (prev: UploadConfig, action: UploadConfigurationStateAction) => {\n switch (action.action) {\n case 'video_quality':\n // If video quality level switches to basic, remove plus-only features\n if (action.value === 'basic') {\n return Object.assign({}, prev, {\n video_quality: action.value,\n static_renditions: [],\n max_resolution_tier: '1080p',\n text_tracks: prev.text_tracks?.filter(({type}) => type !== 'autogenerated'),\n public_policy: true,\n signed_policy: false,\n drm_policy: false,\n })\n // If video quality level switches to plus, add back in default plus features\n }\n return Object.assign({}, prev, {\n video_quality: action.value,\n static_renditions: sanitizeStaticRenditions(pluginConfig.static_renditions || []),\n max_resolution_tier: pluginConfig.max_resolution_tier,\n text_tracks: [...autoTextTracks, ...(prev.text_tracks || [])],\n })\n\n case 'static_renditions':\n case 'max_resolution_tier':\n case 'normalize_audio':\n case 'signed_policy':\n return Object.assign({}, prev, {[action.action]: action.value})\n case 'public_policy':\n return Object.assign({}, prev, {[action.action]: action.value})\n case 'drm_policy':\n return Object.assign({}, prev, {[action.action]: action.value})\n case 'watermark':\n return Object.assign({}, prev, {watermark: action.value})\n // Updating individual tracks\n case 'track': {\n const text_tracks = [...prev.text_tracks]\n const target_track_i = text_tracks.findIndex(({_id}) => _id === action.id)\n switch (action.subAction) {\n case 'add':\n // Exit early if track already exists\n if (target_track_i !== -1) break\n text_tracks.push({\n _id: action.id,\n ...action.value,\n } as AutogeneratedTextTrack)\n break\n case 'update':\n if (target_track_i === -1) break\n text_tracks[target_track_i] = {\n ...text_tracks[target_track_i],\n ...action.value,\n } as UploadTextTrack\n break\n case 'delete':\n if (target_track_i === -1) break\n text_tracks.splice(target_track_i, 1)\n break\n }\n return Object.assign({}, prev, {text_tracks})\n }\n default:\n return prev\n }\n },\n {\n video_quality: pluginConfig.video_quality,\n max_resolution_tier: pluginConfig.max_resolution_tier,\n static_renditions: sanitizeStaticRenditions(pluginConfig.static_renditions || []),\n signed_policy: secrets.enableSignedUrls && pluginConfig.defaultSigned,\n public_policy: pluginConfig.defaultPublic,\n drm_policy: pluginConfig.defaultDrm && !!secrets.drmConfigId,\n normalize_audio: pluginConfig.normalize_audio,\n text_tracks: autoTextTracks,\n } as UploadConfig,\n )\n\n // Video validations\n const [validationError, setValidationError] = useState<string | null>(null)\n const MAX_FILE_SIZE = pluginConfig.maxAssetFileSize\n const MAX_DURATION_SECONDS = pluginConfig.maxAssetDuration\n\n const {fileSize, isLoadingFileSize, canSkipFileSizeValidation} = useFetchFileSize(\n stagedUpload,\n MAX_FILE_SIZE,\n )\n const {videoAssetMetadata, setVideoAssetMetadata, isLoadingMetadata} =\n useMediaMetadata(stagedUpload)\n\n useEffect(() => {\n if (fileSize) {\n setVideoAssetMetadata((old) => ({...old, size: fileSize}))\n }\n }, [fileSize, setVideoAssetMetadata])\n\n useEffect(() => {\n const validateDuration = (duration: number) => {\n if (MAX_DURATION_SECONDS && duration > MAX_DURATION_SECONDS) {\n setValidationError(\n `Video duration (${formatSeconds(duration)}) exceeds maximum allowed duration of ${formatSeconds(MAX_DURATION_SECONDS)}`,\n )\n return false\n }\n return true\n }\n\n const validateFileSize = (size: number): boolean => {\n if (MAX_FILE_SIZE === undefined || size <= MAX_FILE_SIZE) {\n return true\n }\n\n setValidationError(\n `File size (${formatBytes(size)}) exceeds maximum allowed size of ${formatBytes(MAX_FILE_SIZE)}`,\n )\n return false\n }\n\n const validateDrmAvailability = (isAudioOnly: boolean) => {\n if (config.drm_policy && isAudioOnly) {\n setValidationError('Audio-only asset cannot be DRM protected')\n return false\n }\n return true\n }\n\n let valid = true\n if (videoAssetMetadata?.size) {\n valid = valid && (canSkipFileSizeValidation || validateFileSize(videoAssetMetadata.size))\n }\n if (videoAssetMetadata?.duration) {\n valid = valid && validateDuration(videoAssetMetadata.duration)\n }\n if (videoAssetMetadata?.isAudioOnly != undefined) {\n valid = valid && validateDrmAvailability(videoAssetMetadata.isAudioOnly)\n }\n if (valid) {\n // oxlint-disable-next-line react/react-compiler\n setValidationError(null)\n }\n }, [\n MAX_FILE_SIZE,\n MAX_DURATION_SECONDS,\n canSkipFileSizeValidation,\n videoAssetMetadata?.duration,\n videoAssetMetadata?.size,\n videoAssetMetadata?.height,\n videoAssetMetadata?.width,\n videoAssetMetadata,\n config.drm_policy,\n validationError,\n ])\n\n // If user-provided config is disabled, begin the upload immediately with\n // the developer-specified values from the schema or config or defaults.\n // This can include auto-generated subtitles!\n const {disableTextTrackConfig, disableUploadConfig} = pluginConfig\n const skipConfig = disableTextTrackConfig && disableUploadConfig\n useEffect(() => {\n if (skipConfig) {\n const {settings, watermark} = formatUploadConfig(config, secrets, {\n videoAspectRatio: videoAssetMetadata?.aspectRatio,\n })\n startUpload(settings, watermark)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n if (skipConfig) return null\n\n const basicConfig = config.video_quality !== 'plus' && config.video_quality !== 'premium'\n const playbackPolicySelected = config.public_policy || config.signed_policy || config.drm_policy\n const maxSupportedResolution = RESOLUTION_TIERS.findIndex(\n (rt) => rt.value === pluginConfig.max_resolution_tier,\n )\n return (\n <Dialog\n animate\n open\n id=\"upload-configuration\"\n zOffset={1000}\n width={1}\n header=\"Configure Mux Upload\"\n onClose={onClose}\n >\n <Stack padding={4} space={2}>\n {(validationError || watermarkValidationError) && (\n <Card padding={3} tone=\"critical\" radius={2} marginBottom={2}>\n <Flex gap={2} align=\"flex-start\">\n <ErrorOutlineIcon width={20} height={20} />\n <Stack space={2}>\n <Text size={1} weight=\"semibold\">\n Validation Error\n </Text>\n <Text size={1}>{validationError || watermarkValidationError}</Text>\n </Stack>\n </Flex>\n </Card>\n )}\n <Label size={3}>FILE TO UPLOAD</Label>\n <Card\n tone=\"transparent\"\n border\n padding={3}\n paddingY={4}\n style={{borderRadius: '0.1865rem'}}\n >\n <Flex gap={2}>\n <DocumentVideoIcon fontSize=\"2em\" />\n <Stack space={2}>\n <Text textOverflow=\"ellipsis\" as=\"h2\" size={3}>\n {stagedUpload.type === 'file' ? stagedUpload.files[0]!.name : stagedUpload.url}\n </Text>\n <Text as=\"p\" size={1} muted>\n {stagedUpload.type === 'file'\n ? `Direct File Upload (${formatBytes(stagedUpload.files[0]!.size)})`\n : (() => {\n if (videoAssetMetadata?.size) {\n return `File From URL (${formatBytes(videoAssetMetadata.size)})`\n }\n if (isLoadingFileSize) {\n return 'File From URL (Loading size...)'\n }\n return 'File From URL (Unknown size)'\n })()}\n </Text>\n {stagedUpload.type === 'file' && (\n <Stack space={1}>\n {isLoadingMetadata && (\n <Text as=\"p\" size={1} muted>\n Reading video metadata...\n </Text>\n )}\n {videoAssetMetadata?.duration && !validationError && (\n <Text as=\"p\" size={1} muted>\n Duration: {formatSeconds(videoAssetMetadata.duration)}\n </Text>\n )}\n </Stack>\n )}\n </Stack>\n </Flex>\n </Card>\n {!disableUploadConfig && (\n <Stack space={3} paddingBottom={2}>\n <FormField\n path={[]}\n title=\"Video Quality Level\"\n description={\n <>\n The video quality level informs the cost, quality, and available platform features\n for the asset.{' '}\n <a\n href=\"https://docs.mux.com/guides/use-encoding-tiers\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n See the Mux guide for more details.\n </a>\n </>\n }\n >\n <Flex gap={3}>\n {VIDEO_QUALITY_LEVELS.map(({value, label}) => {\n const inputId = `${id}--encodingtier-${value}`\n return (\n <Flex key={value} align=\"center\" gap={2}>\n <Radio\n checked={config.video_quality === value}\n name=\"asset-encodingtier\"\n onChange={(e) =>\n dispatch({\n action: 'video_quality' as const,\n value: e.currentTarget.value as UploadConfig['video_quality'],\n })\n }\n value={value}\n id={inputId}\n />\n <Text as=\"label\" htmlFor={inputId}>\n {label}\n </Text>\n </Flex>\n )\n })}\n </Flex>\n </FormField>\n\n {!basicConfig && (\n <>\n <FormField title=\"Additional Configuration\" path={[]}>\n <Stack space={3}>\n <PlaybackPolicy id={id} config={config} secrets={secrets} dispatch={dispatch} />\n {maxSupportedResolution > 0 && (\n <ResolutionTierSelector\n id={id}\n config={config}\n dispatch={dispatch}\n maxSupportedResolution={maxSupportedResolution}\n />\n )}\n <StaticRenditionSelector id={id} config={config} dispatch={dispatch} />\n {!disableTextTrackConfig && (\n <TextTracksEditor\n tracks={config.text_tracks}\n dispatch={dispatch}\n defaultLang={pluginConfig.defaultAutogeneratedSubtitleLang}\n />\n )}\n </Stack>\n </FormField>\n <WatermarkSection\n config={config}\n dispatch={dispatch}\n stagedUpload={stagedUpload}\n videoAssetMetadata={videoAssetMetadata}\n watermarkPreviewContainerRef={watermarkPreviewContainerRef}\n watermarkPreviewVideoRef={watermarkPreviewVideoRef}\n onValidationChange={setWatermarkValidationError}\n />\n </>\n )}\n </Stack>\n )}\n\n <Box marginTop={4}>\n <Button\n disabled={\n (!basicConfig && !playbackPolicySelected) ||\n validationError !== null ||\n isLoadingMetadata ||\n (isLoadingFileSize && !canSkipFileSizeValidation)\n }\n icon={UploadIcon}\n text=\"Upload\"\n tone=\"positive\"\n onClick={() => {\n if (!validationError) {\n const {settings, watermark} = formatUploadConfig(config, secrets, {\n videoAspectRatio: videoAssetMetadata?.aspectRatio,\n })\n startUpload(settings, watermark)\n }\n }}\n />\n </Box>\n </Stack>\n </Dialog>\n )\n}\n\nfunction setAdvancedPlaybackPolicy(\n config: UploadConfig,\n secrets: Secrets,\n): MuxNewAssetSettings['advanced_playback_policies'] {\n const advanced_playback_policies: MuxNewAssetSettings['advanced_playback_policies'] = []\n if (config.public_policy) {\n advanced_playback_policies.push({policy: 'public'})\n }\n if (config.signed_policy) {\n advanced_playback_policies.push({policy: 'signed'})\n }\n if (config.drm_policy) {\n if (secrets.drmConfigId)\n advanced_playback_policies.push({\n policy: 'drm',\n drm_configuration_id: secrets.drmConfigId ?? undefined,\n })\n else {\n console.error('Selected DRM Policy but missing DRM Configuration Id')\n }\n }\n return advanced_playback_policies\n}\n\nfunction formatUploadConfig(\n config: UploadConfig,\n secrets: Secrets,\n options?: {videoAspectRatio?: number | null},\n): {\n settings: MuxNewAssetSettings\n watermark?: WatermarkConfig\n} {\n const generated_subtitles = config.text_tracks\n .filter<AutogeneratedTextTrack>(isAutogeneratedTrack)\n .map<{name: string; language_code: SupportedMuxLanguage}>((track) => ({\n name: track.name,\n language_code: track.language_code,\n }))\n\n const inputs: NonNullable<MuxNewAssetSettings['input']> = [\n {\n type: 'video',\n generated_subtitles: generated_subtitles.length > 0 ? generated_subtitles : undefined,\n },\n ...config.text_tracks.filter<CustomTextTrack>(isCustomTextTrack).reduce(\n (acc, track) => {\n if (track.language_code && track.file && track.name) {\n acc.push({\n url: track.file.contents,\n type: 'text',\n text_type: track.type === 'subtitles' ? 'subtitles' : undefined,\n language_code: track.language_code,\n name: track.name,\n closed_captions: track.type === 'captions',\n })\n }\n return acc\n },\n [] as NonNullable<MuxNewAssetSettings['input']>,\n ),\n ]\n\n if (config.watermark?.imageUrl) {\n const watermarkForMux: WatermarkConfig = {...config.watermark, enabled: true}\n const overlaySettings = convertWatermarkToMuxOverlay(watermarkForMux, {\n videoAspectRatio: options?.videoAspectRatio ?? undefined,\n units: 'px',\n })\n if (overlaySettings) {\n inputs.push({\n url: config.watermark.imageUrl,\n overlay_settings: overlaySettings,\n })\n }\n }\n\n return {\n settings: {\n input: inputs,\n static_renditions:\n config.static_renditions.length > 0\n ? config.static_renditions.map((resolution) => ({resolution}))\n : undefined,\n advanced_playback_policies: setAdvancedPlaybackPolicy(config, secrets),\n max_resolution_tier: config.max_resolution_tier,\n video_quality: config.video_quality,\n normalize_audio: config.normalize_audio,\n },\n watermark: config.watermark?.imageUrl ? {...config.watermark, enabled: true} : undefined,\n }\n}\n\nfunction WatermarkSection({\n config,\n dispatch,\n stagedUpload,\n videoAssetMetadata,\n watermarkPreviewContainerRef,\n watermarkPreviewVideoRef,\n onValidationChange,\n}: {\n config: UploadConfig\n dispatch: (action: UploadConfigurationStateAction) => void\n stagedUpload: StagedUpload\n videoAssetMetadata: VideoAssetMetadata | null\n watermarkPreviewContainerRef: React.RefObject<HTMLDivElement | null>\n watermarkPreviewVideoRef: React.RefObject<HTMLVideoElement | null>\n onValidationChange: (error: string | null) => void\n}) {\n if (videoAssetMetadata?.isAudioOnly !== false) return null\n return (\n <FormField\n path={[]}\n title=\"Watermark\"\n description={\n <>\n Add a watermark overlay to your video using Mux's native watermark support.{' '}\n <a\n href=\"https://www.mux.com/docs/guides/add-watermarks-to-your-videos\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Learn more about Mux watermarks.\n </a>\n </>\n }\n >\n <Stack space={3}>\n <WatermarkControls\n watermark={config.watermark || {enabled: false}}\n onChange={(watermark) => {\n dispatch({action: 'watermark', value: watermark})\n }}\n onValidationChange={onValidationChange}\n previewContainerRef={watermarkPreviewContainerRef}\n previewVideoRef={watermarkPreviewVideoRef}\n />\n {config.watermark?.imageUrl &&\n stagedUpload.type === 'file' &&\n // Canvas preview is only shown in \"Canvas\" mode (no explicit overlay_settings)\n !config.watermark.overlay_settings && (\n <WatermarkPreview\n stagedUpload={stagedUpload}\n watermark={config.watermark}\n videoAspectRatio={videoAssetMetadata.aspectRatio}\n onWatermarkChange={(watermark) => {\n dispatch({action: 'watermark', value: watermark})\n }}\n previewContainerRef={watermarkPreviewContainerRef}\n videoRef={watermarkPreviewVideoRef}\n />\n )}\n </Stack>\n </FormField>\n )\n}\n\n// Memoized preview component to prevent unnecessary re-renders\nconst WatermarkPreview = memo(function WatermarkPreview({\n stagedUpload,\n watermark,\n onWatermarkChange,\n videoAspectRatio,\n previewContainerRef,\n videoRef,\n}: {\n stagedUpload: StagedUpload\n watermark: WatermarkConfig\n onWatermarkChange: (watermark: WatermarkConfig) => void\n videoAspectRatio?: number | null\n previewContainerRef: React.RefObject<HTMLDivElement | null>\n videoRef: React.RefObject<HTMLVideoElement | null>\n}) {\n // Initialize video source only once\n useEffect(() => {\n if (videoRef.current && stagedUpload.type === 'file') {\n const file = stagedUpload.files[0]\n const url = URL.createObjectURL(file!)\n videoRef.current.src = url\n\n return () => {\n URL.revokeObjectURL(url)\n }\n }\n return undefined\n }, [stagedUpload, videoRef])\n\n const isVertical =\n videoAspectRatio !== null && videoAspectRatio !== undefined && videoAspectRatio < 1\n\n return (\n <Card\n tone=\"transparent\"\n border\n style={{\n overflow: 'hidden',\n // For vertical videos, center the preview and limit its width\n display: 'flex',\n justifyContent: 'center',\n }}\n >\n {/* Inner container that exactly matches the video aspect ratio - no padding, no letterbox */}\n <div\n ref={previewContainerRef}\n style={{\n position: 'relative',\n // For vertical videos: limit width so the preview doesn't get too tall\n // For horizontal videos: use full width\n width: isVertical ? 'auto' : '100%',\n aspectRatio: videoAspectRatio ? String(videoAspectRatio) : '16/9',\n ...(isVertical ? {height: '400px', maxHeight: '50vh'} : {minHeight: '200px'}),\n overflow: 'hidden',\n }}\n >\n <video\n ref={videoRef}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n height: '100%',\n objectFit: 'fill',\n display: 'block',\n }}\n />\n <DraggableWatermark\n watermark={watermark}\n onChange={onWatermarkChange}\n containerRef={previewContainerRef as React.RefObject<HTMLDivElement>}\n videoElementRef={videoRef as React.RefObject<HTMLVideoElement>}\n />\n </div>\n </Card>\n )\n})\n","import {rem} from '@sanity/ui'\nimport type {ComponentType} from 'react'\nimport {css, styled} from 'styled-components'\n\nimport {focusRingBorderStyle, focusRingStyle} from './helpers'\n\nexport function withFocusRing<Props>(component: ComponentType<Props>) {\n return styled(component as unknown as any)<Props & {$border?: boolean}>((props) => {\n const border = {\n width: props.$border ? 1 : 0,\n color: 'var(--card-border-color)',\n }\n\n return css`\n --card-focus-box-shadow: ${focusRingBorderStyle(border)};\n\n border-radius: ${rem(props.theme.sanity.radius[1]!)};\n outline: none;\n box-shadow: var(--card-focus-box-shadow);\n\n &:focus {\n --card-focus-box-shadow: ${focusRingStyle({\n base: props.theme.sanity.color.base,\n border,\n focusRing: props.theme.sanity.focusRing,\n })};\n }\n `\n })\n}\n","import {Card, type CardTone} from '@sanity/ui'\nimport {useCallback, useRef} from 'react'\nimport {styled} from 'styled-components'\n\nimport {withFocusRing} from './withFocusRing'\n\nconst UploadCardWithFocusRing = withFocusRing(Card)\n\ninterface UploadCardProps {\n tone?: CardTone\n children: React.ReactNode\n onPaste: React.ClipboardEventHandler<HTMLInputElement>\n onDrop: React.DragEventHandler<HTMLDivElement>\n onDragOver: React.DragEventHandler<HTMLDivElement>\n onDragLeave: React.DragEventHandler<HTMLDivElement>\n onDragEnter: React.DragEventHandler<HTMLDivElement>\n}\nexport function UploadCard({\n children,\n tone,\n onPaste,\n onDrop,\n onDragEnter,\n onDragLeave,\n onDragOver,\n ref,\n}: UploadCardProps & {ref?: React.Ref<HTMLDivElement>}) {\n const inputRef = useRef<HTMLInputElement>(null)\n const handleKeyDown = useCallback<React.KeyboardEventHandler<HTMLDivElement>>((event) => {\n const target = event.target as HTMLElement\n\n // Don't steal focus when pasting into the VTT input\n if (target.closest('#vtt-url')) {\n return\n }\n\n if ((event.ctrlKey || event.metaKey) && event.key === 'v') {\n inputRef.current!.focus()\n }\n }, [])\n\n return (\n <UploadCardWithFocusRing\n tone={tone}\n ref={ref}\n padding={0}\n radius={2}\n shadow={0}\n tabIndex={0}\n onKeyDown={handleKeyDown}\n onPaste={onPaste}\n onDrop={onDrop}\n onDragEnter={onDragEnter}\n onDragLeave={onDragLeave}\n onDragOver={onDragOver}\n >\n <HiddenInput ref={inputRef} />\n {children}\n </UploadCardWithFocusRing>\n )\n}\n\nconst HiddenInput = styled.input.attrs({type: 'text'})`\n position: absolute;\n border: 0;\n color: white;\n opacity: 0;\n\n &:focus {\n outline: none;\n }\n`\n","import {Button, type ButtonProps} from '@sanity/ui'\nimport {useCallback, useId, useRef} from 'react'\nimport {styled} from 'styled-components'\n\nconst HiddenInput = styled.input`\n overflow: hidden;\n width: 0.1px;\n height: 0.1px;\n opacity: 0;\n position: absolute;\n z-index: -1;\n`\n\nconst Label = styled.label`\n position: relative;\n`\n\nexport interface FileInputButtonProps extends Omit<ButtonProps, 'onSelect'> {\n onSelect: (files: FileList) => void\n accept: string\n}\nexport const FileInputButton = ({onSelect, accept, ...props}: FileInputButtonProps) => {\n const inputId = `FileSelect${useId()}`\n const inputRef = useRef<HTMLInputElement>(null)\n const handleSelect = useCallback<React.ChangeEventHandler<HTMLInputElement>>(\n (event) => {\n if (onSelect) {\n onSelect(event.target.files!)\n }\n },\n [onSelect],\n )\n const handleButtonClick = useCallback(() => inputRef.current?.click(), [])\n return (\n <Label htmlFor={inputId}>\n <HiddenInput\n accept={accept}\n ref={inputRef}\n tabIndex={0}\n type=\"file\"\n id={inputId}\n onChange={handleSelect}\n value=\"\"\n />\n <Button\n onClick={handleButtonClick}\n mode=\"default\"\n tone=\"primary\"\n style={{width: '100%'}}\n {...props}\n />\n </Label>\n )\n}\n","import {DocumentVideoIcon} from '@sanity/icons/DocumentVideo'\nimport {PlugIcon} from '@sanity/icons/Plug'\nimport {SearchIcon} from '@sanity/icons/Search'\nimport {UploadIcon} from '@sanity/icons/Upload'\nimport {Button, Card, Flex, Inline, Text} from '@sanity/ui'\nimport {useCallback} from 'react'\n\nimport {useAccessControl} from '../hooks/useAccessControl'\nimport type {SetDialogState} from '../hooks/useDialogState'\nimport {type PluginConfig} from '../util/types'\nimport {FileInputButton, type FileInputButtonProps} from './FileInputButton'\n\nfunction formatAcceptString(accept: string): string {\n return accept\n .split(',')\n .map((type) => type.trim().replace('/*', ''))\n .join(' or ')\n}\n\ninterface UploadPlaceholderProps {\n setDialogState: SetDialogState\n readOnly: boolean\n hovering: boolean\n needsSetup: boolean\n onSelect: FileInputButtonProps['onSelect']\n config: PluginConfig\n accept: string\n}\nexport default function UploadPlaceholder(props: UploadPlaceholderProps) {\n const {setDialogState, readOnly, onSelect, hovering, needsSetup, accept} = props\n const handleBrowse = useCallback(() => setDialogState('select-video'), [setDialogState])\n const handleConfigureApi = useCallback(() => setDialogState('secrets'), [setDialogState])\n const {hasConfigAccess} = useAccessControl(props.config)\n\n return (\n <Card\n sizing=\"border\"\n tone={readOnly ? 'transparent' : 'inherit'}\n border\n radius={2}\n paddingX={3}\n paddingY={1}\n style={hovering ? {borderColor: 'transparent'} : undefined}\n >\n <Flex\n align=\"center\"\n justify=\"space-between\"\n gap={4}\n direction={['column', 'column', 'row']}\n paddingY={2}\n sizing=\"border\"\n >\n <Flex align=\"center\" justify=\"flex-start\" gap={2} flex={1}>\n <Flex justify=\"center\">\n <Text muted>\n <DocumentVideoIcon />\n </Text>\n </Flex>\n <Flex justify=\"center\">\n <Text size={1} muted>\n Drag {formatAcceptString(accept)} file or paste URL here\n </Text>\n </Flex>\n </Flex>\n <Inline space={2}>\n <FileInputButton\n accept={accept}\n mode=\"bleed\"\n tone=\"default\"\n icon={UploadIcon}\n text=\"Upload\"\n onSelect={onSelect}\n />\n <Button mode=\"bleed\" icon={SearchIcon} text=\"Select\" onClick={handleBrowse} />\n\n {hasConfigAccess && (\n <Button\n padding={3}\n radius={3}\n tone={needsSetup ? 'critical' : undefined}\n onClick={handleConfigureApi}\n icon={PlugIcon}\n mode=\"bleed\"\n title=\"Configure plugin credentials\"\n />\n )}\n </Inline>\n </Flex>\n </Card>\n )\n}\n","import {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {Button, type CardTone, Flex, Text, useToast} from '@sanity/ui'\nimport {useCallback, useEffect, useReducer, useRef, useState} from 'react'\nimport {type Observable, Subject, Subscription} from 'rxjs'\nimport {takeUntil, tap} from 'rxjs/operators'\nimport type {SanityClient} from 'sanity'\nimport {PatchEvent, set, setIfMissing} from 'sanity'\n\nimport {uploadFile, uploadUrl} from '../actions/upload'\nimport {DialogStateProvider} from '../context/DialogStateContext'\nimport {type DialogState, type SetDialogState} from '../hooks/useDialogState'\nimport {isServerError, isValidUrl} from '../util/asserters'\nimport {extractDroppedFiles} from '../util/extractFiles'\nimport {hasPlaybackPolicy} from '../util/getPlaybackPolicy'\nimport type {\n MuxInputProps,\n MuxNewAssetSettings,\n PluginConfig,\n Secrets,\n VideoAssetDocument,\n} from '../util/types'\nimport InputBrowser from './InputBrowser'\nimport Player from './Player'\nimport PlayerActionsMenu from './PlayerActionsMenu'\nimport UploadConfiguration from './UploadConfiguration'\nimport {UploadCard} from './Uploader.styled'\nimport UploadPlaceholder from './UploadPlaceholder'\nimport {UploadProgress} from './UploadProgress'\n\ninterface Props extends Pick<MuxInputProps, 'onChange' | 'readOnly'> {\n config: PluginConfig\n client: SanityClient\n secrets: Secrets\n asset: VideoAssetDocument | null | undefined\n dialogState: DialogState\n setDialogState: SetDialogState\n needsSetup: boolean\n}\n\nexport type StagedUpload = {type: 'file'; files: FileList | File[]} | {type: 'url'; url: string}\ntype UploadStatus = {\n progress: number\n file?: {name: string | undefined; type: string}\n uuid?: string\n url?: string\n}\n\ninterface State {\n stagedUpload: StagedUpload | null\n uploadStatus: UploadStatus | null\n error: Error | null\n}\n\nconst INITIAL_STATE: State = {\n stagedUpload: null,\n uploadStatus: null,\n error: null,\n}\n\ntype UploadFileEvent = ReturnType<typeof uploadFile> extends Observable<infer T> ? T : never\ntype UploadUrlEvent = ReturnType<typeof uploadUrl> extends Observable<infer T> ? T : never\ntype UploaderStateAction =\n | {action: 'stageUpload'; input: NonNullable<State['stagedUpload']>}\n | {action: 'commitUpload'}\n | ({action: 'progressInfo'} & (\n | Extract<UploadFileEvent, {type: 'uuid' | 'file'}>\n | Extract<UploadUrlEvent, {type: 'url'}>\n ))\n | {action: 'progress'; percent: number}\n | {action: 'error'; error: Error; settings: MuxNewAssetSettings}\n | {action: 'complete' | 'reset'}\n\n/**\n * The main interface for inputting a Mux Video. It handles staging an upload\n * file, setting its configuration, displaying upload progress, and showing\n * the preview player.\n */\nexport default function Uploader(props: Props) {\n const toast = useToast()\n const containerRef = useRef<HTMLDivElement>(null)\n\n const dragEnteredEls = useRef<EventTarget[]>([])\n const [dragState, setDragState] = useState<'valid' | 'invalid' | null>(null)\n\n const cancelUploadButton = useRef(\n (() => {\n const events$ = new Subject()\n return {\n observable: events$.asObservable(),\n handleClick: (event: React.MouseEvent<HTMLButtonElement>) => events$.next(event),\n }\n })(),\n ).current\n\n const uploadRef = useRef<Subscription | null>(null)\n const uploadingDocumentId = useRef<string | null>(null)\n const [state, dispatch] = useReducer(\n // oxlint-disable-next-line react/react-compiler\n (prev: State, action: UploaderStateAction) => {\n switch (action.action) {\n case 'stageUpload':\n return Object.assign({}, INITIAL_STATE, {stagedUpload: action.input})\n case 'commitUpload':\n return Object.assign({}, prev, {uploadStatus: {progress: 0}})\n case 'progressInfo': {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {type, action: _, ...payload} = action\n return Object.assign({}, prev, {\n uploadStatus: {\n ...prev.uploadStatus,\n progress: prev.uploadStatus!.progress,\n ...payload,\n },\n } satisfies Pick<typeof prev, 'uploadStatus'>)\n }\n case 'progress':\n return Object.assign({}, prev, {\n uploadStatus: {\n ...prev.uploadStatus,\n progress: action.percent,\n },\n } satisfies Pick<typeof prev, 'uploadStatus'>)\n case 'reset':\n case 'complete':\n // Clear upload observable on completion\n uploadRef.current?.unsubscribe()\n uploadRef.current = null\n uploadingDocumentId.current = null\n return INITIAL_STATE\n case 'error': {\n // Clear upload observable on error\n uploadRef.current?.unsubscribe()\n uploadRef.current = null\n uploadingDocumentId.current = null\n\n let error = action.error\n if (isServerError(action.error) && hasPlaybackPolicy(action.settings, 'drm')) {\n error = new Error(\n 'Unknown Error while uploading DRM protected content. Make sure your DRM configuration ID is valid and set correctly',\n )\n }\n\n return Object.assign({}, INITIAL_STATE, {error: error})\n }\n default:\n return prev\n }\n },\n {\n stagedUpload: null,\n uploadStatus: null,\n error: null,\n },\n )\n\n // Make sure we close out the upload observer on dismount\n // and cleanup orphaned documents if upload was in progress\n useEffect(() => {\n const cleanup = () => {\n // Cancel subscription\n if (uploadRef.current && !uploadRef.current.closed) {\n uploadRef.current.unsubscribe()\n }\n\n // Delete orphaned document if upload was in progress and document is different from the saved asset\n if (uploadingDocumentId.current && props.asset?._id !== uploadingDocumentId.current) {\n const docId = uploadingDocumentId.current\n uploadingDocumentId.current = null\n\n props.client.delete(docId).catch((err) => {\n console.warn('Failed to cleanup orphaned upload document:', err)\n })\n }\n }\n\n const handleBeforeUnload = () => {\n cleanup()\n }\n\n window.addEventListener('beforeunload', handleBeforeUnload)\n window.addEventListener('pagehide', handleBeforeUnload)\n\n return () => {\n window.removeEventListener('beforeunload', handleBeforeUnload)\n window.removeEventListener('pagehide', handleBeforeUnload)\n cleanup()\n }\n }, [props.client, props.asset?._id])\n\n /* -------------------------------------------------------------------------- */\n /* Uploading */\n /* -------------------------------------------------------------------------- */\n\n /**\n * Begins a file or URL upload with the staged files or URL.\n *\n * Should only be called from the UploadConfiguration component, which provides\n * the Mux configuration for the direct asset upload.\n *\n * @param settings The Mux new_asset_settings object to send to Sanity\n * @param watermark Optional watermark configuration\n * @returns\n */\n const startUpload = (\n settings: MuxNewAssetSettings,\n watermark?: import('../util/types').WatermarkConfig,\n ) => {\n const {stagedUpload} = state\n if (!stagedUpload || uploadRef.current) return\n dispatch({action: 'commitUpload'})\n let uploadObservable: Observable<UploadFileEvent | UploadUrlEvent>\n switch (stagedUpload.type) {\n case 'url':\n uploadObservable = uploadUrl({\n client: props.client,\n url: stagedUpload.url,\n settings,\n watermark,\n })\n break\n case 'file':\n uploadObservable = uploadFile({\n client: props.client,\n file: stagedUpload.files[0]!,\n settings,\n watermark,\n }).pipe(\n takeUntil(\n cancelUploadButton.observable.pipe(\n tap(() => {\n if (uploadingDocumentId.current) {\n void props.client.delete(uploadingDocumentId.current)\n uploadingDocumentId.current = null\n }\n }),\n ),\n ),\n )\n break\n }\n uploadRef.current = uploadObservable.subscribe({\n next: (event) => {\n switch (event.type) {\n case 'uuid':\n // Track the document ID for cleanup on unmount\n uploadingDocumentId.current = event.uuid\n dispatch({action: 'progressInfo', ...event})\n break\n case 'file':\n case 'url':\n dispatch({action: 'progressInfo', ...event})\n break\n case 'progress':\n dispatch({action: 'progress', percent: event.percent})\n break\n case 'success':\n dispatch({action: 'progress', percent: 100})\n uploadingDocumentId.current = null\n props.onChange(\n PatchEvent.from([\n setIfMissing({asset: {}}),\n set({_type: 'reference', _weak: true, _ref: event.asset._id}, ['asset']),\n ]),\n )\n break\n case 'pause':\n case 'resume':\n default:\n break\n }\n },\n complete: () => dispatch({action: 'complete'}),\n error: (error) => dispatch({action: 'error', error, settings}),\n })\n }\n\n const invalidFileToast = useCallback(() => {\n toast.push({\n status: 'error',\n title: `Invalid file type. Accepted types: ${props.config.acceptedMimeTypes?.join(', ')}`,\n })\n }, [props.config.acceptedMimeTypes, toast])\n\n /**\n * Validates if any file in the provided FileList or File array has an unsupported MIME type\n * @param files - FileList or File array to validate\n * @returns true if any file has an invalid MIME type, false if all files are valid\n */\n const isInvalidFile = (files: FileList | File[]) => {\n const isInvalid = Array.from(files).some((file) => {\n return !props.config.acceptedMimeTypes?.some((acceptedType) => {\n // Convert mime type pattern to regex (e.g., 'audio/*' -> /^audio\\/.*$/)\n const pattern = `^${acceptedType.replace('*', '.*')}$`\n return new RegExp(pattern).test(file.type)\n })\n })\n\n return isInvalid\n }\n\n /* -------------------------- Upload Initialization ------------------------- */\n // The below populate the uploadInput state field, which then triggers the\n // upload configuration, or the startUpload function if no config is required.\n\n // Stages an upload from the file selector\n const handleUpload = (files: FileList | File[]) => {\n if (isInvalidFile(files)) return\n dispatch({\n action: 'stageUpload',\n input: {type: 'file', files},\n })\n }\n\n // Stages and validates an upload from pasting an asset URL\n const handlePaste: React.ClipboardEventHandler<HTMLInputElement> = (event) => {\n const target = event.target as HTMLElement\n\n // Ignore paste coming from the VTT URL input\n if (target.closest('#vtt-url')) {\n return\n }\n\n event.preventDefault()\n event.stopPropagation()\n const clipboardData =\n event.clipboardData || (window as Window & {clipboardData?: DataTransfer}).clipboardData\n const url = clipboardData?.getData('text')?.trim()\n if (!isValidUrl(url)) {\n toast.push({status: 'error', title: 'Invalid URL for Mux video input.'})\n return\n }\n dispatch({action: 'stageUpload', input: {type: 'url', url: url}})\n }\n\n // Stages and validates an upload from dragging+dropping files or folders\n const handleDrop: React.DragEventHandler<HTMLDivElement> = (event) => {\n event.preventDefault()\n event.stopPropagation()\n if (dragState === 'invalid') {\n invalidFileToast()\n setDragState(null)\n return\n }\n setDragState(null)\n void extractDroppedFiles(event.nativeEvent.dataTransfer!).then((files) => {\n dispatch({\n action: 'stageUpload',\n input: {type: 'file', files},\n })\n })\n }\n\n /* ------------------------------- Drag State ------------------------------- */\n\n const handleDragOver: React.DragEventHandler<HTMLDivElement> = (event) => {\n event.preventDefault()\n event.stopPropagation()\n }\n\n const handleDragEnter: React.DragEventHandler<HTMLDivElement> = (event) => {\n event.stopPropagation()\n dragEnteredEls.current.push(event.target)\n const type = event.dataTransfer.items?.[0]?.type\n const mimeTypes = props.config.acceptedMimeTypes\n\n // Check if the dragged file type matches any of the accepted mime types\n const isValidType = mimeTypes?.some((acceptedType) => {\n // Convert mime type pattern to regex (e.g., 'video/*' -> /^video\\/.*$/)\n const pattern = `^${acceptedType.replace('*', '.*')}$`\n return new RegExp(pattern).test(type!)\n })\n\n setDragState(isValidType ? 'valid' : 'invalid')\n }\n\n const handleDragLeave: React.DragEventHandler<HTMLDivElement> = (event) => {\n event.stopPropagation()\n const idx = dragEnteredEls.current.indexOf(event.target)\n if (idx > -1) {\n dragEnteredEls.current.splice(idx, 1)\n }\n if (dragEnteredEls.current.length === 0) {\n setDragState(null)\n }\n }\n\n /* -------------------------------- Rendering ------------------------------- */\n\n // Upload has errored\n if (state.error !== null) {\n const error = state.error\n return (\n <Flex gap={3} direction=\"column\" justify=\"center\" align=\"center\">\n <Text size={5} muted>\n <ErrorOutlineIcon />\n </Text>\n <Text>Something went wrong</Text>\n {error instanceof Error && error.message && (\n <Text size={1} muted weight=\"semibold\" style={{textAlign: 'center'}}>\n {error.message}\n </Text>\n )}\n <Button text=\"Upload another file\" onClick={() => dispatch({action: 'reset'})} />\n </Flex>\n )\n }\n\n // Upload is in progress\n if (state.uploadStatus !== null) {\n const {uploadStatus} = state\n return (\n <UploadProgress\n // oxlint-disable-next-line react/react-compiler\n onCancel={cancelUploadButton.handleClick}\n progress={uploadStatus.progress}\n filename={uploadStatus.file?.name || uploadStatus.url}\n />\n )\n }\n\n // Upload needs configuration\n if (state.stagedUpload !== null) {\n return (\n <UploadConfiguration\n stagedUpload={state.stagedUpload}\n pluginConfig={props.config}\n secrets={props.secrets}\n startUpload={startUpload}\n onClose={() => dispatch({action: 'reset'})}\n />\n )\n }\n\n // Default: No staged upload\n let tone: CardTone | undefined\n if (dragState) tone = dragState === 'valid' ? 'positive' : 'critical'\n\n const acceptMimeString = props.config?.acceptedMimeTypes?.length\n ? props.config.acceptedMimeTypes.join(',')\n : 'video/*, audio/*'\n\n return (\n <>\n <UploadCard\n tone={tone}\n onDrop={handleDrop}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDragEnter={handleDragEnter}\n onPaste={handlePaste}\n ref={containerRef}\n >\n {props.asset ? (\n <DialogStateProvider\n dialogState={props.dialogState}\n setDialogState={props.setDialogState}\n >\n <Player\n readOnly={props.readOnly}\n asset={props.asset}\n onChange={props.onChange}\n config={props.config}\n buttons={\n <PlayerActionsMenu\n accept={acceptMimeString}\n asset={props.asset}\n dialogState={props.dialogState}\n setDialogState={props.setDialogState}\n onChange={props.onChange}\n onSelect={handleUpload}\n readOnly={props.readOnly}\n config={props.config}\n />\n }\n />\n </DialogStateProvider>\n ) : (\n <UploadPlaceholder\n accept={acceptMimeString}\n hovering={dragState !== null}\n onSelect={handleUpload}\n readOnly={!!props.readOnly}\n setDialogState={props.setDialogState}\n needsSetup={props.needsSetup}\n config={props.config}\n />\n )}\n </UploadCard>\n {props.dialogState === 'select-video' && (\n <InputBrowser\n config={props.config}\n asset={props.asset}\n onChange={props.onChange}\n setDialogState={props.setDialogState}\n />\n )}\n </>\n )\n}\n","import {Card} from '@sanity/ui'\nimport {memo, Suspense} from 'react'\n\nimport {useAccessControl} from '../hooks/useAccessControl'\nimport {useAssetDocumentValues} from '../hooks/useAssetDocumentValues'\nimport {useClient} from '../hooks/useClient'\nimport {useDialogState} from '../hooks/useDialogState'\nimport {useMuxPolling} from '../hooks/useMuxPolling'\nimport {useSecretsDocumentValues} from '../hooks/useSecretsDocumentValues'\nimport type {MuxInputProps, PluginConfig} from '../util/types'\nimport {ConfigureApiDialog} from './ConfigureApi'\nimport ErrorBoundaryCard from './ErrorBoundaryCard'\nimport {InputFallback} from './Input.styled'\nimport Onboard from './Onboard'\nimport Uploader from './Uploader'\n\nexport interface InputProps extends MuxInputProps {\n config: PluginConfig\n}\nconst Input = (props: InputProps) => {\n const client = useClient()\n const secretDocumentValues = useSecretsDocumentValues()\n const assetDocumentValues = useAssetDocumentValues(props.value?.asset)\n const poll = useMuxPolling(props.readOnly ? undefined : assetDocumentValues?.value || undefined)\n const [dialogState, setDialogState] = useDialogState()\n const {hasConfigAccess} = useAccessControl(props.config)\n\n const error = secretDocumentValues.error || assetDocumentValues.error || poll.error /*||\n // @TODO move errored logic to Uploader, where handleRemoveVideo can be called\n (assetDocumentValues.value?.status === 'errored'\n ? new Error(assetDocumentValues.value.data?.errors?.messages?.join(' '))\n : undefined)\n // */\n if (error) {\n // @TODO deal with it more gracefully\n throw error\n }\n const isLoading = secretDocumentValues.isLoading || assetDocumentValues.isLoading\n\n return (\n <Card>\n <ErrorBoundaryCard schemaType={props.schemaType}>\n <Suspense fallback={<InputFallback />}>\n {isLoading ? (\n <InputFallback />\n ) : (\n <>\n {secretDocumentValues.value.needsSetup && !assetDocumentValues.value ? (\n <Onboard setDialogState={setDialogState} config={props.config} />\n ) : (\n <Uploader\n {...props}\n config={props.config}\n onChange={props.onChange}\n client={client}\n secrets={secretDocumentValues.value.secrets}\n asset={assetDocumentValues.value}\n dialogState={dialogState}\n setDialogState={setDialogState}\n needsSetup={secretDocumentValues.value.needsSetup}\n />\n )}\n\n {dialogState === 'secrets' && hasConfigAccess && (\n <ConfigureApiDialog\n setDialogState={setDialogState}\n secrets={secretDocumentValues.value.secrets}\n />\n )}\n </>\n )}\n </Suspense>\n </ErrorBoundaryCard>\n </Card>\n )\n}\n\nexport default memo(Input)\n","import Input from './components/Input'\nimport VideoThumbnail from './components/VideoThumbnail'\nimport type {MuxInputProps, PluginConfig, VideoAssetDocument} from './util/types'\n\nexport function muxVideoCustomRendering(config: PluginConfig) {\n return {\n components: {\n input: (props: MuxInputProps) => (\n <Input config={{...config, ...props.schemaType.options}} {...props} />\n ),\n },\n preview: {\n select: {\n filename: 'asset.filename',\n playbackId: 'asset.playbackId',\n status: 'asset.status',\n assetId: 'asset.assetId',\n thumbTime: 'asset.thumbTime',\n data: 'asset.data',\n },\n prepare: (asset: Partial<VideoAssetDocument>) => {\n const {filename, playbackId, status} = asset\n return {\n title: filename || playbackId || '',\n subtitle: status ? `status: ${status}` : null,\n media: asset.playbackId ? <VideoThumbnail asset={asset} width={64} /> : null,\n }\n },\n },\n }\n}\n","export const muxVideoSchema = {\n name: 'mux.video',\n type: 'object',\n title: 'Video asset reference',\n fields: [\n {\n title: 'Video',\n name: 'asset',\n type: 'reference',\n weak: true,\n to: [{type: 'mux.videoAsset'}],\n },\n ],\n}\n\nconst muxTrack = {\n name: 'mux.track',\n type: 'object',\n fields: [\n {type: 'string', name: 'id'},\n {type: 'string', name: 'type'},\n {type: 'number', name: 'max_width'},\n {type: 'number', name: 'max_frame_rate'},\n {type: 'number', name: 'duration'},\n {type: 'number', name: 'max_height'},\n {type: 'string', name: 'language_code'},\n {type: 'string', name: 'name'},\n {type: 'string', name: 'status'},\n {type: 'string', name: 'text_source'},\n {type: 'string', name: 'text_type'},\n ],\n}\n\nconst muxPlaybackId = {\n name: 'mux.playbackId',\n type: 'object',\n fields: [\n {type: 'string', name: 'id'},\n {type: 'string', name: 'policy'},\n ],\n}\n\nconst muxStaticRenditionFile = {\n name: 'mux.staticRenditionFile',\n type: 'object',\n fields: [\n {type: 'string', name: 'name'},\n {type: 'string', name: 'ext'},\n {type: 'number', name: 'height'},\n {type: 'number', name: 'width'},\n {type: 'number', name: 'bitrate'},\n {type: 'string', name: 'filesize'},\n {type: 'string', name: 'type'},\n {type: 'string', name: 'status'},\n {type: 'string', name: 'resolution_tier'},\n {type: 'string', name: 'resolution'},\n {type: 'string', name: 'id'},\n {type: 'string', name: 'passthrough'},\n ],\n}\n\nconst muxStaticRenditions = {\n name: 'mux.staticRenditions',\n type: 'object',\n fields: [\n {type: 'string', name: 'status'},\n {\n name: 'files',\n type: 'array',\n of: [{type: 'mux.staticRenditionFile'}],\n },\n ],\n}\n\nconst muxMasterFile = {\n name: 'mux.masterFile',\n type: 'object',\n fields: [\n {type: 'string', name: 'status'},\n {type: 'string', name: 'url'},\n ],\n}\n\nconst muxAssetData = {\n name: 'mux.assetData',\n title: 'Mux asset data',\n type: 'object',\n fields: [\n {\n type: 'string',\n name: 'resolution_tier',\n },\n {\n type: 'string',\n name: 'upload_id',\n },\n {\n type: 'string',\n name: 'created_at',\n },\n {\n type: 'string',\n name: 'id',\n },\n {\n type: 'string',\n name: 'status',\n },\n {\n type: 'string',\n name: 'max_stored_resolution',\n },\n {\n type: 'string',\n name: 'passthrough',\n },\n {\n type: 'string',\n name: 'encoding_tier',\n },\n {\n type: 'string',\n name: 'video_quality',\n },\n {\n type: 'string',\n name: 'master_access',\n },\n {\n type: 'string',\n name: 'aspect_ratio',\n },\n {\n type: 'number',\n name: 'duration',\n },\n {\n type: 'number',\n name: 'max_stored_frame_rate',\n },\n {\n type: 'string',\n name: 'mp4_support',\n },\n {\n type: 'string',\n name: 'max_resolution_tier',\n },\n {\n name: 'tracks',\n type: 'array',\n of: [{type: 'mux.track'}],\n },\n {\n name: 'playback_ids',\n type: 'array',\n of: [{type: 'mux.playbackId'}],\n },\n {\n name: 'static_renditions',\n type: 'mux.staticRenditions',\n },\n {\n name: 'master',\n type: 'mux.masterFile',\n },\n ],\n}\n\nconst muxVideoAsset = {\n name: 'mux.videoAsset',\n type: 'document',\n title: 'Video asset',\n fields: [\n {\n type: 'string',\n name: 'status',\n },\n {\n type: 'string',\n name: 'assetId',\n },\n {\n type: 'string',\n name: 'playbackId',\n },\n {\n type: 'string',\n name: 'filename',\n },\n {\n type: 'number',\n name: 'thumbTime',\n },\n {\n type: 'mux.assetData',\n name: 'data',\n },\n ],\n}\n\nexport const schemaTypes = [\n muxTrack,\n muxPlaybackId,\n muxStaticRenditionFile,\n muxStaticRenditions,\n muxMasterFile,\n muxAssetData,\n muxVideoAsset,\n]\n","import {definePlugin} from 'sanity'\n\nimport createStudioTool, {DEFAULT_TOOL_CONFIG} from '../components/StudioTool'\nimport {muxVideoCustomRendering} from '../plugin'\nimport {muxVideoSchema, schemaTypes} from '../schema'\nimport type {PluginConfig, StaticRenditionResolution} from '../util/types'\nexport type {VideoAssetDocument} from '../util/types'\n\nexport const defaultConfig: PluginConfig = {\n static_renditions: [],\n mp4_support: 'none',\n video_quality: 'plus',\n max_resolution_tier: '1080p',\n normalize_audio: false,\n defaultPublic: true,\n defaultSigned: false,\n defaultDrm: false,\n tool: DEFAULT_TOOL_CONFIG,\n allowedRolesForConfiguration: [],\n acceptedMimeTypes: ['video/*', 'audio/*'],\n}\n\n/**\n * Converts legacy mp4_support configuration to static_renditions format\n */\nfunction convertLegacyConfig(config: Partial<PluginConfig>): {\n static_renditions: StaticRenditionResolution[]\n} {\n // If static_renditions is already provided, use it\n if (config.static_renditions && config.static_renditions.length > 0) {\n return {static_renditions: config.static_renditions}\n }\n\n // Convert legacy mp4_support to static_renditions\n if (config.mp4_support === 'standard') {\n return {static_renditions: ['highest']}\n }\n\n return {static_renditions: []}\n}\n\nexport const muxInput = definePlugin<Partial<PluginConfig> | void>((userConfig) => {\n // TODO: Remove this on next major version when we end support for encoding_tier\n if (typeof userConfig === 'object' && 'encoding_tier' in userConfig) {\n const deprecated_encoding_tier = userConfig.encoding_tier\n if (!userConfig.video_quality) {\n if (deprecated_encoding_tier === 'baseline') {\n userConfig.video_quality = 'basic'\n }\n if (deprecated_encoding_tier === 'smart') {\n userConfig.video_quality = 'plus'\n }\n }\n }\n const config: PluginConfig = {\n ...defaultConfig,\n ...userConfig,\n ...convertLegacyConfig(userConfig || {}),\n }\n return {\n name: 'mux-input',\n schema: {\n types: [\n ...schemaTypes,\n {\n ...muxVideoSchema,\n ...muxVideoCustomRendering(config),\n },\n ],\n },\n tools: config.tool === false ? undefined : [createStudioTool(config)],\n }\n})\n"],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"index.js","names":["useClient","useSanityClient","path","FormField","useClient","secretsId","FormField","Image","useClient","useClient","useClient","LANGUAGE_OPTIONS","useClient","useClient","useClient","useClient","useClient","useClient","useClient","FormField","useClient","uuid","generateUuid","SelectAsset","useClient","HiddenInput","Label","PlayerActionsMenu","useClient","ErrorBoundaryCard","Input"],"sources":["../src/components/icons/ToolIcon.tsx","../src/util/types.ts","../src/context/DrmPlaybackWarningContext.tsx","../src/hooks/useClient.ts","../src/util/createSearchFilter.ts","../src/hooks/useAssets.ts","../src/hooks/useDialogState.ts","../src/util/pluginVersion.ts","../src/actions/secrets.ts","../src/hooks/useSaveSecrets.ts","../src/util/constants.ts","../src/hooks/useSecretsDocumentValues.ts","../src/hooks/useSecretsFormState.ts","../src/util/readSecrets.ts","../src/components/MuxLogo.tsx","../src/components/ConfigureApi.styled.tsx","../src/components/FormField.tsx","../src/components/ConfigureApi.tsx","../src/util/assetTitlePlaceholder.ts","../src/util/parsers.ts","../src/actions/assets.ts","../src/hooks/useMuxAssets.ts","../src/hooks/useImportMuxAssets.ts","../src/hooks/useInView.ts","../src/util/getPlaybackPolicy.ts","../src/util/generateJwt.ts","../src/util/createUrlParamsObject.ts","../src/util/getAnimatedPosterSrc.ts","../src/util/getPosterSrc.ts","../src/util/tryWithSuspend.ts","../src/components/VideoThumbnail.tsx","../src/components/ImportVideosFromMux.tsx","../src/components/PageSelector.tsx","../src/util/addKeysToMuxData.ts","../src/hooks/useResyncMuxMetadata.ts","../src/components/ResyncMetadata.tsx","../src/components/SelectSortOptions.tsx","../src/components/SpinnerBox.tsx","../src/components/IconInfo.tsx","../src/components/icons/Resolution.tsx","../src/components/icons/StopWatch.tsx","../src/hooks/useMezzanine.ts","../src/components/MezzanineExplanation.tsx","../src/components/Mezzanine.tsx","../src/hooks/useResyncAsset.ts","../src/util/textTracks.ts","../src/components/AddCaptionDialog.tsx","../src/components/EditCaptionDialog.tsx","../src/components/TextTracksManager.tsx","../src/context/DialogStateContext.tsx","../src/util/getVideoSrc.ts","../src/components/CaptionsDialog.tsx","../src/util/formatSeconds.ts","../src/components/EditThumbnailDialog.tsx","../src/components/icons/Audio.tsx","../src/components/MezzanineDialog.tsx","../src/components/VideoPlayer.tsx","../src/components/documentPreview/MissingSchemaType.tsx","../src/components/documentPreview/TimeAgo.tsx","../src/components/documentPreview/DraftStatus.tsx","../src/components/documentPreview/PublishedStatus.tsx","../src/components/documentPreview/PaneItemPreview.tsx","../src/components/documentPreview/DocumentPreview.tsx","../src/components/VideoDetails/VideoReferences.tsx","../src/components/VideoDetails/DeleteDialog.tsx","../src/hooks/useDocReferences.ts","../src/util/getVideoMetadata.ts","../src/components/VideoDetails/useVideoDetails.ts","../src/components/VideoDetails/VideoDetails.tsx","../src/components/VideoMetadata.tsx","../src/components/VideoInBrowser.tsx","../src/components/VideosBrowser.tsx","../src/components/StudioTool.tsx","../src/hooks/useAccessControl.ts","../src/hooks/useAssetDocumentValues.ts","../src/hooks/useMuxPolling.ts","../src/components/ErrorBoundaryCard.tsx","../src/components/Input.styled.tsx","../src/components/Onboard.tsx","../src/clients/upChunkObservable.ts","../src/util/formatDriveShareLink.ts","../src/util/roundPxString.ts","../src/actions/upload.ts","../src/util/asserters.ts","../src/util/extractFiles.ts","../src/components/SelectAsset.tsx","../src/components/InputBrowser.tsx","../src/hooks/useCancelUpload.ts","../src/components/Player.styled.tsx","../src/components/UploadProgress.tsx","../src/components/Player.tsx","../src/components/withFocusRing/helpers.ts","../src/components/FileInputMenuItem.styled.tsx","../src/components/FileInputMenuItem.tsx","../src/components/PlayerActionsMenu.tsx","../src/hooks/useFetchFileSize.ts","../src/hooks/useMediaMetadata.ts","../src/util/convertWatermarkToMux.ts","../src/util/formatBytes.ts","../src/components/DraggableWatermark.tsx","../src/components/TextTracksEditor.tsx","../src/components/uploadConfiguration/PlaybackPolicyOption.tsx","../src/components/uploadConfiguration/PlaybackPolicyWarning.tsx","../src/components/uploadConfiguration/PlaybackPolicy.tsx","../src/components/uploadConfiguration/ResolutionTierSelector.tsx","../src/components/uploadConfiguration/StaticRenditionSelector.tsx","../src/components/UploadConfiguration.tsx","../src/components/withFocusRing/withFocusRing.ts","../src/components/Uploader.styled.tsx","../src/components/FileInputButton.tsx","../src/components/UploadPlaceholder.tsx","../src/components/Uploader.tsx","../src/components/Input.tsx","../src/plugin.tsx","../src/schema.ts","../src/_exports/index.ts"],"sourcesContent":["/**\n * Icon of a monitor with a play button.\n * Credits: material design icons & react-icons\n */\nconst ToolIcon = () => (\n <svg\n stroke=\"currentColor\"\n fill=\"currentColor\"\n strokeWidth=\"0\"\n viewBox=\"0 0 24 24\"\n height=\"1em\"\n width=\"1em\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path d=\"M21 3H3c-1.11 0-2 .89-2 2v12c0 1.1.89 2 2 2h5v2h8v-2h5c1.1 0 1.99-.9 1.99-2L23 5c0-1.11-.9-2-2-2zm0 14H3V5h18v12zm-5-6l-7 4V7z\" />\n </svg>\n)\n\nexport default ToolIcon\n","import type MuxPlayerElement from '@mux/mux-player'\nimport type {ObjectInputProps} from 'sanity'\nimport type {PartialDeep} from 'type-fest'\n\n/**\n * All static rendition resolution options supported by Mux\n */\nexport type StaticRenditionResolution =\n | 'highest'\n | 'audio-only'\n | '270p'\n | '360p'\n | '480p'\n | '540p'\n | '720p'\n | '1080p'\n | '1440p'\n | '2160p'\n\nexport interface MuxInputConfig {\n /**\n * Enable static renditions by default. Can be overwritten on a per-asset basis.\n * Supports:\n * - Standard mode: 'highest' (up to 4K MP4) and/or 'audio-only' (M4A)\n * - Advanced mode: Specific resolutions ('270p', '360p', '480p', '540p', '720p', '1080p', '1440p', '2160p') and/or 'audio-only'\n *\n * **Important**: 'highest' cannot be mixed with specific resolutions. If both are provided, only 'highest' will be used.\n *\n * @see {@link https://docs.mux.com/guides/video/enable-static-mp4-renditions}\n * @defaultValue []\n */\n static_renditions: StaticRenditionResolution[]\n\n /**\n * @deprecated Use `static_renditions` instead. This field is kept for backward compatibility.\n * Enable static renditions by setting this to 'standard'. Can be overwritten on a per-asset basis.\n * Requires `\"video_quality\": \"plus\"`\n * @see {@link https://docs.mux.com/guides/video/enable-static-mp4-renditions#why-enable-mp4-support}\n * @defaultValue 'none'\n */\n mp4_support: 'none' | 'standard'\n\n /**\n * Max resolution tier can be used to control the maximum resolution_tier your asset is encoded, stored, and streamed at.\n * Requires `\"video_quality\": \"plus\"`\n * @see {@link https://docs.mux.com/guides/stream-videos-in-4k}\n * @defaultValue '1080p'\n */\n max_resolution_tier: '2160p' | '1440p' | '1080p'\n\n /**\n * @deprecated Use {@link video_quality}\n * <br>\n * The encoding tier informs the cost, quality, and available platform features for the asset.\n * @see {@link https://docs.mux.com/guides/use-encoding-tiers}\n * @defaultValue 'smart'\n */\n encoding_tier?: 'baseline' | 'smart'\n\n /**\n * The video quality level informs the cost, quality, and available platform features for the asset.\n * @see {@link https://www.mux.com/docs/guides/use-video-quality-levels}\n * @defaultValue 'plus'\n */\n video_quality: 'basic' | 'plus' | 'premium'\n\n /**\n * Normalize the audio track loudness level.\n * @see {@link https://docs.mux.com/guides/adjust-audio-levels#how-to-turn-on-audio-normalization}\n * @defaultValue false\n */\n normalize_audio: boolean\n\n /**\n * Enables signed URLs by default, if you configured them with your API token.\n * @see {@link https://docs.mux.com/guides/secure-video-playback}\n * @defaultValue false\n */\n defaultSigned?: boolean\n\n /**\n * Enables public URLs by default.\n * @defaultValue true\n */\n defaultPublic?: boolean\n\n /**\n * Enables DRM Protection by default, if you configured your DRM Configuration Id.\n * @see {@link https://www.mux.com/docs/guides/protect-videos-with-drm}\n * @defaultValue true\n */\n defaultDrm?: boolean\n\n /**\n * Auto-generate captions for these languages by default.\n * Requires `\"video_quality\": \"plus\"`\n *\n * @see {@link https://docs.mux.com/guides/add-autogenerated-captions-and-use-transcripts}\n * @deprecated use `defaultAutogeneratedSubtitleLang` instead. Only a single autogenerated\n */\n defaultAutogeneratedSubtitleLangs?: SupportedMuxLanguage[]\n\n /**\n * Auto-generate captions for this language by default. Users can still\n * Requires `\"video_quality\": \"plus\"`\n *\n * @see {@link https://docs.mux.com/guides/add-autogenerated-captions-and-use-transcripts}\n */\n defaultAutogeneratedSubtitleLang?: SupportedMuxLanguage\n\n /**\n * Whether or not to allow content editors to override asset upload\n * configuration settings when uploading a video to Mux.\n *\n * @see {@link https://docs.mux.com/guides/secure-video-playback}\n * @defaultValue false\n */\n disableUploadConfig?: boolean\n\n /**\n * Whether or not to allow content editors to add text tracks alongside their\n * asset when uploading a video to Mux.\n *\n * @see {@link https://docs.mux.com/guides/secure-video-playback}\n * @defaultValue false\n */\n disableTextTrackConfig?: boolean\n\n /**\n * Whether or not to show the playback warning when trying to watch DRM content for the first time.\n *\n * @defaultValue false\n */\n disableDrmPlaybackWarning?: boolean\n\n /**\n * The mime types that are accepted by the input.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/accept}\n * @defaultValue ['video/*','audio/*']\n\n */\n acceptedMimeTypes?: ('audio/*' | 'video/*')[]\n\n /**\n * Maximum file size allowed for video uploads in bytes.\n * If not specified, no file size validation will be performed.\n *\n * @example 1024 * 1024 * 1024 // 1 GB\n * @defaultValue undefined\n */\n maxAssetFileSize?: number\n\n /**\n * Maximum video duration allowed in seconds.\n * If not specified, no duration validation will be performed.\n *\n * @example 2 * 60 * 60 // 2 hours\n * @defaultValue undefined\n */\n maxAssetDuration?: number\n\n /**\n * HLS.js configuration options to be passed to the Mux Player.\n * These options allow you to customize the underlying HLS.js playback engine behavior.\n *\n * @see {@link https://github.com/video-dev/hls.js/blob/master/docs/API.md#fine-tuning}\n * @defaultValue undefined\n * @example\n * ```ts\n * {\n * maxBufferLength: 30,\n * lowLatencyMode: true,\n * capLevelToPlayerSize: true\n * }\n * ```\n */\n hlsConfig?: MuxPlayerElement['_hlsConfig']\n}\n\nexport interface PluginConfig extends MuxInputConfig {\n /**\n * How the videos browser should appear as a studio tool in Sanity's top navigation\n *\n * Pass `false` if you want to disable it.\n * @defaultValue {title: 'Videos', icon: VideoIcon}\n **/\n tool:\n | false\n | {\n title?: string\n icon?: React.ComponentType\n }\n\n /**\n * The roles that are allowed to configure the plugin.\n *\n * If not set, all roles will be allowed to configure the plugin.\n * @defaultValue []\n */\n allowedRolesForConfiguration: string[]\n}\n\nexport const SUPPORTED_MUX_LANGUAGES = [\n {label: 'English', code: 'en', state: 'Stable'},\n {label: 'Spanish', code: 'es', state: 'Stable'},\n {label: 'Italian', code: 'it', state: 'Stable'},\n {label: 'Portuguese', code: 'pt', state: 'Stable'},\n {label: 'German', code: 'de', state: 'Stable'},\n {label: 'French', code: 'fr', state: 'Stable'},\n {label: 'Polish', code: 'pl', state: 'Beta'},\n {label: 'Russian', code: 'ru', state: 'Beta'},\n {label: 'Dutch', code: 'nl', state: 'Beta'},\n {label: 'Catalan', code: 'ca', state: 'Beta'},\n {label: 'Turkish', code: 'tr', state: 'Beta'},\n {label: 'Swedish', code: 'sv', state: 'Beta'},\n {label: 'Ukrainian', code: 'uk', state: 'Beta'},\n {label: 'Norwegian', code: 'no', state: 'Beta'},\n {label: 'Finnish', code: 'fi', state: 'Beta'},\n {label: 'Slovak', code: 'sk', state: 'Beta'},\n {label: 'Greek', code: 'el', state: 'Beta'},\n {label: 'Czech', code: 'cs', state: 'Beta'},\n {label: 'Croatian', code: 'hr', state: 'Beta'},\n {label: 'Danish', code: 'da', state: 'Beta'},\n {label: 'Romanian', code: 'ro', state: 'Beta'},\n {label: 'Bulgarian', code: 'bg', state: 'Beta'},\n] as const\n\nexport const SUPPORTED_MUX_LANGUAGES_VALUES = SUPPORTED_MUX_LANGUAGES.map((l) => l.code)\n\nexport type SupportedMuxLanguage = (typeof SUPPORTED_MUX_LANGUAGES_VALUES)[number]\n\nexport interface TextTrack {\n _id: string\n name: string\n}\n\nexport interface AutogeneratedTextTrack extends TextTrack {\n type: 'autogenerated'\n language_code: SupportedMuxLanguage\n}\n\nexport interface CustomTextTrack extends TextTrack {\n type: 'subtitles' | 'captions'\n language_code: string\n file: {\n contents: string\n type: string\n name: string\n size: number\n }\n}\n\nexport function isCustomTextTrack(track: Partial<UploadTextTrack>): track is CustomTextTrack {\n return track.type !== 'autogenerated'\n}\n\nexport function isAutogeneratedTrack(\n track: Partial<UploadTextTrack>,\n): track is AutogeneratedTextTrack {\n return track.type === 'autogenerated'\n}\n\nexport type UploadTextTrack = AutogeneratedTextTrack | CustomTextTrack\n\n/**\n * Watermark configuration for UI (draggable position)\n */\nexport interface WatermarkConfig {\n enabled: boolean\n imageUrl?: string\n /**\n * Aspect ratio (width / height) of the watermark image.\n * Used to convert between our center-based UI coords and Mux overlay margins.\n */\n imageAspectRatio?: number\n /**\n * Optional explicit Mux `overlay_settings`.\n * When set, these values should be used as-is for the upload request and preview.\n * @see {@link https://www.mux.com/docs/guides/add-watermarks-to-your-videos}\n */\n overlay_settings?: MuxOverlaySettings\n position?: {\n x: number // percentage (0-100)\n y: number // percentage (0-100)\n }\n size?: number // percentage of video width (0-100)\n opacity?: number // 0-1 (converted to percentage string for Mux API)\n}\n\n/**\n * Mux overlay_settings format for watermark API\n * @see {@link https://www.mux.com/docs/guides/add-watermarks-to-your-videos}\n */\nexport interface MuxOverlaySettings {\n vertical_align: 'top' | 'middle' | 'bottom'\n vertical_margin: string // percentage (e.g., \"10%\") or pixels (e.g., \"40px\")\n horizontal_align: 'left' | 'center' | 'right'\n horizontal_margin: string // percentage (e.g., \"10%\") or pixels (e.g., \"40px\")\n width?: string // percentage (e.g., \"25%\") or pixels (e.g., \"80px\")\n height?: string // percentage or pixels\n opacity?: string // percentage string (e.g., \"90%\")\n}\n\nexport interface UploadConfig extends Pick<\n MuxInputConfig,\n 'max_resolution_tier' | 'normalize_audio' | 'video_quality'\n> {\n static_renditions: StaticRenditionResolution[]\n text_tracks: UploadTextTrack[]\n signed_policy: boolean\n public_policy: boolean\n watermark?: WatermarkConfig\n drm_policy: boolean\n}\n\n/**\n * Data sent to Mux to create a new asset.\n * @docs {@link https://docs.mux.com/api-reference#video/operation/create-direct-upload}\n */\nexport interface MuxNewAssetSettings extends Pick<\n MuxInputConfig,\n 'max_resolution_tier' | 'normalize_audio' | 'video_quality'\n> {\n /** Static renditions configuration for downloadable files */\n static_renditions?: {resolution: StaticRenditionResolution}[]\n /** An array of objects that each describe an input file to be used to create the asset.*/\n input?: {\n /** The URL of the file that Mux should download and use. */\n url?: string\n /** Generate subtitle tracks using automatic speech recognition with this configuration. This may only be provided for the first input object (the main input file). */\n generated_subtitles?: {\n /** A name for this subtitle track. */\n name: string\n /** Arbitrary metadata set for the subtitle track. Max 255 characters. */\n passthrough?: string\n /** The language to generate subtitles in. */\n language_code: SupportedMuxLanguage\n }[]\n /** The time offset in seconds from the beginning of the video indicating the clip's starting marker. */\n start_time?: number\n /** The time offset in seconds from the beginning of the video indicating the clip's ending marker. */\n end_time?: number\n /** This parameter is required for text type tracks. */\n type?: 'video' | 'audio' | 'text'\n /** Type of text track. This parameter only supports subtitles value. */\n text_type?: 'subtitles'\n /** The language code value must be a valid BCP 47 specification compliant value. */\n language_code?: string\n /** The name of the track containing a human-readable description. This value must be unique within each group of text or audio track types. */\n name?: string\n /** Indicates the track provides Subtitles for the Deaf or Hard-of-hearing (SDH). */\n closed_captions?: boolean\n /** This optional parameter should be used tracks with type of text and text_type set to subtitles. */\n passthrough?: string\n /** Overlay settings for watermarks. Used when adding a watermark image as a second input. */\n overlay_settings?: MuxOverlaySettings\n }[]\n\n /** An array of playback policy names that you want applied to this asset and available through playback_ids. */\n playback_policy?: PlaybackPolicy[]\n\n /** An array of playback policy objects that you want applied to this asset and available through playback_ids. advanced_playback_policies must be used instead of playback_policies when creating a DRM playback ID. */\n advanced_playback_policies: AdvancedPlaybackPolicy[]\n\n /** Arbitrary user-supplied metadata that will be included in the asset details and related webhooks. */\n passthrough?: string\n}\n\n/** Used by advanced_playback_policies, allows to define DRM config. */\nexport type AdvancedPlaybackPolicy = {\n policy: PlaybackPolicy\n drm_configuration_id?: string\n}\n\nexport interface Secrets {\n token: string | null\n secretKey: string | null\n enableSignedUrls: boolean\n signingKeyId: string | null\n signingKeyPrivate: string | null\n drmConfigId: string | null\n}\n\nexport type MuxImageOrigin = `https://image.mux.com`\nexport type MuxThumbnailUrl = `${MuxImageOrigin}/${string}/thumbnail.png?${string}`\nexport type MuxAnimatedThumbnailUrl = `${MuxImageOrigin}/${string}/animated.gif?${string}`\nexport type MuxVideoOrigin = `https://stream.mux.com`\nexport type MuxVideoUrl = `${MuxVideoOrigin}/${string}.m3u8?${string}`\n\n// 'preserve' by default\n// @url: https://docs.mux.com/guides/video/get-images-from-a-video#thumbnail-query-string-parameters\nexport type FitMode = 'preserve' | 'crop' | 'smartcrop' | 'pad'\n\nexport interface ThumbnailOptions {\n fit_mode?: FitMode\n height?: number\n time?: number\n width?: number\n}\n\nexport interface AnimatedThumbnailOptions {\n // Starting time code for the animation, if no end is set it'll have a 5s duration\n // The start and end timecodes uses `asset.thumbTime` to create an iOS `Live Photo` effect by showing you the 5 secodnds before, and after, the thumb time`\n start?: number\n // End code, can't be longer than 10s after the start code\n end?: number\n // Max 640px, 320px by default\n width?: number\n // Preserves aspect ratio, like width, you can't set both the height and width, max 640\n height?: number\n // The fps is 15 by default, but can go up to 30\n fps?: number\n}\n\nexport interface AssetThumbnailOptions {\n asset: Pick<VideoAssetDocument, 'playbackId' | 'data' | 'thumbTime' | 'filename' | 'assetId'>\n}\n\nexport type PlaybackPolicy = 'signed' | 'public' | 'drm'\n\nexport interface MuxErrors {\n type: string\n messages: string[]\n}\n\nexport interface MuxPlaybackId {\n id: string\n policy: PlaybackPolicy\n}\n\nexport interface MuxVideoTrack {\n type: 'video'\n id: string\n max_width: number\n max_height: number\n // if the fps can't be reliably determined, this will be -1\n max_frame_rate: -1 | number\n // top-level duration is always set, while track level duration is not\n duration?: number\n}\nexport interface MuxAudioTrack {\n type: 'audio'\n id: string\n duration?: number\n max_channels: number\n max_channel_layout: 'stereo' | string\n}\nexport interface MuxTextTrack {\n type: 'text'\n id: string\n text_type?: 'subtitles'\n // https://docs.mux.com/api-reference/video#operation/list-assets:~:text=text%20type%20tracks.-,tracks%5B%5D.,text_source,-string\n text_source?:\n | 'uploaded'\n | 'embedded'\n | 'generated_live'\n | 'generated_live_final'\n | 'generated_vod'\n // BCP 47 language code\n language_code?: 'en' | 'en-US' | string\n // The name of the track containing a human-readable description. The hls manifest will associate a subtitle text track with this value\n name?: 'English' | string\n closed_captions?: boolean\n // Max 255 characters\n passthrough?: string\n status: 'preparing' | 'ready' | 'errored'\n error?: {\n type: string\n messages?: string[]\n }\n}\nexport type MuxTrack = MuxVideoTrack | MuxAudioTrack | MuxTextTrack\n// Typings lifted from https://docs.mux.com/api-reference/video#tag/assets\nexport interface MuxAsset {\n id: string\n /** In seconds (instead of JS's default milliseconds) */\n created_at: string\n status: 'preparing' | 'ready' | 'errored'\n duration: number\n max_stored_resolution: 'Audio only' | 'SD' | 'HD' | 'FHD' | 'UHD'\n max_resolution_tier?: '2160p' | '1440p' | '1080p'\n // if the fps can't be reliably determined, this will be -1\n max_stored_frame_rate: -1 | number\n // The aspect ratio of the asset in the form of width:height, for example 16:9\n aspect_ratio: `${number}:${number}`\n playback_ids: MuxPlaybackId[]\n tracks: MuxTrack[]\n errors?: MuxErrors\n upload_id: string\n is_live?: boolean\n // We use passthrough to set the mux.videoAsset._id of the asset that originally uploaded the video\n passthrough: string\n live_stream_id?: string\n master?: {\n status: 'ready' | 'preparing' | 'errored'\n // Temporary URL to master MP4, expires after 24 hours.\n // Only present once `status` is 'ready'.\n url?: string\n }\n master_access: 'temporary' | 'none'\n mp4_support: 'standard' | 'none'\n // Asset Identifier of the video used as the source for creating the clip.\n source_asset_id?: string\n // Normalize the audio track loudness level. This parameter is only applicable to on-demand (not live) assets., default false\n normalize_audio?: boolean\n // The object does not exist if no static renditions have been requested\n static_renditions?: {\n status: 'ready' | 'preparing' | 'disabled' | 'errored'\n files: {\n name: string\n ext: 'mp4' | 'm4a'\n height: number\n width: number\n bitrate: number\n filesize: string\n type: 'standard' | 'advanced'\n status: 'ready' | 'preparing' | 'skipped' | 'errored'\n resolution_tier?: string\n resolution?: string\n id: string\n passthrough?: string\n }[]\n }\n recording_times?: {\n started_at: string\n duration: number\n type: 'content' | 'slate'\n }[]\n // https://docs.mux.com/guides/video/minimize-processing-time\n non_standard_input_reasons?: {\n video_codec?: string\n audio_codec?: string\n video_gop_size?: 'high'\n video_frame_rate?: string\n video_resolution?: string\n video_bitrate?: 'high'\n pixel_aspect_ratio?: string\n video_edit_list?: 'non-standard'\n audio_edit_list?: 'non-standard'\n unexpected_media_file_parameters?: 'non-standard'\n test?: boolean\n }\n meta?: {\n title?: string\n }\n}\n\nexport interface VideoAssetDocument {\n _id: string\n _type: 'mux.videoAsset'\n _createdAt: string\n _updatedAt?: string\n status?: string\n assetId?: string\n playbackId?: string\n filename?: string\n thumbTime?: number\n // Docs for what goes in `data` https://docs.mux.com/api-reference/video#tag/assets\n data?: PartialDeep<MuxAsset>\n}\n\nexport type Reference = {_type: 'reference'; _ref: string}\n\n// @TODO add Reference, and ReferenceSchemaType in the generic\nexport type MuxInputProps = ObjectInputProps<{\n asset?: Reference\n}>\n","import {Button, Card, Dialog, Stack, Text} from '@sanity/ui'\nimport {createContext, useCallback, useContext, useMemo, useState} from 'react'\n\nimport {type PluginConfig} from '../util/types'\n\nconst LOCAL_STORAGE_HAS_SHOWN_WARNING_KEY = 'mux-plugin-has-shown-drm-playback-warning'\n\ntype DrmPlaybackWarningContextContextProps = {\n hasShownWarning: boolean\n setHasWarnedAboutDrmPlayback: (b: boolean) => void\n}\n\nconst DrmPlaybackWarningContext = createContext<DrmPlaybackWarningContextContextProps>({\n hasShownWarning: false,\n setHasWarnedAboutDrmPlayback: () => {\n return null\n },\n})\n\ninterface DrmPlaybackWarningContextProviderProps {\n config?: PluginConfig\n children: React.ReactNode\n}\n\nexport const DrmPlaybackWarningContextProvider = ({\n config,\n children,\n}: DrmPlaybackWarningContextProviderProps) => {\n const warningDisabled = config?.disableDrmPlaybackWarning ?? false\n const hasWarned: boolean =\n warningDisabled || window.localStorage.getItem(LOCAL_STORAGE_HAS_SHOWN_WARNING_KEY) === 'true'\n const [hasWarnedAboutDrmPlayback, setHasWarnedAboutDrmPlayback] = useState(hasWarned)\n\n const setHasShownWarning = useCallback((b: boolean) => {\n window.localStorage.setItem(LOCAL_STORAGE_HAS_SHOWN_WARNING_KEY, b.toString())\n setHasWarnedAboutDrmPlayback(b)\n }, [])\n\n const value = useMemo(\n () => ({\n hasShownWarning: hasWarnedAboutDrmPlayback,\n setHasWarnedAboutDrmPlayback: setHasShownWarning,\n }),\n [hasWarnedAboutDrmPlayback, setHasShownWarning],\n )\n\n return (\n <DrmPlaybackWarningContext.Provider value={value}>\n {children}\n </DrmPlaybackWarningContext.Provider>\n )\n}\n\nexport const useDrmPlaybackWarningContext = () => {\n const context = useContext(DrmPlaybackWarningContext)\n return context\n}\n\nexport const DRMWarningDialog = ({onClose}: {onClose: () => void}) => {\n const {setHasWarnedAboutDrmPlayback} = useDrmPlaybackWarningContext()\n const _onClose = () => {\n setHasWarnedAboutDrmPlayback(true)\n onClose()\n }\n return (\n <Dialog\n open\n id=\"drm-playback-warn\"\n onClose={_onClose}\n header=\"DRM Playback Warning\"\n footer={\n <Stack padding={3}>\n <Button mode=\"ghost\" tone=\"primary\" onClick={_onClose} text=\"Ok\" />\n </Stack>\n }\n >\n <Stack space={3} padding={3}>\n <Card padding={[3, 3, 3]} radius={2}>\n <Stack space={3}>\n <Text size={1} weight=\"semibold\">\n DRM-protected playback will generate a license with a small associated cost. The\n plugin will attempt to play signed or public playback IDs instead whenever possible.\n </Text>\n </Stack>\n </Card>\n <Card padding={[3, 3, 3]} radius={2} tone=\"suggest\">\n <Stack space={3}>\n <Text size={1} weight=\"semibold\">\n This is a one time warning. If it persists, you can disable it from your plugin\n configuration.\n </Text>\n </Stack>\n </Card>\n </Stack>\n </Dialog>\n )\n}\n","// As it's required to specify the API Version this custom hook ensures it's all using the same version\nimport {useClient as useSanityClient} from 'sanity'\n\nexport const SANITY_API_VERSION = '2024-03-05'\n\nexport function useClient() {\n return useSanityClient({apiVersion: SANITY_API_VERSION})\n}\n","// Adaptation of Sanity's createSearchQuery for our limited use case:\n// https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/core/search/weighted/createSearchQuery.ts\nimport {compact, toLower, trim, uniq, words} from 'lodash'\n\nconst SPECIAL_CHARS = /([^!@#$%^&*(),\\\\/?\";:{}|[\\]+<>\\s-])+/g\nconst STRIP_EDGE_CHARS = /(^[.]+)|([.]+$)/\n\nfunction tokenize(string: string): string[] {\n return (string.match(SPECIAL_CHARS) || []).map((token) => token.replace(STRIP_EDGE_CHARS, ''))\n}\n\nfunction toGroqParams(terms: string[]): Record<string, string> {\n const params: Record<string, string> = {}\n return terms.reduce((acc, term, i) => {\n acc[`t${i}`] = `*${term}*` // \"t\" is short for term\n return acc\n }, params)\n}\n\n/**\n * Convert a string into an array of tokenized terms.\n *\n * Any (multi word) text wrapped in double quotes will be treated as \"phrases\", or separate tokens that\n * will not have its special characters removed.\n * E.g.`\"the\" \"fantastic mr\" fox fox book` =\\> [\"the\", `\"fantastic mr\"`, \"fox\", \"book\"]\n *\n * Phrases wrapped in quotes are assigned relevance scoring differently from regular words.\n *\n * @internal\n */\nfunction extractTermsFromQuery(query: string): string[] {\n const quotedQueries = [] as string[]\n const unquotedQuery = query.replace(/(\"[^\"]*\")/g, (match) => {\n if (words(match).length > 1) {\n quotedQueries.push(match)\n return ''\n }\n return match\n })\n\n // Lowercase and trim quoted queries\n const quotedTerms = quotedQueries.map((str) => trim(toLower(str)))\n\n /**\n * Convert (remaining) search query into an array of deduped, sanitized tokens.\n * All white space and special characters are removed.\n * e.g. \"The saint of Saint-Germain-des-Prés\" =\\> ['the', 'saint', 'of', 'germain', 'des', 'pres']\n */\n const remainingTerms = uniq(compact(tokenize(toLower(unquotedQuery))))\n\n return [...quotedTerms, ...remainingTerms]\n}\n\n/**\n * Create GROQ constraints, given search terms and the full spec of available document types and fields.\n * Essentially a large list of all possible fields (joined by logical OR) to match our search terms against.\n */\nfunction createConstraints(terms: string[], includeAssetId: boolean) {\n const searchPaths = includeAssetId ? ['filename', 'assetId'] : ['filename']\n const constraints = terms\n .map((_term, i) => searchPaths.map((joinedPath) => `${joinedPath} match $t${i}`))\n .filter((constraint) => constraint.length > 0)\n\n return constraints.map((constraint) => `(${constraint.join(' || ')})`)\n}\n\nexport function createSearchFilter(query: string) {\n const terms = extractTermsFromQuery(query)\n\n return {\n filter: createConstraints(terms, query.length >= 8), // if the search is big enough, include the assetId (mux id) in the results\n params: {\n ...toGroqParams(terms),\n },\n }\n}\n","import {useMemo, useState} from 'react'\nimport {\n collate,\n createHookFromObservableFactory,\n type DocumentStore,\n useDocumentStore,\n} from 'sanity'\n\nimport {SANITY_API_VERSION} from '../hooks/useClient'\nimport {createSearchFilter} from '../util/createSearchFilter'\nimport type {VideoAssetDocument} from '../util/types'\n\nexport const ASSET_SORT_OPTIONS = {\n createdDesc: {groq: '_createdAt desc', label: 'Newest first'},\n createdAsc: {groq: '_createdAt asc', label: 'First created (oldest)'},\n filenameAsc: {groq: 'filename asc', label: 'By filename (A-Z)'},\n filenameDesc: {groq: 'filename desc', label: 'By filename (Z-A)'},\n}\n\nexport type SortOption = keyof typeof ASSET_SORT_OPTIONS\n\nconst useAssetDocuments = createHookFromObservableFactory<\n VideoAssetDocument[],\n {\n documentStore: DocumentStore\n sort: SortOption\n searchQuery: string\n }\n>(({documentStore, sort, searchQuery}) => {\n const search = createSearchFilter(searchQuery)\n const filter = [`_type == \"mux.videoAsset\"`, ...search.filter].filter(Boolean).join(' && ')\n\n const sortFragment = ASSET_SORT_OPTIONS[sort].groq\n return documentStore.listenQuery(\n /* groq */ `*[${filter}] | order(${sortFragment})`,\n search.params,\n {\n apiVersion: SANITY_API_VERSION,\n },\n )\n})\n\nexport default function useAssets() {\n const documentStore = useDocumentStore()\n const [sort, setSort] = useState<SortOption>('createdDesc')\n const [searchQuery, setSearchQuery] = useState('')\n\n const [assetDocuments = [], isLoading] = useAssetDocuments(\n useMemo(() => ({documentStore, sort, searchQuery}), [documentStore, sort, searchQuery]),\n )\n\n const assets = useMemo(\n () =>\n // Avoid displaying both drafts & published assets by collating them together and giving preference to drafts\n collate<VideoAssetDocument>(assetDocuments).map(\n (collated) =>\n ({\n ...(collated.draft || collated.published),\n _id: collated.id,\n }) as VideoAssetDocument,\n ),\n [assetDocuments],\n )\n\n return {\n assets,\n isLoading,\n sort,\n searchQuery,\n setSort,\n setSearchQuery,\n }\n}\n","// Handy little state machine to simplify managing which root level dialog to open\n\nimport {useState} from 'react'\n\nexport type DialogState =\n | 'secrets'\n | 'mezzanine'\n | 'select-video'\n | 'edit-thumbnail'\n | 'edit-captions'\n | false\n\nexport function useDialogState() {\n return useState<DialogState>(false)\n}\n\nexport type SetDialogState = ReturnType<typeof useDialogState>[1]\n","export const PLUGIN_VERSION_QUERY = {\n sanityVersion:\n // @ts-expect-error - this constant is search/replaced so must be exact, not accessed with an index signature\n process.env.PKG_VERSION!,\n}\n","import {defer} from 'rxjs'\nimport type {SanityClient} from 'sanity'\n\nimport {PLUGIN_VERSION_QUERY} from '../util/pluginVersion'\n\ninterface SecretsDocument {\n _id: 'secrets.mux'\n _type: 'mux.apiKey'\n token: string\n secretKey: string\n enableSignedUrls: boolean\n signingKeyId: string\n signingKeyPrivate: string\n drmConfigId: string\n}\nexport function saveSecrets(\n client: SanityClient,\n token: string,\n secretKey: string,\n enableSignedUrls: boolean,\n signingKeyId: string,\n signingKeyPrivate: string,\n drmConfigId: string,\n): Promise<SecretsDocument> {\n const doc: SecretsDocument = {\n _id: 'secrets.mux',\n _type: 'mux.apiKey',\n token,\n secretKey,\n enableSignedUrls,\n signingKeyId,\n signingKeyPrivate,\n drmConfigId,\n }\n doc.signingKeyId = enableSignedUrls ? signingKeyId : ''\n doc.signingKeyPrivate = enableSignedUrls ? signingKeyPrivate : ''\n\n return client.createOrReplace(doc)\n}\n\nexport async function createSigningKeys(client: SanityClient) {\n try {\n const {dataset} = client.config()\n const res = await client.request<{\n data: {private_key: string; id: string; created_at: string}\n }>({\n url: `/addons/mux/signing-keys/${dataset}`,\n withCredentials: true,\n method: 'POST',\n query: PLUGIN_VERSION_QUERY,\n })\n return res\n } catch (error: any) {\n console.error('Error creating signing keys', error)\n const message =\n error.response?.statusCode === 401\n ? 'Unauthorized - Failed to create the Signing Key. Please ensure that the token has \"System\" permissions'\n : error.message\n throw new Error(message, {cause: error})\n }\n}\n\nexport function testSecrets(client: SanityClient) {\n const {dataset} = client.config()\n return client.request<{status: boolean}>({\n url: `/addons/mux/secrets/${dataset}/test`,\n withCredentials: true,\n method: 'GET',\n query: PLUGIN_VERSION_QUERY,\n })\n}\n\nexport async function haveValidSigningKeys(\n client: SanityClient,\n signingKeyId: string,\n signingKeyPrivate: string,\n) {\n if (!(signingKeyId && signingKeyPrivate)) {\n return false\n }\n\n const {dataset} = client.config()\n try {\n const res = await client.request<{data: {id: string; created_at: string}}>({\n url: `/addons/mux/signing-keys/${dataset}/${signingKeyId}`,\n withCredentials: true,\n method: 'GET',\n query: PLUGIN_VERSION_QUERY,\n })\n //\n // if this signing key is valid it will return { data: { id: 'xxxx' } }\n //\n return !!(res.data && res.data.id)\n } catch (e) {\n console.error('Error fetching signingKeyId', signingKeyId, 'assuming it is not valid', e)\n return false\n }\n}\n\nexport function testSecretsObservable(client: SanityClient) {\n const {dataset} = client.config()\n return defer(() =>\n client.observable.request<{status: boolean}>({\n url: `/addons/mux/secrets/${dataset}/test`,\n withCredentials: true,\n method: 'GET',\n query: PLUGIN_VERSION_QUERY,\n }),\n )\n}\n","import {useCallback} from 'react'\nimport type {SanityClient} from 'sanity'\n\nimport {createSigningKeys, haveValidSigningKeys, saveSecrets, testSecrets} from '../actions/secrets'\nimport type {Secrets} from '../util/types'\n\nexport const useSaveSecrets = (client: SanityClient, secrets: Secrets) => {\n return useCallback(\n async ({\n token,\n secretKey,\n enableSignedUrls,\n drmConfigId,\n }: Pick<\n Secrets,\n 'token' | 'secretKey' | 'enableSignedUrls' | 'drmConfigId'\n >): Promise<Secrets> => {\n let {signingKeyId, signingKeyPrivate} = secrets\n\n try {\n await saveSecrets(\n client,\n token!,\n secretKey!,\n enableSignedUrls,\n signingKeyId!,\n signingKeyPrivate!,\n drmConfigId!,\n )\n const valid = await testSecrets(client)\n if (!valid?.status && token && secretKey) {\n throw new Error('Invalid secrets')\n }\n } catch (err) {\n console.error('Error while trying to save secrets:', err)\n throw err\n }\n\n if (enableSignedUrls) {\n const hasValidSigningKeys = await haveValidSigningKeys(\n client,\n signingKeyId!,\n signingKeyPrivate!,\n )\n\n if (!hasValidSigningKeys) {\n try {\n const {data} = await createSigningKeys(client)\n signingKeyId = data.id\n signingKeyPrivate = data.private_key\n await saveSecrets(\n client,\n token!,\n secretKey!,\n enableSignedUrls,\n signingKeyId,\n signingKeyPrivate,\n drmConfigId ?? '',\n )\n } catch (err: any) {\n // eslint-disable-next-line no-console\n console.log('Error while creating and saving signing key:', err?.message)\n throw err\n }\n }\n }\n return {\n token,\n secretKey,\n enableSignedUrls,\n signingKeyId,\n signingKeyPrivate,\n drmConfigId,\n }\n },\n [client, secrets],\n )\n}\n","export const name = 'mux-input' as const\n\n// Caching namespace, as suspend-react might be in use by other components on the page we must ensure we don't collide\nexport const cacheNs = 'sanity-plugin-mux-input' as const\n\nexport const muxSecretsDocumentId = 'secrets.mux' as const\n\nexport const DIALOGS_Z_INDEX = 60_000\n\n/** Mux guide explaining the mezzanine (\"master access\") file and how it differs from MP4 renditions. */\nexport const MEZZANINE_LEARN_MORE_URL =\n 'https://www.mux.com/docs/guides/download-for-offline-editing#enable-master-access'\n\nexport const THUMBNAIL_ASPECT_RATIO = 16 / 9\n\n/** To prevent excessive height, thumbnails and input should not go beyond to this aspect ratio. */\nexport const MIN_ASPECT_RATIO = 5 / 4\n\nexport const AUDIO_ASPECT_RATIO = 5 / 1\n","import {useMemo} from 'react'\nimport {useDocumentValues} from 'sanity'\n\nimport {muxSecretsDocumentId} from '../util/constants'\nimport type {Secrets} from '../util/types'\n\nconst path = [\n 'token',\n 'secretKey',\n 'enableSignedUrls',\n 'signingKeyId',\n 'signingKeyPrivate',\n 'drmConfigId',\n]\nexport const useSecretsDocumentValues = () => {\n const {error, isLoading, value} = useDocumentValues<Partial<Secrets> | null | undefined>(\n muxSecretsDocumentId,\n path,\n )\n const cache = useMemo(() => {\n const exists = Boolean(value)\n const secrets: Secrets = {\n token: value?.token || null,\n secretKey: value?.secretKey || null,\n enableSignedUrls: value?.enableSignedUrls || false,\n signingKeyId: value?.signingKeyId || null,\n signingKeyPrivate: value?.signingKeyPrivate || null,\n drmConfigId: value?.drmConfigId || null,\n }\n return {\n isInitialSetup: !exists,\n needsSetup: !secrets?.token || !secrets?.secretKey,\n secrets,\n }\n }, [value])\n\n return {error, isLoading, value: cache}\n}\n","import {useReducer} from 'react'\n\nimport type {Secrets} from '../util/types'\n\nexport interface State extends Pick<\n Secrets,\n 'token' | 'secretKey' | 'enableSignedUrls' | 'drmConfigId'\n> {\n submitting: boolean\n error: string | null\n}\nexport type Action =\n | {type: 'submit'}\n | {type: 'error'; payload: string}\n | {type: 'reset'; payload: Secrets}\n | {type: 'change'; payload: {name: 'token'; value: string}}\n | {type: 'change'; payload: {name: 'secretKey'; value: string}}\n | {type: 'change'; payload: {name: 'enableSignedUrls'; value: boolean}}\n | {type: 'change'; payload: {name: 'drmConfigId'; value: string}}\nfunction init({token, secretKey, enableSignedUrls, drmConfigId}: Secrets): State {\n return {\n submitting: false,\n error: null,\n // Form inputs don't set the state back to null when clearing a field, but uses empty strings\n // This ensures the `dirty` check works correctly\n token: token ?? '',\n secretKey: secretKey ?? '',\n enableSignedUrls: enableSignedUrls ?? false,\n drmConfigId: drmConfigId ?? '',\n }\n}\nfunction reducer(state: State, action: Action) {\n switch (action?.type) {\n case 'submit':\n return {...state, submitting: true, error: null}\n case 'error':\n return {...state, submitting: false, error: action.payload}\n case 'reset':\n return init(action.payload)\n case 'change':\n return {...state, [action.payload.name]: action.payload.value}\n default:\n throw new Error(`Unknown action type: ${(action as unknown as Action)?.type}`)\n }\n}\n\nexport const useSecretsFormState = (secrets: Secrets) => useReducer(reducer, secrets, init)\n","// Utils with a readName prefix are suspendable and should only be called in the render body\n// Not inside event callbacks or a useEffect.\n// They may be called dynamically, unlike useEffect\n\n// @TODO rename to readSigningPair\n\nimport type {SanityClient} from 'sanity'\nimport {suspend} from 'suspend-react'\n\nimport {cacheNs} from '../util/constants'\nimport {type Secrets} from '../util/types'\n\nexport const _id = 'secrets.mux' as const\n\nexport function readSecrets(client: SanityClient): Secrets {\n const {projectId, dataset} = client.config()\n return suspend(async () => {\n const data = await client.fetch(\n /* groq */ `*[_id == $_id][0]{\n token,\n secretKey,\n enableSignedUrls,\n signingKeyId,\n signingKeyPrivate,\n drmConfigId\n }`,\n {_id},\n )\n return {\n token: data?.token || null,\n secretKey: data?.secretKey || null,\n enableSignedUrls: Boolean(data?.enableSignedUrls) || false,\n signingKeyId: data?.signingKeyId || null,\n signingKeyPrivate: data?.signingKeyPrivate || null,\n drmConfigId: data?.drmConfigId || null,\n }\n }, [cacheNs, _id, projectId, dataset])\n}\n","import {useTheme_v2} from '@sanity/ui'\nimport {type CSSProperties, useId, useMemo} from 'react'\n\nexport interface Props {\n height?: number\n}\nexport default function MuxLogo({height = 26}: Props) {\n const id = useId()\n const theme = useTheme_v2()\n const fillColor = theme.color._dark ? 'white' : 'black'\n const titleId = useMemo(() => `${id}-title`, [id])\n\n const pathStyle: CSSProperties = {\n fillRule: 'nonzero',\n }\n\n return (\n <svg\n aria-labelledby={titleId}\n style={{height: `${height}px`}}\n viewBox=\"0 0 1600 500\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n xmlSpace=\"preserve\"\n >\n <g id=\"Layer-1\" fill={fillColor}>\n <path\n d=\"M994.287,93.486c-17.121,-0 -31,-13.879 -31,-31c0,-17.121 13.879,-31 31,-31c17.121,-0 31,13.879 31,31c0,17.121 -13.879,31 -31,31m0,-93.486c-34.509,-0 -62.484,27.976 -62.484,62.486l0,187.511c0,68.943 -56.09,125.033 -125.032,125.033c-68.942,-0 -125.03,-56.09 -125.03,-125.033l0,-187.511c0,-34.51 -27.976,-62.486 -62.485,-62.486c-34.509,-0 -62.484,27.976 -62.484,62.486l0,187.511c0,137.853 112.149,250.003 249.999,250.003c137.851,-0 250.001,-112.15 250.001,-250.003l0,-187.511c0,-34.51 -27.976,-62.486 -62.485,-62.486\"\n style={pathStyle}\n />\n <path\n d=\"M1537.51,468.511c-17.121,-0 -31,-13.879 -31,-31c0,-17.121 13.879,-31 31,-31c17.121,-0 31,13.879 31,31c0,17.121 -13.879,31 -31,31m-275.883,-218.509l-143.33,143.329c-24.402,24.402 -24.402,63.966 0,88.368c24.402,24.402 63.967,24.402 88.369,-0l143.33,-143.329l143.328,143.329c24.402,24.4 63.967,24.402 88.369,-0c24.403,-24.402 24.403,-63.966 0.001,-88.368l-143.33,-143.329l0.001,-0.004l143.329,-143.329c24.402,-24.402 24.402,-63.965 0,-88.367c-24.402,-24.402 -63.967,-24.402 -88.369,-0l-143.329,143.328l-143.329,-143.328c-24.402,-24.401 -63.967,-24.402 -88.369,-0c-24.402,24.402 -24.402,63.965 0,88.367l143.329,143.329l0,0.004Z\"\n style={pathStyle}\n />\n <path\n d=\"M437.511,468.521c-17.121,-0 -31,-13.879 -31,-31c0,-17.121 13.879,-31 31,-31c17.121,-0 31,13.879 31,31c0,17.121 -13.879,31 -31,31m23.915,-463.762c-23.348,-9.672 -50.226,-4.327 -68.096,13.544l-143.331,143.329l-143.33,-143.329c-17.871,-17.871 -44.747,-23.216 -68.096,-13.544c-23.349,9.671 -38.574,32.455 -38.574,57.729l0,375.026c0,34.51 27.977,62.486 62.487,62.486c34.51,-0 62.486,-27.976 62.486,-62.486l0,-224.173l80.843,80.844c24.404,24.402 63.965,24.402 88.369,-0l80.843,-80.844l0,224.173c0,34.51 27.976,62.486 62.486,62.486c34.51,-0 62.486,-27.976 62.486,-62.486l0,-375.026c0,-25.274 -15.224,-48.058 -38.573,-57.729\"\n style={pathStyle}\n />\n </g>\n </svg>\n )\n}\n","import {styled} from 'styled-components'\n\nimport MuxLogo from './MuxLogo'\n\nconst Logo = styled.span`\n display: inline-block;\n height: 0.8em;\n margin-right: 1em;\n transform: translate(0.3em, -0.2em);\n`\n\nexport const Header = () => (\n <>\n <Logo>\n <MuxLogo height={13} />\n </Logo>\n API Credentials\n </>\n)\n","import {Box, Flex, Stack, Text} from '@sanity/ui'\nimport {memo} from 'react'\n\n// @TODO: get rid of this once v3 core is stable\n\nexport interface Props {\n children: React.ReactNode\n title: React.ReactNode\n description?: React.ReactNode\n inputId: string\n}\n\nfunction FormField(props: Props) {\n const {children, title, description, inputId} = props\n\n return (\n <Stack space={1}>\n <Flex align=\"flex-end\">\n <Box flex={1} paddingY={2}>\n <Stack space={2}>\n <Text as=\"label\" htmlFor={inputId} weight=\"semibold\" size={1}>\n {title || <em>Untitled</em>}\n </Text>\n\n {description && (\n <Text muted size={1}>\n {description}\n </Text>\n )}\n </Stack>\n </Box>\n </Flex>\n <div>{children}</div>\n </Stack>\n )\n}\n\nexport default memo(FormField)\n","import {\n Box,\n Button,\n Card,\n Checkbox,\n Code,\n Dialog,\n Flex,\n Inline,\n Stack,\n Text,\n TextInput,\n} from '@sanity/ui'\nimport {useCallback, useEffect, useId, useMemo, useRef} from 'react'\nimport {clear, preload} from 'suspend-react'\n\nimport {useClient} from '../hooks/useClient'\nimport type {SetDialogState} from '../hooks/useDialogState'\nimport {useDialogState} from '../hooks/useDialogState'\nimport {useSaveSecrets} from '../hooks/useSaveSecrets'\nimport {useSecretsDocumentValues} from '../hooks/useSecretsDocumentValues'\nimport {useSecretsFormState} from '../hooks/useSecretsFormState'\nimport {cacheNs, DIALOGS_Z_INDEX} from '../util/constants'\nimport {_id as secretsId} from '../util/readSecrets'\nimport type {Secrets} from '../util/types'\nimport {Header} from './ConfigureApi.styled'\nimport FormField from './FormField'\n\n// Props for the dialog component when used with external state management\nexport interface ConfigureApiDialogProps {\n setDialogState: SetDialogState\n secrets: Secrets\n}\n\nconst fieldNames = ['token', 'secretKey', 'enableSignedUrls', 'drmConfigId'] as const\n\n// Internal dialog component that can be used with external state\nexport function ConfigureApiDialog({secrets, setDialogState}: ConfigureApiDialogProps) {\n const client = useClient()\n const [state, dispatch] = useSecretsFormState(secrets)\n const hasSecretsInitially = useMemo(() => secrets.token && secrets.secretKey, [secrets])\n const handleClose = useCallback(() => setDialogState(false), [setDialogState])\n const dirty = useMemo(\n () =>\n secrets.token !== state.token ||\n secrets.secretKey !== state.secretKey ||\n secrets.enableSignedUrls !== state.enableSignedUrls ||\n secrets.drmConfigId !== state.drmConfigId,\n [secrets, state],\n )\n const id = `ConfigureApi${useId()}`\n const [tokenId, secretKeyId, enableSignedUrlsId, drmConfigIdId] = useMemo<typeof fieldNames>(\n () => fieldNames.map((field) => `${id}-${field}`) as unknown as typeof fieldNames,\n [id],\n )\n const firstField = useRef<HTMLInputElement>(null)\n const handleSaveSecrets = useSaveSecrets(client, secrets)\n const saving = useRef(false)\n\n const handleSubmit = useCallback(\n (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault()\n\n if (!saving.current && event.currentTarget.reportValidity()) {\n saving.current = true\n dispatch({type: 'submit'})\n const {token, secretKey, enableSignedUrls, drmConfigId} = state\n handleSaveSecrets({token, secretKey, enableSignedUrls, drmConfigId})\n .then((savedSecrets) => {\n const {projectId, dataset} = client.config()\n clear([cacheNs, secretsId, projectId, dataset])\n preload(() => Promise.resolve(savedSecrets), [cacheNs, secretsId, projectId, dataset])\n setDialogState(false)\n })\n .catch((err) => dispatch({type: 'error', payload: err.message}))\n .finally(() => {\n saving.current = false\n })\n }\n },\n [client, dispatch, handleSaveSecrets, setDialogState, state],\n )\n const handleChangeToken = useCallback(\n (event: React.FormEvent<HTMLInputElement>) => {\n dispatch({\n type: 'change',\n payload: {name: 'token', value: event.currentTarget.value},\n })\n },\n [dispatch],\n )\n const handleChangeSecretKey = useCallback(\n (event: React.FormEvent<HTMLInputElement>) => {\n dispatch({\n type: 'change',\n payload: {name: 'secretKey', value: event.currentTarget.value},\n })\n },\n [dispatch],\n )\n const handleChangeEnableSignedUrls = useCallback(\n (event: React.FormEvent<HTMLInputElement>) => {\n dispatch({\n type: 'change',\n payload: {name: 'enableSignedUrls', value: event.currentTarget.checked},\n })\n },\n [dispatch],\n )\n const handleChangeDrmConfigId = useCallback(\n (event: React.FormEvent<HTMLInputElement>) => {\n dispatch({\n type: 'change',\n payload: {name: 'drmConfigId', value: event.currentTarget.value},\n })\n },\n [dispatch],\n )\n\n useEffect(() => {\n if (firstField.current) {\n firstField.current.focus()\n }\n }, [firstField])\n\n return (\n <Dialog\n animate\n id={id}\n onClose={handleClose}\n onClickOutside={handleClose}\n header={<Header />}\n zOffset={DIALOGS_Z_INDEX}\n position=\"fixed\"\n width={1}\n >\n <Box padding={3}>\n <form onSubmit={handleSubmit} noValidate>\n <Stack space={4}>\n {!hasSecretsInitially && (\n <Card padding={[3, 3, 3]} radius={2} shadow={1} tone=\"primary\">\n <Stack space={3}>\n <Text size={1}>\n To set up a new access token, go to your{' '}\n <a\n href=\"https://dashboard.mux.com/settings/access-tokens\"\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n >\n account on mux.com\n </a>\n .\n </Text>\n <Text size={1}>\n The access token needs permissions: <strong>Mux Video </strong>\n (Full Access) and <strong>Mux Data</strong> (Read)\n <br />\n To use Signed URLs, the token must also have System permissions.\n <br />\n The credentials will be stored safely in a hidden document only available to\n editors.\n </Text>\n </Stack>\n </Card>\n )}\n <FormField title=\"Access Token\" inputId={tokenId}>\n <TextInput\n id={tokenId}\n ref={firstField}\n onChange={handleChangeToken}\n type=\"text\"\n value={state.token ?? ''}\n required={!!state.secretKey || state.enableSignedUrls}\n />\n </FormField>\n <FormField title=\"Secret Key\" inputId={secretKeyId}>\n <TextInput\n id={secretKeyId}\n onChange={handleChangeSecretKey}\n type=\"text\"\n value={state.secretKey ?? ''}\n required={!!state.token || state.enableSignedUrls}\n />\n </FormField>\n\n <Stack space={4}>\n <Flex align=\"center\">\n <Checkbox\n id={enableSignedUrlsId}\n onChange={handleChangeEnableSignedUrls}\n checked={state.enableSignedUrls}\n style={{display: 'block'}}\n />\n <Box flex={1} paddingLeft={3}>\n <Text>\n <label htmlFor={enableSignedUrlsId}>Enable Signed Urls</label>\n </Text>\n </Box>\n </Flex>\n {secrets.signingKeyId && state.enableSignedUrls ? (\n <Card padding={[3, 3, 3]} radius={2} shadow={1} tone=\"caution\">\n <Stack space={3}>\n <Text size={1}>The signing key ID that Sanity will use is:</Text>\n <Code size={1}>{secrets.signingKeyId}</Code>\n <Text size={1}>\n This key is only used for previewing content in the Sanity UI.\n <br />\n You should generate a different key to use in your application server.\n </Text>\n </Stack>\n </Card>\n ) : null}\n </Stack>\n\n <FormField title=\"DRM Configuration ID\" inputId={drmConfigIdId}>\n <TextInput\n id={drmConfigIdId}\n onChange={handleChangeDrmConfigId}\n type=\"text\"\n value={state.drmConfigId ?? ''}\n required={false}\n />\n </FormField>\n <Card padding={[3, 3, 3]} radius={2} shadow={1} tone=\"neutral\">\n <Stack space={3}>\n <Text size={1}>\n DRM (Digital Rights Management) provides an extra layer of content security for\n video content streamed from Mux. For additional information check out our{' '}\n <a\n href=\"https://www.mux.com/docs/guides/protect-videos-with-drm#play-drm-protected-videos\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n DRM Guide\n </a>\n .\n </Text>\n <Text size={1}>\n <a\n href=\"https://www.mux.com/support/human\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Contact us\n </a>{' '}\n to get started using DRM.\n </Text>\n </Stack>\n </Card>\n\n <Inline space={2}>\n <Button\n text=\"Save\"\n disabled={!dirty}\n loading={state.submitting}\n tone=\"primary\"\n mode=\"default\"\n type=\"submit\"\n />\n <Button\n disabled={state.submitting}\n text=\"Cancel\"\n mode=\"bleed\"\n onClick={handleClose}\n />\n </Inline>\n {state.error && (\n <Card padding={[3, 3, 3]} radius={2} shadow={1} tone=\"critical\">\n <Text>{state.error}</Text>\n </Card>\n )}\n </Stack>\n </form>\n </Box>\n </Dialog>\n )\n}\n\n// Wrapper component that manages its own dialog state (used in VideosBrowser)\nexport default function ConfigureApi() {\n const [dialogOpen, setDialogOpen] = useDialogState()\n const secretDocumentValues = useSecretsDocumentValues()\n\n const openDialog = useCallback(() => setDialogOpen('secrets'), [setDialogOpen])\n\n if (dialogOpen === 'secrets') {\n return (\n <ConfigureApiDialog\n secrets={secretDocumentValues.value.secrets}\n setDialogState={setDialogOpen}\n />\n )\n }\n\n return <Button mode=\"bleed\" text=\"Configure plugin\" onClick={openDialog} />\n}\n","import {truncateString} from 'sanity'\n\n/**\n * Generates a placeholder title for a Mux asset when no title is available.\n * This format is used when importing assets that don't have a title in Mux.\n *\n * @param assetId - The Mux asset ID\n * @returns A placeholder title in the format \"Asset #[truncated-id]\"\n */\nexport function generateAssetPlaceholder(assetId: string): string {\n return `Asset #${truncateString(assetId, 15)}`\n}\n\n/**\n * Checks if a filename is empty or has the placeholder format.\n * This is used to determine if a video title should be updated during metadata sync.\n *\n * @param filename - The current filename/title of the video\n * @param assetId - The Mux asset ID to check against\n * @returns true if the filename is empty or matches the placeholder format\n */\nexport function isEmptyOrPlaceholderTitle(filename: string | undefined, assetId: string): boolean {\n // Check if filename is empty/undefined\n if (!filename || filename.trim() === '') {\n return true\n }\n\n // Check if filename matches the placeholder format for this asset\n const placeholder = generateAssetPlaceholder(assetId)\n return filename === placeholder\n}\n","import type {MuxAsset} from './types'\n\nexport function parseMuxDate(date: MuxAsset['created_at']): Date {\n return new Date(Number(date) * 1000)\n}\n","import type {SanityClient} from 'sanity'\n\nimport {PLUGIN_VERSION_QUERY} from '../util/pluginVersion'\nimport type {MuxAsset, VideoAssetDocument} from '../util/types'\n\nexport function deleteAssetOnMux(client: SanityClient, assetId: string) {\n const {dataset} = client.config()\n return client.request<void>({\n url: `/addons/mux/assets/${dataset}/${assetId}`,\n withCredentials: true,\n method: 'DELETE',\n query: PLUGIN_VERSION_QUERY,\n })\n}\n\nexport async function deleteAsset({\n client,\n asset,\n deleteOnMux,\n}: {\n client: SanityClient\n asset: VideoAssetDocument\n deleteOnMux: boolean\n}) {\n if (!asset?._id) return true\n\n try {\n await client.delete(asset._id)\n } catch {\n return 'failed-sanity'\n }\n\n if (deleteOnMux && asset?.assetId) {\n try {\n await deleteAssetOnMux(client, asset.assetId)\n } catch {\n return 'failed-mux'\n }\n }\n\n return true\n}\n\nexport function getAsset(client: SanityClient, assetId: string) {\n const {dataset} = client.config()\n return client.request<{data: MuxAsset}>({\n url: `/addons/mux/assets/${dataset}/data/${assetId}`,\n withCredentials: true,\n method: 'GET',\n query: PLUGIN_VERSION_QUERY,\n })\n}\n\nexport function listAssets(\n client: SanityClient,\n options: {limit?: number; cursor?: string | null},\n) {\n const {dataset} = client.config()\n const query: {limit?: string; cursor?: string} = {}\n\n if (options.limit) {\n query.limit = options.limit.toString()\n }\n if (options.cursor) {\n query.cursor = options.cursor\n }\n\n return client.request<{data: MuxAsset[]; next_cursor?: string | null}>({\n url: `/addons/mux/assets/${dataset}/data/list`,\n withCredentials: true,\n method: 'GET',\n query: {...query, ...PLUGIN_VERSION_QUERY},\n })\n}\n\n/**\n * Adds a new text track to an existing asset using a VTT file URL\n */\nexport function addTextTrackFromUrl(\n client: SanityClient,\n assetId: string,\n vttUrl: string,\n options: {\n language_code: string\n name: string\n text_type?: 'subtitles'\n },\n) {\n const {dataset} = client.config()\n\n return client.request<{data: MuxAsset}>({\n url: `/addons/mux/assets/${dataset}/${assetId}/tracks`,\n withCredentials: true,\n method: 'POST',\n body: {\n url: vttUrl,\n type: 'text',\n language_code: options.language_code,\n name: options.name,\n text_type: options.text_type || 'subtitles',\n },\n headers: {\n 'Content-Type': 'application/json',\n },\n query: PLUGIN_VERSION_QUERY,\n })\n}\n\n/**\n * Generates subtitles automatically for an audio track\n */\nexport function generateSubtitles(\n client: SanityClient,\n assetId: string,\n audioTrackId: string,\n options: {\n language_code: string\n name: string\n },\n) {\n const {dataset} = client.config()\n return client.request<{data: MuxAsset}>({\n url: `/addons/mux/assets/${dataset}/${assetId}/tracks/${audioTrackId}/generate-subtitles`,\n withCredentials: true,\n method: 'POST',\n body: {\n generated_subtitles: [\n {\n language_code: options.language_code,\n name: options.name,\n },\n ],\n },\n headers: {\n 'Content-Type': 'application/json',\n },\n query: PLUGIN_VERSION_QUERY,\n })\n}\n\n/**\n * Deletes a text track from an asset\n */\nexport function deleteTextTrack(client: SanityClient, assetId: string, trackId: string) {\n const {dataset} = client.config()\n return client.request<{data: MuxAsset}>({\n url: `/addons/mux/assets/${dataset}/${assetId}/tracks/${trackId}`,\n withCredentials: true,\n method: 'DELETE',\n query: PLUGIN_VERSION_QUERY,\n })\n}\n\n/**\n * Updates master access (the \"mezzanine\" file in Mux's docs) on a Mux asset, via the addon proxy.\n * @see {@link https://docs.mux.com/api-reference/video/assets/update-asset-master-access}\n */\nexport function updateMasterAccess(\n client: SanityClient,\n assetId: string,\n masterAccess: 'temporary' | 'none',\n) {\n const {dataset} = client.config()\n return client.request<{data: MuxAsset}>({\n url: `/addons/mux/assets/${dataset}/${assetId}/master-access`,\n withCredentials: true,\n method: 'PUT',\n body: {master_access: masterAccess},\n headers: {\n 'Content-Type': 'application/json',\n },\n query: PLUGIN_VERSION_QUERY,\n })\n}\n","import {useEffect, useState} from 'react'\nimport {defer, of, timer} from 'rxjs'\nimport {concatMap, expand, tap} from 'rxjs/operators'\nimport type {SanityClient} from 'sanity'\n\nimport {listAssets} from '../actions/assets'\nimport type {MuxAsset} from '../util/types'\n\nconst ASSETS_PER_PAGE = 100\n\ntype MuxAssetsState = {\n cursor: string | null\n loading: boolean\n data?: MuxAsset[]\n error?: FetchError\n hasSkippedAssetsWithoutPlayback?: boolean\n}\n\ntype FetchError =\n | {\n _tag: 'FetchError'\n }\n | {_tag: 'MuxError'; error: unknown}\n\ntype PageResult = (\n | {\n data: MuxAsset[]\n next_cursor: string | null\n }\n | {\n error: FetchError\n }\n) & {\n cursor: string | null\n}\n\n/**\n * @docs {@link https://docs.mux.com/api-reference#video/operation/list-assets}\n */\nasync function fetchMuxAssetsPage(\n client: SanityClient,\n cursor: string | null,\n): Promise<PageResult> {\n try {\n const response = await listAssets(client, {\n limit: ASSETS_PER_PAGE,\n cursor,\n })\n\n return {\n cursor,\n data: response.data,\n next_cursor: response.next_cursor || null,\n }\n } catch {\n return {\n cursor,\n error: {_tag: 'FetchError'},\n }\n }\n}\n\nfunction accumulateIntermediateState(\n currentState: MuxAssetsState,\n pageResult: PageResult,\n): MuxAssetsState {\n const currentData = ('data' in currentState && currentState.data) || []\n const newAssets = ('data' in pageResult && pageResult.data) || []\n\n // Filter assets and check for skipped items\n const {validAssets, skippedInThisPage} = newAssets.reduce<{\n validAssets: MuxAsset[]\n skippedInThisPage: boolean\n }>(\n (acc, asset) => {\n const hasPlaybackIds = asset.playback_ids && asset.playback_ids.length > 0\n const isDuplicate = currentData.some((a) => a.id === asset.id)\n\n if (!hasPlaybackIds) {\n acc.skippedInThisPage = true\n }\n\n if (hasPlaybackIds && !isDuplicate) {\n acc.validAssets.push(asset)\n }\n\n return acc\n },\n {validAssets: [], skippedInThisPage: false},\n )\n\n return {\n ...currentState,\n data: [...currentData, ...validAssets],\n error:\n 'error' in pageResult\n ? pageResult.error\n : // Reset error if current page is successful\n undefined,\n cursor: 'next_cursor' in pageResult ? pageResult.next_cursor : pageResult.cursor,\n loading: true,\n hasSkippedAssetsWithoutPlayback:\n currentState.hasSkippedAssetsWithoutPlayback || skippedInThisPage,\n }\n}\n\nfunction hasMorePages(pageResult: PageResult) {\n return (\n typeof pageResult === 'object' && 'next_cursor' in pageResult && pageResult.next_cursor !== null\n )\n}\n\n/**\n * Fetches all assets from a Mux environment. Rules:\n * - One page at a time\n * - Uses cursor-based pagination\n * - We've finished fetching when `next_cursor` is null\n * - Rate limiting to one request per 2 seconds\n * - Update state while still fetching to give feedback to users\n */\nexport default function useMuxAssets({client, enabled}: {client: SanityClient; enabled: boolean}) {\n const [state, setState] = useState<MuxAssetsState>({loading: true, cursor: null})\n\n useEffect(() => {\n if (!enabled) return\n\n const subscription = defer(() =>\n fetchMuxAssetsPage(\n client,\n // When we've already successfully loaded before (fully or partially), we start from the next cursor to avoid re-fetching\n 'data' in state && state.data && state.data.length > 0 && !state.error\n ? state.cursor\n : null,\n ),\n )\n .pipe(\n // Here we use \"expand\" to recursively fetch next pages\n expand((pageResult) => {\n // if fetched page has next_cursor, we continue emitting, requesting the next page\n // after 2s to avoid rate limiting\n if (hasMorePages(pageResult)) {\n return timer(2000).pipe(\n concatMap(() =>\n defer(() =>\n fetchMuxAssetsPage(\n client,\n 'next_cursor' in pageResult ? pageResult.next_cursor : null,\n ),\n ),\n ),\n )\n }\n\n // Else, we stop emitting\n return of()\n }),\n\n // On each iteration, persist intermediate states to give feedback to users\n tap((pageResult) =>\n setState((prevState) => accumulateIntermediateState(prevState, pageResult)),\n ),\n )\n .subscribe({\n // Once done, let the user know we've stopped loading\n complete: () => {\n setState((prev) => ({\n ...prev,\n loading: false,\n }))\n },\n })\n\n // Unsubscribe on component unmount to prevent memory leaks or fetching unnecessarily\n return () => subscription.unsubscribe()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled])\n\n return state\n}\n","import {uuid} from '@sanity/uuid'\nimport {useMemo, useState} from 'react'\nimport {\n createHookFromObservableFactory,\n type DocumentStore,\n useClient,\n useDocumentStore,\n} from 'sanity'\n\nimport {generateAssetPlaceholder} from '../util/assetTitlePlaceholder'\nimport {parseMuxDate} from '../util/parsers'\nimport type {MuxAsset, VideoAssetDocument} from '../util/types'\nimport {SANITY_API_VERSION} from './useClient'\nimport useMuxAssets from './useMuxAssets'\nimport {useSecretsDocumentValues} from './useSecretsDocumentValues'\n\ntype ImportState = 'closed' | 'idle' | 'importing' | 'done' | 'error'\n\nexport type AssetInSanity = {\n uploadId: string\n assetId: string\n}\n\nexport default function useImportMuxAssets() {\n const documentStore = useDocumentStore()\n const client = useClient({\n apiVersion: SANITY_API_VERSION,\n })\n\n const [assetsInSanity, assetsInSanityLoading] = useAssetsInSanity(documentStore)\n\n const secretDocumentValues = useSecretsDocumentValues()\n const hasSecrets = !!secretDocumentValues.value.secrets?.secretKey\n\n const [importError, setImportError] = useState<unknown>()\n const [importState, setImportState] = useState<ImportState>('closed')\n const dialogOpen = importState !== 'closed'\n\n const muxAssets = useMuxAssets({\n client,\n enabled: hasSecrets && dialogOpen,\n })\n\n const missingAssets = useMemo(() => {\n return assetsInSanity && muxAssets.data\n ? muxAssets.data.filter((a) => !assetExistsInSanity(a, assetsInSanity))\n : undefined\n }, [assetsInSanity, muxAssets.data])\n\n const [selectedAssets, setSelectedAssets] = useState<MuxAsset[]>([])\n\n const closeDialog = () => {\n if (importState !== 'importing') setImportState('closed')\n }\n const openDialog = () => {\n if (importState === 'closed') setImportState('idle')\n }\n\n async function importAssets() {\n setImportState('importing')\n const documents = selectedAssets.flatMap((asset) => muxAssetToSanityDocument(asset) || [])\n\n const tx = client.transaction()\n documents.forEach((doc) => tx.create(doc))\n\n try {\n await tx.commit({returnDocuments: false})\n setSelectedAssets([])\n setImportState('done')\n } catch (error) {\n setImportState('error')\n setImportError(error)\n }\n }\n\n return {\n assetsInSanityLoading,\n closeDialog,\n dialogOpen,\n importState,\n importError,\n hasSecrets,\n importAssets,\n missingAssets,\n muxAssets,\n openDialog,\n selectedAssets,\n setSelectedAssets,\n }\n}\n\nfunction muxAssetToSanityDocument(asset: MuxAsset): VideoAssetDocument | undefined {\n const playbackId = (asset.playback_ids || []).find((p) => p.id)?.id\n\n if (!playbackId) return undefined\n\n return {\n _id: uuid(),\n _type: 'mux.videoAsset',\n _updatedAt: new Date().toISOString(),\n _createdAt: parseMuxDate(asset.created_at).toISOString(),\n assetId: asset.id,\n playbackId,\n filename: asset.meta?.title ?? generateAssetPlaceholder(asset.id),\n status: asset.status,\n data: asset,\n }\n}\n\nconst useAssetsInSanity = createHookFromObservableFactory<AssetInSanity[], DocumentStore>(\n (documentStore) => {\n return documentStore.listenQuery(\n /* groq */ `*[_type == \"mux.videoAsset\"] {\n \"uploadId\": coalesce(uploadId, data.upload_id),\n \"assetId\": coalesce(assetId, data.id),\n }`,\n {},\n {\n apiVersion: SANITY_API_VERSION,\n },\n )\n },\n)\n\nfunction assetExistsInSanity(asset: MuxAsset, existingAssets: AssetInSanity[]) {\n // Don't allow importing assets that are not ready\n if (asset.status !== 'ready') return false\n\n return existingAssets.some(\n (existing) => existing.assetId === asset.id || existing.uploadId === asset.upload_id,\n )\n}\n","import {useEffect, useState} from 'react'\n\ntype IntersectionOptions = {\n root?: Element | null\n rootMargin?: string\n threshold?: number\n onChange?: (inView: boolean) => void\n}\n\nexport function useInView(\n ref: React.RefObject<HTMLDivElement | null>,\n options: IntersectionOptions = {},\n) {\n const [inView, setInView] = useState(false)\n\n useEffect(() => {\n if (!ref.current) return\n\n const observer = new IntersectionObserver(([entry], obs) => {\n // ==== from react-intersection-observer ====\n // 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.\n // -Firefox ignores `threshold` when considering `isIntersecting`, so it will never be false again if `threshold` is > 0\n const nowInView =\n entry!.isIntersecting &&\n obs.thresholds.some((threshold) => entry!.intersectionRatio >= threshold)\n\n // Update our state when observer callback fires\n setInView(nowInView)\n options?.onChange?.(nowInView)\n }, options)\n\n const toObserve = ref.current\n observer.observe(toObserve)\n\n return () => {\n if (toObserve) observer.unobserve(toObserve)\n }\n }, [options, ref])\n\n return inView\n}\n","import type {\n AdvancedPlaybackPolicy,\n MuxPlaybackId,\n PlaybackPolicy,\n VideoAssetDocument,\n} from './types'\n\n/* - Returns the playback id of the asset based on the specified priority.\n By default chooses the \"strongest\" policy\n - Otherwise, returns the first playback id in the array.\n */\nexport function getPlaybackId(\n asset: Pick<VideoAssetDocument, 'data'>,\n priority: string[] = ['drm', 'signed', 'public'],\n): string {\n try {\n if (!asset) {\n throw new TypeError('Tried to get playback Id with no asset')\n }\n\n const playbackIds = asset.data?.playback_ids\n if (playbackIds && playbackIds.length > 0) {\n for (const policy of priority) {\n const match = playbackIds.find((entry) => entry.policy === policy)\n if (match) {\n return match.id\n }\n }\n\n return playbackIds[0]!.id\n }\n\n throw new TypeError('Missing playbackId')\n } catch (e) {\n console.error('Asset is missing a playbackId', {asset}, e)\n throw e\n }\n}\n\nexport function getPlaybackPolicy(\n asset: Pick<VideoAssetDocument, 'data' | 'playbackId'>,\n): MuxPlaybackId | undefined {\n return (\n asset.data?.playback_ids?.find(\n (playbackId) => getPlaybackId(asset, ['drm', 'signed', 'public']) === playbackId.id,\n ) ?? {id: '', policy: 'public'}\n )\n}\n\nexport function getPlaybackPolicyById(\n asset: Pick<VideoAssetDocument, 'data'>,\n playbackId: string,\n): MuxPlaybackId | undefined {\n return asset.data?.playback_ids?.find((entry) => playbackId === entry.id)\n}\n\nexport function hasPlaybackPolicy(\n data: Partial<{\n playback_policy?: PlaybackPolicy[]\n advanced_playback_policies: AdvancedPlaybackPolicy[]\n }>,\n policy: PlaybackPolicy,\n) {\n return (\n (data.advanced_playback_policies &&\n data.advanced_playback_policies.find((p) => p.policy === policy)) ||\n data.playback_policy?.find((p) => p === policy)\n )\n}\n","import type {SanityClient} from 'sanity'\nimport {suspend} from 'suspend-react'\n\nimport {readSecrets} from './readSecrets'\nimport type {AnimatedThumbnailOptions, ThumbnailOptions} from './types'\n\nexport type Audience = 'g' | 's' | 't' | 'v' | 'd'\n\nexport type Payload<T extends Audience> = T extends 'g'\n ? AnimatedThumbnailOptions\n : T extends 's'\n ? never\n : T extends 't'\n ? ThumbnailOptions\n : T extends 'v'\n ? never\n : T extends 'd'\n ? never\n : never\n\n/**\n * Uses suspend. Call this with {@link tryWithSuspend} or rethrow the Promise\n */\nexport function generateJwt<T extends Audience>(\n client: SanityClient,\n playbackId: string,\n aud: T,\n payload?: Payload<T>,\n): string {\n const {signingKeyId, signingKeyPrivate} = readSecrets(client)\n if (!signingKeyId) {\n throw new TypeError(\"Missing `signingKeyId`.\\n Check your plugin's configuration\")\n }\n if (!signingKeyPrivate) {\n throw new TypeError(\"Missing `signingKeyPrivate`.\\n Check your plugin's configuration\")\n }\n\n /* Using suspend means we need to use Suspense on parent components.\n Also, this will throw a Promise under the hood (apparently common in React), \n so if we want to catch errors we have to take this into account in catch blocks\n and rethrow promises. */\n // @ts-expect-error - handle missing typings for this package\n const {default: sign} = suspend(() => import('jsonwebtoken-esm/sign'), ['jsonwebtoken-esm/sign'])\n\n return sign(\n payload ? JSON.parse(JSON.stringify(payload, (_, v) => v ?? undefined)) : {},\n atob(signingKeyPrivate),\n {\n algorithm: 'RS256',\n keyid: signingKeyId,\n audience: aud,\n subject: playbackId,\n noTimestamp: true,\n expiresIn: '12h',\n },\n )\n}\n","import type {SanityClient} from 'sanity'\n\nimport {getPlaybackId} from '../util/getPlaybackPolicy'\nimport {type Audience, generateJwt} from './generateJwt'\nimport {getPlaybackPolicyById} from './getPlaybackPolicy'\nimport type {AssetThumbnailOptions} from './types'\n\n/**\n * May throw a Promise. Call this with {@link tryWithSuspend} or rethrow the Promise\n */\nexport function createUrlParamsObject(\n client: SanityClient,\n asset: AssetThumbnailOptions['asset'],\n params: object,\n audience: Audience,\n) {\n const playbackId = getPlaybackId(asset)\n\n let searchParams = new URLSearchParams(\n JSON.parse(JSON.stringify(params, (_, v) => v ?? undefined)),\n )\n const playbackPolicy = getPlaybackPolicyById(asset, playbackId)?.policy\n if (playbackPolicy === 'signed' || playbackPolicy === 'drm') {\n const token = generateJwt(client, playbackId, audience, params)\n searchParams = new URLSearchParams({token})\n }\n\n return {playbackId, searchParams}\n}\n","import type {SanityClient} from 'sanity'\n\nimport {createUrlParamsObject} from './createUrlParamsObject'\nimport type {AnimatedThumbnailOptions, MuxAnimatedThumbnailUrl} from './types'\nimport {type AssetThumbnailOptions} from './types'\n\nexport interface AnimatedPosterSrcOptions extends AnimatedThumbnailOptions {\n asset: AssetThumbnailOptions['asset']\n client: SanityClient\n}\n\nexport function getAnimatedPosterSrc({\n asset,\n client,\n height,\n width,\n start = asset.thumbTime ? Math.max(0, asset.thumbTime - 2.5) : 0,\n end = start + 5,\n fps = 15,\n}: AnimatedPosterSrcOptions): MuxAnimatedThumbnailUrl {\n const params = {height, width, start, end, fps}\n\n const {playbackId, searchParams} = createUrlParamsObject(client, asset, params, 'g')\n\n return `https://image.mux.com/${playbackId}/animated.gif?${searchParams}`\n}\n","import type {SanityClient} from 'sanity'\n\nimport {createUrlParamsObject} from './createUrlParamsObject'\nimport type {MuxThumbnailUrl, ThumbnailOptions} from './types'\nimport {type AssetThumbnailOptions} from './types'\n\nexport interface PosterSrcOptions extends ThumbnailOptions {\n asset: AssetThumbnailOptions['asset']\n client: SanityClient\n}\n\nexport function getPosterSrc({\n asset,\n client,\n fit_mode,\n height,\n time = asset.thumbTime ?? undefined,\n width,\n}: PosterSrcOptions): MuxThumbnailUrl {\n const params = {fit_mode, height, width}\n if (time !== undefined) {\n ;(params as any).time = time\n }\n\n const {playbackId, searchParams} = createUrlParamsObject(client, asset, params, 't')\n\n return `https://image.mux.com/${playbackId}/thumbnail.png?${searchParams}`\n}\n","/**\n * When running `suspend()` from react-suspend a function may throw a Promise\n * causing unexpected behavior when catching.\n * @param block Your block of code that uses suspend\n * @param onError (optional) How to handle a regular Error\n * @returns Whatever is returned by the block if it succeeds, otherwise whatever is resolved by onError if defined\n * @throws rethrows the caught Promise to comply with Suspense logic\n */\nexport function tryWithSuspend<T, E>(\n block: () => T,\n onError?: (error: Error) => E,\n): T | E | undefined {\n try {\n return block()\n } catch (errorOrPromise) {\n if (errorOrPromise instanceof Promise) {\n // react-suspend will throw a Promise\n throw errorOrPromise\n }\n return onError ? onError(errorOrPromise as Error) : undefined\n }\n}\n","import {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {Box, Card, type CardTone, Spinner, Stack, Text} from '@sanity/ui'\nimport {Suspense, useMemo, useRef, useState} from 'react'\nimport {styled} from 'styled-components'\n\nimport {useClient} from '../hooks/useClient'\nimport {useInView} from '../hooks/useInView'\nimport {THUMBNAIL_ASPECT_RATIO} from '../util/constants'\nimport {getAnimatedPosterSrc} from '../util/getAnimatedPosterSrc'\nimport {getPosterSrc} from '../util/getPosterSrc'\nimport {tryWithSuspend} from '../util/tryWithSuspend'\nimport type {AssetThumbnailOptions, MuxAnimatedThumbnailUrl, MuxThumbnailUrl} from '../util/types'\n\nconst Image = styled.img`\n transition: opacity 0.175s ease-out 0s;\n display: block;\n width: 100%;\n height: 100%;\n object-fit: contain;\n object-position: center center;\n`\n\ntype ImageStatus = 'loading' | 'error' | 'loaded'\n\nconst STATUS_TO_TONE: Record<ImageStatus, CardTone> = {\n loading: 'transparent',\n error: 'critical',\n loaded: 'default',\n}\n\n// oxlint-disable-next-line react/react-compiler\nexport default function VideoThumbnail({\n asset,\n width,\n staticImage = false,\n}: {\n asset: AssetThumbnailOptions['asset']\n width?: number\n staticImage?: boolean\n}) {\n const posterWidth = width || 250\n const client = useClient()\n const ref = useRef<HTMLDivElement | null>(null)\n const inView = useInView(ref)\n\n const [status, setStatus] = useState<ImageStatus>('loading')\n const [error, setError] = useState<string | null>(null)\n\n const thumbnailSrc = useMemo(() => {\n return tryWithSuspend(\n () => {\n let thumbnail: MuxAnimatedThumbnailUrl | MuxThumbnailUrl | undefined\n\n if (staticImage) thumbnail = getPosterSrc({asset, client, width: posterWidth})\n else thumbnail = getAnimatedPosterSrc({asset, client, width: posterWidth})\n return thumbnail\n },\n (err: Error) => {\n handleError(err.message)\n return undefined\n },\n )\n }, [asset, client, posterWidth, staticImage])\n\n function handleLoad() {\n setStatus('loaded')\n }\n\n function handleError(err?: string) {\n setStatus('error')\n if (err) {\n setError(err)\n } else {\n setError('Failed loading thumbnail')\n }\n }\n\n return (\n <Suspense fallback={<span>Preparing thumbnail</span>}>\n <Card\n style={{\n aspectRatio: THUMBNAIL_ASPECT_RATIO,\n position: 'relative',\n maxWidth: width ? `${width}px` : undefined,\n width: '100%',\n flex: 1,\n }}\n border\n radius={2}\n ref={ref}\n tone={STATUS_TO_TONE[status]}\n >\n {inView ? (\n <>\n {status === 'loading' && (\n <Box\n style={{\n position: 'absolute',\n left: '50%',\n top: '50%',\n transform: 'translate(-50%, -50%)',\n }}\n >\n <Spinner />\n </Box>\n )}\n {status === 'error' && (\n <Stack\n space={4}\n style={{\n position: 'absolute',\n width: '100%',\n left: 0,\n top: '50%',\n transform: 'translateY(-50%)',\n justifyItems: 'center',\n }}\n >\n <Text size={4} muted>\n <ErrorOutlineIcon style={{fontSize: '1.75em'}} />\n </Text>\n <Text muted align=\"center\">\n {error}\n </Text>\n </Stack>\n )}\n <Image\n src={thumbnailSrc ?? undefined}\n alt={`Preview for ${staticImage ? 'image' : 'video'} ${asset.filename || asset.assetId}`}\n onLoad={handleLoad}\n onError={() => handleError()}\n style={{opacity: status === 'loaded' ? 1 : 0}}\n />\n </>\n ) : null}\n </Card>\n </Suspense>\n )\n}\n","import {CheckmarkCircleIcon} from '@sanity/icons/CheckmarkCircle'\nimport {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {InfoOutlineIcon} from '@sanity/icons/InfoOutline'\nimport {RetrieveIcon} from '@sanity/icons/Retrieve'\nimport {RetryIcon} from '@sanity/icons/Retry'\nimport {\n Box,\n Button,\n Card,\n Checkbox,\n Code,\n Dialog,\n Flex,\n Heading,\n Spinner,\n Stack,\n Text,\n} from '@sanity/ui'\nimport {truncateString, useFormattedDuration} from 'sanity'\nimport {styled} from 'styled-components'\n\nimport useImportMuxAssets from '../hooks/useImportMuxAssets'\nimport {DIALOGS_Z_INDEX} from '../util/constants'\nimport type {MuxAsset} from '../util/types'\nimport VideoThumbnail from './VideoThumbnail'\n\nconst MissingAssetCheckbox = styled(Checkbox)`\n position: static !important;\n\n input::after {\n content: '';\n position: absolute;\n inset: 0;\n display: block;\n cursor: pointer;\n z-index: 1000;\n }\n`\n\nfunction MissingAsset({\n asset,\n selectAsset,\n selected,\n}: {\n asset: MuxAsset\n selectAsset: (selected: boolean) => void\n selected: boolean\n}) {\n const duration = useFormattedDuration(asset.duration * 1000)\n\n return (\n <Card\n key={asset.id}\n tone={selected ? 'positive' : undefined}\n border\n paddingX={2}\n paddingY={3}\n style={{position: 'relative'}}\n radius={1}\n >\n <Flex align=\"center\" gap={2}>\n <MissingAssetCheckbox\n checked={selected}\n onChange={(e) => {\n selectAsset(e.currentTarget.checked)\n }}\n aria-label={selected ? `Import video ${asset.id}` : `Skip import of video ${asset.id}`}\n />\n <VideoThumbnail\n asset={{\n assetId: asset.id,\n data: asset,\n filename: asset.id,\n playbackId: asset.playback_ids.find((p) => p.id)?.id,\n }}\n width={150}\n />\n <Stack space={2}>\n <Flex align=\"center\" gap={1}>\n <Code size={2}>{truncateString(asset.id, 15)}</Code>{' '}\n <Text muted size={2}>\n ({duration.formatted})\n </Text>\n </Flex>\n <Text size={1}>\n Uploaded at{' '}\n {new Date(Number(asset.created_at) * 1000).toLocaleDateString('en', {\n year: 'numeric',\n day: '2-digit',\n month: '2-digit',\n })}\n </Text>\n </Stack>\n </Flex>\n </Card>\n )\n}\n\nfunction ImportVideosDialog(props: ReturnType<typeof useImportMuxAssets>) {\n const {importState} = props\n\n const canTriggerImport =\n (importState === 'idle' || importState === 'error') && props.selectedAssets.length > 0\n const isImporting = importState === 'importing'\n const noAssetsToImport =\n props.missingAssets?.length === 0 && !props.muxAssets.loading && !props.assetsInSanityLoading\n\n return (\n <Dialog\n animate\n header={'Import videos from Mux'}\n zOffset={DIALOGS_Z_INDEX}\n id=\"video-details-dialog\"\n onClose={props.closeDialog}\n onClickOutside={props.closeDialog}\n width={1}\n position=\"fixed\"\n footer={\n importState !== 'done' &&\n !noAssetsToImport && (\n <Card padding={3}>\n <Flex justify=\"space-between\" align=\"center\">\n <Button\n fontSize={2}\n padding={3}\n mode=\"ghost\"\n text=\"Cancel\"\n tone=\"critical\"\n onClick={props.closeDialog}\n disabled={isImporting}\n />\n {props.missingAssets && (\n <Button\n icon={RetrieveIcon}\n fontSize={2}\n padding={3}\n mode=\"ghost\"\n text={\n props.selectedAssets?.length > 0\n ? `Import ${props.selectedAssets.length} video(s)`\n : 'No video(s) selected'\n }\n tone=\"positive\"\n onClick={props.importAssets}\n iconRight={isImporting && Spinner}\n disabled={!canTriggerImport}\n />\n )}\n </Flex>\n </Card>\n )\n }\n >\n <Box padding={3}>\n {/* WARNING: SKIPPED ASSETS WITHOUT PLAYBACK */}\n {props.muxAssets.hasSkippedAssetsWithoutPlayback && (\n <Card tone=\"caution\" marginBottom={5} padding={3} border>\n <Flex align=\"center\" gap={2}>\n <InfoOutlineIcon fontSize={36} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n Some videos were skipped\n </Text>\n <Text size={1}>\n Videos without playback IDs cannot be imported and have been excluded from the\n list.\n </Text>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* LOADING ASSETS STATE */}\n {(props.muxAssets.loading || props.assetsInSanityLoading) && (\n <Card tone=\"primary\" marginBottom={5} padding={3} border>\n <Flex align=\"center\" gap={4}>\n <Spinner muted size={4} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n Loading assets from Mux\n </Text>\n <Text size={1}>\n This may take a while.\n {props.missingAssets &&\n props.missingAssets.length > 0 &&\n ` There are at least ${props.missingAssets.length} video${props.missingAssets.length > 1 ? 's' : ''} currently not in Sanity...`}\n </Text>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* ERROR LOADING MUX */}\n {props.muxAssets.error && (\n <Card tone=\"critical\" marginBottom={5} padding={3} border>\n <Flex align=\"center\" gap={2}>\n <ErrorOutlineIcon fontSize={36} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n There was an error getting all data from Mux\n </Text>\n <Text size={1}>\n {props.missingAssets\n ? `But we've found ${props.missingAssets.length} video${props.missingAssets.length > 1 ? 's' : ''} not in Sanity, which you can start importing now.`\n : 'Please try again or contact a developer for help.'}\n </Text>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* IMPORTING STATE */}\n {importState === 'importing' && (\n <Card tone=\"primary\" marginBottom={5} padding={3} border>\n <Flex align=\"center\" gap={4}>\n <Spinner muted size={4} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n Importing {props.selectedAssets.length} video\n {props.selectedAssets.length > 1 && 's'} from Mux\n </Text>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* ERROR IMPORTING */}\n {importState === 'error' && (\n <Card tone=\"critical\" marginBottom={5} padding={3} border>\n <Flex align=\"center\" gap={2}>\n <ErrorOutlineIcon fontSize={36} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n There was an error importing videos\n </Text>\n <Text size={1}>\n {props.importError\n ? `Error: ${props.importError}`\n : 'Please try again or contact a developer for help.'}\n </Text>\n <Box marginTop={1}>\n <Button\n icon={RetryIcon}\n text=\"Retry\"\n tone=\"primary\"\n onClick={props.importAssets}\n />\n </Box>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* NO ASSETS TO IMPORT or SUCESS STATE */}\n {(noAssetsToImport || importState === 'done') && (\n <Stack paddingY={5} marginBottom={4} space={3} style={{textAlign: 'center'}}>\n <Box>\n <CheckmarkCircleIcon fontSize={48} />\n </Box>\n <Heading size={2}>\n {importState === 'done'\n ? `Videos imported successfully`\n : 'There are no Mux videos to import'}\n </Heading>\n <Text size={2}>\n {importState === 'done'\n ? 'You can now use them in your Sanity content.'\n : \"They're all in Sanity and ready to be used in your content.\"}\n </Text>\n </Stack>\n )}\n\n {/* MISSING ASSETS SELECTOR */}\n {props.missingAssets &&\n props.missingAssets.length > 0 &&\n (importState === 'idle' || importState === 'error') && (\n <Stack space={4}>\n <Heading size={1}>\n There are {props.missingAssets.length}\n {props.muxAssets.loading && '+'} Mux video{props.missingAssets.length > 1 && 's'}{' '}\n not in Sanity\n </Heading>\n {!props.muxAssets.loading && (\n <Flex align=\"center\" paddingX={2}>\n <Checkbox\n id=\"import-all\"\n style={{display: 'block'}}\n onClick={(e) => {\n const selectAll = e.currentTarget.checked\n if (selectAll) {\n // eslint-disable-next-line no-unused-expressions\n props.missingAssets && props.setSelectedAssets(props.missingAssets)\n } else {\n props.setSelectedAssets([])\n }\n }}\n checked={props.selectedAssets.length === props.missingAssets.length}\n />\n <Box flex={1} paddingLeft={3} as=\"label\" htmlFor=\"import-all\">\n <Text>Import all</Text>\n </Box>\n </Flex>\n )}\n {props.missingAssets.map((asset) => (\n <MissingAsset\n key={asset.id}\n asset={asset}\n selectAsset={(selected) => {\n if (selected) {\n props.setSelectedAssets([...props.selectedAssets, asset])\n } else {\n props.setSelectedAssets(props.selectedAssets.filter((a) => a.id !== asset.id))\n }\n }}\n selected={props.selectedAssets.some((a) => a.id === asset.id)}\n />\n ))}\n </Stack>\n )}\n </Box>\n </Dialog>\n )\n}\n\nexport default function ImportVideosFromMux() {\n const importAssets = useImportMuxAssets()\n\n if (!importAssets.hasSecrets) {\n return\n }\n\n if (importAssets.dialogOpen) {\n return <ImportVideosDialog {...importAssets} />\n }\n\n return <Button mode=\"bleed\" text=\"Import from Mux\" onClick={importAssets.openDialog} />\n}\n","import {ChevronLeftIcon} from '@sanity/icons/ChevronLeft'\nimport {ChevronRightIcon} from '@sanity/icons/ChevronRight'\nimport {Button, Label} from '@sanity/ui'\nimport {type Dispatch, type SetStateAction, useEffect} from 'react'\n\nconst PageSelector = (props: {\n page: number\n setPage: Dispatch<SetStateAction<number>>\n total: number\n}) => {\n const page = props.page\n const setPage = props.setPage\n\n useEffect(() => {\n // Constraint in bounds.\n const clamped = Math.min(props.total - 1, Math.max(0, page))\n if (page !== clamped) {\n setPage(clamped)\n }\n }, [page, props.total, setPage])\n\n return (\n <>\n <Button\n icon={ChevronLeftIcon}\n mode=\"bleed\"\n padding={3}\n style={{cursor: 'pointer'}}\n disabled={page <= 0}\n onClick={() => {\n setPage((p) => {\n return Math.min(props.total - 1, Math.max(0, p - 1))\n })\n }}\n />\n <Label muted>\n Page {page + 1}/{props.total}\n </Label>\n <Button\n icon={ChevronRightIcon}\n mode=\"bleed\"\n padding={3}\n style={{cursor: 'pointer'}}\n disabled={page >= props.total - 1}\n onClick={() => {\n setPage((p) => {\n return Math.min(props.total - 1, Math.max(0, p + 1))\n })\n }}\n />\n </>\n )\n}\n\nexport default PageSelector\n","import type {MuxAsset} from './types'\n\n/**\n * Adds a `_key` to array items in MuxAsset data (Sanity requires `_key` on array\n * items). Keys are derived from each item's stable Mux `id`, so repeated calls\n * are idempotent and don't churn the document — important because the asset is\n * persisted on every poll while it prepares.\n */\nexport function addKeysToMuxData(data: MuxAsset): MuxAsset {\n return {\n ...data,\n tracks: data.tracks?.map((track, index) => ({\n ...track,\n _key: track.id || `track-${index}`,\n })),\n playback_ids: data.playback_ids?.map((playbackId, index) => ({\n ...playbackId,\n _key: playbackId.id || `playback-${index}`,\n })),\n static_renditions: data.static_renditions\n ? {\n ...data.static_renditions,\n files: data.static_renditions.files?.map((file, index) => ({\n ...file,\n _key: file.id || `rendition-${index}`,\n })),\n }\n : undefined,\n }\n}\n","import {useMemo, useState} from 'react'\nimport {\n createHookFromObservableFactory,\n type DocumentStore,\n useClient,\n useDocumentStore,\n} from 'sanity'\n\nimport {addKeysToMuxData} from '../util/addKeysToMuxData'\nimport {isEmptyOrPlaceholderTitle} from '../util/assetTitlePlaceholder'\nimport type {VideoAssetDocument} from '../util/types'\nimport {SANITY_API_VERSION} from './useClient'\nimport useMuxAssets from './useMuxAssets'\nimport {useSecretsDocumentValues} from './useSecretsDocumentValues'\n\ntype ResyncState = 'closed' | 'idle' | 'syncing' | 'done' | 'error'\n\nexport default function useResyncMuxMetadata() {\n const documentStore = useDocumentStore()\n const client = useClient({\n apiVersion: SANITY_API_VERSION,\n })\n\n const [sanityAssets, sanityAssetsLoading] = useSanityAssets(documentStore)\n\n const secretDocumentValues = useSecretsDocumentValues()\n const hasSecrets = !!secretDocumentValues.value.secrets?.secretKey\n\n const [resyncError, setResyncError] = useState<unknown>()\n const [resyncState, setResyncState] = useState<ResyncState>('closed')\n const dialogOpen = resyncState !== 'closed'\n\n const muxAssets = useMuxAssets({\n client,\n enabled: hasSecrets && dialogOpen,\n })\n\n const matchedAssets = useMemo(() => {\n return sanityAssets && muxAssets.data\n ? sanityAssets.map((sanityDoc) => {\n const muxAsset = muxAssets.data?.find(\n (m) => m.id === sanityDoc.assetId || m.id === sanityDoc.data?.id,\n )\n return {\n sanityDoc,\n muxAsset,\n muxTitle: muxAsset?.meta?.title,\n currentTitle: sanityDoc.filename,\n }\n })\n : undefined\n }, [sanityAssets, muxAssets.data])\n\n const closeDialog = () => {\n if (resyncState !== 'syncing') setResyncState('closed')\n }\n\n const openDialog = () => {\n if (resyncState === 'closed') setResyncState('idle')\n }\n\n async function syncAllVideos() {\n if (!matchedAssets) return\n\n setResyncState('syncing')\n\n try {\n const tx = client.transaction()\n\n matchedAssets.forEach((matched) => {\n // Update all videos with the Mux title, even if it's undefined/empty\n const newTitle = matched.muxTitle || ''\n tx.patch(matched.sanityDoc._id, {set: {filename: newTitle}})\n })\n\n await tx.commit({returnDocuments: false})\n setResyncState('done')\n } catch (error) {\n setResyncState('error')\n setResyncError(error)\n }\n }\n\n async function syncOnlyEmpty() {\n if (!matchedAssets) return\n\n setResyncState('syncing')\n\n try {\n const tx = client.transaction()\n\n matchedAssets.forEach((matched) => {\n // Only update if the current title is empty or has the placeholder format\n // AND there's a new title available from Mux\n if (\n matched.muxAsset &&\n matched.muxTitle &&\n isEmptyOrPlaceholderTitle(matched.currentTitle, matched.muxAsset.id)\n ) {\n tx.patch(matched.sanityDoc._id, {set: {filename: matched.muxTitle}})\n }\n })\n\n await tx.commit({returnDocuments: false})\n setResyncState('done')\n } catch (error) {\n setResyncState('error')\n setResyncError(error)\n }\n }\n\n async function syncFullData() {\n if (!matchedAssets) return\n\n setResyncState('syncing')\n\n try {\n const tx = client.transaction()\n\n matchedAssets.forEach((matched) => {\n if (!matched.muxAsset) return\n\n const dataWithKeys = addKeysToMuxData(matched.muxAsset)\n\n // Update all fields: filename, status, and full data from Mux\n tx.patch(matched.sanityDoc._id, {\n set: {\n filename: matched.muxTitle || matched.currentTitle || '',\n status: matched.muxAsset.status,\n data: dataWithKeys,\n },\n })\n })\n\n await tx.commit({returnDocuments: false})\n setResyncState('done')\n } catch (error) {\n setResyncState('error')\n setResyncError(error)\n }\n }\n\n return {\n sanityAssetsLoading,\n closeDialog,\n dialogOpen,\n resyncState,\n resyncError,\n hasSecrets,\n syncAllVideos,\n syncOnlyEmpty,\n syncFullData,\n matchedAssets,\n muxAssets,\n openDialog,\n }\n}\n\nconst useSanityAssets = createHookFromObservableFactory<VideoAssetDocument[], DocumentStore>(\n (documentStore) => {\n return documentStore.listenQuery(\n /* groq */ `*[_type == \"mux.videoAsset\"]`,\n {},\n {\n apiVersion: SANITY_API_VERSION,\n },\n )\n },\n)\n","import {CheckmarkCircleIcon} from '@sanity/icons/CheckmarkCircle'\nimport {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {SyncIcon} from '@sanity/icons/Sync'\nimport {Box, Button, Card, Dialog, Flex, Heading, Radio, Spinner, Stack, Text} from '@sanity/ui'\nimport {useState} from 'react'\n\nimport useResyncMuxMetadata from '../hooks/useResyncMuxMetadata'\nimport {isEmptyOrPlaceholderTitle} from '../util/assetTitlePlaceholder'\nimport {DIALOGS_Z_INDEX} from '../util/constants'\n\ntype SyncOption = 'fillEmpty' | 'syncTitles' | 'fullResync'\n\ninterface OptionCardProps {\n id: SyncOption\n selected: boolean\n onSelect: (id: SyncOption) => void\n title: string\n count: number\n description: string\n disabled?: boolean\n}\n\nfunction OptionCard({\n id,\n selected,\n onSelect,\n title,\n count,\n description,\n disabled,\n}: OptionCardProps) {\n return (\n <Card\n as=\"label\"\n padding={3}\n radius={2}\n border\n tone={selected ? 'primary' : 'default'}\n style={{\n cursor: disabled ? 'not-allowed' : 'pointer',\n opacity: disabled ? 0.5 : 1,\n }}\n >\n <Flex gap={3} align=\"flex-start\">\n <Box paddingTop={1}>\n <Radio\n checked={selected}\n onChange={() => onSelect(id)}\n disabled={disabled}\n name=\"sync-option\"\n />\n </Box>\n <Stack space={2} flex={1}>\n <Flex align=\"center\" gap={2}>\n <Text size={2} weight=\"semibold\">\n {title} ({count})\n </Text>\n </Flex>\n <Text size={1} muted>\n {description}\n </Text>\n </Stack>\n </Flex>\n </Card>\n )\n}\n\nfunction ResyncMetadataDialog(props: ReturnType<typeof useResyncMuxMetadata>) {\n const {resyncState} = props\n\n const videosToUpdate = props.matchedAssets?.filter((m) => m.muxAsset).length || 0\n const videosWithEmptyOrPlaceholder =\n props.matchedAssets?.filter(\n (m) => m.muxAsset && m.muxTitle && isEmptyOrPlaceholderTitle(m.currentTitle, m.muxAsset.id),\n ).length || 0\n\n const hasEmptyTitles = videosWithEmptyOrPlaceholder > 0\n const defaultOption: SyncOption = hasEmptyTitles ? 'fillEmpty' : 'syncTitles'\n const [selectedOption, setSelectedOption] = useState<SyncOption>(defaultOption)\n\n const canTriggerResync = resyncState === 'idle' || resyncState === 'error'\n const isResyncing = resyncState === 'syncing'\n const isDone = resyncState === 'done'\n const isLoading = props.muxAssets.loading || props.sanityAssetsLoading\n\n const handleSync = () => {\n switch (selectedOption) {\n case 'fillEmpty':\n void props.syncOnlyEmpty()\n break\n case 'syncTitles':\n void props.syncAllVideos()\n break\n case 'fullResync':\n void props.syncFullData()\n break\n default:\n break\n }\n }\n\n return (\n <Dialog\n animate\n header=\"Sync with Mux\"\n zOffset={DIALOGS_Z_INDEX}\n id=\"resync-metadata-dialog\"\n onClose={props.closeDialog}\n onClickOutside={props.closeDialog}\n width={1}\n position=\"fixed\"\n footer={\n !isDone && (\n <Card padding={3}>\n <Flex justify=\"flex-end\" gap={2}>\n <Button\n fontSize={2}\n padding={3}\n mode=\"ghost\"\n text=\"Cancel\"\n onClick={props.closeDialog}\n disabled={isResyncing}\n />\n <Button\n icon={SyncIcon}\n fontSize={2}\n padding={3}\n text=\"Run sync\"\n tone=\"primary\"\n onClick={handleSync}\n iconRight={isResyncing && Spinner}\n disabled={!canTriggerResync || isLoading}\n />\n </Flex>\n </Card>\n )\n }\n >\n <Box padding={4}>\n {/* LOADING ASSETS STATE */}\n {isLoading && (\n <Card tone=\"primary\" marginBottom={4} padding={3} border radius={2}>\n <Flex align=\"center\" gap={4}>\n <Spinner muted size={4} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n Loading assets from Mux\n </Text>\n <Text size={1} muted>\n This may take a while.\n </Text>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* ERROR LOADING MUX */}\n {props.muxAssets.error && (\n <Card tone=\"critical\" marginBottom={4} padding={3} border radius={2}>\n <Flex align=\"center\" gap={2}>\n <ErrorOutlineIcon fontSize={36} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n There was an error getting data from Mux\n </Text>\n <Text size={1}>Please try again or contact a developer for help.</Text>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* SYNCING STATE */}\n {resyncState === 'syncing' && (\n <Card tone=\"primary\" marginBottom={4} padding={3} border radius={2}>\n <Flex align=\"center\" gap={4}>\n <Spinner muted size={4} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n Syncing metadata\n </Text>\n <Text size={1} muted>\n Updating videos from Mux...\n </Text>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* ERROR SYNCING */}\n {resyncState === 'error' && (\n <Card tone=\"critical\" marginBottom={4} padding={3} border radius={2}>\n <Flex align=\"center\" gap={2}>\n <ErrorOutlineIcon fontSize={36} />\n <Stack space={2}>\n <Text size={2} weight=\"semibold\">\n There was an error syncing metadata\n </Text>\n <Text size={1}>\n {props.resyncError\n ? `Error: ${props.resyncError}`\n : 'Please try again or contact a developer for help.'}\n </Text>\n </Stack>\n </Flex>\n </Card>\n )}\n\n {/* SUCCESS STATE */}\n {resyncState === 'done' && (\n <Stack paddingY={5} space={3} style={{textAlign: 'center'}}>\n <Box>\n <CheckmarkCircleIcon fontSize={48} />\n </Box>\n <Heading size={2}>Sync completed</Heading>\n <Text size={2} muted>\n Videos have been updated from Mux.\n </Text>\n </Stack>\n )}\n\n {/* OPTIONS */}\n {!isDone && !isLoading && !props.muxAssets.error && (\n <Stack space={4}>\n <Text size={1} muted>\n Found {videosToUpdate} video{videosToUpdate === 1 ? '' : 's'} linked to Mux.\n </Text>\n\n <Stack space={3}>\n {hasEmptyTitles && (\n <OptionCard\n id=\"fillEmpty\"\n selected={selectedOption === 'fillEmpty'}\n onSelect={setSelectedOption}\n title=\"Fill missing titles only\"\n count={videosWithEmptyOrPlaceholder}\n description=\"Updates only videos without a title or with placeholder titles (e.g., 'Asset #123') using the title from Mux.\"\n disabled={isResyncing}\n />\n )}\n\n <OptionCard\n id=\"syncTitles\"\n selected={selectedOption === 'syncTitles'}\n onSelect={setSelectedOption}\n title=\"Sync all titles\"\n count={videosToUpdate}\n description=\"Replaces the title in Sanity with the title from Mux for all videos.\"\n disabled={isResyncing}\n />\n\n <OptionCard\n id=\"fullResync\"\n selected={selectedOption === 'fullResync'}\n onSelect={setSelectedOption}\n title=\"Full resync\"\n count={videosToUpdate}\n description=\"Updates all fields from Mux including status, duration, tracks, captions, and renditions.\"\n disabled={isResyncing}\n />\n </Stack>\n </Stack>\n )}\n </Box>\n </Dialog>\n )\n}\n\nexport default function ResyncMetadata() {\n const resyncMetadata = useResyncMuxMetadata()\n\n if (!resyncMetadata.hasSecrets) {\n return\n }\n\n if (resyncMetadata.dialogOpen) {\n return <ResyncMetadataDialog {...resyncMetadata} />\n }\n\n return <Button mode=\"bleed\" text=\"Sync with Mux\" onClick={resyncMetadata.openDialog} />\n}\n","import {SortIcon} from '@sanity/icons/Sort'\nimport {Button, Menu, MenuButton, MenuItem, type PopoverProps} from '@sanity/ui'\nimport {useId} from 'react'\n\nimport {ASSET_SORT_OPTIONS, type SortOption} from '../hooks/useAssets'\n\nconst CONTEXT_MENU_POPOVER_PROPS: PopoverProps = {\n constrainSize: true,\n placement: 'bottom',\n portal: true,\n width: 0,\n}\n\n/**\n * @sanity/ui components adapted from:\n * https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/desk/components/pane/PaneContextMenuButton.tsx#L19\n */\nexport function SelectSortOptions(props: {sort: SortOption; setSort: (s: SortOption) => void}) {\n const id = useId()\n\n return (\n <MenuButton\n button={\n <Button text=\"Sort\" icon={SortIcon} mode=\"bleed\" padding={3} style={{cursor: 'pointer'}} />\n }\n id={id}\n menu={\n <Menu>\n {Object.entries(ASSET_SORT_OPTIONS).map(([type, {label}]) => (\n <MenuItem\n key={type}\n data-as=\"button\"\n onClick={() => props.setSort(type as SortOption)}\n padding={3}\n tone=\"default\"\n text={label}\n pressed={type === props.sort}\n />\n ))}\n </Menu>\n }\n popover={CONTEXT_MENU_POPOVER_PROPS}\n />\n )\n}\n","import {Box, Spinner} from '@sanity/ui'\n\nconst SpinnerBox: React.FC = () => (\n <Box\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: '150px',\n }}\n >\n <Spinner />\n </Box>\n)\n\nexport default SpinnerBox\n","import {Flex, Text} from '@sanity/ui'\n\nconst IconInfo: React.FC<{\n text: string\n icon: React.FC\n size?: number\n muted?: boolean\n}> = (props) => {\n const Icon = props.icon\n return (\n <Flex gap={2} align=\"center\" padding={1}>\n <Text size={(props.size || 1) + 1} muted>\n <Icon />\n </Text>\n <Text size={props.size || 1} muted={props.muted}>\n {props.text}\n </Text>\n </Flex>\n )\n}\n\nexport default IconInfo\n","import type {SVGProps} from 'react'\n\nexport function ResolutionIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1em\" height=\"1em\" viewBox=\"0 0 24 24\" {...props}>\n <path\n fill=\"currentColor\"\n d=\"M20 9V6h-3V4h5v5h-2ZM2 9V4h5v2H4v3H2Zm15 11v-2h3v-3h2v5h-5ZM2 20v-5h2v3h3v2H2Zm4-4V8h12v8H6Zm2-2h8v-4H8v4Zm0 0v-4v4Z\"\n />\n </svg>\n )\n}\n","import type {SVGProps} from 'react'\n\nexport function StopWatchIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"1em\"\n height=\"1em\"\n viewBox=\"0 0 512 512\"\n {...props}\n >\n <path d=\"M232 306.667h48V176h-48v130.667z\" fill=\"currentColor\" />\n <path\n d=\"M407.67 170.271l30.786-30.786-33.942-33.941-30.785 30.786C341.217 111.057 300.369 96 256 96 149.961 96 64 181.961 64 288s85.961 192 192 192 192-85.961 192-192c0-44.369-15.057-85.217-40.33-117.729zm-45.604 223.795C333.734 422.398 296.066 438 256 438s-77.735-15.602-106.066-43.934C121.602 365.735 106 328.066 106 288s15.602-77.735 43.934-106.066C178.265 153.602 215.934 138 256 138s77.734 15.602 106.066 43.934C390.398 210.265 406 247.934 406 288s-15.602 77.735-43.934 106.066z\"\n fill=\"currentColor\"\n />\n <path d=\"M192 32h128v48H192z\" fill=\"currentColor\" />\n </svg>\n )\n}\n","import {useToast} from '@sanity/ui'\nimport {useCallback, useEffect, useMemo, useState} from 'react'\n\nimport {getAsset, updateMasterAccess} from '../actions/assets'\nimport {addKeysToMuxData} from '../util/addKeysToMuxData'\nimport type {MuxAsset, VideoAssetDocument} from '../util/types'\nimport {useClient} from './useClient'\n\n/**\n * UI status for the mezzanine (\"master access\") file of a Mux asset, derived\n * solely from the stored `master` object.\n * - `disabled`: master access is not enabled (or reverted to `none`).\n * - `preparing`: Mux is preparing the file (we poll until it's ready).\n * - `ready`: the file is ready to download.\n * - `errored`: Mux failed to prepare the file.\n */\nexport type MezzanineStatus = 'disabled' | 'preparing' | 'ready' | 'errored'\n\n// Poll cadence while the mezzanine is preparing.\nconst POLL_INTERVAL_MS = 3000\n\nexport interface UseMezzanineReturn {\n status: MezzanineStatus\n /** `true` while an enable or pre-download check request is in flight. */\n busy: boolean\n /**\n * `true` when the last download attempt found the file gone (the 24h window\n * elapsed). Used to show a \"enable it again\" hint; the button state still\n * comes from `status`.\n */\n expired: boolean\n /** Mezzanine resolution label (e.g. `1080p`), when known. */\n resolution?: string\n /** Enables master access and starts polling until the file is ready. */\n enable: () => Promise<void>\n /** Re-fetches the asset and, if the file is still alive, triggers the download. */\n download: () => Promise<void>\n}\n\n/** Derives the mezzanine status from the persisted asset data alone (no polling or local state). */\nexport function getMezzanineStatus(\n asset: VideoAssetDocument,\n): 'disabled' | 'preparing' | 'ready' | 'errored' {\n const master = asset.data?.master\n if (master?.status === 'preparing') return 'preparing'\n if (master?.status === 'ready' && master.url) return 'ready'\n if (master?.status === 'errored') return 'errored'\n return 'disabled'\n}\n\n/**\n * Encapsulates the mezzanine (Mux \"master access\") lifecycle for an asset:\n * enabling it through the Mux addon proxy, persisting the result on the Sanity\n * document, polling until it's ready, and downloading by redirecting to the\n * fresh, short-lived Mux URL.\n *\n * The full Mux asset `data` (including the `master` object) is stored on the\n * Sanity document via `client.patch`, so the status survives reloads and is\n * already present for assets imported from Mux.\n */\nexport function useMezzanine(asset: VideoAssetDocument): UseMezzanineReturn {\n const client = useClient()\n const toast = useToast()\n\n const master = asset.data?.master\n const [busy, setBusy] = useState(false)\n const [expired, setExpired] = useState(false)\n // Track the previous assetId so we can reset transient flags during render\n // when the asset changes, without triggering a cascading setState-in-effect.\n const [prevAssetId, setPrevAssetId] = useState(asset.assetId)\n if (prevAssetId !== asset.assetId) {\n setPrevAssetId(asset.assetId)\n setExpired(false)\n }\n\n const resolution = useMemo(\n () => asset.data?.max_resolution_tier || asset.data?.max_stored_resolution || undefined,\n [asset.data?.max_resolution_tier, asset.data?.max_stored_resolution],\n )\n\n const status: MezzanineStatus = getMezzanineStatus(asset)\n\n // Persist a Mux asset payload on the Sanity document.\n const persist = useCallback(\n async (data: MuxAsset) => {\n if (!asset._id) return\n await client\n .patch(asset._id)\n .set({status: data.status, data: addKeysToMuxData(data)})\n .commit({returnDocuments: false})\n },\n [asset._id, client],\n )\n\n // Fetch the latest asset from Mux (through the proxy) and persist it on the Sanity document.\n const refresh = useCallback(async (): Promise<MuxAsset | undefined> => {\n if (!asset.assetId || !asset._id) return undefined\n const {data} = await getAsset(client, asset.assetId)\n await persist(data)\n return data\n }, [asset.assetId, asset._id, client, persist])\n\n // Poll while the mezzanine is preparing; stop once it's ready or no longer preparing.\n useEffect(() => {\n if (master?.status !== 'preparing' || !asset.assetId || !asset._id) return undefined\n\n let cancelled = false\n let running = false\n const interval = setInterval(async () => {\n // Skip this tick if the previous refresh hasn't finished, so a slow\n // request can't pile up overlapping reads/writes.\n if (running) return\n running = true\n try {\n const data = await refresh()\n if (cancelled) return\n if (!data || data.master?.status !== 'preparing') {\n clearInterval(interval)\n }\n } catch (error) {\n console.error('Failed to poll mezzanine status:', error)\n } finally {\n running = false\n }\n }, POLL_INTERVAL_MS)\n\n return () => {\n cancelled = true\n clearInterval(interval)\n }\n }, [master?.status, asset.assetId, asset._id, refresh])\n\n const enable = useCallback(async () => {\n if (!asset.assetId || !asset._id) return\n\n setBusy(true)\n setExpired(false)\n try {\n const {data} = await updateMasterAccess(client, asset.assetId, 'temporary')\n // Persist the PUT response directly — it already reports master.status\n // 'preparing', so polling starts without relying on a follow-up GET that\n // could read stale data and miss it.\n await persist(data)\n } catch (error) {\n toast.push({\n status: 'error',\n title: 'Could not enable the mezzanine file',\n description: error instanceof Error ? error.message : 'Please try again',\n })\n } finally {\n setBusy(false)\n }\n }, [asset.assetId, asset._id, client, persist, toast])\n\n const download = useCallback(async () => {\n if (!asset.assetId) return\n\n setBusy(true)\n try {\n // The Mux URL is short-lived (24h), so re-fetch the asset right before\n // downloading and only redirect if the file is still alive.\n const data = await refresh()\n const url = data?.master?.status === 'ready' ? data.master.url : undefined\n\n if (url) {\n setExpired(false)\n triggerMezzanineDownload(url)\n } else {\n // The window elapsed and master_access reverted: prompt to re-enable.\n setExpired(true)\n }\n } catch (error) {\n toast.push({\n status: 'error',\n title: 'Could not download the mezzanine file',\n description: error instanceof Error ? error.message : 'Please try again',\n })\n } finally {\n setBusy(false)\n }\n }, [asset.assetId, refresh, toast])\n\n return {status, busy, expired, resolution, enable, download}\n}\n\n/**\n * Redirects the browser to the Mux mezzanine URL to start the download. The URL\n * already serves the file with its default name (`mezzanine.mp4`).\n * @see {@link https://www.mux.com/docs/guides/download-for-offline-editing}\n */\nfunction triggerMezzanineDownload(masterUrl: string): void {\n if (typeof window === 'undefined') return\n\n const anchor = document.createElement('a')\n anchor.href = masterUrl\n anchor.target = '_blank'\n anchor.rel = 'noopener noreferrer'\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n}\n","import {Stack, Text} from '@sanity/ui'\n\n/** Explains what the mezzanine file is and how it differs from the streamable MP4 renditions. */\nexport default function MezzanineExplanation() {\n return (\n <Stack space={3}>\n <Text size={1} muted>\n When you enable the mezzanine file, Mux creates a copy equivalent in quality to your\n original video — ideal for offline editing or archiving. Unlike the streamable MP4 (static)\n renditions, it is not meant for streaming.\n </Text>\n <Text size={1} muted>\n The file is prepared in the background and may take a few minutes depending on the\n asset's duration and resolution. Enabling is free and the download stays available for\n 24 hours.\n </Text>\n </Stack>\n )\n}\n","import {DownloadIcon} from '@sanity/icons/Download'\nimport {Button, Card, Flex, Label, Spinner, Stack, Text} from '@sanity/ui'\n\nimport {useMezzanine} from '../hooks/useMezzanine'\nimport {MEZZANINE_LEARN_MORE_URL} from '../util/constants'\nimport type {VideoAssetDocument} from '../util/types'\nimport MezzanineExplanation from './MezzanineExplanation'\n\nexport interface Props {\n asset: VideoAssetDocument\n /**\n * Render the mezzanine explanation copy inside the card.\n * @defaultValue true\n */\n withExplanation?: boolean\n}\n\n/**\n * \"Mezzanine\" panel, modeled after Mux's dashboard card: enable the\n * master-access copy, watch it prepare, then download it.\n */\nexport default function Mezzanine({asset, withExplanation = true}: Props) {\n const {status, busy, expired, resolution, enable, download} = useMezzanine(asset)\n\n const assetReady = asset.status === 'ready' || asset.data?.status === 'ready'\n // Once a download finds the file gone, treat it as not-ready even if the\n // (stale) asset prop still reports `ready`, so we show the re-enable path\n // instead of a dead Download button.\n const isReady = status === 'ready' && !expired\n const isPreparing = status === 'preparing'\n const showExplanation = !isReady && !isPreparing\n\n return (\n <Card padding={3} radius={2} tone=\"transparent\" border>\n <Stack space={4}>\n <Flex align=\"center\" justify=\"space-between\" gap={3}>\n <Label muted size={1}>\n Mezzanine\n </Label>\n <Text size={1}>\n <a href={MEZZANINE_LEARN_MORE_URL} target=\"_blank\" rel=\"noopener noreferrer\">\n Learn more\n </a>\n </Text>\n </Flex>\n\n <Stack space={2}>\n <Text size={1} muted={!isReady}>\n mezzanine.mp4\n </Text>\n {resolution && (\n <Text size={1} muted>\n {resolution}\n </Text>\n )}\n </Stack>\n\n {withExplanation && showExplanation && <MezzanineExplanation />}\n\n {showExplanation && (expired || status === 'errored') && (\n <Stack space={2}>\n {expired && (\n <Text size={1} muted>\n The previous mezzanine file expired. Enable it again to download.\n </Text>\n )}\n {status === 'errored' && (\n <Text size={1} style={{color: 'var(--card-critical-color)'}}>\n Mux could not prepare the mezzanine file. Please try again.\n </Text>\n )}\n </Stack>\n )}\n\n {isPreparing && (\n <Text size={1} muted>\n Preparing the mezzanine file… this can take a few minutes. You can close this and come\n back later.\n </Text>\n )}\n\n {isReady && (\n <Text size={1} muted>\n Ready to download. The link stays available for about 24 hours.\n </Text>\n )}\n\n <Flex justify=\"flex-end\" gap={2}>\n {isPreparing ? (\n <Flex align=\"center\" gap={2}>\n <Spinner muted size={1} />\n <Text size={1} muted>\n Preparing…\n </Text>\n </Flex>\n ) : isReady ? (\n <Button\n icon={DownloadIcon}\n text=\"Download\"\n tone=\"positive\"\n fontSize={1}\n padding={3}\n loading={busy}\n disabled={busy}\n onClick={() => void download()}\n />\n ) : (\n <Button\n text={status === 'errored' ? 'Try again' : 'Enable'}\n tone=\"primary\"\n fontSize={1}\n padding={3}\n loading={busy}\n disabled={busy || !assetReady}\n onClick={() => void enable()}\n />\n )}\n </Flex>\n </Stack>\n </Card>\n )\n}\n","import {useToast} from '@sanity/ui'\nimport {useCallback, useState} from 'react'\n\nimport {getAsset} from '../actions/assets'\nimport {addKeysToMuxData} from '../util/addKeysToMuxData'\nimport type {MuxAsset, VideoAssetDocument} from '../util/types'\nimport {useClient} from './useClient'\n\ntype ResyncAssetState = 'idle' | 'syncing' | 'success' | 'error'\n\ninterface UseResyncAssetOptions {\n showToast?: boolean\n onSuccess?: (updatedData: MuxAsset) => void\n onError?: (error: unknown) => void\n}\n\ninterface UseResyncAssetReturn {\n resyncState: ResyncAssetState\n resyncError: unknown\n resyncAsset: (asset: VideoAssetDocument) => Promise<MuxAsset | undefined>\n isResyncing: boolean\n}\n\nexport function useResyncAsset(options?: UseResyncAssetOptions): UseResyncAssetReturn {\n const client = useClient()\n const toast = useToast()\n const [resyncState, setResyncState] = useState<ResyncAssetState>('idle')\n const [resyncError, setResyncError] = useState<unknown>(null)\n\n const showToast = options?.showToast ?? false\n\n const resyncAsset = useCallback(\n async (asset: VideoAssetDocument) => {\n if (!asset.assetId) {\n if (showToast) {\n toast.push({\n title: 'Cannot resync',\n description: 'Asset has no Mux ID',\n status: 'error',\n })\n }\n options?.onError?.(new Error('Asset has no Mux ID'))\n return undefined\n }\n\n if (!asset._id) {\n if (showToast) {\n toast.push({\n title: 'Cannot resync',\n description: 'Asset has no document ID',\n status: 'error',\n })\n }\n options?.onError?.(new Error('Asset has no document ID'))\n return undefined\n }\n\n setResyncState('syncing')\n setResyncError(null)\n\n try {\n const response = await getAsset(client, asset.assetId)\n const muxData = response.data\n const dataWithKeys = addKeysToMuxData(muxData)\n\n await client\n .patch(asset._id)\n .set({\n status: muxData.status,\n data: dataWithKeys,\n ...(muxData.meta?.title && {filename: muxData.meta.title}),\n })\n .commit({returnDocuments: false})\n\n setResyncState('success')\n if (showToast) {\n toast.push({\n title: 'Asset synced',\n description: 'Data has been updated from Mux',\n status: 'success',\n })\n }\n\n options?.onSuccess?.(muxData)\n return muxData\n } catch (error) {\n setResyncState('error')\n setResyncError(error)\n console.error('Failed to refresh asset data:', error)\n if (showToast) {\n toast.push({\n title: 'Sync failed',\n description: 'Could not sync asset from Mux',\n status: 'error',\n })\n }\n options?.onError?.(error)\n return undefined\n }\n },\n [client, toast, options, showToast],\n )\n\n return {\n resyncState,\n resyncError,\n resyncAsset,\n isResyncing: resyncState === 'syncing',\n }\n}\n","import type {SanityClient} from '@sanity/client'\n\nimport {getAsset} from '../actions/assets'\nimport {generateJwt} from './generateJwt'\nimport {getPlaybackId} from './getPlaybackPolicy'\nimport {getPlaybackPolicy} from './getPlaybackPolicy'\nimport type {MuxTextTrack, VideoAssetDocument} from './types'\n\nexport function extractErrorMessage(\n error: unknown,\n defaultMessage = 'Failed to process request',\n): string {\n let message = ''\n\n if (error && typeof error === 'object') {\n const err = error as {response?: {body?: {message?: string}}; message?: string}\n message = err.response?.body?.message || err.message || ''\n } else if (typeof error === 'string') {\n message = error\n }\n\n if (!message) {\n return defaultMessage\n }\n\n const match = message.match(/\\(([^)]+)\\)/)\n if (match && match[1]) {\n return match[1]\n }\n\n if (message.includes('responded with')) {\n const parts = message.split('(')\n if (parts.length > 1) {\n return parts[parts.length - 1]!.replace(')', '').trim()\n }\n }\n\n return message\n}\n\nexport interface PollTrackStatusOptions {\n client: SanityClient\n assetId: string\n trackName: string\n trackLanguageCode: string\n maxAttempts?: number\n onTrackFound?: (track: MuxTextTrack) => void\n onTrackErrored?: (track: MuxTextTrack) => void\n onTrackReady?: (track: MuxTextTrack) => void\n}\n\nexport interface PollTrackStatusResult {\n track: MuxTextTrack | undefined\n found: boolean\n status: 'ready' | 'preparing' | 'errored' | 'not-found'\n}\n\n/**\n * Polls Mux API to find and track the status of a newly added text track.\n * The track may be in \"preparing\" state initially, then become \"ready\" or \"errored\".\n *\n * @param options - Configuration options for polling\n * @returns Promise resolving to the poll result\n */\nexport async function pollTrackStatus(\n options: PollTrackStatusOptions,\n): Promise<PollTrackStatusResult> {\n const {\n client,\n assetId,\n trackName,\n trackLanguageCode,\n maxAttempts = 10,\n onTrackFound,\n onTrackErrored,\n onTrackReady,\n } = options\n\n const trimmedName = trackName.trim()\n const trimmedLanguageCode = trackLanguageCode.trim()\n let newTrack: MuxTextTrack | undefined\n let attempts = 0\n let trackFound = false\n\n const findTrack = (textTracks: MuxTextTrack[]): MuxTextTrack | undefined => {\n let foundTrack = textTracks.find(\n (track) => track.name === trimmedName && track.language_code === trimmedLanguageCode,\n )\n\n if (!foundTrack) {\n foundTrack = textTracks.find((track) => track.language_code === trimmedLanguageCode)\n }\n\n if (!foundTrack && textTracks.length > 0) {\n foundTrack = textTracks[textTracks.length - 1]\n }\n\n return foundTrack\n }\n\n while (attempts < maxAttempts) {\n try {\n if (attempts > 0) {\n await new Promise((resolve) => setTimeout(resolve, 1000))\n }\n\n const assetData = await getAsset(client, assetId)\n const textTracks =\n assetData.data.tracks?.filter((track): track is MuxTextTrack => track.type === 'text') || []\n\n const foundTrack = findTrack(textTracks)\n\n if (!foundTrack) {\n attempts++\n continue\n }\n\n trackFound = true\n newTrack = foundTrack\n\n if (onTrackFound) {\n onTrackFound(foundTrack)\n }\n\n if (foundTrack.status === 'ready') {\n if (onTrackReady) {\n onTrackReady(foundTrack)\n }\n break\n }\n\n if (foundTrack.status === 'errored') {\n if (onTrackErrored) {\n onTrackErrored(foundTrack)\n }\n return {\n track: foundTrack,\n found: true,\n status: 'errored',\n }\n }\n } catch (error) {\n console.error('Failed to fetch updated asset:', error)\n }\n\n attempts++\n }\n\n if (!newTrack || !trackFound) {\n return {\n track: undefined,\n found: false,\n status: 'not-found',\n }\n }\n\n if (newTrack.status === 'preparing') {\n return {\n track: newTrack,\n found: true,\n status: 'preparing',\n }\n }\n\n return {\n track: newTrack,\n found: true,\n status: 'ready',\n }\n}\n\n/**\n * May throw a Promise. Call this with {@link tryWithSuspend} or rethrow the Promise\n */\nexport async function downloadVttFile(\n client: SanityClient,\n asset: VideoAssetDocument,\n track: MuxTextTrack,\n): Promise<void> {\n if (!track.id) {\n throw new Error('Track ID is missing')\n }\n\n if (track.status !== 'ready') {\n throw new Error(`Track is not ready yet. Status: ${track.status}`)\n }\n\n if (!asset.assetId) {\n throw new Error('Asset ID is required')\n }\n\n const playbackId = getPlaybackId(asset)\n if (!playbackId) {\n throw new Error('Playback ID is required')\n }\n\n const playbackPolicy = getPlaybackPolicy(asset)?.policy\n\n let downloadUrl = `https://stream.mux.com/${playbackId}/text/${track.id}.vtt`\n\n if (playbackPolicy === 'signed' || playbackPolicy === 'drm') {\n const token = generateJwt(client, playbackId, 'v')\n downloadUrl += `?token=${token}`\n }\n\n const response = await fetch(downloadUrl)\n if (!response.ok) {\n throw new Error(`Failed to download file: ${response.statusText}`)\n }\n\n const blob = await response.blob()\n const blobUrl = URL.createObjectURL(blob)\n\n const link = document.createElement('a')\n link.href = blobUrl\n link.download = `${asset.filename || 'captions'}-${track.language_code || 'en'}.vtt`\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n\n URL.revokeObjectURL(blobUrl)\n}\n","import {TranslateIcon} from '@sanity/icons/Translate'\nimport {UploadIcon} from '@sanity/icons/Upload'\nimport {\n Autocomplete,\n Button,\n Card,\n Checkbox,\n Dialog,\n Flex,\n Label,\n Spinner,\n Stack,\n Text,\n TextInput,\n useToast,\n} from '@sanity/ui'\nimport LanguagesList from 'iso-639-1'\nimport {useId, useRef, useState} from 'react'\n\nimport {addTextTrackFromUrl, generateSubtitles, getAsset} from '../actions/assets'\nimport {useClient} from '../hooks/useClient'\nimport {addKeysToMuxData} from '../util/addKeysToMuxData'\nimport {extractErrorMessage, pollTrackStatus} from '../util/textTracks'\nimport {type MuxTextTrack, SUPPORTED_MUX_LANGUAGES, type VideoAssetDocument} from '../util/types'\n\nconst LANGUAGE_OPTIONS = LanguagesList.getAllCodes().map((code) => ({\n value: code,\n label: LanguagesList.getNativeName(code),\n}))\n\nconst MUX_LANGUAGE_OPTIONS = SUPPORTED_MUX_LANGUAGES.map((lang) => ({\n value: lang.code,\n label: lang.label,\n}))\n\nexport interface Props {\n asset: VideoAssetDocument\n onAdd: (track: MuxTextTrack) => void\n onClose: () => void\n}\n\nexport default function AddCaptionDialog({asset, onAdd, onClose}: Props) {\n const client = useClient()\n const toast = useToast()\n const dialogId = `AddCaptionDialog${useId()}`\n\n const [isAutogenerated, setIsAutogenerated] = useState(false)\n const [vttUrl, setVttUrl] = useState('')\n const [languageCode, setLanguageCode] = useState('')\n const [selectedLanguage, setSelectedLanguage] = useState<{value: string; label: string} | null>(\n null,\n )\n const [name, setName] = useState('')\n const [isSubmitting, setIsSubmitting] = useState(false)\n const [selectedFile, setSelectedFile] = useState<File | null>(null)\n const fileInputRef = useRef<HTMLInputElement>(null)\n\n const uploadVttFile = async (file: File): Promise<string> => {\n const assetDocument = await client.assets.upload('file', file, {\n filename: file.name,\n })\n return assetDocument.url\n }\n\n const refreshAssetData = async () => {\n if (!asset._id || !asset.assetId) return\n try {\n const latestAssetData = await getAsset(client, asset.assetId)\n const dataWithKeys = addKeysToMuxData(latestAssetData.data)\n await client\n .patch(asset._id)\n .set({data: dataWithKeys, status: latestAssetData.data.status})\n .commit({returnDocuments: false})\n } catch (refreshError) {\n console.error('Failed to refresh asset data:', refreshError)\n }\n }\n\n const handleAddTrackFromUrl = async () => {\n if (!asset.assetId) {\n throw new Error('Asset ID is required')\n }\n\n const trimmedName = name.trim()\n const trimmedLanguageCode = languageCode.trim()\n\n let vttUrlToUse = vttUrl.trim()\n\n if (selectedFile) {\n try {\n vttUrlToUse = await uploadVttFile(selectedFile)\n } catch (uploadError) {\n toast.push({\n title: 'Failed to upload caption file',\n status: 'error',\n description: 'Could not upload the caption file to Sanity. Please try again.',\n })\n setIsSubmitting(false)\n throw uploadError\n }\n }\n\n await addTextTrackFromUrl(client, asset.assetId, vttUrlToUse, {\n language_code: trimmedLanguageCode,\n name: trimmedName,\n text_type: 'subtitles',\n })\n\n const result = await pollTrackStatus({\n client,\n assetId: asset.assetId,\n trackName: trimmedName,\n trackLanguageCode: trimmedLanguageCode,\n onTrackErrored: async (track) => {\n const errorMessage =\n track.error?.messages?.[0] ||\n track.error?.type ||\n 'The track failed to download from the provided URL'\n toast.push({\n title: 'Caption track failed',\n status: 'error',\n description: errorMessage,\n })\n await refreshAssetData()\n onAdd(track)\n onClose()\n },\n })\n\n if (!result.found || !result.track) {\n toast.push({\n title: 'Caption track may have been added',\n status: 'warning',\n description:\n '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.',\n })\n onClose()\n return\n }\n\n if (result.status === 'errored') {\n return\n }\n\n if (result.status === 'preparing') {\n toast.push({\n title: 'Caption track is processing',\n status: 'info',\n description:\n 'The track was created and is being processed. It will appear in the list shortly.',\n })\n await refreshAssetData()\n onAdd(result.track)\n onClose()\n return\n }\n\n await refreshAssetData()\n toast.push({\n title: 'Caption track added',\n status: 'success',\n description: 'Caption track added successfully',\n })\n\n onAdd(result.track)\n onClose()\n }\n\n const handleGenerateSubtitles = async () => {\n if (!asset.assetId) {\n throw new Error('Asset ID is required')\n }\n\n const assetData = await getAsset(client, asset.assetId)\n const audioTrack = assetData.data.tracks?.find((track) => track.type === 'audio')\n\n if (!audioTrack || !audioTrack.id) {\n toast.push({\n title: 'No audio track found',\n status: 'error',\n description:\n 'The asset does not have an audio track. Auto-generated subtitles require an audio track.',\n })\n throw new Error('No audio track found')\n }\n\n await generateSubtitles(client, asset.assetId, audioTrack.id, {\n language_code: languageCode.trim(),\n name: name.trim(),\n })\n\n const mockTrackId = `generating-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`\n const mockTrack: MuxTextTrack = {\n type: 'text',\n id: mockTrackId,\n text_type: 'subtitles',\n text_source: 'generated_live',\n language_code: languageCode.trim(),\n name: name.trim(),\n status: 'preparing',\n }\n\n toast.push({\n title: 'Generating subtitles',\n status: 'success',\n description: 'This may take a few minutes',\n })\n\n onAdd(mockTrack)\n onClose()\n }\n\n const handleSubmit = async () => {\n if (!isAutogenerated) {\n if (!selectedFile && !vttUrl.trim()) {\n toast.push({\n title: 'Caption file or URL required',\n status: 'error',\n description: 'Please select a VTT or SRT file or enter a caption file URL',\n })\n return\n }\n\n if (vttUrl.trim() && !selectedFile) {\n try {\n void new URL(vttUrl.trim())\n } catch {\n toast.push({\n title: 'Invalid URL',\n status: 'error',\n description:\n 'Please enter a valid URL (e.g., https://example.com/subtitles.vtt or subtitles.srt)',\n })\n return\n }\n }\n }\n\n if (!name.trim()) {\n toast.push({\n title: 'Audio name required',\n status: 'error',\n description: 'Please enter an audio name for this caption track',\n })\n return\n }\n\n if (!languageCode.trim()) {\n toast.push({\n title: 'Language code required',\n status: 'error',\n description: 'Please enter a language code (e.g., en, es, fr)',\n })\n return\n }\n\n setIsSubmitting(true)\n\n try {\n if (isAutogenerated) {\n await handleGenerateSubtitles()\n } else {\n await handleAddTrackFromUrl()\n }\n } catch (error) {\n toast.push({\n title: 'Failed to add caption track',\n status: 'error',\n description: extractErrorMessage(error, 'Failed to add caption track'),\n })\n } finally {\n setIsSubmitting(false)\n }\n }\n\n return (\n <Dialog\n id={dialogId}\n header=\"Add Caption Track\"\n onClose={onClose}\n width={1}\n onClickOutside={onClose}\n >\n <Stack padding={4} space={4}>\n <Stack space={2}>\n <Flex align=\"center\" marginBottom={3}>\n <Checkbox\n id=\"autogenerated-checkbox\"\n style={{display: 'block'}}\n checked={isAutogenerated}\n onChange={(e) => {\n setIsAutogenerated(e.currentTarget.checked)\n if (e.currentTarget.checked) {\n setVttUrl('')\n }\n }}\n disabled={isSubmitting}\n />\n <Flex flex={1} paddingLeft={2}>\n <Text>\n <label htmlFor=\"autogenerated-checkbox\">Generate captions</label>\n </Text>\n </Flex>\n </Flex>\n {!isAutogenerated && (\n <Stack space={2}>\n <Card padding={3} marginBottom={2} tone=\"transparent\" border radius={2}>\n <Flex align=\"center\" justify=\"space-between\">\n <Text size={1} muted>\n {selectedFile ? `Selected: ${selectedFile.name}` : 'No file selected'}\n </Text>\n <Button\n icon={UploadIcon}\n text=\"Select File\"\n mode=\"ghost\"\n tone=\"primary\"\n fontSize={1}\n padding={2}\n onClick={() => fileInputRef.current?.click()}\n disabled={isSubmitting}\n />\n </Flex>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".vtt,text/vtt,.srt,application/x-subrip\"\n style={{display: 'none'}}\n onChange={(e) => {\n if (e.target.files && e.target.files.length > 0 && !isSubmitting) {\n setSelectedFile(e.target.files[0]!)\n setVttUrl('')\n }\n }}\n />\n </Card>\n <Text size={1} muted style={{textAlign: 'center'}}>\n Or enter the caption file URL\n </Text>\n <Stack space={2}>\n <Label as=\"label\" htmlFor=\"vtt-url\">\n Caption File URL (.vtt or .srt)\n </Label>\n <TextInput\n id=\"vtt-url\"\n placeholder=\"https://example.com/subtitles.vtt\"\n value={vttUrl}\n onChange={(e) => {\n setVttUrl(e.currentTarget.value)\n setSelectedFile(null)\n }}\n disabled={isSubmitting}\n />\n </Stack>\n </Stack>\n )}\n </Stack>\n\n <Stack space={2}>\n <Label as=\"label\" htmlFor=\"caption-name\">\n Audio name\n </Label>\n <Autocomplete\n id=\"caption-name\"\n value={selectedLanguage?.value || ''}\n onChange={(newValue) => {\n const options = isAutogenerated ? MUX_LANGUAGE_OPTIONS : LANGUAGE_OPTIONS\n const selected = options.find((opt) => opt.value === newValue)\n if (selected) {\n setSelectedLanguage(selected)\n setLanguageCode(selected.value)\n setName(selected.label)\n }\n }}\n options={isAutogenerated ? MUX_LANGUAGE_OPTIONS : LANGUAGE_OPTIONS}\n icon={TranslateIcon}\n placeholder=\"Select language\"\n filterOption={(query, option) =>\n option.label.toLowerCase().indexOf(query.toLowerCase()) > -1 ||\n option.value.toLowerCase().indexOf(query.toLowerCase()) > -1\n }\n openButton\n renderValue={(value) =>\n (isAutogenerated ? MUX_LANGUAGE_OPTIONS : LANGUAGE_OPTIONS).find(\n (l) => l.value === value,\n )?.label || value\n }\n renderOption={(option) => (\n <Card data-as=\"button\" padding={3} radius={2} tone=\"inherit\">\n <Text size={2} textOverflow=\"ellipsis\">\n {option.label} ({option.value})\n </Text>\n </Card>\n )}\n disabled={isSubmitting}\n />\n </Stack>\n\n <Stack space={2}>\n <Label as=\"label\" htmlFor=\"caption-language\">\n Language Code\n </Label>\n <TextInput\n id=\"caption-language\"\n placeholder=\"en-US\"\n value={languageCode}\n onChange={(e) => {\n setLanguageCode(e.currentTarget.value)\n if (selectedLanguage && selectedLanguage.value !== e.currentTarget.value) {\n setSelectedLanguage(null)\n if (!name || name === selectedLanguage.label) {\n setName('')\n }\n }\n }}\n disabled={isSubmitting}\n />\n </Stack>\n\n <Flex gap={2} justify=\"flex-end\" marginTop={2}>\n <Button text=\"Cancel\" mode=\"ghost\" onClick={onClose} disabled={isSubmitting} />\n <Button\n text=\"Add Caption Track\"\n tone=\"primary\"\n icon={\n isSubmitting ? (\n <Spinner\n style={{\n verticalAlign: 'middle',\n display: 'inline-block',\n marginBottom: '-3px',\n width: '1em',\n height: '1em',\n marginRight: '-6px',\n }}\n />\n ) : (\n <UploadIcon />\n )\n }\n onClick={handleSubmit}\n disabled={isSubmitting}\n />\n </Flex>\n </Stack>\n </Dialog>\n )\n}\n","import {DownloadIcon} from '@sanity/icons/Download'\nimport {TranslateIcon} from '@sanity/icons/Translate'\nimport {UploadIcon} from '@sanity/icons/Upload'\nimport {\n Autocomplete,\n Button,\n Card,\n Dialog,\n Flex,\n Label,\n Spinner,\n Stack,\n Text,\n TextInput,\n useToast,\n} from '@sanity/ui'\nimport LanguagesList from 'iso-639-1'\nimport {useEffect, useId, useRef, useState} from 'react'\n\nimport {addTextTrackFromUrl, deleteTextTrack, getAsset} from '../actions/assets'\nimport {useClient} from '../hooks/useClient'\nimport {addKeysToMuxData} from '../util/addKeysToMuxData'\nimport {generateJwt} from '../util/generateJwt'\nimport {getPlaybackId} from '../util/getPlaybackPolicy'\nimport {getPlaybackPolicy} from '../util/getPlaybackPolicy'\nimport {downloadVttFile, extractErrorMessage, pollTrackStatus} from '../util/textTracks'\nimport type {MuxTextTrack, VideoAssetDocument} from '../util/types'\n\nconst LANGUAGE_OPTIONS = LanguagesList.getAllCodes().map((code) => ({\n value: code,\n label: LanguagesList.getNativeName(code),\n}))\n\nexport interface Props {\n asset: VideoAssetDocument\n track: MuxTextTrack\n onUpdate: (track: MuxTextTrack, oldTrackId?: string) => void\n onClose: () => void\n}\n\nexport default function EditCaptionDialog({asset, track, onUpdate, onClose}: Props) {\n const client = useClient()\n const toast = useToast()\n const dialogId = `EditCaptionDialog${useId()}`\n\n const isAutogenerated =\n track.text_source === 'generated_live' ||\n track.text_source === 'generated_live_final' ||\n track.text_source === 'generated_vod'\n\n const [vttUrl, setVttUrl] = useState('')\n const [languageCode, setLanguageCode] = useState(track.language_code || '')\n const [selectedLanguage, setSelectedLanguage] = useState<{value: string; label: string} | null>(\n () => {\n const baseCode = track.language_code?.split('-')[0]\n const found = LANGUAGE_OPTIONS.find(\n (opt) => opt.value === track.language_code || opt.value === baseCode,\n )\n if (found) return found\n if (track.name) {\n const foundByName = LANGUAGE_OPTIONS.find((opt) => opt.label === track.name)\n if (foundByName) return foundByName\n }\n return null\n },\n )\n const [name, setName] = useState(track.name || '')\n const [isSubmitting, setIsSubmitting] = useState(false)\n const [downloading, setDownloading] = useState(false)\n const [selectedFile, setSelectedFile] = useState<File | null>(null)\n const fileInputRef = useRef<HTMLInputElement>(null)\n\n useEffect(() => {\n // oxlint-disable-next-line react/react-compiler\n setLanguageCode(track.language_code || '')\n setName(track.name || '')\n setVttUrl('')\n const baseCode = track.language_code?.split('-')[0]\n const foundByCode = LANGUAGE_OPTIONS.find(\n (opt) => opt.value === track.language_code || opt.value === baseCode,\n )\n const foundByName = track.name ? LANGUAGE_OPTIONS.find((opt) => opt.label === track.name) : null\n setSelectedLanguage(foundByCode || foundByName || null)\n }, [track, asset, client])\n\n const handleDownloadCurrentFile = async () => {\n setDownloading(true)\n try {\n await downloadVttFile(client, asset, track)\n } catch (error) {\n let errorMessage = 'Please try again'\n let title = 'Failed to download VTT file'\n\n if (error instanceof Error) {\n errorMessage = error.message\n if (error.message.includes('Track')) {\n title = 'Cannot download'\n }\n } else if (error === 'Track ID is missing' || error === 'Track is not ready yet') {\n errorMessage = error\n title = 'Cannot download'\n }\n\n toast.push({\n title,\n status: 'error',\n description: errorMessage,\n })\n } finally {\n setDownloading(false)\n }\n }\n\n const getCurrentFileName = () => {\n if (track.id && asset.filename) {\n return `${asset.filename}-${track.language_code || 'en'}.vtt`\n }\n return `captions-${track.language_code || 'en'}.vtt`\n }\n\n const uploadVttFile = async (file: File): Promise<string> => {\n const assetDocument = await client.assets.upload('file', file, {\n filename: file.name,\n })\n return assetDocument.url\n }\n\n const refreshAssetData = async () => {\n if (!asset._id || !asset.assetId) return\n try {\n const latestAssetData = await getAsset(client, asset.assetId)\n const dataWithKeys = addKeysToMuxData(latestAssetData.data)\n await client\n .patch(asset._id)\n .set({data: dataWithKeys, status: latestAssetData.data.status})\n .commit({returnDocuments: false})\n } catch (refreshError) {\n console.error('Failed to refresh asset data:', refreshError)\n }\n }\n\n const handleUpdateTrackWithNewUrl = async () => {\n if (!asset.assetId) {\n throw new Error('Asset ID is required')\n }\n\n const trimmedName = name.trim()\n const trimmedLanguageCode = languageCode.trim()\n\n const oldTrackId = track.id\n\n try {\n await deleteTextTrack(client, asset.assetId, oldTrackId)\n } catch (deleteError) {\n toast.push({\n title: 'Failed to delete old track',\n status: 'error',\n description: 'Could not delete the old track. Please try again or delete it manually.',\n })\n setIsSubmitting(false)\n throw deleteError\n }\n\n let vttUrlToUse = vttUrl.trim()\n\n if (selectedFile) {\n try {\n vttUrlToUse = await uploadVttFile(selectedFile)\n } catch (uploadError) {\n toast.push({\n title: 'Failed to upload VTT file',\n status: 'error',\n description: 'Could not upload the VTT file to Sanity. Please try again.',\n })\n setIsSubmitting(false)\n throw uploadError\n }\n }\n\n try {\n await addTextTrackFromUrl(client, asset.assetId, vttUrlToUse, {\n language_code: trimmedLanguageCode,\n name: trimmedName,\n text_type: 'subtitles',\n })\n } catch (error: unknown) {\n toast.push({\n title: 'Failed to update caption track',\n status: 'error',\n description: extractErrorMessage(error, 'Failed to update caption track'),\n })\n setIsSubmitting(false)\n throw error\n }\n\n const result = await pollTrackStatus({\n client,\n assetId: asset.assetId,\n trackName: trimmedName,\n trackLanguageCode: trimmedLanguageCode,\n onTrackErrored: async (erroredTrack) => {\n const errorMessage =\n erroredTrack.error?.messages?.[0] ||\n erroredTrack.error?.type ||\n 'The track failed to download from the provided URL'\n toast.push({\n title: 'Caption track failed',\n status: 'error',\n description: errorMessage,\n })\n await refreshAssetData()\n onUpdate(erroredTrack, oldTrackId)\n setIsSubmitting(false)\n },\n })\n\n if (!result.found || !result.track) {\n toast.push({\n title: 'Caption track may have been updated',\n status: 'warning',\n description:\n 'The track was updated but its status could not be determined. It may still be processing. Please refresh the page to see if it appears.',\n })\n setIsSubmitting(false)\n return\n }\n\n if (result.status === 'errored') {\n return\n }\n\n await refreshAssetData()\n\n if (result.status === 'preparing') {\n toast.push({\n title: 'Caption track is processing',\n status: 'info',\n description:\n 'The track was updated and is being processed. It will appear in the list shortly.',\n })\n } else {\n toast.push({\n title: 'Caption track updated',\n status: 'success',\n description: 'Caption track updated successfully',\n })\n }\n\n onUpdate(result.track, oldTrackId)\n setIsSubmitting(false)\n }\n\n const handleSubmit = async () => {\n if (!name.trim()) {\n toast.push({\n title: 'Audio name required',\n status: 'error',\n description: 'Please enter an audio name for this caption track',\n })\n return\n }\n\n if (!languageCode.trim()) {\n toast.push({\n title: 'Language code required',\n status: 'error',\n description: 'Please enter a language code (e.g., en, es, fr)',\n })\n return\n }\n\n setIsSubmitting(true)\n\n try {\n if (!asset.assetId) {\n throw new Error('Asset ID is required')\n }\n\n const originalVttUrl = (() => {\n if (isAutogenerated || !track.id) return ''\n const playbackId = getPlaybackId(asset)\n if (!playbackId) return ''\n let url = `https://stream.mux.com/${playbackId}/text/${track.id}.vtt`\n if (getPlaybackPolicy(asset)?.policy === 'signed') {\n const token = generateJwt(client, playbackId, 'v')\n url += `?token=${token}`\n }\n return url\n })()\n\n const urlChanged =\n selectedFile !== null || (vttUrl.trim() && vttUrl.trim() !== originalVttUrl)\n\n if (!urlChanged) {\n toast.push({\n title: 'No changes',\n status: 'info',\n description:\n 'Please provide a new VTT file or URL using the \"Replace\" button or URL field to update the track.',\n })\n setIsSubmitting(false)\n return\n }\n\n if (urlChanged) {\n if (!selectedFile && vttUrl.trim()) {\n try {\n void new URL(vttUrl.trim())\n } catch {\n toast.push({\n title: 'Invalid URL',\n status: 'error',\n description: 'Please enter a valid URL (e.g., https://example.com/subtitles.vtt)',\n })\n setIsSubmitting(false)\n return\n }\n }\n\n if (!selectedFile && !vttUrl.trim()) {\n toast.push({\n title: 'VTT file or URL required',\n status: 'error',\n description: 'Please select a VTT file or enter a VTT file URL',\n })\n setIsSubmitting(false)\n return\n }\n\n await handleUpdateTrackWithNewUrl()\n }\n\n onClose()\n } catch (error) {\n toast.push({\n title: 'Failed to update caption track',\n status: 'error',\n description: error instanceof Error ? error.message : 'Please try again',\n })\n } finally {\n setIsSubmitting(false)\n }\n }\n\n return (\n <Dialog\n id={dialogId}\n header=\"Edit Caption Track\"\n onClose={onClose}\n width={1}\n onClickOutside={onClose}\n >\n <Stack padding={4} space={4}>\n <Stack space={2}>\n <Card padding={3} marginBottom={2} tone=\"transparent\" border radius={2}>\n <Flex align=\"center\" justify=\"space-between\">\n <Text>{getCurrentFileName()}</Text>\n <Flex gap={2}>\n {track.status !== 'errored' && (\n <Button\n icon={\n downloading ? (\n <Spinner\n style={{\n verticalAlign: 'middle',\n display: 'inline-block',\n marginTop: '-2px',\n width: '0.5em',\n height: '0.5em',\n }}\n />\n ) : (\n <DownloadIcon />\n )\n }\n text=\"Download\"\n mode=\"ghost\"\n tone=\"primary\"\n fontSize={1}\n padding={2}\n onClick={handleDownloadCurrentFile}\n disabled={downloading || isSubmitting}\n />\n )}\n <Button\n icon={UploadIcon}\n text=\"Replace\"\n mode=\"ghost\"\n tone=\"primary\"\n fontSize={1}\n padding={2}\n onClick={() => fileInputRef.current?.click()}\n disabled={isSubmitting}\n />\n </Flex>\n </Flex>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".vtt,text/vtt\"\n style={{display: 'none'}}\n onChange={(e) => {\n if (e.target.files && e.target.files.length > 0 && !isSubmitting) {\n setSelectedFile(e.target.files[0]!)\n setVttUrl('')\n }\n }}\n />\n {selectedFile && (\n <Text size={1} muted style={{marginTop: 8}}>\n Selected: {selectedFile.name}\n </Text>\n )}\n </Card>\n <Stack space={2}>\n <Label as=\"label\" htmlFor=\"vtt-url\">\n VTT File URL\n </Label>\n <TextInput\n id=\"vtt-url\"\n placeholder=\"https://example.com/subtitles.vtt\"\n value={vttUrl}\n onChange={(e) => {\n setVttUrl(e.currentTarget.value)\n setSelectedFile(null)\n }}\n disabled={isSubmitting}\n />\n <Text size={1} muted>\n Add a URL to replace the existing VTT file with a new one\n </Text>\n </Stack>\n </Stack>\n\n <Stack space={2}>\n <Label as=\"label\" htmlFor=\"caption-name\">\n Audio name\n </Label>\n <Autocomplete\n id=\"caption-name\"\n value={selectedLanguage?.value || ''}\n onChange={(newValue) => {\n const selected = LANGUAGE_OPTIONS.find((opt) => opt.value === newValue)\n if (selected) {\n setSelectedLanguage(selected)\n setLanguageCode(selected.value)\n setName(selected.label)\n }\n }}\n options={LANGUAGE_OPTIONS}\n icon={TranslateIcon}\n placeholder=\"Select language\"\n filterOption={(query, option) =>\n option.label.toLowerCase().indexOf(query.toLowerCase()) > -1 ||\n option.value.toLowerCase().indexOf(query.toLowerCase()) > -1\n }\n openButton\n renderValue={(value) => LANGUAGE_OPTIONS.find((l) => l.value === value)?.label || value}\n renderOption={(option) => (\n <Card data-as=\"button\" padding={3} radius={2} tone=\"inherit\">\n <Text size={2} textOverflow=\"ellipsis\">\n {option.label} ({option.value})\n </Text>\n </Card>\n )}\n disabled={isSubmitting}\n />\n </Stack>\n\n <Stack space={2}>\n <Label as=\"label\" htmlFor=\"caption-language\">\n Language Code\n </Label>\n <TextInput\n id=\"caption-language\"\n placeholder=\"en-US\"\n value={languageCode}\n onChange={(e) => {\n setLanguageCode(e.currentTarget.value)\n if (selectedLanguage && selectedLanguage.value !== e.currentTarget.value) {\n setSelectedLanguage(null)\n if (!name || name === selectedLanguage.label) {\n setName('')\n }\n }\n }}\n disabled={isSubmitting}\n />\n </Stack>\n\n <Flex gap={2} justify=\"flex-end\" marginTop={2}>\n <Button text=\"Cancel\" mode=\"ghost\" onClick={onClose} disabled={isSubmitting} />\n <Button\n text=\"Update Caption Track\"\n tone=\"primary\"\n icon={\n isSubmitting ? (\n <Spinner\n style={{\n verticalAlign: 'middle',\n display: 'inline-block',\n marginBottom: '-3px',\n width: '1em',\n height: '1em',\n marginRight: '-6px',\n }}\n />\n ) : (\n UploadIcon\n )\n }\n onClick={handleSubmit}\n disabled={isSubmitting}\n />\n </Flex>\n </Stack>\n </Dialog>\n )\n}\n","import {AddIcon} from '@sanity/icons/Add'\nimport {ChevronDownIcon} from '@sanity/icons/ChevronDown'\nimport {ChevronUpIcon} from '@sanity/icons/ChevronUp'\nimport {DownloadIcon} from '@sanity/icons/Download'\nimport {EditIcon} from '@sanity/icons/Edit'\nimport {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {TrashIcon} from '@sanity/icons/Trash'\nimport {Box, Button, Card, Dialog, Flex, Heading, Spinner, Stack, Text, useToast} from '@sanity/ui'\nimport {useEffect, useId, useMemo, useState} from 'react'\n\nimport {deleteTextTrack} from '../actions/assets'\nimport {useClient} from '../hooks/useClient'\nimport {useResyncAsset} from '../hooks/useResyncAsset'\nimport {downloadVttFile} from '../util/textTracks'\nimport type {MuxTextTrack, VideoAssetDocument} from '../util/types'\nimport AddCaptionDialog from './AddCaptionDialog'\nimport EditCaptionDialog from './EditCaptionDialog'\n\ninterface TrackCardProps {\n track: MuxTextTrack\n iconOnly: boolean\n downloadingTrackId: string | null\n deletingTrackId: string | null\n trackToEdit: MuxTextTrack | null\n getTrackSourceLabel: (track: MuxTextTrack) => string\n handleDownload: (track: MuxTextTrack) => void\n setTrackToEdit: (track: MuxTextTrack) => void\n setTrackToDelete: (track: MuxTextTrack) => void\n}\n\nfunction TrackCard({\n track,\n iconOnly,\n downloadingTrackId,\n deletingTrackId,\n trackToEdit,\n getTrackSourceLabel,\n handleDownload,\n setTrackToEdit,\n setTrackToDelete,\n}: TrackCardProps) {\n const isDisabled = (action: 'download' | 'edit' | 'delete') => {\n if (action === 'download') {\n return (\n downloadingTrackId !== null || deletingTrackId === track.id || trackToEdit?.id === track.id\n )\n }\n if (action === 'edit') {\n return (\n downloadingTrackId === track.id ||\n deletingTrackId === track.id ||\n trackToEdit?.id === track.id\n )\n }\n return (\n downloadingTrackId === track.id || deletingTrackId !== null || trackToEdit?.id === track.id\n )\n }\n\n const renderActionButtons = () => {\n if (track.status === 'preparing') {\n return (\n <Flex align=\"center\" gap={2}>\n <Spinner\n muted\n style={{\n width: '0.75em',\n height: '0.75em',\n verticalAlign: 'middle',\n display: 'inline-block',\n marginBottom: '-2px',\n }}\n />\n <Text size={1} muted>\n Processing...\n </Text>\n </Flex>\n )\n }\n\n return (\n <Flex gap={2}>\n {track.status !== 'errored' && (\n <Button\n icon={\n downloadingTrackId === track.id ? (\n <Spinner\n style={{\n verticalAlign: 'middle',\n display: 'inline-block',\n marginTop: '-2px',\n width: '0.5em',\n height: '0.5em',\n }}\n />\n ) : (\n <DownloadIcon />\n )\n }\n text={iconOnly ? undefined : 'Download'}\n mode=\"ghost\"\n tone=\"primary\"\n fontSize={1}\n padding={2}\n onClick={() => handleDownload(track)}\n disabled={isDisabled('download')}\n title=\"Download\"\n />\n )}\n <Button\n icon={<EditIcon />}\n text={iconOnly ? undefined : 'Edit'}\n mode=\"ghost\"\n tone=\"primary\"\n fontSize={1}\n padding={2}\n disabled={isDisabled('edit')}\n onClick={() => setTrackToEdit(track)}\n title=\"Edit\"\n />\n <Button\n icon={\n deletingTrackId === track.id ? (\n <Spinner\n style={{\n verticalAlign: 'middle',\n display: 'inline-block',\n marginTop: '-2px',\n width: '0.5em',\n height: '0.5em',\n }}\n />\n ) : (\n <TrashIcon />\n )\n }\n text={iconOnly ? undefined : 'Delete'}\n mode=\"ghost\"\n tone=\"critical\"\n fontSize={1}\n padding={2}\n disabled={isDisabled('delete')}\n onClick={() => setTrackToDelete(track)}\n title=\"Delete\"\n />\n </Flex>\n )\n }\n\n return (\n <Card\n padding={3}\n radius={2}\n tone={track.status === 'errored' ? 'caution' : 'transparent'}\n border\n >\n <Flex align=\"center\" justify=\"space-between\" gap={3}>\n <Stack space={2} flex={1}>\n <Flex align=\"center\" gap={2}>\n <Text weight=\"semibold\">{track.name || 'Untitled'}</Text>\n <Text size={1} muted>\n ({getTrackSourceLabel(track)})\n </Text>\n {track.status === 'errored' && (\n <ErrorOutlineIcon\n style={{color: 'var(--card-critical-color)'}}\n aria-label=\"Error\"\n fontSize={20}\n />\n )}\n </Flex>\n {track.language_code && (\n <Text size={1} muted>\n Language: {track.language_code}\n </Text>\n )}\n {track.status === 'errored' && track.error && (\n <Text size={1} style={{color: 'var(--card-critical-color)'}}>\n {track.error.messages?.[0] || track.error.type || 'Failed to process track'}\n </Text>\n )}\n </Stack>\n {renderActionButtons()}\n </Flex>\n </Card>\n )\n}\n\ninterface TextTracksManagerProps {\n asset: VideoAssetDocument\n iconOnly?: boolean\n tracks?: MuxTextTrack[]\n collapseTracks?: boolean\n}\n\nexport default function TextTracksManager({\n asset,\n iconOnly = false,\n tracks: propTracks,\n collapseTracks = false,\n}: TextTracksManagerProps) {\n const client = useClient()\n const toast = useToast()\n const dialogId = `DeleteCaptionDialog${useId()}`\n const {resyncAsset} = useResyncAsset()\n const [downloadingTrackId, setDownloadingTrackId] = useState<string | null>(null)\n const [deletingTrackId, setDeletingTrackId] = useState<string | null>(null)\n const [addedTracks, setAddedTracks] = useState<MuxTextTrack[]>([])\n const [updatedTracks, setUpdatedTracks] = useState<Map<string, MuxTextTrack>>(new Map())\n const [trackActivityOrder, setTrackActivityOrder] = useState<Map<string, number>>(new Map())\n const [autogeneratedTrackIds, setAutogeneratedTrackIds] = useState<Set<string>>(new Set())\n const [trackToDelete, setTrackToDelete] = useState<MuxTextTrack | null>(null)\n const [trackToEdit, setTrackToEdit] = useState<MuxTextTrack | null>(null)\n const [showAddDialog, setShowAddDialog] = useState(false)\n const [isExpanded, setIsExpanded] = useState(false)\n\n const MAX_VISIBLE_TRACKS = 4\n\n const realTracks: MuxTextTrack[] = propTracks\n ? propTracks\n : asset.data?.tracks?.filter((track): track is MuxTextTrack => track.type === 'text') || []\n\n const activeTracks = realTracks.filter(\n (track) =>\n track.id &&\n (track.status === 'ready' || track.status === 'preparing' || track.status === 'errored'),\n )\n\n const allTracks = useMemo(() => {\n const tracksWithUpdates = activeTracks.map((track) => {\n const updated = updatedTracks.get(track.id)\n return updated || track\n })\n\n const isMockTrackReplaced = (mockTrack: MuxTextTrack, realTracksList: MuxTextTrack[]) => {\n if (!mockTrack.id || !mockTrack.id.startsWith('generating-')) {\n return false\n }\n return realTracksList.some((realTrack) => {\n const nameMatches = realTrack.name === mockTrack.name\n const languageMatches = realTrack.language_code === mockTrack.language_code\n if (!nameMatches || !languageMatches) {\n return false\n }\n if (realTrack.status === 'ready') {\n const isGenerated =\n realTrack.text_source === 'generated_live' ||\n realTrack.text_source === 'generated_live_final' ||\n realTrack.text_source === 'generated_vod'\n return isGenerated\n }\n if (realTrack.status === 'preparing') {\n return true\n }\n return false\n })\n }\n\n const isTrackAlreadyInRealTracks = (\n addedTrack: MuxTextTrack,\n realTracksList: MuxTextTrack[],\n ) => {\n if (!addedTrack.id) return false\n if (addedTrack.id.startsWith('generating-')) {\n return isMockTrackReplaced(addedTrack, realTracksList)\n }\n return realTracksList.some((realTrack) => realTrack.id === addedTrack.id)\n }\n\n const tracksToKeep = addedTracks.filter((addedTrack) => {\n if (addedTrack.id && addedTrack.id.startsWith('generating-')) {\n return !isMockTrackReplaced(addedTrack, tracksWithUpdates)\n }\n return !isTrackAlreadyInRealTracks(addedTrack, tracksWithUpdates)\n })\n\n return [...tracksWithUpdates, ...tracksToKeep]\n }, [activeTracks, addedTracks, updatedTracks])\n\n useEffect(() => {\n const newAutogeneratedIds = new Set<string>()\n\n activeTracks.forEach((track) => {\n if (\n track.id &&\n (track.text_source === 'generated_live' ||\n track.text_source === 'generated_live_final' ||\n track.text_source === 'generated_vod')\n ) {\n newAutogeneratedIds.add(track.id)\n }\n })\n\n addedTracks.forEach((mockTrack) => {\n if (mockTrack.id && mockTrack.id.startsWith('generating-')) {\n const realTrack = activeTracks.find((rt) => {\n const nameMatches = rt.name === mockTrack.name\n const languageMatches = rt.language_code === mockTrack.language_code\n return nameMatches && languageMatches\n })\n if (realTrack?.id) {\n newAutogeneratedIds.add(realTrack.id)\n }\n }\n })\n\n // oxlint-disable-next-line react/react-compiler\n setAutogeneratedTrackIds((prev) => {\n let hasNew = false\n const updated = new Set(prev)\n newAutogeneratedIds.forEach((id) => {\n if (!prev.has(id)) {\n updated.add(id)\n hasNew = true\n }\n })\n return hasNew ? updated : prev\n })\n }, [activeTracks, addedTracks])\n\n useEffect(() => {\n const preparingTracks = allTracks.filter((track) => track.status === 'preparing')\n if (preparingTracks.length === 0 || !asset.assetId || !asset._id) {\n return undefined\n }\n\n const interval = setInterval(async () => {\n try {\n const muxData = await resyncAsset(asset)\n if (!muxData) return\n\n const fetchedTracks =\n muxData.tracks?.filter((track): track is MuxTextTrack => track.type === 'text') || []\n\n const isMockTrackReplaced = (\n mockTrack: MuxTextTrack,\n fetchedTracksList: MuxTextTrack[],\n ) => {\n if (!mockTrack.id || !mockTrack.id.startsWith('generating-')) {\n return false\n }\n return fetchedTracksList.some((realTrack) => {\n const nameMatches = realTrack.name === mockTrack.name\n const languageMatches = realTrack.language_code === mockTrack.language_code\n if (!nameMatches || !languageMatches) {\n return false\n }\n if (realTrack.status === 'ready') {\n const isGenerated =\n realTrack.text_source === 'generated_live' ||\n realTrack.text_source === 'generated_live_final' ||\n realTrack.text_source === 'generated_vod'\n return isGenerated\n }\n if (realTrack.status === 'preparing') {\n return true\n }\n return false\n })\n }\n\n const newAutogeneratedIds = new Set<string>()\n fetchedTracks.forEach((track) => {\n if (\n track.id &&\n (track.text_source === 'generated_live' ||\n track.text_source === 'generated_live_final' ||\n track.text_source === 'generated_vod')\n ) {\n newAutogeneratedIds.add(track.id)\n }\n })\n\n const findMatchingRealTrack = (mockTrack: MuxTextTrack, tracksList: MuxTextTrack[]) => {\n return tracksList.find((rt) => {\n const nameMatches = rt.name === mockTrack.name\n const languageMatches = rt.language_code === mockTrack.language_code\n return nameMatches && languageMatches\n })\n }\n\n setAddedTracks((prev) => {\n return prev.filter((mockTrack) => {\n if (mockTrack.id && mockTrack.id.startsWith('generating-')) {\n const replaced = isMockTrackReplaced(mockTrack, fetchedTracks)\n if (replaced) {\n const realTrack = findMatchingRealTrack(mockTrack, fetchedTracks)\n if (realTrack?.id) {\n newAutogeneratedIds.add(realTrack.id)\n setTrackActivityOrder((prevOrder) => {\n const mockOrder = prevOrder.get(mockTrack.id)\n if (mockOrder) {\n const newMap = new Map(prevOrder)\n newMap.set(realTrack.id, mockOrder)\n return newMap\n }\n return prevOrder\n })\n }\n }\n return !replaced\n }\n return true\n })\n })\n\n if (newAutogeneratedIds.size > 0) {\n setAutogeneratedTrackIds((prevIds) => {\n const updated = new Set(prevIds)\n newAutogeneratedIds.forEach((id) => updated.add(id))\n return updated\n })\n }\n } catch (error) {\n console.error('Failed to refresh asset data:', error)\n }\n }, 3000) // Poll every 3 seconds\n\n return () => clearInterval(interval)\n }, [allTracks, asset, resyncAsset])\n\n const visibleTracks = allTracks\n .filter(\n (track) =>\n track.status === 'ready' || track.status === 'preparing' || track.status === 'errored',\n )\n .sort((a, b) => {\n const orderA = trackActivityOrder.get(a.id) || 0\n const orderB = trackActivityOrder.get(b.id) || 0\n\n if (orderA > 0 && orderB > 0) {\n return orderB - orderA\n }\n\n if (orderA > 0) return -1\n if (orderB > 0) return 1\n\n const aIsPreparing = a.status === 'preparing'\n const bIsPreparing = b.status === 'preparing'\n if (aIsPreparing && !bIsPreparing) return -1\n if (!aIsPreparing && bIsPreparing) return 1\n\n const aIsAutogenerated =\n (a.id && a.id.startsWith('generating-')) || (a.id && autogeneratedTrackIds.has(a.id))\n const bIsAutogenerated =\n (b.id && b.id.startsWith('generating-')) || (b.id && autogeneratedTrackIds.has(b.id))\n if (aIsAutogenerated && !bIsAutogenerated) return -1\n if (!aIsAutogenerated && bIsAutogenerated) return 1\n\n return 0\n })\n\n const handleDownload = async (track: MuxTextTrack) => {\n if (!track.id) return\n\n setDownloadingTrackId(track.id)\n try {\n await downloadVttFile(client, asset, track)\n } catch (error) {\n toast.push({\n title: 'Failed to download VTT file',\n status: 'error',\n description: error instanceof Error ? error.message : 'Please try again',\n })\n } finally {\n setDownloadingTrackId(null)\n }\n }\n\n const confirmDelete = async () => {\n if (!trackToDelete || !trackToDelete.id) return\n\n const track = trackToDelete\n setTrackToDelete(null)\n setDeletingTrackId(track.id)\n try {\n if (!asset.assetId) {\n throw new Error('Asset ID is required')\n }\n await deleteTextTrack(client, asset.assetId, track.id)\n\n // Refresh asset data after deletion\n await resyncAsset(asset)\n\n toast.push({\n title: 'Successfully deleted caption track',\n status: 'success',\n })\n\n setAddedTracks((prev) => prev.filter((t) => t.id !== track.id))\n setUpdatedTracks((prev) => {\n const newMap = new Map(prev)\n newMap.delete(track.id)\n return newMap\n })\n setTrackActivityOrder((prev) => {\n const newMap = new Map(prev)\n newMap.delete(track.id)\n return newMap\n })\n setAutogeneratedTrackIds((prev) => {\n const updated = new Set(prev)\n updated.delete(track.id)\n return updated\n })\n } catch (error) {\n toast.push({\n title: 'Failed to delete caption track',\n status: 'error',\n description: error instanceof Error ? error.message : 'Please try again',\n })\n } finally {\n setDeletingTrackId(null)\n }\n }\n\n const handleAddTrack = (track: MuxTextTrack) => {\n setAddedTracks((prev) => [...prev, track])\n setTrackActivityOrder((prev) => {\n const newMap = new Map(prev)\n newMap.set(track.id, prev.size + 1)\n return newMap\n })\n setShowAddDialog(false)\n }\n\n const handleUpdateTrack = async (updatedTrack: MuxTextTrack, oldTrackId?: string) => {\n if (oldTrackId) {\n setAddedTracks((prev) => prev.filter((t) => t.id !== oldTrackId))\n setUpdatedTracks((prev) => {\n const newMap = new Map(prev)\n newMap.delete(oldTrackId)\n return newMap\n })\n setTrackActivityOrder((prev) => {\n const newMap = new Map(prev)\n newMap.delete(oldTrackId)\n return newMap\n })\n setAutogeneratedTrackIds((prev) => {\n const updated = new Set(prev)\n updated.delete(oldTrackId)\n return updated\n })\n }\n\n const isAddedTrack = addedTracks.some((t) => t.id === updatedTrack.id)\n\n if (isAddedTrack) {\n setAddedTracks((prev) => prev.map((t) => (t.id === updatedTrack.id ? updatedTrack : t)))\n } else {\n setUpdatedTracks((prev) => {\n const newMap = new Map(prev)\n newMap.set(updatedTrack.id, updatedTrack)\n return newMap\n })\n }\n\n setTrackActivityOrder((prev) => {\n const newMap = new Map(prev)\n newMap.set(updatedTrack.id, prev.size + 1)\n return newMap\n })\n\n setTrackToEdit(null)\n\n // Refresh asset data after update\n await resyncAsset(asset)\n }\n\n const getTrackSourceLabel = (track: MuxTextTrack) => {\n if (track.id && track.id.startsWith('generating-')) {\n return 'Auto-generated'\n }\n if (track.id && autogeneratedTrackIds.has(track.id)) {\n return 'Auto-generated'\n }\n if (\n track.text_source === 'generated_live_final' ||\n track.text_source === 'generated_live' ||\n track.text_source === 'generated_vod'\n ) {\n return 'Auto-generated'\n }\n if (track.text_source === 'uploaded') {\n return 'Uploaded'\n }\n return 'Custom'\n }\n\n if (visibleTracks.length === 0 && !showAddDialog) {\n return (\n <Stack space={3}>\n <Flex justify=\"flex-end\">\n <Button\n icon={AddIcon}\n text=\"Add Caption\"\n tone=\"primary\"\n onClick={() => setShowAddDialog(true)}\n />\n </Flex>\n <Card padding={4} radius={2} tone=\"transparent\" border>\n <Text size={1} muted>\n No captions available. Add captions when uploading a video or add them manually.\n </Text>\n </Card>\n {showAddDialog && (\n <AddCaptionDialog\n asset={asset}\n onAdd={handleAddTrack}\n onClose={() => setShowAddDialog(false)}\n />\n )}\n </Stack>\n )\n }\n\n const displayedTracks =\n collapseTracks && !isExpanded ? visibleTracks.slice(0, MAX_VISIBLE_TRACKS) : visibleTracks\n const hasMoreTracks = collapseTracks && visibleTracks.length > MAX_VISIBLE_TRACKS\n\n return (\n <Stack space={3}>\n <Flex justify=\"flex-end\">\n <Button\n icon={AddIcon}\n text=\"Add Caption\"\n tone=\"primary\"\n onClick={() => setShowAddDialog(true)}\n />\n </Flex>\n\n {displayedTracks.map((track) => (\n <TrackCard\n key={track.id}\n track={track}\n iconOnly={iconOnly}\n downloadingTrackId={downloadingTrackId}\n deletingTrackId={deletingTrackId}\n trackToEdit={trackToEdit}\n getTrackSourceLabel={getTrackSourceLabel}\n handleDownload={handleDownload}\n setTrackToEdit={setTrackToEdit}\n setTrackToDelete={setTrackToDelete}\n />\n ))}\n\n {hasMoreTracks && (\n <Flex justify=\"center\">\n <Button\n icon={isExpanded ? ChevronUpIcon : ChevronDownIcon}\n text={\n isExpanded ? 'Show less' : `Show ${visibleTracks.length - MAX_VISIBLE_TRACKS} more`\n }\n mode=\"ghost\"\n tone=\"primary\"\n onClick={() => setIsExpanded(!isExpanded)}\n />\n </Flex>\n )}\n\n {trackToDelete && (\n <Dialog\n animate\n id={dialogId}\n header=\"Delete track\"\n onClose={() => setTrackToDelete(null)}\n onClickOutside={() => setTrackToDelete(null)}\n width={1}\n >\n <Card\n padding={3}\n style={{\n minHeight: '150px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <Stack space={3}>\n <Heading size={2}>\n Are you sure you want to delete "\n {trackToDelete.name || trackToDelete.language_code || 'Untitled'}"?\n </Heading>\n <Text size={2}>This action is irreversible</Text>\n <Stack space={4} marginY={4}>\n <Box>\n <Button\n icon={\n deletingTrackId === trackToDelete.id ? (\n <Spinner\n style={{\n verticalAlign: 'middle',\n display: 'inline-block',\n marginTop: '-2px',\n width: '0.5em',\n height: '0.5em',\n }}\n />\n ) : (\n <TrashIcon />\n )\n }\n fontSize={2}\n padding={3}\n text=\"Delete track\"\n tone=\"critical\"\n onClick={confirmDelete}\n disabled={deletingTrackId !== null}\n />\n </Box>\n </Stack>\n </Stack>\n </Card>\n </Dialog>\n )}\n\n {showAddDialog && (\n <AddCaptionDialog\n asset={asset}\n onAdd={handleAddTrack}\n onClose={() => setShowAddDialog(false)}\n />\n )}\n\n {trackToEdit && (\n <EditCaptionDialog\n asset={asset}\n track={trackToEdit}\n onUpdate={handleUpdateTrack}\n onClose={() => setTrackToEdit(null)}\n />\n )}\n </Stack>\n )\n}\n","import {createContext, useContext, useMemo} from 'react'\n\nimport {type DialogState, type SetDialogState} from '../hooks/useDialogState'\n\ntype DialogStateContextProps = {\n dialogState: DialogState\n setDialogState: SetDialogState\n}\n\nconst DialogStateContext = createContext<DialogStateContextProps>({\n dialogState: false,\n setDialogState: () => {\n return null\n },\n})\n\ninterface DialogStateProviderProps extends DialogStateContextProps {\n children: React.ReactNode\n}\n\nexport const DialogStateProvider = ({\n dialogState,\n setDialogState,\n children,\n}: DialogStateProviderProps) => {\n const value = useMemo(() => ({dialogState, setDialogState}), [dialogState, setDialogState])\n return <DialogStateContext.Provider value={value}>{children}</DialogStateContext.Provider>\n}\n\nexport const useDialogStateContext = () => {\n const context = useContext(DialogStateContext)\n return context\n}\n","import type {SanityClient} from 'sanity'\n\nimport {generateJwt} from './generateJwt'\nimport type {MuxPlaybackId, MuxVideoUrl} from './types'\n\ninterface VideoSrcOptions {\n muxPlaybackId: MuxPlaybackId\n client: SanityClient\n}\n\n/**\n * May throw a Promise. Call this with {@link tryWithSuspend} or rethrow the Promise\n */\nexport function getVideoSrc({client, muxPlaybackId}: VideoSrcOptions): MuxVideoUrl {\n const searchParams = new URLSearchParams()\n\n if (muxPlaybackId.policy === 'signed' || muxPlaybackId.policy === 'drm') {\n const token = generateJwt(client, muxPlaybackId.id, 'v')\n searchParams.set('token', token)\n }\n\n return `https://stream.mux.com/${muxPlaybackId.id}.m3u8?${searchParams}`\n}\n","import {Dialog, Stack} from '@sanity/ui'\nimport {useId} from 'react'\n\nimport {useDialogStateContext} from '../context/DialogStateContext'\nimport type {VideoAssetDocument} from '../util/types'\nimport TextTracksManager from './TextTracksManager'\n\nexport interface Props {\n asset: VideoAssetDocument\n}\n\nexport default function CaptionsDialog({asset}: Props) {\n const {setDialogState} = useDialogStateContext()\n const dialogId = `CaptionsDialog${useId()}`\n\n return (\n <Dialog id={dialogId} header=\"Edit Captions\" onClose={() => setDialogState(false)} width={1}>\n <Stack padding={4}>\n <TextTracksManager asset={asset} />\n </Stack>\n </Dialog>\n )\n}\n","// From: https://stackoverflow.com/a/11486026/10433647\nexport function formatSeconds(seconds: number): string {\n if (typeof seconds !== 'number' || Number.isNaN(seconds)) {\n return ''\n }\n // Hours, minutes and seconds\n const hrs = ~~(seconds / 3600)\n const mins = ~~((seconds % 3600) / 60)\n const secs = ~~seconds % 60\n\n // Output like \"1:01\" or \"4:03:59\" or \"123:03:59\"\n let ret = ''\n\n if (hrs > 0) {\n ret += '' + hrs + ':' + (mins < 10 ? '0' : '')\n }\n\n ret += '' + mins + ':' + (secs < 10 ? '0' : '')\n ret += '' + secs\n return ret\n}\n\n// Output like \"05:14:01\"\nexport function formatSecondsToHHMMSS(seconds: number): string {\n const hrs = Math.floor(seconds / 3600)\n .toString()\n .padStart(2, '0')\n const mins = Math.floor((seconds % 3600) / 60)\n .toString()\n .padStart(2, '0')\n const secs = Math.floor(seconds % 60)\n .toString()\n .padStart(2, '0')\n\n return `${hrs}:${mins}:${secs}`\n}\n\n// Checks if time has a HH:MM:SS format like \"05:14:01\"\nexport function isValidTimeFormat(time: string) {\n const regex = /^([0-1]?[0-9]|2[0-3]):([0-5]?[0-9]):([0-5]?[0-9])$/\n return regex.test(time) || time === ''\n}\n\n// Converts a time like \"05:14:01\" to seconds\nexport function getSecondsFromTimeFormat(time: string): number {\n const [hh = 0, mm = 0, ss = 0] = time.split(':').map(Number)\n return hh * 3600 + mm * 60 + ss\n}\n","import {Button, Dialog, Flex, Stack, Text, TextInput} from '@sanity/ui'\nimport {useId, useMemo, useState} from 'react'\nimport {getDevicePixelRatio} from 'use-device-pixel-ratio'\n\nimport {useDialogStateContext} from '../context/DialogStateContext'\nimport {useClient} from '../hooks/useClient'\nimport {\n formatSecondsToHHMMSS,\n getSecondsFromTimeFormat,\n isValidTimeFormat,\n} from '../util/formatSeconds'\nimport type {VideoAssetDocument} from '../util/types'\nimport VideoThumbnail from './VideoThumbnail'\n\nexport interface Props {\n asset: VideoAssetDocument\n currentTime?: number\n}\n\nexport default function EditThumbnailDialog({asset, currentTime = 0}: Props) {\n const client = useClient()\n\n const {setDialogState} = useDialogStateContext()\n const dialogId = `EditThumbnailDialog${useId()}`\n\n const [timeFormatted, setTimeFormatted] = useState<string>(() =>\n formatSecondsToHHMMSS(currentTime),\n )\n const [nextTime, setNextTime] = useState<number>(currentTime)\n const [inputError, setInputError] = useState<string>('')\n\n const assetWithNewThumbnail = useMemo(() => ({...asset, thumbTime: nextTime}), [asset, nextTime])\n const [saving, setSaving] = useState(false)\n const [saveThumbnailError, setSaveThumbnailError] = useState<Error | null>(null)\n const handleSave = () => {\n setSaving(true)\n client\n .patch(asset._id)\n .set({thumbTime: nextTime})\n .commit({returnDocuments: false})\n .then(() => setDialogState(false))\n .catch(setSaveThumbnailError)\n .finally(() => setSaving(false))\n }\n const width = 300 * getDevicePixelRatio({maxDpr: 2})\n\n if (saveThumbnailError) {\n // @TODO handle errors more gracefully\n throw saveThumbnailError\n }\n\n const handleInputChange = (event: React.FormEvent<HTMLInputElement>) => {\n const value = event.currentTarget.value\n setTimeFormatted(value)\n\n if (isValidTimeFormat(value)) {\n setInputError('')\n const totalSeconds = getSecondsFromTimeFormat(value)\n setNextTime(totalSeconds)\n } else {\n setInputError('Invalid time format')\n }\n }\n\n return (\n <Dialog\n id={dialogId}\n header=\"Edit thumbnail\"\n onClose={() => setDialogState(false)}\n footer={\n <Stack padding={3}>\n <Button\n key=\"thumbnail\"\n disabled={inputError !== ''}\n mode=\"ghost\"\n tone=\"primary\"\n loading={saving}\n onClick={handleSave}\n text=\"Set new thumbnail\"\n />\n </Stack>\n }\n >\n <Stack space={3} padding={3}>\n <Stack space={2}>\n <Text size={1} weight=\"semibold\">\n Current:\n </Text>\n <VideoThumbnail asset={asset} width={width} staticImage />\n </Stack>\n <Stack space={2}>\n <Text size={1} weight=\"semibold\">\n New:\n </Text>\n <VideoThumbnail asset={assetWithNewThumbnail} width={width} staticImage />\n </Stack>\n\n <Stack space={2}>\n <Flex align={'center'} justify={'center'}>\n <Text size={5} weight=\"semibold\">\n Or\n </Text>\n </Flex>\n </Stack>\n\n <Stack space={2}>\n <Text size={1} weight=\"semibold\">\n Selected time for thumbnail (hh:mm:ss):\n </Text>\n <TextInput\n size={1}\n value={timeFormatted}\n placeholder=\"hh:mm:ss\"\n onChange={handleInputChange}\n customValidity={inputError}\n />\n </Stack>\n </Stack>\n </Dialog>\n )\n}\n","import type {SVGProps} from 'react'\n\nexport function AudioIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1em\" height=\"1em\" viewBox=\"0 0 24 24\" {...props}>\n <path\n fill=\"currentColor\"\n style={{opacity: '0.65'}}\n d=\"M10.75 19q.95 0 1.6-.65t.65-1.6V13h3v-2h-4v3.875q-.275-.2-.587-.288t-.663-.087q-.95 0-1.6.65t-.65 1.6t.65 1.6t1.6.65M6 22q-.825 0-1.412-.587T4 20V4q0-.825.588-1.412T6 2h8l6 6v12q0 .825-.587 1.413T18 22zm7-13V4H6v16h12V9zM6 4v5zv16z\"\n />\n </svg>\n )\n}\n","import {Box, Dialog, Stack} from '@sanity/ui'\nimport {useId} from 'react'\n\nimport {useDialogStateContext} from '../context/DialogStateContext'\nimport {getMezzanineStatus} from '../hooks/useMezzanine'\nimport {DIALOGS_Z_INDEX} from '../util/constants'\nimport type {VideoAssetDocument} from '../util/types'\nimport Mezzanine from './Mezzanine'\nimport MezzanineExplanation from './MezzanineExplanation'\n\nexport interface Props {\n asset: VideoAssetDocument\n onClose?: () => void\n}\n\n/**\n * Player actions menu entry point: the explanation in the dialog body (until the\n * file is enabled) with the {@link Mezzanine} card below for the action/status.\n */\nexport default function MezzanineDialog({asset, onClose}: Props) {\n const {setDialogState} = useDialogStateContext()\n const dialogId = `MezzanineDialog${useId()}`\n\n const closing = () => {\n onClose?.()\n setDialogState(false)\n }\n\n const status = getMezzanineStatus(asset)\n const showExplanation = status !== 'preparing' && status !== 'ready'\n\n return (\n <Dialog\n id={dialogId}\n header=\"Mezzanine file\"\n onClose={closing}\n zOffset={DIALOGS_Z_INDEX}\n width={1}\n >\n <Box padding={4}>\n <Stack space={4}>\n {showExplanation && <MezzanineExplanation />}\n <Mezzanine asset={asset} withExplanation={false} />\n </Stack>\n </Box>\n </Dialog>\n )\n}\n","import {type MuxPlayerProps, type MuxPlayerRefAttributes} from '@mux/mux-player-react'\nimport MuxPlayer from '@mux/mux-player-react/lazy'\nimport {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {Card, Text} from '@sanity/ui'\nimport {type PropsWithChildren, Suspense, useMemo, useRef, useState} from 'react'\n\nimport {useDialogStateContext} from '../context/DialogStateContext'\nimport {useClient} from '../hooks/useClient'\nimport {AUDIO_ASPECT_RATIO, MIN_ASPECT_RATIO} from '../util/constants'\nimport {generateJwt} from '../util/generateJwt'\nimport {getPlaybackId} from '../util/getPlaybackPolicy'\nimport {getPlaybackPolicyById} from '../util/getPlaybackPolicy'\nimport {getPosterSrc} from '../util/getPosterSrc'\nimport {getVideoSrc} from '../util/getVideoSrc'\nimport {tryWithSuspend} from '../util/tryWithSuspend'\nimport type {VideoAssetDocument} from '../util/types'\nimport CaptionsDialog from './CaptionsDialog'\nimport EditThumbnailDialog from './EditThumbnailDialog'\nimport {AudioIcon} from './icons/Audio'\nimport MezzanineDialog from './MezzanineDialog'\n\nexport default function VideoPlayer({\n asset,\n thumbnailWidth = 250,\n children,\n hlsConfig,\n ...props\n}: PropsWithChildren<\n {\n asset: VideoAssetDocument\n thumbnailWidth?: number\n forceAspectRatio?: number\n hlsConfig?: MuxPlayerProps['_hlsConfig']\n } & Partial<Pick<MuxPlayerProps, 'autoPlay'>>\n>) {\n const client = useClient()\n const {dialogState} = useDialogStateContext()\n\n const isAudio = assetIsAudio(asset)\n const muxPlayer = useRef<MuxPlayerRefAttributes>(null)\n const playerContainerRef = useRef<HTMLDivElement>(null)\n const [error, setError] = useState<Error>()\n\n /* Playback ID that will be used to play the video */\n const playbackId = useMemo(() => {\n try {\n return getPlaybackId(asset, ['public', 'signed', 'drm'])\n } catch (e) {\n // oxlint-disable-next-line react/react-compiler\n setError(new TypeError('Asset has no playback ID', {cause: e}))\n return undefined\n }\n }, [asset])\n\n const muxPlaybackId = useMemo(() => {\n if (!playbackId) return undefined\n return getPlaybackPolicyById(asset, playbackId)\n }, [asset, playbackId])\n\n const src = useMemo(() => {\n if (!playbackId) return undefined\n if (!muxPlaybackId) return undefined\n return tryWithSuspend(\n () => getVideoSrc({muxPlaybackId, client}),\n (e: Error) => {\n setError(e)\n return undefined\n },\n )\n }, [muxPlaybackId, playbackId, client])\n\n const poster = useMemo(() => {\n return tryWithSuspend(\n () => getPosterSrc({asset, client, width: thumbnailWidth}),\n (e: Error) => {\n setError(e)\n return undefined\n },\n )\n }, [asset, client, thumbnailWidth])\n\n const signedToken = useMemo(() => {\n try {\n const url = new URL(src!)\n return url.searchParams.get('token')\n } catch {\n return undefined\n }\n }, [src])\n const drmToken = useMemo(() => {\n if (!playbackId) return undefined\n if (muxPlaybackId?.policy !== 'drm') return undefined\n\n return tryWithSuspend(\n () => generateJwt(client, playbackId, 'd'),\n (e: Error) => {\n setError(e)\n return undefined\n },\n )\n }, [client, muxPlaybackId?.policy, playbackId])\n const tokens:\n | Partial<{\n playback?: string\n thumbnail?: string\n storyboard?: string\n drm?: string\n }>\n | undefined = useMemo(() => {\n try {\n const partialTokens: {\n playback?: string\n thumbnail?: string\n storyboard?: string\n drm?: string\n } = {\n playback: undefined,\n thumbnail: undefined,\n storyboard: undefined,\n drm: undefined,\n }\n\n if (signedToken) {\n partialTokens.playback = signedToken\n partialTokens.thumbnail = signedToken\n partialTokens.storyboard = signedToken\n }\n\n if (drmToken) {\n partialTokens.drm = drmToken\n }\n\n return {...partialTokens}\n } catch {\n return undefined\n }\n }, [signedToken, drmToken])\n\n const [width, height] = (asset?.data?.aspect_ratio ?? '16:9').split(':').map(Number)\n const targetAspectRatio =\n props.forceAspectRatio || (Number.isNaN(width) ? 16 / 9 : width! / height!)\n let aspectRatio = Math.max(MIN_ASPECT_RATIO, targetAspectRatio)\n if (isAudio) {\n aspectRatio = props.forceAspectRatio\n ? // Make it wider when forcing aspect ratio to balance with videos' rendering height (audio players overflow a bit)\n props.forceAspectRatio * 1.2\n : AUDIO_ASPECT_RATIO\n }\n\n /* We use Suspense here because `generateJwt` and related functions use suspend()\n under the hood */\n return (\n <>\n <Card\n ref={playerContainerRef}\n tone=\"transparent\"\n style={{\n aspectRatio: aspectRatio,\n position: 'relative',\n ...(isAudio && {display: 'flex', alignItems: 'flex-end'}),\n }}\n >\n {src && poster && (\n <>\n {isAudio && (\n <AudioIcon\n style={{\n padding: '0.5em',\n width: '2.2em',\n height: '2.2em',\n position: 'absolute',\n top: 0,\n left: 0,\n zIndex: 1,\n }}\n />\n )}\n <Suspense fallback={null}>\n <MuxPlayer\n poster={isAudio ? undefined : poster}\n ref={muxPlayer}\n {...props}\n playsInline\n playbackId={playbackId}\n tokens={tokens}\n preload=\"metadata\"\n crossOrigin=\"anonymous\"\n metadata={{\n player_name: 'Sanity Admin Dashboard',\n // @ts-expect-error - this constant is search/replaced so must be exact, not accessed with an index signature\n player_version: process.env.PKG_VERSION,\n page_type: 'Preview Player',\n }}\n audio={isAudio}\n _hlsConfig={hlsConfig}\n style={{\n ...(!isAudio && {height: '100%'}),\n width: '100%',\n display: 'block',\n objectFit: 'contain',\n ...(isAudio && {alignSelf: 'end'}),\n }}\n />\n {children}\n </Suspense>\n </>\n )}\n {error ? (\n <div\n style={{\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n }}\n >\n <Text muted>\n <ErrorOutlineIcon style={{marginRight: '0.15em'}} />\n {typeof error === 'object' && 'message' in error && typeof error.message === 'string'\n ? error.message\n : 'Error loading video'}\n </Text>\n </div>\n ) : null}\n {children}\n </Card>\n\n {dialogState === 'edit-thumbnail' && (\n <EditThumbnailDialog\n asset={asset}\n // oxlint-disable-next-line react/react-compiler\n currentTime={muxPlayer?.current?.currentTime}\n />\n )}\n {dialogState === 'edit-captions' && <CaptionsDialog asset={asset} />}\n {dialogState === 'mezzanine' && <MezzanineDialog asset={asset} />}\n </>\n )\n}\n\nexport function assetIsAudio(asset: VideoAssetDocument) {\n return asset.data?.max_stored_resolution === 'Audio only'\n}\n","// Adapted from https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/desk/components/MissingSchemaType.tsx\nimport {WarningOutlineIcon} from '@sanity/icons/WarningOutline'\nimport type {SanityDocument} from 'sanity'\nimport type {GeneralPreviewLayoutKey} from 'sanity'\nimport {SanityDefaultPreview} from 'sanity'\n\nexport interface MissingSchemaTypeProps {\n layout?: GeneralPreviewLayoutKey\n value: SanityDocument\n}\n\nconst getUnknownTypeFallback = (id: string, typeName: string) => ({\n title: (\n <em>\n No schema found for type <code>{typeName}</code>\n </em>\n ),\n subtitle: (\n <em>\n Document: <code>{id}</code>\n </em>\n ),\n media: () => <WarningOutlineIcon />,\n})\n\nexport function MissingSchemaType(props: MissingSchemaTypeProps) {\n const {layout, value} = props\n\n return (\n <SanityDefaultPreview {...getUnknownTypeFallback(value._id, value._type)} layout={layout} />\n )\n}\n","// Adapted from https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/desk/components/TimeAgo.tsx\nimport {useTimeAgo} from 'sanity'\n\nexport interface TimeAgoProps {\n time: string | Date\n}\n\nexport function TimeAgo({time}: TimeAgoProps) {\n const timeAgo = useTimeAgo(time)\n\n return <span title={timeAgo}>{timeAgo} ago</span>\n}\n","// Adapted from https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/desk/components/DraftStatus.tsx\nimport {EditIcon} from '@sanity/icons/Edit'\nimport {Box, Text, Tooltip} from '@sanity/ui'\nimport type {PreviewValue, SanityDocument} from 'sanity'\nimport {TextWithTone} from 'sanity'\n\nimport {TimeAgo} from './TimeAgo'\n\nexport function DraftStatus(props: {document?: PreviewValue | Partial<SanityDocument> | null}) {\n const {document} = props\n const updatedAt = document && '_updatedAt' in document && document._updatedAt\n\n return (\n <Tooltip\n animate\n portal\n content={\n <Box padding={2}>\n <Text size={1}>\n {document ? (\n <>Edited {updatedAt && <TimeAgo time={updatedAt} />}</>\n ) : (\n <>No unpublished edits</>\n )}\n </Text>\n </Box>\n }\n >\n <TextWithTone tone=\"caution\" dimmed={!document} muted={!document} size={1}>\n <EditIcon />\n </TextWithTone>\n </Tooltip>\n )\n}\n","// Adapted from https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/desk/components/PublishedStatus.tsx\n\nimport {PublishIcon} from '@sanity/icons/Publish'\nimport {Box, Text, Tooltip} from '@sanity/ui'\nimport type {PreviewValue, SanityDocument} from 'sanity'\nimport {TextWithTone} from 'sanity'\n\nimport {TimeAgo} from './TimeAgo'\n\nexport function PublishedStatus(props: {document?: PreviewValue | Partial<SanityDocument> | null}) {\n const {document} = props\n const updatedAt = document && '_updatedAt' in document && document._updatedAt\n\n return (\n <Tooltip\n animate\n portal\n content={\n <Box padding={2}>\n <Text size={1}>\n {document ? (\n <>Published {updatedAt && <TimeAgo time={updatedAt} />}</>\n ) : (\n <>Not published</>\n )}\n </Text>\n </Box>\n }\n >\n <TextWithTone tone=\"positive\" dimmed={!document} muted={!document} size={1}>\n <PublishIcon />\n </TextWithTone>\n </Tooltip>\n )\n}\n","// Adapted from:\n// https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/desk/components/paneItem/PaneItemPreview.tsx\nimport {Inline} from '@sanity/ui'\nimport {isNumber, isString} from 'lodash'\nimport {isValidElement, useMemo} from 'react'\nimport {useObservable} from 'react-rx'\nimport type {SanityDocument, SchemaType} from 'sanity'\nimport {\n type DocumentPresence,\n DocumentPreviewPresence,\n type DocumentPreviewStore,\n type GeneralPreviewLayoutKey,\n getPreviewStateObservable,\n getPreviewValueWithFallback,\n isRecord,\n SanityDefaultPreview,\n} from 'sanity'\n\nimport {DraftStatus} from './DraftStatus'\nimport {PublishedStatus} from './PublishedStatus'\n\nexport interface PaneItemPreviewProps {\n documentPreviewStore: DocumentPreviewStore\n icon: React.ComponentType | false\n layout: GeneralPreviewLayoutKey\n presence?: DocumentPresence[]\n schemaType: SchemaType\n value: SanityDocument\n}\n\nexport function PaneItemPreview(props: PaneItemPreviewProps) {\n const {icon, layout, presence, schemaType, value} = props\n const title =\n (isRecord(value['title']) && isValidElement(value['title'])) ||\n isString(value['title']) ||\n isNumber(value['title'])\n ? value['title']\n : null\n\n const observable = useMemo(\n () => getPreviewStateObservable(props.documentPreviewStore, schemaType, value._id),\n [props.documentPreviewStore, schemaType, value._id],\n )\n const {snapshot, original, isLoading} = useObservable(observable, {\n isLoading: true,\n snapshot: null,\n original: null,\n })\n\n const status = isLoading ? null : (\n <Inline space={4}>\n {presence && presence.length > 0 && <DocumentPreviewPresence presence={presence} />}\n <PublishedStatus document={original} />\n <DraftStatus document={snapshot} />\n </Inline>\n )\n\n return (\n <SanityDefaultPreview\n {...(getPreviewValueWithFallback({snapshot, original, fallback: {title}}) as any)}\n isPlaceholder={isLoading}\n icon={icon}\n layout={layout}\n status={status}\n />\n )\n}\n","// Adapted from https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/desk/components/paneItem/PaneItem.tsx\n\nimport {DocumentIcon} from '@sanity/icons/Document'\nimport type {PropsWithChildren} from 'react'\nimport {useMemo} from 'react'\nimport type {CollatedHit, FIXME, SanityDocument, SchemaType} from 'sanity'\nimport {PreviewCard, useDocumentPresence, useDocumentPreviewStore, useSchema} from 'sanity'\nimport {IntentLink} from 'sanity/router'\n\nimport {MissingSchemaType} from './MissingSchemaType'\nimport {PaneItemPreview} from './PaneItemPreview'\n\ninterface DocumentPreviewProps {\n schemaType?: SchemaType\n documentPair: CollatedHit<SanityDocument>\n}\n\n/**\n * Return `false` if we explicitly disable the icon.\n * Otherwise return the passed icon or the schema type icon as a backup.\n */\nfunction getIconWithFallback(\n icon: React.ComponentType<any> | false | undefined,\n schemaType: SchemaType | undefined,\n defaultIcon: React.ComponentType<any>,\n): React.ComponentType<any> | false {\n if (icon === false) {\n return false\n }\n\n return icon || ((schemaType && schemaType.icon) as any) || defaultIcon || false\n}\n\nfunction DocumentPreviewLink(props: DocumentPreviewProps) {\n return (linkProps: PropsWithChildren) => (\n <IntentLink intent=\"edit\" params={{id: props.documentPair.id}}>\n {linkProps.children}\n </IntentLink>\n )\n}\n\nexport function DocumentPreview(props: DocumentPreviewProps) {\n const {schemaType, documentPair} = props\n const doc = documentPair?.draft || documentPair?.published\n const id = documentPair.id || ''\n const documentPreviewStore = useDocumentPreviewStore()\n const schema = useSchema()\n const documentPresence = useDocumentPresence(id)\n const hasSchemaType = Boolean(schemaType && schemaType.name && schema.get(schemaType.name))\n\n const PreviewComponent = useMemo(() => {\n if (!doc) return null\n\n if (!schemaType || !hasSchemaType) {\n return <MissingSchemaType value={doc} />\n }\n\n return (\n <PaneItemPreview\n documentPreviewStore={documentPreviewStore}\n icon={getIconWithFallback(undefined, schemaType, DocumentIcon)}\n schemaType={schemaType}\n layout=\"default\"\n value={doc}\n presence={documentPresence}\n />\n )\n }, [hasSchemaType, schemaType, documentPresence, doc, documentPreviewStore])\n\n return (\n <PreviewCard\n __unstable_focusRing\n // oxlint-disable-next-line react/react-compiler\n as={DocumentPreviewLink(props) as FIXME}\n data-as=\"a\"\n data-ui=\"PaneItem\"\n padding={2}\n radius={2}\n tone=\"inherit\"\n >\n {PreviewComponent}\n </PreviewCard>\n )\n}\n","import type {SanityDocument} from '@sanity/client'\nimport {Box, Card, Text} from '@sanity/ui'\nimport {collate, useSchema} from 'sanity'\nimport {styled} from 'styled-components'\n\nimport {DocumentPreview} from '../documentPreview/DocumentPreview'\nimport SpinnerBox from '../SpinnerBox'\n\nconst Container = styled(Box)`\n * {\n color: ${(props: any) => props.theme.sanity.color.base.fg};\n }\n a {\n text-decoration: none;\n }\n h2 {\n font-size: ${(props: any) => props.theme.sanity.fonts.text.sizes[1]};\n }\n`\n\nconst VideoReferences: React.FC<{\n references?: SanityDocument[]\n isLoaded: boolean\n}> = (props) => {\n const schema = useSchema()\n if (!props.isLoaded) {\n return <SpinnerBox />\n }\n\n if (!props.references?.length) {\n return (\n <Card border radius={3} padding={3}>\n <Text size={2}>No documents are using this video</Text>\n </Card>\n )\n }\n\n const documentPairs = collate(props.references || [])\n return (\n <Container>\n {documentPairs?.map((documentPair) => {\n const schemaType = schema.get(documentPair.type)\n\n return (\n <Card\n key={documentPair.id}\n marginBottom={2}\n padding={2}\n radius={2}\n shadow={1}\n style={{overflow: 'hidden'}}\n >\n <Box>\n <DocumentPreview documentPair={documentPair} schemaType={schemaType} />\n </Box>\n </Card>\n )\n })}\n </Container>\n )\n}\n\nexport default VideoReferences\n","import {TrashIcon} from '@sanity/icons/Trash'\nimport {Box, Button, Card, Checkbox, Dialog, Flex, Heading, Stack, Text, useToast} from '@sanity/ui'\nimport {useEffect, useState} from 'react'\nimport type {SanityDocument} from 'sanity'\n\nimport {deleteAsset} from '../../actions/assets'\nimport {useClient} from '../../hooks/useClient'\nimport {DIALOGS_Z_INDEX} from '../../util/constants'\nimport type {VideoAssetDocument} from '../../util/types'\nimport SpinnerBox from '../SpinnerBox'\nimport VideoReferences from './VideoReferences'\n\nexport default function DeleteDialog({\n asset,\n references,\n referencesLoading,\n cancelDelete,\n succeededDeleting,\n}: {\n asset: VideoAssetDocument\n references?: SanityDocument[]\n referencesLoading: boolean\n cancelDelete: () => void\n succeededDeleting: () => void\n}) {\n const client = useClient()\n const [state, setState] = useState<\n 'processing_deletion' | 'checkingReferences' | 'error_deleting' | 'cantDelete' | 'confirm'\n >('checkingReferences')\n const [deleteOnMux, setDeleteOnMux] = useState(true)\n const toast = useToast()\n\n useEffect(() => {\n if (state !== 'checkingReferences' || referencesLoading) return\n\n // oxlint-disable-next-line react/react-compiler\n setState(references?.length ? 'cantDelete' : 'confirm')\n }, [state, references, referencesLoading])\n\n async function confirmDelete() {\n if (state !== 'confirm') return\n\n setState('processing_deletion')\n const worked = await deleteAsset({client, asset, deleteOnMux})\n if (worked === true) {\n toast.push({title: 'Successfully deleted video', status: 'success'})\n succeededDeleting()\n } else if (worked === 'failed-mux') {\n toast.push({\n title: 'Deleted video in Sanity',\n description: \"But it wasn't deleted in Mux\",\n status: 'warning',\n })\n succeededDeleting()\n } else {\n toast.push({title: 'Failed deleting video', status: 'error'})\n\n setState('error_deleting')\n }\n }\n\n return (\n <Dialog\n animate\n header={'Delete video'}\n zOffset={DIALOGS_Z_INDEX}\n id=\"deleting-video-details-dialog\"\n onClose={cancelDelete}\n onClickOutside={cancelDelete}\n width={1}\n position=\"fixed\"\n >\n <Card\n padding={3}\n style={{\n minHeight: '150px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <Stack space={3}>\n {state === 'checkingReferences' && (\n <>\n <Heading size={2}>Checking if video can be deleted</Heading>\n <SpinnerBox />\n </>\n )}\n {state === 'cantDelete' && (\n <>\n <Heading size={2}>Video can't be deleted</Heading>\n <Text size={2} style={{marginBottom: '2rem'}}>\n There are {references?.length} document{references && references.length > 0 && 's'}{' '}\n pointing to this video. Remove their references to this file or delete them before\n proceeding.\n </Text>\n <VideoReferences references={references} isLoaded={!referencesLoading} />\n </>\n )}\n {state === 'confirm' && (\n <>\n <Heading size={2}>Are you sure you want to delete this video?</Heading>\n <Text size={2}>This action is irreversible</Text>\n <Stack space={4} marginY={4}>\n <Flex align=\"center\" as=\"label\">\n <Checkbox\n checked={deleteOnMux}\n onChange={() => setDeleteOnMux((prev) => !prev)}\n />\n <Text style={{margin: '0 10px'}}>Delete asset on Mux</Text>\n </Flex>\n <Flex align=\"center\" as=\"label\">\n <Checkbox disabled checked />\n <Text style={{margin: '0 10px'}}>Delete video from dataset</Text>\n </Flex>\n <Box>\n <Button\n icon={TrashIcon}\n fontSize={2}\n padding={3}\n text=\"Delete video\"\n tone=\"critical\"\n onClick={confirmDelete}\n disabled={['processing_deletion', 'checkingReferences', 'cantDelete'].some(\n (s) => s === state,\n )}\n />\n </Box>\n </Stack>\n </>\n )}\n {state === 'processing_deletion' && (\n <>\n <Heading size={2}>Deleting video...</Heading>\n <SpinnerBox />\n </>\n )}\n {state === 'error_deleting' && (\n <>\n <Heading size={2}>Something went wrong!</Heading>\n <Text size={2}>Try deleting the video again by clicking the button below</Text>\n </>\n )}\n </Stack>\n </Card>\n </Dialog>\n )\n}\n","import {createHookFromObservableFactory, type DocumentStore, type SanityDocument} from 'sanity'\n\nimport {SANITY_API_VERSION} from './useClient'\n\nconst useDocReferences = createHookFromObservableFactory<\n SanityDocument[],\n {\n documentStore: DocumentStore\n id: string\n }\n>(({documentStore, id}) => {\n return documentStore.listenQuery(\n /* groq */ '*[references($id)]{_id, _type, _rev, _updatedAt, _createdAt}',\n {id},\n {\n apiVersion: SANITY_API_VERSION,\n },\n )\n})\n\nexport default useDocReferences\n","import {formatSeconds} from './formatSeconds'\nimport type {MuxTextTrack, VideoAssetDocument} from './types'\n\nexport default function getVideoMetadata(doc: VideoAssetDocument) {\n const id = doc.assetId || doc._id || ''\n const date = doc.data?.created_at\n ? new Date(Number(doc.data.created_at) * 1000)\n : new Date(doc._createdAt || doc._updatedAt || Date.now())\n\n return {\n title: doc.filename || id.slice(0, 12),\n id: id,\n playbackId: doc.playbackId,\n createdAt: date,\n duration: doc.data?.duration ? formatSeconds(doc.data?.duration) : undefined,\n playback_ids: doc.data?.playback_ids,\n aspect_ratio: doc.data?.aspect_ratio,\n max_stored_resolution: doc.data?.max_stored_resolution,\n max_stored_frame_rate: doc.data?.max_stored_frame_rate,\n text_tracks:\n doc.data?.tracks?.filter((track): track is MuxTextTrack => track.type === 'text') || [],\n }\n}\n","import {useToast} from '@sanity/ui'\nimport {useMemo, useState} from 'react'\nimport {useDocumentStore} from 'sanity'\n\nimport {useClient} from '../../hooks/useClient'\nimport useDocReferences from '../../hooks/useDocReferences'\nimport {useResyncAsset} from '../../hooks/useResyncAsset'\nimport getVideoMetadata from '../../util/getVideoMetadata'\nimport {type VideoAssetDocument} from '../../util/types'\n\ntype VideoDetailsState = 'idle' | 'saving' | 'deleting' | 'closing' | 'resyncing'\n\nexport interface VideoDetailsProps {\n closeDialog: () => void\n asset: VideoAssetDocument & {autoPlay?: boolean}\n}\n\nexport default function useVideoDetails(props: VideoDetailsProps) {\n const documentStore = useDocumentStore()\n const toast = useToast()\n const client = useClient()\n\n const [references, referencesLoading] = useDocReferences(\n useMemo(() => ({documentStore, id: props.asset._id}), [documentStore, props.asset._id]),\n )\n\n const [originalAsset, setOriginalAsset] = useState(() => props.asset)\n const [filename, setFilename] = useState(props.asset.filename)\n const modified = filename !== originalAsset.filename\n\n const displayInfo = getVideoMetadata({...props.asset, filename})\n\n const [state, setState] = useState<VideoDetailsState>('idle')\n\n const {resyncAsset, isResyncing} = useResyncAsset({showToast: true})\n\n async function handleResync() {\n if (state !== 'idle') return\n setState('resyncing')\n await resyncAsset(props.asset)\n setState('idle')\n }\n\n function handleClose() {\n if (state !== 'idle') return\n\n if (modified) {\n setState('closing')\n return\n }\n\n props.closeDialog()\n }\n\n function confirmClose(shouldClose: boolean) {\n if (state !== 'closing') return\n\n if (shouldClose) props.closeDialog()\n\n setState('idle')\n }\n\n async function saveChanges() {\n if (state !== 'idle') return\n setState('saving')\n\n try {\n await client.patch(props.asset._id).set({filename}).commit()\n setOriginalAsset((prev) => ({...prev, filename}))\n toast.push({\n title: 'Video title updated',\n description: `New title: ${filename}`,\n status: 'success',\n })\n props.closeDialog()\n } catch (error) {\n toast.push({\n title: 'Failed updating file name',\n status: 'error',\n description: typeof error === 'string' ? error : 'Please try again',\n })\n setFilename(originalAsset.filename)\n }\n\n setState('idle')\n }\n\n return {\n references,\n referencesLoading,\n modified,\n filename,\n setFilename,\n displayInfo,\n state,\n setState,\n handleClose,\n confirmClose,\n saveChanges,\n handleResync,\n isResyncing,\n }\n}\n","import {CalendarIcon} from '@sanity/icons/Calendar'\nimport {CheckmarkIcon} from '@sanity/icons/Checkmark'\nimport {ClockIcon} from '@sanity/icons/Clock'\nimport {CropIcon} from '@sanity/icons/Crop'\nimport {EditIcon} from '@sanity/icons/Edit'\nimport {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {RevertIcon} from '@sanity/icons/Revert'\nimport {SearchIcon} from '@sanity/icons/Search'\nimport {SyncIcon} from '@sanity/icons/Sync'\nimport {TagIcon} from '@sanity/icons/Tag'\nimport {TrashIcon} from '@sanity/icons/Trash'\nimport {\n Button,\n Card,\n Dialog,\n Flex,\n Heading,\n Spinner,\n Stack,\n Tab,\n TabList,\n TabPanel,\n Text,\n TextInput,\n} from '@sanity/ui'\nimport {useEffect, useRef, useState} from 'react'\n\nimport {DIALOGS_Z_INDEX} from '../../util/constants'\nimport type {MuxPlaybackId, MuxTextTrack, PlaybackPolicy} from '../../util/types'\nimport FormField from '../FormField'\nimport IconInfo from '../IconInfo'\nimport {ResolutionIcon} from '../icons/Resolution'\nimport {StopWatchIcon} from '../icons/StopWatch'\nimport Mezzanine from '../Mezzanine'\nimport TextTracksManager from '../TextTracksManager'\nimport VideoPlayer from '../VideoPlayer'\nimport DeleteDialog from './DeleteDialog'\nimport useVideoDetails, {type VideoDetailsProps} from './useVideoDetails'\nimport VideoReferences from './VideoReferences'\n\nconst AssetInput: React.FC<{\n label: string\n description?: string\n placeholder?: string\n value: string\n onInput: (e: React.FormEvent<HTMLInputElement>) => void\n disabled?: boolean\n}> = (props) => (\n <FormField title={props.label} description={props.description} inputId={props.label}>\n <TextInput\n id={props.label}\n value={props.value}\n placeholder={props.placeholder}\n onInput={props.onInput}\n disabled={props.disabled}\n />\n </FormField>\n)\n\nconst VideoDetails: React.FC<VideoDetailsProps> = (props) => {\n const [tab, setTab] = useState<'details' | 'references'>('details')\n const {\n displayInfo,\n filename,\n modified,\n references,\n referencesLoading,\n setFilename,\n state,\n setState,\n handleClose,\n confirmClose,\n saveChanges,\n handleResync,\n isResyncing,\n } = useVideoDetails(props)\n\n const isSaving = state === 'saving'\n\n // Avoid layout shifts in large screens' 2-column dialog by setting their `minHeight` to the container's\n const [containerHeight, setContainerHeight] = useState<number | null>(null)\n const contentsRef = useRef<HTMLDivElement>(null)\n useEffect(() => {\n if (!contentsRef.current || !('getBoundingClientRect' in contentsRef.current)) return\n\n setContainerHeight(contentsRef.current.getBoundingClientRect().height)\n }, [])\n\n return (\n <Dialog\n animate\n header={displayInfo.title}\n zOffset={DIALOGS_Z_INDEX}\n id=\"video-details-dialog\"\n onClose={handleClose}\n onClickOutside={handleClose}\n width={2}\n position=\"fixed\"\n footer={\n <Card padding={3}>\n <Flex justify=\"space-between\" align=\"center\">\n <Flex gap={2}>\n <Button\n icon={TrashIcon}\n fontSize={2}\n padding={3}\n mode=\"bleed\"\n text=\"Delete\"\n tone=\"critical\"\n onClick={() => setState('deleting')}\n disabled={isSaving || isResyncing}\n />\n <Button\n icon={SyncIcon}\n fontSize={2}\n padding={3}\n mode=\"bleed\"\n text=\"Resync\"\n tone=\"primary\"\n onClick={handleResync}\n disabled={isSaving || isResyncing}\n iconRight={isResyncing && Spinner}\n />\n </Flex>\n {modified && (\n <Button\n icon={CheckmarkIcon}\n fontSize={2}\n padding={3}\n mode=\"ghost\"\n text=\"Save and close\"\n tone=\"positive\"\n onClick={saveChanges}\n iconRight={isSaving && Spinner}\n disabled={isSaving || isResyncing}\n />\n )}\n </Flex>\n </Card>\n }\n >\n {/* DELETION DIALOG */}\n {state === 'deleting' && (\n <DeleteDialog\n asset={props.asset}\n cancelDelete={() => setState('idle')}\n referencesLoading={referencesLoading}\n references={references}\n succeededDeleting={() => {\n props.closeDialog()\n }}\n />\n )}\n\n {/* CONFIRM CLOSING DIALOG */}\n {state === 'closing' && (\n <Dialog\n animate\n header={'You have unsaved changes'}\n zOffset={DIALOGS_Z_INDEX}\n id=\"closing-video-details-dialog\"\n onClose={() => confirmClose(false)}\n onClickOutside={() => confirmClose(false)}\n width={1}\n position=\"fixed\"\n footer={\n <Card padding={3}>\n <Flex justify=\"space-between\" align=\"center\">\n <Button\n icon={ErrorOutlineIcon}\n fontSize={2}\n padding={3}\n text=\"Discard changes\"\n tone=\"critical\"\n onClick={() => confirmClose(true)}\n />\n {modified && (\n <Button\n icon={RevertIcon}\n fontSize={2}\n padding={3}\n mode=\"ghost\"\n text=\"Keep editing\"\n tone=\"primary\"\n onClick={() => confirmClose(false)}\n />\n )}\n </Flex>\n </Card>\n }\n >\n <Card padding={5}>\n <Stack style={{textAlign: 'center'}} space={3}>\n <Heading size={2}>Unsaved changes will be lost</Heading>\n <Text size={2}>Are you sure you want to discard them?</Text>\n </Stack>\n </Card>\n </Dialog>\n )}\n <Card\n padding={4}\n sizing=\"border\"\n style={{\n containerType: 'inline-size',\n }}\n >\n <Flex\n sizing=\"border\"\n gap={4}\n direction={['column', 'column', 'row']}\n align=\"flex-start\"\n ref={contentsRef}\n style={\n typeof containerHeight === 'number'\n ? {\n minHeight: containerHeight,\n }\n : undefined\n }\n >\n <Stack space={4} flex={1} sizing=\"border\">\n <VideoPlayer asset={props.asset} autoPlay={props.asset.autoPlay || false} />\n {tab === 'details' && (\n <>\n <TextTracksManager\n asset={props.asset}\n iconOnly\n collapseTracks\n tracks={\n displayInfo?.text_tracks ||\n props.asset.data?.tracks?.filter(\n (track): track is MuxTextTrack => track.type === 'text',\n ) ||\n []\n }\n />\n <Mezzanine asset={props.asset} />\n </>\n )}\n </Stack>\n <Stack space={4} flex={1} sizing=\"border\">\n <TabList space={2}>\n <Tab\n aria-controls=\"details-panel\"\n icon={EditIcon}\n id=\"details-tab\"\n label=\"Details\"\n onClick={() => setTab('details')}\n selected={tab === 'details'}\n />\n <Tab\n aria-controls=\"references-panel\"\n icon={SearchIcon}\n id=\"references-tab\"\n label={`Used by ${references ? `(${references.length})` : ''}`}\n onClick={() => setTab('references')}\n selected={tab === 'references'}\n />\n </TabList>\n <TabPanel\n aria-labelledby=\"details-tab\"\n id=\"details-panel\"\n hidden={tab !== 'details'}\n style={{wordBreak: 'break-word'}}\n >\n <Stack space={4}>\n <AssetInput\n label=\"Video title or file name\"\n description=\"Not visible to users. Useful for finding videos later.\"\n value={filename || ''}\n onInput={(e) => setFilename(e.currentTarget.value)}\n disabled={state !== 'idle'}\n />\n <Stack space={3}>\n {displayInfo?.duration && (\n <IconInfo\n text={`Duration: ${displayInfo.duration}`}\n icon={ClockIcon}\n size={2}\n />\n )}\n {displayInfo?.max_stored_resolution && (\n <IconInfo\n text={`Max Resolution: ${displayInfo.max_stored_resolution}`}\n icon={ResolutionIcon}\n size={2}\n />\n )}\n {displayInfo?.max_stored_frame_rate && (\n <IconInfo\n text={`Frame rate: ${displayInfo.max_stored_frame_rate}`}\n icon={StopWatchIcon}\n size={2}\n />\n )}\n {displayInfo?.aspect_ratio && (\n <IconInfo\n text={`Aspect Ratio: ${displayInfo.aspect_ratio}`}\n icon={CropIcon}\n size={2}\n />\n )}\n <IconInfo\n text={`Uploaded on: ${displayInfo.createdAt.toLocaleDateString('en', {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n hour12: true,\n })}`}\n icon={CalendarIcon}\n size={2}\n />\n <IconInfo text={`Mux ID: \\n${displayInfo.id}`} icon={TagIcon} size={2} />\n <PlaybackIds playback_ids={displayInfo.playback_ids} />\n </Stack>\n </Stack>\n </TabPanel>\n <TabPanel\n aria-labelledby=\"references-tab\"\n id=\"references-panel\"\n hidden={tab !== 'references'}\n >\n <VideoReferences references={references} isLoaded={!referencesLoading} />\n </TabPanel>\n </Stack>\n </Flex>\n </Card>\n </Dialog>\n )\n}\n\nconst PlaybackIds = ({playback_ids}: {playback_ids?: MuxPlaybackId[]}) => {\n if (playback_ids) {\n return playback_ids.map((entry) => (\n <IconInfo\n key={entry.id}\n text={`Playback ID [${policyToText(entry.policy)}]: ${entry.id}`}\n icon={TagIcon}\n size={2}\n />\n ))\n }\n return <IconInfo text={'No Playback ID'} icon={TagIcon} size={2} />\n}\n\nconst policyToText = (policy: PlaybackPolicy) => {\n switch (policy) {\n case 'drm':\n return 'DRM'\n case 'signed':\n return 'Signed'\n case 'public':\n return 'Public'\n default:\n return policy\n }\n}\nexport default VideoDetails\n","import {CalendarIcon} from '@sanity/icons/Calendar'\nimport {ClockIcon} from '@sanity/icons/Clock'\nimport {TagIcon} from '@sanity/icons/Tag'\nimport {Inline, Stack, Text} from '@sanity/ui'\n\nimport getVideoMetadata from '../util/getVideoMetadata'\nimport type {VideoAssetDocument} from '../util/types'\nimport IconInfo from './IconInfo'\n\nconst VideoMetadata = (props: {asset: VideoAssetDocument}) => {\n if (!props.asset) {\n return null\n }\n\n const displayInfo = getVideoMetadata(props.asset)\n return (\n <Stack space={2}>\n {displayInfo.title && (\n <Text\n size={1}\n weight=\"semibold\"\n style={{\n wordWrap: 'break-word',\n }}\n >\n {displayInfo.title}\n </Text>\n )}\n <Inline space={3}>\n {displayInfo?.duration && (\n <IconInfo text={displayInfo.duration} icon={ClockIcon} size={1} muted />\n )}\n <IconInfo\n text={displayInfo.createdAt.toISOString().split('T')[0]!}\n icon={CalendarIcon}\n size={1}\n muted\n />\n {displayInfo.title != displayInfo.id.slice(0, 12) && (\n <IconInfo text={displayInfo.id.slice(0, 12)} icon={TagIcon} size={1} muted />\n )}\n </Inline>\n </Stack>\n )\n}\n\nexport default VideoMetadata\n","import {CheckmarkIcon} from '@sanity/icons/Checkmark'\nimport {EditIcon} from '@sanity/icons/Edit'\nimport {LockIcon} from '@sanity/icons/Lock'\nimport {PlayIcon} from '@sanity/icons/Play'\nimport {Button, Card, Stack, Text, Tooltip} from '@sanity/ui'\nimport {useCallback, useState} from 'react'\nimport {styled} from 'styled-components'\n\nimport {DRMWarningDialog, useDrmPlaybackWarningContext} from '../context/DrmPlaybackWarningContext'\nimport {THUMBNAIL_ASPECT_RATIO} from '../util/constants'\nimport {getPlaybackPolicy} from '../util/getPlaybackPolicy'\nimport {type VideoAssetDocument} from '../util/types'\nimport IconInfo from './IconInfo'\nimport {AudioIcon} from './icons/Audio'\nimport VideoMetadata from './VideoMetadata'\nimport VideoPlayer, {assetIsAudio} from './VideoPlayer'\nimport VideoThumbnail from './VideoThumbnail'\n\nconst PlayButton = styled.button`\n display: block;\n padding: 0;\n margin: 0;\n border: none;\n border-radius: 0.1875rem;\n position: relative;\n cursor: pointer;\n\n &::after {\n content: '';\n background: var(--card-fg-color);\n opacity: 0;\n display: block;\n position: absolute;\n inset: 0;\n z-index: 10;\n transition: 0.15s ease-out;\n border-radius: inherit;\n }\n\n > div[data-play] {\n z-index: 11;\n opacity: 0;\n transition: 0.15s 0.05s ease-out;\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n color: var(--card-fg-color);\n background: var(--card-bg-color);\n width: auto;\n height: 30%;\n aspect-ratio: 1;\n border-radius: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n box-sizing: border-box;\n > svg {\n display: block;\n width: 70%;\n height: auto;\n // Visual balance to center-align the icon\n transform: translateX(5%);\n }\n }\n\n &:hover,\n &:focus {\n &::after {\n opacity: 0.3;\n }\n > div[data-play] {\n opacity: 1;\n }\n }\n`\n\ntype RenderState = 'render-video' | 'pre-render-warn' | false\n\nexport default function VideoInBrowser({\n onSelect,\n onEdit,\n asset,\n}: {\n onSelect?: (asset: VideoAssetDocument) => void\n onEdit?: (asset: VideoAssetDocument) => void\n asset: VideoAssetDocument\n}) {\n const [renderVideo, setRenderVideo] = useState<RenderState>(false)\n const select = useCallback(() => onSelect?.(asset), [onSelect, asset])\n const edit = useCallback(() => onEdit?.(asset), [onEdit, asset])\n const {hasShownWarning} = useDrmPlaybackWarningContext()\n\n if (!asset) {\n return null\n }\n\n const playbackPolicy = getPlaybackPolicy(asset)\n const onClickPlay = () => {\n if (playbackPolicy?.policy === 'drm' && !hasShownWarning) {\n setRenderVideo('pre-render-warn')\n } else {\n setRenderVideo('render-video')\n }\n }\n return (\n <Card\n border\n padding={2}\n sizing=\"border\"\n radius={2}\n style={{\n position: 'relative',\n }}\n >\n {playbackPolicy?.policy === 'signed' && (\n <Tooltip\n animate\n content={\n <Card padding={2} radius={2}>\n <IconInfo icon={LockIcon} text=\"Signed playback policy\" size={2} />\n </Card>\n }\n placement=\"right\"\n fallbackPlacements={['top', 'bottom']}\n portal\n >\n <Card\n tone=\"caution\"\n style={{\n borderRadius: '100%',\n position: 'absolute',\n left: '1em',\n top: '1em',\n zIndex: 11,\n }}\n padding={2}\n border\n >\n <Text muted size={1}>\n <LockIcon />\n </Text>\n </Card>\n </Tooltip>\n )}\n {playbackPolicy?.policy === 'drm' && (\n <Tooltip\n animate\n content={\n <Card padding={2} radius={2}>\n <IconInfo icon={LockIcon} text=\"DRM playback policy\" size={2} />\n </Card>\n }\n placement=\"right\"\n fallbackPlacements={['top', 'bottom']}\n portal\n >\n <Card\n tone=\"caution\"\n style={{\n borderRadius: '0.25rem',\n position: 'absolute',\n left: '1em',\n top: '1em',\n zIndex: 11,\n }}\n padding={2}\n border\n >\n <Text muted size={1} weight=\"semibold\" style={{color: 'var(--card-icon-color)'}}>\n DRM\n </Text>\n </Card>\n </Tooltip>\n )}\n <Stack\n space={3}\n height=\"fill\"\n style={{\n gridTemplateRows: 'min-content min-content 1fr',\n }}\n >\n {renderVideo === 'pre-render-warn' && (\n <DRMWarningDialog\n onClose={() => {\n setRenderVideo('render-video')\n }}\n />\n )}\n {renderVideo === 'render-video' ? (\n <VideoPlayer asset={asset} autoPlay forceAspectRatio={THUMBNAIL_ASPECT_RATIO} />\n ) : (\n <PlayButton onClick={onClickPlay}>\n <div data-play>\n <PlayIcon />\n </div>\n {assetIsAudio(asset) ? (\n <div\n style={{\n aspectRatio: THUMBNAIL_ASPECT_RATIO,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <AudioIcon width=\"3em\" height=\"3em\" />\n </div>\n ) : (\n <VideoThumbnail asset={asset} />\n )}\n </PlayButton>\n )}\n <VideoMetadata asset={asset} />\n <div\n style={{\n display: 'flex',\n width: '100%',\n alignItems: 'flex-end',\n justifyContent: 'flex-start',\n gap: '.35rem',\n }}\n >\n {onSelect && (\n <Button\n icon={CheckmarkIcon}\n fontSize={2}\n padding={2}\n mode=\"ghost\"\n text=\"Select\"\n style={{flex: 1}}\n tone=\"positive\"\n onClick={select}\n />\n )}\n <Button\n icon={EditIcon}\n fontSize={2}\n padding={2}\n mode=\"ghost\"\n text=\"Details\"\n style={{flex: 1}}\n onClick={edit}\n />\n </div>\n </Stack>\n </Card>\n )\n}\n","import {SearchIcon} from '@sanity/icons/Search'\nimport {Card, Flex, Grid, Inline, Label, Stack, Text, TextInput} from '@sanity/ui'\nimport {useMemo, useState} from 'react'\n\nimport {DrmPlaybackWarningContextProvider} from '../context/DrmPlaybackWarningContext'\nimport useAssets from '../hooks/useAssets'\nimport type {PluginConfig, VideoAssetDocument} from '../util/types'\nimport ConfigureApi from './ConfigureApi'\nimport ImportVideosFromMux from './ImportVideosFromMux'\nimport PageSelector from './PageSelector'\nimport ResyncMetadata from './ResyncMetadata'\nimport {SelectSortOptions} from './SelectSortOptions'\nimport SpinnerBox from './SpinnerBox'\nimport type {VideoDetailsProps} from './VideoDetails/useVideoDetails'\nimport VideoDetails from './VideoDetails/VideoDetails'\nimport VideoInBrowser from './VideoInBrowser'\n\nexport interface VideosBrowserProps {\n config: PluginConfig\n onSelect?: (asset: VideoAssetDocument) => void\n}\n\nexport default function VideosBrowser({onSelect, config}: VideosBrowserProps) {\n const {assets, isLoading, searchQuery, setSearchQuery, setSort, sort} = useAssets()\n const [page, setPage] = useState<number>(0)\n const pageLimit = 20\n const pageTotal = Math.floor(assets.length / pageLimit) + 1\n const [editedAsset, setEditedAsset] = useState<VideoDetailsProps['asset'] | null>(null)\n const freshEditedAsset = useMemo(\n () => assets.find((a) => a._id === editedAsset?._id) || editedAsset,\n [editedAsset, assets],\n )\n\n const pageStart = page * pageLimit\n const pageEnd = pageStart + pageLimit\n\n const placement = onSelect ? 'input' : 'tool'\n return (\n <DrmPlaybackWarningContextProvider config={config}>\n <Stack padding={4} space={4} style={{minHeight: '50vh'}}>\n <Flex justify=\"space-between\" align=\"center\">\n <Flex align=\"center\" gap={3}>\n <TextInput\n value={searchQuery}\n icon={SearchIcon}\n onInput={(e: React.FormEvent<HTMLInputElement>) =>\n setSearchQuery(e.currentTarget.value)\n }\n placeholder=\"Search videos\"\n />\n <SelectSortOptions setSort={setSort} sort={sort} />\n <PageSelector page={page} setPage={setPage} total={pageTotal} />\n </Flex>\n {placement === 'tool' && (\n <Inline space={2}>\n <ImportVideosFromMux />\n <ResyncMetadata />\n <ConfigureApi />\n </Inline>\n )}\n </Flex>\n <Stack space={3}>\n {assets?.length > 0 && (\n <Label muted>\n {assets.length} video{assets.length > 1 ? 's' : null}{' '}\n {searchQuery ? `matching \"${searchQuery}\"` : 'found'}\n </Label>\n )}\n <Grid\n gap={2}\n style={{\n gridTemplateColumns: 'repeat(auto-fill, minmax(250px, 1fr))',\n }}\n >\n {assets.slice(pageStart, pageEnd).map((asset) => (\n <VideoInBrowser\n key={asset._id}\n asset={asset}\n onEdit={setEditedAsset}\n onSelect={onSelect}\n />\n ))}\n </Grid>\n </Stack>\n {isLoading && <SpinnerBox />}\n\n {!isLoading && assets.length === 0 && (\n <Card marginY={4} paddingX={4} paddingY={6} border radius={2} tone=\"transparent\">\n <Text align=\"center\" muted size={3}>\n {searchQuery ? `No videos found for \"${searchQuery}\"` : 'No videos in this dataset'}\n </Text>\n </Card>\n )}\n </Stack>\n {freshEditedAsset && (\n <VideoDetails closeDialog={() => setEditedAsset(null)} asset={freshEditedAsset} />\n )}\n </DrmPlaybackWarningContextProvider>\n )\n}\n","import type {Tool} from 'sanity'\n\nimport type {PluginConfig} from '../util/types'\nimport ToolIcon from './icons/ToolIcon'\nimport VideosBrowser from './VideosBrowser'\n\nconst StudioTool: React.FC<PluginConfig> = (config) => {\n return <VideosBrowser config={config} />\n}\n\nexport const DEFAULT_TOOL_CONFIG = {\n icon: ToolIcon,\n title: 'Videos',\n}\n\nexport default function createStudioTool(config: PluginConfig): Tool {\n const toolConfig = typeof config.tool === 'object' ? config.tool : DEFAULT_TOOL_CONFIG\n return {\n name: 'mux',\n icon: toolConfig.icon || DEFAULT_TOOL_CONFIG.icon,\n title: toolConfig.title || DEFAULT_TOOL_CONFIG.title,\n component: (props: any) => <StudioTool {...config} {...props} />,\n }\n}\n","import {useCurrentUser} from 'sanity'\n\nimport {type PluginConfig} from '../util/types'\n\nexport const useAccessControl = (config: PluginConfig) => {\n const user = useCurrentUser()\n\n const hasConfigAccess =\n !config?.allowedRolesForConfiguration?.length ||\n user?.roles?.some((role) => config.allowedRolesForConfiguration.includes(role.name))\n\n return {hasConfigAccess}\n}\n","import {isReference} from 'sanity'\nimport {useDocumentValues} from 'sanity'\n\nimport type {Reference, VideoAssetDocument} from '../util/types'\n\nconst path = ['assetId', 'data', 'playbackId', 'status', 'thumbTime', 'filename']\nexport const useAssetDocumentValues = (asset: Reference | null | undefined) =>\n useDocumentValues<VideoAssetDocument | null | undefined>(\n isReference(asset) ? asset._ref : '',\n path,\n )\n","import {useMemo, useRef} from 'react'\nimport {useDataset, useProjectId} from 'sanity'\nimport useSWR from 'swr'\n\nimport {useClient} from '../hooks/useClient'\nimport {addKeysToMuxData} from '../util/addKeysToMuxData'\nimport {PLUGIN_VERSION_QUERY} from '../util/pluginVersion'\nimport type {MuxAsset, VideoAssetDocument} from '../util/types'\n\n// Poll MUX if it's preparing the main document or its own static renditions\nexport const useMuxPolling = (asset?: VideoAssetDocument) => {\n const client = useClient()\n const projectId = useProjectId()\n const dataset = useDataset()\n const isPreparingStaticRenditions = useMemo(() => {\n // Legacy: If static_renditions has a status field, it was created with mp4_support (deprecated)\n // We don't process this old format, just return false\n // Note: 'disabled' status is valid in the new format when no renditions were requested\n if (\n asset?.data?.static_renditions?.status &&\n asset?.data?.static_renditions?.status !== 'disabled'\n ) {\n return false\n }\n\n const files = asset?.data?.static_renditions?.files\n if (!files || files.length === 0) {\n return false\n }\n return files.some((file) => file.status === 'preparing')\n }, [asset?.data?.static_renditions?.status, asset?.data?.static_renditions?.files])\n\n const shouldFetch = useMemo(\n () => !!asset?.assetId && (asset?.status === 'preparing' || isPreparingStaticRenditions),\n [asset?.assetId, asset?.status, isPreparingStaticRenditions],\n )\n // Only log the first failure of a streak so a persistent error doesn't flood\n // the console on every interval.\n const errorLoggedRef = useRef(false)\n return useSWR(\n shouldFetch ? `/${projectId}/addons/mux/assets/${dataset}/data/${asset?.assetId}` : null,\n async () => {\n try {\n const {data} = await client.request<{data: MuxAsset}>({\n url: `/addons/mux/assets/${dataset}/data/${asset!.assetId}`,\n withCredentials: true,\n method: 'GET',\n query: PLUGIN_VERSION_QUERY,\n })\n if (!asset?._id || !data) return\n await client\n .patch(asset._id)\n .set({status: data.status, data: addKeysToMuxData(data)})\n .commit({returnDocuments: false})\n errorLoggedRef.current = false\n } catch (error) {\n // Input re-throws `poll.error`, so a background polling failure would\n // crash the whole field. Swallow it instead.\n if (!errorLoggedRef.current) {\n errorLoggedRef.current = true\n console.error('[sanity-plugin-mux-input] Mux polling failed', {\n assetId: asset?.assetId,\n documentId: asset?._id,\n error,\n })\n }\n }\n },\n {refreshInterval: 2000, refreshWhenHidden: true, dedupingInterval: 1000},\n )\n}\n","/* eslint-disable no-console */\nimport {Button, Card, Flex, Grid, Heading, Inline, Text, useToast} from '@sanity/ui'\nimport {memo, useCallback, useRef} from 'react'\nimport scrollIntoView from 'scroll-into-view-if-needed'\nimport {clear} from 'suspend-react'\nimport {useErrorBoundary} from 'use-error-boundary'\n\nimport {name} from '../util/constants'\nimport {type MuxInputProps} from '../util/types'\n\nexport interface Props extends Pick<MuxInputProps, 'schemaType'> {\n children: React.ReactNode\n}\nfunction ErrorBoundaryCard(props: Props) {\n const {children, schemaType} = props\n const {push: pushToast} = useToast()\n const errorRef = useRef(null)\n const {ErrorBoundary, didCatch, error, reset} = useErrorBoundary({\n // oxlint-disable-next-line no-unstable-nested-components\n onDidCatch: (err, errorInfo) => {\n console.group(err.toString())\n console.groupCollapsed('console.error')\n console.error(err)\n console.groupEnd()\n if (err.stack) {\n console.groupCollapsed('error.stack')\n console.log(err.stack)\n console.groupEnd()\n }\n if (errorInfo?.componentStack) {\n console.groupCollapsed('errorInfo.componentStack')\n console.log(errorInfo.componentStack)\n console.groupEnd()\n }\n console.groupEnd()\n pushToast({\n status: 'error',\n title: 'Plugin crashed',\n description: (\n <Flex align=\"center\">\n <Inline space={1}>\n An error happened while rendering\n <Button\n padding={1}\n fontSize={1}\n style={{transform: 'translateY(1px)'}}\n mode=\"ghost\"\n text={schemaType.title}\n onClick={() => {\n if (errorRef.current) {\n scrollIntoView(errorRef.current, {\n behavior: 'smooth',\n scrollMode: 'if-needed',\n block: 'center',\n })\n }\n }}\n />\n </Inline>\n </Flex>\n ),\n })\n },\n })\n const handleRetry = useCallback(() => {\n // Purge request cache before retrying, otherwise the cached errors will rethrow\n clear([name])\n\n reset()\n }, [reset])\n\n if (didCatch) {\n return (\n <Card ref={errorRef} paddingX={[2, 3, 4, 4]} height=\"fill\" shadow={1} overflow=\"auto\">\n <Flex justify=\"flex-start\" align=\"center\" height=\"fill\">\n <Grid columns={1} gap={[2, 3, 4, 4]}>\n <Heading as=\"h1\">\n The <code>{name}</code> plugin crashed\n </Heading>\n {error?.message && (\n <Card padding={3} tone=\"critical\" shadow={1} radius={2}>\n <Text>{error.message}</Text>\n </Card>\n )}\n <Inline>\n <Button onClick={handleRetry} text=\"Retry\" />\n </Inline>\n </Grid>\n </Flex>\n </Card>\n )\n }\n\n return <ErrorBoundary>{children}</ErrorBoundary>\n}\n\nexport default memo(ErrorBoundaryCard)\n","import {Box, Card, Flex, Spinner, Text} from '@sanity/ui'\n\nexport const InputFallback = () => {\n return (\n <div style={{padding: 1}}>\n <Card\n shadow={1}\n sizing=\"border\"\n style={{aspectRatio: '16/9', width: '100%', borderRadius: '1px'}}\n >\n <Flex align=\"center\" direction=\"column\" height=\"fill\" justify=\"center\">\n <Spinner muted />\n <Box marginTop={3}>\n <Text align=\"center\" muted size={1}>\n Loading…\n </Text>\n </Box>\n </Flex>\n </Card>\n </div>\n )\n}\n","import {PlugIcon} from '@sanity/icons/Plug'\nimport {Button, Card, Flex, Grid, Heading, Inline, Text} from '@sanity/ui'\nimport {useCallback} from 'react'\n\nimport {useAccessControl} from '../hooks/useAccessControl'\nimport type {SetDialogState} from '../hooks/useDialogState'\nimport {type PluginConfig} from '../util/types'\nimport MuxLogo from './MuxLogo'\n\ninterface OnboardProps {\n setDialogState: SetDialogState\n config: PluginConfig\n}\n\nexport default function Onboard(props: OnboardProps) {\n const {setDialogState} = props\n const handleOpen = useCallback(() => setDialogState('secrets'), [setDialogState])\n const {hasConfigAccess} = useAccessControl(props.config)\n\n return (\n <>\n <div style={{padding: 2}}>\n <Card\n display=\"flex\"\n sizing=\"border\"\n style={{\n aspectRatio: '16/9',\n width: '100%',\n boxShadow: 'var(--card-bg-color) 0 0 0 2px',\n }}\n paddingX={[2, 3, 4, 4]}\n radius={1}\n tone=\"transparent\"\n >\n <Flex justify=\"flex-start\" align=\"center\">\n <Grid columns={1} gap={[2, 3, 4, 4]}>\n <Inline paddingY={1}>\n <div style={{height: '32px'}}>\n <MuxLogo />\n </div>\n </Inline>\n <Inline paddingY={1}>\n <Heading size={[0, 1, 2, 2]}>\n Upload and preview videos directly from your studio.\n </Heading>\n </Inline>\n <Inline paddingY={1}>\n {hasConfigAccess ? (\n <Button mode=\"ghost\" icon={PlugIcon} text=\"Configure API\" onClick={handleOpen} />\n ) : (\n <Card padding={[3, 3, 3]} radius={2} shadow={1} tone=\"critical\">\n <Text>\n You do not have access to configure the Mux API. Please contact your\n administrator.\n </Text>\n </Card>\n )}\n </Inline>\n </Grid>\n </Flex>\n </Card>\n </div>\n </>\n )\n}\n","import {UpChunk} from '@mux/upchunk'\nimport {Observable} from 'rxjs'\n\nexport function createUpChunkObservable(uuid: string, uploadUrl: string, source: File) {\n return new Observable<\n | {type: 'pause' | 'resume'; id: string}\n | {type: 'success'; id: string}\n | {type: 'progress'; percent: number}\n >((subscriber) => {\n const upchunk = UpChunk.createUpload({\n endpoint: uploadUrl,\n file: source,\n dynamicChunkSize: true, // changes the chunk size based on network speeds\n })\n\n const successHandler = () => {\n subscriber.next({\n type: 'success',\n id: uuid,\n })\n subscriber.complete()\n }\n\n const errorHandler = (data: CustomEvent) => subscriber.error(new Error(data.detail.message))\n\n const progressHandler = (data: CustomEvent) => {\n return subscriber.next({type: 'progress', percent: data.detail})\n }\n\n const offlineHandler = () => {\n upchunk.pause()\n subscriber.next({\n type: 'pause',\n id: uuid,\n })\n }\n\n const onlineHandler = () => {\n upchunk.resume()\n subscriber.next({\n type: 'resume',\n id: uuid,\n })\n }\n\n upchunk.on('success', successHandler)\n upchunk.on('error', errorHandler)\n upchunk.on('progress', progressHandler)\n upchunk.on('offline', offlineHandler)\n upchunk.on('online', onlineHandler)\n\n return () => upchunk.abort()\n })\n}\n","/**\n * Format Google Drive share links as Google Drive export links.\n * Supported formats:\n * - https://drive.google.com/uc?id=<ID>...\n * - https://drive.google.com/open?id=<ID>...\n * - https://drive.google.com/file/d/<ID>...\n * - https://drive.google.com/folder/<ID>...\n *\n * @param url Google Drive share link to format.\n * @returns Google Drive export link (URL passthrough if not share link).\n */\nexport function formatDriveShareLink(url: string): string {\n // Export link formatter.\n const formatExportLink = (id: string) => {\n return `https://drive.google.com/uc?export=download&id=${id}`\n }\n\n // URL formatting.\n try {\n // Parse URL.\n const trimmed = url.trim()\n const parsed = new URL(trimmed)\n\n // Enforce strict host name.\n if (parsed.hostname !== 'drive.google.com') {\n throw new Error('URL is not from Google Drive.')\n }\n\n // Look for ID in search parameters.\n const id = parsed.searchParams.get('id') || ''\n if (id.length) {\n return formatExportLink(id)\n }\n\n // Look for ID in path name.\n const path = parsed.pathname.split('/') || []\n\n // Path is /file/d/<ID>...\n if (path.includes('file') && path.includes('d')) {\n const index =\n path.findIndex((value: string) => {\n return value === 'd'\n }) + 1\n const fileId = path.at(index) || ''\n return formatExportLink(fileId)\n }\n\n // Path is /folder/<ID>...\n if (path.includes('folders')) {\n const index =\n path.findIndex((value: string) => {\n return value === 'folders'\n }) + 1\n const folderId = path.at(index) || ''\n return formatExportLink(folderId)\n }\n\n // URL not recognized.\n throw new Error('URL was not recognized.')\n } catch {\n // URL passthrough by default.\n return url\n }\n}\n","/**\n * Rounds the numeric part of a px string to the nearest integer.\n * Returns undefined if the value is not a valid px string or not a finite number.\n * Avoids sending 0px (and JS -0); snaps to ±1 instead.\n */\nexport function roundPxString(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.endsWith('px')) return undefined\n const n = Number(trimmed.slice(0, -2))\n if (!Number.isFinite(n)) return undefined\n let rounded = Math.round(n)\n // Avoid sending 0px (and JS -0); keep sign when negative.\n if (rounded === 0) rounded = n < 0 ? -1 : 1\n return `${rounded}px`\n}\n","import {uuid as generateUuid} from '@sanity/uuid'\nimport {concat, defer, from, type Observable, of, throwError} from 'rxjs'\nimport {catchError, mergeMap, mergeMapTo, switchMap} from 'rxjs/operators'\nimport type {SanityClient} from 'sanity'\n\nimport {createUpChunkObservable} from '../clients/upChunkObservable'\nimport {formatDriveShareLink} from '../util/formatDriveShareLink'\nimport {PLUGIN_VERSION_QUERY} from '../util/pluginVersion'\nimport {roundPxString} from '../util/roundPxString'\nimport type {MuxAsset, MuxNewAssetSettings, WatermarkConfig} from '../util/types'\nimport {getAsset} from './assets'\nimport {testSecretsObservable} from './secrets'\n\nfunction sanitizeOverlaySettingsInPlace(settings: MuxNewAssetSettings) {\n const inputs = settings.input\n if (!inputs) return\n for (const input of inputs) {\n const overlay = (input as {overlay_settings?: Record<string, unknown>}).overlay_settings\n if (!overlay) continue\n\n const hm = roundPxString(overlay['horizontal_margin'])\n const vm = roundPxString(overlay['vertical_margin'])\n const w = roundPxString(overlay['width'])\n\n if (hm) overlay['horizontal_margin'] = hm\n if (vm) overlay['vertical_margin'] = vm\n if (w) overlay['width'] = w\n }\n}\n\nfunction sanitizePxStringsInJson(json: string): string {\n return json.replace(/\"(-?\\d+(?:\\.\\d+)?)px\"/g, (_match, num) => {\n const n = Number(num)\n if (!Number.isFinite(n)) return _match\n let rounded = Math.round(n)\n if (rounded === 0) rounded = n < 0 ? -1 : 1\n return `\"${rounded}px\"`\n })\n}\n\nfunction cancelUpload(client: SanityClient, uuid: string) {\n return client.observable.request({\n url: `/addons/mux/uploads/${client.config().dataset}/${uuid}`,\n withCredentials: true,\n method: 'DELETE',\n query: PLUGIN_VERSION_QUERY,\n })\n}\n\nexport function uploadUrl({\n url,\n settings,\n client,\n}: {\n url: string\n settings: MuxNewAssetSettings\n client: SanityClient\n watermark?: WatermarkConfig\n}) {\n return testUrl(url).pipe(\n switchMap((validUrl) => {\n return concat(\n of({type: 'url' as const, url: validUrl}),\n testSecretsObservable(client).pipe(\n switchMap((json) => {\n if (!json || !json.status) {\n return throwError(new Error('Invalid credentials'))\n }\n const uuid = generateUuid()\n const muxBody = settings\n if (!muxBody.input) muxBody.input = [{type: 'video'}]\n muxBody.input[0]!.url = validUrl\n sanitizeOverlaySettingsInPlace(muxBody)\n\n const query: Record<string, string> = {\n muxBody: sanitizePxStringsInJson(JSON.stringify(muxBody)),\n }\n const filename = validUrl.split('/').slice(-1)[0]\n if (filename) {\n query['filename'] = filename\n }\n\n const dataset = client.config().dataset\n return defer(() =>\n client.observable.request({\n url: `/addons/mux/assets/${dataset}`,\n withCredentials: true,\n method: 'POST',\n headers: {\n 'MUX-Proxy-UUID': uuid,\n 'Content-Type': 'application/json',\n },\n query: {...query, ...PLUGIN_VERSION_QUERY},\n }),\n ).pipe(\n mergeMap((result) => {\n const asset =\n (result && result.results && result.results[0] && result.results[0].document) ||\n null\n\n if (!asset) {\n return throwError(new Error('No asset document returned'))\n }\n return of({type: 'success' as const, id: uuid, asset})\n }),\n )\n }),\n ),\n )\n }),\n )\n}\n\nexport function uploadFile({\n settings,\n client,\n file,\n watermark,\n}: {\n settings: MuxNewAssetSettings\n client: SanityClient\n file: File\n watermark?: WatermarkConfig\n}) {\n return testFile(file).pipe(\n switchMap((fileOptions) => {\n return concat(\n of({type: 'file' as const, file: fileOptions}),\n testSecretsObservable(client).pipe(\n switchMap((json) => {\n if (!json || !json.status) {\n return throwError(() => new Error('Invalid credentials'))\n }\n const uuid = generateUuid()\n const body = settings\n sanitizeOverlaySettingsInPlace(body)\n\n return concat(\n of({type: 'uuid' as const, uuid}),\n defer(() =>\n client.observable.request<{\n sanityAssetId: string\n upload: {\n cors_origin: string\n id: string\n new_asset_settings: MuxNewAssetSettings\n status: 'waiting'\n timeout: number\n url: string\n }\n }>({\n url: `/addons/mux/uploads/${client.config().dataset}`,\n withCredentials: true,\n method: 'POST',\n headers: {\n 'MUX-Proxy-UUID': uuid,\n 'Content-Type': 'application/json',\n },\n body,\n query: PLUGIN_VERSION_QUERY,\n }),\n ).pipe(\n mergeMap((result) => {\n return createUpChunkObservable(uuid, result.upload.url, file).pipe(\n // @TODO type the observable events\n mergeMap((event) => {\n if (event.type !== 'success') {\n return of(event)\n }\n return from(updateAssetDocumentFromUpload(client, uuid, watermark)).pipe(\n mergeMap((doc) => of({...event, asset: doc})),\n )\n }),\n catchError((err) => {\n // Delete asset document\n return cancelUpload(client, uuid).pipe(mergeMapTo(throwError(err)))\n }),\n )\n }),\n ),\n )\n }),\n ),\n )\n }),\n )\n}\n\ntype UploadResponse = {\n data: {\n asset_id: string\n cors_origin: string\n id: string\n new_asset_settings: {\n static_renditions?: {resolution: string}[]\n passthrough: string\n playback_policies: ['public' | 'signed' | 'drm']\n }\n status: string\n timeout: number\n }\n}\nfunction getUpload(client: SanityClient, assetId: string) {\n const {dataset} = client.config()\n return client.request<UploadResponse>({\n url: `/addons/mux/uploads/${dataset}/${assetId}`,\n withCredentials: true,\n method: 'GET',\n query: PLUGIN_VERSION_QUERY,\n })\n}\n\nfunction pollUpload(client: SanityClient, uuid: string): Promise<UploadResponse> {\n const maxTries = 10\n let pollInterval: number\n let tries = 0\n let assetId: string\n let upload: UploadResponse\n return new Promise((resolve, reject) => {\n pollInterval = (setInterval as typeof window.setInterval)(async () => {\n try {\n upload = await getUpload(client, uuid)\n } catch (err) {\n reject(err)\n return\n }\n assetId = upload && upload.data && upload.data.asset_id\n if (assetId) {\n clearInterval(pollInterval)\n resolve(upload)\n }\n if (tries > maxTries) {\n clearInterval(pollInterval)\n reject(new Error('Upload did not finish'))\n }\n tries++\n }, 2000)\n })\n}\n\nasync function updateAssetDocumentFromUpload(\n client: SanityClient,\n uuid: string,\n _watermark?: WatermarkConfig,\n) {\n let upload: UploadResponse\n let asset: {data: MuxAsset}\n try {\n upload = await pollUpload(client, uuid)\n } catch (err) {\n return Promise.reject(err)\n }\n try {\n asset = await getAsset(client, upload.data.asset_id)\n } catch (err) {\n return Promise.reject(err)\n }\n\n const doc = {\n _id: uuid,\n _type: 'mux.videoAsset',\n status: asset.data.status,\n data: asset.data,\n assetId: asset.data.id,\n playbackId: asset.data.playback_ids[0]?.id,\n uploadId: upload.data.id,\n }\n return client.createOrReplace(doc).then(() => {\n return doc\n })\n}\n\nfunction testFile(file: File) {\n if (typeof window !== 'undefined' && file instanceof window.File) {\n const fileOptions = optionsFromFile({}, file)\n return of(fileOptions)\n }\n return throwError(new Error('Invalid file'))\n}\n\nfunction testUrl(url: string): Observable<string> {\n const error = new Error('Invalid URL')\n if (typeof url !== 'string') {\n return throwError(error)\n }\n let formattedUrl = url.trim()\n formattedUrl = formatDriveShareLink(formattedUrl)\n let parsed\n try {\n parsed = new URL(formattedUrl)\n } catch {\n return throwError(error)\n }\n if (parsed && !parsed.protocol.match(/http:|https:/)) {\n return throwError(error)\n }\n return of(formattedUrl)\n}\n\nfunction optionsFromFile(opts: {preserveFilename?: boolean}, file: File) {\n if (typeof window === 'undefined' || !(file instanceof window.File)) {\n return undefined\n }\n return {\n name: opts.preserveFilename === false ? undefined : file.name,\n type: file.type,\n }\n}\n","import type {ServerError} from '@sanity/client'\n\nexport function isValidUrl(url: string): boolean {\n try {\n const parsed = new URL(url)\n return parsed && !!parsed.protocol.match(/http:|https:/)\n } catch {\n return false\n }\n}\n\n/**\n * We consider a server error one with status code 5XX.\n * Used mainly to handle unknown Proxy issues.\n */\nexport function isServerError(error: Error): error is ServerError {\n return (\n 'statusCode' in error &&\n typeof error.statusCode === 'number' &&\n 500 <= error.statusCode &&\n error.statusCode <= 600\n )\n}\n","/**\n * Utilities for extracting files from dataTransfer in a predictable cross-browser fashion.\n * Also recursively extracts files from a directory\n * Inspired by https://github.com/component/normalized-upload\n */\n\nexport function extractDroppedFiles(dataTransfer: DataTransfer) {\n const files = Array.from(dataTransfer.files || [])\n const items = Array.from(dataTransfer.items || [])\n if (files && files.length > 0) {\n return Promise.resolve(files)\n }\n return normalizeItems(items).then((arr) => arr.flat())\n}\n\nfunction normalizeItems(items: DataTransferItem[]) {\n return Promise.all(\n items.map((item) => {\n // directory\n if (item.kind === 'file' && item.webkitGetAsEntry) {\n let entry: FileSystemEntry | File[] | null\n // Edge throws\n try {\n entry = item.webkitGetAsEntry()\n } catch {\n return [item.getAsFile()]\n }\n if (!entry) {\n return []\n }\n return entry.isDirectory ? walk(entry) : [item.getAsFile()]\n }\n\n // file\n if (item.kind === 'file') {\n const file = item.getAsFile()\n return Promise.resolve(file ? [file] : [])\n }\n\n // others\n return new Promise((resolve) => item.getAsString(resolve)).then((str?: any) =>\n str ? [new File([str], 'unknown.txt', {type: item.type})] : [],\n )\n }),\n )\n}\n\nfunction isFile(entry: FileSystemEntry): entry is FileSystemFileEntry {\n return entry.isFile\n}\nfunction isDirectory(entry: FileSystemEntry): entry is FileSystemDirectoryEntry {\n return entry.isDirectory\n}\n\nfunction walk(entry: FileSystemEntry): any {\n if (isFile(entry)) {\n return new Promise((resolve) => entry.file(resolve)).then((file) => [file])\n }\n\n if (isDirectory(entry)) {\n const dir = entry.createReader()\n return new Promise<any>((resolve) => dir.readEntries(resolve))\n .then((entries: FileSystemEntry[]) => entries.filter((entr) => !entr.name.startsWith('.')))\n .then((entries) => Promise.all(entries.map(walk)).then((arr) => arr.flat()))\n }\n return Promise.resolve([])\n}\n","import {useCallback} from 'react'\nimport {PatchEvent, set, setIfMissing, unset} from 'sanity'\n\nimport type {SetDialogState} from '../hooks/useDialogState'\nimport type {MuxInputProps, PluginConfig, VideoAssetDocument} from '../util/types'\nimport VideosBrowser, {type VideosBrowserProps} from './VideosBrowser'\n\nexport interface Props extends Pick<MuxInputProps, 'onChange'> {\n asset?: VideoAssetDocument | null | undefined\n setDialogState: SetDialogState\n config: PluginConfig\n}\n\nexport default function SelectAssets({\n asset: selectedAsset,\n onChange,\n setDialogState,\n config,\n}: Props) {\n const handleSelect = useCallback<Required<VideosBrowserProps>['onSelect']>(\n (chosenAsset) => {\n if (!chosenAsset?._id) {\n onChange(PatchEvent.from([unset(['asset'])]))\n }\n if (chosenAsset._id !== selectedAsset?._id) {\n onChange(\n PatchEvent.from([\n setIfMissing({asset: {}, _type: 'mux.video'}),\n set({_type: 'reference', _weak: true, _ref: chosenAsset._id}, ['asset']),\n ]),\n )\n }\n setDialogState(false)\n },\n [onChange, setDialogState, selectedAsset],\n )\n\n return <VideosBrowser onSelect={handleSelect} config={config} />\n}\n","import {Dialog} from '@sanity/ui'\nimport {useCallback, useId} from 'react'\nimport {styled} from 'styled-components'\n\nimport type {SetDialogState} from '../hooks/useDialogState'\nimport SelectAsset, {type Props as SelectAssetProps} from './SelectAsset'\n\n/** To prevent Content Layout Shift (CLS), ensure that the dialog always occupies the entire available height. */\nconst StyledDialog = styled(Dialog)`\n > div[data-ui='DialogCard'] > div[data-ui='Card'] {\n height: 100%;\n }\n`\n\nexport default function InputBrowser({\n setDialogState,\n asset,\n onChange,\n config,\n}: Pick<SelectAssetProps, 'onChange' | 'asset' | 'config'> & {\n setDialogState: SetDialogState\n}) {\n const id = `InputBrowser${useId()}`\n const handleClose = useCallback(() => setDialogState(false), [setDialogState])\n return (\n <StyledDialog\n __unstable_autoFocus\n header=\"Select video\"\n id={id}\n onClose={handleClose}\n width={2}\n >\n <SelectAsset\n config={config}\n asset={asset}\n onChange={onChange}\n setDialogState={setDialogState}\n />\n </StyledDialog>\n )\n}\n","import {useCallback} from 'react'\nimport {PatchEvent, unset} from 'sanity'\n\nimport {deleteAssetOnMux} from '../actions/assets'\nimport {useClient} from '../hooks/useClient'\nimport type {MuxInputProps, VideoAssetDocument} from '../util/types'\n\nexport const useCancelUpload = (asset: VideoAssetDocument, onChange: MuxInputProps['onChange']) => {\n const client = useClient()\n return useCallback(() => {\n if (!asset) {\n return\n }\n onChange(PatchEvent.from(unset()))\n if (asset.assetId) {\n void deleteAssetOnMux(client, asset.assetId)\n }\n if (asset._id) {\n void client.delete(asset._id)\n }\n }, [asset, client, onChange])\n}\n","import {styled} from 'styled-components'\n\nexport const TopControls = styled.div`\n position: absolute;\n top: 0;\n right: 0;\n justify-content: flex-end;\n button {\n height: auto;\n }\n`\n","// Lifted from sanity/form/inputs/files/common/UploadProgress\n\nimport {Button, Card, Code, Flex, Inline, Stack, Text} from '@sanity/ui'\nimport {LinearProgress} from 'sanity'\nimport {styled} from 'styled-components'\n\nconst CardWrapper = styled(Card)`\n min-height: 82px;\n box-sizing: border-box;\n`\n\nconst FlexWrapper = styled(Flex)`\n text-overflow: ellipsis;\n overflow: hidden;\n`\n\nconst LeftSection = styled(Stack)`\n position: relative;\n width: 60%;\n`\n\nconst CodeWrapper = styled(Code)`\n position: relative;\n width: 100%;\n\n code {\n overflow: hidden;\n text-overflow: ellipsis;\n position: relative;\n max-width: 200px;\n }\n`\n\nexport const UploadProgress = ({\n progress = 100,\n onCancel,\n filename,\n text = 'Uploading',\n}: {\n progress: number\n filename?: React.ReactNode\n onCancel?: React.MouseEventHandler<HTMLButtonElement>\n text?: React.ReactNode\n}) => {\n // Disable cancel button when upload is 90% or more complete\n // to prevent inconsistency between Mux and Sanity\n const isCancelDisabled = progress >= 90\n\n return (\n <CardWrapper tone=\"primary\" padding={4} border height=\"fill\">\n <FlexWrapper align=\"center\" justify=\"space-between\" height=\"fill\" direction=\"row\" gap={2}>\n <LeftSection>\n <Flex justify=\"center\" gap={[3, 3, 2, 2]} direction={['column', 'column', 'row']}>\n <Text size={1}>\n <Inline space={2}>\n {text}\n <CodeWrapper size={1}>{filename ? filename : '...'}</CodeWrapper>\n </Inline>\n </Text>\n </Flex>\n\n <Card marginTop={3} radius={5} shadow={1}>\n <LinearProgress value={progress} />\n </Card>\n </LeftSection>\n\n {onCancel ? (\n <Button\n fontSize={2}\n text=\"Cancel upload\"\n mode=\"ghost\"\n tone=\"critical\"\n onClick={onCancel}\n disabled={isCancelDisabled}\n />\n ) : null}\n </FlexWrapper>\n </CardWrapper>\n )\n}\n","import {Card, Text} from '@sanity/ui'\nimport {useEffect, useMemo, useRef} from 'react'\n\nimport {useCancelUpload} from '../hooks/useCancelUpload'\nimport type {MuxInputProps, PluginConfig, VideoAssetDocument} from '../util/types'\nimport {TopControls} from './Player.styled'\nimport {UploadProgress} from './UploadProgress'\nimport VideoPlayer from './VideoPlayer'\n\ninterface Props extends Pick<MuxInputProps, 'onChange' | 'readOnly'> {\n buttons?: React.ReactNode\n asset: VideoAssetDocument\n config?: PluginConfig\n}\n\nconst Player = ({asset, buttons, readOnly, onChange, config}: Props) => {\n const isLoading = useMemo<boolean | string>(() => {\n if (asset?.status === 'preparing') {\n return 'Preparing the video'\n }\n if (asset?.status === 'waiting_for_upload') {\n return 'Waiting for upload to start'\n }\n if (asset?.status === 'waiting') {\n return 'Processing upload'\n }\n if (asset?.status === 'ready') {\n return false\n }\n if (typeof asset?.status === 'undefined') {\n return false\n }\n\n return true\n }, [asset])\n // oxlint-disable-next-line react/react-compiler\n const isPreparingStaticRenditions = useMemo<boolean>(() => {\n // Legacy: If static_renditions has a status field, it was created with mp4_support (deprecated)\n // We don't process this old format, just return false\n // Note: 'disabled' status is valid in the new format when no renditions were requested\n if (\n asset?.data?.static_renditions?.status &&\n asset?.data?.static_renditions?.status !== 'disabled'\n ) {\n return false\n }\n\n // Check if any file in static_renditions is still preparing\n const files = asset?.data?.static_renditions?.files\n if (!files || files.length === 0) {\n return false\n }\n return files.some((file) => file.status === 'preparing')\n }, [asset?.data?.static_renditions?.status, asset?.data?.static_renditions?.files])\n const playRef = useRef<HTMLDivElement>(null)\n const muteRef = useRef<HTMLDivElement>(null)\n const handleCancelUpload = useCancelUpload(asset, onChange)\n\n useEffect(() => {\n const style = document.createElement('style')\n style.innerHTML = 'button svg { vertical-align: middle; }'\n\n if (playRef.current?.shadowRoot) {\n playRef.current.shadowRoot.appendChild(style)\n }\n if (muteRef?.current?.shadowRoot) {\n muteRef.current.shadowRoot.appendChild(style.cloneNode(true))\n }\n }, [])\n\n useEffect(() => {\n if (asset?.status === 'errored') {\n handleCancelUpload()\n // @TODO use better error handling\n throw new Error(asset.data?.errors?.messages?.join(' '))\n }\n }, [asset.data?.errors?.messages, asset?.status, handleCancelUpload])\n\n if (!asset || !asset.status) {\n return null\n }\n\n if (isLoading) {\n return (\n <UploadProgress\n progress={100}\n filename={asset?.filename}\n text={(isLoading !== true && isLoading) || 'Waiting for Mux to complete the upload'}\n onCancel={readOnly ? undefined : () => handleCancelUpload()}\n />\n )\n }\n\n return (\n <VideoPlayer asset={asset} hlsConfig={config?.hlsConfig}>\n {buttons && <TopControls slot=\"top-chrome\">{buttons}</TopControls>}\n {isPreparingStaticRenditions && (\n <Card\n padding={2}\n radius={1}\n style={{\n background: 'var(--card-fg-color)',\n position: 'absolute',\n top: '0.5em',\n left: '0.5em',\n }}\n >\n <Text size={1} style={{color: 'var(--card-bg-color)'}}>\n MUX is preparing static renditions, please stand by\n </Text>\n </Card>\n )}\n </VideoPlayer>\n )\n}\n\nexport default Player\n","// todo: get these utils from @sanity/ui instead\nexport function focusRingBorderStyle(border: {color: string; width: number}): string {\n return `inset 0 0 0 ${border.width}px ${border.color}`\n}\n\nexport function focusRingStyle(opts: {\n base?: {bg: string}\n border?: {color: string; width: number}\n focusRing: {offset: number; width: number}\n}): string {\n const {base, border, focusRing} = opts\n const focusRingOutsetWidth = focusRing.offset + focusRing.width\n const focusRingInsetWidth = 0 - focusRing.offset\n const bgColor = base ? base.bg : 'var(--card-bg-color)'\n\n return [\n focusRingInsetWidth > 0 && `inset 0 0 0 ${focusRingInsetWidth}px var(--card-focus-ring-color)`,\n border && focusRingBorderStyle(border),\n focusRingInsetWidth < 0 && `0 0 0 ${0 - focusRingInsetWidth}px ${bgColor}`,\n focusRingOutsetWidth > 0 && `0 0 0 ${focusRingOutsetWidth}px var(--card-focus-ring-color)`,\n ]\n .filter(Boolean)\n .join(',')\n}\n","import {MenuItem} from '@sanity/ui'\nimport {css, styled} from 'styled-components'\n\nimport {focusRingStyle} from './withFocusRing/helpers'\n\nexport const FileButton = styled(MenuItem)(({theme}) => {\n const {focusRing} = theme.sanity\n const base = theme.sanity.color.base\n const border = {width: 1, color: 'var(--card-border-color)'}\n\n return css`\n position: relative;\n\n &:not([data-disabled='true']) {\n &:focus-within {\n box-shadow: ${focusRingStyle({base, border, focusRing})};\n }\n }\n\n & input {\n overflow: hidden;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n position: absolute;\n min-width: 0;\n display: block;\n appearance: none;\n padding: 0;\n margin: 0;\n border: 0;\n opacity: 0;\n }\n `\n})\n","import {Box, type ButtonProps, Flex, Text} from '@sanity/ui'\nimport {isValidElement, useId, useCallback} from 'react'\nimport {isValidElementType} from 'react-is'\n\nimport {FileButton} from './FileInputMenuItem.styled'\n\nexport interface FileInputMenuItemProps extends Omit<ButtonProps, 'onSelect'> {\n accept?: string\n capture?: 'user' | 'environment'\n multiple?: boolean\n onSelect?: (files: File[]) => void\n disabled?: boolean\n}\n\nexport function FileInputMenuItem(\n props: FileInputMenuItemProps &\n Omit<React.HTMLProps<HTMLButtonElement>, 'as' | 'ref' | 'type' | 'value' | 'onSelect'> & {\n ref?: React.Ref<HTMLInputElement>\n },\n) {\n const {\n icon: Icon,\n id: idProp,\n accept,\n capture,\n fontSize,\n multiple,\n onSelect,\n space = 3,\n textAlign,\n text,\n disabled,\n ref,\n ...rest\n } = props\n const idHook = useId()\n const id = idProp || idHook\n\n const handleChange = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n if (onSelect && event.target.files) {\n onSelect(Array.from(event.target.files))\n }\n },\n [onSelect],\n )\n\n const content = (\n <Flex align=\"center\" justify=\"flex-start\">\n {/* Icon */}\n {Icon && (\n <Box marginRight={text ? space : undefined}>\n <Text size={fontSize}>\n {isValidElement(Icon) && Icon}\n {isValidElementType(Icon) && <Icon />}\n </Text>\n </Box>\n )}\n\n {/* Text */}\n {text && (\n <Text align={textAlign} size={fontSize} textOverflow=\"ellipsis\">\n {text}\n </Text>\n )}\n </Flex>\n )\n\n return (\n <FileButton {...rest} htmlFor={id} disabled={disabled} ref={ref}>\n {content}\n\n {/* Visibly hidden input */}\n <input\n data-testid=\"file-button-input\"\n accept={accept}\n capture={capture}\n id={id}\n multiple={multiple}\n onChange={handleChange}\n type=\"file\"\n value=\"\"\n disabled={disabled}\n />\n </FileButton>\n )\n}\n","import {DownloadIcon} from '@sanity/icons/Download'\nimport {EllipsisHorizontalIcon} from '@sanity/icons/EllipsisHorizontal'\nimport {ImageIcon} from '@sanity/icons/Image'\nimport {LockIcon} from '@sanity/icons/Lock'\nimport {PlugIcon} from '@sanity/icons/Plug'\nimport {ResetIcon} from '@sanity/icons/Reset'\nimport {SearchIcon} from '@sanity/icons/Search'\nimport {SyncIcon} from '@sanity/icons/Sync'\nimport {TranslateIcon} from '@sanity/icons/Translate'\nimport {UploadIcon} from '@sanity/icons/Upload'\nimport {\n Box,\n Button,\n Card,\n Inline,\n Label,\n Menu,\n MenuDivider,\n MenuItem,\n Popover,\n Text,\n Tooltip,\n useClickOutsideEvent,\n} from '@sanity/ui'\nimport {memo, useCallback, useEffect, useMemo, useState} from 'react'\nimport {PatchEvent, unset} from 'sanity'\nimport {styled} from 'styled-components'\n\nimport {useAccessControl} from '../hooks/useAccessControl'\nimport {type DialogState, type SetDialogState} from '../hooks/useDialogState'\nimport {useResyncAsset} from '../hooks/useResyncAsset'\nimport {getPlaybackPolicy} from '../util/getPlaybackPolicy'\nimport type {MuxInputProps, PluginConfig, VideoAssetDocument} from '../util/types'\nimport {FileInputMenuItem} from './FileInputMenuItem'\n\nconst LockCard = styled(Card)`\n position: absolute;\n top: 0;\n left: 0;\n opacity: 0.6;\n mix-blend-mode: screen;\n background: transparent;\n`\n\nconst LockButton = styled(Button)`\n background: transparent;\n color: white;\n`\n\n// @TODO: add support for audio type (asset._type) when uploading an audio file so we can hide the thumbnail option.\nconst isVideoAsset = (asset: VideoAssetDocument) => {\n return asset._type === 'mux.videoAsset'\n}\n\nfunction PlayerActionsMenu(\n props: Pick<MuxInputProps, 'onChange' | 'readOnly'> & {\n asset: VideoAssetDocument\n onSelect: (files: File[]) => void\n dialogState: DialogState\n setDialogState: SetDialogState\n config: PluginConfig\n accept: string\n },\n) {\n const {asset, readOnly, dialogState, setDialogState, onChange, onSelect, accept} = props\n const [open, setOpen] = useState(false)\n const [menuElement, setMenuRef] = useState<HTMLDivElement | null>(null)\n const isSigned = useMemo(() => getPlaybackPolicy(asset)?.policy === 'signed', [asset])\n const {hasConfigAccess} = useAccessControl(props.config)\n const {resyncAsset, isResyncing} = useResyncAsset({showToast: true})\n\n const onReset = useCallback(() => onChange(PatchEvent.from(unset([]))), [onChange])\n\n const handleResync = useCallback(async () => {\n setOpen(false)\n await resyncAsset(asset)\n }, [resyncAsset, asset])\n\n useEffect(() => {\n if (open && dialogState) {\n // oxlint-disable-next-line react/react-compiler\n setOpen(false)\n }\n }, [dialogState, open])\n\n useClickOutsideEvent(\n () => setOpen(false),\n () => [menuElement],\n )\n\n return (\n <Inline space={1} padding={2}>\n {isSigned && (\n <Tooltip\n animate\n content={\n <Box padding={2}>\n <Text muted size={1}>\n Signed playback policy\n </Text>\n </Box>\n }\n placement=\"right\"\n portal\n >\n <LockCard radius={2} margin={2} scheme=\"dark\" tone=\"positive\">\n <LockButton icon={LockIcon} mode=\"bleed\" tone=\"positive\" />\n </LockCard>\n </Tooltip>\n )}\n <Popover\n animate\n content={\n <Menu ref={setMenuRef}>\n <Box padding={2}>\n <Label muted size={1}>\n Replace\n </Label>\n </Box>\n <FileInputMenuItem\n accept={accept}\n icon={UploadIcon}\n onSelect={onSelect}\n text=\"Upload\"\n disabled={readOnly}\n fontSize={1}\n />\n <MenuItem\n icon={SearchIcon}\n text=\"Browse\"\n onClick={() => setDialogState('select-video')}\n />\n {isVideoAsset(asset) && (\n <>\n <MenuItem\n icon={ImageIcon}\n text=\"Thumbnail\"\n onClick={() => setDialogState('edit-thumbnail')}\n />\n <MenuItem\n icon={TranslateIcon}\n text=\"Captions\"\n onClick={() => setDialogState('edit-captions')}\n />\n <MenuItem\n icon={SyncIcon}\n text=\"Resync from Mux\"\n onClick={handleResync}\n disabled={readOnly || isResyncing}\n />\n </>\n )}\n <MenuDivider />\n <MenuItem\n icon={DownloadIcon}\n text=\"Mezzanine\"\n onClick={() => setDialogState('mezzanine')}\n />\n <MenuDivider />\n {hasConfigAccess && (\n <>\n <MenuItem\n icon={PlugIcon}\n text=\"Configure API\"\n onClick={() => setDialogState('secrets')}\n />\n <MenuDivider />\n </>\n )}\n <MenuItem\n tone=\"critical\"\n icon={ResetIcon}\n text=\"Clear field\"\n onClick={onReset}\n disabled={readOnly}\n />\n </Menu>\n }\n portal\n open={open}\n >\n <Button\n icon={EllipsisHorizontalIcon}\n mode=\"ghost\"\n fontSize={1}\n onClick={() => {\n setDialogState(false)\n setOpen(true)\n }}\n />\n </Popover>\n </Inline>\n )\n}\n\nexport default memo(PlayerActionsMenu)\n","import {useEffect, useState} from 'react'\n\nimport {type StagedUpload} from '../components/Uploader'\n\nexport function useFetchFileSize(stagedUpload: StagedUpload, maxFileSize?: number) {\n const [fileSize, setFileSize] = useState<number | null>(null)\n const [isLoadingFileSize, setIsLoadingFileSize] = useState(false)\n const [canSkipFileSizeValidation, setCanSkipFileSizeValidation] = useState(false)\n\n useEffect(() => {\n // Fetch URL Upload file size\n if (stagedUpload.type === 'url') {\n // oxlint-disable-next-line react/react-compiler\n setIsLoadingFileSize(false)\n setCanSkipFileSizeValidation(false)\n setFileSize(null)\n const url = stagedUpload.url\n\n // Get file size from URL\n const fetchFileSize = async () => {\n setIsLoadingFileSize(true)\n try {\n const response = await fetch(url, {method: 'HEAD'})\n const contentLength = response.headers.get('content-length')\n const newFileSize = contentLength ? parseInt(contentLength, 10) : null\n\n setIsLoadingFileSize(false)\n if (newFileSize) {\n setFileSize(newFileSize)\n }\n if (newFileSize === null && maxFileSize !== undefined) {\n // Size unknown but size limit is configured - skip file size validation\n setCanSkipFileSizeValidation(true)\n }\n } catch {\n console.warn('Could not validate file size from URL')\n // Skip validation of file size, but still validate duration\n setCanSkipFileSizeValidation(true)\n setIsLoadingFileSize(false)\n }\n }\n\n void fetchFileSize()\n }\n if (stagedUpload.type === 'file') {\n setFileSize(stagedUpload.files[0]!.size)\n }\n }, [maxFileSize, stagedUpload, stagedUpload.type])\n\n return {\n fileSize,\n isLoadingFileSize,\n canSkipFileSizeValidation,\n }\n}\n","import {useEffect, useState} from 'react'\n\nimport {type StagedUpload} from '../components/Uploader'\n\nexport interface VideoAssetMetadata {\n width?: number\n height?: number\n isAudioOnly?: boolean\n duration?: number\n size?: number\n aspectRatio?: number\n}\n\nexport function useMediaMetadata(stagedUpload: StagedUpload) {\n const [videoAssetMetadata, setVideoAssetMetadata] = useState<VideoAssetMetadata | null>(null)\n const [isLoadingMetadata, setIsLoadingMetadata] = useState(false)\n useEffect(() => {\n let videoSrc = null\n // Validate file uploads\n if (stagedUpload.type === 'file') {\n const file = stagedUpload.files[0]\n videoSrc = URL.createObjectURL(file!)\n }\n\n // Validate URL uploads\n if (stagedUpload.type === 'url') {\n videoSrc = stagedUpload.url\n }\n\n // oxlint-disable-next-line react/react-compiler\n setVideoAssetMetadata((old) => ({\n ...old,\n duration: undefined,\n width: undefined,\n height: undefined,\n }))\n\n if (!videoSrc) return () => null\n\n setIsLoadingMetadata(true)\n const videoElement = document.createElement('video')\n videoElement.preload = 'metadata'\n\n const metadataListeners = [\n () => {\n setIsLoadingMetadata(false)\n },\n () => {\n const duration = videoElement.duration\n const width = videoElement.videoWidth\n const height = videoElement.videoHeight\n const isAudioOnly = width <= 0 && height <= 0\n const aspectRatio = width / height\n setVideoAssetMetadata((old) => {\n return {\n ...old,\n duration: duration,\n width: width,\n height: height,\n isAudioOnly: isAudioOnly,\n aspectRatio: aspectRatio,\n }\n })\n },\n ]\n\n const cleanupVideo = (videoEl: HTMLVideoElement) => {\n const currentVideoSrc = videoEl?.src\n if (videoEl) {\n metadataListeners.forEach((listener) =>\n videoEl.removeEventListener('loadedmetadata', listener),\n )\n videoEl.onerror = null\n videoEl.src = ''\n videoEl.load()\n }\n if (currentVideoSrc?.startsWith('blob:')) {\n URL.revokeObjectURL(currentVideoSrc)\n }\n }\n metadataListeners.push(() => setTimeout(() => cleanupVideo(videoElement), 0))\n\n videoElement.onerror = () => {\n setIsLoadingMetadata(false)\n console.warn('Could not read video metadata for validation')\n cleanupVideo(videoElement)\n }\n\n metadataListeners.forEach((listener) =>\n videoElement.addEventListener('loadedmetadata', listener),\n )\n videoElement.src = videoSrc\n\n return () => {\n cleanupVideo(videoElement)\n }\n }, [stagedUpload.type, stagedUpload])\n\n return {\n videoAssetMetadata,\n setVideoAssetMetadata,\n isLoadingMetadata,\n }\n}\n","import {roundPxString} from './roundPxString'\nimport type {MuxOverlaySettings, WatermarkConfig} from './types'\n\n/**\n * Converts a draggable watermark position (x, y percentages) to Mux's overlay_settings format.\n *\n * @param watermark - The watermark configuration with position, size, and opacity\n * @returns Mux overlay_settings object\n * @see {@link https://www.mux.com/docs/guides/add-watermarks-to-your-videos}\n */\nexport function convertWatermarkToMuxOverlay(\n watermark: WatermarkConfig,\n options?: {\n /**\n * Video aspect ratio (width / height). Needed for correct vertical positioning,\n * especially on vertical videos.\n */\n videoAspectRatio?: number\n /**\n * Unit to emit for margins/width when generating overlay_settings from Canvas mode.\n * - 'px' will generate pixel strings according to Mux's scaling rules:\n * values are applied as if the video were scaled to 1920x1080 (horizontal)\n * or 1080x1920 (vertical).\n * - '%' preserves existing behavior.\n */\n units?: '%' | 'px'\n },\n): MuxOverlaySettings | null {\n if (!watermark.enabled || !watermark.imageUrl) {\n return null\n }\n\n const size = watermark.size || 20\n const opacity = watermark.opacity ?? 0.7\n\n /**\n * Convert a percentage to whole-pixel string, using Mux's base dimensions:\n * - Horizontal video: 1920x1080\n * - Vertical video: 1080x1920\n */\n const toPxString = (valuePercent: number, axis: 'x' | 'y') => {\n const videoAspectRatio = options?.videoAspectRatio ?? 16 / 9\n const isVertical = videoAspectRatio > 0 && videoAspectRatio < 1\n const baseW = isVertical ? 1080 : 1920\n const baseH = isVertical ? 1920 : 1080\n const base = axis === 'x' ? baseW : baseH\n const px = (valuePercent / 100) * base\n let rounded = Math.round(px)\n // Avoid sending 0px (and JS -0); keep sign for negative margins.\n if (rounded === 0) rounded = px < 0 ? -1 : 1\n return `${rounded}px`\n }\n\n const normalizeToPixels = (value: string | undefined, axis: 'x' | 'y'): string | undefined => {\n if (!value) return value\n const trimmed = value.trim()\n if (trimmed.endsWith('px')) {\n return roundPxString(trimmed)\n }\n if (trimmed.endsWith('%')) {\n const n = Number(trimmed.slice(0, -1))\n if (!Number.isFinite(n)) return value\n return toPxString(n, axis)\n }\n return value\n }\n\n // If user provided explicit overlay settings, use them (Mux-documented format).\n // When `options.units === 'px'`, we normalize both % and px to whole-pixel strings,\n // honoring vertical vs horizontal video bases.\n if (watermark.overlay_settings) {\n const widthValue = watermark.overlay_settings.width\n const widthNormalized =\n options?.units === 'px' ? normalizeToPixels(widthValue, 'x') : widthValue\n return {\n ...watermark.overlay_settings,\n horizontal_margin:\n options?.units === 'px'\n ? (normalizeToPixels(watermark.overlay_settings.horizontal_margin, 'x') ??\n watermark.overlay_settings.horizontal_margin)\n : watermark.overlay_settings.horizontal_margin,\n vertical_margin:\n options?.units === 'px'\n ? (normalizeToPixels(watermark.overlay_settings.vertical_margin, 'y') ??\n watermark.overlay_settings.vertical_margin)\n : watermark.overlay_settings.vertical_margin,\n width: widthNormalized ?? `${size}%`,\n opacity: watermark.overlay_settings.opacity ?? `${Math.round(opacity * 100)}%`,\n }\n }\n\n const position = watermark.position || {x: 50, y: 50}\n\n /**\n * Our UI stores watermark position as the *center point* in percentages.\n * Mux margins are interpreted relative to an *edge* (based on align).\n *\n * To make \"corner\" placements match what the user dragged, we convert from\n * center-position to top-left margins by subtracting half the watermark size.\n *\n * Note: `size` is a percentage of video width. Mux `width` is also expressed\n * as a percentage of the video width, so we can reuse it for horizontal math.\n * For vertical math, we approximate using the same percentage to keep behavior\n * consistent with the current draggable UI (which also uses `size` in both axes\n * for bounds).\n */\n // Allow negative margins to compensate for rounding / letterboxing edge-cases.\n // We still clamp to a sane range so values don't explode.\n const clampPercent = (value: number) => Math.max(-100, Math.min(100, value))\n\n // Mux accepts percentage strings; avoid sending an exact \"0%\" by nudging to 0.01%.\n // This also handles the JS -0 edge case and tiny floating point remnants.\n const toPercentString = (value: number) => {\n const epsilon = 1e-9\n const isZeroish = value === 0 || Object.is(value, -0) || Math.abs(value) < epsilon\n return `${isZeroish ? 0.01 : value}%`\n }\n\n const watermarkWidthPercentOfVideoWidth = size\n\n /**\n * Convert watermark height into % of video height.\n * height% = (watermarkWidthPx / imageAspectRatio) / videoHeightPx\n * = (size% * videoWidthPx / imageAspectRatio) / videoHeightPx\n * = size% * (videoWidthPx/videoHeightPx) / imageAspectRatio\n * = size% * videoAspectRatio / imageAspectRatio\n */\n const videoAspectRatio = options?.videoAspectRatio ?? 16 / 9\n const imageAspectRatio = watermark.imageAspectRatio ?? 1\n const watermarkHeightPercentOfVideoHeight = Math.max(\n 0,\n Math.min(100, (size * videoAspectRatio) / imageAspectRatio),\n )\n\n const halfWidth = watermarkWidthPercentOfVideoWidth / 2\n const halfHeight = watermarkHeightPercentOfVideoHeight / 2\n\n const leftMargin = clampPercent(\n Math.min(position.x - halfWidth, 100 - watermarkWidthPercentOfVideoWidth),\n )\n const topMargin = clampPercent(\n Math.min(position.y - halfHeight, 100 - watermarkHeightPercentOfVideoHeight),\n )\n\n const units = options?.units ?? '%'\n const marginX = units === 'px' ? toPxString(leftMargin, 'x') : toPercentString(leftMargin)\n const marginY = units === 'px' ? toPxString(topMargin, 'y') : toPercentString(topMargin)\n const width = units === 'px' ? toPxString(size, 'x') : `${size}%`\n\n const overlaySettings: MuxOverlaySettings = {\n vertical_align: 'top',\n vertical_margin: marginY,\n horizontal_align: 'left',\n horizontal_margin: marginX,\n width,\n opacity: `${Math.round(opacity * 100)}%`,\n }\n\n return overlaySettings\n}\n","// From: https://stackoverflow.com/questions/10420352/converting-file-size-in-bytes-to-human-readable-string\n/**\n * Format bytes as human-readable text.\n *\n * @param bytes Number of bytes.\n * @param si True to use metric (SI) units, aka powers of 1000. False to use\n * binary (IEC), aka powers of 1024.\n * @param dp Number of decimal places to display.\n *\n * @return Formatted string.\n */\nexport default function formatBytes(bytes: number, si = false, dp = 1) {\n const thresh = si ? 1000 : 1024\n\n if (Math.abs(bytes) < thresh) {\n return bytes + ' B'\n }\n\n const units = si\n ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']\n : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']\n let u = -1\n const r = 10 ** dp\n\n do {\n bytes /= thresh\n ++u\n } while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1)\n\n return bytes.toFixed(dp) + ' ' + units[u]\n}\n","import {CheckmarkCircleIcon} from '@sanity/icons/CheckmarkCircle'\nimport {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {Box, Button, Card, Flex, Grid, Stack, Text, TextInput} from '@sanity/ui'\nimport {useCallback, useEffect, useRef, useState} from 'react'\nimport {styled} from 'styled-components'\n\nimport {convertWatermarkToMuxOverlay} from '../util/convertWatermarkToMux'\nimport type {MuxOverlaySettings, WatermarkConfig} from '../util/types'\n\nconst RangeInput = styled.input`\n width: 100%;\n height: 4px;\n border-radius: 2px;\n background: var(--card-border-color);\n outline: none;\n -webkit-appearance: none;\n appearance: none;\n\n &::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--card-focus-ring-color, #2276fc);\n cursor: pointer;\n border: 2px solid white;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n }\n\n &::-moz-range-thumb {\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--card-focus-ring-color, #2276fc);\n cursor: pointer;\n border: 2px solid white;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n }\n\n &:hover::-webkit-slider-thumb {\n background: var(--card-focus-ring-color, #1a5fc7);\n }\n\n &:hover::-moz-range-thumb {\n background: var(--card-focus-ring-color, #1a5fc7);\n }\n`\n\nconst WatermarkOverlay = styled.div<{$opacity: number}>`\n position: absolute;\n max-width: 200px;\n opacity: ${(props) => props.$opacity};\n cursor: move;\n user-select: none;\n z-index: 10;\n pointer-events: auto;\n\n img {\n width: 100%;\n height: auto;\n display: block;\n pointer-events: none;\n }\n\n &:hover {\n outline: 2px dashed rgba(255, 255, 255, 0.8);\n outline-offset: 4px;\n }\n`\n\ninterface DraggableWatermarkProps {\n watermark: WatermarkConfig\n onChange: (watermark: WatermarkConfig) => void\n containerRef?: React.RefObject<HTMLDivElement>\n videoElementRef?: React.RefObject<HTMLVideoElement>\n}\n\nexport default function DraggableWatermark({\n watermark,\n onChange,\n containerRef,\n videoElementRef,\n}: DraggableWatermarkProps) {\n const [isDragging, setIsDragging] = useState(false)\n const [dragStart, setDragStart] = useState({x: 0, y: 0})\n const [startPosition, setStartPosition] = useState({x: 0, y: 0})\n const watermarkRef = useRef<HTMLDivElement>(null)\n const debounceTimeoutRef = useRef<NodeJS.Timeout | null>(null)\n const [localPosition, setLocalPosition] = useState(watermark.position || {x: 50, y: 50})\n\n const position = localPosition\n const size = watermark.size || 20\n const opacity = watermark.opacity ?? 0.7\n\n const parseOpacityPercent = (value: string | undefined): number | null => {\n if (!value) return null\n const trimmed = value.trim()\n if (!trimmed.endsWith('%')) return null\n const num = Number(trimmed.slice(0, -1))\n if (!Number.isFinite(num)) return null\n return Math.max(0, Math.min(1, num / 100))\n }\n\n const getVideoContentBox = useCallback(() => {\n const container = containerRef?.current\n if (!container) return {x: 0, y: 0, width: 0, height: 0}\n\n const rect = container.getBoundingClientRect()\n const containerW = rect.width\n const containerH = rect.height\n\n const videoEl = videoElementRef?.current\n const videoW = videoEl?.videoWidth || 0\n const videoH = videoEl?.videoHeight || 0\n\n if (!videoW || !videoH || !containerW || !containerH) {\n return {x: 0, y: 0, width: containerW, height: containerH}\n }\n\n // object-fit: contain sizing\n const scale = Math.min(containerW / videoW, containerH / videoH)\n const contentW = videoW * scale\n const contentH = videoH * scale\n const offsetX = (containerW - contentW) / 2\n const offsetY = (containerH - contentH) / 2\n\n return {x: offsetX, y: offsetY, width: contentW, height: contentH}\n }, [containerRef, videoElementRef])\n\n const parseOverlayValue = (value: string | undefined): {n: number; unit: '%' | 'px'} | null => {\n if (!value) return null\n const trimmed = value.trim()\n const px = trimmed.endsWith('px')\n const pct = trimmed.endsWith('%')\n const num = Number(trimmed.replace(/px|%/g, ''))\n if (!Number.isFinite(num)) return null\n if (px) return {n: num, unit: 'px'}\n if (pct) return {n: num, unit: '%'}\n return null\n }\n\n const computeManualStyle = (overlay: MuxOverlaySettings) => {\n const rect = containerRef?.current?.getBoundingClientRect()\n const w = rect?.width ?? 0\n const h = rect?.height ?? 0\n const isVertical = h > w\n const baseW = isVertical ? 1080 : 1920\n const baseH = isVertical ? 1920 : 1080\n\n const hm = parseOverlayValue(overlay.horizontal_margin)\n const vm = parseOverlayValue(overlay.vertical_margin)\n const ww = parseOverlayValue(overlay.width)\n const manualOpacity = parseOpacityPercent(overlay.opacity)\n\n const toCss = (v: {n: number; unit: '%' | 'px'} | null, axis: 'x' | 'y') => {\n if (!v) return undefined\n if (v.unit === '%') return `${v.n}%`\n if (axis === 'x') return `${(v.n * w) / baseW}px`\n return `${(v.n * h) / baseH}px`\n }\n\n const computeHorizontalStyle = () => {\n if (overlay.horizontal_align === 'left') {\n return {left: toCss(hm, 'x'), right: undefined, transform: 'translate(0, 0)'}\n }\n if (overlay.horizontal_align === 'right') {\n return {right: toCss(hm, 'x'), left: undefined, transform: 'translate(0, 0)'}\n }\n return {left: '50%', right: undefined, transform: 'translate(-50%, 0)'}\n }\n\n const computeVerticalStyle = () => {\n if (overlay.vertical_align === 'top') {\n return {top: toCss(vm, 'y'), bottom: undefined}\n }\n if (overlay.vertical_align === 'bottom') {\n return {bottom: toCss(vm, 'y'), top: undefined}\n }\n return {top: '50%', bottom: undefined}\n }\n\n const hStyle = computeHorizontalStyle()\n const vStyle = computeVerticalStyle()\n\n let transform = hStyle.transform\n if (overlay.vertical_align === 'middle') {\n transform =\n overlay.horizontal_align === 'center' ? 'translate(-50%, -50%)' : 'translate(0, -50%)'\n }\n\n return {\n position: 'absolute' as const,\n ...hStyle,\n ...vStyle,\n transform,\n width: ww ? toCss(ww, 'x') : `${size}%`,\n opacity: manualOpacity ?? opacity,\n cursor: 'default',\n }\n }\n\n const debouncedOnChange = useCallback(\n (newWatermark: WatermarkConfig) => {\n if (debounceTimeoutRef.current) {\n clearTimeout(debounceTimeoutRef.current)\n }\n debounceTimeoutRef.current = setTimeout(() => {\n onChange(newWatermark)\n }, 300)\n },\n [onChange],\n )\n\n useEffect(() => {\n return () => {\n if (debounceTimeoutRef.current) {\n clearTimeout(debounceTimeoutRef.current)\n }\n }\n }, [])\n\n useEffect(() => {\n if (!isDragging && watermark.position) {\n // oxlint-disable-next-line react/react-compiler\n setLocalPosition(watermark.position)\n }\n }, [watermark.position, isDragging])\n\n const handleMouseDown = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault()\n setIsDragging(true)\n setDragStart({x: e.clientX, y: e.clientY})\n setStartPosition({x: position.x, y: position.y})\n },\n [position],\n )\n\n const handleMouseMove = useCallback(\n (e: MouseEvent) => {\n if (!isDragging || !containerRef?.current) return\n\n const container = containerRef.current\n const rect = container.getBoundingClientRect()\n const content = getVideoContentBox()\n const contentW = content.width || rect.width\n const contentH = content.height || rect.height\n const dx = e.clientX - dragStart.x\n const dy = e.clientY - dragStart.y\n\n const deltaXPercent = (dx / contentW) * 100\n const deltaYPercent = (dy / contentH) * 100\n\n let newX = startPosition.x + deltaXPercent\n let newY = startPosition.y + deltaYPercent\n\n newX = Math.max(0, Math.min(100, newX))\n newY = Math.max(0, Math.min(100, newY))\n\n setLocalPosition({x: newX, y: newY})\n\n debouncedOnChange({\n ...watermark,\n position: {x: newX, y: newY},\n })\n },\n [\n isDragging,\n dragStart,\n startPosition,\n containerRef,\n watermark,\n debouncedOnChange,\n getVideoContentBox,\n ],\n )\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false)\n if (debounceTimeoutRef.current) {\n clearTimeout(debounceTimeoutRef.current)\n debounceTimeoutRef.current = null\n }\n onChange({\n ...watermark,\n position: localPosition,\n })\n }, [watermark, localPosition, onChange])\n\n useEffect(() => {\n if (isDragging) {\n document.addEventListener('mousemove', handleMouseMove)\n document.addEventListener('mouseup', handleMouseUp)\n return () => {\n document.removeEventListener('mousemove', handleMouseMove)\n document.removeEventListener('mouseup', handleMouseUp)\n }\n }\n return undefined\n }, [isDragging, handleMouseMove, handleMouseUp])\n\n if (!watermark.imageUrl) {\n return null\n }\n\n const hasManualOverlay = Boolean(watermark.overlay_settings)\n const opacityForRender = hasManualOverlay\n ? (parseOpacityPercent(watermark.overlay_settings?.opacity) ?? opacity)\n : opacity\n // oxlint-disable-next-line react/react-compiler\n const contentBox = getVideoContentBox()\n const hasContentBox = contentBox.width > 0 && contentBox.height > 0\n\n const computeWatermarkStyle = () => {\n if (hasManualOverlay) {\n return computeManualStyle(watermark.overlay_settings!)\n }\n if (hasContentBox) {\n return {\n left: `${contentBox.x + (position.x / 100) * contentBox.width}px`,\n top: `${contentBox.y + (position.y / 100) * contentBox.height}px`,\n transform: 'translate(-50%, -50%)',\n width: `${Math.max(1, (size / 100) * contentBox.width)}px`,\n cursor: isDragging ? 'grabbing' : 'grab',\n }\n }\n return {\n left: `${position.x}%`,\n top: `${position.y}%`,\n transform: 'translate(-50%, -50%)',\n width: `${size}%`,\n cursor: isDragging ? 'grabbing' : 'grab',\n }\n }\n\n return (\n <WatermarkOverlay\n ref={watermarkRef}\n $opacity={opacityForRender}\n onMouseDown={hasManualOverlay ? undefined : handleMouseDown}\n // oxlint-disable-next-line react/react-compiler\n style={computeWatermarkStyle()}\n >\n <img src={watermark.imageUrl} alt=\"Watermark\" draggable={false} />\n </WatermarkOverlay>\n )\n}\n\ninterface WatermarkControlsProps {\n watermark: WatermarkConfig\n onChange: (watermark: WatermarkConfig) => void\n onValidationChange?: (error: string | null) => void\n previewContainerRef?: React.RefObject<HTMLDivElement | null>\n previewVideoRef?: React.RefObject<HTMLVideoElement | null>\n}\n\nexport function WatermarkControls({\n watermark,\n onChange,\n onValidationChange,\n previewContainerRef,\n previewVideoRef,\n}: WatermarkControlsProps) {\n const [urlInput, setUrlInput] = useState(watermark.imageUrl || '')\n const [urlError, setUrlError] = useState<string | null>(null)\n const [isValidating, setIsValidating] = useState(false)\n const [isValid, setIsValid] = useState<boolean | null>(null)\n const validationTimeoutRef = useRef<NodeJS.Timeout | null>(null)\n const [mode, setMode] = useState<'canvas' | 'manual'>(\n watermark.overlay_settings ? 'manual' : 'canvas',\n )\n\n const isUpdatingRef = useRef(false)\n\n const isValidExtension = useCallback((extension: string) => {\n return extension.endsWith('.png') || extension.endsWith('.jpg') || extension.endsWith('.jpeg')\n }, [])\n\n const validateUrl = useCallback(\n (url: string) => {\n if (validationTimeoutRef.current) {\n clearTimeout(validationTimeoutRef.current)\n }\n\n if (!url) {\n setUrlError(null)\n setIsValid(null)\n setIsValidating(false)\n onValidationChange?.(null)\n isUpdatingRef.current = true\n onChange({\n ...watermark,\n enabled: false,\n imageUrl: undefined,\n overlay_settings: undefined,\n })\n return\n }\n\n setIsValidating(true)\n setIsValid(null)\n setUrlError(null)\n\n validationTimeoutRef.current = setTimeout(() => {\n try {\n const urlObj = new URL(url)\n const pathname = urlObj.pathname.toLowerCase()\n if (isValidExtension(pathname)) {\n setIsValid(true)\n setUrlError(null)\n onValidationChange?.(null)\n const img = new Image()\n img.onload = () => {\n const imageAspectRatio =\n img.naturalWidth && img.naturalHeight ? img.naturalWidth / img.naturalHeight : 1\n isUpdatingRef.current = true\n onChange({\n ...watermark,\n enabled: true,\n imageUrl: url,\n imageAspectRatio,\n })\n }\n img.onerror = () => {\n isUpdatingRef.current = true\n onChange({\n ...watermark,\n enabled: true,\n imageUrl: url,\n imageAspectRatio: watermark.imageAspectRatio,\n })\n }\n img.src = url\n } else {\n const errorMsg =\n 'Mux only supports PNG and JPG watermark images. Please use a .png or .jpg file.'\n setIsValid(false)\n setUrlError(errorMsg)\n onValidationChange?.(errorMsg)\n isUpdatingRef.current = true\n onChange({\n ...watermark,\n enabled: false,\n imageUrl: undefined,\n imageAspectRatio: undefined,\n overlay_settings: undefined,\n })\n }\n } catch {\n setIsValid(false)\n const errorMsg = 'Please enter a valid URL (e.g., https://example.com/watermark.png)'\n setUrlError(errorMsg)\n onValidationChange?.(errorMsg)\n isUpdatingRef.current = true\n onChange({\n ...watermark,\n enabled: false,\n imageUrl: undefined,\n imageAspectRatio: undefined,\n overlay_settings: undefined,\n })\n } finally {\n setIsValidating(false)\n }\n }, 500)\n },\n [watermark, onChange, onValidationChange, isValidExtension],\n )\n\n useEffect(() => {\n return () => {\n if (validationTimeoutRef.current) {\n clearTimeout(validationTimeoutRef.current)\n }\n }\n }, [])\n\n useEffect(() => {\n // oxlint-disable-next-line react/react-compiler\n setMode(watermark.overlay_settings ? 'manual' : 'canvas')\n }, [watermark.overlay_settings])\n\n const handleUrlChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const url = e.target.value\n setUrlInput(url)\n\n if (watermark.imageUrl && url !== watermark.imageUrl) {\n isUpdatingRef.current = true\n onChange({\n ...watermark,\n enabled: false,\n imageUrl: undefined,\n imageAspectRatio: undefined,\n overlay_settings: undefined,\n })\n }\n\n validateUrl(url)\n }\n\n const normalizeZeroPercent = (value: string | undefined) => {\n if (!value) return value\n const trimmed = value.trim()\n if (!trimmed.endsWith('%')) return value\n const n = Number(trimmed.slice(0, -1))\n if (!Number.isFinite(n)) return value\n const epsilon = 1e-9\n if (n === 0 || Object.is(n, -0) || Math.abs(n) < epsilon) return '0.01%'\n return `${n}%`\n }\n\n const updateOverlaySettings = (next: Partial<MuxOverlaySettings>) => {\n const prev = watermark.overlay_settings\n const base: MuxOverlaySettings = prev ?? {\n vertical_align: 'bottom',\n vertical_margin: '2%',\n horizontal_align: 'right',\n horizontal_margin: '2%',\n width: `${watermark.size ?? 20}%`,\n opacity: `${Math.round((watermark.opacity ?? 0.7) * 100)}%`,\n }\n\n const merged: MuxOverlaySettings = {\n ...base,\n ...next,\n }\n\n onChange({\n ...watermark,\n enabled: true,\n overlay_settings: {\n ...merged,\n horizontal_margin:\n normalizeZeroPercent(merged.horizontal_margin) || merged.horizontal_margin,\n vertical_margin: normalizeZeroPercent(merged.vertical_margin) || merged.vertical_margin,\n },\n })\n }\n\n const getVideoContentBox = () => {\n const container = previewContainerRef?.current\n if (!container) return {x: 0, y: 0, width: 0, height: 0}\n\n const rect = container.getBoundingClientRect()\n const containerW = rect.width\n const containerH = rect.height\n\n const videoEl = previewVideoRef?.current\n const videoW = videoEl?.videoWidth || 0\n const videoH = videoEl?.videoHeight || 0\n\n if (!videoW || !videoH || !containerW || !containerH) {\n return {x: 0, y: 0, width: containerW, height: containerH}\n }\n\n const scale = Math.min(containerW / videoW, containerH / videoH)\n const contentW = videoW * scale\n const contentH = videoH * scale\n const offsetX = (containerW - contentW) / 2\n const offsetY = (containerH - contentH) / 2\n\n return {x: offsetX, y: offsetY, width: contentW, height: contentH}\n }\n\n return (\n <Stack space={3}>\n <Stack space={2}>\n <Text size={1} weight=\"medium\">\n Watermark Image URL\n </Text>\n <Text size={0} muted>\n Enter a URL to a PNG or JPG image. Mux will download this image and overlay it on your\n video.\n </Text>\n <Box style={{position: 'relative', width: '100%'}}>\n <input\n type=\"url\"\n value={urlInput}\n onChange={handleUrlChange}\n placeholder=\"https://example.com/watermark.png\"\n style={{\n padding: '8px 12px',\n paddingRight: (() => {\n if (urlInput) return '96px'\n if (isValid !== null) return '36px'\n return '12px'\n })(),\n border: (() => {\n if (urlError || isValid === false) return '1px solid #e74c3c'\n if (isValid === true) return '1px solid #4caf50'\n return '1px solid #ccc'\n })(),\n borderRadius: '4px',\n width: '100%',\n maxWidth: '100%',\n boxSizing: 'border-box',\n fontSize: '14px',\n }}\n />\n {(urlInput || isValidating || isValid !== null) && (\n <Box\n style={{\n position: 'absolute',\n right: '8px',\n top: '50%',\n transform: 'translateY(-50%)',\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n }}\n >\n {urlInput && (\n <Button\n text=\"Clear\"\n mode=\"bleed\"\n tone=\"critical\"\n onClick={() => {\n setUrlInput('')\n validateUrl('')\n }}\n disabled={isValidating}\n style={{fontSize: '11px', height: '24px'}}\n />\n )}\n {isValidating && (\n <Text size={0} muted>\n Validating...\n </Text>\n )}\n {isValid === true && !isValidating && (\n <CheckmarkCircleIcon style={{color: '#4caf50', fontSize: '18px'}} />\n )}\n {isValid === false && !isValidating && (\n <ErrorOutlineIcon style={{color: '#e74c3c', fontSize: '18px'}} />\n )}\n </Box>\n )}\n </Box>\n {urlError && (\n <Card padding={2} tone=\"critical\" radius={2}>\n <Flex align=\"center\" gap={2}>\n <ErrorOutlineIcon style={{color: '#e74c3c', flexShrink: 0}} />\n <Text size={0} style={{color: '#e74c3c'}}>\n {urlError}\n </Text>\n </Flex>\n </Card>\n )}\n </Stack>\n\n {watermark.imageUrl && (\n <Stack space={2}>\n <Card padding={3} tone=\"transparent\" border radius={2}>\n <Flex\n align=\"center\"\n justify=\"space-between\"\n gap={3}\n style={{flexWrap: 'wrap', alignItems: 'flex-start'}}\n >\n <Stack space={2} style={{minWidth: 240, flex: 1}}>\n <Text size={1} weight=\"medium\">\n Positioning mode\n </Text>\n <Text size={0} muted>\n Choose between dragging on the canvas or manually editing the Mux{' '}\n <code>overlay_settings</code> fields (as in{' '}\n <a\n href=\"https://www.mux.com/docs/guides/add-watermarks-to-your-videos\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n the docs\n </a>\n ).\n </Text>\n </Stack>\n <Flex gap={2} style={{flexWrap: 'wrap'}}>\n <Button\n text=\"Canvas\"\n mode={mode === 'canvas' ? 'default' : 'ghost'}\n onClick={() => {\n setMode('canvas')\n onChange({...watermark, enabled: true, overlay_settings: undefined})\n }}\n />\n <Button\n text=\"Manual\"\n mode={mode === 'manual' ? 'default' : 'ghost'}\n onClick={() => {\n setMode('manual')\n const overlay = convertWatermarkToMuxOverlay({...watermark, enabled: true})\n updateOverlaySettings(overlay ?? {})\n }}\n />\n </Flex>\n </Flex>\n </Card>\n\n {mode === 'manual' && (\n <Card padding={3} tone=\"transparent\" border radius={2}>\n <Stack space={3}>\n <Text size={1} weight=\"medium\">\n Mux overlay_settings\n </Text>\n <Grid columns={[1, 2]} gap={3} style={{width: '100%'}}>\n <Stack space={2} style={{minWidth: 0}}>\n <Text size={0} muted>\n horizontal_align\n </Text>\n <select\n value={watermark.overlay_settings?.horizontal_align || 'right'}\n onChange={(e) =>\n updateOverlaySettings({\n horizontal_align: (e.target.value ||\n 'right') as MuxOverlaySettings['horizontal_align'],\n })\n }\n style={{\n width: '100%',\n padding: '8px 10px',\n border: '1px solid #ccc',\n borderRadius: 4,\n }}\n >\n <option value=\"left\">left</option>\n <option value=\"center\">center</option>\n <option value=\"right\">right</option>\n </select>\n </Stack>\n <Stack space={2} style={{minWidth: 0}}>\n <Text size={0} muted>\n horizontal_margin (e.g. 2% or 40px)\n </Text>\n <TextInput\n value={watermark.overlay_settings?.horizontal_margin || '2%'}\n onChange={(e) =>\n updateOverlaySettings({horizontal_margin: e.currentTarget.value})\n }\n />\n </Stack>\n <Stack space={2} style={{minWidth: 0}}>\n <Text size={0} muted>\n vertical_align\n </Text>\n <select\n value={watermark.overlay_settings?.vertical_align || 'bottom'}\n onChange={(e) =>\n updateOverlaySettings({\n vertical_align: (e.target.value ||\n 'bottom') as MuxOverlaySettings['vertical_align'],\n })\n }\n style={{\n width: '100%',\n padding: '8px 10px',\n border: '1px solid #ccc',\n borderRadius: 4,\n }}\n >\n <option value=\"top\">top</option>\n <option value=\"middle\">middle</option>\n <option value=\"bottom\">bottom</option>\n </select>\n </Stack>\n <Stack space={2} style={{minWidth: 0}}>\n <Text size={0} muted>\n vertical_margin (e.g. 2% or 40px)\n </Text>\n <TextInput\n value={watermark.overlay_settings?.vertical_margin || '2%'}\n onChange={(e) =>\n updateOverlaySettings({vertical_margin: e.currentTarget.value})\n }\n />\n </Stack>\n <Stack space={2} style={{minWidth: 0}}>\n <Text size={0} muted>\n width (e.g. 25% or 80px)\n </Text>\n <TextInput\n value={watermark.overlay_settings?.width || `${watermark.size ?? 20}%`}\n onChange={(e) => updateOverlaySettings({width: e.currentTarget.value})}\n />\n </Stack>\n <Stack space={2} style={{minWidth: 0}}>\n <Text size={0} muted>\n opacity (e.g. 90%)\n </Text>\n <TextInput\n value={\n watermark.overlay_settings?.opacity ||\n `${Math.round((watermark.opacity ?? 0.7) * 100)}%`\n }\n onChange={(e) => updateOverlaySettings({opacity: e.currentTarget.value})}\n />\n </Stack>\n </Grid>\n <Text size={0} muted>\n Margins and width accept either percentages or pixels, per the Mux guide.\n </Text>\n </Stack>\n </Card>\n )}\n\n {mode === 'canvas' && (\n <>\n <Box>\n <Text size={1} weight=\"medium\">\n {/* oxlint-disable-next-line react/react-compiler */}\n {(() => {\n const sizePct = watermark.size || 20\n const contentW = getVideoContentBox().width\n if (!contentW) return `Size: ${sizePct}%`\n const px = Math.max(1, Math.round((sizePct / 100) * contentW))\n return `Size: ${px}px`\n })()}\n </Text>\n <RangeInput\n type=\"range\"\n // oxlint-disable-next-line react/react-compiler\n value={(() => {\n const sizePct = watermark.size || 20\n const contentW = getVideoContentBox().width\n if (!contentW) return sizePct\n return Math.max(1, Math.round((sizePct / 100) * contentW))\n })()}\n // oxlint-disable-next-line react/react-compiler\n min={(() => {\n const contentW = getVideoContentBox().width\n if (!contentW) return 5\n return Math.max(1, Math.round(contentW * 0.05))\n })()}\n // oxlint-disable-next-line react/react-compiler\n max={(() => {\n const contentW = getVideoContentBox().width\n if (!contentW) return 50\n return Math.max(1, Math.round(contentW * 0.5))\n })()}\n step={1}\n onChange={(e) => {\n const raw = Number(e.target.value)\n const contentW = getVideoContentBox().width\n const nextPct = contentW ? (raw / contentW) * 100 : raw\n const clampedPct = Math.max(5, Math.min(50, nextPct))\n onChange({\n ...watermark,\n size: clampedPct,\n })\n }}\n />\n </Box>\n\n <Box>\n <Text size={1} weight=\"medium\">\n Opacity: {Math.round((watermark.opacity ?? 0.7) * 100)}%\n </Text>\n <RangeInput\n type=\"range\"\n value={watermark.opacity ?? 0.7}\n min={0}\n max={1}\n step={0.05}\n onChange={(e) =>\n onChange({\n ...watermark,\n opacity: Number(e.target.value),\n })\n }\n />\n </Box>\n </>\n )}\n\n <Card padding={2} tone=\"transparent\" border radius={2}>\n <Text size={0} muted>\n {mode === 'manual'\n ? 'Manual mode: edit the overlay_settings fields above'\n : '💡 Drag the watermark on the preview to position it'}\n </Text>\n </Card>\n </Stack>\n )}\n </Stack>\n )\n}\n","import {TranslateIcon} from '@sanity/icons/Translate'\nimport {Autocomplete, Box, Card, Checkbox, Flex, Stack, Text} from '@sanity/ui'\nimport {uuid} from '@sanity/uuid'\nimport LanguagesList from 'iso-639-1'\nimport {type Dispatch} from 'react'\nimport {FormField} from 'sanity'\n\nimport {type PluginConfig, SUPPORTED_MUX_LANGUAGES, type UploadTextTrack} from '../util/types'\n\nconst ALL_LANGUAGE_CODES = LanguagesList.getAllCodes().map((code) => ({\n value: code,\n label: LanguagesList.getNativeName(code),\n}))\n\nconst SUBTITLE_LANGUAGES: Record<\n Extract<UploadTextTrack, {language_code: any}>['type'],\n {value: string; label: string}[]\n> = {\n autogenerated: SUPPORTED_MUX_LANGUAGES.map((lang) => ({\n value: lang.code,\n label: lang.label,\n })),\n subtitles: ALL_LANGUAGE_CODES,\n captions: ALL_LANGUAGE_CODES,\n}\n\ntype TrackSubAction =\n | {subAction: 'add'; value: Partial<UploadTextTrack>}\n | {subAction: 'update'; value: Partial<UploadTextTrack>}\n | {subAction: 'delete'}\n\nexport type TrackAction = {action: 'track'; id: string} & TrackSubAction\n\nexport default function TextTracksEditor({\n tracks,\n dispatch,\n defaultLang,\n}: {\n /**\n * Although the schema for tracks is an array, which we'll eventually support to allow uploading\n * multiple custom subtitles, for now we only support a single auto-generated track.\n */\n tracks: (Partial<UploadTextTrack> & {_id: string})[]\n dispatch: Dispatch<TrackAction>\n defaultLang: PluginConfig['defaultAutogeneratedSubtitleLang']\n}) {\n const track = tracks[0]\n return (\n <FormField title=\"Auto-generated subtitle or caption\" path={[]}>\n <Stack space={2}>\n <Flex align=\"center\">\n <Checkbox\n id=\"include-autogenerated-track\"\n style={{display: 'block'}}\n checked={!!track?.language_code}\n onChange={() => {\n if (track) {\n dispatch({action: 'track', id: track._id, subAction: 'delete'})\n } else {\n dispatch({\n action: 'track',\n id: uuid(),\n subAction: 'add',\n value: {\n type: 'autogenerated',\n name: defaultLang || undefined,\n language_code: defaultLang || undefined,\n },\n })\n }\n }}\n />\n <Box flex={1} paddingLeft={3}>\n <Text>\n <label htmlFor=\"checkbox\">Generate captions</label>\n </Text>\n </Box>\n </Flex>\n {track && (\n <Autocomplete\n id={`text-tract-editor--language`}\n value={track.language_code}\n onChange={(newValue) =>\n dispatch({\n action: 'track',\n id: track._id,\n subAction: 'update',\n value: {\n language_code: newValue,\n name: LanguagesList.getNativeName(newValue),\n },\n })\n }\n options={SUBTITLE_LANGUAGES[track.type!]}\n icon={TranslateIcon}\n placeholder=\"Select language\"\n filterOption={(query, option) =>\n option.label.toLowerCase().indexOf(query.toLowerCase()) > -1 ||\n option.value.toLowerCase().indexOf(query.toLowerCase()) > -1\n }\n openButton\n renderValue={(value) =>\n SUBTITLE_LANGUAGES[track.type!].find((l) => l.value === value)?.label || value\n }\n renderOption={(option) => (\n <Card data-as=\"button\" padding={3} radius={2} tone=\"inherit\">\n <Text size={2} textOverflow=\"ellipsis\">\n {option.label} ({option.value})\n </Text>\n </Card>\n )}\n />\n )}\n </Stack>\n </FormField>\n )\n}\n","import {Checkbox, Flex, Grid, Text} from '@sanity/ui'\nimport {type ActionDispatch, type CSSProperties, type ReactNode, useState} from 'react'\n\nimport {type UploadConfigurationStateAction} from '../UploadConfiguration'\n\nexport default function PlaybackPolicyOption({\n id,\n checked,\n optionName,\n description,\n dispatch,\n action,\n disabled,\n}: {\n id: string\n checked: boolean\n optionName: string\n description: string | ReactNode\n dispatch: ActionDispatch<[action: UploadConfigurationStateAction]>\n action?: 'public_policy' | 'signed_policy' | 'drm_policy'\n disabled?: boolean\n}) {\n const [scale, setScale] = useState(1)\n\n const boxStyle: CSSProperties = {\n outline: '0.01rem solid grey',\n transform: `scale(${scale})`,\n transition: 'transform 0.1s ease-in-out',\n cursor: disabled ? 'not-allowed' : 'pointer',\n borderRadius: '0.25rem',\n }\n\n const triggerAnimation = () => {\n setScale(0.98)\n setTimeout(() => {\n setScale(1)\n }, 100)\n }\n\n const handleBoxClick = () => {\n if (!action) return\n triggerAnimation()\n dispatch({\n action,\n value: !checked,\n })\n }\n\n const descriptionJsx =\n typeof description === 'string' ? (\n <Text size={2} muted>\n {description}\n </Text>\n ) : (\n description\n )\n return (\n <label>\n <Flex gap={3} padding={3} style={boxStyle}>\n <Checkbox\n id={id}\n required\n checked={checked}\n onChange={handleBoxClick}\n disabled={disabled}\n />\n <Grid gap={3}>\n <Text size={3} weight=\"bold\">\n {optionName}\n </Text>\n {descriptionJsx}\n </Grid>\n </Flex>\n </label>\n )\n}\n","import {WarningFilledIcon} from '@sanity/icons/WarningFilled'\nimport {Box, Flex, Text} from '@sanity/ui'\nimport {type CSSProperties} from 'react'\n\nexport default function PlaybackPolicyWarning() {\n const textStyle: CSSProperties = {\n color: '#13141A',\n fontWeight: 500,\n }\n\n const boxStyle: CSSProperties = {\n outline: '0.01rem solid grey',\n backgroundColor: '#979cb0',\n borderRadius: '0.5rem',\n width: 'max-content',\n color: '#13141A',\n }\n\n return (\n <Box padding={2} style={boxStyle}>\n <Flex align=\"center\" gap={2}>\n <WarningFilledIcon />\n <Text size={1} style={textStyle}>\n Please select at least one Playback Policy\n </Text>\n </Flex>\n </Box>\n )\n}\n","import {Code, Grid, Text} from '@sanity/ui'\nimport {type ActionDispatch} from 'react'\n\nimport {type Secrets, type UploadConfig} from '../../util/types'\nimport {type UploadConfigurationStateAction} from '../UploadConfiguration'\nimport PlaybackPolicyOption from './PlaybackPolicyOption'\nimport PlaybackPolicyWarning from './PlaybackPolicyWarning'\n\nexport default function PlaybackPolicy({\n id,\n config,\n secrets,\n dispatch,\n}: {\n id: string\n config: UploadConfig\n secrets: Secrets\n dispatch: ActionDispatch<[action: UploadConfigurationStateAction]>\n}) {\n const noPolicySelected = !(config.public_policy || config.signed_policy || config.drm_policy)\n const drmPolicyDisabled = !secrets.drmConfigId\n return (\n <Grid gap={3}>\n <Text weight=\"bold\">Advanced Playback Policies</Text>\n <PlaybackPolicyOption\n id={`${id}--public`}\n checked={config.public_policy}\n optionName=\"Public\"\n description={\n <>\n <Text size={2} muted>\n Playback IDs are accessible by constructing an HLS URL like\n </Text>\n <Code>{'https://stream.mux.com/{PLAYBACK_ID}'}</Code>\n </>\n }\n dispatch={dispatch}\n action=\"public_policy\"\n />\n {secrets.enableSignedUrls && (\n <PlaybackPolicyOption\n id={`${id}--signed`}\n checked={config.signed_policy}\n optionName=\"Signed\"\n description={\n <>\n <Text size={2} muted>\n Playback IDs should be used with tokens\n </Text>\n <Code>{'https://stream.mux.com/{PLAYBACK_ID}?token={TOKEN}'}</Code>\n <Text size={2} muted>\n See{' '}\n <a\n href=\"https://www.mux.com/docs/guides/secure-video-playback\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Secure video playback\n </a>{' '}\n for details about creating tokens.\n </Text>\n </>\n }\n // See Secure video playback for details about creating tokens.\"\n dispatch={dispatch}\n action=\"signed_policy\"\n />\n )}\n {drmPolicyDisabled ? (\n <PlaybackPolicyOption\n id={`${id}--drm`}\n checked={false}\n optionName=\"DRM - Disabled\"\n description={\n <>\n <Text size={2} muted>\n To enable DRM add your DRM Configuration Id to your plugin configuration in the API\n Credentials view.{' '}\n <a\n href=\"https://www.mux.com/support/human\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Contact us\n </a>{' '}\n to get started using DRM.\n </Text>\n </>\n }\n dispatch={dispatch}\n disabled\n />\n ) : (\n <PlaybackPolicyOption\n id={`${id}--drm`}\n checked={config.drm_policy}\n optionName=\"DRM\"\n description={\n <>\n <Text size={2} muted>\n Playback IDs should be used with tokens as with Signed playback, but require extra\n configuration.\n </Text>\n <Code>{'https://stream.mux.com/{PLAYBACK_ID}?token={TOKEN}'}</Code>\n <Text size={2} muted>\n See{' '}\n <a\n href=\"https://www.mux.com/docs/guides/protect-videos-with-drm#play-drm-protected-videos\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Protect videos with DRM\n </a>{' '}\n for details about configuring your player for DRM playback and{' '}\n <a\n href=\"https://www.mux.com/docs/guides/secure-video-playback\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Secure video playback\n </a>{' '}\n for details about creating tokens.\n </Text>\n </>\n }\n dispatch={dispatch}\n action=\"drm_policy\"\n />\n )}\n {noPolicySelected && <PlaybackPolicyWarning />}\n </Grid>\n )\n}\n","import {Flex, Radio, Text} from '@sanity/ui'\nimport {type ActionDispatch} from 'react'\nimport {FormField} from 'sanity'\n\nimport {type UploadConfig} from '../../util/types'\nimport {type UploadConfigurationStateAction} from '../UploadConfiguration'\n\nexport const RESOLUTION_TIERS = [\n {value: '1080p', label: '1080p'},\n {value: '1440p', label: '1440p (2k)'},\n {value: '2160p', label: '2160p (4k)'},\n] as const satisfies {value: UploadConfig['max_resolution_tier']; label: string}[]\n\nexport const ResolutionTierSelector = ({\n id,\n config,\n dispatch,\n maxSupportedResolution,\n}: {\n id: string\n config: UploadConfig\n dispatch: ActionDispatch<[action: UploadConfigurationStateAction]>\n maxSupportedResolution: number\n}) => {\n return (\n <FormField\n path={[]}\n title=\"Resolution Tier\"\n description={\n <>\n The maximum{' '}\n <a\n href=\"https://docs.mux.com/api-reference#video/operation/create-direct-upload\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n resolution_tier\n </a>{' '}\n your asset is encoded, stored, and streamed at.\n </>\n }\n >\n <Flex gap={3} wrap={'wrap'}>\n {RESOLUTION_TIERS.map(({value, label}, index) => {\n const inputId = `${id}--type-${value}`\n\n if (index > maxSupportedResolution) return null\n\n return (\n <Flex key={value} align=\"center\" gap={2}>\n <Radio\n checked={config.max_resolution_tier === value}\n name=\"asset-resolutiontier\"\n onChange={(e) =>\n dispatch({\n action: 'max_resolution_tier',\n value: e.currentTarget.value as UploadConfig['max_resolution_tier'],\n })\n }\n value={value}\n id={inputId}\n />\n <Text as=\"label\" htmlFor={inputId}>\n {label}\n </Text>\n </Flex>\n )\n })}\n </Flex>\n </FormField>\n )\n}\n","import {Checkbox, Flex, Label, Radio, Stack, Text} from '@sanity/ui'\nimport {type ActionDispatch, useMemo, useState} from 'react'\nimport {FormField} from 'sanity'\n\nimport {type StaticRenditionResolution, type UploadConfig} from '../../util/types'\nimport {type UploadConfigurationStateAction} from '../UploadConfiguration'\n\nconst ADVANCED_RESOLUTIONS: {value: StaticRenditionResolution; label: string}[] = [\n {value: '270p', label: '270p'},\n {value: '360p', label: '360p'},\n {value: '480p', label: '480p'},\n {value: '540p', label: '540p'},\n {value: '720p', label: '720p'},\n {value: '1080p', label: '1080p'},\n {value: '1440p', label: '1440p'},\n {value: '2160p', label: '2160p'},\n]\n\nexport const StaticRenditionSelector = ({\n id,\n config,\n dispatch,\n}: {\n id: string\n config: UploadConfig\n dispatch: ActionDispatch<[action: UploadConfigurationStateAction]>\n}) => {\n // Determine if user is in advanced mode based on selected renditions\n const isAdvancedMode = useMemo(() => {\n const specificResolutions = config.static_renditions.filter(\n (r) => r !== 'highest' && r !== 'audio-only',\n )\n return specificResolutions.length > 0\n }, [config.static_renditions])\n\n const [renditionMode, setRenditionMode] = useState<'standard' | 'advanced'>(\n isAdvancedMode ? 'advanced' : 'standard',\n )\n\n // Helper to toggle a rendition\n const toggleRendition = (rendition: StaticRenditionResolution) => {\n const current = config.static_renditions\n const hasRendition = current.includes(rendition)\n\n if (hasRendition) {\n dispatch({\n action: 'static_renditions',\n value: current.filter((r) => r !== rendition),\n })\n } else {\n dispatch({\n action: 'static_renditions',\n value: [...current, rendition],\n })\n }\n }\n\n // When switching modes, clear renditions that don't apply\n const handleModeChange = (mode: 'standard' | 'advanced') => {\n setRenditionMode(mode)\n if (mode === 'standard') {\n // Remove specific resolutions, keep only highest and audio-only\n dispatch({\n action: 'static_renditions',\n value: config.static_renditions.filter((r) => r === 'highest' || r === 'audio-only'),\n })\n } else {\n // Remove highest, keep specific resolutions and audio-only\n dispatch({\n action: 'static_renditions',\n value: config.static_renditions.filter((r) => r !== 'highest'),\n })\n }\n }\n return (\n <Stack space={3}>\n <FormField\n path={[]}\n title=\"Static Renditions\"\n description=\"Generate downloadable MP4 or M4A files. Note: Mux will not upscale to produce MP4 renditions - renditions that would cause upscaling are skipped.\"\n >\n <Stack space={3}>\n {/* Mode Selector */}\n <Flex gap={3}>\n <Flex align=\"center\" gap={2}>\n <Radio\n checked={renditionMode === 'standard'}\n name=\"rendition-mode\"\n onChange={() => handleModeChange('standard')}\n value=\"standard\"\n id={`${id}--mode-standard`}\n />\n <Text as=\"label\" htmlFor={`${id}--mode-standard`}>\n Standard\n </Text>\n </Flex>\n <Flex align=\"center\" gap={2}>\n <Radio\n checked={renditionMode === 'advanced'}\n name=\"rendition-mode\"\n onChange={() => handleModeChange('advanced')}\n value=\"advanced\"\n id={`${id}--mode-advanced`}\n />\n <Text as=\"label\" htmlFor={`${id}--mode-advanced`}>\n Advanced\n </Text>\n </Flex>\n </Flex>\n\n {/* Standard Mode Options */}\n {renditionMode === 'standard' && (\n <Stack space={2}>\n <Flex align=\"center\" gap={2} padding={[0, 2]}>\n <Checkbox\n id={`${id}--highest`}\n style={{display: 'block'}}\n checked={config.static_renditions.includes('highest')}\n onChange={() => toggleRendition('highest')}\n />\n <Text as=\"label\" htmlFor={`${id}--highest`}>\n Highest Resolution (up to 4K)\n </Text>\n </Flex>\n <Flex align=\"center\" gap={2} padding={[0, 2]}>\n <Checkbox\n id={`${id}--audio-only-standard`}\n style={{display: 'block'}}\n checked={config.static_renditions.includes('audio-only')}\n onChange={() => toggleRendition('audio-only')}\n />\n <Text as=\"label\" htmlFor={`${id}--audio-only-standard`}>\n Audio Only (M4A)\n </Text>\n </Flex>\n </Stack>\n )}\n\n {/* Advanced Mode Options */}\n {renditionMode === 'advanced' && (\n <Stack space={2}>\n <Label size={1} muted>\n Select specific resolutions:\n </Label>\n <Flex gap={2} wrap=\"wrap\">\n {ADVANCED_RESOLUTIONS.map(({value, label}) => {\n const inputId = `${id}--resolution-${value}`\n return (\n <Flex key={value} align=\"center\" gap={2}>\n <Checkbox\n id={inputId}\n style={{display: 'block'}}\n checked={config.static_renditions.includes(value)}\n onChange={() => toggleRendition(value)}\n />\n <Text as=\"label\" htmlFor={inputId} size={1}>\n {label}\n </Text>\n </Flex>\n )\n })}\n </Flex>\n <Flex align=\"center\" gap={2} padding={[2, 2, 0, 2]}>\n <Checkbox\n id={`${id}--audio-only-advanced`}\n style={{display: 'block'}}\n checked={config.static_renditions.includes('audio-only')}\n onChange={() => toggleRendition('audio-only')}\n />\n <Text as=\"label\" htmlFor={`${id}--audio-only-advanced`}>\n Audio Only (M4A)\n </Text>\n </Flex>\n </Stack>\n )}\n </Stack>\n </FormField>\n </Stack>\n )\n}\n","import {DocumentVideoIcon} from '@sanity/icons/DocumentVideo'\nimport {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {UploadIcon} from '@sanity/icons/Upload'\nimport {Box, Button, Card, Dialog, Flex, Label, Radio, Stack, Text} from '@sanity/ui'\nimport {uuid} from '@sanity/uuid'\nimport LanguagesList from 'iso-639-1'\nimport {memo, useEffect, useId, useReducer, useRef, useState} from 'react'\nimport {FormField} from 'sanity'\n\nimport {useFetchFileSize} from '../hooks/useFetchFileSize'\nimport {useMediaMetadata, type VideoAssetMetadata} from '../hooks/useMediaMetadata'\nimport {convertWatermarkToMuxOverlay} from '../util/convertWatermarkToMux'\nimport formatBytes from '../util/formatBytes'\nimport {formatSeconds} from '../util/formatSeconds'\nimport {\n type AutogeneratedTextTrack,\n type CustomTextTrack,\n isAutogeneratedTrack,\n isCustomTextTrack,\n type MuxNewAssetSettings,\n type PluginConfig,\n type Secrets,\n type StaticRenditionResolution,\n type SupportedMuxLanguage,\n type UploadConfig,\n type UploadTextTrack,\n type WatermarkConfig,\n} from '../util/types'\nimport DraggableWatermark, {WatermarkControls} from './DraggableWatermark'\nimport TextTracksEditor, {type TrackAction} from './TextTracksEditor'\nimport PlaybackPolicy from './uploadConfiguration/PlaybackPolicy'\nimport {\n RESOLUTION_TIERS,\n ResolutionTierSelector,\n} from './uploadConfiguration/ResolutionTierSelector'\nimport {StaticRenditionSelector} from './uploadConfiguration/StaticRenditionSelector'\nimport type {StagedUpload} from './Uploader'\n\nexport type UploadConfigurationStateAction =\n | {action: 'video_quality'; value: UploadConfig['video_quality']}\n | {action: 'max_resolution_tier'; value: UploadConfig['max_resolution_tier']}\n | {action: 'static_renditions'; value: UploadConfig['static_renditions']}\n | {action: 'normalize_audio'; value: UploadConfig['normalize_audio']}\n | {action: 'signed_policy'; value: UploadConfig['signed_policy']}\n | {action: 'public_policy'; value: UploadConfig['public_policy']}\n | {action: 'drm_policy'; value: UploadConfig['drm_policy']}\n | {action: 'watermark'; value: WatermarkConfig}\n | TrackAction\n\nconst VIDEO_QUALITY_LEVELS = [\n {value: 'basic', label: 'Basic'},\n {value: 'plus', label: 'Plus'},\n {value: 'premium', label: 'Premium'},\n] as const satisfies {value: UploadConfig['video_quality']; label: string}[]\n\n/**\n * Sanitizes static renditions configuration to ensure 'highest' is not mixed with specific resolutions.\n * If both are present, only 'highest' (and 'audio-only' if present) will be kept.\n */\nfunction sanitizeStaticRenditions(\n renditions: StaticRenditionResolution[],\n): StaticRenditionResolution[] {\n const hasHighest = renditions.includes('highest')\n const hasSpecificResolutions = renditions.some((r) => r !== 'highest' && r !== 'audio-only')\n\n if (hasHighest && hasSpecificResolutions) {\n return renditions.filter((r) => r === 'highest' || r === 'audio-only')\n }\n\n return renditions\n}\n\n/**\n * The modal for configuring a staged upload. Handles triggering of the asset\n * upload, even if no modal needs to be shown.\n *\n * @returns\n */\nexport default function UploadConfiguration({\n stagedUpload,\n secrets,\n pluginConfig,\n startUpload,\n onClose,\n}: {\n stagedUpload: StagedUpload\n secrets: Secrets\n pluginConfig: PluginConfig\n startUpload: (settings: MuxNewAssetSettings, watermark: WatermarkConfig | undefined) => void\n onClose: () => void\n}) {\n const id = useId()\n const [watermarkValidationError, setWatermarkValidationError] = useState<string | null>(null)\n const watermarkPreviewContainerRef = useRef<HTMLDivElement>(null)\n const watermarkPreviewVideoRef = useRef<HTMLVideoElement>(null)\n // oxlint-disable-next-line react/react-compiler\n const autoTextTracks = useRef<NonNullable<UploadConfig['text_tracks']>>(\n pluginConfig.video_quality === 'plus' && pluginConfig.defaultAutogeneratedSubtitleLang\n ? [\n {\n _id: uuid(),\n type: 'autogenerated',\n language_code: pluginConfig.defaultAutogeneratedSubtitleLang,\n name: LanguagesList.getNativeName(pluginConfig.defaultAutogeneratedSubtitleLang),\n } satisfies AutogeneratedTextTrack,\n ]\n : [],\n ).current\n\n const [config, dispatch] = useReducer(\n // oxlint-disable-next-line react/react-compiler\n (prev: UploadConfig, action: UploadConfigurationStateAction) => {\n switch (action.action) {\n case 'video_quality':\n // If video quality level switches to basic, remove plus-only features\n if (action.value === 'basic') {\n return Object.assign({}, prev, {\n video_quality: action.value,\n static_renditions: [],\n max_resolution_tier: '1080p',\n text_tracks: prev.text_tracks?.filter(({type}) => type !== 'autogenerated'),\n public_policy: true,\n signed_policy: false,\n drm_policy: false,\n })\n // If video quality level switches to plus, add back in default plus features\n }\n return Object.assign({}, prev, {\n video_quality: action.value,\n static_renditions: sanitizeStaticRenditions(pluginConfig.static_renditions || []),\n max_resolution_tier: pluginConfig.max_resolution_tier,\n text_tracks: [...autoTextTracks, ...(prev.text_tracks || [])],\n })\n\n case 'static_renditions':\n case 'max_resolution_tier':\n case 'normalize_audio':\n case 'signed_policy':\n return Object.assign({}, prev, {[action.action]: action.value})\n case 'public_policy':\n return Object.assign({}, prev, {[action.action]: action.value})\n case 'drm_policy':\n return Object.assign({}, prev, {[action.action]: action.value})\n case 'watermark':\n return Object.assign({}, prev, {watermark: action.value})\n // Updating individual tracks\n case 'track': {\n const text_tracks = [...prev.text_tracks]\n const target_track_i = text_tracks.findIndex(({_id}) => _id === action.id)\n switch (action.subAction) {\n case 'add':\n // Exit early if track already exists\n if (target_track_i !== -1) break\n text_tracks.push({\n _id: action.id,\n ...action.value,\n } as AutogeneratedTextTrack)\n break\n case 'update':\n if (target_track_i === -1) break\n text_tracks[target_track_i] = {\n ...text_tracks[target_track_i],\n ...action.value,\n } as UploadTextTrack\n break\n case 'delete':\n if (target_track_i === -1) break\n text_tracks.splice(target_track_i, 1)\n break\n }\n return Object.assign({}, prev, {text_tracks})\n }\n default:\n return prev\n }\n },\n {\n video_quality: pluginConfig.video_quality,\n max_resolution_tier: pluginConfig.max_resolution_tier,\n static_renditions: sanitizeStaticRenditions(pluginConfig.static_renditions || []),\n signed_policy: secrets.enableSignedUrls && pluginConfig.defaultSigned,\n public_policy: pluginConfig.defaultPublic,\n drm_policy: pluginConfig.defaultDrm && !!secrets.drmConfigId,\n normalize_audio: pluginConfig.normalize_audio,\n text_tracks: autoTextTracks,\n } as UploadConfig,\n )\n\n // Video validations\n const [validationError, setValidationError] = useState<string | null>(null)\n const MAX_FILE_SIZE = pluginConfig.maxAssetFileSize\n const MAX_DURATION_SECONDS = pluginConfig.maxAssetDuration\n\n const {fileSize, isLoadingFileSize, canSkipFileSizeValidation} = useFetchFileSize(\n stagedUpload,\n MAX_FILE_SIZE,\n )\n const {videoAssetMetadata, setVideoAssetMetadata, isLoadingMetadata} =\n useMediaMetadata(stagedUpload)\n\n useEffect(() => {\n if (fileSize) {\n setVideoAssetMetadata((old) => ({...old, size: fileSize}))\n }\n }, [fileSize, setVideoAssetMetadata])\n\n useEffect(() => {\n const validateDuration = (duration: number) => {\n if (MAX_DURATION_SECONDS && duration > MAX_DURATION_SECONDS) {\n setValidationError(\n `Video duration (${formatSeconds(duration)}) exceeds maximum allowed duration of ${formatSeconds(MAX_DURATION_SECONDS)}`,\n )\n return false\n }\n return true\n }\n\n const validateFileSize = (size: number): boolean => {\n if (MAX_FILE_SIZE === undefined || size <= MAX_FILE_SIZE) {\n return true\n }\n\n setValidationError(\n `File size (${formatBytes(size)}) exceeds maximum allowed size of ${formatBytes(MAX_FILE_SIZE)}`,\n )\n return false\n }\n\n const validateDrmAvailability = (isAudioOnly: boolean) => {\n if (config.drm_policy && isAudioOnly) {\n setValidationError('Audio-only asset cannot be DRM protected')\n return false\n }\n return true\n }\n\n let valid = true\n if (videoAssetMetadata?.size) {\n valid = valid && (canSkipFileSizeValidation || validateFileSize(videoAssetMetadata.size))\n }\n if (videoAssetMetadata?.duration) {\n valid = valid && validateDuration(videoAssetMetadata.duration)\n }\n if (videoAssetMetadata?.isAudioOnly != undefined) {\n valid = valid && validateDrmAvailability(videoAssetMetadata.isAudioOnly)\n }\n if (valid) {\n // oxlint-disable-next-line react/react-compiler\n setValidationError(null)\n }\n }, [\n MAX_FILE_SIZE,\n MAX_DURATION_SECONDS,\n canSkipFileSizeValidation,\n videoAssetMetadata?.duration,\n videoAssetMetadata?.size,\n videoAssetMetadata?.height,\n videoAssetMetadata?.width,\n videoAssetMetadata,\n config.drm_policy,\n validationError,\n ])\n\n // If user-provided config is disabled, begin the upload immediately with\n // the developer-specified values from the schema or config or defaults.\n // This can include auto-generated subtitles!\n const {disableTextTrackConfig, disableUploadConfig} = pluginConfig\n const skipConfig = disableTextTrackConfig && disableUploadConfig\n useEffect(() => {\n if (skipConfig) {\n const {settings, watermark} = formatUploadConfig(config, secrets, {\n videoAspectRatio: videoAssetMetadata?.aspectRatio,\n })\n startUpload(settings, watermark)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n if (skipConfig) return null\n\n const basicConfig = config.video_quality !== 'plus' && config.video_quality !== 'premium'\n const playbackPolicySelected = config.public_policy || config.signed_policy || config.drm_policy\n const maxSupportedResolution = RESOLUTION_TIERS.findIndex(\n (rt) => rt.value === pluginConfig.max_resolution_tier,\n )\n return (\n <Dialog\n animate\n open\n id=\"upload-configuration\"\n zOffset={1000}\n width={1}\n header=\"Configure Mux Upload\"\n onClose={onClose}\n >\n <Stack padding={4} space={2}>\n {(validationError || watermarkValidationError) && (\n <Card padding={3} tone=\"critical\" radius={2} marginBottom={2}>\n <Flex gap={2} align=\"flex-start\">\n <ErrorOutlineIcon width={20} height={20} />\n <Stack space={2}>\n <Text size={1} weight=\"semibold\">\n Validation Error\n </Text>\n <Text size={1}>{validationError || watermarkValidationError}</Text>\n </Stack>\n </Flex>\n </Card>\n )}\n <Label size={3}>FILE TO UPLOAD</Label>\n <Card\n tone=\"transparent\"\n border\n padding={3}\n paddingY={4}\n style={{borderRadius: '0.1865rem'}}\n >\n <Flex gap={2}>\n <DocumentVideoIcon fontSize=\"2em\" />\n <Stack space={2}>\n <Text textOverflow=\"ellipsis\" as=\"h2\" size={3}>\n {stagedUpload.type === 'file' ? stagedUpload.files[0]!.name : stagedUpload.url}\n </Text>\n <Text as=\"p\" size={1} muted>\n {stagedUpload.type === 'file'\n ? `Direct File Upload (${formatBytes(stagedUpload.files[0]!.size)})`\n : (() => {\n if (videoAssetMetadata?.size) {\n return `File From URL (${formatBytes(videoAssetMetadata.size)})`\n }\n if (isLoadingFileSize) {\n return 'File From URL (Loading size...)'\n }\n return 'File From URL (Unknown size)'\n })()}\n </Text>\n {stagedUpload.type === 'file' && (\n <Stack space={1}>\n {isLoadingMetadata && (\n <Text as=\"p\" size={1} muted>\n Reading video metadata...\n </Text>\n )}\n {videoAssetMetadata?.duration && !validationError && (\n <Text as=\"p\" size={1} muted>\n Duration: {formatSeconds(videoAssetMetadata.duration)}\n </Text>\n )}\n </Stack>\n )}\n </Stack>\n </Flex>\n </Card>\n {!disableUploadConfig && (\n <Stack space={3} paddingBottom={2}>\n <FormField\n path={[]}\n title=\"Video Quality Level\"\n description={\n <>\n The video quality level informs the cost, quality, and available platform features\n for the asset.{' '}\n <a\n href=\"https://docs.mux.com/guides/use-encoding-tiers\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n See the Mux guide for more details.\n </a>\n </>\n }\n >\n <Flex gap={3}>\n {VIDEO_QUALITY_LEVELS.map(({value, label}) => {\n const inputId = `${id}--encodingtier-${value}`\n return (\n <Flex key={value} align=\"center\" gap={2}>\n <Radio\n checked={config.video_quality === value}\n name=\"asset-encodingtier\"\n onChange={(e) =>\n dispatch({\n action: 'video_quality' as const,\n value: e.currentTarget.value as UploadConfig['video_quality'],\n })\n }\n value={value}\n id={inputId}\n />\n <Text as=\"label\" htmlFor={inputId}>\n {label}\n </Text>\n </Flex>\n )\n })}\n </Flex>\n </FormField>\n\n {!basicConfig && (\n <>\n <FormField title=\"Additional Configuration\" path={[]}>\n <Stack space={3}>\n <PlaybackPolicy id={id} config={config} secrets={secrets} dispatch={dispatch} />\n {maxSupportedResolution > 0 && (\n <ResolutionTierSelector\n id={id}\n config={config}\n dispatch={dispatch}\n maxSupportedResolution={maxSupportedResolution}\n />\n )}\n <StaticRenditionSelector id={id} config={config} dispatch={dispatch} />\n {!disableTextTrackConfig && (\n <TextTracksEditor\n tracks={config.text_tracks}\n dispatch={dispatch}\n defaultLang={pluginConfig.defaultAutogeneratedSubtitleLang}\n />\n )}\n </Stack>\n </FormField>\n <WatermarkSection\n config={config}\n dispatch={dispatch}\n stagedUpload={stagedUpload}\n videoAssetMetadata={videoAssetMetadata}\n watermarkPreviewContainerRef={watermarkPreviewContainerRef}\n watermarkPreviewVideoRef={watermarkPreviewVideoRef}\n onValidationChange={setWatermarkValidationError}\n />\n </>\n )}\n </Stack>\n )}\n\n <Box marginTop={4}>\n <Button\n disabled={\n (!basicConfig && !playbackPolicySelected) ||\n validationError !== null ||\n isLoadingMetadata ||\n (isLoadingFileSize && !canSkipFileSizeValidation)\n }\n icon={UploadIcon}\n text=\"Upload\"\n tone=\"positive\"\n onClick={() => {\n if (!validationError) {\n const {settings, watermark} = formatUploadConfig(config, secrets, {\n videoAspectRatio: videoAssetMetadata?.aspectRatio,\n })\n startUpload(settings, watermark)\n }\n }}\n />\n </Box>\n </Stack>\n </Dialog>\n )\n}\n\nfunction setAdvancedPlaybackPolicy(\n config: UploadConfig,\n secrets: Secrets,\n): MuxNewAssetSettings['advanced_playback_policies'] {\n const advanced_playback_policies: MuxNewAssetSettings['advanced_playback_policies'] = []\n if (config.public_policy) {\n advanced_playback_policies.push({policy: 'public'})\n }\n if (config.signed_policy) {\n advanced_playback_policies.push({policy: 'signed'})\n }\n if (config.drm_policy) {\n if (secrets.drmConfigId)\n advanced_playback_policies.push({\n policy: 'drm',\n drm_configuration_id: secrets.drmConfigId ?? undefined,\n })\n else {\n console.error('Selected DRM Policy but missing DRM Configuration Id')\n }\n }\n return advanced_playback_policies\n}\n\nfunction formatUploadConfig(\n config: UploadConfig,\n secrets: Secrets,\n options?: {videoAspectRatio?: number | null},\n): {\n settings: MuxNewAssetSettings\n watermark?: WatermarkConfig\n} {\n const generated_subtitles = config.text_tracks\n .filter<AutogeneratedTextTrack>(isAutogeneratedTrack)\n .map<{name: string; language_code: SupportedMuxLanguage}>((track) => ({\n name: track.name,\n language_code: track.language_code,\n }))\n\n const inputs: NonNullable<MuxNewAssetSettings['input']> = [\n {\n type: 'video',\n generated_subtitles: generated_subtitles.length > 0 ? generated_subtitles : undefined,\n },\n ...config.text_tracks.filter<CustomTextTrack>(isCustomTextTrack).reduce(\n (acc, track) => {\n if (track.language_code && track.file && track.name) {\n acc.push({\n url: track.file.contents,\n type: 'text',\n text_type: track.type === 'subtitles' ? 'subtitles' : undefined,\n language_code: track.language_code,\n name: track.name,\n closed_captions: track.type === 'captions',\n })\n }\n return acc\n },\n [] as NonNullable<MuxNewAssetSettings['input']>,\n ),\n ]\n\n if (config.watermark?.imageUrl) {\n const watermarkForMux: WatermarkConfig = {...config.watermark, enabled: true}\n const overlaySettings = convertWatermarkToMuxOverlay(watermarkForMux, {\n videoAspectRatio: options?.videoAspectRatio ?? undefined,\n units: 'px',\n })\n if (overlaySettings) {\n inputs.push({\n url: config.watermark.imageUrl,\n overlay_settings: overlaySettings,\n })\n }\n }\n\n return {\n settings: {\n input: inputs,\n static_renditions:\n config.static_renditions.length > 0\n ? config.static_renditions.map((resolution) => ({resolution}))\n : undefined,\n advanced_playback_policies: setAdvancedPlaybackPolicy(config, secrets),\n max_resolution_tier: config.max_resolution_tier,\n video_quality: config.video_quality,\n normalize_audio: config.normalize_audio,\n },\n watermark: config.watermark?.imageUrl ? {...config.watermark, enabled: true} : undefined,\n }\n}\n\nfunction WatermarkSection({\n config,\n dispatch,\n stagedUpload,\n videoAssetMetadata,\n watermarkPreviewContainerRef,\n watermarkPreviewVideoRef,\n onValidationChange,\n}: {\n config: UploadConfig\n dispatch: (action: UploadConfigurationStateAction) => void\n stagedUpload: StagedUpload\n videoAssetMetadata: VideoAssetMetadata | null\n watermarkPreviewContainerRef: React.RefObject<HTMLDivElement | null>\n watermarkPreviewVideoRef: React.RefObject<HTMLVideoElement | null>\n onValidationChange: (error: string | null) => void\n}) {\n if (videoAssetMetadata?.isAudioOnly !== false) return null\n return (\n <FormField\n path={[]}\n title=\"Watermark\"\n description={\n <>\n Add a watermark overlay to your video using Mux's native watermark support.{' '}\n <a\n href=\"https://www.mux.com/docs/guides/add-watermarks-to-your-videos\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Learn more about Mux watermarks.\n </a>\n </>\n }\n >\n <Stack space={3}>\n <WatermarkControls\n watermark={config.watermark || {enabled: false}}\n onChange={(watermark) => {\n dispatch({action: 'watermark', value: watermark})\n }}\n onValidationChange={onValidationChange}\n previewContainerRef={watermarkPreviewContainerRef}\n previewVideoRef={watermarkPreviewVideoRef}\n />\n {config.watermark?.imageUrl &&\n stagedUpload.type === 'file' &&\n // Canvas preview is only shown in \"Canvas\" mode (no explicit overlay_settings)\n !config.watermark.overlay_settings && (\n <WatermarkPreview\n stagedUpload={stagedUpload}\n watermark={config.watermark}\n videoAspectRatio={videoAssetMetadata.aspectRatio}\n onWatermarkChange={(watermark) => {\n dispatch({action: 'watermark', value: watermark})\n }}\n previewContainerRef={watermarkPreviewContainerRef}\n videoRef={watermarkPreviewVideoRef}\n />\n )}\n </Stack>\n </FormField>\n )\n}\n\n// Memoized preview component to prevent unnecessary re-renders\nconst WatermarkPreview = memo(function WatermarkPreview({\n stagedUpload,\n watermark,\n onWatermarkChange,\n videoAspectRatio,\n previewContainerRef,\n videoRef,\n}: {\n stagedUpload: StagedUpload\n watermark: WatermarkConfig\n onWatermarkChange: (watermark: WatermarkConfig) => void\n videoAspectRatio?: number | null\n previewContainerRef: React.RefObject<HTMLDivElement | null>\n videoRef: React.RefObject<HTMLVideoElement | null>\n}) {\n // Initialize video source only once\n useEffect(() => {\n if (videoRef.current && stagedUpload.type === 'file') {\n const file = stagedUpload.files[0]\n const url = URL.createObjectURL(file!)\n videoRef.current.src = url\n\n return () => {\n URL.revokeObjectURL(url)\n }\n }\n return undefined\n }, [stagedUpload, videoRef])\n\n const isVertical =\n videoAspectRatio !== null && videoAspectRatio !== undefined && videoAspectRatio < 1\n\n return (\n <Card\n tone=\"transparent\"\n border\n style={{\n overflow: 'hidden',\n // For vertical videos, center the preview and limit its width\n display: 'flex',\n justifyContent: 'center',\n }}\n >\n {/* Inner container that exactly matches the video aspect ratio - no padding, no letterbox */}\n <div\n ref={previewContainerRef}\n style={{\n position: 'relative',\n // For vertical videos: limit width so the preview doesn't get too tall\n // For horizontal videos: use full width\n width: isVertical ? 'auto' : '100%',\n aspectRatio: videoAspectRatio ? String(videoAspectRatio) : '16/9',\n ...(isVertical ? {height: '400px', maxHeight: '50vh'} : {minHeight: '200px'}),\n overflow: 'hidden',\n }}\n >\n <video\n ref={videoRef}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n height: '100%',\n objectFit: 'fill',\n display: 'block',\n }}\n />\n <DraggableWatermark\n watermark={watermark}\n onChange={onWatermarkChange}\n containerRef={previewContainerRef as React.RefObject<HTMLDivElement>}\n videoElementRef={videoRef as React.RefObject<HTMLVideoElement>}\n />\n </div>\n </Card>\n )\n})\n","import {rem} from '@sanity/ui'\nimport type {ComponentType} from 'react'\nimport {css, styled} from 'styled-components'\n\nimport {focusRingBorderStyle, focusRingStyle} from './helpers'\n\nexport function withFocusRing<Props>(component: ComponentType<Props>) {\n return styled(component as unknown as any)<Props & {$border?: boolean}>((props) => {\n const border = {\n width: props.$border ? 1 : 0,\n color: 'var(--card-border-color)',\n }\n\n return css`\n --card-focus-box-shadow: ${focusRingBorderStyle(border)};\n\n border-radius: ${rem(props.theme.sanity.radius[1]!)};\n outline: none;\n box-shadow: var(--card-focus-box-shadow);\n\n &:focus {\n --card-focus-box-shadow: ${focusRingStyle({\n base: props.theme.sanity.color.base,\n border,\n focusRing: props.theme.sanity.focusRing,\n })};\n }\n `\n })\n}\n","import {Card, type CardTone} from '@sanity/ui'\nimport {useCallback, useRef} from 'react'\nimport {styled} from 'styled-components'\n\nimport {withFocusRing} from './withFocusRing'\n\nconst UploadCardWithFocusRing = withFocusRing(Card)\n\ninterface UploadCardProps {\n tone?: CardTone\n children: React.ReactNode\n onPaste: React.ClipboardEventHandler<HTMLInputElement>\n onDrop: React.DragEventHandler<HTMLDivElement>\n onDragOver: React.DragEventHandler<HTMLDivElement>\n onDragLeave: React.DragEventHandler<HTMLDivElement>\n onDragEnter: React.DragEventHandler<HTMLDivElement>\n}\nexport function UploadCard({\n children,\n tone,\n onPaste,\n onDrop,\n onDragEnter,\n onDragLeave,\n onDragOver,\n ref,\n}: UploadCardProps & {ref?: React.Ref<HTMLDivElement>}) {\n const inputRef = useRef<HTMLInputElement>(null)\n const handleKeyDown = useCallback<React.KeyboardEventHandler<HTMLDivElement>>((event) => {\n const target = event.target as HTMLElement\n\n // Don't steal focus when pasting into the VTT input\n if (target.closest('#vtt-url')) {\n return\n }\n\n if ((event.ctrlKey || event.metaKey) && event.key === 'v') {\n inputRef.current!.focus()\n }\n }, [])\n\n return (\n <UploadCardWithFocusRing\n tone={tone}\n ref={ref}\n padding={0}\n radius={2}\n shadow={0}\n tabIndex={0}\n onKeyDown={handleKeyDown}\n onPaste={onPaste}\n onDrop={onDrop}\n onDragEnter={onDragEnter}\n onDragLeave={onDragLeave}\n onDragOver={onDragOver}\n >\n <HiddenInput ref={inputRef} />\n {children}\n </UploadCardWithFocusRing>\n )\n}\n\nconst HiddenInput = styled.input.attrs({type: 'text'})`\n position: absolute;\n border: 0;\n color: white;\n opacity: 0;\n\n &:focus {\n outline: none;\n }\n`\n","import {Button, type ButtonProps} from '@sanity/ui'\nimport {useCallback, useId, useRef} from 'react'\nimport {styled} from 'styled-components'\n\nconst HiddenInput = styled.input`\n overflow: hidden;\n width: 0.1px;\n height: 0.1px;\n opacity: 0;\n position: absolute;\n z-index: -1;\n`\n\nconst Label = styled.label`\n position: relative;\n`\n\nexport interface FileInputButtonProps extends Omit<ButtonProps, 'onSelect'> {\n onSelect: (files: FileList) => void\n accept: string\n}\nexport const FileInputButton = ({onSelect, accept, ...props}: FileInputButtonProps) => {\n const inputId = `FileSelect${useId()}`\n const inputRef = useRef<HTMLInputElement>(null)\n const handleSelect = useCallback<React.ChangeEventHandler<HTMLInputElement>>(\n (event) => {\n if (onSelect) {\n onSelect(event.target.files!)\n }\n },\n [onSelect],\n )\n const handleButtonClick = useCallback(() => inputRef.current?.click(), [])\n return (\n <Label htmlFor={inputId}>\n <HiddenInput\n accept={accept}\n ref={inputRef}\n tabIndex={0}\n type=\"file\"\n id={inputId}\n onChange={handleSelect}\n value=\"\"\n />\n <Button\n onClick={handleButtonClick}\n mode=\"default\"\n tone=\"primary\"\n style={{width: '100%'}}\n {...props}\n />\n </Label>\n )\n}\n","import {DocumentVideoIcon} from '@sanity/icons/DocumentVideo'\nimport {PlugIcon} from '@sanity/icons/Plug'\nimport {SearchIcon} from '@sanity/icons/Search'\nimport {UploadIcon} from '@sanity/icons/Upload'\nimport {Button, Card, Flex, Inline, Text} from '@sanity/ui'\nimport {useCallback} from 'react'\n\nimport {useAccessControl} from '../hooks/useAccessControl'\nimport type {SetDialogState} from '../hooks/useDialogState'\nimport {type PluginConfig} from '../util/types'\nimport {FileInputButton, type FileInputButtonProps} from './FileInputButton'\n\nfunction formatAcceptString(accept: string): string {\n return accept\n .split(',')\n .map((type) => type.trim().replace('/*', ''))\n .join(' or ')\n}\n\ninterface UploadPlaceholderProps {\n setDialogState: SetDialogState\n readOnly: boolean\n hovering: boolean\n needsSetup: boolean\n onSelect: FileInputButtonProps['onSelect']\n config: PluginConfig\n accept: string\n}\nexport default function UploadPlaceholder(props: UploadPlaceholderProps) {\n const {setDialogState, readOnly, onSelect, hovering, needsSetup, accept} = props\n const handleBrowse = useCallback(() => setDialogState('select-video'), [setDialogState])\n const handleConfigureApi = useCallback(() => setDialogState('secrets'), [setDialogState])\n const {hasConfigAccess} = useAccessControl(props.config)\n\n return (\n <Card\n sizing=\"border\"\n tone={readOnly ? 'transparent' : 'inherit'}\n border\n radius={2}\n paddingX={3}\n paddingY={1}\n style={hovering ? {borderColor: 'transparent'} : undefined}\n >\n <Flex\n align=\"center\"\n justify=\"space-between\"\n gap={4}\n direction={['column', 'column', 'row']}\n paddingY={2}\n sizing=\"border\"\n >\n <Flex align=\"center\" justify=\"flex-start\" gap={2} flex={1}>\n <Flex justify=\"center\">\n <Text muted>\n <DocumentVideoIcon />\n </Text>\n </Flex>\n <Flex justify=\"center\">\n <Text size={1} muted>\n Drag {formatAcceptString(accept)} file or paste URL here\n </Text>\n </Flex>\n </Flex>\n <Inline space={2}>\n <FileInputButton\n accept={accept}\n mode=\"bleed\"\n tone=\"default\"\n icon={UploadIcon}\n text=\"Upload\"\n onSelect={onSelect}\n />\n <Button mode=\"bleed\" icon={SearchIcon} text=\"Select\" onClick={handleBrowse} />\n\n {hasConfigAccess && (\n <Button\n padding={3}\n radius={3}\n tone={needsSetup ? 'critical' : undefined}\n onClick={handleConfigureApi}\n icon={PlugIcon}\n mode=\"bleed\"\n title=\"Configure plugin credentials\"\n />\n )}\n </Inline>\n </Flex>\n </Card>\n )\n}\n","import {ErrorOutlineIcon} from '@sanity/icons/ErrorOutline'\nimport {Button, type CardTone, Flex, Text, useToast} from '@sanity/ui'\nimport {useCallback, useEffect, useReducer, useRef, useState} from 'react'\nimport {type Observable, Subject, Subscription} from 'rxjs'\nimport {takeUntil, tap} from 'rxjs/operators'\nimport type {SanityClient} from 'sanity'\nimport {PatchEvent, set, setIfMissing} from 'sanity'\n\nimport {uploadFile, uploadUrl} from '../actions/upload'\nimport {DialogStateProvider} from '../context/DialogStateContext'\nimport {type DialogState, type SetDialogState} from '../hooks/useDialogState'\nimport {isServerError, isValidUrl} from '../util/asserters'\nimport {extractDroppedFiles} from '../util/extractFiles'\nimport {hasPlaybackPolicy} from '../util/getPlaybackPolicy'\nimport type {\n MuxInputProps,\n MuxNewAssetSettings,\n PluginConfig,\n Secrets,\n VideoAssetDocument,\n} from '../util/types'\nimport InputBrowser from './InputBrowser'\nimport Player from './Player'\nimport PlayerActionsMenu from './PlayerActionsMenu'\nimport UploadConfiguration from './UploadConfiguration'\nimport {UploadCard} from './Uploader.styled'\nimport UploadPlaceholder from './UploadPlaceholder'\nimport {UploadProgress} from './UploadProgress'\n\ninterface Props extends Pick<MuxInputProps, 'onChange' | 'readOnly'> {\n config: PluginConfig\n client: SanityClient\n secrets: Secrets\n asset: VideoAssetDocument | null | undefined\n dialogState: DialogState\n setDialogState: SetDialogState\n needsSetup: boolean\n}\n\nexport type StagedUpload = {type: 'file'; files: FileList | File[]} | {type: 'url'; url: string}\ntype UploadStatus = {\n progress: number\n file?: {name: string | undefined; type: string}\n uuid?: string\n url?: string\n}\n\ninterface State {\n stagedUpload: StagedUpload | null\n uploadStatus: UploadStatus | null\n error: Error | null\n}\n\nconst INITIAL_STATE: State = {\n stagedUpload: null,\n uploadStatus: null,\n error: null,\n}\n\ntype UploadFileEvent = ReturnType<typeof uploadFile> extends Observable<infer T> ? T : never\ntype UploadUrlEvent = ReturnType<typeof uploadUrl> extends Observable<infer T> ? T : never\ntype UploaderStateAction =\n | {action: 'stageUpload'; input: NonNullable<State['stagedUpload']>}\n | {action: 'commitUpload'}\n | ({action: 'progressInfo'} & (\n | Extract<UploadFileEvent, {type: 'uuid' | 'file'}>\n | Extract<UploadUrlEvent, {type: 'url'}>\n ))\n | {action: 'progress'; percent: number}\n | {action: 'error'; error: Error; settings: MuxNewAssetSettings}\n | {action: 'complete' | 'reset'}\n\n/**\n * The main interface for inputting a Mux Video. It handles staging an upload\n * file, setting its configuration, displaying upload progress, and showing\n * the preview player.\n */\nexport default function Uploader(props: Props) {\n const toast = useToast()\n const containerRef = useRef<HTMLDivElement>(null)\n\n const dragEnteredEls = useRef<EventTarget[]>([])\n const [dragState, setDragState] = useState<'valid' | 'invalid' | null>(null)\n\n const cancelUploadButton = useRef(\n (() => {\n const events$ = new Subject()\n return {\n observable: events$.asObservable(),\n handleClick: (event: React.MouseEvent<HTMLButtonElement>) => events$.next(event),\n }\n })(),\n ).current\n\n const uploadRef = useRef<Subscription | null>(null)\n const uploadingDocumentId = useRef<string | null>(null)\n const [state, dispatch] = useReducer(\n // oxlint-disable-next-line react/react-compiler\n (prev: State, action: UploaderStateAction) => {\n switch (action.action) {\n case 'stageUpload':\n return Object.assign({}, INITIAL_STATE, {stagedUpload: action.input})\n case 'commitUpload':\n return Object.assign({}, prev, {uploadStatus: {progress: 0}})\n case 'progressInfo': {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {type, action: _, ...payload} = action\n return Object.assign({}, prev, {\n uploadStatus: {\n ...prev.uploadStatus,\n progress: prev.uploadStatus!.progress,\n ...payload,\n },\n } satisfies Pick<typeof prev, 'uploadStatus'>)\n }\n case 'progress':\n return Object.assign({}, prev, {\n uploadStatus: {\n ...prev.uploadStatus,\n progress: action.percent,\n },\n } satisfies Pick<typeof prev, 'uploadStatus'>)\n case 'reset':\n case 'complete':\n // Clear upload observable on completion\n uploadRef.current?.unsubscribe()\n uploadRef.current = null\n uploadingDocumentId.current = null\n return INITIAL_STATE\n case 'error': {\n // Clear upload observable on error\n uploadRef.current?.unsubscribe()\n uploadRef.current = null\n uploadingDocumentId.current = null\n\n let error = action.error\n if (isServerError(action.error) && hasPlaybackPolicy(action.settings, 'drm')) {\n error = new Error(\n 'Unknown Error while uploading DRM protected content. Make sure your DRM configuration ID is valid and set correctly',\n )\n }\n\n return Object.assign({}, INITIAL_STATE, {error: error})\n }\n default:\n return prev\n }\n },\n {\n stagedUpload: null,\n uploadStatus: null,\n error: null,\n },\n )\n\n // Make sure we close out the upload observer on dismount\n // and cleanup orphaned documents if upload was in progress\n useEffect(() => {\n const cleanup = () => {\n // Cancel subscription\n if (uploadRef.current && !uploadRef.current.closed) {\n uploadRef.current.unsubscribe()\n }\n\n // Delete orphaned document if upload was in progress and document is different from the saved asset\n if (uploadingDocumentId.current && props.asset?._id !== uploadingDocumentId.current) {\n const docId = uploadingDocumentId.current\n uploadingDocumentId.current = null\n\n props.client.delete(docId).catch((err) => {\n console.warn('Failed to cleanup orphaned upload document:', err)\n })\n }\n }\n\n const handleBeforeUnload = () => {\n cleanup()\n }\n\n window.addEventListener('beforeunload', handleBeforeUnload)\n window.addEventListener('pagehide', handleBeforeUnload)\n\n return () => {\n window.removeEventListener('beforeunload', handleBeforeUnload)\n window.removeEventListener('pagehide', handleBeforeUnload)\n cleanup()\n }\n }, [props.client, props.asset?._id])\n\n /* -------------------------------------------------------------------------- */\n /* Uploading */\n /* -------------------------------------------------------------------------- */\n\n /**\n * Begins a file or URL upload with the staged files or URL.\n *\n * Should only be called from the UploadConfiguration component, which provides\n * the Mux configuration for the direct asset upload.\n *\n * @param settings The Mux new_asset_settings object to send to Sanity\n * @param watermark Optional watermark configuration\n * @returns\n */\n const startUpload = (\n settings: MuxNewAssetSettings,\n watermark?: import('../util/types').WatermarkConfig,\n ) => {\n const {stagedUpload} = state\n if (!stagedUpload || uploadRef.current) return\n dispatch({action: 'commitUpload'})\n let uploadObservable: Observable<UploadFileEvent | UploadUrlEvent>\n switch (stagedUpload.type) {\n case 'url':\n uploadObservable = uploadUrl({\n client: props.client,\n url: stagedUpload.url,\n settings,\n watermark,\n })\n break\n case 'file':\n uploadObservable = uploadFile({\n client: props.client,\n file: stagedUpload.files[0]!,\n settings,\n watermark,\n }).pipe(\n takeUntil(\n cancelUploadButton.observable.pipe(\n tap(() => {\n if (uploadingDocumentId.current) {\n void props.client.delete(uploadingDocumentId.current)\n uploadingDocumentId.current = null\n }\n }),\n ),\n ),\n )\n break\n }\n uploadRef.current = uploadObservable.subscribe({\n next: (event) => {\n switch (event.type) {\n case 'uuid':\n // Track the document ID for cleanup on unmount\n uploadingDocumentId.current = event.uuid\n dispatch({action: 'progressInfo', ...event})\n break\n case 'file':\n case 'url':\n dispatch({action: 'progressInfo', ...event})\n break\n case 'progress':\n dispatch({action: 'progress', percent: event.percent})\n break\n case 'success':\n dispatch({action: 'progress', percent: 100})\n uploadingDocumentId.current = null\n props.onChange(\n PatchEvent.from([\n setIfMissing({asset: {}}),\n set({_type: 'reference', _weak: true, _ref: event.asset._id}, ['asset']),\n ]),\n )\n break\n case 'pause':\n case 'resume':\n default:\n break\n }\n },\n complete: () => dispatch({action: 'complete'}),\n error: (error) => dispatch({action: 'error', error, settings}),\n })\n }\n\n const invalidFileToast = useCallback(() => {\n toast.push({\n status: 'error',\n title: `Invalid file type. Accepted types: ${props.config.acceptedMimeTypes?.join(', ')}`,\n })\n }, [props.config.acceptedMimeTypes, toast])\n\n /**\n * Validates if any file in the provided FileList or File array has an unsupported MIME type\n * @param files - FileList or File array to validate\n * @returns true if any file has an invalid MIME type, false if all files are valid\n */\n const isInvalidFile = (files: FileList | File[]) => {\n const isInvalid = Array.from(files).some((file) => {\n return !props.config.acceptedMimeTypes?.some((acceptedType) => {\n // Convert mime type pattern to regex (e.g., 'audio/*' -> /^audio\\/.*$/)\n const pattern = `^${acceptedType.replace('*', '.*')}$`\n return new RegExp(pattern).test(file.type)\n })\n })\n\n return isInvalid\n }\n\n /* -------------------------- Upload Initialization ------------------------- */\n // The below populate the uploadInput state field, which then triggers the\n // upload configuration, or the startUpload function if no config is required.\n\n // Stages an upload from the file selector\n const handleUpload = (files: FileList | File[]) => {\n if (isInvalidFile(files)) return\n dispatch({\n action: 'stageUpload',\n input: {type: 'file', files},\n })\n }\n\n // Stages and validates an upload from pasting an asset URL\n const handlePaste: React.ClipboardEventHandler<HTMLInputElement> = (event) => {\n const target = event.target as HTMLElement\n\n // Ignore paste coming from the VTT URL input\n if (target.closest('#vtt-url')) {\n return\n }\n\n event.preventDefault()\n event.stopPropagation()\n const clipboardData =\n event.clipboardData || (window as Window & {clipboardData?: DataTransfer}).clipboardData\n const url = clipboardData?.getData('text')?.trim()\n if (!isValidUrl(url)) {\n toast.push({status: 'error', title: 'Invalid URL for Mux video input.'})\n return\n }\n dispatch({action: 'stageUpload', input: {type: 'url', url: url}})\n }\n\n // Stages and validates an upload from dragging+dropping files or folders\n const handleDrop: React.DragEventHandler<HTMLDivElement> = (event) => {\n event.preventDefault()\n event.stopPropagation()\n if (dragState === 'invalid') {\n invalidFileToast()\n setDragState(null)\n return\n }\n setDragState(null)\n void extractDroppedFiles(event.nativeEvent.dataTransfer!).then((files) => {\n dispatch({\n action: 'stageUpload',\n input: {type: 'file', files},\n })\n })\n }\n\n /* ------------------------------- Drag State ------------------------------- */\n\n const handleDragOver: React.DragEventHandler<HTMLDivElement> = (event) => {\n event.preventDefault()\n event.stopPropagation()\n }\n\n const handleDragEnter: React.DragEventHandler<HTMLDivElement> = (event) => {\n event.stopPropagation()\n dragEnteredEls.current.push(event.target)\n const type = event.dataTransfer.items?.[0]?.type\n const mimeTypes = props.config.acceptedMimeTypes\n\n // Check if the dragged file type matches any of the accepted mime types\n const isValidType = mimeTypes?.some((acceptedType) => {\n // Convert mime type pattern to regex (e.g., 'video/*' -> /^video\\/.*$/)\n const pattern = `^${acceptedType.replace('*', '.*')}$`\n return new RegExp(pattern).test(type!)\n })\n\n setDragState(isValidType ? 'valid' : 'invalid')\n }\n\n const handleDragLeave: React.DragEventHandler<HTMLDivElement> = (event) => {\n event.stopPropagation()\n const idx = dragEnteredEls.current.indexOf(event.target)\n if (idx > -1) {\n dragEnteredEls.current.splice(idx, 1)\n }\n if (dragEnteredEls.current.length === 0) {\n setDragState(null)\n }\n }\n\n /* -------------------------------- Rendering ------------------------------- */\n\n // Upload has errored\n if (state.error !== null) {\n const error = state.error\n return (\n <Flex gap={3} direction=\"column\" justify=\"center\" align=\"center\">\n <Text size={5} muted>\n <ErrorOutlineIcon />\n </Text>\n <Text>Something went wrong</Text>\n {error instanceof Error && error.message && (\n <Text size={1} muted weight=\"semibold\" style={{textAlign: 'center'}}>\n {error.message}\n </Text>\n )}\n <Button text=\"Upload another file\" onClick={() => dispatch({action: 'reset'})} />\n </Flex>\n )\n }\n\n // Upload is in progress\n if (state.uploadStatus !== null) {\n const {uploadStatus} = state\n return (\n <UploadProgress\n // oxlint-disable-next-line react/react-compiler\n onCancel={cancelUploadButton.handleClick}\n progress={uploadStatus.progress}\n filename={uploadStatus.file?.name || uploadStatus.url}\n />\n )\n }\n\n // Upload needs configuration\n if (state.stagedUpload !== null) {\n return (\n <UploadConfiguration\n stagedUpload={state.stagedUpload}\n pluginConfig={props.config}\n secrets={props.secrets}\n startUpload={startUpload}\n onClose={() => dispatch({action: 'reset'})}\n />\n )\n }\n\n // Default: No staged upload\n let tone: CardTone | undefined\n if (dragState) tone = dragState === 'valid' ? 'positive' : 'critical'\n\n const acceptMimeString = props.config?.acceptedMimeTypes?.length\n ? props.config.acceptedMimeTypes.join(',')\n : 'video/*, audio/*'\n\n return (\n <>\n <UploadCard\n tone={tone}\n onDrop={handleDrop}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDragEnter={handleDragEnter}\n onPaste={handlePaste}\n ref={containerRef}\n >\n {props.asset ? (\n <DialogStateProvider\n dialogState={props.dialogState}\n setDialogState={props.setDialogState}\n >\n <Player\n readOnly={props.readOnly}\n asset={props.asset}\n onChange={props.onChange}\n config={props.config}\n buttons={\n <PlayerActionsMenu\n accept={acceptMimeString}\n asset={props.asset}\n dialogState={props.dialogState}\n setDialogState={props.setDialogState}\n onChange={props.onChange}\n onSelect={handleUpload}\n readOnly={props.readOnly}\n config={props.config}\n />\n }\n />\n </DialogStateProvider>\n ) : (\n <UploadPlaceholder\n accept={acceptMimeString}\n hovering={dragState !== null}\n onSelect={handleUpload}\n readOnly={!!props.readOnly}\n setDialogState={props.setDialogState}\n needsSetup={props.needsSetup}\n config={props.config}\n />\n )}\n </UploadCard>\n {props.dialogState === 'select-video' && (\n <InputBrowser\n config={props.config}\n asset={props.asset}\n onChange={props.onChange}\n setDialogState={props.setDialogState}\n />\n )}\n </>\n )\n}\n","import {Card} from '@sanity/ui'\nimport {memo, Suspense} from 'react'\n\nimport {useAccessControl} from '../hooks/useAccessControl'\nimport {useAssetDocumentValues} from '../hooks/useAssetDocumentValues'\nimport {useClient} from '../hooks/useClient'\nimport {useDialogState} from '../hooks/useDialogState'\nimport {useMuxPolling} from '../hooks/useMuxPolling'\nimport {useSecretsDocumentValues} from '../hooks/useSecretsDocumentValues'\nimport type {MuxInputProps, PluginConfig} from '../util/types'\nimport {ConfigureApiDialog} from './ConfigureApi'\nimport ErrorBoundaryCard from './ErrorBoundaryCard'\nimport {InputFallback} from './Input.styled'\nimport Onboard from './Onboard'\nimport Uploader from './Uploader'\n\nexport interface InputProps extends MuxInputProps {\n config: PluginConfig\n}\nconst Input = (props: InputProps) => {\n const client = useClient()\n const secretDocumentValues = useSecretsDocumentValues()\n const assetDocumentValues = useAssetDocumentValues(props.value?.asset)\n const poll = useMuxPolling(props.readOnly ? undefined : assetDocumentValues?.value || undefined)\n const [dialogState, setDialogState] = useDialogState()\n const {hasConfigAccess} = useAccessControl(props.config)\n\n const error = secretDocumentValues.error || assetDocumentValues.error || poll.error /*||\n // @TODO move errored logic to Uploader, where handleRemoveVideo can be called\n (assetDocumentValues.value?.status === 'errored'\n ? new Error(assetDocumentValues.value.data?.errors?.messages?.join(' '))\n : undefined)\n // */\n if (error) {\n // @TODO deal with it more gracefully\n throw error\n }\n const isLoading = secretDocumentValues.isLoading || assetDocumentValues.isLoading\n\n return (\n <Card>\n <ErrorBoundaryCard schemaType={props.schemaType}>\n <Suspense fallback={<InputFallback />}>\n {isLoading ? (\n <InputFallback />\n ) : (\n <>\n {secretDocumentValues.value.needsSetup && !assetDocumentValues.value ? (\n <Onboard setDialogState={setDialogState} config={props.config} />\n ) : (\n <Uploader\n {...props}\n config={props.config}\n onChange={props.onChange}\n client={client}\n secrets={secretDocumentValues.value.secrets}\n asset={assetDocumentValues.value}\n dialogState={dialogState}\n setDialogState={setDialogState}\n needsSetup={secretDocumentValues.value.needsSetup}\n />\n )}\n\n {dialogState === 'secrets' && hasConfigAccess && (\n <ConfigureApiDialog\n setDialogState={setDialogState}\n secrets={secretDocumentValues.value.secrets}\n />\n )}\n </>\n )}\n </Suspense>\n </ErrorBoundaryCard>\n </Card>\n )\n}\n\nexport default memo(Input)\n","import Input from './components/Input'\nimport VideoThumbnail from './components/VideoThumbnail'\nimport type {MuxInputProps, PluginConfig, VideoAssetDocument} from './util/types'\n\nexport function muxVideoCustomRendering(config: PluginConfig) {\n return {\n components: {\n input: (props: MuxInputProps) => (\n <Input config={{...config, ...props.schemaType.options}} {...props} />\n ),\n },\n preview: {\n select: {\n filename: 'asset.filename',\n playbackId: 'asset.playbackId',\n status: 'asset.status',\n assetId: 'asset.assetId',\n thumbTime: 'asset.thumbTime',\n data: 'asset.data',\n },\n prepare: (asset: Partial<VideoAssetDocument>) => {\n const {filename, playbackId, status} = asset\n return {\n title: filename || playbackId || '',\n subtitle: status ? `status: ${status}` : null,\n media: asset.playbackId ? <VideoThumbnail asset={asset} width={64} /> : null,\n }\n },\n },\n }\n}\n","export const muxVideoSchema = {\n name: 'mux.video',\n type: 'object',\n title: 'Video asset reference',\n fields: [\n {\n title: 'Video',\n name: 'asset',\n type: 'reference',\n weak: true,\n to: [{type: 'mux.videoAsset'}],\n },\n ],\n}\n\nconst muxTrack = {\n name: 'mux.track',\n type: 'object',\n fields: [\n {type: 'string', name: 'id'},\n {type: 'string', name: 'type'},\n {type: 'number', name: 'max_width'},\n {type: 'number', name: 'max_frame_rate'},\n {type: 'number', name: 'duration'},\n {type: 'number', name: 'max_height'},\n {type: 'string', name: 'language_code'},\n {type: 'string', name: 'name'},\n {type: 'string', name: 'status'},\n {type: 'string', name: 'text_source'},\n {type: 'string', name: 'text_type'},\n ],\n}\n\nconst muxPlaybackId = {\n name: 'mux.playbackId',\n type: 'object',\n fields: [\n {type: 'string', name: 'id'},\n {type: 'string', name: 'policy'},\n ],\n}\n\nconst muxStaticRenditionFile = {\n name: 'mux.staticRenditionFile',\n type: 'object',\n fields: [\n {type: 'string', name: 'name'},\n {type: 'string', name: 'ext'},\n {type: 'number', name: 'height'},\n {type: 'number', name: 'width'},\n {type: 'number', name: 'bitrate'},\n {type: 'string', name: 'filesize'},\n {type: 'string', name: 'type'},\n {type: 'string', name: 'status'},\n {type: 'string', name: 'resolution_tier'},\n {type: 'string', name: 'resolution'},\n {type: 'string', name: 'id'},\n {type: 'string', name: 'passthrough'},\n ],\n}\n\nconst muxStaticRenditions = {\n name: 'mux.staticRenditions',\n type: 'object',\n fields: [\n {type: 'string', name: 'status'},\n {\n name: 'files',\n type: 'array',\n of: [{type: 'mux.staticRenditionFile'}],\n },\n ],\n}\n\nconst muxMasterFile = {\n name: 'mux.masterFile',\n type: 'object',\n fields: [\n {type: 'string', name: 'status'},\n {type: 'string', name: 'url'},\n ],\n}\n\nconst muxAssetData = {\n name: 'mux.assetData',\n title: 'Mux asset data',\n type: 'object',\n fields: [\n {\n type: 'string',\n name: 'resolution_tier',\n },\n {\n type: 'string',\n name: 'upload_id',\n },\n {\n type: 'string',\n name: 'created_at',\n },\n {\n type: 'string',\n name: 'id',\n },\n {\n type: 'string',\n name: 'status',\n },\n {\n type: 'string',\n name: 'max_stored_resolution',\n },\n {\n type: 'string',\n name: 'passthrough',\n },\n {\n type: 'string',\n name: 'encoding_tier',\n },\n {\n type: 'string',\n name: 'video_quality',\n },\n {\n type: 'string',\n name: 'master_access',\n },\n {\n type: 'string',\n name: 'aspect_ratio',\n },\n {\n type: 'number',\n name: 'duration',\n },\n {\n type: 'number',\n name: 'max_stored_frame_rate',\n },\n {\n type: 'string',\n name: 'mp4_support',\n },\n {\n type: 'string',\n name: 'max_resolution_tier',\n },\n {\n name: 'tracks',\n type: 'array',\n of: [{type: 'mux.track'}],\n },\n {\n name: 'playback_ids',\n type: 'array',\n of: [{type: 'mux.playbackId'}],\n },\n {\n name: 'static_renditions',\n type: 'mux.staticRenditions',\n },\n {\n name: 'master',\n type: 'mux.masterFile',\n },\n ],\n}\n\nconst muxVideoAsset = {\n name: 'mux.videoAsset',\n type: 'document',\n title: 'Video asset',\n fields: [\n {\n type: 'string',\n name: 'status',\n },\n {\n type: 'string',\n name: 'assetId',\n },\n {\n type: 'string',\n name: 'playbackId',\n },\n {\n type: 'string',\n name: 'filename',\n },\n {\n type: 'number',\n name: 'thumbTime',\n },\n {\n type: 'mux.assetData',\n name: 'data',\n },\n ],\n}\n\nexport const schemaTypes = [\n muxTrack,\n muxPlaybackId,\n muxStaticRenditionFile,\n muxStaticRenditions,\n muxMasterFile,\n muxAssetData,\n muxVideoAsset,\n]\n","import {definePlugin} from 'sanity'\n\nimport createStudioTool, {DEFAULT_TOOL_CONFIG} from '../components/StudioTool'\nimport {muxVideoCustomRendering} from '../plugin'\nimport {muxVideoSchema, schemaTypes} from '../schema'\nimport type {PluginConfig, StaticRenditionResolution} from '../util/types'\nexport type {VideoAssetDocument} from '../util/types'\n\nexport const defaultConfig: PluginConfig = {\n static_renditions: [],\n mp4_support: 'none',\n video_quality: 'plus',\n max_resolution_tier: '1080p',\n normalize_audio: false,\n defaultPublic: true,\n defaultSigned: false,\n defaultDrm: false,\n tool: DEFAULT_TOOL_CONFIG,\n allowedRolesForConfiguration: [],\n acceptedMimeTypes: ['video/*', 'audio/*'],\n}\n\n/**\n * Converts legacy mp4_support configuration to static_renditions format\n */\nfunction convertLegacyConfig(config: Partial<PluginConfig>): {\n static_renditions: StaticRenditionResolution[]\n} {\n // If static_renditions is already provided, use it\n if (config.static_renditions && config.static_renditions.length > 0) {\n return {static_renditions: config.static_renditions}\n }\n\n // Convert legacy mp4_support to static_renditions\n if (config.mp4_support === 'standard') {\n return {static_renditions: ['highest']}\n }\n\n return {static_renditions: []}\n}\n\nexport const muxInput = definePlugin<Partial<PluginConfig> | void>((userConfig) => {\n // TODO: Remove this on next major version when we end support for encoding_tier\n if (typeof userConfig === 'object' && 'encoding_tier' in userConfig) {\n const deprecated_encoding_tier = userConfig.encoding_tier\n if (!userConfig.video_quality) {\n if (deprecated_encoding_tier === 'baseline') {\n userConfig.video_quality = 'basic'\n }\n if (deprecated_encoding_tier === 'smart') {\n userConfig.video_quality = 'plus'\n }\n }\n }\n const config: PluginConfig = {\n ...defaultConfig,\n ...userConfig,\n ...convertLegacyConfig(userConfig || {}),\n }\n return {\n name: 'mux-input',\n schema: {\n types: [\n ...schemaTypes,\n {\n ...muxVideoSchema,\n ...muxVideoCustomRendering(config),\n },\n ],\n },\n tools: config.tool === false ? undefined : [createStudioTool(config)],\n }\n})\n"],"mappings":"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"}
\ No newline at end of file