Skip to content

Instantly share code, notes, and snippets.

@pkfrank
Last active April 1, 2026 22:54
Show Gist options
  • Select an option

  • Save pkfrank/c12956df781fefaaad6c3716fe02344e to your computer and use it in GitHub Desktop.

Select an option

Save pkfrank/c12956df781fefaaad6c3716fe02344e to your computer and use it in GitHub Desktop.
DEV.to draft: I Digitized My Family's DVDs and Built a Private Streaming Site for $0/month
title I Digitized My Family's DVDs and Built a Private Streaming Site for $0/month
published false
tags tutorial, webdev, cloudflare, claude

Somewhere in your house there's a box of DVDs. Maybe it's home videos from 2003. Maybe it's your kid's first steps, a wedding, a holiday dinner where your uncle fell asleep at the table. You haven't watched them in years because who even owns a DVD player anymore?

Those discs are slowly degrading. The hardware to read them is disappearing. And the memories on them are irreplaceable.

I'm not really a systems programmer or a DevOps person. But I had a stack of family DVDs, a free afternoon, and Claude Code — Anthropic's CLI tool that can run terminal commands, write code, and figure things out alongside you. Between the two of us, we turned a box of old discs into a private streaming site my whole family can pull up on their phones. Total ongoing cost: $0/month.

Here's how we did it.

What you need

One piece of hardware: a USB external DVD drive. I used an Amicool A11 from Amazon (~$25). Any USB optical drive should work.

On the software side, everything is free CLI tools installed through Homebrew: ddrescue for ripping, ffmpeg for video conversion, and wrangler for uploading to Cloudflare. Claude Code handled the commands — I mostly described what I wanted and swapped discs.

Step one: make a safe copy of each disc

The first thing Claude Code suggested was making a bit-perfect copy of each disc before doing anything else. That way even if a disc gets scratched later, we have an exact digital duplicate.

The tool for this is ddrescue (not dd). The difference: if a disc has scratches or bad spots, dd just fails. ddrescue is smarter — it copies what it can, then goes back and retries the problem areas.

brew install ddrescue

There were a couple of macOS-specific gotchas that Claude Code figured out along the way. The disc drive doesn't show up in diskutil list like a normal drive — you need drutil status to detect it. And ddrescue needs to be told the exact disc size, otherwise it thinks there's 9,223 petabytes of data to read (basically infinity). The size comes from the block count that drutil reports.

We wrapped all of this into a script so I could just run ./rip.sh disc-01, wait about 10 minutes, swap the disc, and repeat. Each disc produced a ~4.3 GB .iso file — a perfect clone that I can keep forever as an archive.

Step two: convert to something playable

Mount the ISO and you find a VIDEO_TS folder full of .VOB files. That's the old DVD-Video format — fine for DVD players, useless for phones and browsers.

ffmpeg converts each clip to a modern H.264 MP4:

ffmpeg -i VTS_01_1.VOB \
  -c:v libx264 -crf 22 \
  -c:a aac -b:a 128k \
  -movflags +faststart \
  clip-01.mp4

I didn't know any of these flags — Claude Code picked the settings and explained why each one matters (the -movflags +faststart one moves metadata to the front of the file so browsers can stream it without downloading the whole thing first). My discs had 13 to 21 clips each.

Step three: put it online

You could upload these to YouTube (unlisted), Google Drive, or Dropbox and call it a day. But I liked the idea of having my own thing — files on storage I control, a simple site I can customize, no platform deciding to compress my videos or change their sharing features.

Claude Code set up the hosting on Cloudflare, which turned out to be free for this use case:

  • Cloudflare R2 stores the video files. It's object storage, like a hard drive in the cloud. You upload files with a CLI command and they just sit there.
  • Cloudflare Pages hosts a simple website — one HTML file with a grid of video thumbnails.
  • A small Pages Function connects the two, serving videos from R2 when you click play.

The upload was just a loop running wrangler r2 object put for each clip. Claude Code handled the commands while I did other things.

The one step I had to do manually in the Cloudflare dashboard was connecting the R2 bucket to the Pages site. Under the project's Settings > Bindings, I added an R2 binding so the site's code could actually read from the bucket. Took about 30 seconds but it's not something the CLI can do yet.

To lock it down to family only, there's Cloudflare Access — you add email addresses of people who should have access, and everyone else gets a login screen. Also free for small groups.

The gallery

The site itself is a single HTML page. No React, no build step. Just a dark grid of thumbnails.

Claude Code added a couple of nice touches:

Lightweight thumbnails — instead of loading 47 video players on page load, each clip shows a tiny JPEG thumbnail (~5 KB) with a play button. Click it and the actual video loads. The page loads in under a second.

Hover preview — move your mouse across any thumbnail and it scrubs through the video, YouTube-style. This is done with sprite sheets — one image per clip containing 20 frames tiled horizontally (~40 KB each). No video data loads until you actually click play.

There's a small progress bar at the bottom of each thumbnail as you scrub so you can tell where you are in the clip.

The video manifest is just a JavaScript object that maps disc names to clip counts. When I rip a new disc, I add one line and redeploy.

What it costs

Here's where I had to double-check my assumptions, because "free video streaming" sounds too good:

Bandwidth is genuinely free. Cloudflare R2 doesn't charge for egress — when family members stream videos, there are no per-GB download fees. This is R2's main advantage over AWS S3 or Google Cloud Storage, which charge you every time someone watches.

Storage has a generous free tier. R2 gives you 10 GB free per month. My 3-disc archive is about 8 GB of converted video, so I'm under the limit. If I rip all 15 discs in the box, I'd be around 35 GB — that's $0.38/month for the storage over the free tier. Even at 30 discs it'd be under $1/month.

Read operations have limits but they're high. Each time a video buffers or someone seeks, that's a "read operation" on R2. You get 10 million per month free. A single video watch might use 5-50 operations. For a family of 10 casually watching old home videos, you'd use maybe a few thousand per month. There's an enormous amount of headroom before this costs anything.

So realistically: free today, and even at 10x the current archive size, we're talking pocket change.

The rip script

Here's the script Claude Code and I ended up with. It auto-detects the disc, figures out the size, and runs a two-pass rip:

#!/usr/bin/env bash
set -euo pipefail

if [[ $# -lt 1 ]]; then
  echo "Usage: $0 <disc-label>"
  exit 1
fi

LABEL="$1"
RAW_DIR="$(dirname "$0")/raw"
LOG_DIR="$(dirname "$0")/logs"

DISC=$(drutil status 2>/dev/null | grep "Name:" | awk '{print $NF}')
if [[ -z "$DISC" ]]; then
  echo "No disc detected. Insert a disc and try again."
  exit 1
fi

BLOCKS=$(drutil status 2>/dev/null \
  | grep "Space Used:" \
  | sed 's/.*blocks:[[:space:]]*//' \
  | awk '{print $1}')
DISC_SIZE=$(( BLOCKS * 2048 ))

diskutil unmountDisk "$DISC" 2>/dev/null || true

ddrescue -b 2048 -s "$DISC_SIZE" -n "$DISC" "$RAW_DIR/${LABEL}.iso" "$LOG_DIR/${LABEL}.log"
ddrescue -b 2048 -s "$DISC_SIZE" -r 3 "$DISC" "$RAW_DIR/${LABEL}.iso" "$LOG_DIR/${LABEL}.log"

echo "Done! $(ls -lh "$RAW_DIR/${LABEL}.iso" | awk '{print $5}')"

Pop a disc in, run ./rip.sh disc-04, swap, repeat. About 10 minutes per disc.


The whole project took an afternoon. Most of that was just waiting for discs to rip and videos to upload while I did other things. Claude Code handled the parts I didn't know — the ffmpeg flags, the Cloudflare Pages Function for video seeking, the sprite sheet math — and I handled the part it couldn't: physically swapping discs.

My mom can now watch her old home videos on her phone. That alone was worth it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment