| cmd | ||
| internal | ||
| web | ||
| .dockerignore | 225 B | |
| .gitignore | 639 B | |
| .hearthforge-ci.toml | 3.5 KB | |
| assets.go | 643 B | |
| compose.yml | 1.0 KB | |
| Containerfile | 2.1 KB | |
| go.mod | 699 B | |
| go.sum | 5.0 KB | |
| README.md | 4.0 KB |
VidArchive
A self-hosted web front end for 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-dlponPATH(or setVIDARCHIVE_YTDLP_PATH)ffmpegandffprobefor 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:
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:
docker compose build --pull --no-cache vidarchive
From source:
go build -o vidarchive ./cmd/vidarchive
./vidarchive
Then open http://localhost:8080.
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 |
<data>/vidarchive.db |
SQLite database |
VIDARCHIVE_LIBRARY_DIR |
<data>/library |
Imported media |
VIDARCHIVE_TEMP_DIR |
<data>/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:
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:
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 placeskip— keep a yt-dlp download archive and fetch only new entriesmetadata— 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.