Skip to content

Releases: johncrash64/radio-dj

v0.5.0 — skip & previous controls for the live broadcast

Choose a tag to compare

@johncrash64 johncrash64 released this 07 Aug 05:42
546a3f7

Skip & previous controls for the live broadcast

The player gets ◀◀ / ▶▶ transport keys, backed by a new POST /control endpoint.

SkipCurrent() kills only the in-flight music decoder and leaves the master Icecast source untouched — connected listeners stay on, the filtergraph just stops receiving new PCM. The radio loop then advances to the next track or replays the previous one. It's a shared broadcast: a skip changes what every listener hears.

POST /control
{ "action": "next" }          // or "previous"

→ 202 {"ok":true}                     accepted, loop advances
→ 409 {"error":"no track playing"}    nothing on air (between songs)
→ 400 {"error":"action must be ..."}  invalid action

Rapid clicks coalesce into one pending action. The transport keys latch down until the track actually changes, like a real deck key staying engaged while it works, then spring back — with a 4s safety timer so a key can never stick.

Fixed

  • Two data races in the control path, both reachable from an HTTP goroutine and invisible without -race. Server.controlHandler was read/written unguarded while the HTTP server was already serving; and the control closure captured streamer, which the radio loop reassigns on a master reopen. Both are now properly synchronized.
  • install.sh could not install a pinned version. GitHub serves the floating latest and a pinned tag from different URL shapes; the script built the pinned form the latest way, so RDJ_VERSION=v0.4.0 returned 404.
  • install.sh's build-from-source fallback was broken. go.mod declares module radio-dj, not the GitHub path, so go install github.com/johncrash64/radio-dj@... failed with a module path mismatch. It now clones the tag and builds.
  • Music-only stations could not open the player UI (carried over from the previous release cycle).

Added

  • radio-dj version — release builds report their tag, development builds report dev. The release script had been injecting -X main.version into a symbol that didn't exist, so no build could report what it was.

Known limitations

  • previous on the very first track after startup behaves as next — there is no previous track recorded yet.
  • A skip during a previous replay is consumed as "return to the interrupted track".
  • Returning from a replay re-emits the request DJ-log line for that track.
  • There is no client-side reconnect, so the key springs back when the metadata changes — a buffer-depth ahead of what the listener actually hears.

Install

curl -fsSL https://github.com/johncrash64/radio-dj/raw/master/install.sh | bash

Or pin it — which, as of this release, actually works:

RDJ_VERSION=v0.5.0 bash -c "$(curl -fsSL https://github.com/johncrash64/radio-dj/raw/master/install.sh)"

v0.4.0 — hardware AAC encoder + cross-platform defaults

Choose a tag to compare

@johncrash64 johncrash64 released this 06 Aug 21:57

✨ What's new

Configurable, cross-platform broadcast encoder. The stream encoder is now platform-aware and overridable:

Platform Default encoder Notes
macOS aac_at Apple AudioToolbox, hardware-accelerated — ~128× realtime, far lower CPU than software MP3
Linux / Windows aac ffmpeg's built-in — always present, no extra lib
Override RDJ_ENCODER=libmp3lame (or any ffmpeg audio encoder)

The stream mount follows the encoder: aac* → /stream.aac, libmp3lame → /stream.mp3. Everything — icecast mount-name, reverse-proxy route, web <audio> src — is derived from one place (internal/codec), so the player can no longer desync from the stream.

⚠️ Breaking — for listeners with a hardcoded URL

The default stream URL is now /stream.aac (was /stream.mp3). To keep MP3, set RDJ_ENCODER=libmp3lame.

🐛 Fixed

The web player's <audio> src was hardcoded to stream.mp3 in the page JS — it would 404 after any encoder/mount change. Now follows the configured mount.

⚡ Performance

The always-on encoder is ~1.6× faster on Apple Silicon (aac_at 128× vs libmp3lame ~78× realtime). The live DJ ducking filtergraph remains the bulk of CPU by design — that's the cost of real-time voice-over ducking.


Install: curl -fsSL https://github.com/johncrash64/radio-dj/raw/master/install.sh | bash
Full changelog: see CHANGELOG.md

v0.3.1 — legacy dj-log render fix

Choose a tag to compare

@johncrash64 johncrash64 released this 06 Aug 15:39

🔧 Fix

Follow-up to v0.3.0's structured DJ log.

Problem: legacy HH:MM:SS [KIND] text entries (written by v0.2.0 and earlier) parse to {kind:"", text:"<whole line>"}. The structured renderer prefixed every entry with a kind bracket, so legacy lines showed a stray empty [] before the raw text — and on an upgrade, 100% of the existing log is legacy.

Fix: when kind is empty (legacy), render the line as-is with no bracket prefix. Structured entries (from v0.3.0's JSONL writer) still get the localized label.

📦 Binaries

radio-dj-{darwin,linux}-{arm64,amd64} — stripped, CGO_ENABLED=0.

v0.3.0 — structural i18n + structured DJ log

Choose a tag to compare

@johncrash64 johncrash64 released this 06 Aug 15:31
5341b25

🔧 Fixes

Structural i18n — no more text-injection bugs

PR #4 hand-escaped one localized string to stop an apostrophe (The DJ hasn't spoken yet…) from breaking the player. Five more sites had the same latent bug. This release fixes the whole class structurally:

  • text/template → html/template — contextual auto-escaping for every HTML/attribute context.
  • JSON data island — JS-consumed strings travel as <script type="application/json" id="i18n">, read via JSON.parse. Strings are never interpolated into JS source, so a quote or apostrophe can't break the page or open XSS. Adding a UI string = add an ui_* key to prompts/{lang}.json, zero plumbing.

Structured DJ log — the regex is gone

The DJ-log view parsed its own text format with a regex whose tokens (DJ|PEDIDO|HORA) were duplicated between writer and reader — rename one and the view silently broke.

  • /dj-log now returns structured JSON ([{t,kind,text}]).
  • Shared kind enum (status.LogKindDJ/Req/Time) used by both writer and reader — single source of truth, no regex, no token drift.
  • Backward compatible: legacy HH:MM:SS [KIND] text lines degrade to raw entries, so an in-place upgrade never breaks the view.
  • Log-kind labels localized — EN users no longer see Spanish PEDIDO/HORA tokens.

⬆️ Upgrade

Existing installs pick this up with no config change:

curl -fsSL https://github.com/johncrash64/radio-dj/raw/master/install.sh | bash

Or pin this version: RDJ_VERSION=v0.3.0 before running the installer.

📦 Binaries

Stripped, cross-compiled (CGO_ENABLED=0):

  • radio-dj-darwin-arm64 — Apple Silicon
  • radio-dj-darwin-amd64 — Intel Mac
  • radio-dj-linux-arm64 — Raspberry Pi 4/5
  • radio-dj-linux-amd64 — x86_64 servers

Full diff: #5

v0.2.0 — OpenRC + full i18n

Choose a tag to compare

@johncrash64 johncrash64 released this 05 Aug 16:31

v0.2.0

New install targets (OpenRC) and a fully localized UI — plus several fixes
reported after the v0.1.0 launch.

✨ New

  • OpenRC init support — installs as a service on Alpine, Artix, Void, and
    Gentoo (systemd and macOS launchd still supported).
  • Full UI localization — dashboard and DJ prompts render entirely in your
    RDJ_LANGUAGE (es/en): tabs, buttons, placeholders, play/connecting states,
    empty views, and aria-labels. The document now also declares the correct
    <html lang> for screen readers.
  • Prebuilt binaries for Linux/macOS (arm64 + amd64) — install.sh downloads
    the matching one and skips the Go toolchain.

🐛 Fixed

  • Symlinked music libraries now scan — a NAS/gvfs-mounted library no longer
    returns 0 tracks. (Thanks @vrutkovs — PR #1)
  • GLM provider no longer breaks Groq/OpenAI — the thinking field is sent
    only to GLM, so other providers stop rejecting requests.
  • Installer skips already-installed deps and sets up the OpenRC conf.d
    PATH correctly.
  • DJ clock guard made symmetric; PWA audio buffer released on stop.

Full diff: v0.1.0...v0.2.0

v0.1.0 — first release

Choose a tag to compare

@johncrash64 johncrash64 released this 02 Aug 03:17

First public release of radio-dj — a 24/7 AI-DJ internet radio in a single Go binary (~20 MB RAM).

Downloads

File Platform
radio-dj-darwin-arm64 macOS (Apple Silicon)
radio-dj-darwin-amd64 macOS (Intel)
radio-dj-linux-arm64 Linux ARM64 (Raspberry Pi 4/5)
radio-dj-linux-amd64 Linux x86_64
curl -fsSL https://github.com/johncrash64/radio-dj/raw/master/install.sh | bash

The installer picks the right binary for your platform automatically. See README for setup.

SHA-256 checksums in checksums-sha256.txt.