A YouTube/SoundCloud/Bandcamp search music player with local playback, downloads, and OS media controls, built with iced.
- Search — YouTube Music (Songs / Videos / Artists / Albums / Playlists) via ytmusicapi with yt-dlp fallback, plus SoundCloud, Bandcamp, Last.fm (built-in app key), and MusicBrainz search. Drill into artists, albums, and playlists.
- Streaming & caching — Stream audio via yt-dlp (YouTube/SoundCloud) or direct HTTP (Bandcamp), with fully native decoding, cached to disk for instant replay.
- Downloads — Download tracks to MP3 via yt-dlp, with a Downloads view and on-row indicators.
- Local music & playlists — Add local files (MP3, FLAC, WAV, OGG, M4A, AAC, OPUS, WMA) and create, rename, delete, and organize playlists.
- Library — Save albums, artists, and playlists; browse them from the sidebar.
- Artist pages — Header with stats plus Most popular, Albums, Playlists, and Fans-also-like sections, each with its own provider picker.
- Radio — Song radio and artist radio from search results.
- Queue — Queue panel with Up Next and Recently Played tabs.
- Trashbin — Trash tracks from the context menu; trashed tracks are skipped at track-change time, marked with an icon, and listed in the sidebar Trashbin view.
- Split panes — Split the main view.
- Drag & drop — Drag tracks between views, into the queue, onto playlists (reorder or turn a card into a local playlist), and into the Library.
- Lyrics — Free, no-key LRCLib lyrics with synced lines that seek on click, plus Genius with per-line annotations, the song blurb, and a language picker row for its translations (loaded on demand); cached per track. Add your own named custom lyrics per track (plain or
[mm:ss.xx]-synced) — they appear as tabs next to the providers, editable and deletable from the lyrics view. Attach multi-line notes to any custom line with#comment lines; the active line's note shows in an editable block below the lyrics. Translate with AI — translate the active lyrics (with learner notes) via any OpenAI-compatible server or local Ollama; the API key, server URL, and model live in Settings, and the result opens in the lyrics editor for review. - Media controls — OS media keys / MPRIS (Linux) / SMTC (Windows) / Now Playing (macOS) via souvlaki.
- More — Search history, volume normalization, navigation history, session restore, right-click context menus (tracks, and artist/album/playlist cards for open / open in browser / save as playlist), dark theme.
- Localization — 13 languages: English, Polski, Español, Português (Brasil), 简体中文, العربية, Беларуская, Français, Deutsch, 日本語, Русский, हिन्दी, Українська.
curl -fsSL https://raw.githubusercontent.com/GooseOb/music_plr/master/scripts/install.sh | bashDetects your platform, downloads the latest release, and installs everything. On Linux it also sets up the desktop entry and icon.
Download the latest release and extract to a folder. Run goosemusic.exe.
Download from GitHub releases or compile from source:
cargo install goosemusicThe release tarball includes a .desktop file and icon. After extracting:
cp goosemusic ~/.local/bin/
cp goosemusic.desktop ~/.local/share/applications/
cp icons/logo.svg ~/.local/share/icons/goosemusic.svgExtract the .app.tar.gz and drag Goosemusic.app to your Applications folder. On first open, right-click → Open if macOS blocks it (unsigned app).
English (en), Polski (pl), Español (es), Português (Brasil) (pt_br), 简体中文 (zh_cn), العربية (ar), Беларуская (be), Français (fr), Deutsch (de), 日本語 (ja), Русский (ru), हिन्दी (hi), Українська (uk).
Pick a language from the in-app Settings view. To add one, copy src/i18n/en.rs to a new module, translate the strings, and append one entry to the languages! macro in src/i18n/mod.rs — the Language enum and picker are generated from that list.
Prerequisites
- Rust (stable, edition 2021)
- yt-dlp — YouTube audio streaming and downloads
- Python 3 +
ytmusicapi— YouTube Music search (optional; falls back to yt-dlp) - D-Bus session bus (Linux) — for MPRIS
- Network access — lyrics fetch live from LRCLib and Genius (no keys)
cargo build
cargo run| Key | Action |
|---|---|
| Space | Toggle play/pause |
| Esc | Close in-list search → close search history → clear selection → return to Search |
| Delete | Delete selected tracks (playlist/Downloads/Trashbin views) |
| ←/→ or h/l | Move focus between queue panel and track list |
| ↑/↓ or k/j | Move through the focused list (auto-scrolls, wraps) |
| gg / G, Home/End | First / last row |
| PgUp/PgDn, Ctrl+U/D | Page / half-page |
| Shift+↑/↓ (J/K), Ctrl+Space | Extend selection / toggle selection on focused row |
| Ctrl+F | In-list fuzzy search over the hovered track list (n/p step matches) |
| Enter | Play the focused (or hovered) track |
| Ctrl+C / Ctrl+V | Copy / paste selected tracks |
| Ctrl+A | Select all tracks in the focused list |
| Alt+P / Alt+1..5, Alt+S | Stage search provider / scope (pending until Enter) |
| Alt+Enter | Run the pending search from anywhere |
| Alt+↑/↓, Ctrl+K | Prev/next playlist, playlist jumper (Enter open, Shift+Enter play) |
| Alt+←/→ | Back / forward in the focused pane |
| N / P | Next / previous track |
| Q / R / Shift+L | Toggle queue / repeat / lyrics |
| T | Switch queue panel tab: Queue ↔ Recently Played (opens panel if hidden) |
| M, -/=, ,/. | Mute, volume, seek ∓5s (Shift ∓10s) |
| </kbd> / Shift+</kbd> | Split focused pane side by side / stacked |
| Ctrl+W | Close the focused pane |
| Ctrl+←/→/↑/↓ | Move focus to the adjacent pane |
| Ctrl+Tab, Ctrl+1..4 | Cycle / jump between panes |
| ? / F1 | Show this cheatsheet in-app |
Config lives at ~/.config/goosemusic/config.json and is also editable live from the in-app Settings view.
| Field | Description | Default |
|---|---|---|
download_dir |
Download directory | ~/Music/goosemusic |
cache_max_size_mb |
Max stream cache size (MB) | 1024 |
max_search_history_stored |
Search history entries kept on disk | 100 |
max_search_history_visible |
Entries shown in the dropdown | 10 |
max_recently_played |
Tracks kept in Recently Played | 50 |
volume_normalization |
Consistent loudness across tracks | false |
cookie_browser |
Browser yt-dlp reads cookies from (age-restricted videos) | none |
Persistent data goes to ~/.local/share/goosemusic (playlists, library, downloads, trashbin, search history); regenerable caches (session, streamed audio,
thumbnails, lyrics) go to ~/.cache/goosemusic.
State — All state lives in one MusicPlayer; view() is a pure function of &MusicPlayer. Background work (search, download, thumbnails)
returns via an mpsc channel drained by a 1Hz tick (none when idle). Stores implement a JsonStore trait and degrade to defaults on failure.
Audio — A dedicated output thread runs the rodio sink. yt-dlp streams AAC-in-M4A into a still-growing cache file; a custom
SymphoniaStreamingSource over a non-seekable GrowingMediaSource decodes sequentially so playback starts within a few KB.
Cached/downloaded/local files use the same source in seekable mode. Per-track normalization gain is computed once (symphonia) and applied on
replay.
MIT
