crabidy/architecture
Test User a2e3da6aa5 cbd-tui: speak MPRIS, so the media keys reach the server
The recollection that this used to exist is false — `git log --all -S
mpris` finds nothing on any branch. What has always been there is the
desktop *notification* on a track change, which is D-Bus but not MPRIS: a
popup is neither a status-bar entry nor a key target. So this is new, not
a regression.

Everything the protocol needs was already on the wire, so cbd-tui gains a
second front-end onto the two channels it already has: stream updates in,
MessageFromUi out. The MPRIS player is a peer of the UI thread — it
commands the server through the very channel the keybindings use, and it
learns the result the way the UI learns about a keypress from another
client. No proto change, no server change.

The decisions worth knowing (architecture/mpris.md):

- An absolute protocol over a toggling server. Play/Pause/SetShuffle/
  SetLoopStatus consult the last state the server broadcast and send
  nothing when it already matches, or the pause key would start playback
  on a paused player. Volume is the same idea with arithmetic; muting is
  spelled "volume 0", and the setter mutes on a zero target so the level
  survives to be unmuted to.
- No URL reaches the bus. xesam:url would have to be the stream URL,
  which clients never see and which several providers sign with
  credentials, and every peer on a session bus can read properties. The
  trackid is the queue position — also the only spelling that is a valid
  object path.
- mpris:length is omitted when unknown rather than sent as zero, which
  would make consumers draw a full progress bar.
- Unrepresentable requests are refused, not approximated: repeat-one,
  rates other than 1.0, OpenUri, Raise, and Quit — a status-bar button
  has no business closing someone's terminal.
- No session bus is a normal way to run (ssh, a tty, a container): the
  connection carries a timeout and its failure is an info log, after
  which the client behaves exactly as before.

Behind the `mpris` feature, on by default beside `notifications` and
forwarded by `cbd`; the nix package names it in headlessFeatures, since
naming a feature set at all replaces the crate defaults. It costs one
crate and no system library — zbus speaks D-Bus in pure Rust and
notify-rust had already brought it in.

Verified with the real thing, not only a test double: under
dbus-run-session, playerctl lists the player, reads its metadata
("Playing: the artist - the song (4:00)"), and drives play-pause,
`position 30+` and `volume 0.8` into the right commands. It also refuses
`next` when the queue is empty, which is CanGoNext being honest. The
committed bus test covers the round trip and skips where there is no bus.
2026-07-28 01:27:28 +02:00
..
audiobookshelf-provider.md Architecture: audiobookshelf (`/abs`) provider design 2026-07-23 23:09:54 +02:00
bookmarks.md Design the crabidy content store; add wire + fsdy foundations 2026-07-22 10:58:11 +02:00
build-features.md nix, opus: let the packager choose where libopus comes from 2026-07-28 00:24:03 +02:00
capture-deletion.md Design the crabidy content store; add wire + fsdy foundations 2026-07-22 10:58:11 +02:00
captures.md Design the crabidy content store; add wire + fsdy foundations 2026-07-22 10:58:11 +02:00
cbd-bundle.md Give cbd its own config file, separate from cbd-tui 2026-07-21 22:57:43 +02:00
cli.md Design a comprehensive clap-derive CLI (architecture/cli.md) 2026-07-22 11:45:05 +02:00
client-configs.md Give cbd its own config file, separate from cbd-tui 2026-07-21 22:57:43 +02:00
crabidy-store.md Let a same-source W re-capture replace its save in place 2026-07-22 22:35:48 +02:00
fs-provider.md Persist queues as fs-provider folders 2026-07-21 10:41:49 +02:00
fyyd-provider.md Add the fyyd podcast provider (/fyyd) 2026-07-23 17:29:13 +02:00
help-modal.md Add a help modal to cbd-tui behind a declarative binding table 2026-07-20 17:27:12 +02:00
incremental-captures.md Capture local files by copying them; add W to capture the queue 2026-07-22 01:08:29 +02:00
jamendo-provider.md jamendo: send a User-Agent (Jamendo returns empty results without one) 2026-07-24 15:54:31 +02:00
mpris.md cbd-tui: speak MPRIS, so the media keys reach the server 2026-07-28 01:27:28 +02:00
node-editing.md Add rename and delete for modifiable library nodes 2026-07-20 23:34:47 +02:00
orphans.md Add the /orphans provider: a store garbage-collection view 2026-07-22 22:47:23 +02:00
overview.md Document the as-built architecture 2026-07-20 10:34:45 +02:00
progressive-queueing.md Playback: retry the start when a skipped/short head runs the player dry 2026-07-23 19:55:18 +02:00
queue-persistence.md Capture library subtrees as bookmarks 2026-07-21 11:11:27 +02:00
queue-register.md cbd-tui: queue marks, visual mode, and a paste register 2026-07-26 10:24:51 +02:00
roles-auth.md Web client: prompt for login on visit when auth is enabled 2026-07-23 17:51:55 +02:00
rss-provider.md architecture: design the /rss subscription provider 2026-07-26 12:19:23 +02:00
search.md Add Tidal search as creatable library nodes 2026-07-20 17:58:44 +02:00
seek.md seek: put seek and track-skip on two keys, and make the web gauge clickable 2026-07-26 14:29:30 +02:00
soundcloud-provider.md soundcloud: prefer the progressive mp3 stream (HLS exchange 404s anonymously) 2026-07-24 02:47:13 +02:00
spectrum.md Add a server-streamed frequency spectrum visualizer 2026-07-21 23:14:03 +02:00
tui-search.md Add a / search filter to the TUI library and queue panes 2026-07-21 22:54:39 +02:00
visual-mode.md cbd-tui: fix visual mode stranding the turnaround row (anchor the range) 2026-07-24 16:29:26 +02:00
web-client.md Web client: prompt for login on visit when auth is enabled 2026-07-23 17:51:55 +02:00
youtube-provider.md Replace the yt-dlp subprocess with the pure-Rust rustypipe client 2026-07-21 17:12:40 +02:00
youtube-rustypipe.md Fetch streams in bounded windows and restore yt-dlp for stream URLs 2026-07-21 18:18:40 +02:00