crabidy/docs/src/clients/tui.md

10 KiB

Terminal UI — cbd-tui

cbd-tui is the terminal client: a ratatui/crossterm application that connects to a running server over gRPC and redraws from the pushed update stream. It reads cbd-tui.toml for its connection defaults (see Configuration); flags before a subcommand override the file, and running it with no subcommand starts the TUI (see Command line).

Layout

The screen has two focusable panes side by side and a now-playing pane:

  • Library (left) — the current library node: the child folders and tracks under the path you have browsed to. Entering a folder replaces the listing.
  • Queue (right) — the play queue, with the playing track highlighted.
  • Now playing — the current track, a progress gauge, and the frequency-spectrum bars below it (see Spectrum, fills the rest of the right column).

Tab cycles focus between the library and the queue; keys are routed to whichever pane has focus (plus the global keys, which apply in either).

Navigating

Navigation is vim-style. In the library, j/k move the selection, l enters the selected folder, h goes back to the parent, and g/G and Ctrl-d/Ctrl-u jump. Enter replaces the queue with the current selection; a appends it and L queues it after the current track. In the queue, Enter plays the selected track, o jumps the selection to the playing track, d removes a track, p inserts the library selection after the selected track, and c/C clear the queue.

% creates a child of the open node where that is allowed (e.g. a search term under /tidal/search — see Search); e renames such a node; d deletes the selection. Playback keys (Space, r, Ctrl-n/Ctrl-p, volume, m, z, x) are global. Press ? at any time for the full binding table; Esc or ? closes it, and while it is open every other key is inert.

Marks and saving

  • s toggles a mark on the selected item. Marks live on the full item list (they survive filtering) so a marked-but-hidden row still counts when you queue or save.
  • v (or V) enters visual mode: movement then marks or unmarks the rows you sweep over, like vim's visual selection. The selection is anchored where you entered it, so moving back over a row reverses it. Esc leaves visual mode (keeping the marks and any / filter), and so does any non-movement action. The pane title shows — VISUAL while it is on. Both panes have it.
  • w saves the selection — a library subtree, or in the queue pane the whole queue — as a new folder of link files under /crabidy/<name>; playback replays it from the source provider.
  • W captures the selection into /crabidy/<name>: like w, but each track's audio is fetched into the shared content store (de-duplicated), so it plays back fully local afterwards. It works on a library subtree and on the queue. Downloads can take a while; progress shows in the library pane. See The crabidy store.
  • Captured rows are marked with a trailing (down-arrow) at the end of the row, visible even while you browse another provider, so you can see what you already have.
Saves and captures all live under the one `/crabidy` provider. Inside
`/crabidy`, `d` deletes a folder or track immediately with no
confirmation — it removes only the metadata toml, never the shared
store audio, which other saves may reference.

The register: y, d, and p/P

The queue has marks and visual mode too, and they feed a register — one in-memory slot, like vim's unnamed register:

  • y yanks the selection into the register without changing anything. It works in both panes: in the library it yanks the paths you have marked (or the row under the cursor), in the queue the marked tracks.
  • d in the queue deletes every marked row (or the cursor row) in one go — and puts them in the register first.
  • c and C also fill the register with what they clear, so emptying the queue by accident is recoverable.
  • p pastes the register after the cursor, P before it. The register survives, so you can paste again.

That gives you the two vim moves: d then P puts the tracks back exactly where they were, and dp moves them somewhere else. The queue title shows register: n while something is in it, so a paste is never blind.

`p` used to insert the **library** selection at the cursor. It now pastes
the register, so that flow is `y` in the library, then `p` in the queue.
`a`, `L`, and `Enter` still queue the library selection directly.
The register lives in **your client**, in memory, one slot deep: another
client cannot undo your delete, a restart forgets it, and each write
overwrites the last. It holds *paths*, so a paste re-resolves them — a
yanked album node expands to its tracks at paste time, and a path that no
longer resolves (a search term you deleted meanwhile) does not come back.

The / live filter

Pressing / opens a search input that filters the focused pane's items live as you type (case-insensitive substring). It narrows the visible list rather than jumping to a match, so you can filter and then act on what is left. Enter keeps the filter applied and returns to navigation; Esc clears it. Movement, marks, and queue actions all map back to the real underlying rows, so acting on a filtered row affects the right track.

This `/` filter is a local view filter over items already listed. It is
distinct from the search-node feature (`%` on `/tidal/search` and
friends), which asks a provider for results. See
[Search](../providers/search.md).

Entering a library folder resets the filter (a fresh listing); the queue's filter is preserved across the constant queue updates and only its visible set is recomputed.

Frequency spectrum

A row of frequency bars is drawn under the track progress while audio plays, as block glyphs (▁▂▃▄▅▆▇█) in the accent color. The bars are produced on the server: it taps its own audio output, runs an FFT (~20 fps), folds the result into a few log-spaced bins, and streams them on the update stream like every other bit of live state. So the bars work whether the server is local or on another machine, and when nothing is playing they fall to the floor.

Press f to show or hide them at runtime; spectrum in the client config sets the startup default (spectrum = true is the default; false starts hidden). Either way it is only a display choice — the server always computes and streams the bars while audio flows.

Key bindings

Global keys work in either pane. Pane keys apply only while that pane is focused (several chords, like j/Enter/d, mean different things per pane).

Scope Key Action
Global ? Show help
Global q Quit
Global Tab Switch between library and queue
Global Space Play/pause
Global r Restart current track
Global K Volume up
Global J Volume down
Global m Toggle mute
Global z Toggle shuffle
Global x Toggle repeat
Global Ctrl-n Next track
Global Ctrl-p Previous track
Global f Toggle the frequency spectrum
Library j / k Select next / previous item
Library g / G Select first / last item
Library Ctrl-d Jump 15 items down
Library Ctrl-u Jump 15 items up
Library h Go to parent folder
Library l Enter selected folder
Library s Mark / unmark selection
Library v / V Visual mode: movement toggles marks
Library y Yank selection into the register
Library Enter Replace queue with selection
Library a Append selection to queue
Library L Queue selection after current track
Library % Create node here (e.g. search term)
Library e Rename selected node
Library d Delete selection
Library w Save selection as bookmark
Library W Capture selection into /crabidy (audio)
Library / Filter this view
Queue j / k Select next / previous track
Queue g / G Select first / last track
Queue Ctrl-d Jump 15 tracks down
Queue Ctrl-u Jump 15 tracks up
Queue s Mark / unmark selection
Queue v / V Visual mode: movement toggles marks
Queue y Yank selection into the register
Queue o Select the playing track
Queue Enter Play selected track
Queue p / P Paste the register after / before
Queue d Remove selection (into the register)
Queue c Clear queue except current (to register)
Queue C Clear entire queue (to register)
Queue w Save queue under a name
Queue W Capture the queue into /crabidy (audio)
Queue / Filter this view
Help ? / Esc / q Close help