sanity-plugin-mux-input 2.3.4 → 2.3.6

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.
@@ -4,7 +4,7 @@ import {Card, Text} from '@sanity/ui'
4
4
  import {type PropsWithChildren, useMemo} from 'react'
5
5
 
6
6
  import {useClient} from '../hooks/useClient'
7
- import {MIN_ASPECT_RATIO} from '../util/constants'
7
+ import {AUDIO_ASPECT_RATIO, MIN_ASPECT_RATIO} from '../util/constants'
8
8
  import {getVideoSrc} from '../util/getVideoSrc'
9
9
  import type {VideoAssetDocument} from '../util/types'
10
10
 
@@ -17,6 +17,8 @@ export default function VideoPlayer({
17
17
  >) {
18
18
  const client = useClient()
19
19
 
20
+ const isAudio = assetIsAudio(asset)
21
+
20
22
  const {src: videoSrc, error} = useMemo(() => {
21
23
  try {
22
24
  const src = asset?.playbackId && getVideoSrc({client, asset})
@@ -41,7 +43,13 @@ export default function VideoPlayer({
41
43
  const [width, height] = (asset?.data?.aspect_ratio ?? '16:9').split(':').map(Number)
42
44
  const targetAspectRatio =
43
45
  props.forceAspectRatio || (Number.isNaN(width) ? 16 / 9 : width / height)
44
- const aspectRatio = Math.max(MIN_ASPECT_RATIO, targetAspectRatio)
46
+ let aspectRatio = Math.max(MIN_ASPECT_RATIO, targetAspectRatio)
47
+ if (isAudio) {
48
+ aspectRatio = props.forceAspectRatio
49
+ ? // Make it wider when forcing aspect ratio to balance with videos' rendering height (audio players overflow a bit)
50
+ props.forceAspectRatio * 1.2
51
+ : AUDIO_ASPECT_RATIO
52
+ }
45
53
 
46
54
  return (
47
55
  <Card tone="transparent" style={{aspectRatio: aspectRatio, position: 'relative'}}>
@@ -63,6 +71,7 @@ export default function VideoPlayer({
63
71
  player_version: process.env.PKG_VERSION,
64
72
  page_type: 'Preview Player',
65
73
  }}
74
+ audio={isAudio}
66
75
  style={{
67
76
  height: '100%',
68
77
  width: '100%',
@@ -94,3 +103,7 @@ export default function VideoPlayer({
94
103
  </Card>
95
104
  )
96
105
  }
106
+
107
+ export function assetIsAudio(asset: VideoAssetDocument) {
108
+ return asset.data?.max_stored_resolution === 'Audio only'
109
+ }
@@ -6,7 +6,7 @@ import {styled} from 'styled-components'
6
6
  import {useClient} from '../hooks/useClient'
7
7
  import useInView from '../hooks/useInView'
8
8
  import {THUMBNAIL_ASPECT_RATIO} from '../util/constants'
9
- import {getAnimatedPosterSrc, type AnimatedPosterSrcOptions} from '../util/getAnimatedPosterSrc'
9
+ import {type AnimatedPosterSrcOptions, getAnimatedPosterSrc} from '../util/getAnimatedPosterSrc'
10
10
  import {VideoAssetDocument} from '../util/types'
11
11
 
12
12
  const Image = styled.img`
@@ -2,8 +2,8 @@
2
2
  // https://github.com/sanity-io/sanity/blob/next/packages/sanity/src/desk/components/paneItem/PaneItemPreview.tsx
3
3
  import {Inline} from '@sanity/ui'
4
4
  import {isNumber, isString} from 'lodash'
5
- import {isValidElement} from 'react'
6
- import {useMemoObservable} from 'react-rx'
5
+ import {isValidElement, useMemo} from 'react'
6
+ import {useObservable} from 'react-rx'
7
7
  import type {SanityDocument, SchemaType} from 'sanity'
8
8
  import type {PreviewValue} from 'sanity'
9
9
  import {
@@ -44,12 +44,15 @@ export function PaneItemPreview(props: PaneItemPreviewProps) {
44
44
  ? value.title
45
45
  : null
46
46
 
47
- // NOTE: this emits sync so can never be null
48
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
49
- const {draft, published, isLoading} = useMemoObservable<PaneItemPreviewState>(
47
+ const observable = useMemo(
50
48
  () => getPreviewStateObservable(props.documentPreviewStore, schemaType, value._id, title),
51
- [props.documentPreviewStore, schemaType, value._id, title]
52
- )!
49
+ [props.documentPreviewStore, schemaType, title, value._id]
50
+ )
51
+ const {draft, published, isLoading} = useObservable(observable, {
52
+ draft: null,
53
+ published: null,
54
+ isLoading: true,
55
+ })
53
56
 
54
57
  const status = isLoading ? null : (
55
58
  <Inline space={4}>
@@ -58,7 +58,7 @@ export default function useImportMuxAssets() {
58
58
 
59
59
  async function importAssets() {
60
60
  setImportState('importing')
61
- const documents = selectedAssets.map(muxAssetToSanityDocument)
61
+ const documents = selectedAssets.flatMap((asset) => muxAssetToSanityDocument(asset) || [])
62
62
 
63
63
  const tx = client.transaction()
64
64
  documents.forEach((doc) => tx.create(doc))
@@ -89,14 +89,18 @@ export default function useImportMuxAssets() {
89
89
  }
90
90
  }
91
91
 
92
- function muxAssetToSanityDocument(asset: MuxAsset): VideoAssetDocument {
92
+ function muxAssetToSanityDocument(asset: MuxAsset): VideoAssetDocument | undefined {
93
+ const playbackId = (asset.playback_ids || []).find((p) => p.id)?.id
94
+
95
+ if (!playbackId) return undefined
96
+
93
97
  return {
94
98
  _id: uuid(),
95
99
  _type: 'mux.videoAsset',
96
100
  _updatedAt: new Date().toISOString(),
97
101
  _createdAt: parseMuxDate(asset.created_at).toISOString(),
98
102
  assetId: asset.id,
99
- playbackId: asset.playback_ids.find((p) => p.id)?.id,
103
+ playbackId,
100
104
  filename: `Asset #${truncateString(asset.id, 15)}`,
101
105
  status: asset.status,
102
106
  data: asset,
package/src/schema.ts ADDED
@@ -0,0 +1,181 @@
1
+ export const muxVideoSchema = {
2
+ name: 'mux.video',
3
+ type: 'object',
4
+ title: 'Video asset reference',
5
+ fields: [
6
+ {
7
+ title: 'Video',
8
+ name: 'asset',
9
+ type: 'reference',
10
+ weak: true,
11
+ to: [{type: 'mux.videoAsset'}],
12
+ },
13
+ ],
14
+ }
15
+
16
+ const muxTrack = {
17
+ name: 'mux.track',
18
+ type: 'object',
19
+ fields: [
20
+ {type: 'string', name: 'id'},
21
+ {type: 'string', name: 'type'},
22
+ {type: 'number', name: 'max_width'},
23
+ {type: 'number', name: 'max_frame_rate'},
24
+ {type: 'number', name: 'duration'},
25
+ {type: 'number', name: 'max_height'},
26
+ ],
27
+ }
28
+
29
+ const muxPlaybackId = {
30
+ name: 'mux.playbackId',
31
+ type: 'object',
32
+ fields: [
33
+ {type: 'string', name: 'id'},
34
+ {type: 'string', name: 'policy'},
35
+ ],
36
+ }
37
+
38
+ const muxStaticRenditionFile = {
39
+ name: 'mux.staticRenditionFile',
40
+ type: 'object',
41
+ fields: [
42
+ {type: 'string', name: 'ext'},
43
+ {type: 'string', name: 'name'},
44
+ {type: 'number', name: 'width'},
45
+ {type: 'number', name: 'bitrate'},
46
+ {type: 'number', name: 'filesize'},
47
+ {type: 'number', name: 'height'},
48
+ ],
49
+ }
50
+
51
+ const muxStaticRenditions = {
52
+ name: 'mux.staticRenditions',
53
+ type: 'object',
54
+ fields: [
55
+ {type: 'string', name: 'status'},
56
+ {
57
+ name: 'files',
58
+ type: 'array',
59
+ of: [{type: 'mux.staticRenditionFile'}],
60
+ },
61
+ ],
62
+ }
63
+
64
+ const muxAssetData = {
65
+ name: 'mux.assetData',
66
+ title: 'Mux asset data',
67
+ type: 'object',
68
+ fields: [
69
+ {
70
+ type: 'string',
71
+ name: 'resolution_tier',
72
+ },
73
+ {
74
+ type: 'string',
75
+ name: 'upload_id',
76
+ },
77
+ {
78
+ type: 'string',
79
+ name: 'created_at',
80
+ },
81
+ {
82
+ type: 'string',
83
+ name: 'id',
84
+ },
85
+ {
86
+ type: 'string',
87
+ name: 'status',
88
+ },
89
+ {
90
+ type: 'string',
91
+ name: 'max_stored_resolution',
92
+ },
93
+ {
94
+ type: 'string',
95
+ name: 'passthrough',
96
+ },
97
+ {
98
+ type: 'string',
99
+ name: 'encoding_tier',
100
+ },
101
+ {
102
+ type: 'string',
103
+ name: 'master_access',
104
+ },
105
+ {
106
+ type: 'string',
107
+ name: 'aspect_ratio',
108
+ },
109
+ {
110
+ type: 'number',
111
+ name: 'duration',
112
+ },
113
+ {
114
+ type: 'number',
115
+ name: 'max_stored_frame_rate',
116
+ },
117
+ {
118
+ type: 'string',
119
+ name: 'mp4_support',
120
+ },
121
+ {
122
+ type: 'string',
123
+ name: 'max_resolution_tier',
124
+ },
125
+ {
126
+ name: 'tracks',
127
+ type: 'array',
128
+ of: [{type: 'mux.track'}],
129
+ },
130
+ {
131
+ name: 'playback_ids',
132
+ type: 'array',
133
+ of: [{type: 'mux.playbackId'}],
134
+ },
135
+ {
136
+ name: 'static_renditions',
137
+ type: 'mux.staticRenditions',
138
+ },
139
+ ],
140
+ }
141
+
142
+ const muxVideoAsset = {
143
+ name: 'mux.videoAsset',
144
+ type: 'object',
145
+ title: 'Video asset',
146
+ fields: [
147
+ {
148
+ type: 'string',
149
+ name: 'status',
150
+ },
151
+ {
152
+ type: 'string',
153
+ name: 'assetId',
154
+ },
155
+ {
156
+ type: 'string',
157
+ name: 'playbackId',
158
+ },
159
+ {
160
+ type: 'string',
161
+ name: 'filename',
162
+ },
163
+ {
164
+ type: 'number',
165
+ name: 'thumbTime',
166
+ },
167
+ {
168
+ type: 'mux.assetData',
169
+ name: 'data',
170
+ },
171
+ ],
172
+ }
173
+
174
+ export const schemaTypes = [
175
+ muxTrack,
176
+ muxPlaybackId,
177
+ muxStaticRenditionFile,
178
+ muxStaticRenditions,
179
+ muxAssetData,
180
+ muxVideoAsset,
181
+ ]
@@ -11,3 +11,5 @@ export const THUMBNAIL_ASPECT_RATIO = 16 / 9
11
11
 
12
12
  /** To prevent excessive height, thumbnails and input should not go beyond to this aspect ratio. */
13
13
  export const MIN_ASPECT_RATIO = 5 / 4
14
+
15
+ export const AUDIO_ASPECT_RATIO = 5 / 1
@@ -24,10 +24,10 @@ export function generateJwt<T extends Audience>(
24
24
  ): string {
25
25
  const {signingKeyId, signingKeyPrivate} = readSecrets(client)
26
26
  if (!signingKeyId) {
27
- throw new TypeError('Missing signingKeyId')
27
+ throw new TypeError("Missing `signingKeyId`.\n Check your plugin's configuration")
28
28
  }
29
29
  if (!signingKeyPrivate) {
30
- throw new TypeError('Missing signingKeyPrivate')
30
+ throw new TypeError("Missing `signingKeyPrivate`.\n Check your plugin's configuration")
31
31
  }
32
32
 
33
33
  // @ts-expect-error - handle missing typings for this package
package/src/util/types.ts CHANGED
@@ -43,11 +43,19 @@ export interface MuxInputConfig {
43
43
  * Auto-generate captions for these languages by default.
44
44
  * Requires `"encoding_tier": "smart"`
45
45
  *
46
- * @see {@link https://docs.mux.com/guides/secure-video-playback}
47
- * @defaultValue false
46
+ * @see {@link https://docs.mux.com/guides/add-autogenerated-captions-and-use-transcripts}
47
+ * @deprecated use `defaultAutogeneratedSubtitleLang` instead. Only a single autogenerated
48
48
  */
49
49
  defaultAutogeneratedSubtitleLangs?: SupportedMuxLanguage[]
50
50
 
51
+ /**
52
+ * Auto-generate captions for this language by default. Users can still
53
+ * Requires `"encoding_tier": "smart"`
54
+ *
55
+ * @see {@link https://docs.mux.com/guides/add-autogenerated-captions-and-use-transcripts}
56
+ */
57
+ defaultAutogeneratedSubtitleLang?: SupportedMuxLanguage
58
+
51
59
  /**
52
60
  * Whether or not to allow content editors to override asset upload
53
61
  * configuration settings when uploading a video to Mux.