Skip to content

chore(deps): update dependency largemodgames/spotatui to v0.42.0 - #53

Open
renovate[bot] wants to merge 2 commits into
mainfrom
renovate/largemodgames-spotatui-0.x
Open

chore(deps): update dependency largemodgames/spotatui to v0.42.0#53
renovate[bot] wants to merge 2 commits into
mainfrom
renovate/largemodgames-spotatui-0.x

Conversation

@renovate

@renovate renovate Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Update Change
LargeModGames/spotatui minor 0.41.00.42.0

Release Notes

LargeModGames/spotatui (LargeModGames/spotatui)

v0.42.0

Compare Source

Changed
  • Your own Spotify app now comes first: Spotify rate limits are per app, and the shared ncspot client ID that the quick setup uses is counted against every ncspot and spotatui user at once, so playlists stopped loading and the log filled with 429 Too Many Requests no matter what spotatui itself did. Option 2 of the setup wizard (spotatui --reconfigure-auth) now writes your own app as the primary client_id and keeps the shared id only as the fallback for a failed login; before, it was the other way round and your own app was never used while the shared one still answered. A client.yml from an older version is read the new way round, but your app still needs one login: the first launch after the upgrade runs on the shared id and says so until you run spotatui --reconfigure-auth once. When a session runs on the shared id, the rate-limit status message and the log say so and name spotatui --reconfigure-auth as the way out, the wizard's text says which option shares its limit, the wizard asks for the port before it prints the Redirect URI to register, and the login's wait for the browser callback gives up after three minutes instead of holding startup forever. A rate limit on the plan check at startup no longer switches native streaming off for the session: the check waits for the window and asks again.

  • Status messages and errors share the bar more predictably: every status message the network layer shows now lasts as long as status_message_ttl_percent says, the way the in-app ones already did, and none of them overwrites an error that is still on screen; the error stays until its own time is up. A normal message shown right after an error is no longer drawn in the error colour.

  • GitHub releases list every download as a link: the release page now carries direct download links for each binary instead of bare file names, adds the Debian/Ubuntu .deb packages (amd64 and arm64) to the list, and takes its notes from the merged pull requests instead of an excerpt of this file.

Added
  • Qobuz source (--features qobuz, included in the Linux, macOS, and Windows release binaries): spotatui can now play your Qobuz library. Pick Qobuz in the first-run picker or the d menu and log in through the browser; the token is saved in qobuz_credentials.yml (owner-only on Unix), and SPOTATUI_QOBUZ_TOKEN overrides it. The sidebar lists your favorite tracks, playlists, and favorite albums, search finds tracks, and every playback feature the other sources have works: next/previous, seek, repeat and shuffle, the cross-source queue, last_session.yml resume, cover art, lyrics, and OS media controls. Playback uses the same encrypted stream the Qobuz web player uses: each track is decrypted and rebuilt as a FLAC temporary file while it plays through spotatui's own engine (playback starts after the first segments arrive, and a seek past the downloaded part continues the download from there), all off the event pump so the UI stays responsive. behavior.qobuz_quality picks the stream (5 MP3 320, 6 FLAC 16/44.1, 7 FLAC 24/96, 27 FLAC 24/192; default 6). The constants the API needs are read from the Qobuz web player at runtime and cached by bundle version, never embedded; SPOTATUI_QOBUZ_APP_ID, SPOTATUI_QOBUZ_APP_SECRET, and SPOTATUI_QOBUZ_OAUTH_KEY override them when Qobuz changes its web player.

  • Fuzzy filter for the Settings screen: Press the search key (/ by default) in Settings to filter the rows instead of scrolling for one. The query is a fuzzy subsequence, so its characters only have to appear in order: volinc finds Volume Increment and skms finds Seek Duration (ms). Rows match on their name and on their config.yml key, and are ranked best-first with the matched characters highlighted, so every row the filter leaves shows why it is there. Enter applies the filter, Esc clears it before it means "leave Settings", and the filter survives / so one query can be walked across tabs. It reuses the Help menu's filter input, so the editing keys (Ctrl+W, Ctrl+U, Backspace) are the same on both screens (#​469).

  • Tokyo Night theme: preset: "Tokyo Night" under theme: in config.yml (or the Theme row in Settings) switches every colour to the Tokyo Night palette, next to the existing presets.

  • Adaptive theme from the cover art: with behavior.cover_art_theme: true (the Adaptive Theme row in Settings; off by default), the accent colours follow the album that plays. The two dominant colours of the cover become the active border, banner, hover and selection colours, the playbar progress, the highlighted lyric line and the visualizer bars, fading in over under a second at every track change and fading back to your preset when you switch it off. Text, background, hints and error colours stay as the preset sets them so nothing becomes unreadable on a washed-out cover. The cover is fetched for its colours even when the art pane is hidden. Only in builds with the cover-art feature, which every release binary has.

  • cava visualizer: the analysis screen's default visualizer is now a port of cava's engine, running inside spotatui with no cava install needed. Bars are drawn in eighth-blocks as a mirrored stereo layout with the bass meeting in the middle, and the bar count follows the terminal width. V on the analysis screen cycles between it and the Braille bar graph; in config.yml the styles are Cava and BarGraph, and a file that still says Equalizer or Classic loads as Cava.

Fixed
  • Your own Spotify app works again for search, follow, and playlists: since March 2026 Spotify runs Development Mode apps (every app you create yourself; the shared ncspot client ID is exempt) against a smaller API. The search endpoint caps limit at 10, while spotatui sized every search request by the terminal height, up to 50, so with your own client ID every search on the search screen and in the add-to-playlist picker ended in Spotify API 400 Bad Request ... "Invalid limit". Search requests are now capped at 10 results per category; the library pages keep their 50, and spotatui search --limit and the DJ's search_tracks tool accept 1 to 10. The artist follow check that runs after every search, follow and unfollow of an artist, creating a playlist, removing a track from a playlist, and the DJ's Liked Songs check, playlist crawl and queue-by-URI lookup still used endpoints Spotify removed for those apps (me/following, users/{id}/playlists, playlists/{id}/tracks, me/tracks/contains, tracks?ids=), which answered 403 Forbidden; each now uses its replacement (me/library, me/playlists, playlists/{id}/items, one tracks/{id} per track), and a failed follow check is logged instead of taking over the screen. The artist screen's top tracks and related artists, Discover, and Recommendations have no replacement for Development Mode apps yet.

  • A Listening Party can no longer start Spotify on top of another source: with Local Files, Subsonic, Internet Radio, YouTube or Qobuz playing, native Spotify streaming is only paused, and the party relay (a guest following the host's state, a host running a guest's command) still picked the Spotify player from its device identity. It transferred and activated the Connect device and loaded the host's track into it, or paused, skipped and seeked the paused player, so Spotify audio started on top of the track you were hearing. Every Spotify playback call now checks who owns the output first and does nothing while another source plays (switching Spotify to the spotatui device says so; switching it to another device still works), and the party ignores messages until Spotify plays again. The host publishes only a Spotify track it plays itself: while it plays another source or the cross-source queue it sends nothing instead of the suspended Spotify track, and a guest ignores a state it cannot play instead of pausing or resuming its own music to match. Party commands now run through the same path as a keypress.

  • The jump and add-to-playlist keys follow the track that plays: with a Spotify track playing from the cross-source queue, jump to album (a), jump to artist (A) and add the playing track to a playlist (w/W) acted on the track of the suspended Spotify context, so they opened the album, the artist and the picker for a song you were not hearing; they now use the queued track itself, and jump to context (o) says the queue slot has no play context. Under Local Files, Subsonic, Internet Radio, YouTube or Qobuz those five keys (a, A, o, w, W) say they need a Spotify track playing instead of acting on the suspended one, and with nothing playing the three jump keys say so instead of doing nothing. Like (F) already followed the queued track and keeps doing so; it now shares the same resolution.

  • Spotify's rate limit no longer crashes spotatui at startup: with a cached login, startup verifies the token with one /me request, and that request went straight through rspotify with none of the pacing and Retry-After retries every other Spotify call gets. A 429 there ended the process with Error: http error: status code 429 Too Many Requests before the UI existed, and relaunching only added more unpaced hits on a rate limit that is shared by everyone using the same client ID. The check now goes through the same paced, retrying request path as the rest of the app, and when Spotify still answers with anything other than a rejected token (a rate limit that outlasts the retries, an outage, no network) spotatui keeps the cached token and starts instead of quitting; the native-streaming account check asks again with its own retries (#​504).

  • Logging in to Spotify no longer fails with "Unable to connect" when the browser was not already running: both login flows (the startup wizard and d then Spotify in the app) opened the browser first and only then started listening for the OAuth redirect on 127.0.0.1:8989. On Linux desktops where xdg-open runs the browser in the foreground (Hyprland and other sessions it does not recognise), a browser that was not already open kept that launch call from returning until the browser was closed, so the listener never started and the redirect landed on a closed port; inside the app, the network layer was stuck for the same time. The listener is now bound before the browser opens, and every browser launch (Spotify login, Qobuz login, the listening recap) is detached so a launcher that waits can never stall spotatui.

  • The sidebar, the help menu and Settings only offer what your source can do: without a Spotify session the Library panel used to be hidden under every other source, which also hid Friends and Stats even though neither needs Spotify, while under the Spotify scope it kept offering Liked Songs, Albums, Artists, Podcasts, Discover and Recently Played, each ending in the "Spotify not connected" message. The panel is now drawn under every source with the rows that work: Friends and Stats always, Local Files and AI DJ when built in, and the six Spotify rows only with a Spotify session; a mouse click on the panel lands on the row you see. The help menu (?) applies the same rule: a rebindable key that needs Spotify or another source stays listed with a (needs Spotify) / (not for Local Files) / (Internet Radio only) suffix, and a fixed key of a screen your source cannot reach is left out. Settings hides the Spotify-only behavior rows (the playback poll, the liked and episode icons, the saved-library sort orders, the community pin) without a session, marks the Spotify-only key rows the same way, offers only home and stats as startup routes without a session instead of five screens that would open empty, and names the d row "Switch Music Source" to match the help menu. The copy-song-URL and copy-album-URL keys now follow the track that plays, not the browse scope: a Spotify track playing under another source still copies, and with nothing playing both keys say so instead of doing nothing. The search key without a Spotify session says so too, instead of opening an input that cannot search.

  • Disconnecting headphones no longer freezes spotatui: with a decoded source playing (Local Files, Subsonic, Internet Radio, YouTube, Qobuz), unplugging the output device — Bluetooth headphones disconnecting, a USB DAC pulled — left the audio engine waiting on an audio callback that would never run again. Because that wait happens on the same serial queue every other request goes through, the whole app stopped responding: playback was silent and searches, browsing, and playback controls stopped working until restart. The engine now notices the device is gone - both when it is unplugged and when the system simply moves its default output elsewhere, which nothing reports - and refuses those calls instead of waiting, then rebuilds the output on the new default device and puts the track back where it was. Unplugging pauses it there, the same thing macOS does when AirPods come out; plugging something in keeps it playing, now through the device you just connected. Radio stops instead (a live stream has no position to return to), and a track playing from the queue resumes at the next queued item (#​496).

  • A radio station spotatui cannot decode no longer freezes the app: picking certain stations played nothing, showed no error, and left the app unusable — the music already playing kept going, but search and the playback controls stopped responding until restart. Starting a station ends with working out its audio format, and that search reads the stream until it recognises something; a live stream never ends, so a station in a format the decoder does not know left it reading forever, blocking everything else. Tune-in is now bounded like the connection and header steps already were: it gives up, stops the download, and says the format was not recognised. Common on Italian and other European stations, which often broadcast a variety of AAC the bundled decoder does not identify — those still will not play, but they now fail in a second or two and leave the app working (#​497).

  • The extra music sources now play on macOS: Local Files, Subsonic, Internet Radio, YouTube, and Qobuz all decode through one shared audio engine, and that engine refused to open an output device on macOS, so picking any of those sources answered "No audio output for local playback" instead of playing. The refusal was inherited from crashes in librespot's own older audio backend (#​9/#​20) and never applied to this engine, which is a different, newer output path; measured on CoreAudio, it plays. All five sources now work on macOS and are included in the macOS release binaries. Native Spotify streaming is unaffected: it keeps its own portaudio backend. The macOS media keys and Now Playing now work for these sources without a Spotify login.

  • Local files: nested music folders are now browsable: the local-files library only listed the immediate subfolders of behavior.local_music_path and only counted the audio sitting directly inside them, so a library organised one level deeper — Artist/Album/…, or a downloader's Jamendo/Playlist - Fresh & New/… — showed those container folders with a 0 track count and an empty track table when selected. The scan now walks the tree up to eight levels deep: every folder that actually holds audio becomes a playlist, named by its path relative to the music root (Jamendo/Playlist - Fresh & New), while folders that only contain other folders are no longer listed at all. Linked folders are walked once, hidden entries are skipped in both the folder count and the track table, and a folder that cannot be read is skipped instead of failing the scan, so neither a link loop nor one permission-denied folder can hide the rest of the library.

  • Self-update now works on Linux ARM64: the checksum verifier only knew four platforms, so spotatui update aborted with "unsupported platform" on aarch64 Linux (Raspberry Pi, ARM servers, Asahi) even though every release publishes spotatui-linux-aarch64.tar.gz. The platform table now covers all five published targets, with a test pinning it against the release workflow (#​440).

  • A malformed keybinding no longer crashes spotatui at startup: a binding like ctrl-, a bare ctrl, or a multi-key suffix like ctrl-ab in config.yml panicked (or was silently mis-read) during config load, before the UI existed. It is now a logged config warning naming the offending shortcut, that binding keeps its default, and the app starts normally, like every other invalid config value (#​441).

  • The Stats screen can be chosen as the startup screen from Settings: startup_route: "stats" always worked when typed into config.yml, but the in-app Settings cycle never offered it. The cycle now matches the full startup-route list, and a test keeps the two from drifting again (#​443).

  • Plugin keybindings can no longer silently shadow remove-from-queue: the collision check that rejects plugin commands bound to named action keys was missing remove_from_queue (default x), so a plugin bound to x loaded without a warning and fought the queue view for the key. It is now rejected with the same collision warning as every other named action (#​445).

  • Native streaming no longer steals playback back after a Spotify Connect handoff: session teardowns are now classified by librespot's disconnect reason instead of inferred from connection state. When playback moves from spotatui to a phone, car, or another device, the rebuilt Connect backend stays idle: the published queue slot and any parked playback request are cleared instead of replayed, the dead queue slot no longer owns the playbar and transport controls, recovery re-registration no longer transfers playback off a device that took over, and the "Playback moved to another Spotify device." message is no longer overwritten by a bogus "recovered" notice. Unexpected shutdowns still restore playback, including a queue playing over an idle app, and local shutdowns stay stopped (#​437).

  • Spamming Previous on the first track no longer bricks native streaming: under native streaming, pressing Previous within the first 3 seconds of the first track of a context (or after skipping back through every earlier track) told librespot to go to a track that does not exist, and librespot answered by stopping playback: audio went silent, the progress bar froze, and Play, Pause, and Seek could not bring it back until a track was started by hand or playback was transferred from another device. That is upstream librespot behaviour, so the fix lives in our maintained fork (0.8.2): Previous with nothing before it now restarts the current track, the way Spotify's own clients do, and a seek made on the player also updates the position librespot uses for its 3-second rule, so a second press right after a restart goes to the previous track instead of restarting again (#​366).

  • nix build and nix run download crates again: since 2026-08-27 every crate fetch in the flake build failed with HTTP 403, on released tags too. crates.io now refuses the deprecated api/v1/crates/<name>/<version>/download endpoint to the fetcher nixpkgs uses, and the nixpkgs revision pinned in flake.lock (March 2026) downloaded every crate through it. The pin moves to current nixos-unstable, whose importCargoLock fetches from static.crates.io instead, and the Nix toolchain goes from Rust 1.93 to 1.97 with it. That nixpkgs (26.11) also dropped x86_64-darwin, so the flake no longer declares that system; Intel Mac users keep the release tarball, which is still built (#​493).

  • spotatui starts and plays without a Spotify login: a launch used to open the browser for a Spotify login whenever no token was cached, even for someone who had picked Local Files, Subsonic, Internet Radio, YouTube or Qobuz and never wanted one, and a cancelled login was written to state.yml so the next launch asked again. The browser now opens only right after the setup wizard or --reconfigure-auth; a plain launch loads the cached token silently and starts without one, and d then Spotify logs in from inside the app. A CLI subcommand without a token stops with "Spotify is not connected. Start spotatui, press d and pick Spotify to log in." instead of opening a browser. Without a session, the transport keys say "Nothing is playing" instead of sending commands to a Spotify that is not there, starting a track from a source the binary was built without says which feature is missing instead of tearing down what plays, and starting or joining a Listening Party says Spotify is not connected instead of hanging the app. On Windows, the media keys and the system media overlay now work for the decoded sources without a Spotify login.

  • A Spotify rate limit no longer stalls the other sources: a 429 Too Many Requests used to be retried in place, sleeping on the same serial queue every other request goes through, so a saturated shared client ID delayed a Qobuz or Local Files track change or skip by up to half a minute and put the error page up. Spotify's Retry-After is now remembered, requests that would hit Spotify inside that window are queued in order and released when it ends, and the bar says "Spotify rate limit: waiting 30s" once. The playback poll also stops while another source owns the sink, so it no longer spends the rate limit for nothing.

  • The error screen no longer latches for the rest of the session: an error, once shown, stayed recorded forever; leaving the screen by pressing the search key rewrote the error frame into the search input, after which no later error could render at all. Errors now expire after a minute (an expired error still on screen hands its text to the status bar), Esc and the back key dismiss the frame and the message together, and the search key on the error screen dismisses it first. A failed state.yml save is a status-bar message instead of the error page, reported once per failure run rather than twice a second.

  • cargo install spotatui gets the maintained librespot fork: the fork was pulled in through a [patch] section that cargo drops when a crate is published, so a crates.io install silently built against upstream librespot 0.8.0 and missed every fork fix (the CDN 530 fallback, dealer reconnects, the hardened OAuth listener). The fork is now published as the spotatui-librespot-* crates and pinned directly, so every install method builds the same player.

  • A symlinked config.yml keeps its link, and a read-only one no longer aborts startup: config files managed by home-manager, stow or chezmoi are symlinks into a store that may be read-only, and every write replaced the link with a plain file or, for a read-only target, crashed at boot. Writes now follow the link and swap the file at its target, a dangling link gets its target created, and a write into a read-only store fails with an error and leaves the link alone. The global song counter prompt, the first-run source picker and the Subsonic setup warn that the answer could not be saved and carry on (the prompt names enable_global_song_count as the key to set by hand); the settings editor still shows the error and applies the change for the session (#​512).

  • A queued Spotify track no longer goes silent at its end: under native streaming, when a track playing from the cross-source queue ended, librespot looked for the next track of a context it had never loaded, found none and stopped the player, so the next queued item never played; the playback poll also redrew a paused playbar over queued playback it could not see. The fork (0.8.3) now tells the queue's loads apart from its own context, and the poll no longer marks queued playback paused.

  • The CLI works again when no Spotify device is active: spotatui playback --play, --pause, --next, --previous, --seek, --shuffle, --repeat, --volume and spotatui play all failed with 404 NO_ACTIVE_DEVICE as soon as the TUI had exited, which is the CLI's normal state. On that answer, each command now retries once on the device saved by spotatui set-device, which also activates it; a failed retry shows the original error. play --queue cannot be retried this way, since queueing cannot activate a device (#​464).

  • Plugins and agents respect who owns playback: a Lua plugin's set_repeat reached the real Spotify device while the cross-source queue or a radio station owned the sink, changing the repeat mode of a player that was not on screen; it now gets "Repeat does not apply to this source" like the key does (#​376). The MCP and AI DJ skip_track tool went straight to Spotify as well, skipping the wrong player while the queue or a decoded source played; it now takes the same path as the next-track key.

  • YouTube downloads retry through the embedded player: YouTube's PO-token enforcement makes most label uploads fail with a 403 on the default player clients, so those videos would not play. A failed download is retried once through the web_embedded and tv_embedded clients, which still serve embeddable videos without a token; a video that is both token-gated and not embeddable still fails, with the original error.

  • AI DJ no longer crashes when the config directory cannot be written: the DJ's agent CLI ran in a scratch directory under the config dir and failed outright when that could not be created, as in a Nix sandbox or a read-only home. It now falls back to a fresh, owner-only directory under the system temp dir, and a failed launch of the agent command names the directory and the OS error instead of implying the binary is missing (#​478).


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Enabled.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate
renovate Bot enabled auto-merge (squash) September 8, 2026 12:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants