
Spotifust
A multi-platform, ultra-lightweight Spotify client built entirely from scratch in Rust. Ditching the heavy browser engines for pure native playback.
The Story Behind Spotifust
Spotifust started from a simple but stubborn idea: why does a music player need to load an entire web browser inside it?
Modern desktop apps often rely on heavy web engines like Electron or Chromium, which eat up RAM and battery. Our purpose is to build an application that does one thing perfectly—playing music—while maintaining a baseline memory footprint of less than 25 MB.
No Node.js running behind the scenes, no full Chromium instance rendering four buttons. Just one binary, one process, and your GPU doing what it does best. That's the core philosophy.
RAM Footprint Comparison
* The final optimization goal is to maintain a baseline footprint of ≤ 25 MB.
** Measurements based on the native Windows application.
Powered by Rust
Spotifust relies on the Rust ecosystem's best crates to deliver a smooth and safe native experience.
🎨 iced & tiny-skia
For a GPU-accelerated GUI based on the Elm Architecture (MVU). Clean state management without mutability nightmares.
🎵 librespot
An embedded engine for session management, DRM decryption, and chunk fetching straight from Spotify's servers.
🔊 rodio
Handles cross-platform audio output to feed decoded PCM arrays directly to the system sound drivers.
🌐 rspotify & tokio
Asynchronous multi-threading for the Spotify Web API and network requests, avoiding UI thread blocking.
📊 Language Distribution
Architecture & Roadmap
We follow a strict zero-crashing policy and an Elm-like pure Model-View-Update flow. Here is where the project is heading.
Phase 1: Bootstrapping & Core Architecture
- Configure Cargo.toml with feature flags for Iced (tiny-skia backend), RSpotify, and Librespot
- Define central
AppErrorenum (thiserror) with per-subsystem variants - Set up base Model-View-Update loop in
src/app.rs - Set up full GitHub Actions CI/CD infrastructure, Issue templates, and documentation
- Verify all
librespotandrspotifyraw error types are wrapped inAppErrorbefore reachingMessagevariants - Audit and eliminate any remaining
.unwrap()/.expect()calls outsidemain()bootstrap - Reduce RAM baseline from ~45 MB down to the target < 25 MB ceiling
Phase 2: Spotify Resizable Panel Layout Engine
- Implement 3-column layout structure (Left Sidebar library, Main content, Right panel)
- Add interactive drag handles with
ResizingHorizontallymouse cursor interaction - Handle global pointer move/up events for robust dragging/resizing
- Implement right dynamic slot panel showing Now Playing or Queue based on playback bar triggers
- Implement left library sidebar collapse to icon-only compact layout below width threshold
- Persist layout panel widths to disk
Phase 3: Librespot Audio & Session Pipeline
- Implement
librespot::core::session::Sessionsetup and credential-based login - Implement a custom
librespotaudioSinkthat captures decoded PCM frames - Route PCM frames from the custom Sink through a bounded
mpscchannel to arodioplayback thread - Wire a synthetic sine-wave test pipeline to validate the
rodiobackend end-to-end - Wire UI Play command to call
player.load()on the activelibrespotplayer instance - Wire UI Pause / Resume commands to the librespot player
- Wire UI Skip Next / Skip Previous commands to the librespot player
- Implement Seek: accept a
f32position ratio from the seek bar and callplayer.seek(ms) - Extract current track metadata (title, artist, album, duration) from
PlayerEventand emit them asMessage::TrackChanged - Stream playback position (elapsed ms) from the audio task to the UI via the mpsc channel
- Implement end-of-track detection via
PlayerEvent::EndOfTrackand auto-advance to next track - Validate that the mpsc channel remains bounded under sustained high-throughput decoding
- Wire volume control: slider value in UI →
rodio::Sink::set_volume()(full 0.0–1.0 range, not binary) - Fix seek bar so it travels the full 0–100% range and reflects real playback position
- Handle
librespotsession expiry and reconnection without crashing - Fix app crash during track playback (
src/audio/sink.rs:35:14: Cannot block the current thread from within a runtime&Invalid Spotify URI '') - Refine audio pipeline for 320kbps high-quality bitrate, synchronized rodio pause/resume and instant volume binding
Phase 4: RSpotify Web API, Auth & Aggressive Caching
- Implement PKCE Authorization Code Flow with
rspotify - Register
spotifust://callbackcustom protocol handler for the OAuth redirect - Verify the refresh token is stored exclusively via the OS keychain (
keyringcrate), never as plaintext - Implement token refresh on expiry: detect 401 responses and silently re-authenticate
- Fetch the authenticated user's profile (
/me) and display name and avatar in the sidebar - Fetch the user's full playlist library (
/me/playlists, paginated) and stream items into the sidebar list - Fetch playlist track listings on demand when a playlist is selected
- Fetch the user's saved albums and expose them in a dedicated Albums view
- Fetch the user's top tracks and expose them in a Home/For You view
- Implement search: send queries to
/searchand display track, album, and artist results - Implement album detail view: fetch
/albums/{id}and list its tracks - Implement artist detail view: fetch
/artists/{id}with top tracks and discography - Fetch currently playing track via
/me/player/currently-playingon startup and sync UI state - Implement album art fetching: download cover images asynchronously and cache to disk in
src/api/cache.rs - Implement a metadata cache layer in
src/api/cache.rsto avoid redundant API calls (TTL-based) - Implement rate-limit handling: respect
Retry-Afterheaders from the Spotify API - Display large cover art in playlist and album detail header views
- Audit and remove all remaining mock data across all UI views and components, fetching 100% live Spotify API data
- Optimize long playlist loading with incremental chunking/streaming or virtualized pagination to avoid UI lag
- Validate existing token/session before rendering initial screen to eliminate temporary login flicker
- Achieve near-instant API data loading through aggressive metadata and disk image caching (TTL-based, local disk cache for instant startup render)
- Implement local audio file scanner and persistence matching local tracks in playlists
- Implement Track & Artist Radio / Recommendations endpoint (
GET /v1/recommendations, "Made for You", "New Releases")
Phase 5: UI Design System, Component Polish & Settings Page
- Define a unified design token system (color palette, spacing scale, typography scale) in a central
theme.rs - Replace all ad-hoc hardcoded color literals and magic numbers with design tokens
- Implement smooth hover transitions on sidebar items, buttons, and playback controls
- Implement animated loading skeletons for album art, playlist headers, and track list placeholders while initial Spotify API data is fetching (zero mock/temp data, instant Spotify data render)
- Remove "Explore Premium" / "Explorar Premium" button from sidebar and navigation
- Add waveform or animated equalizer bars to the Now Playing area during active playback
- Implement smooth progress bar animation that interpolates position between tick updates
- Add context menus (right-click) on tracks, albums, and artists with distinct tailored options (Add to queue, Go to artist, Go to album, Share link, Copy URI, Add/remove from playlist, Save album, Follow artist, Edit/delete playlist) with click-outside dismiss, accurate cursor positioning, and 5s auto-dismiss toasts
- Implement a proper volume slider that covers the full 0–100% range with a mute toggle
- Add keyboard shortcuts for Play/Pause (Space), Skip (→/←), Volume (↑/↓)
- Implement a mini-player / compact mode for when the window is resized to small dimensions
- Implement drag-and-drop track reordering within a playlist queue view
- Add toast / snackbar notifications for user-facing errors and confirmations
- Audit and refine all font sizes, weights, and line heights for visual consistency
- Ensure the entire UI is navigable via keyboard (tab order, focus rings)
- SETTINGS PAGE: Build base Settings page layout frame
- LYRICS: Implement base Lyrics view layout frame
- Integrate LRCLIB REST API for millisecond-synced
.lrclyrics auto-scrolling with Genius plain lyrics fallback - Integrate Last.fm API (
artist.getInfo) + Wikipedia REST API for artist bio, curiosities, genres, and similar artists in Now Playing right panel - Implement Spotify Connect icon & interactive device selector modal/popover in bottom playback bar
- Enhance Search screen with Category Pill filters (Tracks, Albums, Artists, Playlists) and Top Result spotlight card
- Implement Friend Activity / Social Feed side panel in right panel slot
Phase 6: Queue, Playback State, Shuffle & Advanced Audio
- Implement an internal play queue data structure in the
Model - Display the current queue in a slide-out panel
- Implement Shuffle mode: randomise queue order and persist the shuffle seed
- Implement Repeat modes: No Repeat, Repeat Queue, Repeat One
- Implement "Add to queue" action from track context menus
- Implement track reordering and control within the play queue view
- Implement Spotify-style structured User Queue, Context Queue, and playback History stack
- Eliminate progress bar jumps and sync position directly with audio stream
- Spotify Connect: Full bi-directional Spotify Connect integration for remote control and device sync
- Crossfade: Smooth audio crossfade between tracks (configurable duration in Settings)
- Implement multi-band DSP Audio Equalizer with presets (Flat, Bass Boost, Vocal, Rock, Pop) integrated into
rodioaudio pipeline - Implement Audio Loudness Normalization (ReplayGain / Spotify Normalization)
- Implement Gapless Playback transition between tracks
Phase 7: System Integration & Local Files
- Add application window and taskbar/dock icon support for Windows, macOS, and Linux distros
- Add 100% functional native System Tray (Systray) icon for Linux, macOS, and Windows with minimize-to-tray and playback menu (Play/Pause, Skip, Show/Hide, Quit)
- Register global media key bindings (MPRIS on Linux, MediaSession on Windows/macOS)
- Implement MPRIS2 D-Bus interface on Linux for desktop environment integration
- Local Files: Implement local audio file scanner and playback for custom local music directory path
- Implement Drag-and-Drop: drop tracks onto left sidebar playlists to append items
- Package the binary as a
.deband.rpmfor Linux - Package the binary as a
.dmg/.appbundle for macOS - Package the binary as an
.msiinstaller for Windows - Integrate auto-update check: compare current version against GitHub Releases on startup
- Write end-to-end integration tests for the auth flow and audio pipeline
Phase 8: Performance & Speed Optimization
- Optimize general app execution speed, reducing UI update latency and startup load time
- Run a full memory profile and verify the application stays under 25 MB baseline at idle
- Profile and eliminate any hot-path allocations in the canvas render loop and audio callback
- Replace any
.clone()/.to_string()in hot paths with borrows (&str,&[u8]) where applicable - Run
cargo clippy --all-targets -- -D warningsclean and resolve all lints - Run
cargo deny checkand ensure no disallowed licenses or duplicated dependencies - Set up memory-leak detection in CI (Valgrind or similar) for the audio pipeline
- Add structured logging (
tracingcrate) with configurable verbosity levels - Implement graceful shutdown: flush audio buffers and close the librespot session cleanly on exit
- RAM baseline optimization: bounded image cache handle capacity to 64 items to keep RAM under 25 MB ceiling
Phase 9: Comprehensive Functional Settings System (100% Backend Wired, Zero Mockups)
- SECTION 1 - Account & Language: External browser link to login methods (
spotify.com/account) & persistent i18n UI language selector dropdown - SECTION 2 - Explicit Content & Autoplay: Explicit content filter toggle (hide
explicit == truetracks) & Autoplay toggle switch (auto-fetch/v1/recommendationson end of queue) - SECTION 3 - Audio Quality & Library: Bitrate selector dropdown (Normal 96k, High 160k, Very High 320k bound to librespot decoder), automatic bitrate step-down on network lag, compact library view toggle, show/hide local files toggle, multi-folder source picker list with live rescanner, and external playlist import button
- SECTION 4 - Display & Canvas: Display toggles (auto-open Now Playing on play, desktop overlay on playback controls) & Canvas/Video toggles (looping background Canvas & audio-only video fallback)
- SECTION 5 - UI Scaling & Hotkeys: UI Scale selector (70%-130%) with
Ctrl +/Ctrl -hotkeys and Reset button - SECTION 6 - Privacy & Profile: Private Session toggle (6h auto-off), recent activity visibility dropdown, connected apps link, and profile element toggles (recent artists, followers, default public playlists)
- SECTION 7 - Playback & DSP Equalizer: Crossfade slider (0-12s), Automix toggle, Smart Shuffle switch, Mono Audio downmix toggle, Volume Normalization & Loudness level (Normal/Loud/Quiet), interactive 6-band DSP Equalizer (60Hz, 150Hz, 400Hz, 1kHz, 2.4kHz, 15kHz with -12dB to +12dB sliders & presets), and audio output device selector dropdown bound to rodio output enumeration
- SECTION 8 - System, Storage & Hardware: Auto-start on system boot dropdown, Close button minimizes to system tray toggle, Storage usage indicator (Downloads vs Cache MB), Clear Cache button (
src/api/cache.rs), Offline storage path relocation picker, Proxy configuration selector (Auto-detect, HTTP, SOCKS5), and Hardware Acceleration switch
Project Metrics
Daily Commits (Last 28 days) (Last 7 days)
Get Involved
If you love systems programming in Rust, software architecture, or simply enjoy crafting highly performant tools, the door is open for your contributions.
Built with passion and code by gefydev. Any PR that respects our philosophy is more than welcome.
Read Contributing Guide