Self-hosted YouTube Music downloader. Tags, organizes, and keeps playlists in sync.
Python
1,615
768 commits
updated Sep 13, 2026
Self-hosted YouTube Music downloader. Paste a link, get a tagged, organized library.
Scheduled sync. Smart deduplication. Media server ready. Browser extension included.
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 lives in its album folder; the M3U file references it:
#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
.lrc files for karaoke-style playback in supported playersopus (best quality/size), mp3, or m4a β direct download when available, transcoded otherwiseDownload tracks and subscribe to playlists directly from YouTube and YouTube Music without leaving the page.
More info in the extension's README.md.
# compose.yaml
services:
yubal:
image: ghcr.io/guillevc/yubal:latest
container_name: yubal
ports:
- 8000:8000
environment:
PUID: 1000
PGID: 1000
YUBAL_SCHEDULER_CRON: "0 0 * * *"
YUBAL_DOWNLOAD_UGC: false
YUBAL_TZ: UTC
volumes:
- ./data:/app/data
- ./config:/app/config
restart: unless-stopped
[!TIP] Volume permissions: Set
PUID/PGIDto match your host user (runidto check). This also ensures compatibility with podman rootless. If/app/datais an NFS/Unraid mount that does not allowchown, make sure it is already writable by the configuredPUID/PGID.
docker compose up -d
# Open http://localhost:8000
Unraid? Use the community Docker template by @SerpentDrago (unraid forum thread).
| Variable | Description | Default (Docker) |
|---|---|---|
PUID | User ID for file ownership | 1000 |
PGID | Group ID for file ownership | 1000 |
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_YTMUSIC_LYRICS_FALLBACK | Fall back to YouTube Music lyrics on lrclib miss | true |
YUBAL_DOWNLOAD_UGC | Download user-generated content to _Unofficial/ | false |
YUBAL_REPLAYGAIN | Apply track gain; album gain for complete albums | true |
YUBAL_JOB_TIMEOUT_SECONDS | Job execution timeout in seconds | 1800 |
YUBAL_BASE_PATH | URL base path for reverse proxy subfolder | β |
YUBAL_TZ | Timezone (IANA format) | UTC |
| 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
[!TIP] Recommended stack: yubal + Navidrome gives you a self-hosted music streaming setup. Add a client like Symfonium (Android), Amperfy or Arpeggi (iOS), or Supersonic (desktop) to listen anywhere.
No configuration required. Optionally, make imported playlists public:
ND_DEFAULTPLAYLISTPUBLICVISIBILITY=true
See Navidrome docs.
For multi-artist support:
For artist linking:
GONIC_MULTI_VALUE_ARTIST=multi
GONIC_MULTI_VALUE_ALBUM_ARTIST=multi
M3U playlists are not supported (pending PR).
Need age-restricted content, private playlists, your Liked Music (list=LM), or Premium quality? Add your cookies:
https://www.youtube.com/ cookies with a browser extension (yt-dlp guide)config/ytdlp/cookies.txt or 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.
yubal is free, open-source, and built by one person. If it saves you time, consider supporting development:
A β also helps others find the project!
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.
13,166 followers Β· starred Feb 2026
917 followers Β· starred Feb 2026
148 followers Β· starred Jan 2026
361 followers Β· starred Jan 2026
Self-hosted YouTube Music downloader. Tags, organizes, and keeps playlists in sync.
Python
1,615
768 commits
updated Sep 13, 2026
Self-hosted YouTube Music downloader. Paste a link, get a tagged, organized library.
Scheduled sync. Smart deduplication. Media server ready. Browser extension included.
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 lives in its album folder; the M3U file references it:
#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
.lrc files for karaoke-style playback in supported playersopus (best quality/size), mp3, or m4a β direct download when available, transcoded otherwiseDownload tracks and subscribe to playlists directly from YouTube and YouTube Music without leaving the page.
More info in the extension's README.md.
# compose.yaml
services:
yubal:
image: ghcr.io/guillevc/yubal:latest
container_name: yubal
ports:
- 8000:8000
environment:
PUID: 1000
PGID: 1000
YUBAL_SCHEDULER_CRON: "0 0 * * *"
YUBAL_DOWNLOAD_UGC: false
YUBAL_TZ: UTC
volumes:
- ./data:/app/data
- ./config:/app/config
restart: unless-stopped
[!TIP] Volume permissions: Set
PUID/PGIDto match your host user (runidto check). This also ensures compatibility with podman rootless. If/app/datais an NFS/Unraid mount that does not allowchown, make sure it is already writable by the configuredPUID/PGID.
docker compose up -d
# Open http://localhost:8000
Unraid? Use the community Docker template by @SerpentDrago (unraid forum thread).
| Variable | Description | Default (Docker) |
|---|---|---|
PUID | User ID for file ownership | 1000 |
PGID | Group ID for file ownership | 1000 |
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_YTMUSIC_LYRICS_FALLBACK | Fall back to YouTube Music lyrics on lrclib miss | true |
YUBAL_DOWNLOAD_UGC | Download user-generated content to _Unofficial/ | false |
YUBAL_REPLAYGAIN | Apply track gain; album gain for complete albums | true |
YUBAL_JOB_TIMEOUT_SECONDS | Job execution timeout in seconds | 1800 |
YUBAL_BASE_PATH | URL base path for reverse proxy subfolder | β |
YUBAL_TZ | Timezone (IANA format) | UTC |
| 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
[!TIP] Recommended stack: yubal + Navidrome gives you a self-hosted music streaming setup. Add a client like Symfonium (Android), Amperfy or Arpeggi (iOS), or Supersonic (desktop) to listen anywhere.
No configuration required. Optionally, make imported playlists public:
ND_DEFAULTPLAYLISTPUBLICVISIBILITY=true
See Navidrome docs.
For multi-artist support:
For artist linking:
GONIC_MULTI_VALUE_ARTIST=multi
GONIC_MULTI_VALUE_ALBUM_ARTIST=multi
M3U playlists are not supported (pending PR).
Need age-restricted content, private playlists, your Liked Music (list=LM), or Premium quality? Add your cookies:
https://www.youtube.com/ cookies with a browser extension (yt-dlp guide)config/ytdlp/cookies.txt or 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.
yubal is free, open-source, and built by one person. If it saves you time, consider supporting development:
A β also helps others find the project!
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.
13,166 followers Β· starred Feb 2026
917 followers Β· starred Feb 2026
148 followers Β· starred Jan 2026
361 followers Β· starred Jan 2026