{"id":35767299,"url":"https://github.com/guillevc/yubal","last_synced_at":"2026-02-15T19:27:56.698Z","repository":{"id":332056762,"uuid":"1124730302","full_name":"guillevc/yubal","owner":"guillevc","description":"YouTube Music album downloader with Spotify metadata auto-tagging","archived":false,"fork":false,"pushed_at":"2026-01-09T01:45:42.000Z","size":7129,"stargazers_count":266,"open_issues_count":3,"forks_count":4,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-01-12T17:21:36.238Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/guillevc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null},"funding":{"ko_fi":"guillevc"}},"created_at":"2025-12-29T14:14:08.000Z","updated_at":"2026-01-12T10:27:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/guillevc/yubal","commit_stats":null,"previous_names":["guillevc/yubal"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/guillevc/yubal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guillevc%2Fyubal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guillevc%2Fyubal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guillevc%2Fyubal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guillevc%2Fyubal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/guillevc","download_url":"https://codeload.github.com/guillevc/yubal/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guillevc%2Fyubal/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28400125,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T14:36:09.778Z","status":"ssl_error","status_checked_at":"2026-01-13T14:35:19.697Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-07T02:15:21.644Z","updated_at":"2026-02-15T19:27:56.689Z","avatar_url":"https://github.com/guillevc.png","language":"Python","funding_links":["https://ko-fi.com/guillevc","https://github.com/sponsors/guillevc"],"categories":["Python"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# yubal\n\n**Self-hosted YouTube Music downloader with automatic metadata tagging and playlist sync.**\n\nPaste 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.\n\n[![CI](https://github.com/guillevc/yubal/actions/workflows/ci.yaml/badge.svg)](https://github.com/guillevc/yubal/actions/workflows/ci.yaml)\n[![Release](https://img.shields.io/github/v/release/guillevc/yubal)](https://github.com/guillevc/yubal/releases)\n[![Docker](https://img.shields.io/badge/ghcr.io-blue?logo=docker\u0026logoColor=white)](https://ghcr.io/guillevc/yubal)\n[![codecov](https://codecov.io/gh/guillevc/yubal/branch/master/graph/badge.svg)](https://codecov.io/gh/guillevc/yubal)\n\n\u003cpicture\u003e\n  \u003cimg src=\"docs/demo.gif\" alt=\"yubal demo\" width=\"75%\"\u003e\n\u003c/picture\u003e\n\n\u003c/div\u003e\n\n\u003cbr/\u003e\n\n\u003e [!IMPORTANT]\n\u003e **Upgrading from v0.3?** Folder and file names now preserve unicode characters (`Bjork` → `Björk`), which may create duplicates alongside existing ASCII-named items.\n\u003e\n\u003e To keep the previous ASCII behavior, set `YUBAL_ASCII_FILENAMES=true`. Otherwise, check your library and merge any duplicates after upgrading.\n\n## 📖 How It Works\n\nDownloading music is easy. _Organizing_ it is the hard part.\n\nyubal takes a YouTube Music URL and produces a clean, tagged music library:\n\n```\ndata/\n├── Pink Floyd/\n│   └── 1973 - The Dark Side of the Moon/\n│       ├── 01 - Speak to Me.opus\n│       ├── 01 - Speak to Me.lrc\n│       ├── 02 - Breathe.opus\n│       ├── 02 - Breathe.lrc\n│       └── cover.jpg\n│\n├── Radiohead/\n│   └── 1997 - OK Computer/\n│       ├── 01 - Airbag.opus\n│       ├── 01 - Airbag.lrc\n│       ├── 02 - Paranoid Android.opus\n│       ├── 02 - Paranoid Android.lrc\n│       └── cover.jpg\n│\n└── _Playlists/\n    ├── My Favorites [n2g-XhDv].m3u\n    └── My Favorites [n2g-XhDv].jpg\n```\n\nWhen downloading a playlist, each track goes to its album folder—the M3U file just references them:\n\n```m3u\n#EXTM3U\n#EXTINF:239,Pink Floyd - Breathe\n../Pink Floyd/1973 - The Dark Side of the Moon/02 - Breathe.opus\n#EXTINF:386,Radiohead - Paranoid Android\n../Radiohead/1997 - OK Computer/02 - Paranoid Android.opus\n```\n\n## ✨ Features\n\n- **Web UI** — Real-time progress, job queue, responsive design\n- **Albums, playlists \u0026 tracks** — Paste any YouTube Music link, get organized files\n- **Scheduled sync** — Subscribe to playlists; new tracks download automatically\n- **Smart deduplication** — Same track across 10 playlists? Stored once, referenced everywhere\n- **Reliable downloads** — Automatic retry on failures, graceful cancellation\n- **Automatic lyrics** — Synced `.lrc` files downloaded alongside tracks when available\n- **ReplayGain tagging** — Track and album ReplayGain/R128 tags for consistent playback volume\n- **Format options** — Native `opus` (best quality), mp3, or m4a (direct download when available, transcoded otherwise)\n- **Media server ready** — Tested with [Navidrome, Jellyfin, and Gonic](#-media-server-integration)\n- **[CLI](packages/yubal/src/yubal/cli/README.md)** — Download and inspect metadata from the terminal\n\n## 🚀 Quick Start\n\n```yaml\n# compose.yaml\nservices:\n  yubal:\n    image: ghcr.io/guillevc/yubal:latest\n    container_name: yubal\n    user: 1000:1000\n    ports:\n      - 8000:8000\n    environment:\n      YUBAL_SCHEDULER_CRON: \"0 0 * * *\"\n      YUBAL_DOWNLOAD_UGC: false\n      YUBAL_TZ: UTC\n    volumes:\n      - ./data:/app/data\n      - ./config:/app/config\n    restart: unless-stopped\n```\n\n\u003e [!TIP]\n\u003e **Volume permissions:** The container runs as UID:GID `1000:1000` by default. If your host user has a different UID, either:\n\u003e\n\u003e - Change `user:` to match your UID:GID (run `id` to check), or\n\u003e - Set ownership on the volume directories: `chown 1000:1000 -R data config`\n\n```bash\ndocker compose up -d\n# Open http://localhost:8000\n```\n\n\u003e **Unraid?** Use the [community Docker template](https://github.com/SerpentDrago/UnraidDockerTemplates/tree/main/yubal) by [@SerpentDrago](https://github.com/SerpentDrago) ([unraid forum thread](https://forums.unraid.net/topic/197157-support-yubal-self-hosted-youtube-music-downloader/)).\n\n## ⚙️ Configuration\n\n| Variable                    | Description                                       | Default (Docker) |\n| --------------------------- | ------------------------------------------------- | ---------------- |\n| `YUBAL_AUDIO_FORMAT`        | `opus`, `mp3`, or `m4a`                           | `opus`           |\n| `YUBAL_AUDIO_QUALITY`       | Transcode quality (0=best, 10=worst)              | `0`              |\n| `YUBAL_SCHEDULER_ENABLED`   | Enable automatic scheduled sync                   | `true`           |\n| `YUBAL_SCHEDULER_CRON`      | Cron schedule for auto-sync                       | `0 0 * * *`      |\n| `YUBAL_FETCH_LYRICS`        | Fetch lyrics from lrclib.net                      | `true`           |\n| `YUBAL_DOWNLOAD_UGC`        | Download user-generated content to `_Unofficial/` | `false`          |\n| `YUBAL_REPLAYGAIN`          | Apply ReplayGain tags to downloads                | `true`           |\n| `YUBAL_JOB_TIMEOUT_SECONDS` | Job execution timeout in seconds                  | `1800`           |\n| `YUBAL_TZ`                  | Timezone (IANA format)                            | `UTC`            |\n\n\u003cdetails\u003e\n\u003csummary\u003eAll options\u003c/summary\u003e\n\n| Variable                | Description                         | Default (Docker) |\n| ----------------------- | ----------------------------------- | ---------------- |\n| `YUBAL_HOST`            | Server bind address                 | `127.0.0.1`      |\n| `YUBAL_PORT`            | Server port                         | `8000`           |\n| `YUBAL_DATA`            | Music library output                | `/app/data`      |\n| `YUBAL_CONFIG`          | Config directory                    | `/app/config`    |\n| `YUBAL_LOG_LEVEL`       | `DEBUG`, `INFO`, `WARNING`, `ERROR` | `INFO`           |\n| `YUBAL_ASCII_FILENAMES` | Transliterate unicode to ASCII      | `false`          |\n| `YUBAL_CORS_ORIGINS`    | Allowed CORS origins                | `[\"*\"]`          |\n| `YUBAL_TEMP`            | Temp directory                      | System temp      |\n\n\u003c/details\u003e\n\n## 🔌 Media Server Integration\n\nTested with Navidrome, Jellyfin, and Gonic. Artists link correctly, even on tracks with multiple artists.\n\n| Server        | Artist linking                                                | Playlists |\n| ------------- | ------------------------------------------------------------- | :-------: |\n| **Navidrome** | ✅ Works out of the box                                       |    ✅     |\n| **Jellyfin**  | ⚙️ Enable \"Use non-standard artists tags\" in library settings |    ✅     |\n| **Gonic**     | ⚙️ Set `GONIC_MULTI_VALUE_ARTIST=multi`                       |    ❌     |\n\n✅ Supported · ⚙️ Requires configuration · ❌ Not supported\n\n\u003cdetails\u003e\n\u003csummary\u003eDetailed setup guides\u003c/summary\u003e\n\n### Navidrome\n\nNo configuration required. Optionally, make imported playlists public:\n\n```bash\nND_DEFAULTPLAYLISTPUBLICVISIBILITY=true\n```\n\nSee [Navidrome docs](https://www.navidrome.org/docs/usage/configuration/options/).\n\n### Jellyfin\n\nFor multi-artist support:\n\n1. **Dashboard → Libraries → Music Library → Manage Library**\n2. Check **Use non-standard artists tags**\n3. Save and rescan\n\n### Gonic\n\nFor artist linking:\n\n```bash\nGONIC_MULTI_VALUE_ARTIST=multi\nGONIC_MULTI_VALUE_ALBUM_ARTIST=multi\n```\n\nM3U playlists are not supported ([pending PR](https://github.com/sentriz/gonic/pull/537)).\n\n\u003c/details\u003e\n\n## 🍪 Cookies (Optional)\n\nNeed age-restricted content, private playlists, or Premium quality? Add your cookies:\n\n1. Export `https://www.youtube.com/` cookies with a browser extension ([yt-dlp guide](https://github.com/yt-dlp/yt-dlp/wiki/FAQ#how-do-i-pass-cookies-to-yt-dlp))\n2. Place at `config/ytdlp/cookies.txt` or upload via the web UI\n\n\u003e [!CAUTION]\n\u003e Cookie usage may trigger stricter rate limiting and could put your account at risk. See [#3](https://github.com/guillevc/yubal/issues/3) and [yt-dlp wiki](https://github.com/yt-dlp/yt-dlp/wiki/Extractors#youtube).\n\n## 🗺️ What's Coming\n\n- [x] Playlist support with M3U generation ([v0.2.0](https://github.com/guillevc/yubal/releases/tag/v0.2.0))\n- [x] Single track downloads ([v0.3.0](https://github.com/guillevc/yubal/releases/tag/v0.3.0))\n- [x] Automatic lyrics (.lrc) ([v0.3.0](https://github.com/guillevc/yubal/releases/tag/v0.3.0))\n- [x] Auto-sync playlists ([v0.4.0](https://github.com/guillevc/yubal/releases/tag/v0.4.0))\n- [x] UGC tracks (user-generated content, remixes, unofficial tracks) ([v0.5.0](https://github.com/guillevc/yubal/releases/tag/v0.5.0))\n- [ ] Flat folder mode\n- [ ] Browser extension\n- [ ] Post-download webhooks\n- [ ] New music automatic discovery\n\n## 💜 Support\n\nIf yubal is useful to you, consider supporting its development:\n\n[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/guillevc) [![Sponsor](https://img.shields.io/badge/sponsor-GitHub-ea4aaa?logo=github)](https://github.com/sponsors/guillevc)\n\nA ⭐ also helps others discover yubal!\n\n## 📈 Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=guillevc/yubal\u0026type=Date)](https://star-history.com/#guillevc/yubal\u0026Date)\n\n## 🙏 Acknowledgments\n\nBuilt with [yt-dlp](https://github.com/yt-dlp/yt-dlp) and [ytmusicapi](https://github.com/sigma67/ytmusicapi).\n\nThanks to everyone who's starred, shared, reported bugs, suggested features, or [supported the project](https://ko-fi.com/guillevc) 💝\n\n## License\n\n[MIT](LICENSE)\n\n---\n\n\u003csub\u003eFor personal archiving only. Comply with YouTube's Terms of Service and applicable copyright laws.\u003c/sub\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguillevc%2Fyubal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fguillevc%2Fyubal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguillevc%2Fyubal/lists"}