Self-hosted YouTube Music downloader with automatic metadata tagging and playlist sync.
Paste a link, get a properly tagged and organized library. Subscribe to playlists to keep them synced. Albums sorted by artist and year. No duplicates. Media server ready.
Important
Upgrading from v0.3? Folder and file names now preserve unicode characters (Bjork → Björk), which may create duplicates alongside existing ASCII-named items.
To keep the previous ASCII behavior, set YUBAL_ASCII_FILENAMES=true. Otherwise, check your library and merge any duplicates after upgrading.
Downloading music is easy. Organizing it is the hard part.
yubal takes a YouTube Music URL and produces a clean, tagged music library:
data/
├── Pink Floyd/
│ └── 1973 - The Dark Side of the Moon/
│ ├── 01 - Speak to Me.opus
│ ├── 01 - Speak to Me.lrc
│ ├── 02 - Breathe.opus
│ ├── 02 - Breathe.lrc
│ └── cover.jpg
│
├── Radiohead/
│ └── 1997 - OK Computer/
│ ├── 01 - Airbag.opus
│ ├── 01 - Airbag.lrc
│ ├── 02 - Paranoid Android.opus
│ ├── 02 - Paranoid Android.lrc
│ └── cover.jpg
│
└── _Playlists/
├── My Favorites [n2g-XhDv].m3u
└── My Favorites [n2g-XhDv].jpg
When downloading a playlist, each track goes to its album folder—the M3U file just references them:
#EXTM3U
#EXTINF:239,Pink Floyd - Breathe
../Pink Floyd/1973 - The Dark Side of the Moon/02 - Breathe.opus
#EXTINF:386,Radiohead - Paranoid Android
../Radiohead/1997 - OK Computer/02 - Paranoid Android.opus- Web UI — Real-time progress, job queue, responsive design
- Albums, playlists & tracks — Paste any YouTube Music link, get organized files
- Scheduled sync — Subscribe to playlists; new tracks download automatically
- Smart deduplication — Same track across 10 playlists? Stored once, referenced everywhere
- Reliable downloads — Automatic retry on failures, graceful cancellation
- Automatic lyrics — Synced
.lrcfiles downloaded alongside tracks when available - ReplayGain tagging — Track and album ReplayGain/R128 tags for consistent playback volume
- Format options — Native
opus(best quality), mp3, or m4a (direct download when available, transcoded otherwise) - Media server ready — Tested with Navidrome, Jellyfin, and Gonic
- CLI — Download and inspect metadata from the terminal
# compose.yaml
services:
yubal:
image: ghcr.io/guillevc/yubal:latest
container_name: yubal
user: 1000:1000
ports:
- 8000:8000
environment:
YUBAL_SCHEDULER_CRON: "0 0 * * *"
YUBAL_DOWNLOAD_UGC: false
YUBAL_TZ: UTC
volumes:
- ./data:/app/data
- ./config:/app/config
restart: unless-stoppedTip
Volume permissions: The container runs as UID:GID 1000:1000 by default. If your host user has a different UID, either:
- Change
user:to match your UID:GID (runidto check), or - Set ownership on the volume directories:
chown 1000:1000 -R data config
docker compose up -d
# Open http://localhost:8000| Variable | Description | Default (Docker) |
|---|---|---|
YUBAL_AUDIO_FORMAT |
opus, mp3, or m4a |
opus |
YUBAL_AUDIO_QUALITY |
Transcode quality (0=best, 10=worst) | 0 |
YUBAL_SCHEDULER_ENABLED |
Enable automatic scheduled sync | true |
YUBAL_SCHEDULER_CRON |
Cron schedule for auto-sync | 0 0 * * * |
YUBAL_FETCH_LYRICS |
Fetch lyrics from lrclib.net | true |
YUBAL_DOWNLOAD_UGC |
Download user-generated content to _Unofficial/ |
false |
YUBAL_REPLAYGAIN |
Apply ReplayGain tags to downloads | true |
YUBAL_TZ |
Timezone (IANA format) | UTC |
All options
| Variable | Description | Default (Docker) |
|---|---|---|
YUBAL_HOST |
Server bind address | 127.0.0.1 |
YUBAL_PORT |
Server port | 8000 |
YUBAL_DATA |
Music library output | /app/data |
YUBAL_CONFIG |
Config directory | /app/config |
YUBAL_LOG_LEVEL |
DEBUG, INFO, WARNING, ERROR |
INFO |
YUBAL_ASCII_FILENAMES |
Transliterate unicode to ASCII | false |
YUBAL_CORS_ORIGINS |
Allowed CORS origins | ["*"] |
YUBAL_TEMP |
Temp directory | System temp |
Tested with Navidrome, Jellyfin, and Gonic. Artists link correctly, even on tracks with multiple artists.
| Server | Artist linking | Playlists |
|---|---|---|
| Navidrome | ✅ Works out of the box | ✅ |
| Jellyfin | ⚙️ Enable "Use non-standard artists tags" in library settings | ✅ |
| Gonic | ⚙️ Set GONIC_MULTI_VALUE_ARTIST=multi |
❌ |
✅ Supported · ⚙️ Requires configuration · ❌ Not supported
Detailed setup guides
No configuration required. Optionally, make imported playlists public:
ND_DEFAULTPLAYLISTPUBLICVISIBILITY=trueSee Navidrome docs.
For multi-artist support:
- Dashboard → Libraries → Music Library → Manage Library
- Check Use non-standard artists tags
- Save and rescan
For artist linking:
GONIC_MULTI_VALUE_ARTIST=multi
GONIC_MULTI_VALUE_ALBUM_ARTIST=multiM3U playlists are not supported (pending PR).
Need age-restricted content, private playlists, or Premium quality? Add your cookies:
- Export
https://www.youtube.com/cookies with a browser extension (yt-dlp guide) - Place at
config/ytdlp/cookies.txtor upload via the web UI
Caution
Cookie usage may trigger stricter rate limiting and could put your account at risk. See #3 and yt-dlp wiki.
- Playlist support with M3U generation (v0.2.0)
- Single track downloads (v0.3.0)
- Automatic lyrics (.lrc) (v0.3.0)
- Auto-sync playlists (v0.4.0)
- UGC tracks (user-generated content, remixes, unofficial tracks) (v0.5.0)
- Flat folder mode
- Browser extension
- Post-download webhooks
- New music automatic discovery
If yubal is useful to you, consider supporting its development:
A ⭐ also helps others discover yubal!
Built with yt-dlp and ytmusicapi.
Thanks to everyone who's starred, shared, reported bugs, suggested features, or supported the project 💝
For personal archiving only. Comply with YouTube's Terms of Service and applicable copyright laws.