Docker + Next.js app to download HLS (.m3u8) streams as MP4 files — inspired by jakiyaa/m3u8-downloader and the Colab notebook that runs:
sudo apt install -y ffmpeg
pip install --user m3u8downloader
downloadm3u8 -o output.mp4 "https://…/playlist.m3u8"- Single download (
/) — title + m3u8 link form - Batch downloads (
/batch) — table UI for multiple jobs - From URL (
/extract) — paste a video page URL; auto-fetch title + m3u8 when present - All-video downloader (
/all-video-downloader) — public page/media URLs via yt-dlp + HLS/ffmpeg + direct HTTP (DRM hosts blocked) - Prisma + SQLite job history and status
- Background queue — Redis + Celery process-isolated workers (prefork); parallel downloads without hanging the Next.js process
- Cookies.txt, playlist toggle, quality/format pickers, optional AI classify router (
CLASSIFY_AI_URL/CLASSIFY_AI_KEY) - shadcn/ui components + Magic UI-style grid background & animated theme toggle
- axios · zustand · motion · react-hook-form · react-icons
| Layer | Tech |
|---|---|
| UI | Next.js (App Router), Tailwind v4, shadcn/ui |
| State | Zustand + axios polling |
| DB | Prisma 7 + SQLite (better-sqlite3 adapter, WAL for multi-worker) |
| Queue | Redis 7 + Celery 5 (prefork pool, late ack, time limits) |
| All-video | yt-dlp + smart router (classify_media.py) |
| Downloader | Python download_stream.py / all_video_download.py in isolated child processes |
| Extract | Python extract_stream.py (requests + BeautifulSoup + Playwright) |
| Deploy | Docker / Docker Compose (web + redis + worker) |
Windows (double-click or from cmd):
run.batLinux / macOS / Git Bash:
chmod +x run.sh
./run.shThe scripts will:
- Verify Docker CLI is installed
- Wait/retry until the Docker daemon is running
- Detect
docker compose(v2) ordocker-compose(v1) - Fingerprint app sources (
src/,python/,prisma/, Dockerfile, compose, lockfile, …) - Compare to
.docker-build-fingerprint+ container label → detect old vs new code - If code changed (or container missing/unhealthy):
docker compose up -d --build --force-recreate - If already running with matching fingerprint: fast path (no rebuild)
- Confirm container exists & is running (restart/create with retries)
- Poll health at
http://127.0.0.1:38478/api/downloads - Open the app URL in your default browser
Force a rebuild anytime:
FORCE_BUILD=1 ./run.shset FORCE_BUILD=1
run.batdocker compose up --build -dOpen http://localhost:38478.
Production listens on port 38478 (host + container) so it won’t collide with common Next/dev ports like 3000 / 8080. Override with PORT and the compose ports: mapping if needed.
Persistent volumes:
m3u8-data→ SQLite databasem3u8-downloads→ completed MP4 files
- Node.js 20+
- ffmpeg on
PATH(and optionallypip install m3u8downloader)
npm install --legacy-peer-deps
cp .env.example .env
npm run db:push
npm run dev| Script | Description |
|---|---|
npm run dev |
Next.js dev server |
npm run build |
Production build |
npm run start |
Start production server |
npm run db:generate |
Generate Prisma client |
npm run db:push |
Push schema to SQLite (dev) |
npm run db:migrate |
Create/apply migrations |
npm run db:studio |
Prisma Studio |
See .env.example:
DATABASE_URL="file:./prisma/dev.db"
DOWNLOADS_DIR="./downloads"
MAX_CONCURRENT_DOWNLOADS=2
# DOWNLOADM3U8_BIN=/usr/local/bin/downloadm3u8
# FFMPEG_BIN=ffmpeg| Method | Path | Description |
|---|---|---|
GET |
/api/downloads |
List jobs |
POST |
/api/downloads |
Create one { title, url } or batch { items: [...] } |
GET |
/api/downloads/:id |
Job detail |
DELETE |
/api/downloads/:id |
Delete job (+ file) |
PATCH |
/api/downloads/:id |
{ "action": "retry" } |
GET |
/api/downloads/:id/file |
Download completed MP4 |
- Only download content you have the right to access.
- Some streams require cookies/headers or DRM; this tool handles plain HLS best.
- Progress is approximate when using ffmpeg without a known duration.
- Default downloader is ffmpeg (
DOWNLOADER=ffmpeg). SetDOWNLOADER=downloadm3u8to use the Python CLI from the Colab notebook instead. - ffmpeg is run with
-nostdinso it works correctly as a background child process.
MIT