UNPKG

sanity-plugin-mux-input

Version:

An input component that integrates Sanity Studio with Mux video encoding/hosting service.

420 lines (378 loc) 14.5 kB
import type {ObjectInputProps, PreviewLayoutKey, PreviewProps, SchemaType} from 'sanity' import type {PartialDeep} from 'type-fest' export interface MuxInputConfig { /** * Enable static renditions by setting this to 'standard'. Can be overwritten on a per-asset basis. * Requires `"encoding_tier": "smart"` * @see {@link https://docs.mux.com/guides/video/enable-static-mp4-renditions#why-enable-mp4-support} * @defaultValue 'none' */ mp4_support: 'none' | 'standard' /** * Max resolution tier can be used to control the maximum resolution_tier your asset is encoded, stored, and streamed at. * Requires `"encoding_tier": "smart"` * @see {@link https://docs.mux.com/guides/stream-videos-in-4k} * @defaultValue '1080p' */ max_resolution_tier: '2160p' | '1440p' | '1080p' /** * The encoding tier informs the cost, quality, and available platform features for the asset. * @see {@link https://docs.mux.com/guides/use-encoding-tiers} * @defaultValue 'smart' */ encoding_tier: 'baseline' | 'smart' /** * Normalize the audio track loudness level. * @see {@link https://docs.mux.com/guides/adjust-audio-levels#how-to-turn-on-audio-normalization} * @defaultValue false */ normalize_audio: boolean /** * Enables signed URLs by default, if you configured them with your API token. * @see {@link https://docs.mux.com/guides/secure-video-playback} * @defaultValue false */ defaultSigned?: boolean /** * Auto-generate captions for these languages by default. * Requires `"encoding_tier": "smart"` * * @see {@link https://docs.mux.com/guides/add-autogenerated-captions-and-use-transcripts} * @deprecated use `defaultAutogeneratedSubtitleLang` instead. Only a single autogenerated */ defaultAutogeneratedSubtitleLangs?: SupportedMuxLanguage[] /** * Auto-generate captions for this language by default. Users can still * Requires `"encoding_tier": "smart"` * * @see {@link https://docs.mux.com/guides/add-autogenerated-captions-and-use-transcripts} */ defaultAutogeneratedSubtitleLang?: SupportedMuxLanguage /** * Whether or not to allow content editors to override asset upload * configuration settings when uploading a video to Mux. * * @see {@link https://docs.mux.com/guides/secure-video-playback} * @defaultValue false */ disableUploadConfig?: boolean /** * Whether or not to allow content editors to add text tracks alongside their * asset when uploading a video to Mux. * * @see {@link https://docs.mux.com/guides/secure-video-playback} * @defaultValue false */ disableTextTrackConfig?: boolean } export interface PluginConfig extends MuxInputConfig { /** * How the videos browser should appear as a studio tool in Sanity's top navigation * * Pass `false` if you want to disable it. * @defaultValue {title: 'Videos', icon: VideoIcon} **/ tool: | false | { title?: string icon?: React.ComponentType } /** * The roles that are allowed to configure the plugin. * * If not set, all roles will be allowed to configure the plugin. * @defaultValue [] */ allowedRolesForConfiguration: string[] } export const SUPPORTED_MUX_LANGUAGES = [ {label: 'English', code: 'en', state: 'Stable'}, {label: 'Spanish', code: 'es', state: 'Stable'}, {label: 'Italian', code: 'it', state: 'Stable'}, {label: 'Portuguese', code: 'pt', state: 'Stable'}, {label: 'German', code: 'de', state: 'Stable'}, {label: 'French', code: 'fr', state: 'Stable'}, {label: 'Polish', code: 'pl', state: 'Beta'}, {label: 'Russian', code: 'ru', state: 'Beta'}, {label: 'Dutch', code: 'nl', state: 'Beta'}, {label: 'Catalan', code: 'ca', state: 'Beta'}, {label: 'Turkish', code: 'tr', state: 'Beta'}, {label: 'Swedish', code: 'sv', state: 'Beta'}, {label: 'Ukrainian', code: 'uk', state: 'Beta'}, {label: 'Norwegian', code: 'no', state: 'Beta'}, {label: 'Finnish', code: 'fi', state: 'Beta'}, {label: 'Slovak', code: 'sk', state: 'Beta'}, {label: 'Greek', code: 'el', state: 'Beta'}, {label: 'Czech', code: 'cs', state: 'Beta'}, {label: 'Croatian', code: 'hr', state: 'Beta'}, {label: 'Danish', code: 'da', state: 'Beta'}, {label: 'Romanian', code: 'ro', state: 'Beta'}, {label: 'Bulgarian', code: 'bg', state: 'Beta'}, ] as const export const ENCODING_TIERS = [ {label: 'Baseline', value: 'baseline'}, {label: 'Smart', value: 'smart'}, ] as const export const SUPPORTED_MUX_LANGUAGES_VALUES = SUPPORTED_MUX_LANGUAGES.map((l) => l.code) export type SupportedMuxLanguage = (typeof SUPPORTED_MUX_LANGUAGES_VALUES)[number] export interface TextTrack { _id: string name: string } export interface AutogeneratedTextTrack extends TextTrack { type: 'autogenerated' language_code: SupportedMuxLanguage } export interface CustomTextTrack extends TextTrack { type: 'subtitles' | 'captions' language_code: string file: { contents: string type: string name: string size: number } } export function isCustomTextTrack(track: Partial<UploadTextTrack>): track is CustomTextTrack { return track.type !== 'autogenerated' } export function isAutogeneratedTrack( track: Partial<UploadTextTrack> ): track is AutogeneratedTextTrack { return track.type === 'autogenerated' } export type UploadTextTrack = AutogeneratedTextTrack | CustomTextTrack export interface UploadConfig extends Pick< MuxInputConfig, 'encoding_tier' | 'max_resolution_tier' | 'mp4_support' | 'normalize_audio' > { text_tracks: UploadTextTrack[] signed_policy: boolean public_policy: boolean } /** * Data sent to Mux to create a new asset. * @docs {@link https://docs.mux.com/api-reference#video/operation/create-direct-upload} */ export interface MuxNewAssetSettings extends Pick< MuxInputConfig, 'encoding_tier' | 'max_resolution_tier' | 'mp4_support' | 'normalize_audio' > { /** An array of objects that each describe an input file to be used to create the asset.*/ input?: { /** The URL of the file that Mux should download and use. */ url?: string /** Generate subtitle tracks using automatic speech recognition with this configuration. This may only be provided for the first input object (the main input file). */ generated_subtitles?: { /** A name for this subtitle track. */ name: string /** Arbitrary metadata set for the subtitle track. Max 255 characters. */ passthrough?: string /** The language to generate subtitles in. */ language_code: SupportedMuxLanguage }[] /** The time offset in seconds from the beginning of the video indicating the clip's starting marker. */ start_time?: number /** The time offset in seconds from the beginning of the video indicating the clip's ending marker. */ end_time?: number /** This parameter is required for text type tracks. */ type: 'video' | 'audio' | 'text' /** Type of text track. This parameter only supports subtitles value. */ text_type?: 'subtitles' /** The language code value must be a valid BCP 47 specification compliant value. */ language_code?: string /** The name of the track containing a human-readable description. This value must be unique within each group of text or audio track types. */ name?: string /** Indicates the track provides Subtitles for the Deaf or Hard-of-hearing (SDH). */ closed_captions?: boolean /// @TODO Huhh?>?? Below /** This optional parameter should be used tracks with type of text and text_type set to subtitles. */ passthrough?: string }[] /** An array of playback policy names that you want applied to this asset and available through playback_ids. */ playback_policy: ('public' | 'signed' | 'drm')[] /** Arbitrary user-supplied metadata that will be included in the asset details and related webhooks. */ passthrough?: string } export interface Secrets { token: string | null secretKey: string | null enableSignedUrls: boolean signingKeyId: string | null signingKeyPrivate: string | null } // This narrowed type indicates that there may be assets that are signed, and we have the secrets to access them // enabledSignedUrls might be false but that's only relevant for future uploads and their playback policy export interface SignableSecrets extends Omit<Secrets, 'signingKeyId' | 'signingKeyPrivate'> { signingKeyId: string signingKeyPrivate: string } export type MuxImageOrigin = `https://image.mux.com` export type MuxThumbnailUrl = `${MuxImageOrigin}/${string}/thumbnail.png?${string}` export type MuxAnimatedThumbnailUrl = `${MuxImageOrigin}/${string}/animated.gif?${string}` export type MuxStoryboardUrl = `${MuxImageOrigin}/${string}/storyboard.vtt?${string}` export type MuxVideoOrigin = `https://stream.mux.com` export type MuxVideoUrl = `${MuxVideoOrigin}/${string}.m3u8?${string}` export type MuxApiUrl = MuxThumbnailUrl | MuxAnimatedThumbnailUrl | MuxStoryboardUrl | MuxVideoUrl // 'preserve' by default // @url: https://docs.mux.com/guides/video/get-images-from-a-video#thumbnail-query-string-parameters export type FitMode = 'preserve' | 'crop' | 'smartcrop' | 'pad' export interface ThumbnailOptions { fit_mode?: FitMode height?: number time?: number width?: number } export interface AnimatedThumbnailOptions { // Starting time code for the animation, if no end is set it'll have a 5s duration // 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` start?: number // End code, can't be longer than 10s after the start code end?: number // Max 640px, 320px by default width?: number // Preserves aspect ratio, like width, you can't set both the height and width, max 640 height?: number // The fps is 15 by default, but can go up to 30 fps?: number } export interface AssetThumbnailOptions { asset: Pick<VideoAssetDocument, 'playbackId' | 'data' | 'thumbTime' | 'filename' | 'assetId'> } export type PlaybackPolicy = 'signed' | 'public' export interface MuxErrors { type: string messages: string[] } export interface MuxPlaybackId { id: string policy: PlaybackPolicy } export interface MuxVideoTrack { type: 'video' id: string max_width: number max_height: number // if the fps can't be reliably determined, this will be -1 max_frame_rate: -1 | number // top-level duration is always set, while track level duration is not duration?: number } export interface MuxAudioTrack { type: 'audio' id: string duration?: number max_channels: number max_channel_layout: 'stereo' | string } export interface MuxTextTrack { type: 'text' id: string text_type?: 'subtitles' // https://docs.mux.com/api-reference/video#operation/list-assets:~:text=text%20type%20tracks.-,tracks%5B%5D.,text_source,-string text_source?: 'uploaded' | 'embedded' | 'generated_live' | 'generated_live_final' // BCP 47 language code language_code?: 'en' | 'en-US' | string // The name of the track containing a human-readable description. The hls manifest will associate a subtitle text track with this value name?: 'English' | string closed_captions?: boolean // Max 255 characters passthrough?: string status: 'preparing' | 'ready' | 'errored' } export type MuxTrack = MuxVideoTrack | MuxAudioTrack // Typings lifted from https://docs.mux.com/api-reference/video#tag/assets export interface MuxAsset { id: string /** In seconds (instead of JS's default milliseconds) */ created_at: string status: 'preparing' | 'ready' | 'errored' duration: number max_stored_resolution: 'Audio only' | 'SD' | 'HD' | 'FHD' | 'UHD' // if the fps can't be reliably determined, this will be -1 max_stored_frame_rate: -1 | number // The aspect ratio of the asset in the form of width:height, for example 16:9 aspect_ratio: `${number}:${number}` playback_ids: MuxPlaybackId[] tracks: MuxTrack[] errors?: MuxErrors upload_id: string is_live?: boolean // We use passthrough to set the mux.videoAsset._id of the asset that originally uploaded the video passthrough: string live_stream_id?: string master?: { status: 'ready' | 'preparing' | 'errored' // Temporary URL to master MP4, expires after 24 hours url: string } master_access: 'temporary' | 'none' mp4_support: 'standard' | 'none' // Asset Identifier of the video used as the source for creating the clip. source_asset_id?: string // Normalize the audio track loudness level. This parameter is only applicable to on-demand (not live) assets., default false normalize_audio?: boolean // The object does not exist if no static renditions have been requested static_renditions?: { status: 'ready' | 'preparing' | 'disabled' | 'errored' files: { name: 'low.mp4' | 'medium.mp4' | 'high.mp4' | 'audio.m4a' ext: 'mp4' | 'm4a' height: number width: number bitrate: number filesize: number }[] } recording_times?: { started_at: string duration: number type: 'content' | 'slate' }[] // https://docs.mux.com/guides/video/minimize-processing-time non_standard_input_reasons?: { video_codec?: string audio_codec?: string video_gop_size?: 'high' video_frame_rate?: string video_resolution?: string video_bitrate?: 'high' pixel_aspect_ratio?: string video_edit_list?: 'non-standard' audio_edit_list?: 'non-standard' unexpected_media_file_parameters?: 'non-standard' test?: boolean } meta?: { title?: string } } export interface VideoAssetDocument { _id: string _type: 'mux.videoAsset' _createdAt: string _updatedAt?: string status?: string assetId?: string playbackId?: string filename?: string thumbTime?: number // Docs for what goes in `data` https://docs.mux.com/api-reference/video#tag/assets data?: PartialDeep<MuxAsset> } export type Reference = {_type: 'reference'; _ref: string} // @TODO add Reference, and ReferenceSchemaType in the generic export type MuxInputProps = ObjectInputProps<{ asset?: Reference }> export interface MuxInputPreviewProps extends Omit<PreviewProps<PreviewLayoutKey>, 'value'> { schemaType: SchemaType value?: { asset?: Reference } | null } /** Whether the VideosBrowser was opened from a field in a document, or from the standalone studio tool */ export type PluginPlacement = 'input' | 'tool'