# VidArchive ![CI](https://forge.unix-root.de/vidarchive/ci/badge.svg) A self-hosted web front end for [yt-dlp](https://github.com/yt-dlp/yt-dlp). It queues downloads, keeps the results in a browsable library with playback, metadata, subtitles and comments, and re-runs saved subscriptions on a schedule. Go standard library plus chi, SQLite (pure-Go driver), and server-rendered templates. No JavaScript, no build step for the front end. ## Requirements - `yt-dlp` on `PATH` (or set `VIDARCHIVE_YTDLP_PATH`) - `ffmpeg` and `ffprobe` for thumbnails, subtitle conversion, and media probing - Go 1.26+ to build from source Missing tools are reported at startup and on `/healthz`; the app still starts. ## Run With the container image: ```sh docker compose up -d # or: podman-compose up -d ``` The compose file mounts `./data` and publishes port 8080. The image installs yt-dlp at build time, so rebuild to update it: ```sh docker compose build --pull --no-cache vidarchive ``` From source: ```sh go build -o vidarchive ./cmd/vidarchive ./vidarchive ``` Then open . ## Configuration All configuration is environment variables. Templates and static assets are embedded in the binary. | Variable | Default | Purpose | | --- | --- | --- | | `VIDARCHIVE_PORT` | `8080` | Listen port | | `VIDARCHIVE_DATA_DIR` | `./data` | Root for everything below | | `VIDARCHIVE_DB_PATH` | `/vidarchive.db` | SQLite database | | `VIDARCHIVE_LIBRARY_DIR` | `/library` | Imported media | | `VIDARCHIVE_TEMP_DIR` | `/temp` | Download scratch space | | `VIDARCHIVE_YTDLP_PATH` | `yt-dlp` | yt-dlp binary | | `VIDARCHIVE_FFMPEG_PATH` | `ffmpeg` | ffmpeg binary | | `VIDARCHIVE_FFPROBE_PATH` | `ffprobe` | ffprobe binary | | `VIDARCHIVE_WORKERS` | `2` | Concurrent downloads (minimum 1) | | `VIDARCHIVE_SCHEDULER_INTERVAL` | `60` | Seconds between subscription checks | | `VIDARCHIVE_BASE_URL` | — | External URL; an `https://` value enables HSTS | ## Tests The offline suite needs no network and stubs yt-dlp with shell scripts: ```sh go test ./... ``` Some tests build real media files. They are skipped unless `ffmpeg` and `ffprobe` are on `PATH`. The online suite runs the real yt-dlp against a real YouTube video. It checks that a new yt-dlp release still behaves the way VidArchive expects. It needs network access and `yt-dlp` on `PATH`, and is skipped otherwise: ```sh VIDARCHIVE_ONLINE_TESTS=1 go test ./internal/service -run Live -v ``` Set `VIDARCHIVE_TEST_VIDEO_URL` to use a different video. ## Concepts **Presets** collect the yt-dlp options for a download: format selection, audio extraction, subtitle and thumbnail embedding, info-JSON and comment collection, plus free-form custom flags. One preset can be the default. A download may override the format and add its own flags. **Queue.** A download row is claimed by a worker, which runs yt-dlp into a scratch directory and then imports each finished item into the library. Live output is streamed into memory and flushed to the row periodically, so the detail page shows progress. Stopping the server leaves in-flight downloads `downloading`; they are re-queued on the next start. **Library items** are directories holding one or more media files, a `.vidarchive-item.toml` marker, yt-dlp's `info.json`, thumbnails, and an optional `subtitles/` directory. The marker is the source of truth for the item's name, source URL, video id, and per-file durations, so listing pages never have to run ffprobe. Directories without a marker are shown as folders, which makes the library browsable as a tree. **Subscriptions** re-download a URL on a cron schedule into a directory they own. Three refresh modes: - `overwrite` — replace the existing copy of each item in place - `skip` — keep a yt-dlp download archive and fetch only new entries - `metadata` — refresh metadata for known items, download only genuinely new ones With *prune removed* enabled, items no longer present upstream are deleted locally. Pruning is skipped when the source cannot be enumerated, so a network error cannot empty the directory.