atradio
atradio.fm in your terminal — a TUI radio player on the AT Protocol.
A native Rust client for atradio.fm: browse trending / popular / recently-played stations, fuzzy-search the whole radio-browser directory, play live streams with a full Rockbox DSP/equalizer chain, and — when signed in — favorite stations, add your own, and post comments to your PDS.

Contents
- Install
- Build (from a checkout)
- Usage
- Signing in
- Keybindings (TUI)
- Equalizer & DSP
- atradio Connect (remote control)
- Run as a service (systemd, Linux only)
- Platform notes
- Lexicon bindings
Install
Prebuilt release tarballs, .deb, and .rpm packages are attached to every
GitHub release, named
atradio-<version>-<os>-<arch>.tar.gz (macos-amd64, macos-aarch64,
linux-amd64, linux-aarch64, freebsd-amd64, freebsd-aarch64,
netbsd-amd64, netbsd-aarch64) — each contains the binary, README, and
LICENSE. The BSD builds run in emulated VMs and are attached to the release
shortly after it's published (aarch64 ones can take hours).
macOS / Linux — Homebrew
Linux — Debian / Ubuntu
Direct .deb:
# amd64
# arm64 (Raspberry Pi 4/5, Apple-silicon VM, …)
Or via the Gemfury apt repo (auto-updates with apt upgrade):
|
&&
Linux — Fedora / RHEL / openSUSE
Direct .rpm:
Or via the Gemfury dnf/yum repo:
Nix
# Optional: use the binary cache to skip building.
# One-off run:
# Install into your user profile:
# Dev shell (rust toolchain + build deps):
From source (Cargo)
# Runtime/build deps: a C toolchain (for the Rockbox codecs) + ALSA on Linux.
Build (from a checkout)
Building compiles the vendored Rockbox codecs, so a C toolchain is required
(clang/gcc). macOS uses CoreAudio; Linux needs ALSA dev headers
(libasound2-dev).
License note: this crate links
rockbox-playback(GPL-2.0-or-later), so the compiledatradiobinary is GPL-2.0-or-later.
Usage
Signing in
Reads to the AppView are public; favoriting, commenting, adding stations, appearing in recently-played, and atradio Connect require a session. Two ways to authenticate:
- App password — set env vars, then
atradio login:
Its session stays signed in the longest and refreshes silently — recommended for a long-running headless daemon. - OAuth —
atradio login --oauth you.bsky.social, or presssin the TUI to open the sign-in modal, which completes the flow in your browser. Convenient for interactive use, but its session expires sooner than an app password, so an always-on daemon may need the occasional re-login.
The session + a small profile cache are stored under ~/.config/atradio/
(also settings.toml for volume + DSP).
Keybindings (TUI)
| Key | Action |
|---|---|
↑/↓ j/k |
move selection |
←/→ Tab |
switch home tab |
1 … 5 |
tabs: Trending / Popular / Recent / Favorites / Yours |
Enter |
play the selected station |
Space |
play / pause · m mute · +/- volume (or adjust DSP) |
/ |
fuzzy station search |
f |
favorite the selected/current station |
A |
add a custom station (when signed in) |
c / a |
comments / add a comment |
d |
Connect: pick a device to play/control (see below) |
n |
notifications |
p |
your profile (with playable recently-played) |
e |
equalizer & DSP settings |
s |
sign in (OAuth) / sign out |
h · ? |
home · help |
q / Esc |
quit / close overlay |
Equalizer & DSP
Press e for the full Rockbox chain: a 10-band equalizer, bass/treble tone,
crossfeed, perceptual bass, Haas surround, a compressor, and channel mode /
stereo width. Changes apply live and persist to settings.toml.
Syncing settings (push / pull)
When you're signed in, the whole DSP chain also syncs to your PDS as the
fm.atradio.audio.settings singleton record — the CLI's EQ bands (32 Hz–16 kHz)
now match the web build, so your EQ + DSP follow your account across the web app
and other devices. The TUI syncs automatically: on startup a signed-in session
pulls the record and applies it (remote wins), then pushes the current
chain back when you quit.
You can also sync on demand (both require signing in):
pullreplaces the local DSP chain with the synced record (it keeps your localvolume). If you have no record yet,push(or quitting the TUI) creates it.
atradio Connect (remote control)
Like Spotify Connect: when signed in, every atradio client you have open — this CLI, the web app, other terminals — shows up as a device on your account, and any of them can control the selected player. Requires a session (it's keyed to your DID and authenticated with an atproto service-auth token); logged-out clients don't participate.
- Press
dto open the device picker. Pick This device to play here, or pick another device to control it from here — pressingEnteron a station,Space,m, and+/-are then sent to that device instead of your local audio. The player bar shows a◉ Controlling <device>indicator with the remote's now-playing and volume. - Selecting a device transfers playback to it (Spotify-style): what you're playing follows you to the device you pick; picking This device pulls it back and stops the remote.
- Your listening status (
fm.atradio.actor.status) is now driven by Connect: it's cleared automatically once none of your devices are playing.
Headless daemon (--no-tui)
Runs with no TUI — just an online player you drive from the web app or another client (great for a Raspberry Pi or a always-on box wired to your speakers).
Sign in with an app password for a daemon. OAuth refresh tokens are short-lived, so an OAuth-authenticated daemon eventually drops offline and prints
session expired — run atradio login to reconnectuntil you sign in again. An app-password session stays signed in far longer and refreshes on its own — setATPROTO_IDENTIFIER+ATPROTO_APP_PASSWORDand runatradio login(no--oauth). See Signing in.
The device name shown to your other clients defaults to a hostname-based label;
set a custom one in ~/.config/atradio/settings.toml:
= "Living Room"
Run as a service (systemd, Linux only)
On Linux you can install the headless daemon as a systemctl --user service
so it starts on login and restarts on failure — ideal for a Raspberry Pi or an
always-on box. Sign in with an app password first so the daemon
stays online unattended.
install drops a unit at ~/.config/systemd/user/atradio.service whose
ExecStart points at the current atradio binary running --no-tui, then runs
daemon-reload, enable, and start. Follow its logs with:
To keep the service running after you log out (e.g. on a headless Pi), enable lingering once:
sudo loginctl enable-linger $USER.
The service subcommand is Linux-only — it is compiled out entirely on
macOS, FreeBSD, NetBSD, and other platforms, where systemd isn't available.
Platform notes
- Linux: the player is exposed over MPRIS (D-Bus), so media keys and
desktop panels /
playerctlcan see now-playing and drive play/pause/stop.
Lexicon bindings
The typed fm.atradio.* records/queries in src/fm_atradio/ and
src/builder_types.rs are generated from the lexicon JSON in
packages/lexicons/lexicons/atradio via jacquard's codegen. Regenerate with: