The ultimate terminal Internet Radio streaming application for developers who live in the command line.
Built with Go & Bubble Tea, featuring a LazyVim-inspired keyboard-driven interface.
brew install halpworld/tap/halpradio
halpradiocurl -fsSL https://raw.githubusercontent.com/halpworld/halpradio/main/install.sh | bash
halpradiodocker run --rm -it --device /dev/snd halpworld/halpradio:latest| Feature | 📻 halpradio | PyRadio | Curseradio | radio-active | mocp / cmus |
|---|---|---|---|---|---|
| Zero-Dependency Audio Engine | ✅ Yes (oto/v3 Go native) |
❌ (requires MPV/VLC) | ❌ (requires MPV) | ❌ (requires FFmpeg) | ❌ (C daemons) |
| Linux MPRIS v2 & Media Keys | ✅ Native D-Bus + playerctl |
❌ None | ❌ None | ❌ None | |
| Song Change Desktop Notifications | ✅ Native macOS/Linux/Win + Dedupe | ❌ None | ❌ None | ❌ None | ❌ None |
CLI & Hotkey Remote (halpradio remote) |
✅ macOS Shortcuts, Raycast, tmux | ❌ None | ❌ None | ❌ None | |
Terminal Party Line (Ctrl+p) |
✅ P2P Mesh Sync, E2EE Rooms & Reactions | ❌ None | ❌ None | ❌ None | ❌ None |
Acoustic Fingerprinting (I) |
✅ Chromaprint / AcoustID + Ad Strip | ❌ None | ❌ None | ❌ None | ❌ None |
Pomodoro & Sleep Timers (z) |
✅ Intervals, Station Switch & OS Notify | ❌ None | ❌ None | ❌ None | |
| Beat-Reactive Animated Visualizers | ✅ 5 Animal DJs + EQ Spectrum | ❌ None | ❌ None | ❌ None | |
| Live ICY Metadata (Song / Artist) | ✅ Real-time Async Extraction | ❌ None | |||
| 30,000+ Online Station Search | ✅ Built-in RadioBrowser API | ❌ Manual list | ❌ TuneIn scrap | ❌ Local files | |
Vim Navigation & Which-Key (?) |
✅ Full Vim Modal UX | ❌ Non-modal | |||
| Modern Theme Engine | ✅ 6 Themes (Tokyo Night, Synthwave, etc.) | ❌ Basic curses | ❌ Basic | ||
1-Key PR Clipboard Export (p) |
✅ Instant YAML snippet for PRs | ❌ Manual | ❌ Manual | ❌ Manual | ❌ N/A |
Press v anytime in halpradio to cycle through 5 animated animal DJs, classic bars, waveform, spectrum, or minimal meters:
| Visualizer Mode | Animal Character | DJ Booth & Live Equalizer Render |
|---|---|---|
dj-cat (default) |
🐱 DJ Cat | 🎧 (=^・ω・^=)ノ [💿 ◓] ♫ ▂▃▄▅▆ |
dj-dog |
🐶 DJ Dog | 🎧 (∪・ω・∪) ノ [💿 ◑] ♫ ▂▃▄▅▆ |
dj-bear |
🐻 DJ Bear | 🎧 ʕ •ᴥ•ʔ ノ [💿 ◒] ♫ ▂▃▄▅▆ |
dj-frog |
🐸 DJ Frog | 🎧 ( •⊖• ) ノ [💿 ◐] ♫ ▂▃▄▅▆ |
dj-bunny |
🐰 DJ Bunny | 🎧 ( •ㅅ• ) ノ [💿 ◓] ♫ ▂▃▄▅▆ |
bars |
📊 Bars Equalizer | ♫ ▂▃▄▅▆▇█▇▆▅▄▃▂ ♬ |
wave |
∿ Waveform | ∿ _⎽⎼─⎻⎺▔⎺⎻─⎼⎽_ ∿ |
spectrum |
🔊 Spectrum | 🔊 BASS ███ MID ███ TREB ███ |
minimal |
🎚️ Minimal VU | L:████░░░░ R:██████░░ |
- Zero-Jitter Normalized Poses: Every pose (head + arm + deck) has an exact, invariant width (24 visual columns) for smooth, stable rendering without horizontal shifting.
- Harmonic Multi-Frequency Equalizer Rack: Solid 6-bar mini-EQ (
▂▃▄▅▆) driven by harmonic frequency physics (sub-bass kick, mid melody, treble shimmer) with smooth attack and exponential decay. - Rhythmic Groove: Head bobbing and turntable vinyl rotation (
◓,◑,◒,◐) tempo-matched to audio playback. - Sleep State: When stopped/paused, the DJ rests peacefully on the turntable (
🎧 (= - ω - =)..zzZ [ 💿 ] ⏹ STOPPED).
Press z or Z anywhere in halpradio to open the Timer & Pomodoro Focus Modal:
🍅 Pomodoro Focus Sprints | ☕ Short & Long Breaks | ⏳ Sleep Timer with Volume Fade-Out
- Sprint & Rest Intervals: Seamlessly cycle between Focus sessions (default:
25 min), Short Breaks (5 min), and Long Breaks (15 minafter 4 completed cycles). - Auto Station Switching: Automatically tune into your deep focus station (e.g. Lofi Girl / Synthwave) during sprints, and switch to relaxing sounds (e.g. Ambient Cafe / Jazz) or silence during breaks.
- Live Visual Countdown: Real-time progress bar and badges displayed directly in the playerbar (
🍅 18:42 (#2/4)/☕ 04:50 (Break)), statusbar, and OSC native terminal tab title ([🍅 18:42] ▶ Track | halpradio).
- Quick Presets: Instant
15 min,30 min,45 min,60 min,90 min, or custom minute countdowns. - Graceful Volume Fade-Out: Smoothly scales audio volume down to 0% during the final 10 seconds before stopping playback, keeping your initial volume preference intact for next morning.
- Cross-Platform Desktop Notifications: Silent native banner notifications on macOS (
osascript), Linux (notify-send), and Windows (PowerShell toast notifications). - Terminal Bell (
\a): Optional audio bell cue on interval transitions. - Custom Shell Event Hook: Execute your own shell script on timer transitions with rich environment variables (
HALPRADIO_EVENT,HALPRADIO_PHASE,HALPRADIO_CYCLE,HALPRADIO_STATION_NAME), perfect for triggering macOS Focus Mode, smart desk lights, Waybar/Polybar, or Slack status!
# Install directly from the official tap
brew install halpworld/tap/halpradioTo upgrade anytime:
brew upgrade halpradioAutomatically detects your OS and architecture (arm64 / amd64), downloads the latest release binary, and installs it to /usr/local/bin:
curl -fsSL https://raw.githubusercontent.com/halpworld/halpradio/main/install.sh | bashDownload pre-compiled standalone tarballs from the GitHub Releases page:
| Platform | Architecture | Package |
|---|---|---|
| macOS | Apple Silicon (M1/M2/M3/M4) | halpradio_*_darwin_arm64.tar.gz |
| macOS | Intel x86_64 | halpradio_*_darwin_amd64.tar.gz |
| Linux | x86_64 | halpradio_*_linux_amd64.tar.gz |
| Linux | ARM64 / Raspberry Pi / AWS Graviton | halpradio_*_linux_arm64.tar.gz |
| Windows | x86_64 / ARM64 | halpradio_*_windows_*.zip |
If you have Go 1.21+ installed:
go install github.com/halpworld/halpradio@latestgit clone https://github.com/halpworld/halpradio.git
cd halpradio
go build -o halpradio main.go
./halpradioFor Arch Linux (AUR), Scoop (Windows), or Nix packaging, see the Packaging Guide.
halpradio works completely out of the box using its built-in native Go audio engine (oto/v3 + go-mp3) with zero external binary dependencies required!
| Audio Backend | Priority | MP3 | AAC | OGG | FLAC | HLS / M3U8 | Dependencies |
|---|---|---|---|---|---|---|---|
| mpv (recommended) | 1st | ✅ | ✅ | ✅ | ✅ | ✅ | brew install mpv / apt install mpv |
| vlc / cvlc | 2nd | ✅ | ✅ | ✅ | ✅ | ✅ | brew install vlc / apt install vlc |
| ffplay | 3rd | ✅ | ✅ | ✅ | ✅ | ✅ | ffmpeg |
| native (Go oto) | 4th | ✅ | ❌ | ❌ | ❌ | ❌ | Zero dependencies (built-in) |
halpradio will automatically detect mpv > vlc > ffplay > native on startup. You can override this anytime with the -backend flag:
halpradio -backend mpv
halpradio -backend nativehalpradio provides deep desktop operating system integration across macOS and Linux:
Shows live radio playback activity directly on your Discord profile in real time:
- Station Name: e.g.
SomaFM Groove Salad - Track Info: e.g.
Tycho - A Walk(orStreaming Live...) - Active Animal DJ Avatar: Matches your active visualizer (
dj_cat,dj_dog,dj_bear,dj_frog,dj_bunny). - Duration: Live elapsed listening timer.
- Non-blocking and silent failover if Discord is not running.
- Toggle via
-discord=falseflag ordiscord_rpc: falseinconfig.yaml.
Query the running instance instantly from scripts and custom desktop status lines without opening the TUI:
# Plain text output for status lines
halpradio current
# Output: SomaFM Groove Salad: Tycho - A Walk
# Full JSON metadata payload for Waybar / Polybar / SketchyBar
halpradio current --json
# Output:
# {
# "status": "playing",
# "station_id": "somafm_groovesalad",
# "station_name": "SomaFM Groove Salad",
# "artist": "Tycho",
# "title": "A Walk",
# "bitrate": 128,
# "backend": "mpv",
# "volume": 80,
# "visualizer": "dj-cat"
# }Control playback instantly from the terminal, window managers (i3/sway/hyprland), Raycast, Alfred, or tmux:
# Convenience shortcuts:
halpradio toggle # Toggle play / pause
halpradio next # Jump to next station
halpradio prev # Jump to previous station
halpradio stop # Stop playback
halpradio current # Query current station & track
# Subcommand style:
halpradio remote toggle
halpradio remote volup # Volume +5%
halpradio remote voldown # Volume -5%
halpradio remote mute # Toggle mute
halpradio remote random # Play random station
halpradio remote status # Inspect full status- macOS Shortcuts / Raycast / Alfred: Map
halpradio toggleorhalpradio nextto media keys or hotkeys. - tmux: Add
bind-key P run-shell "halpradio toggle"andset -g status-right "#(halpradio current)"to~/.tmux.conf. - Waybar: Add custom module with
exec: "halpradio current --json",return-type: "json".
Registers standard D-Bus service org.mpris.MediaPlayer2.halpradio on the session bus.
- Control halpradio seamlessly from your keyboard media keys, GNOME / KDE Plasma media panels, and Waybar/Polybar modules.
- Supports standard MPRIS methods:
PlayPause,Play,Pause,Stop,Next,Previous,Quit. - Control from terminal:
playerctl play-pause,playerctl next,playerctl previous,playerctl stop.
Whenever a radio station broadcasts a new track title via ICY metadata, halpradio fires a native desktop notification banner:
- Title:
📻 halpradio — [Station Name] - Body:
🎶 [Artist] - [Title] - Built-in deduplication ensures zero spam.
- Toggle via
-notifications=falseorsong_notifications: falseinconfig.yaml.
When the default audio output device leaves Bluetooth — e.g. AirPods taken out of the ears or the case closed — playback pauses automatically, matching macOS Music behavior:
- Works with every backend (
mpv,vlc,ffplay,native, ...). - Toggle via
-autopause=falseorautopause: falseinconfig.yaml.
Tired of stations broadcasting mystery tracks with zero metadata, or streams polluted with ads, jingles, station slogans, and website URLs? halpradio features an acoustic stream recognition engine and intelligent metadata sanitizer:
- Instant Recognition: Press
Ianywhere during playback to identify what is playing directly from raw audio PCM data. - Chromaprint & AcoustID: Captures a 5-second sample buffer, computes audio subfingerprints (using
fpcalcor pure-Go fallback), and queries the AcoustID and MusicBrainz databases. - Visual Confidence Score: Displays the matched artist, song, album, year, and a live confidence bar directly in the playerbar (
[✨ Identified via AcoustID (94%)]/████████░ 94%). - Auto-Identify Mode: Set
auto_identify: trueinconfig.yamlor launch with--auto-identifyto automatically fingerprint songs on streams that lack ICY metadata after 20 seconds. - Clipboard & Search Integration: Yanking (
y) copies the verified track title to your clipboard. Searching (o) immediately opens Spotify, Apple Music, or YouTube with clean metadata. - Persistent History (
H): Identified tracks are automatically recorded to the History tab with a✨star badge. - Graceful Offline Fallback: If offline or if the database cannot find a match, the player falls back cleanly without interrupting playback.
Internet radio ICY streams often emit dirty titles like:
LIVE NOW: Tycho - A Walk (Buy on Somafm.com) // Best Chill Music! - 128kbps
halpradio continuously cleans ICY stream titles with built-in regex sanitizers:
- Strips advertisements, sponsors, promotional URLs, and "Buy on ..." text.
- Removes radio jingles, slogans, frequencies (
104.5 FM), and station station identifiers. - Cleans composite delimiters, extra brackets, and bitrate tags while preserving genuine artist and song titles.
Modern terminals grew real graphics capabilities, so halpradio uses them. Press L for a live lyric sheet that scrolls itself, and A for the cover art of whatever is on air — all without leaving the terminal.
- LRCLIB First: Queries LRCLIB with the artist, title and duration taken from ICY stream metadata or the acoustic fingerprint, then falls back to NetEase when LRCLIB has no match.
- Auto-Scrolling Karaoke View: When timestamped
.lrcdata exists, the drawer highlights the line being sung, fades the surrounding lines, and draws a progress gauge across the active line. - Manual Scroll For Plain Text: Unsynced lyrics render as a formatted sheet you scroll with
j/k. - Sync Nudge: Internet radio exposes no seek position, so the lyric clock starts when the station announces a new title. Press
,and.to shift the sync in 0.5 second steps when a station announces late or early. - Never Blocks The UI: Every lookup runs as a Bubble Tea command off the update loop, so the TUI stays responsive on slow connections.
- Fits Any Terminal: At 80 columns or wider the drawer takes its own columns rather than overlapping the station list; below that the sheet becomes a full-width overlay, and resizing moves it between the two without closing it.
- Disk & Memory Cache: Sheets are memoised in RAM and cached under
~/.cache/halpradio/lyrics/, and stations with no match are negative-cached so the APIs are not hammered every track.
halpradio detects your terminal's best image transport at startup and encodes artwork for it:
| Priority | Protocol | Terminals |
|---|---|---|
| 1 | Kitty Graphics | Ghostty, Kitty, WezTerm |
| 2 | iTerm2 Inline Images | iTerm2, WezTerm |
| 3 | Sixel | Foot, xterm, mlterm, yaft |
| 4 | Truecolor Half-Block | every 24-bit colour terminal |
| 5 | Braille | 256-colour and monochrome fallback |
- High-Res Cover Lookup: Artwork is resolved from the iTunes Search API, Deezer, MusicBrainz plus the Cover Art Archive, and Last.fm when you supply
lastfm_api_key. - No Distortion On Basic Terminals: The half-block and Braille renderers letterbox the image to keep covers square, and every renderer emits output padded to an exact cell grid so the surrounding layout never shifts.
- Two Surfaces: A thumbnail sits at the top of the lyrics drawer, and
Aopens a floating full-size viewer showing the album, the provider and the active protocol. - Cached Locally: Downloaded covers live under
~/.cache/halpradio/art/.
┌─ 📻 CATALOG ──────────────────┬─ 📜 LIVE LYRICS ───────────────┐
│ ▶ SomaFM Groove Salad │ ▄▄▄▄▄▄▄▄▄▄▄▄ │
│ Nightwave Plaza │ █ ALBUM ART █ │
│ Radio Paradise │ ▀▀▀▀▀▀▀▀▀▀▀▀ │
│ KEXP 90.3 │ 🖼 iTunes │
│ │ Tycho - A Walk │
│ │ │
│ │ I've been wandering │
│ │ ► Searching for a signal ◄ │
│ │ Everything is quiet │
│ │ ━━━━━━━━━━━─────── │
│ │ ⏱ Synced via LRCLIB │
│ │ L close · , . sync │
└───────────────────────────────┴────────────────────────────────┘
Tune the feature from ~/.config/halpradio/config.yaml:
lyrics_enabled: true # LRCLIB / NetEase synced lyrics engine
lyrics_auto_open: false # open the drawer on startup
lyrics_offset_ms: 0 # persistent sync correction
album_art_enabled: true # terminal cover art renderer
album_art_protocol: auto # auto | kitty | iterm2 | sixel | halfblock | braille | off
lastfm_api_key: "" # optional extra cover art providerSet HALPRADIO_NO_ART=1 to disable image rendering for a single run, or HALPRADIO_ART_PROTOCOL=halfblock to force a transport when detection guesses wrong.
Share the groove with teammates, study groups, or friends with zero central audio relaying! halpradio features an end-to-end encrypted (E2EE) P2P mesh party system powered by WebRTC data channels:
- Quick Create & Join: Press
Ctrl+panywhere in the app to host a new room with a memorable 6-character room code (e.g.#8X2K9P) or join an existing session. - Argon2id & AES-256-GCM Encryption: Every party room derives high-entropy session keys with Argon2id and encrypts all peer-to-peer control traffic using AES-256-GCM with CSPRNG nonces.
- Zero Central Audio Relaying: Audio streams directly from the source radio broadcast on each client while synchronization commands and metadata travel peer-to-peer over WebRTC data channels.
- DJ Pass Governance: Host can choose Host Only (only the room creator can change stations) or Open Democracy (any participant can tune stations).
- Sub-Second Playback Sync: Late-joining listeners automatically tune to the room's current broadcast with sub-second clock sync.
- Deterministic Host Election: If the room host disconnects, peers deterministically elect a successor host without interrupting playback.
- While in an active party room, press
1-5anytime to float live reactions across connected listeners' terminals:1: 🔥 Fire2: ❤️ Heart3: ☕ Coffee4: 🚀 Rocket5: 👀 Eyes
- Floating reactions rise and decay gracefully over 3.5 seconds in the party bar without disturbing your TUI view.
Control and join party rooms directly from your shell or tmux sessions:
halpradio party create "team-focus" # Create room and launch TUI
halpradio party create --dj-pass=open # Create room with democratic DJ control
halpradio party create --headless # Host room headlessly in server / tmux
halpradio party join 8X2K9P # Join room #8X2K9P with interactive TUI
halpradio party status # Inspect current room, listener count, and host
halpradio party react 1 # Send 🔥 reaction to current room
halpradio party chat "Loving this track!" # Send mini-chat ping to room
halpradio party leave # Disconnect from current roomPress ? or F1 anywhere in halpradio to open the floating WhichKey Overlay.
| Category | Keybinding | Action |
|---|---|---|
| Navigation | j / k or ↓ / ↑ |
Move down / up |
n / ] |
Jump and play Next station in active list | |
N / [ |
Jump and play Previous station in active list | |
h / l or ← / → |
Focus sidebar / main list or prev/next tab | |
1 - 9 (0) |
Direct jump to Tab (1: Activities, 2: Catalog, 3: Countries, 4: Genres, 5: Favorites, 6: Online, 7: Custom, 8: History, 9: Globe, 0: Tuner) | |
C |
Jump directly to Countries / FM tab | |
H |
Jump directly to Track History tab | |
9 / M |
Jump directly to 3D Globe Explorer | |
0 / F |
Jump directly to Analog Frequency Tuner (experimental) | |
g / G |
Jump to top / bottom of list | |
Ctrl+u / Ctrl+d |
Half page up / down | |
| Discovery & Sharing | Ctrl+p |
Open Party Room Manager (P2P mesh synchronized listening & room setup) |
1 - 5 |
Send live floating ASCII reaction (🔥 ❤️ ☕ 🚀 👀) when in Party Room | |
I |
Identify playing track via acoustic stream fingerprinting (Chromaprint / AcoustID) | |
L |
Toggle live synced lyrics drawer (LRCLIB / NetEase) | |
A |
Toggle album art viewer (Kitty / Sixel / iTerm2 / half-block) | |
, / . |
Nudge lyric sync backward / forward by 0.5s (lyrics drawer open) | |
y |
Yank / copy track metadata (Artist - Title) or identified song to system clipboard |
|
o |
Open streaming search in default web browser (Spotify, YT Music, Apple, DDG, Google) | |
s |
Star / bookmark track to ~/.config/halpradio/saved_tracks.txt (on History tab) |
|
c |
Clear track history log (on History tab) | |
p |
Export station YAML snippet to clipboard for GitHub PR | |
| Playback | Space / Enter / ⏯️ |
Toggle Play / Pause selected station (or tune in from history) |
s / x / ⏹️ |
Stop audio stream (on station tabs) | |
z / Z |
Open Sleep Timer & Pomodoro Focus modal | |
r / R |
Play random station | |
+ / - / = / > |
Volume up / down (5% step, supports ANSI, ISO, AZERTY, QWERTZ) | |
m / M / 0 |
Mute / unmute | |
v |
Cycle visualizer (dj-cat, dj-dog, dj-bear, dj-frog, dj-bunny, bars, wave, spectrum, minimal) |
|
b |
Switch dial band (FM / AM / SW) in frequency tuner mode |
|
| Catalog | f |
Toggle Favorite star ⭐ |
/ |
Live fuzzy search / filter stations | |
w / c |
Jump & filter by Activity Mode / Genre Category | |
a |
Open Add Custom Station modal | |
e / d |
Edit / Delete local custom station | |
| UI & Options | P |
Open Plugins & Extensions Manager (Wasm Sandbox) |
t |
Theme picker modal (Tokyo Night, Catppuccin, Synthwave, etc.) | |
? / F1 |
Toggle WhichKey help overlay | |
q / Ctrl+c |
Quit halpradio |
halpradio includes a secure, capability-based WebAssembly (Wasm) Plugin Engine powered by tetratelabs/wazero (zero CGo, pure Go) and an official community registry at halpworld/halpradio-plugins.
- Press
Panywhere in halpradio to browse installed plugins and explore the official online registry. - 1-click install, enable/disable toggle, and interactive capability permission review modal (network whitelists, isolated storage).
halpradio plugin list # List installed and official registry plugins
halpradio plugin install <plugin-id> # Install plugin from official registry with SHA-256 verification
halpradio plugin enable <plugin-id> # Enable plugin
halpradio plugin disable <plugin-id> # Disable plugin
halpradio plugin remove <plugin-id> # Uninstall plugin
halpradio plugin update --all # Update plugins to latest version- Webhook Broadcaster: Broadcasts now-playing tracks to Discord, Slack, or Home Assistant webhooks in real-time.
- Scrobble Logger & Stats: Records station play counts, tracks listening milestones, and persists stats 100% offline.
👉 Want to build your own plugin? Check out the Plugin Developer SDK & Starter Template!
Switch themes on the fly by pressing t or pass -theme <name> via CLI:
- 🌌 Tokyo Night (
tokyonight) — Neon blue and purple developer aesthetic - ☕ Catppuccin Mocha (
catppuccin) — Soothing pastel dark palette - 🌆 Retro Synthwave '84 (
synthwave) — Vibrant neon magenta and cyan - ❄️ Nord (
nord) — Cool arctic blue minimalism - 🪵 Gruvbox Dark (
gruvbox) — Warm retro terminal tones - 🧛 Dracula (
dracula) — High-contrast gothic vampire theme
- Discover & Download: Press
tthenTabto enter the Community Hub ([2] 🌐 Community Hub). Browse dozens of online community palettes (Rosé Pine, Everforest, Kanagawa, Monokai Pro, One Dark Pro, Cyberpunk 2077, Cyberdream, etc.) and pressiorEnterto download & apply instantly. - 👁️ Live Preview: Press
pon any theme to preview it live in your full terminal interface before downloading or saving! PressporEscto revert. - Filter & Search: Press
/in the Community Hub to filter themes by name, style, or author.
halpradio theme list # List installed and community hub themes
halpradio theme preview rose-pine # Preview color swatches & mockup in terminal
halpradio theme install rose-pine # Download and install from themes repo
halpradio theme info everforest # Inspect semantic color tokens
halpradio theme export my-theme # Export active palette as YAML starter
halpradio theme remove my-theme # Uninstall custom themeExplore and contribute community themes in the official halpradio-themes repository.
Explore hundreds of curated streams across diverse activity moods and global genres:
- 🎧 Focus & Flow: Lofi Girl Radio, Chillhop Music, SomaFM Groove Salad, DEF CON Radio, Nightwave Plaza
- ☕ Acoustic & Coffee: Cafe De Paris, Smooth Jazz Florida, Swiss Classic, Instrumental Ambient
- 🚀 High Energy Coding: Synthwave 1980s, Cyberpunk FM, Goa Psytrance, Digitally Imported (DI.FM)
- 🌏 Global Radio: BBC Radio 6 Music (UK), KEXP 90.3 FM Seattle (US), Radio Paradise (US), FM 802 Osaka (JP), Big B Radio K-Pop (KR), FIP Radio (FR), Triple J (AU)
- 📰 News & Public Broadcasts: NPR 24 Hour Program Stream, BBC World Service, Deutschlandfunk
If halpradio misbehaves — a freeze, silent playback, a station that never connects — run it with --debug:
halpradio --debugDiagnostics are written to ~/.config/halpradio/debug.log (override with --debug-log <path>, or set
HALPRADIO_DEBUG=1). The log records the halpradio version, OS, terminal, selected audio backend, the exact
player command line, every keystroke the UI handled, and the state of the desktop integrations (MPRIS, IPC,
Discord).
Because the TUI runs a single-threaded update loop, a freeze is almost always something blocking inside it. A built-in watchdog notices when the loop has been stuck for more than five seconds and appends a full goroutine dump to the log, which usually names the culprit outright:
14:02:11.884 [update] → Update KeyMsg "enter"
14:02:16.885 [watchdog] STALLED: Update KeyMsg "enter" (stuck 5.001s)
14:02:16.885 [watchdog] goroutine dump (stalled operation): ...
So if the UI locks up, wait about ten seconds before killing halpradio (from another terminal:
pkill halpradio), then attach debug.log to your bug report.
The log contains station stream URLs and local file paths; it is written with 0600 permissions, and it never
records credentials. Skim it before pasting it into a public issue.
Explore detailed technical documentation in the docs/ folder:
- 🏗️ Architecture Overview: Elm Architecture (Bubble Tea MVU), package breakdown, event loop, and concurrency model.
- 🔌 Plugin & Extension System Guide: Sandboxed WebAssembly (Wasm) architecture, capability permissions, developer SDK, and publishing to the official registry.
- 🎵 Audio Engine & Stream Player: Multi-backend auto-detection (
mpv,vlc,ffplay, native Go), process lifecycle, and real-time ICY metadata extraction. - 📻 Station Catalog & RadioBrowser Integration: Station storage hierarchy (
stations.yaml, local config, favorites), RadioBrowser API client, and PR export workflow. - 📜 Synced Lyrics & Terminal Album Art: LRCLIB / NetEase lyric providers, LRC parsing, playback-position estimation, cover art providers, and the Kitty / iTerm2 / Sixel / half-block / Braille renderers.
- 🎨 Theme System & Audio Visualizers: Lipgloss styling system, theme palettes, and TUI visualizer algorithms.
- ⚙️ Configuration & Keybindings: Directory layout,
config.yamloptions, CLI flags, and complete keymap reference. - 📦 Packaging & Distribution Guide: Specifications for Homebrew, Arch Linux AUR, Docker, Scoop, and Nix.
- 🤝 Developer & Contribution Guide: Developer setup, code standards, unit testing, and Pull Request checklist.
- 🤖 AI Agent Integration Guide: Guidelines for AI coding agents (Google Antigravity via
AGENTS.md& Claude Code viaCLAUDE.md).
We love community contributions! Expanding the catalog takes less than 30 seconds:
- Select any station in halpradio and press
p(copies formatted YAML to clipboard). - Paste the snippet into
stations.yamland submit a Pull Request. - Alternatively, submit a Station Suggestion Issue.
- See CONTRIBUTING.md for full guidelines.
This project is licensed under the GNU General Public License v3.0 (GPL-3.0).





