You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
separates Spotify Web API tokens from reusable librespot playback credentials
adds a one-time playback authorization flow using librespot's built-in client identity, PKCE, the streaming scope, and the /login callback
stops playback before queue commit/advance when authorization is missing or rejected
preserves local-file playback and genuine per-track unavailable behavior
shows a descriptive modal, retains the intended track, and retries it exactly once after authorization
logs playback phase, URI, librespot error kind, and full underlying error without credential material
documents the August 2026 Spotify/login5 compatibility change and the research behind the fix
Root cause
Spotify Web API OAuth still permitted library sync and search, but Spotify's login5 playback path began rejecting credentials minted under Retune's Web API client identity. The prior implementation reused one OAuth credential for two independent contracts, so browsing remained healthy while every audio load failed with FailedPrecondition / INVALID_CREDENTIALS.
Rejected and transient authorization are not tested at the controller boundary.playback/mod.rs:1841-1893 proves only the missing-credential start/advance paths. The rejected/transient tests stop at local.rs:565-624, directly calling session_error; they never exercise step_locked (playback/mod.rs:1092-1100) or start with a semantic login5 failure. A regression that advances/commits before handling a rejected credential, or turns a transient failure into an authorization prompt, would pass. Add controller tests for rejected start/advance retaining the original snapshot/index, and transient failure retaining credentials without authorization handling.
The Cancel/Escape and exactly-once retry journey has no behavioral test. The retry and cancellation state live in App.tsx:346-357, while the modal delegates Escape/Cancel through dialogViews.tsx:165-170. test/ui.test.ts:135-148 tests only pure predicates, not usePlayer's pending reference or calls to start. It would remain green if Cancel left a pending target or a successful authorization invoked play_tracks twice. Add a small hook/component-level test that drives prompt → Cancel/Escape and prompt → authorized connection change, asserting zero and one retry respectively for the original target.
Durable playback credentials are not covered through the stores and Web reconnect path. The encrypted-store test at tokens.rs:510-537 saves a token with playback_credentials: None; the base64 test at tokens.rs:441-454 bypasses the store. The reconnect preservation added in spotify_commands.rs:58-71 has no test, and the new authorization command is covered only by the field-validation helper at spotify_commands.rs:451-465. A change that drops the reusable credential during encrypted persistence or a normal Web OAuth reconnect would pass. Add a round trip through EncryptedFsTokenStore with credentials and a reconnect-token replacement test preserving them.
The no-secret diagnostic requirement has no regression check.local.rs:327-329 logs the complete librespot error with {:?}, and the new authentication paths surface error.to_string() (spotify_commands.rs:116-123). No test captures diagnostics with sentinel access/auth values and asserts they are absent. Add one logging/error-boundary test so future dependency/error-format changes cannot leak reusable credentials.
Minor
Offline-safe preference saves are untested. The changed behavior is in lib.rs:679-703, but no test invokes this branch with local playback selected and an unavailable Spotify client/token store. The current code is straightforward, so this is lower risk, but a focused command/state test should prove the setting persists without attempting activation or emitting an operation error.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #15
What changed
streamingscope, and the/logincallbackRoot cause
Spotify Web API OAuth still permitted library sync and search, but Spotify's login5 playback path began rejecting credentials minted under Retune's Web API client identity. The prior implementation reused one OAuth credential for two independent contracts, so browsing remained healthy while every audio load failed with
FailedPrecondition / INVALID_CREDENTIALS.Validation
cargo test --workspacecargo clippy --workspace --all-targets -- -D warningscargo fmt --all -- --check