Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ halpradio/
├── pkg/
├── app/app.go # CLI flags (-backend, -theme, -version), config loading, tea.Program setup
├── player/player.go # Player interface, Manager struct, multi-backend exec, native Oto audio, ICY stream listener
├── party/ # P2P mesh synchronized radio rooms, Argon2id/AES-256-GCM E2EE & protocol engine
├── plugin/ # Wazero Wasm sandbox, capability permissions, host API, registry client
├── radio/ # Store (bundled/local/favorites), Station struct, RadioBrowser HTTP client
├── theme/theme.go # Theme struct & color palettes (tokyonight, catppuccin, synthwave, nord, gruvbox, dracula)
Expand Down
10 changes: 5 additions & 5 deletions Formula/halpradio.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@
class Halpradio < Formula
desc "LazyVim-inspired Terminal Internet Radio Streamer"
homepage "https://github.com/halpworld/halpradio"
version "0.4.0"
version "0.5.0"
license "GPL-3.0-or-later"

on_macos do
if Hardware::CPU.arm?
url "https://github.com/halpworld/halpradio/releases/download/v0.4.0/halpradio_0.4.0_darwin_arm64.tar.gz"
url "https://github.com/halpworld/halpradio/releases/download/v0.5.0/halpradio_0.5.0_darwin_arm64.tar.gz"
else
url "https://github.com/halpworld/halpradio/releases/download/v0.4.0/halpradio_0.4.0_darwin_amd64.tar.gz"
url "https://github.com/halpworld/halpradio/releases/download/v0.5.0/halpradio_0.5.0_darwin_amd64.tar.gz"
end
end

on_linux do
if Hardware::CPU.arm? && Hardware::CPU.is_64_bit?
url "https://github.com/halpworld/halpradio/releases/download/v0.4.0/halpradio_0.4.0_linux_arm64.tar.gz"
url "https://github.com/halpworld/halpradio/releases/download/v0.5.0/halpradio_0.5.0_linux_arm64.tar.gz"
else
url "https://github.com/halpworld/halpradio/releases/download/v0.4.0/halpradio_0.4.0_linux_amd64.tar.gz"
url "https://github.com/halpworld/halpradio/releases/download/v0.5.0/halpradio_0.5.0_linux_amd64.tar.gz"
end
end

Expand Down
41 changes: 40 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ docker run --rm -it --device /dev/snd halpworld/halpradio:latest
| **Linux MPRIS v2 & Media Keys** | ✅ **Native D-Bus + `playerctl`** | ❌ None | ❌ None | ❌ None | ⚠️ Basic MPRIS |
| **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 | ⚠️ Socket |
| **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 | ⚠️ Basic sleep |
| **Beat-Reactive Animated Visualizers** | ✅ **5 Animal DJs + EQ Spectrum** | ❌ None | ❌ None | ❌ None | ⚠️ Basic VU |
Expand Down Expand Up @@ -321,6 +322,42 @@ Internet radio ICY streams often emit dirty titles like:

---

## 🎉 Terminal Party Line: P2P Mesh Synchronized Radio Rooms & Reactions

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:

### 👥 In-TUI Party Manager (`Ctrl+p`)
- **Quick Create & Join**: Press `Ctrl+p` anywhere 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.

### 🎈 Live ASCII Reactions & Mini-Chat
- While in an active party room, press `1` - `5` anytime to float live reactions across connected listeners' terminals:
- `1`: 🔥 Fire
- `2`: ❤️ Heart
- `3`: ☕ Coffee
- `4`: 🚀 Rocket
- `5`: 👀 Eyes
- Floating reactions rise and decay gracefully over 3.5 seconds in the party bar without disturbing your TUI view.

### ⌨️ CLI Party Commands
Control and join party rooms directly from your shell or tmux sessions:
```bash
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 room
```

---

## ⌨️ Navigation & Keybindings (Vim & Media Style)

Press `?` or `F1` anywhere in **halpradio** to open the floating **WhichKey Overlay**.
Expand All @@ -338,7 +375,9 @@ Press `?` or `F1` anywhere in **halpradio** to open the floating **WhichKey Over
| | `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** | `I` | **Identify playing track** via acoustic stream fingerprinting (Chromaprint / AcoustID) |
| **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) |
| | `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) |
Expand Down
1 change: 1 addition & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ We actively provide security patches and updates for the following versions of *

| Version | Supported |
| ------- | ------------------ |
| 0.5.x | :white_check_mark: |
| 0.4.x | :white_check_mark: |
| 0.3.x | :white_check_mark: |
| 0.2.x | :white_check_mark: |
Expand Down
6 changes: 4 additions & 2 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,22 @@ halpradio/
├── app/ # CLI flag parsing, configuration loading & app bootstrap
├── player/ # Multi-backend audio playback engine & ICY stream reader
│ └── fingerprint/ # Acoustic stream recognition, Chromaprint / AcoustID client, LRU cache
├── party/ # P2P mesh synchronized radio rooms, Argon2id/AES-256-GCM E2EE & protocol engine
├── plugin/ # Wazero Wasm sandboxing engine, capability permissions, host API, registry client
├── radio/ # Station catalog store, YAML parser, RadioBrowser client & metadata sanitizer
├── theme/ # Theme definitions & color palette registry
├── timer/ # Pomodoro focus engine, sleep timer with volume fade, and OS event dispatcher
├── ui/ # Main Bubble Tea Model, Update, View, and Keymap logic
│ └── components/ # Modular UI sub-views (Header, StationList, PlayerBar, Visualizer, Modals)
│ └── components/ # Modular UI sub-views (Header, StationList, PlayerBar, Visualizer, Modals, PartyBar)
└── util/ # OS configuration directory resolution & clipboard utilities
```

### Module Breakdown:

| Package | Key Types / Files | Responsibilities |
|---|---|---|
| [`pkg/app`](../pkg/app/app.go) | `Run()`, `RunPluginCLI()` | Parses CLI flags (`--backend`, `--theme`, `--version`, `--fingerprint`, `--auto-identify`), handles CLI subcommands (`remote`, `plugin`), sets up store, instantiates `player.Manager`, initializes `tea.Program`. |
| [`pkg/app`](../pkg/app/app.go) | `Run()`, `RunPluginCLI()` | Parses CLI flags (`--backend`, `--theme`, `--version`, `--fingerprint`, `--auto-identify`), handles CLI subcommands (`remote`, `plugin`, `party`), sets up store, instantiates `player.Manager`, initializes `tea.Program`. |
| [`pkg/party`](../pkg/party/sync.go) | `Session`, `MeshNode`, `Packet`, `Crypto` | P2P mesh synchronized radio rooms, WebRTC data channels, Argon2id key derivation & AES-256-GCM encryption, sub-second playback sync, host election, ASCII reaction bus. |
| [`pkg/player`](../pkg/player/player.go) | `Player`, `Manager`, `TrackInfo` | Detects audio CLI backends (`mpv`, `vlc`, `ffplay`, etc.) or falls back to native Go audio. Runs ICY metadata streaming goroutine. |
| [`pkg/player/fingerprint`](../pkg/player/fingerprint/client.go) | `Client`, `Result`, `LRUCache` | Captures 5s audio buffers, computes Chromaprint subfingerprints, queries AcoustID & MusicBrainz APIs with LRU caching. |
| [`pkg/plugin`](../pkg/plugin/manager.go) | `Manager`, `Sandbox`, `Manifest`, `RegistryClient` | Executes sandboxed WebAssembly plugins via Wazero with capability checks (`network`, `storage`, `events`). Fetches and verifies official registry packages. |
Expand Down
10 changes: 5 additions & 5 deletions docs/PACKAGING.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ For Arch Linux users, the binary package can be built using the following `PKGBU
```bash
# Maintainer: halpworld <https://github.com/halpworld>
pkgname=halpradio-bin
pkgver=0.4.0
pkgver=0.5.0
pkgrel=1
pkgdesc="LazyVim-inspired Terminal Internet Radio Streamer"
arch=('x86_64' 'aarch64')
Expand Down Expand Up @@ -88,17 +88,17 @@ For Windows users using [Scoop](https://scoop.sh):

```json
{
"version": "0.4.0",
"version": "0.5.0",
"description": "LazyVim-inspired Terminal Internet Radio Streamer",
"homepage": "https://github.com/halpworld/halpradio",
"license": "GPL-3.0-or-later",
"architecture": {
"64bit": {
"url": "https://github.com/halpworld/halpradio/releases/download/v0.4.0/halpradio_0.4.0_windows_amd64.zip",
"url": "https://github.com/halpworld/halpradio/releases/download/v0.5.0/halpradio_0.5.0_windows_amd64.zip",
"bin": "halpradio.exe"
},
"arm64": {
"url": "https://github.com/halpworld/halpradio/releases/download/v0.4.0/halpradio_0.4.0_windows_arm64.zip",
"url": "https://github.com/halpworld/halpradio/releases/download/v0.5.0/halpradio_0.5.0_windows_arm64.zip",
"bin": "halpradio.exe"
}
}
Expand All @@ -114,7 +114,7 @@ For Windows users using [Scoop](https://scoop.sh):

buildGoModule rec {
pname = "halpradio";
version = "0.4.0";
version = "0.5.0";

src = fetchFromGitHub {
owner = "halpworld";
Expand Down
2 changes: 1 addition & 1 deletion install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ if [ -z "${VERSION}" ]; then
echo "🔍 Fetching latest halpradio release..."
VERSION=$(curl -s "https://api.github.com/repos/${REPO}/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
if [ -z "${VERSION}" ]; then
VERSION="v0.4.0"
VERSION="v0.5.0"
fi
fi

Expand Down
2 changes: 1 addition & 1 deletion pkg/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
"github.com/halpworld/halpradio/pkg/util"
)

var Version = "0.4.0"
var Version = "0.5.0"

type AppInstance struct {
Program *tea.Program
Expand Down
Loading