mono/packages/ui/docs/mux-integration.md
2026-02-08 15:09:32 +01:00

307 lines
7.1 KiB
Markdown

# Mux Video Integration
This project integrates [Mux](https://www.mux.com) for professional video upload, processing, and streaming capabilities.
## Overview
Mux provides:
- **Video Upload**: Drag & drop or click to upload video files
- **Automatic Processing**: Videos are automatically transcoded and optimized
- **HLS Streaming**: Adaptive bitrate streaming for smooth playback
- **Thumbnail Generation**: Automatic thumbnails and poster images
- **Analytics**: Track video views and engagement (optional)
## Architecture
### Flow
1. **Client requests upload URL** → Frontend calls our Supabase Edge Function
2. **Edge Function creates upload** → Calls Mux API to generate signed upload URL
3. **User uploads video** → Mux Uploader handles the upload with progress tracking
4. **Mux processes video** → Transcodes video, creates HLS stream, generates thumbnails
5. **Get playback ID** → Poll for asset creation, retrieve playback ID
6. **Play video** → Use Vidstack player with Mux HLS stream URL
### Components
- **MuxUploader**: React component for uploading videos (`@mux/mux-uploader-react`)
- **VideoCard**: Component for displaying videos with Vidstack player
- **mux-proxy**: Supabase Edge Function that interfaces with Mux API
## Setup
### 1. Get Mux Credentials
1. Sign up at [mux.com](https://www.mux.com)
2. Navigate to **Settings****Access Tokens**
3. Create a new access token with permissions:
- `Mux Video` - Read and Write
4. Copy the **Token ID** and **Token Secret**
### 2. Configure Environment Variables
Add these to your Supabase Edge Function environment variables:
```bash
MUX_TOKEN_ID=your_token_id_here
MUX_TOKEN_SECRET=your_token_secret_here
```
To set them in Supabase:
```bash
# Using Supabase CLI
supabase secrets set MUX_TOKEN_ID=your_token_id
supabase secrets set MUX_TOKEN_SECRET=your_token_secret
# Or via Supabase Dashboard
# Project Settings → Edge Functions → Secrets
```
### 3. Deploy Edge Function
```bash
supabase functions deploy mux-proxy
```
## Usage
### Upload Video
```tsx
import MuxUploader from "@mux/mux-uploader-react";
import { supabase } from "@/integrations/supabase/client";
const fetchUploadUrl = async () => {
const response = await fetch(
`${supabase.supabaseUrl}/functions/v1/mux-proxy`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${session.access_token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ action: 'create-upload' }),
}
);
const { data } = await response.json();
return data.url;
};
function VideoUpload() {
return (
<MuxUploader
endpoint={fetchUploadUrl}
onSuccess={(event) => {
console.log('Upload complete!', event.detail);
}}
/>
);
}
```
### Play Video
Once you have the playback ID from Mux, you can play the video:
```tsx
import VideoCard from "@/components/VideoCard";
function VideoPlayer({ playbackId }: { playbackId: string }) {
const videoUrl = `https://stream.mux.com/${playbackId}.m3u8`;
const thumbnailUrl = `https://image.mux.com/${playbackId}/thumbnail.jpg`;
return (
<VideoCard
videoId="123"
videoUrl={videoUrl}
thumbnailUrl={thumbnailUrl}
title="My Video"
author="User"
authorId="user-id"
likes={0}
comments={0}
/>
);
}
```
## Mux API Actions
### create-upload
Creates a new direct upload URL.
**Request:**
```json
{
"action": "create-upload"
}
```
**Response:**
```json
{
"success": true,
"data": {
"id": "upload_abc123",
"url": "https://storage.googleapis.com/...",
"status": "waiting"
}
}
```
### get-upload
Get the status of an upload and check if asset was created.
**Request:**
```json
{
"action": "get-upload",
"uploadId": "upload_abc123"
}
```
**Response:**
```json
{
"success": true,
"data": {
"id": "upload_abc123",
"status": "asset_created",
"asset_id": "asset_xyz789"
}
}
```
### get-asset
Get asset details including playback IDs.
**Request:**
```json
{
"action": "get-asset",
"assetId": "asset_xyz789"
}
```
**Response:**
```json
{
"success": true,
"data": {
"id": "asset_xyz789",
"status": "ready",
"playback_ids": [
{
"id": "playback_def456",
"policy": "public"
}
]
}
}
```
## Database Schema
Store Mux video data in your `videos` table:
```sql
CREATE TABLE videos (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL,
title TEXT NOT NULL,
description TEXT,
video_url TEXT NOT NULL, -- https://stream.mux.com/{playback_id}.m3u8
thumbnail_url TEXT, -- https://image.mux.com/{playback_id}/thumbnail.jpg
meta JSONB, -- { mux_asset_id, mux_playback_id }
created_at TIMESTAMP DEFAULT NOW()
);
```
Store in meta:
- `mux_asset_id`: For managing the asset via Mux API
- `mux_playback_id`: For generating stream/thumbnail URLs
## Mux URLs
### Stream URL (HLS)
```
https://stream.mux.com/{PLAYBACK_ID}.m3u8
```
This is an HLS stream that works with Vidstack, Mux Player, and most video players.
### Thumbnail URL
```
https://image.mux.com/{PLAYBACK_ID}/thumbnail.jpg
```
Query parameters:
- `?width=1280` - Set width
- `?height=720` - Set height
- `?time=10` - Thumbnail at 10 seconds
### MP4 URL (if enabled)
```
https://stream.mux.com/{PLAYBACK_ID}/high.mp4
```
Available qualities: `low.mp4`, `medium.mp4`, `high.mp4`
## Webhooks (Optional)
For production, set up Mux webhooks to get notified when:
- Upload completes (`video.upload.asset_created`)
- Video is ready (`video.asset.ready`)
- Errors occur (`video.asset.errored`)
This is more efficient than polling. See [Mux Webhooks Docs](https://docs.mux.com/guides/listen-for-webhooks).
## Playground
Test the integration at `/playground/video-player`:
- **Upload tab**: Upload videos using Mux
- **Test with URL tab**: Test Vidstack player with any video URL
## Pricing
Mux charges based on:
- **Encoding**: Minutes of video processed
- **Streaming**: Minutes of video delivered
- **Storage**: GB-months of video stored
See [Mux Pricing](https://www.mux.com/pricing) for current rates.
Free tier includes:
- $20/month in free credits
- Enough for ~40 minutes of encoding + 100 hours of streaming
## Troubleshooting
### Upload fails immediately
- Check that MUX_TOKEN_ID and MUX_TOKEN_SECRET are set in Supabase
- Verify the edge function is deployed
- Check browser console for CORS errors
### Video stuck in "processing"
- Large videos can take several minutes to process
- Check Mux dashboard for asset status
- Verify the upload completed successfully
### Video won't play
- Check that playback policy is set to "public"
- Verify the HLS URL format is correct
- Check browser console for player errors
## Resources
- [Mux Documentation](https://docs.mux.com)
- [Mux Uploader Docs](https://www.mux.com/docs/guides/mux-uploader)
- [Vidstack Player Docs](https://vidstack.io)
- [Mux Dashboard](https://dashboard.mux.com)