guillevc/yubal

Self-hosted YouTube Music downloader. Tags, organizes, and keeps playlists in sync.

Python

1,615

768 commits

updated Sep 13, 2026

See the code

README

yubal

Self-hosted YouTube Music downloader. Paste a link, get a tagged, organized library.

Scheduled sync. Smart deduplication. Media server ready. Browser extension included.

CI Release Firefox Add-on Chrome Extension Docker codecov

yubal demo

πŸ“– How It Works

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

✨ Features

  • Web UI β€” Real-time progress, job queue, works on mobile
  • Albums, playlists & tracks β€” Paste any YouTube Music link, get organized files
  • Scheduled sync β€” Subscribe to playlists; new tracks appear in your library automatically
  • Smart deduplication β€” Same track across 10 playlists? Stored once, referenced everywhere
  • Reliable downloads β€” Automatic retry on failures, graceful cancellation
  • Automatic lyrics β€” Synced .lrc files for karaoke-style playback in supported players
  • ReplayGain tagging β€” Track gain for consistent volume; album gain when downloading complete albums
  • Format options β€” opus (best quality/size), 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

🧩 Browser Extension

Download tracks and subscribe to playlists directly from YouTube and YouTube Music without leaving the page.

Track view Playlist view Settings view

Get the add-on for Firefox Chrome manual install

More info in the extension's README.md.

πŸš€ Quick Start

# 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/PGID to match your host user (run id to check). This also ensures compatibility with podman rootless. If /app/data is an NFS/Unraid mount that does not allow chown, make sure it is already writable by the configured PUID/PGID.

docker compose up -d
# Open http://localhost:8000

Unraid? Use the community Docker template by @SerpentDrago (unraid forum thread).

βš™οΈ Configuration

VariableDescriptionDefault (Docker)
PUIDUser ID for file ownership1000
PGIDGroup ID for file ownership1000
YUBAL_AUDIO_FORMATopus, mp3, or m4aopus
YUBAL_AUDIO_QUALITYTranscode quality (0=best, 10=worst)0
YUBAL_SCHEDULER_ENABLEDEnable automatic scheduled synctrue
YUBAL_SCHEDULER_CRONCron schedule for auto-sync0 0 * * *
YUBAL_FETCH_LYRICSFetch lyrics from lrclib.nettrue
YUBAL_YTMUSIC_LYRICS_FALLBACKFall back to YouTube Music lyrics on lrclib misstrue
YUBAL_DOWNLOAD_UGCDownload user-generated content to _Unofficial/false
YUBAL_REPLAYGAINApply track gain; album gain for complete albumstrue
YUBAL_JOB_TIMEOUT_SECONDSJob execution timeout in seconds1800
YUBAL_BASE_PATHURL base path for reverse proxy subfolderβ€”
YUBAL_TZTimezone (IANA format)UTC
All options
VariableDescriptionDefault (Docker)
YUBAL_HOSTServer bind address127.0.0.1
YUBAL_PORTServer port8000
YUBAL_DATAMusic library output/app/data
YUBAL_CONFIGConfig directory/app/config
YUBAL_LOG_LEVELDEBUG, INFO, WARNING, ERRORINFO
YUBAL_ASCII_FILENAMESTransliterate unicode to ASCIIfalse
YUBAL_CORS_ORIGINSAllowed CORS origins["*"]
YUBAL_TEMPTemp directorySystem temp

πŸ”Œ Media Server Integration

Tested with Navidrome, Jellyfin, and Gonic. Artists link correctly, even on tracks with multiple artists.

ServerArtist linkingPlaylists
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.

Detailed setup guides

No configuration required. Optionally, make imported playlists public:

ND_DEFAULTPLAYLISTPUBLICVISIBILITY=true

See Navidrome docs.

Jellyfin

For multi-artist support:

  1. Dashboard β†’ Libraries β†’ Music Library β†’ Manage Library
  2. Check Use non-standard artists tags
  3. Save and rescan

Gonic

For artist linking:

GONIC_MULTI_VALUE_ARTIST=multi
GONIC_MULTI_VALUE_ALBUM_ARTIST=multi

M3U playlists are not supported (pending PR).

πŸͺ Cookies (Optional)

Need age-restricted content, private playlists, your Liked Music (list=LM), or Premium quality? Add your cookies:

  1. Export https://www.youtube.com/ cookies with a browser extension (yt-dlp guide)
  2. Place at 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.

πŸ—ΊοΈ Roadmap

  • Flat folder mode
  • Post-download webhooks
  • New music automatic discovery
  • Browser extension (v0.7.0)
  • UGC tracks β€” remixes, unofficial content (v0.5.0)
  • Auto-sync playlists (v0.4.0)
  • Automatic lyrics (.lrc) (v0.3.0)
  • Single track downloads (v0.3.0)
  • Playlist support with M3U generation (v0.2.0)

πŸ’œ Support

yubal is free, open-source, and built by one person. If it saves you time, consider supporting development:

ko-fi Sponsor BTC

A ⭐ also helps others find the project!

πŸ“ˆ Star History

Star History Chart

πŸ™ Acknowledgments

Built with yt-dlp and ytmusicapi.

Thanks to everyone who's starred, shared, reported bugs, suggested features, or supported the project πŸ’

License

MIT


For personal archiving only. Comply with YouTube's Terms of Service and applicable copyright laws.

docker
fastapi
homelab
metadata
music-downloader
playlist
python
self-hosted
sync
youtube-music
yt-dlp

guillevc/yubal

Self-hosted YouTube Music downloader. Tags, organizes, and keeps playlists in sync.

Python

1,615

768 commits

updated Sep 13, 2026

See the code

README

yubal

Self-hosted YouTube Music downloader. Paste a link, get a tagged, organized library.

Scheduled sync. Smart deduplication. Media server ready. Browser extension included.

CI Release Firefox Add-on Chrome Extension Docker codecov

yubal demo

πŸ“– How It Works

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

✨ Features

  • Web UI β€” Real-time progress, job queue, works on mobile
  • Albums, playlists & tracks β€” Paste any YouTube Music link, get organized files
  • Scheduled sync β€” Subscribe to playlists; new tracks appear in your library automatically
  • Smart deduplication β€” Same track across 10 playlists? Stored once, referenced everywhere
  • Reliable downloads β€” Automatic retry on failures, graceful cancellation
  • Automatic lyrics β€” Synced .lrc files for karaoke-style playback in supported players
  • ReplayGain tagging β€” Track gain for consistent volume; album gain when downloading complete albums
  • Format options β€” opus (best quality/size), 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

🧩 Browser Extension

Download tracks and subscribe to playlists directly from YouTube and YouTube Music without leaving the page.

Track view Playlist view Settings view

Get the add-on for Firefox Chrome manual install

More info in the extension's README.md.

πŸš€ Quick Start

# 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/PGID to match your host user (run id to check). This also ensures compatibility with podman rootless. If /app/data is an NFS/Unraid mount that does not allow chown, make sure it is already writable by the configured PUID/PGID.

docker compose up -d
# Open http://localhost:8000

Unraid? Use the community Docker template by @SerpentDrago (unraid forum thread).

βš™οΈ Configuration

VariableDescriptionDefault (Docker)
PUIDUser ID for file ownership1000
PGIDGroup ID for file ownership1000
YUBAL_AUDIO_FORMATopus, mp3, or m4aopus
YUBAL_AUDIO_QUALITYTranscode quality (0=best, 10=worst)0
YUBAL_SCHEDULER_ENABLEDEnable automatic scheduled synctrue
YUBAL_SCHEDULER_CRONCron schedule for auto-sync0 0 * * *
YUBAL_FETCH_LYRICSFetch lyrics from lrclib.nettrue
YUBAL_YTMUSIC_LYRICS_FALLBACKFall back to YouTube Music lyrics on lrclib misstrue
YUBAL_DOWNLOAD_UGCDownload user-generated content to _Unofficial/false
YUBAL_REPLAYGAINApply track gain; album gain for complete albumstrue
YUBAL_JOB_TIMEOUT_SECONDSJob execution timeout in seconds1800
YUBAL_BASE_PATHURL base path for reverse proxy subfolderβ€”
YUBAL_TZTimezone (IANA format)UTC
All options
VariableDescriptionDefault (Docker)
YUBAL_HOSTServer bind address127.0.0.1
YUBAL_PORTServer port8000
YUBAL_DATAMusic library output/app/data
YUBAL_CONFIGConfig directory/app/config
YUBAL_LOG_LEVELDEBUG, INFO, WARNING, ERRORINFO
YUBAL_ASCII_FILENAMESTransliterate unicode to ASCIIfalse
YUBAL_CORS_ORIGINSAllowed CORS origins["*"]
YUBAL_TEMPTemp directorySystem temp

πŸ”Œ Media Server Integration

Tested with Navidrome, Jellyfin, and Gonic. Artists link correctly, even on tracks with multiple artists.

ServerArtist linkingPlaylists
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.

Detailed setup guides

No configuration required. Optionally, make imported playlists public:

ND_DEFAULTPLAYLISTPUBLICVISIBILITY=true

See Navidrome docs.

Jellyfin

For multi-artist support:

  1. Dashboard β†’ Libraries β†’ Music Library β†’ Manage Library
  2. Check Use non-standard artists tags
  3. Save and rescan

Gonic

For artist linking:

GONIC_MULTI_VALUE_ARTIST=multi
GONIC_MULTI_VALUE_ALBUM_ARTIST=multi

M3U playlists are not supported (pending PR).

πŸͺ Cookies (Optional)

Need age-restricted content, private playlists, your Liked Music (list=LM), or Premium quality? Add your cookies:

  1. Export https://www.youtube.com/ cookies with a browser extension (yt-dlp guide)
  2. Place at 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.

πŸ—ΊοΈ Roadmap

  • Flat folder mode
  • Post-download webhooks
  • New music automatic discovery
  • Browser extension (v0.7.0)
  • UGC tracks β€” remixes, unofficial content (v0.5.0)
  • Auto-sync playlists (v0.4.0)
  • Automatic lyrics (.lrc) (v0.3.0)
  • Single track downloads (v0.3.0)
  • Playlist support with M3U generation (v0.2.0)

πŸ’œ Support

yubal is free, open-source, and built by one person. If it saves you time, consider supporting development:

ko-fi Sponsor BTC

A ⭐ also helps others find the project!

πŸ“ˆ Star History

Star History Chart

πŸ™ Acknowledgments

Built with yt-dlp and ytmusicapi.

Thanks to everyone who's starred, shared, reported bugs, suggested features, or supported the project πŸ’

License

MIT


For personal archiving only. Comply with YouTube's Terms of Service and applicable copyright laws.

docker
fastapi
homelab
metadata
music-downloader
playlist
python
self-hosted
sync
youtube-music
yt-dlp

Significant stargazers

Jason Miller

13,166 followers Β· starred Feb 2026

Devin Buhl

917 followers Β· starred Feb 2026

PandaDEV

148 followers Β· starred Jan 2026

Zef Hemel

361 followers Β· starred Jan 2026