All posts
Film clapperboard on a video production set

Protect course videos with FFmpeg, HLS & signed blob URLs

A single MP4 in `/public` is trivial to download. Adaptive HLS plus short-lived URLs and controlled playback raises the bar without DRM theater.

Pipeline: FFmpeg → HLS segments

Transcode source to multiple rungs (360p, 720p, 1080p), segment with FFmpeg, and ship a master `.m3u8` plus `.ts` or fMP4 chunks. Store segments on object storage (S3, R2) behind a CDN — not in your Nuxt public folder.

Example one-liner mindset: input MP4 → H.264 + AAC ladder → 6-second segments → `playlist.m3u8`. Run once on upload; serve many times.

  • `-hls_time 6` — segment length; shorter = faster start, more requests
  • `-hls_playlist_type vod` — video on demand (not live sliding window)
  • Separate audio group if you add multiple languages later

Playback: hls.js or native Safari

In the browser, `hls.js` attaches to a `<video>` element for Chrome/Firefox; Safari plays HLS natively. Your page requests the manifest only after the user is authenticated — the API returns a signed URL valid for minutes.

What is a blob URL for video?

`URL.createObjectURL(blob)` gives the `<video>` element a temporary `blob:https://yoursite.com/...` source in memory. Useful when you fetch encrypted or same-origin chunks and assemble them in JS — the address bar never shows a direct `.mp4` CDN link. Revoke with `URL.revokeObjectURL` on teardown to avoid memory leaks.

  • Blob URL ≠ security by itself — anyone with DevTools still sees network requests
  • Combine with signed cookies on CDN, short TTL tokens on manifest + segments
  • Disable `controlsList="nodownload"` and right-click only as light UX friction

Architecture checklist

  1. Upload → queue job → FFmpeg on worker → upload segments to private bucket
  2. Nitro route: `GET /api/lessons/:id/stream` checks session → returns signed m3u8 URL
  3. CDN signed URLs expire in 5–15 minutes; refresh before playback ends
  4. Optional: per-user watermark overlay in CSS/canvas for paid courses

Continue reading

DevOps

Best VPS tools in 2026: Portainer, Coolify, CapRover & aaPanel

Read article
CRM

Email open tracking in CRM: old pixels vs Resend webhooks

Read article