Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: configurable uploads and import from Mux #350

Merged
merged 11 commits into from Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
164 changes: 148 additions & 16 deletions README.md
Expand Up @@ -73,17 +73,125 @@ Having the ID be non-root ensures that only editors are able to see it.

The Mux plugin will find its access tokens by fetching this document.

# Playing videos in the frontend
## Fetching playback IDs and understanding the data structure

When a Mux video is uploaded/chosen in a document via this plugin, it gets stored as a reference to the video document:

```json
// example document
{
"_type": "exampleSchemaWithVideo",
// Example video field
"myVideoField": {
"_type": "mux.video",
"asset": {
"_type": "reference",
"_weak": true,
"_ref": "4e37284e-cec2-406d-973c-fdf9ab1e5598" // 👈 ID of the document holding the video's Mux data
}
}
}
```

Before you can display videos in your frontend, you need to follow these references to fetch the asset's playback ID, which will be used to create a player. Here's an example GROQ query to expand the video reference in the example data above:

```groq
// Example for fetching data above
*[ _type == "exampleSchemaWithVideo" ] {
myVideoField {
asset-> {
playbackId,
assetId,
filename,
}
}
}
```

💡 For more information on querying references, refer to the documentation on [Writing GROQ queries for references](https://www.sanity.io/docs/reference-type#96b949753900) or on [Sanity's GraphQL API](https://www.sanity.io/docs/graphql).

For reference, here's an example `mux.videoAsset` document:

```json
{
"_id": "4e37284e-cec2-406d-973c-fdf9ab1e5598",
"_type": "mux.videoAsset",
"assetId": "7ovyI76F92n02H00mWP7lOCZMIU00N4iysDiQDNppX026HY",
"filename": "mux-example-video.mp4",
"status": "ready",
"playbackId": "YA02HBpY02fKWHDRMNilo301pdH02LY3k9HTcK43ItGJLWA",
// Full Mux asset data:
"data": {
"encoding_tier": "smart",
"max_resolution_tier": "1080p",
"aspect_ratio": "16:9",
"created_at": "1706645034",
"duration": 25.492133,
"status": "ready",
"master_access": "none",
"max_stored_frame_rate": 29.97,
"playback_ids": [
{
"id": "YA02HBpY02fKWHDRMNilo301pdH02LY3k9HTcK43ItGJLWA",
"policy": "signed"
}
],
"resolution_tier": "1080p",
"ingest_type": "on_demand_url",
"max_stored_resolution": "HD",
"tracks": [
{
"max_channel_layout": "stereo",
"max_channels": 2,
"id": "00MKMC73SYimw1YTh0102lPJJp9w2R5rHddpNX1N9opAMk",
"type": "audio",
"primary": true,
"duration": 25.45
},
{
"max_frame_rate": 29.97,
"max_height": 1080,
"id": "g1wEph3CVvbJL01YNKzAWMyH8N1SxW00WeECGjqwEHW9g",
"type": "video",
"duration": 25.4254,
"max_width": 1920
}
],
"id": "7ovyI76F92n02H00mWP7lOCZMIU00N4iysDiQDNppX026HY",
"mp4_support": "none"
}
}
```

We recommend using [Mux Player](https://www.mux.com/player), try the [Codesandbox example](https://codesandbox.io/s/github/sanity-io/sanity-plugin-mux-input/tree/main/example).
## Playing videos in the frontend

# Enabling Signed URLs
We recommend using [Mux Player](https://www.mux.com/player) to properly display your videos, through packages like `@mux/mux-player` and `@mux/mux-player-react`. Here's an example of how you can use the Mux Player to display a video in a React component:

```tsx
'use client'

import MuxPlayer from '@mux/mux-player-react'

export default function MuxVideo({playbackId, title}: {playbackId?: string; title?: string}) {
if (!playbackId) return null

return <MuxPlayer playbackId={playbackId} metadata={title ? {video_title: title} : undefined} />
}
```

💡 You can try these recommendations through the [Codesandbox example](https://codesandbox.io/s/github/sanity-io/sanity-plugin-mux-input/tree/main/example).

## Configuring Mux video uploads

### Signed URLs (private playbacks)

To enable [signed urls](https://docs.mux.com/docs/security-signed-urls) with content uploaded to Mux, you will need to check the "Enable Signed Urls" option in the Mux Plugin configuration. Assuming that the API Access Token and Secret Key are set (as per the [Quick start](#quick-start) section).

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
### Encoding tier

### MP4 support (downloadable videos)

To enable [static MP4 renditions](https://docs.mux.com/guides/video/enable-static-mp4-renditions), add `mp4_support: 'standard'` to the `options` of your `mux.video` schema type.

Expand All @@ -95,9 +203,37 @@ export default defineConfig({
})
```

Currently, `mp4_support` is the only supported MUX option and this supports a value of either `standard` or `none` (the default).
If MP4 support is enabled in the plugin's configuration, editors can still choose to enable MP4 renditions on a per-video basis when uploading new assets.

### Video resolution (max_resolution_tier)

# Contributing
To edit [max_resolution_tier](https://docs.mux.com/api-reference#video/operation/create-direct-upload) to support other resolutions other than 1080p, add `max_resolution_tier: '1080p' | '1440p' | '2160p'` to the `options` of your `mux.video` schema type. Defaults to `1080p`.

```js
import {muxInput} from 'sanity-plugin-mux-input'

export default defineConfig({
plugins: [muxInput({max_resolution_tier: '2160p'})],
})
```

When uploading new assets, editors can still choose a lower resolution for each video than configured globally.

### Encoding tier (smart or baseline)

The [encoding tier](https://docs.mux.com/guides/use-encoding-tiers) informs the cost, quality, and available platform features for the asset. You can choose between `smart` and `baseline` at the plugin configuration. Defaults to `smart`.

```js
import {muxInput} from 'sanity-plugin-mux-input'

export default defineConfig({
plugins: [muxInput({encoding_tier: 'baseline'})],
})
```

If `encoding_tier: 'smart'`, editors can still choose to use the `baseline` encoding tier on a per-video basis when uploading new assets.

## Contributing

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

Expand All @@ -111,7 +247,7 @@ Issues are actively monitored and PRs are welcome. When developing this plugin t
1. Edit `schemas/post.js` and add follow the plugin documentation to add a `mux.video` type field.
1. Your studio should reload, and now when you edit the plugin code it should reload the studio, when you're done creating a branch, put in a PR and a maintainer will review it. Thank you!

# Publishing
### Publishing

Run the ["CI" workflow](https://github.com/sanity-io/sanity-plugin-mux-input/actions/workflows/ci.yml).
Make sure to select the main branch and check "Release new version".
Expand All @@ -133,15 +269,7 @@ On the [main](/tree/main) branch this will result in:

After Studio v3 turns stable this behavior will change. The v2 version will then be available on the `studio-v2` dist-tag, and `studio-v3` is upgraded to live on `latest`.

# Test

`npm test`

## License

MIT-licensed. See LICENSE.

## Develop & test
### Develop & test

This plugin uses [@sanity/plugin-kit](https://github.com/sanity-io/plugin-kit)
with default configuration for build & watch scripts.
Expand All @@ -155,3 +283,7 @@ Run ["CI & Release" workflow](https://github.com/sanity-io/sanity-plugin-mux-inp
Make sure to select the main branch and check "Release new version".

Semantic release will only release on configured branches, so it is safe to run release on any branch.

## License

MIT-licensed. See LICENSE.
3 changes: 3 additions & 0 deletions example/.env.example
@@ -0,0 +1,3 @@
NEXT_PUBLIC_SANITY_PROJECT_ID=""
NEXT_PUBLIC_SANITY_DATASET="production"
NEXT_PUBLIC_SANITY_API_VERSION="2024-01-30"
21 changes: 17 additions & 4 deletions example/.gitignore
Expand Up @@ -4,20 +4,33 @@
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
36 changes: 36 additions & 0 deletions example/README.md
@@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
6 changes: 0 additions & 6 deletions example/ignored-build-step.sh

This file was deleted.

4 changes: 4 additions & 0 deletions example/next.config.mjs
@@ -0,0 +1,4 @@
/** @type {import('next').NextConfig} */
const nextConfig = {}

export default nextConfig