A fast, good-looking desktop client for YouTube Music Premium.
Rust under the hood, a Qt Quick UI in Material 3 Expressive on top.
- Material 3 Expressive design. Shape-morphing buttons, a large art pane, a docked player and the app's own title bar. Five color seeds (Mono, Ember, Ocean, Forest, Orchid), each in light and dark.
- Opens instantly. The last sign-in result plus home, library and playlist rows come from a small metadata-only disk cache, so the app is usable before the network answers. Fresh data then replaces it in the background.
- Picks up where you left off. Close the app mid-song and it reopens on the same queue, paused at the same second. The song is already loaded and seeked in the background, so Play starts instantly. Both behaviours can be switched off in Settings.
- Handles big playlists. Playlists load page by page as you scroll, and the list is virtualized, so even a fully loaded playlist with thousands of songs only draws the rows on screen.
- Better search. Merges the signed-in and guest Songs results, then ranks by how well the title matches and by play count. So "Hello" finds Adele first.
- Lyrics. Tap the mic button and the art pane turns into the song's lyrics over a blurred, tinted cover, whenever YouTube Music has them.
- Your YouTube likes. Hearts come from your Liked Music, and liking a song here likes it on YouTube Music too.
- Works with your OS media controls. GNOME's media panel, media keys and the lock screen see what's playing and can control it (MPRIS).
- Low-performance mode. One switch in Settings turns off animations and next-song preloading, and draws without the graphics card, for older or busy machines.
- Queue that makes sense. Playing a row queues the list around it. Shuffle, repeat one/all, radio and autoplay of similar songs are all there, and the next track is prefetched so Next is instant.
![]() |
![]() |
![]() |
![]() |
- Requires YouTube Music Premium. Playback is gated on a verified Premium account. The app never removes, skips or blocks ads.
- Streams only. Nothing is downloaded, saved or exported. Stream URLs live in memory only and are never logged or written to disk.
- Secrets stay in your OS keyring. Sign-in happens in a separate browser window, so your password never touches the app. The resulting session cookie goes straight to the system keyring, and logs are redacted.
- Cache is metadata only.
~/.cache/spinwave/holds titles, ids and artwork links. Settings live in~/.config/spinwave/.
This is an unofficial client and is not affiliated with or endorsed by Google or YouTube.
Linux for now; other platforms are planned.
Requirements
- Rust (stable) and Qt 6.11 with
qmake6on yourPATH(bindings via QtBridge) - ALSA/PipeWire audio (playback uses
rodio) - A Secret Service keyring (GNOME Keyring, KWallet, …)
- For browser sign-in:
python3-gobjectandwebkit2gtk4.1. Without them, the app falls back to pasting a cookie header. - Fonts: Material Symbols Rounded, Google Sans Flex and Roboto. Put them in
~/.local/share/fonts/and runfc-cache -f; without them, icons show up as words.
Build and run
cargo run --releaseChecks
cargo test
cargo clippy --all-targets -- -D warningssrc/: all logic in Rust.- Sign-in and keyring (
auth/), the Premium check (premium_gate.rs) and streaming plus the queue (playback/). - YouTube Music home, search and library (
ytmusic/), list models (models/) and theme generation (theme.rs). - The disk cache (
disk_cache.rs) and preferences (prefs.rs).
- Sign-in and keyring (
qml/: thin Qt Quick views and small Material 3 parts (IconButton,PillButton,Segmented,Toggle, …). Colors only come from the RustTheme.
Playback uses YouTube's InnerTube player API. Audio is fetched in 256 KiB ranges, held in memory only and decoded by rodio.
MIT. Spinwave uses Qt and qtbridge under the LGPL-3.0; packaged builds ship the Roboto and Google Sans Flex fonts (SIL OFL 1.1) and Material Symbols (Apache 2.0), with their license texts beside them.




