docs: add CLAUDE.md operator manual and README.md

This commit is contained in:
devilreef 2026-04-30 11:01:01 +06:00
parent 9500a93fde
commit 21d214abe9
Signed by: devilreef
SSH key fingerprint: SHA256:UZisRr4iuXx+IhkbZnR655L2RWAT6o2rgbGv5F/6m3Y
2 changed files with 283 additions and 0 deletions

79
README.md Normal file
View file

@ -0,0 +1,79 @@
# denpa-radio
a tiny independent multi-station internet radio. cassette-deck aesthetic, real audio, no algorithms.
live at **<https://denpa.femboy.page>**.
## what's playing
| station | description | mp3 | opus |
| --------- | ---------------------------------------- | --------------------------------------------------- | ----------------------------------------------------- |
| minecraft | C418, Lena Raine, Aaron Cherof — vol α+β | <https://denpa.femboy.page/minecraft.mp3> (192k) | <https://denpa.femboy.page/minecraft.opus> (96k) |
drop a stream URL into VLC, mpv, foobar, or any internet-radio app.
## endpoints
- `/<station>.mp3` — MP3 192 kbps stream
- `/<station>.opus` — Opus 96 kbps stream
- `/now-playing/<station>.json` — currently playing (artist, title, album, duration, started_at)
- `/now-playing/<station>.history.json` — last 50 tracks for the station
- `/api/stations.json` — list of all stations with metadata
- `/api/stations/<station>/cover` — cover art (when present)
- `/status-json.xsl` — raw Icecast status (listener counts, mount info)
CORS is open on all of the above; build your own scrobbler / dashboard / overlay.
## architecture
```
Caddy (host) ─┬─ /<station>.{mp3,opus}, /status-json.xsl → icecast (libretime/icecast)
├─ /now-playing/*.json → caddy file_server
├─ /api/* → frontend (astro 5 + react)
└─ / → frontend
└─ liquidsoap (savonet/liquidsoap)
│ reads station folders
│ writes now-playing JSON
Hetzner Storage Box (CIFS, mounted RO)
```
three docker containers (icecast, liquidsoap, frontend) and a Caddy host service. each station is a folder on the storage box with a `_meta.yml`, a `tracks/` subdir, and an optional `cover.{jpg,png,webp}`. the frontend reads `_meta.yml` files at request time, so adding a station does not require a rebuild.
## adding a station
on the storage box (mounted at `/mnt/trashbox/denpa-radio/library/` on summer):
```
mkdir <station-id>/{tracks,jingles}
cat > <station-id>/_meta.yml <<EOF
name: My Station
description: short description
color: '#5cae34'
tags: [tag1, tag2]
EOF
# drop audio files into <station-id>/tracks/
# (optional) drop cover.jpg into <station-id>/
```
then on summer:
```
# duplicate the existing minecraft station block in /srv/denpa-radio/config/liquidsoap.liq
# rename references to your new id, then:
docker compose -f /srv/denpa-radio/docker-compose.yml restart liquidsoap
```
the frontend picks up the new station within ~30s. no Caddy reload, no Icecast restart.
station ids must match `[a-z0-9-]+`.
## tags
- **v0.1.0** — radio backend live (Minecraft station, MP3 + Opus).
- **v0.2.0** — frontend live (cassette deck UI, real WebAudio spectrum, recently-played).
## working on this repo
see [`CLAUDE.md`](./CLAUDE.md) for the full operator's manual: SSH conventions, deploy quirks, frontend stack notes, Liquidsoap gotchas, and the things we've already learned the hard way.