project / linux setup
activeCrimson Playback TUI
A terminal-first, accessibility-focused playback controller designed around one authoritative browser-backed device instead of translating between two competing queues.
- Rust
- Ratatui
- Spotify Web API
- Web Playback SDK
- OAuth PKCE
- NixOS
- Eww
Current direction
Crimson Playback TUI is the next step after a useful but increasingly fragile experiment: embedding ncspot in an Eww-managed terminal panel and forwarding its selections to a persistent browser playback engine.
That prototype exposed the central problem. ncspot and the browser each owned a different queue and playback context. MPRIS could report the current track, but not enough of the initiating view to preserve every Liked Songs, playlist, album, and queue action. More translation code made the mismatch more visible; it did not remove it.
The new design gives Spotify’s supported playback interfaces sole authority. The terminal application renders library and playback state directly, while a managed browser supplies the DRM-capable Web Playback SDK device.
terminal UI → local daemon → documented Web API
└──────→ managed browser playback engine
One application
Authorization, callback handling, token refresh, browser startup, device registration, and the TUI will ship as one application.
The normal entry point is deliberately simple:
crimson-playback
On first launch it starts the daemon, opens authorization in the normal browser, receives the loopback PKCE callback, starts the internal playback engine, waits for its fresh device ID, and then presents the terminal interface. The browser is still an internal process because the playback SDK requires it, but it is no longer something the user has to manage.
The TUI may close while the daemon keeps playback alive. Reopening it reconnects to the same authoritative session instead of creating another player.
Why terminal-first
The project is not an attempt to reproduce every screen in an official client. Its independent value is a compact keyboard workflow designed for a heavily customized Niri desktop:
- predictable navigation at fixed terminal dimensions;
- visible, inspectable state rather than hidden browser automation;
- local IPC for Eww and future Quickshell surfaces;
- an accessible command model that does not depend on pointer-heavy layouts;
- one source of truth shared with phone and Spotify Connect controls.
Device contract first
The existing bridge’s most useful result is its device lifecycle. The Web
Playback SDK emits a fresh ephemeral device ID when it becomes ready. The new
daemon records that ID only as runtime state, invalidates it immediately when
the SDK reports not_ready, and refuses to target a stale or silently selected
household device.
The active target is always visible in the terminal status surface. Restarting the browser requires a new registration; restarting the TUI does not.
Public API boundary
The implementation will use documented Web API and Web Playback SDK behavior. It will not depend on DOM scraping, private endpoints, undocumented collection contexts, downloaded audio, or synthetic engagement.
This boundary matters most for Liked Songs. If the public API cannot represent the same context label that an official client uses, the interface will disclose that limitation instead of guessing an album or claiming false synchronization.
Present state
The project currently has a detailed architecture, device contract, security model, policy boundary, testing strategy, and staged implementation plan. No production application code exists yet.
The first build session will implement only one vertical slice: authorization, a registered browser device, a visible now-playing surface, one album view, and exact album-context playback. Queue and library breadth come after the phone, TUI, and browser agree on that minimal state.