Skip to content

Commit

Permalink
feat: Adds opt-in support mp4 generation (refs #10)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
robinpyon authored and hdoro committed Oct 7, 2021
1 parent b92c929 commit fbff5da
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 9 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ To enable [signed urls](https://docs.mux.com/docs/security-signed-urls) with con
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)

# Enabling MP4 support

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.

```
{
"mp4_support": "standard"
}
```

Currently `mp4_support` is the only supported MUX option and this supports a value of either `standard` or `none` (the default).

# Contributing

Issues are actively monitored and PRs are welcome. When developing this plugin the easiest setup is:
Expand Down
3 changes: 3 additions & 0 deletions config.dist.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"mp4_support": "none"
}
11 changes: 7 additions & 4 deletions src/actions/upload.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable camelcase */
import {uuid as generateUuid} from '@sanity/uuid'
import config from '../config'
import {isString} from 'lodash'
import {concat, defer, from, of, throwError} from 'rxjs'
import {catchError, mergeMap, mergeMapTo, switchMap} from 'rxjs/operators'
Expand Down Expand Up @@ -31,11 +32,13 @@ export function uploadUrl(url, options = {}) {
const muxBody = {
input: validUrl,
playback_policy: [enableSignedUrls ? 'signed' : 'public'],
mp4_support: config.mp4_support,
}
const query = {
muxBody: JSON.stringify(muxBody),
filename: validUrl.split('/').slice(-1)[0],
}

const dataset = client.clientConfig.dataset
return defer(() =>
client.observable.request({
Expand All @@ -53,6 +56,7 @@ export function uploadUrl(url, options = {}) {
const asset =
(result && result.results && result.results[0] && result.results[0].document) ||
null

if (!asset) {
return throwError(new Error('No asset document returned'))
}
Expand All @@ -79,12 +83,10 @@ export function uploadFile(file, options = {}) {
const uuid = generateUuid()
const {enableSignedUrls} = options
const body = {
mp4_support: config.mp4_support,
playback_policy: [enableSignedUrls ? 'signed' : 'public'],
// TODO: These parameters were enabled by Sanity, but we are not using them yet
// mp4_support: false (default),
// normalize_audio: false (default),
// master_access: false (default),
}

return concat(
of({type: 'uuid', uuid}),
defer(() =>
Expand Down Expand Up @@ -178,6 +180,7 @@ async function updateAssetDocumentFromUpload(uuid) {
} catch (err) {
return Promise.reject(err)
}

const doc = {
_id: uuid,
_type: 'mux.videoAsset',
Expand Down
28 changes: 25 additions & 3 deletions src/components/Input.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import SelectAsset from './SelectAsset'
import Setup from './Setup'
import Uploader from './Uploader'
import Video from './Video'
import config from '../config'

const NOOP = () => {
/* intentional noop */
Expand Down Expand Up @@ -177,12 +178,31 @@ export default withDocument(
})
})
}
if (assetDocument && assetDocument.status === 'preparing') {
// Poll MUX if it's preparing the main document or its own static renditions
if (
assetDocument?.status === 'preparing' ||
assetDocument?.data?.static_renditions?.status === 'preparing'
) {
this.pollMux()
}
// If MP4 support is enabled: MUX will prepare static_renditions only _after_ an asset
// has been successfully uploaded.
// A _ready_ asset doesn't mean static mp4s are generated and ready for use!
// In these cases, wait for `static_renditions.status === 'ready'` before clearing the poll interval.
if (assetDocument && assetDocument.status === 'ready') {
clearInterval(this.pollInterval)
this.pollInterval = null
switch (config.mp4_support) {
case 'standard':
if (assetDocument?.data?.static_renditions?.status === 'ready') {
clearInterval(this.pollInterval)
this.pollInterval = null
}
break
case 'none':
default:
clearInterval(this.pollInterval)
this.pollInterval = null
break
}
}

// eslint-disable-next-line camelcase
Expand All @@ -207,6 +227,8 @@ export default withDocument(
getAsset(assetDocument.assetId)
.then((response) => {
const props = response.data

// TODO: consider a deep comparison on `props` with asset data and only patch only if it's changed
client
.patch(assetDocument._id)
.set({
Expand Down
33 changes: 31 additions & 2 deletions src/components/Video.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Card, Stack, Text} from '@sanity/ui'
import {Box, Card, Stack, Text} from '@sanity/ui'
import Hls from 'hls.js'
import 'media-chrome'
import Button from 'part:@sanity/components/buttons/default'
Expand Down Expand Up @@ -37,6 +37,7 @@ class MuxVideo extends Component {
isLoading: true,
error: null,
isDeletedOnMux: false,
isPreparingStaticRenditions: false,
secrets: null,
}
this.playRef = React.createRef()
Expand All @@ -46,6 +47,7 @@ class MuxVideo extends Component {
// eslint-disable-next-line complexity
static getDerivedStateFromProps(nextProps) {
let isLoading = true
let isPreparingStaticRenditions = false
const {assetDocument} = nextProps

if (assetDocument && assetDocument.status === 'preparing') {
Expand All @@ -63,7 +65,16 @@ class MuxVideo extends Component {
if (assetDocument && typeof assetDocument.status === 'undefined') {
isLoading = false
}
return {isLoading}
if (assetDocument?.data?.static_renditions?.status === 'preparing') {
isPreparingStaticRenditions = true
}
if (assetDocument?.data?.static_renditions?.status === 'ready') {
isPreparingStaticRenditions = false
}
return {
isLoading,
isPreparingStaticRenditions,
}
}

componentDidMount() {
Expand Down Expand Up @@ -234,6 +245,7 @@ class MuxVideo extends Component {
<track label="thumbnails" default kind="metadata" src={this.state.storyboardUrl} />
)}
</video>

{showControls && (
<media-control-bar>
<media-play-button ref={this.playRef} />
Expand All @@ -252,6 +264,23 @@ class MuxVideo extends Component {
</Stack>
</Card>
)}

{this.state.isPreparingStaticRenditions && (
<Card
padding={2}
radius={1}
style={{
background: 'var(--card-fg-color)',
position: 'absolute',
top: '0.5em',
left: '0.5em',
}}
>
<Text size={1} style={{color: 'var(--card-bg-color)'}}>
MUX is preparing static renditions, please stand by
</Text>
</Card>
)}
</div>
)
}
Expand Down
6 changes: 6 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* eslint-disable camelcase */
import config from 'config:mux-input'

export default {
mp4_support: config?.mp4_support || 'none',
}

0 comments on commit fbff5da

Please sign in to comment.