# HLS (m3u8) Implementation Plan ## Objective Transition internal video processing and serving from single MP4 files to HLS (HTTP Live Streaming) to improve playback performance, seekability, and support adaptive bitrate streaming. ## Technical Changes ### 1. Video Processing (Worker) **File**: `server/src/products/videos/worker.ts` **Current**: Generates single `jobId.mp4`. **New**: Generate HLS playlist and segments. **FFmpeg Command**: ```bash ffmpeg -i input.mp4 \ -b:v 1M \ -g 60 \ -hls_time 2 \ -hls_list_size 0 \ -hls_segment_size 500000 \ output.m3u8 ``` **Storage Structure**: Instead of flat files in `videos/`, use a directory per job: ``` videos/ ├── [jobId]/ │ ├── playlist.m3u8 │ ├── output0.ts │ ├── output1.ts │ └── ... ``` ### 2. API Endpoints (Product) **File**: `server/src/products/videos/routes.ts` & `index.ts` Create new endpoints to serve HLS assets. We need to serve both the playlist (`.m3u8`) and the segment files (`.ts`). #### Endpoints: 1. **Playlist**: `GET /api/videos/jobs/:id/hls/playlist.m3u8` * **Handler**: Looks up directory `videos/:id/`, serves `playlist.m3u8`. * **Content-Type**: `application/vnd.apple.mpegurl` or `application/x-mpegURL`. 2. **Segments**: `GET /api/videos/jobs/:id/hls/:segment` * **Handler**: Looks up directory `videos/:id/`, serves requested `.ts` file. * **Content-Type**: `video/MP2T`. **Note**: The playlist generated by ffmpeg usually contains relative paths (e.g., `output0.ts`). If the browser loads the playlist from `.../hls/playlist.m3u8`, it will resolve segments relative to that base, `.../hls/output0.ts`, which fits the proposed endpoint structure perfectly. ### 3. Frontend (Playground & Components) **File**: `src/pages/VideoPlayerPlaygroundIntern.tsx` * Update `pollJob` or `handleUpload` completion logic. * Instead of setting `videoUrl` to the MP4 download link, set it to the HLS playlist endpoint: * `http://localhost:3333/api/videos/jobs/[jobId]/hls/playlist.m3u8` * Pass type `application/x-mpegurl` (or `application/vnd.apple.mpegurl`) to `VideoCard`. **File**: `src/components/VideoCard.tsx` * Ensure `Vidstack` / `MediaPlayer` handles the HLS mime type correctly. Vidstack has built-in HLS support (often requires `hls.js` but it's usually bundled or easily added). * Verify `src` prop handling for HLS. ### 4. Database / Metadata * Update `resultUrl` in the job completion data (in `pg-boss` or returned to frontend) to point to the `.m3u8` file. * Supabase `pictures` table: Update `image_url` to store the HLS playlist URL instead of the MP4 download URL. ## Migration Strategy 1. **Implement new Worker logic**: Create a new job name or update existing `video-processing` to output HLS. 2. **Implement new Endpoints**: Add HLS routes to `VideosProduct`. 3. **Update Frontend**: Point playground to new endpoints. 4. **Verify**: Test playback. 5. **Cleanup**: Remove MP4 download endpoint and old worker logic once verified. ## Outstanding Questions * **Storage Cleanup**: Deleting a video now means deleting a directory. Ensure `handleDelete` is updated. * **Legacy Content**: Old MP4s will stop working if we aggressively remove the old endpoint. * *Decision*: Keep the old `download` endpoint for backward compatibility if needed, or migration script to convert old videos (out of scope for now).