diff --git a/README.md b/README.md index 782e4fba..ea2bd544 100644 --- a/README.md +++ b/README.md @@ -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: diff --git a/config.dist.json b/config.dist.json new file mode 100644 index 00000000..9859cb7b --- /dev/null +++ b/config.dist.json @@ -0,0 +1,3 @@ +{ + "mp4_support": "none" +} diff --git a/src/actions/upload.js b/src/actions/upload.js index fe6ae5b8..6b98aebb 100644 --- a/src/actions/upload.js +++ b/src/actions/upload.js @@ -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' @@ -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({ @@ -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')) } @@ -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(() => @@ -178,6 +180,7 @@ async function updateAssetDocumentFromUpload(uuid) { } catch (err) { return Promise.reject(err) } + const doc = { _id: uuid, _type: 'mux.videoAsset', diff --git a/src/components/Input.js b/src/components/Input.js index 1ac51f4c..651ef47c 100644 --- a/src/components/Input.js +++ b/src/components/Input.js @@ -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 */ @@ -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 @@ -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({ diff --git a/src/components/Video.js b/src/components/Video.js index 1bdd5691..14267766 100644 --- a/src/components/Video.js +++ b/src/components/Video.js @@ -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' @@ -37,6 +37,7 @@ class MuxVideo extends Component { isLoading: true, error: null, isDeletedOnMux: false, + isPreparingStaticRenditions: false, secrets: null, } this.playRef = React.createRef() @@ -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') { @@ -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() { @@ -234,6 +245,7 @@ class MuxVideo extends Component { )} + {showControls && ( @@ -252,6 +264,23 @@ class MuxVideo extends Component { )} + + {this.state.isPreparingStaticRenditions && ( + + + MUX is preparing static renditions, please stand by + + + )} ) } diff --git a/src/config.js b/src/config.js new file mode 100644 index 00000000..41af231e --- /dev/null +++ b/src/config.js @@ -0,0 +1,6 @@ +/* eslint-disable camelcase */ +import config from 'config:mux-input' + +export default { + mp4_support: config?.mp4_support || 'none', +}