# Tailored builds Every provider, Opus decoding, the spectrum bars, the embedded web UI and the TUI's two desktop integrations sit behind a Cargo **feature**. All of them are **on by default**, so a plain `cargo build` gives you the full player. Turning some off gives you a smaller binary that pulls fewer dependencies — useful for a single-purpose box (a Raspberry Pi playing a local flac collection) or a build environment you want to keep lean. This is the *compile-time* half of provider selection. The runtime half — the `providers` list in `crabidy-server.toml` — still works exactly as before; see [Configuration](./config.md#enabling-and-disabling-providers). The two compose in one direction: **a provider that is not compiled in cannot be enabled in the config**, and if you name one anyway the server logs a warning and carries on. ## What this build has ```sh crabidy-server features # or: cbd features ``` prints one feature per line — the providers it can mount, then the extras. The same list goes into the server's startup log, so a support question ("why is `/tidal` missing?") is answerable from the binary and its log. ## The features | Feature | Turning it off drops | | -------------- | --------------------------------------------------------- | | `tidal` | the `/tidal` provider (`tidaldy`) | | `youtube` | the `/youtube` provider (`ytdy`, and with it `rustypipe`) | | `fyyd` | the `/fyyd` podcast provider | | `abs` | the `/abs` audiobookshelf provider | | `soundcloud` | the `/soundcloud` provider | | `jamendo` | the `/jamendo` provider | | `rss` | the `/rss` podcast-subscription provider | | `fs` | local files **and persistent state** — see below | | `opus` | Ogg-Opus decoding (`symphonia` + libopus) | | `opus-bundled` | compiling libopus; links the system copy instead | | `spectrum` | the server-side FFT feeding clients' spectrum bars | | `web-ui` | the embedded web client (`tonic-web` + the wasm bundle) | Plus `all-providers`, which enables the eight provider features at once, and the TUI's two desktop features — `notifications` and `mpris` (below). `cbd` (the bundle) mirrors all of them. ### `notifications` and `mpris` Both belong to `cbd-tui` and both are on by default; both put the client on the session bus, and neither costs the server anything. | Feature | Turning it off drops | | --------------- | ------------------------------------------------- | | `notifications` | the desktop "now playing" popups (`notify-rust`) | | `mpris` | the MPRIS player: media keys, status bars | `mpris` publishes the MPRIS2 interfaces so the `XF86Audio*` keys and status-bar modules drive the server — see [Terminal UI](./clients/tui.md#media-keys-and-the-desktop). It costs one crate (`mpris-server`) and no system library: the `zbus` underneath it speaks D-Bus in pure Rust, and `notify-rust` already brought it in. Drop it for a client on a machine with no desktop session; it also stands down by itself when there is no session bus to sit on, so a client over ssh needs no separate build. ### `fs` is more than `/fs` The `/fs` provider, the content store, and everything built on it are all written against the same crate, so they share one feature. With `fs` off you lose: - the `/fs` mount (your local music folder); - `/crabidy` — saved queues, bookmarks (`w`) and captures (`W`); - `/orphans`, which is a view over the store; - **queue persistence**: the queue lives in memory, so a restart starts empty; - the `scan` command (it fails with a message naming the feature); - captured-track markers in library listings. The capture and save-queue RPCs answer `Unimplemented` on such a server, so clients report an ordinary error instead of hanging. If you want `/fs` but not `/crabidy`, keep the feature and prune the `providers` list at runtime instead — that is what it is for. ### `opus` and where libopus comes from `symphonia` (and so rodio) has no Opus decoder, so Ogg-Opus files are decoded through libopus. Turning `opus` off removes the crates, the library, and the C build with them. `opus-bundled` picks *which* libopus. It is on by default, so a plain `cargo build` compiles the vendored source and needs `cmake` and a C compiler but nothing installed. Drop it — `--no-default-features --features …,opus` — and the build links the system libopus instead: ```sh # a distribution build: Opus decoding, no vendored C build cargo build --release -p crabidy-server \ --no-default-features --features all-providers,opus,spectrum,web-ui ``` That is what this repo's Nix package does, taking libopus from nixpkgs. The build script emits a bare `-lopus` and leaves the search path to the linker (the bindings are pregenerated, so no headers are needed); point `OPUS_LIB_DIR` at the directory holding the library if the linker does not find it on its own, as the dev shell does. The aarch64 cross build keeps `opus-bundled`, because a static binary needs a static libopus for the target and compiling the vendored copy is the way to get one. `opus-bundled` without `opus` does nothing at all — it only chooses a source for a library the `opus` feature decides to use. The `opus` feature also decides whether `scan` treats `.opus` files as playable at all, so a build that cannot decode Opus will not index Opus files either. An Opus file that reaches such a build fails to decode with a message naming the missing feature and is skipped, exactly like any unplayable file. ### `spectrum` and `web-ui` `spectrum` only affects the *server*: with it off no frames are computed or broadcast, and clients simply show no bars — nothing else changes, and no client needs rebuilding. `web-ui` drops the embedded browser client; the gRPC service on port 50051 still serves `cbd-tui` and the CLI. ## Examples A local-files appliance — no network providers, no web UI, no FFT: ```sh cargo build --release -p crabidy-server \ --no-default-features --features fs,opus ``` A streaming box with the browser client and the bars, no local library: ```sh cargo build --release -p crabidy-server \ --no-default-features --features tidal,web-ui,opus,spectrum ``` The bundle, tailored the same way (its features forward to the server): ```sh cargo build --release -p cbd --no-default-features --features fs,opus ``` A terminal client with no D-Bus dependency at all — no popups, no media keys: ```sh cargo build --release -p cbd-tui --no-default-features ``` Or one that keeps the media keys and drops the popups: ```sh cargo build --release -p cbd-tui --no-default-features --features mpris ``` `--no-default-features` on its own is legal and compiles: you get a server that starts, serves an empty library and plays nothing. It is the base case the feature matrix checks, not a useful deployment. ## What is *not* behind a feature - **Authorization.** `[auth]` and its password hashing always ship. A build that ignored configured role hashes would silently run an intended-to-be-locked server open — a fail-open hole not worth a small dependency. - **Audio output.** The server is the player; a server without audio has no purpose. - **HLS streaming and the spectrum tap.** They bring no dependencies of their own, so gating them would add build complexity and save nothing. ## Checking combinations `devenv shell -- check-features` runs the curated matrix — defaults, no features, each provider alone, each extra dropped, both examples above, and the client crates — and requires every one to be clippy-clean. The two libopus variants are *built*, not just checked: clippy links nothing, so only a real build can tell a resolvable `-lopus` from a missing one. Run it after changing anything that sits behind a feature.