diff --git a/README.md b/README.md index 49379ae7..4e29f721 100644 --- a/README.md +++ b/README.md @@ -58,9 +58,9 @@ Eight services start: `db`, `icecast`, `engine`, `api`, `kokoro` (TTS synthesize - **API:** `http://localhost:8080` — anonymous hot path (`GET /media/random`, `GET /media/{id}`, `GET /health`) plus the cookie-auth admin surface under `/api/*` - **Spectator page:** `http://localhost:8081` — the station's read-only public face (now playing, history, stats, an optional anonymous song-request line with free-text wishes plus genre/mood pickers). Off by default: flip the live `Station:SpectatorMode` setting to enable it; [DEPLOYMENT.md](DEPLOYMENT.md) covers the four operating modes and the public topology. Metadata-aware players also get **per-track album art** via ICY `StreamUrl` once `Station:PublicBaseUrl` is set. -On first boot the library scans `MEDIA_DIR`, enriches each file (loudness + cue + energy + BPM + tags, plus a high-confidence MusicBrainz release-year lookup when the tags carry none — disable-able live via `Library:YearLookup:Enabled`), and the feeder begins pulling ready tracks. Until the first tracks are ready, the engine plays the safe-rotation source — a curated library scope (`Station:SafeScope:LibraryIds`) pulled via `GET /internal/safe-track`. On a fresh deploy, a one-shot boot seed creates a `safe` library, renders a branded TTS announcement ("Please Stand By"), and points SafeScope at it — so drains air the announcement, not a random track; an operator-set SafeScope is never overwritten. If the scope resolves empty, `mksafe` emits silence as a logged degraded mode. The Orchestrator interleaves TTS patter (station IDs, lead-ins, back-announces — and, opt-in, top-of-hour time checks plus weather and this-day-in-history segments) with music once Kokoro is up. When an `Llm:Endpoint` is configured (Settings page — live, no restart), lead-ins and back-announces become LLM-authored copy, optionally in an operator-authored DJ persona's voice (Personas page) — or hire a ready-made DJ from the community [Community Catalog](https://github.com/GenWave-Org/genwave-catalog) (CC0 persona cards, browsed and adopted one-click from the Admin UI after a full-card review); with no LLM configured the template patter airs unchanged. Station identity (`STATION_NAME`, voice, scope) defaults to `GWAV 108.8` / `af_heart` / library 1 — override via env if needed. +On first boot the library scans `MEDIA_DIR`, enriches each file (loudness + cue + energy + BPM + tags, plus a high-confidence MusicBrainz release-year lookup when the tags carry none — disable-able live via `Library:YearLookup:Enabled`), and the feeder begins pulling ready tracks. Until the first tracks are ready, the engine plays the safe-rotation source — a curated library scope (`Station:SafeScope:LibraryIds`) pulled via `GET /internal/safe-track`. On a fresh deploy, a one-shot boot seed creates a `safe` library, renders a branded TTS announcement ("Please Stand By"), and points SafeScope at it — so drains air the announcement, not a random track; an operator-set SafeScope is never overwritten. If the scope resolves empty, `mksafe` emits silence as a logged degraded mode. The Orchestrator interleaves TTS patter (station IDs, lead-ins, back-announces — and, opt-in, top-of-hour time checks plus weather and this-day-in-history segments) with music once Kokoro is up. When an `Llm:Endpoint` is configured (Settings page — live, no restart), lead-ins and back-announces become LLM-authored copy, optionally in an operator-authored DJ persona's voice (Personas page) — or hire a ready-made DJ from the community [Community Catalog](https://github.com/GenWave-Org/genwave-catalog) (CC0 persona cards, browsed and adopted one-click from the Admin UI after a full-card review); with no LLM configured the template patter airs unchanged. A weekly **format clock** (Schedule page — a drag-paint 7×48 grid) decides who's on the air when, with audible DJ-to-DJ handoffs at the boundaries; since v3.4.0 the hours have names too: **shows** (a name, a tagline, and a flavor line that colors the DJ's patter) assign to whole runs in one click, sign-ons welcome you to the named show, top-of-hour idents brand it, dated **specials** shadow the weekly grid for one-off broadcasts, and the spectator card tells listeners what's on now and up next. Station identity (`STATION_NAME`, voice, scope) defaults to `GWAV 108.8` / `af_heart` / library 1 — override via env if needed. -The station's look is themeable too (v3.0.0–v3.2.0). A theme is one JSON manifest — colour tokens for light and dark plus curated fonts — composed live into CSS for both the Admin UI and the spectator page; pick one via Settings or the switcher on either surface (a cookie-remembered visitor choice outranks the station default). The Community Catalog generalized from a persona-only shelf into a multi-kind one — personas, themes, and Dean-curated font packs, all adopted through the same one-click review flow. Installed font packs list on the **Wardrobe** page (v3.1.0), which is also where a pack is uninstalled — refused while a saved theme still references one of its faces; the **theme editor** (`/editor`, v3.2.0) mixes any theme's palette with a vendored-or-installed face and saves the remix as your own station theme. +The station's look is themeable too (v3.0.0–v3.2.0). A theme is one JSON manifest — colour tokens for light and dark plus curated fonts — composed live into CSS for both the Admin UI and the spectator page; pick one via Settings or the switcher on either surface (a cookie-remembered visitor choice outranks the station default). The Community Catalog generalized from a persona-only shelf into a multi-kind one — personas, themes, shows (v3.4.0), and Dean-curated font packs, all adopted through the same one-click review flow. Installed font packs list on the **Wardrobe** page (v3.1.0), which is also where a pack is uninstalled — refused while a saved theme still references one of its faces; the **theme editor** (`/editor`, v3.2.0) mixes any theme's palette with a vendored-or-installed face and saves the remix as your own station theme. ### Resilience & operator tools @@ -77,7 +77,7 @@ The broadcast never depends on a sick dependency. **LLM failure is a mode, not a │ └─ genwave.liq # Liquidsoap playout script ├─ db/ │ ├─ 01-library.sh # library schema + library_svc role (canonical fresh install) -│ └─ 02..34-*-migration.sh # idempotent in-place upgrades, one per shipped feature — +│ └─ 02..36-*-migration.sh # idempotent in-place upgrades, one per shipped feature — │ # each header says what it adds; ./migrate.sh applies them all ├─ icecast/ │ ├─ Dockerfile # self-owned Icecast2 image