media-rip/README.md
xpltd 44e24e9393 README: add Docker image location + pull/run instructions
- Added ghcr.io/xpltdco/media-rip:latest prominently in Quickstart
- Added curl one-liner to grab docker-compose.yml
- Added docker run alternative for users who don't want compose
- Updated features: 9 built-in themes (was 3)
2026-03-22 17:15:21 -05:00

9.2 KiB

media.rip()

A self-hostable yt-dlp web frontend. Paste a URL, pick quality, download — with session isolation, real-time progress, and a cyberpunk default theme.

License Docker

Features

  • Paste & download — Any URL yt-dlp supports. Format picker with live quality extraction.
  • Real-time progress — Server-Sent Events stream download progress to the browser instantly.
  • Session isolation — Each browser gets its own download queue. No cross-talk.
  • Playlist support — Collapsible parent/child jobs with per-video status tracking.
  • 9 built-in themes — 5 dark (Cyberpunk, Dark, Midnight, Hacker, Neon) + 4 light (Light, Paper, Arctic, Solarized). Admin picks the pair, visitors toggle dark/light.
  • Custom themes — Drop a CSS file into /themes volume. No rebuild needed.
  • Admin panel — Session management, storage info, manual purge, error logs. Protected by bcrypt auth.
  • Cookie auth — Upload cookies.txt per session for paywalled/private content.
  • Auto-purge — Configurable scheduled cleanup of old downloads and logs.
  • Zero telemetry — No outbound requests. No CDN, no fonts, no analytics. CSP enforced.
  • Mobile-friendly — Responsive layout with bottom tabs on small screens.

Quickstart

The Docker image is published to GitHub Container Registry:

ghcr.io/xpltdco/media-rip:latest

Pull and run with Docker Compose (recommended):

# Download the compose file
curl -O https://raw.githubusercontent.com/xpltdco/media-rip/master/docker-compose.yml

# Start the container
docker compose up -d

Or pull and run directly:

docker run -d \
  --name mediarip \
  -p 8080:8000 \
  -v ./downloads:/downloads \
  -v mediarip-data:/data \
  --restart unless-stopped \
  ghcr.io/xpltdco/media-rip:latest

Open http://localhost:8080 and paste a URL. On first run, you'll set an admin password.

Downloads are saved to ./downloads/. Everything else (database, sessions, logs) lives in a named Docker volume.

That's it. The defaults are production-ready: isolated sessions, admin panel with first-run setup wizard, 24h auto-purge, 3 concurrent downloads. Most users don't need to set any environment variables.

Docker Volumes

Mount Purpose Required
/downloads Downloaded media files Bind mount recommended
/data SQLite database, session cookies, error logs Named volume recommended
/themes Custom theme CSS overrides Optional
/app/config.yaml YAML config file Optional

Configuration

Everything works out of the box. The settings below are for operators who want to tune specific behavior.

Most Useful Settings

These are the knobs most operators actually touch — all shown commented out in docker-compose.yml:

Variable Default When to change
MEDIARIP__SESSION__MODE isolated Set to shared for family/team use, open to disable sessions entirely
MEDIARIP__DOWNLOADS__MAX_CONCURRENT 3 Increase for faster connections, decrease on low-spec hardware
MEDIARIP__PURGE__MAX_AGE_MINUTES 1440 Raise for longer retention, or set PURGE__ENABLED=false to keep forever
MEDIARIP__ADMIN__PASSWORD (empty) Pre-set to skip the first-run wizard (useful for automated deployments)

All Settings

Full reference — click to expand

Core

Variable Default Description
MEDIARIP__SERVER__PORT 8000 Internal server port
MEDIARIP__SERVER__LOG_LEVEL info Log level (debug, info, warning, error)
MEDIARIP__DOWNLOADS__MAX_CONCURRENT 3 Maximum parallel downloads
MEDIARIP__SESSION__MODE isolated isolated, shared, or open
MEDIARIP__SESSION__TIMEOUT_HOURS 72 Session cookie lifetime (hours)

Admin

Variable Default Description
MEDIARIP__ADMIN__ENABLED true Enable admin panel
MEDIARIP__ADMIN__USERNAME admin Admin username
MEDIARIP__ADMIN__PASSWORD (empty) Admin password (hashed on startup, never stored as plaintext)

Purge

Variable Default Description
MEDIARIP__PURGE__ENABLED true Enable automatic cleanup of old downloads
MEDIARIP__PURGE__MAX_AGE_MINUTES 1440 Delete completed downloads older than this (minutes)
MEDIARIP__PURGE__CRON * * * * * Purge check schedule (cron syntax)
MEDIARIP__PURGE__PRIVACY_MODE false Aggressive cleanup — removes downloads + logs on schedule
MEDIARIP__PURGE__PRIVACY_RETENTION_MINUTES 1440 Retention period when privacy mode is enabled

UI

Variable Default Description
MEDIARIP__UI__DEFAULT_THEME dark Default theme (dark, light, cyberpunk, or custom)
MEDIARIP__UI__WELCOME_MESSAGE (built-in) Header subtitle text shown to users

yt-dlp

Variable Default Description
MEDIARIP__YTDLP__EXTRACTOR_ARGS {} JSON object of yt-dlp extractor args

Note: Internal paths (SERVER__DB_PATH, SERVER__DATA_DIR, DOWNLOADS__OUTPUT_DIR) are pre-configured in the Docker image. Only override these if you change the volume mount points.

Session Modes

  • isolated (default): Each browser session has its own private download queue.
  • shared: All sessions see all downloads. Good for household/team use.
  • open: No session tracking at all. Everyone shares one queue.

Admin Panel

Enabled by default. On first run, you'll be prompted to set a password in the browser.

To pre-configure for automated deployments (skip the wizard), set the password via environment variable or .env file:

# docker-compose.yml
environment:
  - MEDIARIP__ADMIN__PASSWORD=your-password-here
# Or in .env file
MEDIARIP__ADMIN__PASSWORD=your-password-here

The plaintext password is hashed on startup and cleared from memory — it's never stored or logged.

Troubleshooting: YouTube 403 Errors

YouTube downloads work out of the box — yt-dlp automatically selects the right player clients. If you do hit HTTP 403 errors, it's usually one of:

  1. VPN/datacenter IP — YouTube blocks many VPN exit IPs. Run the container on your direct internet connection instead.
  2. Private/age-restricted content — Upload a cookies.txt from a logged-in browser session via the UI.
  3. YouTube-side changes — As a last resort, you can override yt-dlp's player client selection:
MEDIARIP__YTDLP__EXTRACTOR_ARGS='{"youtube": {"player_client": ["web_safari"]}}'

Custom Themes

  1. Create a folder in your themes volume: ./themes/my-theme/
  2. Add metadata.json:
    { "name": "My Theme", "author": "You", "description": "A cool theme" }
    
  3. Add theme.css with CSS variable overrides:
    [data-theme="my-theme"] {
      --color-bg: #1a1a2e;
      --color-accent: #e94560;
      /* See base.css for all 50+ tokens */
    }
    
  4. Restart the container. Your theme appears in the picker.

See the built-in themes in frontend/src/themes/ for fully commented examples.

Secure Deployment

For production with TLS, use the included Caddy reverse proxy:

cp docker-compose.example.yml docker-compose.yml
cp .env.example .env
# Edit .env with your domain and admin password
docker compose up -d

Caddy automatically provisions Let's Encrypt TLS certificates for your domain.

Development

Backend

cd backend
python -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/pip install pytest pytest-asyncio pytest-anyio httpx ruff
.venv/bin/python -m pytest tests/ -v -m "not integration"

Frontend

cd frontend
npm install
npm run dev       # Dev server with hot reload
npx vitest run    # Run tests
npm run build     # Production build

API

Endpoint Method Description
/api/health GET Health check with version + uptime
/api/config/public GET Public configuration
/api/downloads GET List downloads for current session
/api/downloads POST Start a new download
/api/downloads/{id} DELETE Cancel/remove a download
/api/formats GET Extract available formats for a URL
/api/events GET SSE stream for real-time progress
/api/cookies POST Upload cookies.txt for authenticated downloads
/api/cookies DELETE Remove cookies.txt for current session
/api/themes GET List available custom themes
/api/admin/* GET/POST Admin endpoints (requires auth)

Architecture

  • Backend: Python 3.12 + FastAPI + aiosqlite + yt-dlp
  • Frontend: Vue 3 + TypeScript + Pinia + Vite
  • Transport: Server-Sent Events for real-time progress
  • Database: SQLite with WAL mode
  • Styling: CSS custom properties (no Tailwind, no component library)
  • Container: Multi-stage build, non-root user, amd64 + arm64

License

MIT