crabidy/docs/src/clients/tui.md

202 lines
10 KiB
Markdown

# Terminal UI — cbd-tui
<!-- toc -->
`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](../config.md)); flags before a subcommand override the
file, and running it with no subcommand starts the TUI (see
[Command line](./cli.md)).
## Layout
The screen has two focusable panes side by side and a now-playing pane:
- **Library** (left) — the current [library node](../library.md): the
child folders and tracks under the path you have browsed to. Entering
a folder replaces the listing.
- **Queue** (right) — the play [queue](../queue.md), with the playing
track highlighted.
- **Now playing** — the current track, a progress gauge, and the
frequency-spectrum bars below it (see [Spectrum](#frequency-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](../providers/search.md));
`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](../store.md).
- 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.
```admonish note
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 `d` … `p` moves them somewhere else. The queue title
shows `register: n` while something is in it, so a paste is never blind.
```admonish note
`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.
```
```admonish warning
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.
```admonish tip
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 |