Play is a self-hosted video collection manager. Paste any video URL, and Play saves it to your library — ready to stream in-browser or download. Organize your videos into collections, search across your library, and keep everything on your own machine.
- Paste any URL and Play fetches the title, thumbnail, and metadata via yt-dlp
- Stream in-browser with a persistent bottom player — keep watching while you browse your library
- Download videos or extract MP3 audio directly to a folder on your server
- Organize into collections with custom colors
- Multiple desktops — separate workspaces for different libraries
- Full-text search across your video library
- Export and import your full library as a backup
- 10 built-in themes (light and dark)
- No tracking, no accounts, no cloud — your data stays on your machine
Pick whichever install path matches your setup. Docker installs and the dev server (npm run dev) land on http://localhost:3030; a local production build (npm start) serves on http://localhost:3031 unless you set PORT.
Non-Docker installs need
yt-dlpandffmpegonPATH. The Docker image bundles both — nothing extra to install.
Works on Synology, Unraid, TrueNAS, QNAP, Proxmox, or a plain Docker host.
One-liner:
docker run -d \
--name play \
-p 3030:3030 \
-v play-data:/app/data \
--restart unless-stopped \
larsmikki/play:latestDocker Compose (recommended):
services:
play:
image: larsmikki/play:latest
container_name: play
ports:
- "3030:3030"
volumes:
- play-data:/app/data
# - /path/to/your/output:/output # optional: mount a host folder for downloads
restart: unless-stopped
volumes:
play-data:To download videos to a folder on your host machine, uncomment the second volume line, set the host path, and configure the download path to /output in Settings.
Requires Git for Windows, Node.js 20+, yt-dlp, and ffmpeg. The easiest way to get the binaries is via Chocolatey or Scoop:
scoop install nodejs-lts git yt-dlp ffmpeg
git clone https://github.com/larsmikki/play.git
cd play
npm install
npm run devFor a production build:
npm run build
npm startbrew install node git yt-dlp ffmpeg
git clone https://github.com/larsmikki/play.git
cd play
npm install
npm run devFor a production build:
npm run build
npm startDebian/Ubuntu:
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs git ffmpeg python3-pip
sudo pip3 install -U yt-dlp
git clone https://github.com/larsmikki/play.git
cd play
npm install
npm run devOn Fedora/RHEL use dnf install nodejs git ffmpeg yt-dlp; on Arch use pacman -S nodejs npm git ffmpeg yt-dlp.
For a production build: npm run build && npm start.
| Variable | Default | Description |
|---|---|---|
PORT |
3031 (the Docker image sets 3030) |
Port the server listens on |
DATA_DIR |
/app/data |
Directory for the database and downloaded videos |
FFMPEG_PATH |
/usr/bin/ffmpeg |
Path to ffmpeg binary (pre-installed in Docker) |
| Action | How |
|---|---|
| Add a video | Click Add Video and paste any URL |
| Play a video | Click the thumbnail — player appears at the bottom |
| Download video | Open a video's menu → Download |
| Extract MP3 | Open a video's menu → Download MP3 |
| Organize | Create a collection and drag videos into it |
| Switch desktop | Use the desktop switcher in the header |
| Backup | Settings → Export |
| Restore | Settings → Import |
| Watch offline | Save for offline on a video card or in the player — see docs/offline.md |
Play works offline as an installable PWA (requires serving over HTTPS) and as a sideloadable Android app whose Capacitor project lives in client/android/. Setup, HTTPS options, and APK build steps are covered in docs/offline.md; the recommended HTTPS route (host or Docker sidecar) is in docs/tailscale.md.
The application database remains data/data.db, so the rename does not change its on-disk format. Existing Docker data is not moved automatically: either keep mounting the old video-downloader-data volume//volume2/docker/video-downloader host directory, or migrate its contents to the new play-data volume//volume2/docker/play path before starting Play. The Android app ID changed to app.play.client, so Play installs as a separate Android app; install play-client.apk and configure its server address again.
/app/data/
data.db # SQLite database (videos, collections, settings)
videos/ # downloaded video files (if download path is inside /app/data)
Video fails to fetch metadata Some sites are not supported by yt-dlp or may require cookies. Check that the URL is publicly accessible and try updating to the latest Docker image (yt-dlp is updated with each release).
Streaming doesn't work Play streams directly from the source URL via yt-dlp. If the source site throttles or blocks server-side requests, playback may fail. Downloading the video first is a reliable alternative.
Download path not working
Make sure you have mounted a host folder into the container and set the path in Settings → Download path to match the container-side mount point (e.g. /output).
If Play saves you time, consider buying me a coffee or donating via PayPal. It helps keep the project free and maintained.
