# 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 ( { 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 ( ); } ``` ## 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)