Skip to content

catalystcommunity/ichoi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ichoi

Ichoi is a music player, library manager, and distributed jukebox server. One static binary runs your library, streams to browsers and native clients, and turns speakers on other machines — a Raspberry Pi in the kitchen, a tablet by the door — into shared, controllable playback targets that anyone you permit can queue music to.

It is deliberately not a Subsonic clone. Ichoi has no passwords (identity is LinkKeys, or login-less on a trusted LAN), a real capability-negotiated media pipeline, and a CSIL-native API — the web UI, native apps, and satellites all speak the same transport. See docs/DESIGN.md for the full architecture and the reasoning behind every decision, and CONTRIBUTING.md for working conventions.

Status: design. The architecture is settled; implementation is in progress.

What it does

  • Streams full-quality or transcodes on demand. The client always runs the same Symphonia decoder; the core sends original packets (direct mode) or re-encodes to AAC-LC / MP3 (transcoded mode) based on what each consumer negotiates — bitrate cap, codec, or an undecodable source (Opus, HE-AAC). Transcoding shells out to a bundled static ffmpeg; it is never linked.
  • Distributed jukebox. Satellites connect out to a core and register their outputs as shared targets. Control and audio travel back down the connection the satellite opened, so NAT'd Pis just work. The core never connects to a satellite.
  • Multi-server clients. One client can browse several servers at once and, when permitted, copy albums and playlists between them (never delete).
  • Browser-first, served by the same binary over a WebSocket carrier, with a Symphonia→WASM decoder. Firefox is first-class. Themeable, i18n + a11y from day one.
  • Gapless, sample-accurate playback with time-based seeking.

The three roles

All three are the same binary; the role is configuration.

Role What it is
core Owns the library, database, ffmpeg, and TLS keys. Serves the API, indexes and transcodes, coordinates jukebox state, accepts client-mediated imports. May own local outputs.
satellite A dumb output node (typically a Pi). Connects out to one core, registers its speakers as shared targets, plays AAC-LC. No library access.
client A browser or native app carrying a LinkKeys identity. Browses one or more servers, plays locally, copies between servers, and may become a shared satellite of one server.

Quickstart

# Run a core over your music library.
ICHOI_MUSIC_DIR=/path/to/music ichoi serve

That serves the browser UI on http://localhost:4042 and the CSIL+TLS listener on :4043. On a trusted LAN this is login-less (guest); the first LinkKeys login promoted with ICHOI_ADMIN_TOKEN becomes the admin.

Browsers should reach Ichoi over HTTPS via a reverse proxy — the HTTP listener is plain HTTP by design. See deploy/ for a ready-to-edit Caddy example and a docker-compose that runs Ichoi behind it.

Configuration

Precedence is environment (ICHOI_-prefixed) → TOML config → defaults. The common settings:

Setting Env Default
Role ICHOI_ROLE core
Music directory ICHOI_MUSIC_DIR (required for a core)
Audiobook directory ICHOI_AUDIOBOOK_DIR unset
Flatten disc subfolders into parent albums ICHOI_ALBUM_SUBFOLDER_FLAT true
Disc-subfolder matching words ICHOI_ALBUM_SUBFOLDER_WORDS cd,disc,disk,bonus disc
Database directory ICHOI_DB_DIR music dir
HTTP listen ICHOI_HTTP_ADDR :4042
CSIL listen ICHOI_CSIL_ADDR :4043
Core address (satellite) ICHOI_CORE_ADDR (required for a satellite)
Core key fingerprints (satellite) ICHOI_CORE_KEYS (required for a satellite)
Node token (satellite) ICHOI_NODE_TOKEN (required for a satellite)
CSIL/TLS certificate (core) ICHOI_TLS_CERT <db-dir>/csil-cert.der
CSIL/TLS private key (core) ICHOI_TLS_KEY <db-dir>/csil-key.der
Admin bootstrap token ICHOI_ADMIN_TOKEN unset
DNS-less LinkKeys RP ICHOI_LINKKEYS_LOCAL_RP disabled; only exact true enables
Local RP name ICHOI_LINKKEYS_LOCAL_RP_NAME unset
Regular LinkKeys RP ICHOI_LINKKEYS_RP disabled; only exact true enables
RP TCP endpoint ICHOI_LINKKEYS_RP_ADDR unset
RP TLS fingerprints ICHOI_LINKKEYS_RP_FINGERPRINTS unset
RP API key ICHOI_LINKKEYS_RP_API_KEY or ICHOI_LINKKEYS_RP_API_KEY_FILE unset
RP domain ICHOI_LINKKEYS_RP_DOMAIN unset
Public HTTPS origin ICHOI_PUBLIC_URL unset
Trusted LinkKeys identities ICHOI_LINKKEYS_TRUSTED_IDENTITIES unset
ffmpeg override ICHOI_FFMPEG bundled → PATH
Default transcode codec ICHOI_TRANSCODE_CODEC aac
Log level ICHOI_LOG warn

Setting ICHOI_AUDIOBOOK_DIR enables the Audiobooks view. The directory may be separate from the music collection or nested below it; a nested audiobook tree is excluded from the music catalog automatically. Signed-in users get independent per-chapter listening progress and resume positions. While the server has no accounts, guest playback uses one global progress profile shared by everyone browsing that server.

By default, disc-like subfolders such as CD1, CD2, Disc One, and Bonus Disc are fuzzy-matched and flattened into one album named after their parent folder. Track titles retain their source folder as a prefix, for example CD1 - Chapter 01. Set ICHOI_ALBUM_SUBFOLDER_FLAT=false to retain separate subfolder albums, or provide a comma-separated ICHOI_ALBUM_SUBFOLDER_WORDS list to replace the default matching vocabulary.

The database is a single SQLite file (WAL) in the database directory. ffmpeg is resolved bundled-next-to-the-binary first, then PATH; if neither is found, transcoding is disabled and the core serves direct mode only — Ichoi never fails to start for lack of ffmpeg.

Administrators can start a full library resync from Settings. Resync uses the same single-flight scanner as startup, updates changed metadata, and removes catalog rows for files that disappeared; starting another resync while one is active does not create a competing scan.

Chromebook and browser satellites

The default web UI is an installable PWA. An administrator (or anyone on a login-less guest instance) can create a named, one-time satellite token in Settings and enter it at /satellite. The token is stored only in that browser profile. While present, every other application route redirects to the restricted satellite console; leaving satellite mode and signing in normally are separate, explicit actions.

Satellite tokens define whether newly discovered audio outputs are shared and which access groups inherit them. The built-in Everyone group includes guests and every account. Administrators can create narrower groups, change an individual output's groups, or disable an output globally so it is not listed or controllable by anyone. The console supports Chrome's audio-output chooser when available, falls back to the system default, and offers a fullscreen action. ChromeOS still requires a user gesture through Enable audio before remote playback and a personal ChromeOS login after a reboot; session restore can reopen the installed PWA afterward.

DNS-less LinkKeys login on a LAN

Local-RP login is completely opt-in and gives Ichoi a key-fingerprint identity rather than a public DNS identity or RP sidecar. Enable it with all three settings:

ICHOI_LINKKEYS_LOCAL_RP=true
ICHOI_LINKKEYS_LOCAL_RP_NAME="Kitchen Ichoi"
ICHOI_LINKKEYS_TRUSTED_IDENTITIES="family.example,alice@friends.example"

Only the exact lowercase value true enables the mode. A domain entry accepts every verified handle at that LinkKeys domain; handle@domain accepts only that verified handle. Users normally enter handle@domain in Ichoi's sign-in dialog. Ichoi derives its callback from the browser's same-origin LAN address, so no public URL setting or public availability is required.

The first enabled start generates the local RP signing/encryption identity and stores the SDK's opaque key bundle in ichoi.db. It remains stable across restarts; changing the name does not silently rotate it. Backups of the database therefore contain private RP key material and must be protected. Approve the fingerprint reported in the log or /api/auth at each trusted LinkKeys domain before users log in.

Regular LinkKeys RP login

For a public deployment backed by an existing DNS-pinned LinkKeys RP service, enable regular-RP mode instead. It is mutually exclusive with DNS-less mode:

ICHOI_LINKKEYS_RP=true
ICHOI_LINKKEYS_RP_ADDR="linkkeys.example.com:4987"
ICHOI_LINKKEYS_RP_FINGERPRINTS="fingerprint1,fingerprint2"
ICHOI_LINKKEYS_RP_API_KEY_FILE="/run/secrets/linkkeys_rp_api_key"
ICHOI_LINKKEYS_RP_DOMAIN="ichoi.example.com"
ICHOI_PUBLIC_URL="https://ichoi.example.com"
ICHOI_LINKKEYS_TRUSTED_IDENTITIES="family.example,alice@friends.example"

The API key must belong to an RP service account with LinkKeys' api_access relation. The file form is preferred for containers because it keeps the key out of Compose interpolation and the container environment. Ichoi pins the RP server's TLS certificate to the configured fingerprints, requests and verifies the handle claim, and applies the same domain/handle admission selectors used by DNS-less mode.

Native satellite installation

Satellites authenticate with a node token only after establishing rustls TLS to a pinned core key. No DNS name or public CA is involved. On the core, print the fingerprint that must be provisioned out of band:

ichoi core-fingerprint

Then install the same binary on the output machine. Reading the token from a file or stdin keeps it out of shell history and process listings:

ichoi install satellite \
  --core 192.168.1.20:4043 \
  --core-key sha256:<fingerprint> \
  --node-token-file ./theater-node.token

Use --dry-run to print every file and service-manager command without changing the host. --scope user selects a per-user installation; the defaults are a system service on Linux and a user service on macOS and Windows.

Inspect or remove the same installation with:

ichoi status --scope user
ichoi uninstall --scope user --keep-config
  • Linux installs a systemd system or user unit. System scope uses /etc/ichoi/ichoi.toml; user scope follows $XDG_CONFIG_HOME.
  • macOS installs a LaunchAgent under ~/Library/LaunchAgents and keeps its configuration under ~/Library/Application Support/Ichoi.
  • Windows user scope installs an ONLOGON scheduled task. System scope installs a native Windows Service and stores configuration under %PROGRAMDATA%\Ichoi.

Linux retains its runtime-loaded ALSA backend. macOS and Windows builds compile only their native CoreAudio/WASAPI backend, so those dependencies never enter Linux artifacts.

Repository layout

Each independently versioned target lives in its own top-level directory (the multiple-directory release strategy — a future mobile app would be a sibling mobile/). The server target is under server/; the repo root holds only shared CI (.reactorcide/), project docs, and the ./tools.sh helper.

Building

Ichoi is a single static binary with zero system-library link dependencies. SQLite is compiled in; ffmpeg and host audio are never linked. Direct cargo runs from the server target dir; use the musl targets for a fully static build:

cd server
cargo build --release --target x86_64-unknown-linux-musl   # amd64
cargo build --release --target aarch64-unknown-linux-musl  # arm64 (Pi satellites)

Day-to-day, use ./tools.sh from the repo root (it drives the server target for you), which mirrors what CI runs:

./tools.sh build     # cargo build --workspace
./tools.sh test      # TEST_DATABASE_BACKEND=sqlite cargo test --workspace
./tools.sh fmt       # cargo fmt --all
./tools.sh clippy    # cargo clippy --workspace --all-targets -- -D warnings
./tools.sh check     # csil-validate + fmt + clippy + test (the full local gate)
./tools.sh gen       # regenerate CSIL bindings (server + all client languages)

Docker

The server/Dockerfile produces a minimal scratch image (multi-arch, linux/amd64 + linux/arm64) containing the ichoi binary, a bundled static LGPL ffmpeg, and the web UI. Scratch is safe because host audio is loaded at runtime — a server needs no audio output, so the image just reports audio_outputs: none.

docker buildx build --platform linux/amd64,linux/arm64 -t ichoi:dev server
docker run --rm -e ICHOI_MUSIC_DIR=/music -v /path/to/music:/music -p 4043:4043 ichoi:dev

Published images live at containers.catalystsquad.com/public/catalystcommunity/ichoi. For a full deployment behind TLS, see server/deploy/docker-compose.yml.

Testing & CI

Tests hit a real SQLite database inside a transaction that rolls back — no mocks for the data layer, every test isolated in its own transaction. CI runs on Reactorcide (not GitHub Actions): conventional commits gate PRs and fan out to build (amd64 + arm64), the SQLite suite, and CSIL validation; semver-tags cuts per-target releases (server/vX.Y.Z) on merge to main. ./tools.sh check reproduces the gate locally. Definitions live in .reactorcide/jobs/.

License

Apache-2.0. See LICENSE. Nothing copyleft or patent-encumbered lives inside the Ichoi binary; the bundled ffmpeg is a separate LGPL program, subprocessed (see docs/ffmpeg.md).

About

Turn a local music collection into an internet jukebox experience

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages