Fixed
- Liked icons now show reliably everywhere: Album tracklists, artist pages, Recently Played, Discover lists, and recommendations now fetch the liked state of their tracks when opened, so the liked marker no longer appears only for songs played or searched this session. Artist pages also fetch saved-album and followed-artist state for their heart markers. In addition, liked-state lookups are now batched at Spotify's documented 40-URI limit instead of 50, fixing a
400 Bad Request "Too many uris"error that silently blanked the icons for any playlist or album longer than 40 tracks (#118). - Native idle recovery no longer repeats forever: When Spotify reports no active playback after a stale native session, spotatui still tries to restore the local device automatically. It now stops after two recovery attempts for the same idle session instead of sending
transfer(None)andactivate()every few seconds (#311). - Album tracklists no longer cut off at 50 songs: Opening an album now pages through the full Spotify tracklist instead of stopping at the API's 50-track page limit, whether the album is opened from search results, an artist's discography, a track's context, or the saved-albums library (#324).
cargo install spotatuibuilds again: A fresh dependency resolve pulled invergen 9.1.0, which breaks librespot's build script (two incompatiblevergen-libversions in the graph, error E0277). A constraint-only pin keepsvergenbelow 9.1 until librespot ships a fix; the README now also recommendscargo install --locked(#350).ssaves tracks in search results: Pressingson a highlighted track in the Songs search block now toggles its saved/liked state, matching the track-table binding shown in the help menu. Search results also fetch the liked state of listed tracks, so already-liked songs show the liked marker and toggle correctly (#348).- MPRIS controls survive native-player recovery: Linux MPRIS events now look up the active native streaming player when they arrive, rather than retaining the instance created at startup. Media controls therefore continue to work after spotatui recreates its native player during streaming recovery (#356).
- Unmapped high function keys no longer crash the TUI:
F13throughF24now safely map to the unknown-key fallback instead of panicking, which protects spotatui from extended function keys emitted by global hotkeys (#332).
Added
- Lua scripting API v5: A major expansion of the plugin API. Plugins can now read library data asynchronously (
get_playlists,get_queue,get_search_results,get_saved_tracks/albums/shows,get_recently_played,get_devices,get_lyrics, all with the(data, err)callback convention), drive far more of the app (set_repeat/cycle_repeat,transfer_playback,play_uri/play_context,add_to_queue, playlist create/edit, save/follow actions), schedule work withset_timeout/set_interval/cancel_timer, persist state in a per-plugin JSON store (storage_get/set/remove/keys), navigate (navigate/back/current_route), read the user config (config()), react to new events (shuffle_change,repeat_change,device_change,search_results,route_change), and register full custom screens with paragraph/list/gauge widgets and per-key callbacks (register_screen,set_screen,show_screen,close_screen). Seedocs/scripting.mdand the newexamples/plugins/queue-browser.lua. - In-app listening stats and recap flow: The Library now includes a Stats screen with selectable 7-day, 30-day, monthly, yearly, and all-time views of total plays/listening time, top tracks/artists/albums, recent daily activity, plus current and longest listening streaks. Press the configurable recap key (
Rby default) to generate a shareable HTML card for the active period; the app can also offer a monthly recap on first launch of a new month (disable it withbehavior.enable_monthly_recap_prompt). Listening history now syncs individual completed songs to spotatui.com whenbehavior.sync_tokenis configured, while retaining unsynced records locally for later retry. - Playlist folders in the add-to-playlist picker: The
w"Add Track To Playlist" dialog now shows your Spotify playlist folders and navigates them like the sidebar:Enteron a 📁 row opens the folder, the←row goes back, andEnteron a playlist adds the track. Only editable (owned or collaborative) playlists are offered, and the "Playlist Folders First" setting orders the dialog too. If folder data is unavailable (librespot rootlist fetch fails, or a build without native streaming), the dialog falls back to the previous flat list. - Global customization: Nearly every part of the UI is now configurable via
config.ymland the Settings screen. Pick the screen that opens at launch (startup_route: home, recently played, podcasts, discover, artists, or saved albums — fetched on startup so it arrives populated) and a default sort order per screen (default_sort_playlist_tracks/_saved_albums/_saved_artists/_recently_played, asfieldorfield:desc). Rearrange the layout withsidebar_position: left|right|hidden(hidden auto-reveals while the sidebar has focus) andplaybar_position: bottom|top, and tune the responsive breakpoints (small_terminal_width/_height). New icon fields (progress-gauge fill, sort arrows, episode-played marker, active-source dot, list cursor) join the existing ones in a new Icons Settings tab, with one-column width validation where table alignment depends on it. The playbar buttons can be relabeled (behavior.playbar_control_labels, hitboxes resize automatically), the playbar status line and window title are format templates (format:section with{state},{device},{volume}, … placeholders), and every table's columns can be reordered, removed, renamed, and resized (tables:section). Timing constants are exposed too: status-message duration (status_message_ttl_percent), playback poll interval, table scroll padding, and like-animation length. Invalid values never brick the app — structural config errors log a warning and fall back to the built-in default. Documented indocs/configuration.mdwith a full commented example atexamples/config.example.yml. - Native cross-source play queue: Press
zon any track to add it to a native queue that plays across sources (Spotify, Local Files, Subsonic, and YouTube in one FIFO; internet radio is excluded since a live stream is not a finite track). Queued tracks play before the underlying playlist/album context, then that context resumes where it left off. Open the queue withShift+Q: remove the selected item withx(rebindable viaremove_from_queue, defaultx), reorder it withJ/K, or pressEnterto skip ahead and play it now. The Queue screen also previews what resumes from the underlying context once the queue drains. The queue survives restarts (persisted inlast_session.yml). Spotify tracks queue through native (librespot) streaming; when you are controlling an external Spotify Connect device instead,zkeeps the previous Web-API "add to Spotify's queue" behavior (#206). - Terminal (ANSI) theme preset: A new theme preset built entirely from the terminal's own ANSI palette colors instead of hardcoded RGB, so terminal-theming tools like pywal recolor spotatui live, without a restart (#336).
- Playlist Folders First setting: A new
behavior.group_folders_firsttoggle (Settings → "Playlist Folders First") lists your Spotify playlist folders at the top of the Playlists tab, above playlists, keeping each group's existing order. Off by default. Handy because folders keep their creation date and otherwise sink to the bottom of the recency-sorted list. - GitHub profile now-playing widget: With a spotatui.com account you can now embed a live "now playing" card in your GitHub profile README (
), enabled from the spotatui.com dashboard by picking a public username and turning the widget on. To power it, the now-playing cloud sync (requiresbehavior.sync_token) now includes the album, cover-art URL, track duration and progress, play/pause state, and a LIVE flag for internet radio; it also pushes immediately on pause/resume and seeks, keeps heartbeating while paused so the card shows "paused" instead of going offline, and clears your status as soon as playback stops rather than only on exit.
Changed
- Documentation refresh: Reworked the README around spotatui as a multi-source terminal music player, with a shorter quickstart, source overview, feature summary, and updated
cargo install --lockedguidance. The configuration and scripting documentation now cover the expanded customization and Lua APIs.
Internal
- Dependency maintenance: Updated the Rust dependency set, including
rodio0.22,symphonia0.6,lofty0.24,mlua0.12,md-50.11, and theclap_complete/open/tempfilerollup. - CI maintenance: Documentation table-of-contents updates now open a pull request instead of attempting to push directly to protected
main.
Downloads
- On Windows 10/11 (64-bit) →
spotatui-windows-x86_64.zip - On Linux (Ubuntu, Arch, Fedora, etc.) →
spotatui-linux-x86_64.tar.gz - On macOS with Intel CPU →
spotatui-macos-x86_64.tar.gz - On macOS with Apple Silicon (M1/M2/M3) →
spotatui-macos-aarch64.tar.gz
Checksums (.sha256) are optional and only needed if you want to verify the download.
The Linux and Windows builds include the extra music sources (Local Files, Subsonic, Internet Radio, YouTube). The YouTube source needs yt-dlp installed (ffmpeg recommended).
To update use "spotatui update --install" or use your package manager of choice.