Skip to content

Commit fbff5da

Browse files
robinpyonhdoro
authored andcommitted
feat: Adds opt-in support mp4 generation (refs #10)
This update exposes a `mux-input.json` config file where users can opt-in to mp4 support. Polling behaviour has been updated to listen for static renditions completed on MUX's end. If a user has opted in, a small badge / reminder is also displayed over the video input when static generation is still in progress.
1 parent b92c929 commit fbff5da

File tree

6 files changed

+84
-9
lines changed

6 files changed

+84
-9
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,18 @@ To enable [signed urls](https://docs.mux.com/docs/security-signed-urls) with con
5959

6060
More information for this feature of the plugin can be found on Mux's [documentation](https://docs.mux.com/docs/headless-cms-sanity#advanced-signed-urls)
6161

62+
# Enabling MP4 support
63+
64+
To enable [static MP4 renditions](https://docs.mux.com/guides/video/enable-static-mp4-renditions), create or open the config file found in `config/mux-input.json` in your studio folder. This file is automatically created the first time the studio starts after adding the plugin.
65+
66+
```
67+
{
68+
"mp4_support": "standard"
69+
}
70+
```
71+
72+
Currently `mp4_support` is the only supported MUX option and this supports a value of either `standard` or `none` (the default).
73+
6274
# Contributing
6375

6476
Issues are actively monitored and PRs are welcome. When developing this plugin the easiest setup is:

config.dist.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"mp4_support": "none"
3+
}

src/actions/upload.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable camelcase */
22
import {uuid as generateUuid} from '@sanity/uuid'
3+
import config from '../config'
34
import {isString} from 'lodash'
45
import {concat, defer, from, of, throwError} from 'rxjs'
56
import {catchError, mergeMap, mergeMapTo, switchMap} from 'rxjs/operators'
@@ -31,11 +32,13 @@ export function uploadUrl(url, options = {}) {
3132
const muxBody = {
3233
input: validUrl,
3334
playback_policy: [enableSignedUrls ? 'signed' : 'public'],
35+
mp4_support: config.mp4_support,
3436
}
3537
const query = {
3638
muxBody: JSON.stringify(muxBody),
3739
filename: validUrl.split('/').slice(-1)[0],
3840
}
41+
3942
const dataset = client.clientConfig.dataset
4043
return defer(() =>
4144
client.observable.request({
@@ -53,6 +56,7 @@ export function uploadUrl(url, options = {}) {
5356
const asset =
5457
(result && result.results && result.results[0] && result.results[0].document) ||
5558
null
59+
5660
if (!asset) {
5761
return throwError(new Error('No asset document returned'))
5862
}
@@ -79,12 +83,10 @@ export function uploadFile(file, options = {}) {
7983
const uuid = generateUuid()
8084
const {enableSignedUrls} = options
8185
const body = {
86+
mp4_support: config.mp4_support,
8287
playback_policy: [enableSignedUrls ? 'signed' : 'public'],
83-
// TODO: These parameters were enabled by Sanity, but we are not using them yet
84-
// mp4_support: false (default),
85-
// normalize_audio: false (default),
86-
// master_access: false (default),
8788
}
89+
8890
return concat(
8991
of({type: 'uuid', uuid}),
9092
defer(() =>
@@ -178,6 +180,7 @@ async function updateAssetDocumentFromUpload(uuid) {
178180
} catch (err) {
179181
return Promise.reject(err)
180182
}
183+
181184
const doc = {
182185
_id: uuid,
183186
_type: 'mux.videoAsset',

src/components/Input.js

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import SelectAsset from './SelectAsset'
3333
import Setup from './Setup'
3434
import Uploader from './Uploader'
3535
import Video from './Video'
36+
import config from '../config'
3637

3738
const NOOP = () => {
3839
/* intentional noop */
@@ -177,12 +178,31 @@ export default withDocument(
177178
})
178179
})
179180
}
180-
if (assetDocument && assetDocument.status === 'preparing') {
181+
// Poll MUX if it's preparing the main document or its own static renditions
182+
if (
183+
assetDocument?.status === 'preparing' ||
184+
assetDocument?.data?.static_renditions?.status === 'preparing'
185+
) {
181186
this.pollMux()
182187
}
188+
// If MP4 support is enabled: MUX will prepare static_renditions only _after_ an asset
189+
// has been successfully uploaded.
190+
// A _ready_ asset doesn't mean static mp4s are generated and ready for use!
191+
// In these cases, wait for `static_renditions.status === 'ready'` before clearing the poll interval.
183192
if (assetDocument && assetDocument.status === 'ready') {
184-
clearInterval(this.pollInterval)
185-
this.pollInterval = null
193+
switch (config.mp4_support) {
194+
case 'standard':
195+
if (assetDocument?.data?.static_renditions?.status === 'ready') {
196+
clearInterval(this.pollInterval)
197+
this.pollInterval = null
198+
}
199+
break
200+
case 'none':
201+
default:
202+
clearInterval(this.pollInterval)
203+
this.pollInterval = null
204+
break
205+
}
186206
}
187207

188208
// eslint-disable-next-line camelcase
@@ -207,6 +227,8 @@ export default withDocument(
207227
getAsset(assetDocument.assetId)
208228
.then((response) => {
209229
const props = response.data
230+
231+
// TODO: consider a deep comparison on `props` with asset data and only patch only if it's changed
210232
client
211233
.patch(assetDocument._id)
212234
.set({

src/components/Video.js

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {Card, Stack, Text} from '@sanity/ui'
1+
import {Box, Card, Stack, Text} from '@sanity/ui'
22
import Hls from 'hls.js'
33
import 'media-chrome'
44
import Button from 'part:@sanity/components/buttons/default'
@@ -37,6 +37,7 @@ class MuxVideo extends Component {
3737
isLoading: true,
3838
error: null,
3939
isDeletedOnMux: false,
40+
isPreparingStaticRenditions: false,
4041
secrets: null,
4142
}
4243
this.playRef = React.createRef()
@@ -46,6 +47,7 @@ class MuxVideo extends Component {
4647
// eslint-disable-next-line complexity
4748
static getDerivedStateFromProps(nextProps) {
4849
let isLoading = true
50+
let isPreparingStaticRenditions = false
4951
const {assetDocument} = nextProps
5052

5153
if (assetDocument && assetDocument.status === 'preparing') {
@@ -63,7 +65,16 @@ class MuxVideo extends Component {
6365
if (assetDocument && typeof assetDocument.status === 'undefined') {
6466
isLoading = false
6567
}
66-
return {isLoading}
68+
if (assetDocument?.data?.static_renditions?.status === 'preparing') {
69+
isPreparingStaticRenditions = true
70+
}
71+
if (assetDocument?.data?.static_renditions?.status === 'ready') {
72+
isPreparingStaticRenditions = false
73+
}
74+
return {
75+
isLoading,
76+
isPreparingStaticRenditions,
77+
}
6778
}
6879

6980
componentDidMount() {
@@ -234,6 +245,7 @@ class MuxVideo extends Component {
234245
<track label="thumbnails" default kind="metadata" src={this.state.storyboardUrl} />
235246
)}
236247
</video>
248+
237249
{showControls && (
238250
<media-control-bar>
239251
<media-play-button ref={this.playRef} />
@@ -252,6 +264,23 @@ class MuxVideo extends Component {
252264
</Stack>
253265
</Card>
254266
)}
267+
268+
{this.state.isPreparingStaticRenditions && (
269+
<Card
270+
padding={2}
271+
radius={1}
272+
style={{
273+
background: 'var(--card-fg-color)',
274+
position: 'absolute',
275+
top: '0.5em',
276+
left: '0.5em',
277+
}}
278+
>
279+
<Text size={1} style={{color: 'var(--card-bg-color)'}}>
280+
MUX is preparing static renditions, please stand by
281+
</Text>
282+
</Card>
283+
)}
255284
</div>
256285
)
257286
}

src/config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/* eslint-disable camelcase */
2+
import config from 'config:mux-input'
3+
4+
export default {
5+
mp4_support: config?.mp4_support || 'none',
6+
}

0 commit comments

Comments
 (0)