Two bugs from the register work, both reported from actual use.
**Paste landed one row too far.** `QueueManager::insert_tracks` spliced at
`position + 1` — it inserted *after* the given index, while its own CLI help
says "insert tracks/subtrees at a position". So `p` (which sent cursor + 1)
landed two below the cursor and `P` (cursor) landed one below, exactly as
reported. The clients were already computing the right indices for an
insert-*at* API.
Fixed at the primitive rather than in the clients, because "after" cannot
express the front of the queue: the earliest reachable index was 1, so
pasting before the first row — and therefore undoing a delete of it — was
impossible. `insert_tracks` now inserts **at** `position`, pushing that row
down, with 0 the front and past-the-end an append. The two callers that
genuinely mean "after" pass `N + 1`: `ResolveKind::InsertAfter` (which keeps
its name and its streaming-chunk arithmetic) and `queue_tracks` (play-next,
`L`). All existing behaviour is preserved — the whole server suite passes
untouched — and three tests pin the new front/interior/play-next cases.
`queue insert <POS>` on the CLI shifts by one accordingly, which brings it
in line with what its help always claimed. Documented in the proto, the CLI
help, and the book.
**Queue marks were invisible.** The TUI rendered no mark indicator, so `s`
and visual mode had no feedback. Marked rows now carry the library's `*`
prefix and the same green bold; the playing row keeps `>` and its red, and a
row that is both shows `> * title`. The web client already rendered marks
(its `.marked .title` rule), but neither client showed visual mode outside
the TUI's pane title — both panes there now get a VISUAL badge in the
toolbar.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
All on by default, so a plain build is unchanged (verified: the default
dependency set for crabidy-server is byte-identical to before). Tailor a
smaller binary with --no-default-features --features …
(architecture/build-features.md).
Compile-time features draw dependency boundaries; the existing
crabidy-server.toml providers list keeps doing per-mount runtime
toggling. The compile-time set bounds the runtime one: a provider built
out cannot be enabled from the config, and naming it earns one startup
warning rather than silence.
- crabidy-server: tidal · youtube · fyyd · abs · soundcloud · jamendo ·
fs · opus · spectrum · web-ui, plus the all-providers group.
- fs is local files *and* persistent state (D5): the /fs mount, the
content store behind /crabidy and /orphans, bookmarks/captures, queue
persistence, and scan. Without it Capture/SaveQueue answer
Unimplemented and scan says which feature is missing — never a panic.
- opus drops symphonia + symphonia-adapter-libopus, and with them the
bundled libopus C build (no more cmake requirement). It also decides
whether scan indexes .opus at all, so scan never indexes what this
build cannot play. An Ogg-Opus file in an opus-less build reports the
missing feature and is skipped like any undecodable file.
- spectrum drops realfft and the FFT task; clients just never receive a
frame. cbd-tui gains notifications (notify-rust, a D-Bus stack).
- crabidy-server/cbd features print the compiled set, and startup logs
it, so a tailored binary is self-describing.
Not gated, deliberately: [auth]/argon2 (a build ignoring configured
hashes would run open — fail-open security hole), and hls.rs /
spectrum_tap.rs / windowed_http.rs (no dependency of their own, so
gating them buys cfg noise and nothing else).
devenv gains check-features: the curated matrix (defaults, nothing, each
provider alone, each axis dropped, both worked examples, the client
crates) all clippy-clean under -D warnings.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The audio-devices command only listed. Give it an optional positional
argument: with none it lists as before; with a device name (or
case-insensitive fragment) it writes that into [audio] device in
crabidy-server.toml and then lists, so the same command both configures
and confirms (the chosen device is marked with *). If the fragment
matches no current output device it still writes but warns, mirroring
the server's startup fallback -- so a typo is caught here, not as silent
output.
Plumbing: AudioDevices carries an AudioDevicesArgs { device: Option }
on both `crabidy-server` and `cbd`; cli::audio_devices takes the option
and, when set, loads/updates/stores the settings via the existing
ServerSettings writer. README shows the set form.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The player always opened the system default output device. On a
Raspberry Pi that default is often HDMI, so playback ran but nothing
came out of the headphone jack or a USB/DAC -- "it plays but I hear no
sound".
Add an [audio] device option to crabidy-server.toml: a case-insensitive
substring of the output device name (a memorable fragment is enough).
The player engine opens the first matching device and falls back to the
system default with a warning if none matches. Absent config keeps the
system default, so existing setups are unchanged.
To discover the names, a new `crabidy-server audio-devices` subcommand
(also on `cbd`) lists the output devices and marks the one the current
config selects, using the same match the server applies at startup.
Plumbing: audio_player::output_device_names() enumerates via cpal;
Player::new(Option<String>) replaces the device-less construction
(Default = new(None)); Playback::new takes the device and serve() reads
it from settings. cpal's name() is deprecated in favor of description(),
but name() returns the ALSA-stable string users see in `aplay -l` and
match against, so it is kept behind a documented #[allow(deprecated)].
README documents the [audio] device option under the Pi/config section.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Every binary is now a clap-derive CLI; no subcommand keeps the current
default (run server / TUI / both).
- cbd-cli: run_remote executes library/queue/global against a running
server (mirrors RpcClient; direct Stop; connect+request timeouts;
concise errors; human-readable listings).
- crabidy-server: guard (hash + write [auth], stdin fallback, --no-config),
scan (walk + write .cbd-track.toml; --capture/--move via new
CrabidyStore::ingest_file), ServerSettings::store; replaces hash-password.
- cbd-tui: auth writes the client config; config load+override keeps the
first-run-defaults / flag-overrides-file behavior.
- cbd: union of server + client subcommands.
- build.rs in each binary generates shell completions + man pages
(OUT_DIR, and CBD_ASSET_DIR when set); devenv gen-cli-assets → dist/.
- README CLI section; tests for parse, config writers, scan/ingest, guard.
Deviations (plan/summary.md): ClapSerde kept; connection flags top-level
(not clap-global, to avoid colliding with auth --address); Box<dyn Error>
CLI reports per existing convention.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stage 2 of the CLI dev-flow (api-design). cbd-cli holds the clap
Parser/Subcommand types for all three binaries (ServerCli/TuiCli/CbdCli,
library/queue/global, guard/scan/auth, Role, RemoteArgs), asset generation
(clap_complete + clap_mangen), and a feature-gated gRPC executor
(run_remote) whose per-command dispatch is stubbed for the implement stage.
Compiles with and without the client feature.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>