It's like mopidy but good.
Go to file
Test User 21fc4dc15a Give cbd its own config file, separate from cbd-tui
cbd (server + TUI in one process) and cbd-tui (standalone client) both
read cbd-tui.toml, so pointing that file at a remote server for cbd-tui
also dragged cbds local TUI to the remote while its in-process server
ran unused. cbd now reads its own cbd.toml (same options, same localhost
default that matches its embedded server), so a self-contained cbd and a
remote-pointed cbd-tui coexist on one machine without their address
settings colliding.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 22:57:43 +02:00
.gitea Clean up a bit 2023-06-13 10:12:26 +02:00
architecture Give cbd its own config file, separate from cbd-tui 2026-07-21 22:57:43 +02:00
audio-player Refetch mutable library listings and redact stream URLs from logs 2026-07-21 18:37:10 +02:00
cbd Give cbd its own config file, separate from cbd-tui 2026-07-21 22:57:43 +02:00
cbd-tui Add a / search filter to the TUI library and queue panes 2026-07-21 22:54:39 +02:00
cbd-web Add a Leptos web client served by the server 2026-07-21 22:43:06 +02:00
crabidy-core Add a Leptos web client served by the server 2026-07-21 22:43:06 +02:00
crabidy-server Add a Leptos web client served by the server 2026-07-21 22:43:06 +02:00
fsdy Delete captures from disk at any depth, behind a confirmation 2026-07-21 20:34:03 +02:00
plan Give cbd its own config file, separate from cbd-tui 2026-07-21 22:57:43 +02:00
quality Add a Leptos web client served by the server 2026-07-21 22:43:06 +02:00
tidaldy Delete captures from disk at any depth, behind a confirmation 2026-07-21 20:34:03 +02:00
ytdy Delete captures from disk at any depth, behind a confirmation 2026-07-21 20:34:03 +02:00
.editorconfig Add cross compile release flow 2023-06-12 09:38:19 +02:00
.gitignore Add devenv-based dev environment and README 2026-07-19 21:29:23 +02:00
Cargo.lock Add a Leptos web client served by the server 2026-07-21 22:43:06 +02:00
Cargo.toml Add a Leptos web client served by the server 2026-07-21 22:43:06 +02:00
Cross.toml Generate x86_64 target 2023-06-12 18:21:58 +02:00
README.md Give cbd its own config file, separate from cbd-tui 2026-07-21 22:57:43 +02:00
aarch64-unknown-linux-gnu-Dockerfile Try to add release files 2023-06-12 18:06:00 +02:00
armv7-unknown-linux-gnueabihf-Dockerfile Try to add release files 2023-06-12 18:06:00 +02:00
devenv-rust.nix Add devenv-based dev environment and README 2026-07-19 21:29:23 +02:00
devenv.lock Add devenv-based dev environment and README 2026-07-19 21:29:23 +02:00
devenv.nix Add a Leptos web client served by the server 2026-07-21 22:43:06 +02:00
devenv.yaml Add devenv-based dev environment and README 2026-07-19 21:29:23 +02:00
rust-toolchain.toml Add devenv-based dev environment and README 2026-07-19 21:29:23 +02:00
x86_64-unknown-linux-gnu-Dockerfile Generate x86_64 target 2023-06-12 18:21:58 +02:00

README.md

crabidy

A client/server music player. A headless gRPC server owns the library, the play queue, and audio output; a terminal UI connects to it over localhost (or the network). Media comes from pluggable providers, each mounted as a subtree of one library:

/
├── tidal        Tidal streaming (see tidaldy/README.md)
├── youtube      YouTube search & playlists (see ytdy/README.md)
├── fs           a local music folder (see fsdy/README.md)
├── queues       saved play queues (managed by the server)
├── bookmarks    link snapshots of library subtrees (`w`)
└── captures     downloaded snapshots with local audio (`W`)

Binaries

  • crabidy-server — the server: providers, queue, playback, gRPC on 0.0.0.0:50051. Also serves the web client at that address (see below).
  • cbd-tui — the terminal client. Press ? inside for all key bindings.
  • cbd — both in one process: starts the server, waits until it accepts connections, then runs the TUI. Adopts an already-running server instead of failing on an occupied port.
  • cbd-web — the browser client (Leptos/WASM), with the same functionality as the TUI. Not run directly: it is built to a bundle and embedded into crabidy-server (see cbd-web/README.md).

Quick start

The toolchain is managed by devenv:

devenv shell          # provides rust, yt-dlp, and friends
cargo run -p cbd      # server + TUI in one process

Or run the halves separately: cargo run -p crabidy-server and, in another terminal, cargo run -p cbd-tui.

Configuration

All configuration lives in ~/.config/crabidy/ (the platform config directory). Every file is optional; missing providers simply do not mount. Files are created/rewritten on first start with their defaults filled in.

File Component Documentation
tidaly.toml Tidal tidaldy/README.md
ytdy.toml YouTube ytdy/README.md
fsdy.toml local fs fsdy/README.md
cbd-tui.toml cbd-tui below
cbd.toml cbd below (same options as cbd-tui.toml)
crabidy-server.toml server below (never auto-created)

The server-managed folders (queues/, bookmarks/, captures/) also live in ~/.config/crabidy/; they need no configuration and hold plain folders of track files in the format documented in fsdy/README.md.

cbd-tui.toml and cbd.toml

Client configuration. cbd-tui (the standalone terminal client) reads cbd-tui.toml; cbd (server + TUI in one process) reads its own cbd.toml. They are separate files with the same options so the two can run side by side on one machine — a common setup is cbd playing locally against its in-process server while cbd-tui points at a remote server (e.g. a Raspberry Pi). A shared file would force one to follow the other's address.

# Where to find the server. Default (both files): localhost, which is
# what cbd's own in-process server listens on. Point cbd-tui.toml at a
# remote server to use it as a remote control.
address = "http://127.0.0.1:50051"

# Credentials, when the server has [auth] configured (see below).
# `user` is the role name; leave both empty against an open server.
# The password is stored in plaintext — keep this file private.
user = ""
password = ""

Every option is also available as a command-line flag (cbd-tui --address ..., cbd --address ...).

crabidy-server.toml — roles and rights

By default the server is open: everyone who can reach the port has full control. Adding an [auth] section turns on HTTP basic auth for every RPC and hands out roles (see architecture/roles-auth.md):

  • owner — everything (the normal user).
  • queue-owner — anything on the queue and playback, but no library writes: no bookmarks (w), captures (W), queue saving, renames or deletes.
  • queue-appender — may browse/search and append tracks to the queue; nothing else.
[auth]
# One PHC hash per role; omit a role to disable it. Generate with:
#   crabidy-server hash-password   (reads the password from stdin)
owner = "$argon2id$v=19$m=19456,t=2,p=1$..."
queue_owner = "$argon2id$..."
queue_appender = "$argon2id$..."

Clients authenticate with the role name as the basic-auth user (see cbd-tui.toml above). A malformed crabidy-server.toml aborts server startup rather than silently running open. Note that the transport is plain HTTP/2: fine on a trusted home network, but anything exposed further needs TLS termination (reverse proxy, VPN) in front.

Using the library

Navigation is vim-style: j/k select, l enters the selected folder, h goes to the parent, Tab switches between library and queue, Enter replaces the queue with the selection. % creates a node where the pane title shows % to add (e.g. a search term), e renames, d deletes. / filters the current pane (library or queue) live as you type — Enter keeps the filter, Esc clears it.

  • w saves the selection as a bookmark (links; needs the source provider to replay) or, in the queue pane, saves the queue.
  • W captures the selection: the subtree is mirrored under /captures/<name> with every track's audio downloaded next to its metadata — fully local playback afterwards. Captures are incremental: re-capturing the same name resumes and completes it; tracks whose source cannot be captured are recorded as skipped (red in the UI, skipped by playback). Download captures can take long; progress is shown in the library pane. Inside /captures, d deletes any folder or single track from disk (audio included) after a y/N confirmation.

Press ? for the full binding table.

Web client

crabidy-server serves a browser client with the same functionality as the TUI at its own address (http://<server>:50051/) — same navigation, same keys (j/k/h/l, %, e, d, w, W, queue and playback controls, ? for help), plus clickable equivalents and a light/dark theme toggle. It talks gRPC-web to the same service the TUI uses, so it honors the same [auth] roles (it shows a login form when the server requires credentials).

It is compiled to a WASM bundle and embedded into the server binary, behind the default-on web-ui cargo feature. A plain cargo build needs no WASM toolchain — it embeds a "not built" placeholder page until you build the bundle:

devenv shell -- build-web        # writes cbd-web/dist
cargo build -p crabidy-server    # embeds it

Build the server with --no-default-features for a headless, gRPC-only binary. See cbd-web/README.md for the dev loop and details.

Logs

cbd and cbd-tui log to ~/.local/state/crabidy/ (daily files); crabidy-server logs to stderr. Stream URLs and credentials are redacted from logs by design.

Development

Design documents live in architecture/, per-feature quality gates in quality/, and implementation plans in plan/. See CLAUDE.md / AGENTS.md for the development workflow and coding rules.