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
fix: keep the streaming OAuth callback alive through browser noise (#423)
# Summary
Fixes#414. The streaming login hands port 8989 to librespot, whose
callback server accepted exactly one connection and gave up if it was
not the redirect, dropping the listener and closing the port. Some
browsers, LibreWolf in particular, send a bare CRLF or open a connection
without writing to it before the real callback arrives. librespot
consumed that, failed to parse it, and closed the port, so the redirect
carrying the code hit a dead port. The user is left on a browser "unable
to connect" page, and because the flow errors before `save_credentials`
it repeats on every launch, which is the "streaming cookie does not get
cached" the reporter described.
Not Windows specific. Three independent reports line up: upstream
[librespot#1705](librespot-org/librespot#1705)
(LibreWolf + ncspot on Fedora, with a debug trace showing the empty line
and vanilla Firefox working as a control), #234 (LibreWolf on Gentoo,
same "web API login works, streaming fails" split), and #364 (a
commenter with `AuthCodeListenerParse` in their log who confirmed Chrome
works). The common variable is the browser.
spotatui's own callback server never had this problem:
`extract_callback_url` runs `split_whitespace()` over the whole buffer,
which steps over a leading CRLF, and it answers unrelated requests with
a 400 and keeps waiting. `read_line` stops at the first `\n`. Only the
librespot half was fragile, which is why the web API login succeeded and
the streaming one did not.
Fixed in our librespot fork rather than here, since that is where the
defective listener lives. The fork cherry-picks upstream PR
[#1706](librespot-org/librespot#1706) with its
original attribution, then hardens it: #1706 skips to the next
*connection* on a blank line, which is correct only if the blank line
arrives on its own connection and hangs if it is a leading CRLF on the
same one. This PR bumps the `[patch.crates-io]` rev to pick that up.
Three unrelated startup bugs found while tracing this are fixed in their
own commits:
- **Auto-update deadlock.** `run_auto_update` ran concurrently with
authentication in a `tokio::join!` and re-exec'd immediately on a
successful install. The re-exec blocks the task in `Command::status()`,
so the joined authentication future stops being polled while it still
owns the callback port, and the child, which repeats startup from
scratch, cannot bind that port. The parent waits on the child, the child
waits on a port the parent will never release. The check still runs
concurrently; only the restart moves to after the join.
- **Log path.** `setup_logging` hard-coded `/tmp/spotatui_logs/`, which
on Windows is drive-relative, so the app printed a location the user's
shell could not resolve directly above the line inviting them to report
bugs. Now resolved through `std::env::temp_dir`.
- **OAuth port probe.** `wait_for_oauth_callback_port` refused to start
the login when its probe timed out, so we never even attempted and
reported something vaguer than the bind error librespot would have
produced. It now warns and proceeds.
# Testing
- `cargo fmt --all` (and `--check`, clean)
- `cargo clippy --no-default-features --features telemetry -- -D
warnings` (clean)
- `cargo clippy -- -D warnings` (clean, default features)
- `cargo test --no-default-features --features telemetry` (544 passed)
- `cargo test` (809 passed)
In the fork, `cargo test -p librespot-oauth` (14 passed) and `cargo
clippy -p librespot-oauth --all-targets -- -D warnings` (clean). The
listener tests cover both shapes of librespot#1705 (blank line on the
same connection, and on a separate one), a `/favicon.ico` request before
the callback, a code surviving a browser that hangs up before the
success page is written, and a peer dribbling bytes being cut off at the
deadline. They run behind a watchdog so a regression fails the suite
instead of hanging it.
Reviewed across five rounds with the Codex CLI, which caught four real
defects: a captured authorization code being discarded when the success
page failed to write, the accept loop having no overall deadline, HTTP
header lines being read as if each were a request, and the deadline not
covering an in-flight read.
# Additional notes
Not verified against a live LibreWolf on Windows. I am on Linux and
cannot reproduce the reporter's setup, so this rests on code reading
plus the three corroborating reports above rather than an observed
repro.
A fork fix reaches everyone who installs today: GitHub releases, winget,
Homebrew, both AUR packages, and `install.sh`/`install.ps1` all build
with `[patch]` active. The one gap is `cargo install spotatui` from
crates.io, which is stuck at 0.40.2 because the v0.40.3 publish job
fails to compile against upstream librespot (`unresolved import
librespot_connect::SavedPlaybackState`). Worth fixing separately; those
users cannot get 0.40.3+ by any route today.
Workaround for anyone hitting this before the next release: set
`enable_streaming: false` in `client.yml`. That stops the every-launch
browser flow and leaves Spotify Connect working.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Log files now use a platform-appropriate temporary directory and
include the process ID.
- The changelog displays the actual log-file location.
- Automatic updates restart after authentication resources are released.
- **Bug Fixes**
- Improved OAuth callback handling when the callback port is
unavailable.
- Streaming authentication errors now include more actionable details.
- Updated playback and connection reliability fixes.
- **Documentation**
- Updated safe-by-default guidance to explain how to find the log-file
location.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Copy file name to clipboardExpand all lines: docs/configuration.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -15,7 +15,7 @@ Machine-managed runtime state lives separately in `$XDG_STATE_HOME/spotatui/stat
15
15
16
16
## Safe by default
17
17
18
-
A typo in `config.yml` never prevents the app from starting. Structural mistakes — an unknown sort field, a bad template placeholder, an invalid column id, an icon that is too wide — are logged as warnings and the affected value falls back to its built-in default. Warnings go to the log file whose path is printed at startup (`/tmp/spotatui_logs/spotatuilog<pid>`).
18
+
A typo in `config.yml` never prevents the app from starting. Structural mistakes (an unknown sort field, a bad template placeholder, an invalid column id, an icon that is too wide) are logged as warnings and the affected value falls back to its built-in default. Warnings go to the log file whose path is printed at startup, a `spotatui_logs/spotatuilog<pid>` file inside your system temp directory (`%TEMP%` on Windows, `$TMPDIR` where set, otherwise `/tmp`). The startup line reports the resolved path, so copy it from there rather than guessing.
19
19
20
20
Only two kinds of errors are fatal: YAML syntax errors (the file cannot be parsed at all) and a handful of out-of-range numeric values that bypass the warn-and-fallback policy: `volume_increment` outside 0–100, a tick rate (or animation tick rate) outside 1–999ms, an unparseable `auto_update_delay`, `playback_poll_seconds` below 1, and `like_animation_frames` below 1.
0 commit comments