https://github.com/pibulus/kpab-fm
Modular pirate radio web player. Fork it, make your own station.
https://github.com/pibulus/kpab-fm
Last synced: about 1 month ago
JSON representation
Modular pirate radio web player. Fork it, make your own station.
- Host: GitHub
- URL: https://github.com/pibulus/kpab-fm
- Owner: pibulus
- Created: 2026-03-28T00:03:43.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-04-08T03:26:37.000Z (3 months ago)
- Last Synced: 2026-04-08T05:21:18.783Z (3 months ago)
- Language: HTML
- Size: 104 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# KPAB.FM — Forkable Pirate Radio Player
A modular web player for internet radio stations running [AzuraCast](https://azuracast.com/). No build tools, no frameworks, no dependencies — just static files you can host anywhere.
Fork it. Change `js/config.js`. You have a radio station.
## Quick Start
1. **Set up AzuraCast** — self-hosted or cloud. Get your station running and streaming.
2. **Fork this repo**
3. **Edit `js/config.js`** — point it at your AzuraCast instance (see Config Reference below)
4. **Edit `index.html`** — replace the KPAB.FM branding, FAQ copy, and about section with your own
5. **Edit `offline.html`** — replace the station name and flavor text
6. **Edit `css/style.css` `:root` block** — swap the color tokens to retheme (see Theming below)
7. **Serve it** — any static file host works (nginx, Caddy, GitHub Pages, Netlify). HTTPS required for the service worker and PWA features.
## Config Reference
All station-specific values live in `js/config.js`:
```js
const STATION = {
name: // Station display name (used in UI, Media Session, share text)
tagline: // Short tagline shown when no track metadata
subtitle: // Shown in header area
url: // Public URL of your station (used by share feature)
streamUrl: // Direct MP3 stream URL (AzuraCast: /radio.mp3 or /listen/your_mount/radio.mp3)
apiUrl: // AzuraCast now-playing API (e.g. /api/nowplaying/your_station_shortcode)
catalogUrl: // URL to your catalog JSON (see Catalog section below)
mutinyEndpoint: // OPTIONAL — vote-to-skip backend (set to null to hide the feature)
msgEndpoint: // OPTIONAL — listener message drop backend (set to null to hide the feature)
pollInterval: // How often to poll for now-playing data in ms (10000 = 10s is sensible)
};
```
### Finding your AzuraCast values
- **streamUrl**: AzuraCast Admin > Station > Mount Points. The default is usually `/radio.mp3`
- **apiUrl**: `https://your-azuracast-domain/api/nowplaying/your_station_shortcode` — the shortcode is in Station > Profile > URL Stub
- **catalogUrl**: This is a custom JSON file you generate (see below), not a built-in AzuraCast endpoint
### Optional features (Mutiny & Messages)
`mutinyEndpoint` and `msgEndpoint` are **not** AzuraCast routes — they're custom microservices. If you don't have these backends, the buttons still appear but will show a network error. To properly disable them, set the values to `null` in config and remove the corresponding `` blocks from `index.html`.
## Catalog (Song Request Search)
The request panel lets listeners search and request songs. It needs a JSON file at your `catalogUrl` with this schema:
```json
[
{ "a": "Artist Name", "t": "Track Title", "b": "Album Name", "art": "/art/path.jpg", "id": "azuracast_unique_id" },
{ "a": "Another Artist", "t": "Another Track", "b": "", "art": null, "url": "/api/station/1/request/abc123" }
]
```
| Field | Required | Description |
|-------|----------|-------------|
| `a` | yes | Artist name |
| `t` | yes | Track title |
| `b` | no | Album name |
| `art` | no | Album art URL (absolute or relative) |
| `id` | yes* | AzuraCast unique song ID (used to build request URL) |
| `url` | yes* | OR a full request URL path (takes priority over `id`) |
*One of `id` or `url` is required per track.
The catalog is cached in IndexedDB on the client and refreshed every 6 hours. See `catalog.example.json` for a sample.
### Generating your catalog
AzuraCast doesn't expose a single "all songs" endpoint. Common approaches:
- Export from AzuraCast's media manager and transform with a script
- Query AzuraCast's API station media endpoints
- Build a cron job that regenerates the JSON periodically
## Theming
All colors, spacing, and component sizes are CSS custom properties in the `:root` block of `css/style.css`. Swap these to retheme — zero hardcoded values exist outside `:root`.
```css
:root {
--bg: #060608; /* Page background */
--cyan: #00ffea; /* Primary accent */
--magenta: #ff00ff; /* Secondary accent */
--text: #d8d8dc; /* Body text */
--dim: #5a5a66; /* Muted text */
--panel: #0c0c10; /* Panel backgrounds */
--border: #1c1c24; /* Panel borders */
/* ...plus surface, danger, spacing, and size tokens */
}
```
## Architecture
```
index.html — markup (edit branding and copy here)
offline.html — shown when service worker can't reach the server
manifest.json — PWA manifest (update name, icons, colors)
sw.js — service worker (network-first JS/CSS, cache-first icons)
css/style.css — all styles, fully tokenized via :root custom properties
js/
config.js — single config file (START HERE when forking)
utils.js — shared helpers (fmtTime, fixArtUrl, escHtml)
player.js — core player: streaming, now-playing, progress, history, visualizer
request.js — song catalog search with IndexedDB caching
mutiny.js — vote-to-skip feature (optional, needs backend)
messages.js — listener message drop (optional, needs backend)
about.js — FAQ panel toggle
share.js — Web Share / clipboard share
deploy.sh — deployment script (configure for your server)
```
All JS modules are IIFE-wrapped — no globals leak except `STATION` (config) and `shareStation` (share helper).
## Deployment
The included `deploy.sh` is configured for KPAB's Pi server. The canonical production path is `/home/pibulus/pibulus-os/www/html/kpab`.
To use it for your setup:
1. Set `PI_HOST` env var to your `user@host`
2. Update the `DEST` path in the script to your web root
3. Ensure SSH key auth is configured (no passwords in the script)
Legacy note: an older passport-drive path existed during Pi migration work. Do not use it as a second live copy. Keep one live path and use git or timestamped backups for rollback.
Or just copy the files to any static host. No build step required.
## Browser Support
Works in all modern browsers. Key features and their fallbacks:
- **IndexedDB** (catalog cache): falls back to in-memory array
- **BroadcastChannel** (cross-tab polling): gracefully ignored if unavailable
- **Media Session API** (lock screen controls): ignored if unavailable
- **Service Worker** (offline/caching): site works without it, just no offline support
## License
MIT