sanity-plugin-mux-input 2.2.4 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +148 -16
- package/lib/index.cjs +3996 -3677
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +210 -0
- package/lib/index.d.ts +109 -25
- package/lib/index.esm.js +4390 -0
- package/lib/index.esm.js.map +1 -0
- package/lib/index.js +3964 -3626
- package/lib/index.js.map +1 -1
- package/package.json +48 -52
- package/src/_exports/index.ts +32 -0
- package/src/actions/upload.ts +35 -40
- package/src/clients/upChunkObservable.ts +5 -1
- package/src/components/ConfigureApi.tsx +0 -1
- package/src/components/FileInputArea.tsx +92 -0
- package/src/components/FileInputButton.tsx +3 -2
- package/src/components/FileInputMenuItem.styled.tsx +2 -2
- package/src/components/FileInputMenuItem.tsx +2 -10
- package/src/components/ImportVideosFromMux.tsx +317 -0
- package/src/components/Input.tsx +3 -3
- package/src/components/PlayerActionsMenu.tsx +14 -12
- package/src/components/SelectAsset.tsx +1 -1
- package/src/components/StudioTool.tsx +11 -6
- package/src/components/TextTracksEditor.tsx +214 -0
- package/src/components/UploadConfiguration.tsx +390 -0
- package/src/components/UploadPlaceholder.tsx +41 -55
- package/src/components/Uploader.styled.tsx +0 -1
- package/src/components/Uploader.tsx +384 -0
- package/src/components/VideoDetails/DeleteDialog.tsx +20 -24
- package/src/components/VideoPlayer.tsx +33 -5
- package/src/components/VideoThumbnail.tsx +21 -7
- package/src/components/VideosBrowser.tsx +6 -3
- package/src/components/withFocusRing/withFocusRing.ts +20 -22
- package/src/hooks/useClient.ts +1 -1
- package/src/hooks/useImportMuxAssets.ts +127 -0
- package/src/hooks/useMuxAssets.ts +168 -0
- package/src/plugin.tsx +5 -5
- package/src/util/asserters.ts +9 -0
- package/src/util/createSearchFilter.ts +1 -1
- package/src/util/formatBytes.ts +32 -0
- package/src/util/generateJwt.ts +1 -0
- package/src/util/getAnimatedPosterSrc.ts +1 -1
- package/src/util/getPlaybackId.ts +1 -1
- package/src/util/getPlaybackPolicy.ts +1 -1
- package/src/util/parsers.ts +5 -0
- package/src/util/types.ts +195 -12
- package/lib/index.cjs.js +0 -5
- package/src/components/__legacy__Uploader.tsx +0 -280
- package/src/index.ts +0 -29
package/src/util/types.ts
CHANGED
|
@@ -1,26 +1,80 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ObjectInputProps,
|
|
3
|
-
PreviewLayoutKey,
|
|
4
|
-
PreviewProps,
|
|
5
|
-
SanityDocument,
|
|
6
|
-
SchemaType,
|
|
7
|
-
} from 'sanity'
|
|
1
|
+
import type {ObjectInputProps, PreviewLayoutKey, PreviewProps, SchemaType} from 'sanity'
|
|
8
2
|
import type {PartialDeep} from 'type-fest'
|
|
9
3
|
|
|
10
|
-
export interface
|
|
4
|
+
export interface MuxInputConfig {
|
|
11
5
|
/**
|
|
12
|
-
* Enable static renditions by setting this to 'standard'
|
|
6
|
+
* Enable static renditions by setting this to 'standard'. Can be overwritten on a per-asset basis.
|
|
7
|
+
* Requires `"encoding_tier": "smart"`
|
|
13
8
|
* @see {@link https://docs.mux.com/guides/video/enable-static-mp4-renditions#why-enable-mp4-support}
|
|
14
9
|
* @defaultValue 'none'
|
|
15
10
|
*/
|
|
16
11
|
mp4_support: 'none' | 'standard'
|
|
17
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Max resolution tier can be used to control the maximum resolution_tier your asset is encoded, stored, and streamed at.
|
|
15
|
+
* Requires `"encoding_tier": "smart"`
|
|
16
|
+
* @see {@link https://docs.mux.com/guides/stream-videos-in-4k}
|
|
17
|
+
* @defaultValue '1080p'
|
|
18
|
+
*/
|
|
19
|
+
max_resolution_tier: '2160p' | '1440p' | '1080p'
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The encoding tier informs the cost, quality, and available platform features for the asset.
|
|
23
|
+
* @see {@link https://docs.mux.com/guides/use-encoding-tiers}
|
|
24
|
+
* @defaultValue 'smart'
|
|
25
|
+
*/
|
|
26
|
+
encoding_tier: 'baseline' | 'smart'
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Normalize the audio track loudness level.
|
|
30
|
+
* @see {@link https://docs.mux.com/guides/adjust-audio-levels#how-to-turn-on-audio-normalization}
|
|
31
|
+
* @defaultValue false
|
|
32
|
+
*/
|
|
33
|
+
normalize_audio: boolean
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Enables signed URLs by default, if you configured them with your API token.
|
|
37
|
+
* @see {@link https://docs.mux.com/guides/secure-video-playback}
|
|
38
|
+
* @defaultValue false
|
|
39
|
+
*/
|
|
40
|
+
defaultSigned?: boolean
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Auto-generate captions for these languages by default.
|
|
44
|
+
* Requires `"encoding_tier": "smart"`
|
|
45
|
+
*
|
|
46
|
+
* @see {@link https://docs.mux.com/guides/secure-video-playback}
|
|
47
|
+
* @defaultValue false
|
|
48
|
+
*/
|
|
49
|
+
defaultAutogeneratedSubtitleLangs?: SupportedMuxLanguage[]
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Whether or not to allow content editors to override asset upload
|
|
53
|
+
* configuration settings when uploading a video to Mux.
|
|
54
|
+
*
|
|
55
|
+
* @see {@link https://docs.mux.com/guides/secure-video-playback}
|
|
56
|
+
* @defaultValue false
|
|
57
|
+
*/
|
|
58
|
+
disableUploadConfig?: boolean
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Whether or not to allow content editors to add text tracks alongside their
|
|
62
|
+
* asset when uploading a video to Mux.
|
|
63
|
+
*
|
|
64
|
+
* @see {@link https://docs.mux.com/guides/secure-video-playback}
|
|
65
|
+
* @defaultValue false
|
|
66
|
+
*/
|
|
67
|
+
disableTextTrackConfig?: boolean
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface PluginConfig extends MuxInputConfig {
|
|
18
71
|
/**
|
|
19
72
|
* How the videos browser should appear as a studio tool in Sanity's top navigation
|
|
20
73
|
*
|
|
21
74
|
* Pass `false` if you want to disable it.
|
|
75
|
+
* @defaultValue {title: 'Videos', icon: VideoIcon}
|
|
22
76
|
**/
|
|
23
|
-
tool
|
|
77
|
+
tool:
|
|
24
78
|
| false
|
|
25
79
|
| {
|
|
26
80
|
title?: string
|
|
@@ -28,6 +82,130 @@ export interface Config {
|
|
|
28
82
|
}
|
|
29
83
|
}
|
|
30
84
|
|
|
85
|
+
export const SUPPORTED_MUX_LANGUAGES = [
|
|
86
|
+
{label: 'English', code: 'en', state: 'Stable'},
|
|
87
|
+
{label: 'Spanish', code: 'es', state: 'Stable'},
|
|
88
|
+
{label: 'Italian', code: 'it', state: 'Stable'},
|
|
89
|
+
{label: 'Portuguese', code: 'pt', state: 'Stable'},
|
|
90
|
+
{label: 'German', code: 'de', state: 'Stable'},
|
|
91
|
+
{label: 'French', code: 'fr', state: 'Stable'},
|
|
92
|
+
{label: 'Polish', code: 'pl', state: 'Beta'},
|
|
93
|
+
{label: 'Russian', code: 'ru', state: 'Beta'},
|
|
94
|
+
{label: 'Dutch', code: 'nl', state: 'Beta'},
|
|
95
|
+
{label: 'Catalan', code: 'ca', state: 'Beta'},
|
|
96
|
+
{label: 'Turkish', code: 'tr', state: 'Beta'},
|
|
97
|
+
{label: 'Swedish', code: 'sv', state: 'Beta'},
|
|
98
|
+
{label: 'Ukrainian', code: 'uk', state: 'Beta'},
|
|
99
|
+
{label: 'Norwegian', code: 'no', state: 'Beta'},
|
|
100
|
+
{label: 'Finnish', code: 'fi', state: 'Beta'},
|
|
101
|
+
{label: 'Slovak', code: 'sk', state: 'Beta'},
|
|
102
|
+
{label: 'Greek', code: 'el', state: 'Beta'},
|
|
103
|
+
{label: 'Czech', code: 'cs', state: 'Beta'},
|
|
104
|
+
{label: 'Croatian', code: 'hr', state: 'Beta'},
|
|
105
|
+
{label: 'Danish', code: 'da', state: 'Beta'},
|
|
106
|
+
{label: 'Romanian', code: 'ro', state: 'Beta'},
|
|
107
|
+
{label: 'Bulgarian', code: 'bg', state: 'Beta'},
|
|
108
|
+
] as const
|
|
109
|
+
|
|
110
|
+
export const ENCODING_TIERS = [
|
|
111
|
+
{label: 'Baseline', value: 'baseline'},
|
|
112
|
+
{label: 'Smart', value: 'smart'},
|
|
113
|
+
] as const
|
|
114
|
+
|
|
115
|
+
export const SUPPORTED_MUX_LANGUAGES_VALUES = SUPPORTED_MUX_LANGUAGES.map((l) => l.code)
|
|
116
|
+
|
|
117
|
+
export type SupportedMuxLanguage = (typeof SUPPORTED_MUX_LANGUAGES_VALUES)[number]
|
|
118
|
+
|
|
119
|
+
export interface TextTrack {
|
|
120
|
+
_id: string
|
|
121
|
+
name: string
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface AutogeneratedTextTrack extends TextTrack {
|
|
125
|
+
type: 'autogenerated'
|
|
126
|
+
language_code: SupportedMuxLanguage
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface CustomTextTrack extends TextTrack {
|
|
130
|
+
type: 'subtitles' | 'captions'
|
|
131
|
+
language_code: string
|
|
132
|
+
file: {
|
|
133
|
+
contents: string
|
|
134
|
+
type: string
|
|
135
|
+
name: string
|
|
136
|
+
size: number
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function isCustomTextTrack(track: Partial<UploadTextTrack>): track is CustomTextTrack {
|
|
141
|
+
return track.type !== 'autogenerated'
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function isAutogeneratedTrack(
|
|
145
|
+
track: Partial<UploadTextTrack>
|
|
146
|
+
): track is AutogeneratedTextTrack {
|
|
147
|
+
return track.type === 'autogenerated'
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export type UploadTextTrack = AutogeneratedTextTrack | CustomTextTrack
|
|
151
|
+
|
|
152
|
+
export interface UploadConfig
|
|
153
|
+
extends Pick<
|
|
154
|
+
MuxInputConfig,
|
|
155
|
+
'encoding_tier' | 'max_resolution_tier' | 'mp4_support' | 'normalize_audio'
|
|
156
|
+
> {
|
|
157
|
+
text_tracks: UploadTextTrack[]
|
|
158
|
+
signed: boolean
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Data sent to Mux to create a new asset.
|
|
163
|
+
* @docs {@link https://docs.mux.com/api-reference#video/operation/create-direct-upload}
|
|
164
|
+
*/
|
|
165
|
+
export interface MuxNewAssetSettings
|
|
166
|
+
extends Pick<
|
|
167
|
+
MuxInputConfig,
|
|
168
|
+
'encoding_tier' | 'max_resolution_tier' | 'mp4_support' | 'normalize_audio'
|
|
169
|
+
> {
|
|
170
|
+
/** An array of objects that each describe an input file to be used to create the asset.*/
|
|
171
|
+
input?: {
|
|
172
|
+
/** The URL of the file that Mux should download and use. */
|
|
173
|
+
url?: string
|
|
174
|
+
/** Generate subtitle tracks using automatic speech recognition with this configuration. This may only be provided for the first input object (the main input file). */
|
|
175
|
+
generated_subtitles?: {
|
|
176
|
+
/** A name for this subtitle track. */
|
|
177
|
+
name: string
|
|
178
|
+
/** Arbitrary metadata set for the subtitle track. Max 255 characters. */
|
|
179
|
+
passthrough?: string
|
|
180
|
+
/** The language to generate subtitles in. */
|
|
181
|
+
language_code: SupportedMuxLanguage
|
|
182
|
+
}[]
|
|
183
|
+
/** The time offset in seconds from the beginning of the video indicating the clip's starting marker. */
|
|
184
|
+
start_time?: number
|
|
185
|
+
/** The time offset in seconds from the beginning of the video indicating the clip's ending marker. */
|
|
186
|
+
end_time?: number
|
|
187
|
+
/** This parameter is required for text type tracks. */
|
|
188
|
+
type: 'video' | 'audio' | 'text'
|
|
189
|
+
/** Type of text track. This parameter only supports subtitles value. */
|
|
190
|
+
text_type?: 'subtitles'
|
|
191
|
+
/** The language code value must be a valid BCP 47 specification compliant value. */
|
|
192
|
+
language_code?: string
|
|
193
|
+
/** The name of the track containing a human-readable description. This value must be unique within each group of text or audio track types. */
|
|
194
|
+
name?: string
|
|
195
|
+
/** Indicates the track provides Subtitles for the Deaf or Hard-of-hearing (SDH). */
|
|
196
|
+
closed_captions?: boolean
|
|
197
|
+
/// @TODO Huhh?>?? Below
|
|
198
|
+
/** This optional parameter should be used tracks with type of text and text_type set to subtitles. */
|
|
199
|
+
passthrough?: string
|
|
200
|
+
}[]
|
|
201
|
+
|
|
202
|
+
/** An array of playback policy names that you want applied to this asset and available through playback_ids. */
|
|
203
|
+
playback_policy: ('public' | 'signed')[]
|
|
204
|
+
|
|
205
|
+
/** Arbitrary user-supplied metadata that will be included in the asset details and related webhooks. */
|
|
206
|
+
passthrough?: string
|
|
207
|
+
}
|
|
208
|
+
|
|
31
209
|
export interface Secrets {
|
|
32
210
|
token: string | null
|
|
33
211
|
secretKey: string | null
|
|
@@ -35,6 +213,7 @@ export interface Secrets {
|
|
|
35
213
|
signingKeyId: string | null
|
|
36
214
|
signingKeyPrivate: string | null
|
|
37
215
|
}
|
|
216
|
+
|
|
38
217
|
// This narrowed type indicates that there may be assets that are signed, and we have the secrets to access them
|
|
39
218
|
// enabledSignedUrls might be false but that's only relevant for future uploads and their playback policy
|
|
40
219
|
export interface SignableSecrets extends Omit<Secrets, 'signingKeyId' | 'signingKeyPrivate'> {
|
|
@@ -123,6 +302,7 @@ export type MuxTrack = MuxVideoTrack | MuxAudioTrack
|
|
|
123
302
|
// Typings lifted from https://docs.mux.com/api-reference/video#tag/assets
|
|
124
303
|
export interface MuxAsset {
|
|
125
304
|
id: string
|
|
305
|
+
/** In seconds (instead of JS's default milliseconds) */
|
|
126
306
|
created_at: string
|
|
127
307
|
status: 'preparing' | 'ready' | 'errored'
|
|
128
308
|
duration: number
|
|
@@ -183,8 +363,11 @@ export interface MuxAsset {
|
|
|
183
363
|
}
|
|
184
364
|
}
|
|
185
365
|
|
|
186
|
-
export interface VideoAssetDocument
|
|
187
|
-
|
|
366
|
+
export interface VideoAssetDocument {
|
|
367
|
+
_id: string
|
|
368
|
+
_type: 'mux.videoAsset'
|
|
369
|
+
_createdAt: string
|
|
370
|
+
_updatedAt?: string
|
|
188
371
|
status?: string
|
|
189
372
|
assetId?: string
|
|
190
373
|
playbackId?: string
|
package/lib/index.cjs.js
DELETED
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-nested-ternary */
|
|
2
|
-
// This component needs to be refactored into a functional component
|
|
3
|
-
|
|
4
|
-
import React, {Component} from 'react'
|
|
5
|
-
import {type Observable, Subject} from 'rxjs'
|
|
6
|
-
import {takeUntil, tap} from 'rxjs/operators'
|
|
7
|
-
import type {SanityClient} from 'sanity'
|
|
8
|
-
import {PatchEvent, set, setIfMissing} from 'sanity'
|
|
9
|
-
|
|
10
|
-
import {uploadFile, uploadUrl} from '../actions/upload'
|
|
11
|
-
import {type DialogState, type SetDialogState} from '../hooks/useDialogState'
|
|
12
|
-
import {extractDroppedFiles} from '../util/extractFiles'
|
|
13
|
-
import type {Config, MuxInputProps, Secrets, VideoAssetDocument} from '../util/types'
|
|
14
|
-
import InputBrowser from './InputBrowser'
|
|
15
|
-
import Player from './Player'
|
|
16
|
-
import PlayerActionsMenu from './PlayerActionsMenu'
|
|
17
|
-
import {UploadCard} from './Uploader.styled'
|
|
18
|
-
import UploadPlaceholder from './UploadPlaceholder'
|
|
19
|
-
import {UploadProgress} from './UploadProgress'
|
|
20
|
-
|
|
21
|
-
interface Props extends Pick<MuxInputProps, 'onChange' | 'readOnly'> {
|
|
22
|
-
config: Config
|
|
23
|
-
client: SanityClient
|
|
24
|
-
secrets: Secrets
|
|
25
|
-
asset: VideoAssetDocument | null | undefined
|
|
26
|
-
dialogState: DialogState
|
|
27
|
-
setDialogState: SetDialogState
|
|
28
|
-
needsSetup: boolean
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
interface State {
|
|
32
|
-
isDraggingOver: boolean
|
|
33
|
-
invalidPaste: boolean
|
|
34
|
-
invalidFile: boolean
|
|
35
|
-
fileInfo: {name?: string; type?: string} | null
|
|
36
|
-
uuid: null
|
|
37
|
-
uploadProgress: number | null
|
|
38
|
-
error: Error | null
|
|
39
|
-
url: string | null
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
class MuxVideoInputUploader extends Component<Props, State> {
|
|
43
|
-
state: State = {
|
|
44
|
-
isDraggingOver: false,
|
|
45
|
-
invalidPaste: false,
|
|
46
|
-
invalidFile: false,
|
|
47
|
-
uploadProgress: null,
|
|
48
|
-
fileInfo: null,
|
|
49
|
-
uuid: null,
|
|
50
|
-
error: null,
|
|
51
|
-
url: null,
|
|
52
|
-
}
|
|
53
|
-
dragEnteredEls: EventTarget[] = []
|
|
54
|
-
|
|
55
|
-
ctrlDown = false
|
|
56
|
-
|
|
57
|
-
// eslint-disable-next-line no-warning-comments
|
|
58
|
-
// @TODO add proper typings for the return values of uploadFile and uploadUrl
|
|
59
|
-
upload: any | null = null
|
|
60
|
-
|
|
61
|
-
container = React.createRef<HTMLDivElement>()
|
|
62
|
-
|
|
63
|
-
onCancelUploadButtonClick$: Observable<unknown> | undefined
|
|
64
|
-
handleCancelUploadButtonClick: React.MouseEventHandler<HTMLButtonElement> | undefined
|
|
65
|
-
|
|
66
|
-
componentWillUnmount() {
|
|
67
|
-
this.unSubscribeToUpload()
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
componentDidMount() {
|
|
71
|
-
const events$ = new Subject()
|
|
72
|
-
this.onCancelUploadButtonClick$ = events$.asObservable()
|
|
73
|
-
this.handleCancelUploadButtonClick = (event) => events$.next(event)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
unSubscribeToUpload() {
|
|
77
|
-
if (this.upload && !this.upload.closed) {
|
|
78
|
-
this.upload.unsubscribe()
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
handleProgress = (evt: {percent: number}) => {
|
|
83
|
-
this.setState({uploadProgress: evt.percent})
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
onUpload = (files: FileList | File[]) => {
|
|
87
|
-
this.setState({uploadProgress: 0, fileInfo: null, uuid: null})
|
|
88
|
-
this.upload = uploadFile(this.props.config, this.props.client, files[0], {
|
|
89
|
-
enableSignedUrls: this.props.secrets.enableSignedUrls,
|
|
90
|
-
})
|
|
91
|
-
.pipe(
|
|
92
|
-
takeUntil(
|
|
93
|
-
this.onCancelUploadButtonClick$!.pipe(
|
|
94
|
-
tap(() => {
|
|
95
|
-
if (this.state.uuid) {
|
|
96
|
-
this.props.client.delete(this.state.uuid)
|
|
97
|
-
}
|
|
98
|
-
})
|
|
99
|
-
)
|
|
100
|
-
)
|
|
101
|
-
)
|
|
102
|
-
.subscribe({
|
|
103
|
-
complete: () => {
|
|
104
|
-
this.setState({error: null, uploadProgress: null, uuid: null})
|
|
105
|
-
},
|
|
106
|
-
next: (event) => {
|
|
107
|
-
this.handleUploadEvent(event)
|
|
108
|
-
},
|
|
109
|
-
error: (err) => {
|
|
110
|
-
this.setState({error: err, uploadProgress: null, uuid: null})
|
|
111
|
-
},
|
|
112
|
-
})
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// eslint-disable-next-line no-warning-comments
|
|
116
|
-
// @TODO add proper typings for the Observable events
|
|
117
|
-
handleUploadEvent = (event: any) => {
|
|
118
|
-
switch (event.type) {
|
|
119
|
-
case 'success':
|
|
120
|
-
return this.handleUploadSuccess(event.asset)
|
|
121
|
-
case 'progress':
|
|
122
|
-
return this.handleProgress(event)
|
|
123
|
-
case 'file':
|
|
124
|
-
return this.setState({fileInfo: event.file})
|
|
125
|
-
case 'uuid':
|
|
126
|
-
// Means we created a mux.videoAsset document with an uuid
|
|
127
|
-
return this.setState({uuid: event.uuid})
|
|
128
|
-
case 'url':
|
|
129
|
-
return this.setState({url: event.url, uploadProgress: 100})
|
|
130
|
-
default:
|
|
131
|
-
return null
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
handleUploadSuccess = (asset: VideoAssetDocument) => {
|
|
136
|
-
this.setState({uploadProgress: 100})
|
|
137
|
-
this.props.onChange(
|
|
138
|
-
PatchEvent.from([
|
|
139
|
-
setIfMissing({asset: {}}),
|
|
140
|
-
set({_type: 'reference', _weak: true, _ref: asset._id}, ['asset']),
|
|
141
|
-
])
|
|
142
|
-
)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
handlePaste: React.ClipboardEventHandler<HTMLInputElement> = (event) => {
|
|
146
|
-
const clipboardData = event.clipboardData || (window as any).clipboardData
|
|
147
|
-
const url = clipboardData.getData('text')
|
|
148
|
-
const options = {enableSignedUrls: this.props.secrets.enableSignedUrls}
|
|
149
|
-
|
|
150
|
-
this.upload = uploadUrl(this.props.config, this.props.client, url, options).subscribe({
|
|
151
|
-
complete: () => {
|
|
152
|
-
this.setState({error: null, uploadProgress: null, url: null})
|
|
153
|
-
},
|
|
154
|
-
next: (sEvent) => {
|
|
155
|
-
this.handleUploadEvent(sEvent)
|
|
156
|
-
},
|
|
157
|
-
error: (err) => {
|
|
158
|
-
let error
|
|
159
|
-
// Don't output error dialog when just invalid url
|
|
160
|
-
if (!err.message.toLowerCase().match('invalid url')) {
|
|
161
|
-
error = err
|
|
162
|
-
}
|
|
163
|
-
this.setState({invalidPaste: true, error}, () => {
|
|
164
|
-
setTimeout(() => {
|
|
165
|
-
this.setState({invalidPaste: false, uploadProgress: null})
|
|
166
|
-
}, 2000)
|
|
167
|
-
})
|
|
168
|
-
},
|
|
169
|
-
})
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
handleDrop: React.DragEventHandler<HTMLDivElement> = (event) => {
|
|
173
|
-
this.setState({isDraggingOver: false})
|
|
174
|
-
event.preventDefault()
|
|
175
|
-
event.stopPropagation()
|
|
176
|
-
extractDroppedFiles(event.nativeEvent.dataTransfer!).then((files) => {
|
|
177
|
-
if (files) {
|
|
178
|
-
// eslint-disable-next-line no-warning-comments
|
|
179
|
-
// @TODO fix the typing on files
|
|
180
|
-
this.onUpload(files as any)
|
|
181
|
-
}
|
|
182
|
-
})
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
handleDragOver: React.DragEventHandler<HTMLDivElement> = (event) => {
|
|
186
|
-
event.preventDefault()
|
|
187
|
-
event.stopPropagation()
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
handleDragEnter: React.DragEventHandler<HTMLDivElement> = (event) => {
|
|
191
|
-
event.stopPropagation()
|
|
192
|
-
this.dragEnteredEls.push(event.target)
|
|
193
|
-
this.setState({isDraggingOver: true})
|
|
194
|
-
const type = event.dataTransfer.items?.[0]?.type
|
|
195
|
-
this.setState({invalidFile: !type.startsWith('video/')})
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
handleDragLeave: React.DragEventHandler<HTMLDivElement> = (event) => {
|
|
199
|
-
event.stopPropagation()
|
|
200
|
-
const idx = this.dragEnteredEls.indexOf(event.target)
|
|
201
|
-
if (idx > -1) {
|
|
202
|
-
this.dragEnteredEls.splice(idx, 1)
|
|
203
|
-
}
|
|
204
|
-
if (this.dragEnteredEls.length === 0) {
|
|
205
|
-
this.setState({isDraggingOver: false})
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
render() {
|
|
210
|
-
if (this.state.uploadProgress !== null) {
|
|
211
|
-
return (
|
|
212
|
-
<UploadProgress
|
|
213
|
-
onCancel={this.handleCancelUploadButtonClick!}
|
|
214
|
-
progress={this.state.uploadProgress}
|
|
215
|
-
filename={this.state.fileInfo?.name || this.state.url}
|
|
216
|
-
/>
|
|
217
|
-
)
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (this.state.error) {
|
|
221
|
-
// @TODO better error handling
|
|
222
|
-
throw this.state.error
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return (
|
|
226
|
-
<>
|
|
227
|
-
<UploadCard
|
|
228
|
-
tone={
|
|
229
|
-
this.state.isDraggingOver && (this.state.invalidPaste || this.state.invalidFile)
|
|
230
|
-
? 'critical'
|
|
231
|
-
: this.state.isDraggingOver
|
|
232
|
-
? 'positive'
|
|
233
|
-
: undefined
|
|
234
|
-
}
|
|
235
|
-
onDrop={this.handleDrop}
|
|
236
|
-
onDragOver={this.handleDragOver}
|
|
237
|
-
onDragLeave={this.handleDragLeave}
|
|
238
|
-
onDragEnter={this.handleDragEnter}
|
|
239
|
-
onPaste={this.handlePaste}
|
|
240
|
-
ref={this.container}
|
|
241
|
-
>
|
|
242
|
-
{this.props.asset ? (
|
|
243
|
-
<Player
|
|
244
|
-
readOnly={this.props.readOnly}
|
|
245
|
-
asset={this.props.asset}
|
|
246
|
-
onChange={this.props.onChange}
|
|
247
|
-
buttons={
|
|
248
|
-
<PlayerActionsMenu
|
|
249
|
-
asset={this.props.asset}
|
|
250
|
-
dialogState={this.props.dialogState}
|
|
251
|
-
setDialogState={this.props.setDialogState}
|
|
252
|
-
onChange={this.props.onChange}
|
|
253
|
-
onUpload={this.onUpload}
|
|
254
|
-
readOnly={this.props.readOnly}
|
|
255
|
-
/>
|
|
256
|
-
}
|
|
257
|
-
/>
|
|
258
|
-
) : (
|
|
259
|
-
<UploadPlaceholder
|
|
260
|
-
hovering={this.state.isDraggingOver}
|
|
261
|
-
onSelect={this.onUpload}
|
|
262
|
-
readOnly={this.props.readOnly!}
|
|
263
|
-
setDialogState={this.props.setDialogState}
|
|
264
|
-
needsSetup={this.props.needsSetup}
|
|
265
|
-
/>
|
|
266
|
-
)}
|
|
267
|
-
</UploadCard>
|
|
268
|
-
{this.props.dialogState === 'select-video' && (
|
|
269
|
-
<InputBrowser
|
|
270
|
-
asset={this.props.asset}
|
|
271
|
-
onChange={this.props.onChange}
|
|
272
|
-
setDialogState={this.props.setDialogState}
|
|
273
|
-
/>
|
|
274
|
-
)}
|
|
275
|
-
</>
|
|
276
|
-
)
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
export default MuxVideoInputUploader
|
package/src/index.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import {definePlugin} from 'sanity'
|
|
2
|
-
|
|
3
|
-
import createStudioTool from './components/StudioTool'
|
|
4
|
-
import {muxVideoCustomRendering} from './plugin'
|
|
5
|
-
import {muxVideo, muxVideoAsset} from './schema'
|
|
6
|
-
import type {Config} from './util/types'
|
|
7
|
-
|
|
8
|
-
export type {VideoAssetDocument} from './util/types'
|
|
9
|
-
|
|
10
|
-
export const defaultConfig: Config = {
|
|
11
|
-
mp4_support: 'none',
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const muxInput = definePlugin<Partial<Config> | void>((userConfig) => {
|
|
15
|
-
const config: Config = {...defaultConfig, ...userConfig}
|
|
16
|
-
return {
|
|
17
|
-
name: 'mux-input',
|
|
18
|
-
schema: {
|
|
19
|
-
types: [
|
|
20
|
-
muxVideoAsset,
|
|
21
|
-
{
|
|
22
|
-
...muxVideo,
|
|
23
|
-
...muxVideoCustomRendering(config),
|
|
24
|
-
},
|
|
25
|
-
],
|
|
26
|
-
},
|
|
27
|
-
tools: config.tool === false ? undefined : [createStudioTool(config)],
|
|
28
|
-
}
|
|
29
|
-
})
|