feat(providers): add nine catalogues and the Radio Browser directory
This commit is contained in:
1 parent
a3ad693132
commit
49f7efe0d2
27 files changed
+1695
-22
No files matched your search
@@ -7,11 +7,17 @@ song history, and full desktop media integration, drawn with your terminal's
|
||||
own ANSI palette on the terminal's default background so it fits any theme
|
||||
(including transparent terminals).
|
||||
|
||||
The station catalogue is pluggable. Beefy Player ships with
|
||||
**[SomaFM](https://somafm.com)** (≈50 curated channels),
|
||||
**[tilderadio](https://tilderadio.org)** (the tildeverse's single community
|
||||
stream) and **[Bassdrive](https://bassdrive.com)** (worldwide drum & bass), and
|
||||
the UI never talks to a station catalogue directly: it asks a
|
||||
The station catalogue is pluggable. Beefy Player ships with thirteen catalogues
|
||||
— **[SomaFM](https://somafm.com)** (≈50 curated channels),
|
||||
**[Radio Paradise](https://radioparadise.com)** (five mixes), the community
|
||||
stations **[tilderadio](https://tilderadio.org)**,
|
||||
**[Bassdrive](https://bassdrive.com)**, **[dublab](https://dublab.com)**,
|
||||
**[Rinse FM](https://rinse.fm)**, **[Refuge Worldwide](https://refugeworldwide.com)**,
|
||||
**[LYL Radio](https://lyl.live)**, **[The Lot Radio](https://thelotradio.com)**,
|
||||
**[Cashmere Radio](https://cashmereradio.com)**,
|
||||
**[Datafruits](https://datafruits.fm)** and **[aNONradio](https://anonradio.net)**,
|
||||
plus the **[Radio Browser](https://www.radio-browser.info)** directory
|
||||
(300 stations) — and the UI never talks to a station catalogue directly: it asks a
|
||||
[provider](#providers) for stations, song history and stream URLs. Press `p` to
|
||||
switch catalogue without restarting. Adding another internet-radio catalogue is
|
||||
a self-contained module, not a rewrite.
|
||||
@@ -55,7 +61,9 @@ implemented here from public endpoints and open protocols.
|
||||
- **Last played** — the full recent history, newest first.
|
||||
- **Every station** — with SomaFM that is the whole `channels.json` roster
|
||||
(≈50 channels), live listener counts and genre search; tilderadio is a
|
||||
single-station catalogue, and the list simply holds one.
|
||||
single-station catalogue, and the list simply holds one. Long lists get a grey
|
||||
thumb down the right edge (no rail) and a `12/51` position in the pane title;
|
||||
`pgup`/`pgdn` move a screen at a time.
|
||||
- **Favourites** that float to the top, remembered between runs.
|
||||
- **Pluggable catalogues** — one `providers` module per radio network, with a
|
||||
`p` picker in the UI, `--provider` on the command line, and the choice
|
||||
@@ -197,23 +205,46 @@ layout and the guessed icecast mirrors all live in
|
||||
`beefy_player/providers/somafm/`. Nothing outside that package imports it; the
|
||||
app only ever holds a `RadioProvider`.
|
||||
|
||||
Three catalogues ship today:
|
||||
Thirteen catalogues ship today:
|
||||
|
||||
| slug | catalogue | station list | history | streams |
|
||||
| slug | catalogue | stations | what is on | relays |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `somafm` | [SomaFM](https://somafm.com) | `channels.json` (≈50) | `songs/<station>.json` | `.pls` → icecast mirrors |
|
||||
| `tilderadio` | [tilderadio](https://tilderadio.org) | `/api/now/` (1) | `now_playing` + `history[]` | AzuraCast mounts (mp3/ogg, 320k) |
|
||||
| `bassdrive` | [Bassdrive](https://bassdrive.com) | icecast status (1) | rolling `display-title` | three mounts + mirrors |
|
||||
| `radioparadise` | [Radio Paradise](https://radioparadise.com) | five mixes | `api/now_playing` (artist, album, cover) | FLAC / AAC / MP3 icecast |
|
||||
| `tilderadio` | [tilderadio](https://tilderadio.org) | 1 + schedule | `/api/now/` | AzuraCast mounts |
|
||||
| `bassdrive` | [Bassdrive](https://bassdrive.com) | 1 + schedule | icecast `display-title` (the show) | three mounts + mirrors |
|
||||
| `dublab` | [dublab](https://dublab.com) | 1 + schedule | dublab's calendar | Airtime mp3 |
|
||||
| `rinse` | [Rinse FM](https://rinse.fm) | 3 | — | proxy mounts (aac+) |
|
||||
| `refuge` | [Refuge Worldwide](https://refugeworldwide.com) | 1 | `public.radio.co` status | radio.co mp3 |
|
||||
| `lyl` | [LYL Radio](https://lyl.live) | 1 | — | icecast mp3 |
|
||||
| `lot` | [The Lot Radio](https://thelotradio.com) | 1 | — | HLS |
|
||||
| `cashmere` | [Cashmere Radio](https://cashmereradio.com) | 1 | — | Airtime ogg/mp3 |
|
||||
| `datafruits` | [Datafruits](https://datafruits.fm) | 1 | streampusher icecast | relay mp3 |
|
||||
| `anonradio` | [aNONradio](https://anonradio.net) | 1 | icecast title | icecast mp3 |
|
||||
| `radiobrowser` | [Radio Browser](https://www.radio-browser.info) | 300 (directory) | — | whatever each station publishes |
|
||||
|
||||
They are deliberately different shapes: fifty channels with PLS playlists, a
|
||||
single AzuraCast stream that carries its own history, and an Icecast relay whose
|
||||
"now playing" is the *show* rather than the track. That is the seam working.
|
||||
|
||||
The single-stream catalogues also use the optional capabilities: their left
|
||||
pane is the broadcast schedule rather than a list containing one station, and
|
||||
they opt out of Bandcamp lookups. Bassdrive is the extreme case — Icecast
|
||||
reports one title and keeps no history, so the provider maps the title to
|
||||
`Station.dj`/`presenter` and keeps a rolling record of the shows it has heard.
|
||||
The single-stream catalogues also use the optional capabilities: where a
|
||||
schedule exists (`tilderadio`, `bassdrive`, `dublab`) the left pane is that
|
||||
schedule rather than a list containing one station, and none of them do
|
||||
Bandcamp lookups. Bassdrive is the extreme case — Icecast reports one title and
|
||||
keeps no history, so the provider maps the title to `Station.dj`/`presenter`
|
||||
and keeps a rolling record of the shows it has heard.
|
||||
|
||||
The community stations share one base class,
|
||||
`providers/community/base.py`, which knows how to read an Icecast
|
||||
`status-json.xsl`, a `public.radio.co` status, a scheduled show, or nothing at
|
||||
all; each station is then ten lines of data (relays, wordmark, tagline). Where
|
||||
a relay publishes no metadata (Rinse, LYL, The Lot, Cashmere) the app simply
|
||||
plays it and says so, rather than inventing a track.
|
||||
|
||||
`radiobrowser` is the directory case: three hundred of the most-clicked working
|
||||
stations from the community database, keyless and public-domain, with no
|
||||
per-station history at all — breadth rather than depth, and the one catalogue
|
||||
where ON AIR legitimately has nothing to say.
|
||||
|
||||
### Header wordmarks
|
||||
|
||||
@@ -306,6 +337,7 @@ The UI wants roughly **84×24**; it also works smaller, just less pretty.
|
||||
| key | action |
|
||||
| -------------- | --------------------------------------------- |
|
||||
| `↑` / `↓`, `j` / `k` | move through stations |
|
||||
| `pgup` / `pgdn` | page through stations |
|
||||
| `enter` | tune in to the selected station |
|
||||
| `space` | play / pause |
|
||||
| `s` | stop |
|
||||
@@ -363,8 +395,11 @@ beefy_player/
|
||||
base.py RadioProvider interface + HTTP/playlist toolkit
|
||||
wordmark.py the half-block font every hero is drawn with
|
||||
somafm/ the SomaFM catalogue (API, hero, bundled fallback list)
|
||||
radiobrowser/ the community directory (300 stations, no metadata)
|
||||
radioparadise/ five curated mixes with real track metadata
|
||||
tilderadio/ the tilderadio catalogue (one station, hero, schedule)
|
||||
bassdrive/ Bassdrive (Icecast status, show schedule, rolling history)
|
||||
community/ one module per community station, on a shared base
|
||||
player.py mpv over a Unix-socket JSON IPC channel
|
||||
spectrum.py analyser (parec / Core Audio tap / ffmpeg / sim)
|
||||
macos_tap.py macOS output capture (ctypes + Core Audio)
|
||||
@@ -404,6 +439,10 @@ tools/
|
||||
values. A memoised fetch and a lock keep a cold start to one homepage
|
||||
download; the display-title's show is matched against the running slot for
|
||||
"live from <city>".
|
||||
- `beefy_player/providers/community/` — the community stations: `base.py` reads
|
||||
Icecast or radio.co status, keeps the rolling history and turns a running
|
||||
schedule slot into "what is on"; each station module is data. `rinse.py`
|
||||
shows the multi-station case and `dublab.py` the schedule case.
|
||||
- `beefy_player/providers/wordmark.py` — the half-block capitals behind every
|
||||
hero, with per-character style spans.
|
||||
- `beefy_player/widgets/schedule.py` — the left pane for single-stream
|
||||
|
||||
Reference in new issue
Block a user