{"id":49898410,"url":"https://github.com/pibulus/kpab-fm","last_synced_at":"2026-05-16T01:37:26.256Z","repository":{"id":347458151,"uuid":"1194116999","full_name":"pibulus/kpab-fm","owner":"pibulus","description":"Modular pirate radio web player. Fork it, make your own station.","archived":false,"fork":false,"pushed_at":"2026-04-08T03:26:37.000Z","size":107,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-08T05:21:18.783Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pibulus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-28T00:03:43.000Z","updated_at":"2026-04-08T03:26:40.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/pibulus/kpab-fm","commit_stats":null,"previous_names":["pibulus/kpab-fm"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pibulus/kpab-fm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pibulus%2Fkpab-fm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pibulus%2Fkpab-fm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pibulus%2Fkpab-fm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pibulus%2Fkpab-fm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pibulus","download_url":"https://codeload.github.com/pibulus/kpab-fm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pibulus%2Fkpab-fm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33087028,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-15T20:25:35.270Z","status":"ssl_error","status_checked_at":"2026-05-15T20:25:34.732Z","response_time":103,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-16T01:37:24.950Z","updated_at":"2026-05-16T01:37:26.242Z","avatar_url":"https://github.com/pibulus.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# KPAB.FM — Forkable Pirate Radio Player\n\nA 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.\n\nFork it. Change `js/config.js`. You have a radio station.\n\n## Quick Start\n\n1. **Set up AzuraCast** — self-hosted or cloud. Get your station running and streaming.\n2. **Fork this repo**\n3. **Edit `js/config.js`** — point it at your AzuraCast instance (see Config Reference below)\n4. **Edit `index.html`** — replace the KPAB.FM branding, FAQ copy, and about section with your own\n5. **Edit `offline.html`** — replace the station name and flavor text\n6. **Edit `css/style.css` `:root` block** — swap the color tokens to retheme (see Theming below)\n7. **Serve it** — any static file host works (nginx, Caddy, GitHub Pages, Netlify). HTTPS required for the service worker and PWA features.\n\n## Config Reference\n\nAll station-specific values live in `js/config.js`:\n\n```js\nconst STATION = {\n  name:            // Station display name (used in UI, Media Session, share text)\n  tagline:         // Short tagline shown when no track metadata\n  subtitle:        // Shown in header area\n  url:             // Public URL of your station (used by share feature)\n  streamUrl:       // Direct MP3 stream URL (AzuraCast: /radio.mp3 or /listen/your_mount/radio.mp3)\n  apiUrl:          // AzuraCast now-playing API (e.g. /api/nowplaying/your_station_shortcode)\n  catalogUrl:      // URL to your catalog JSON (see Catalog section below)\n  mutinyEndpoint:  // OPTIONAL — vote-to-skip backend (set to null to hide the feature)\n  msgEndpoint:     // OPTIONAL — listener message drop backend (set to null to hide the feature)\n  pollInterval:    // How often to poll for now-playing data in ms (10000 = 10s is sensible)\n};\n```\n\n### Finding your AzuraCast values\n\n- **streamUrl**: AzuraCast Admin \u003e Station \u003e Mount Points. The default is usually `/radio.mp3`\n- **apiUrl**: `https://your-azuracast-domain/api/nowplaying/your_station_shortcode` — the shortcode is in Station \u003e Profile \u003e URL Stub\n- **catalogUrl**: This is a custom JSON file you generate (see below), not a built-in AzuraCast endpoint\n\n### Optional features (Mutiny \u0026 Messages)\n\n`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 `\u003csection\u003e` blocks from `index.html`.\n\n## Catalog (Song Request Search)\n\nThe request panel lets listeners search and request songs. It needs a JSON file at your `catalogUrl` with this schema:\n\n```json\n[\n  { \"a\": \"Artist Name\", \"t\": \"Track Title\", \"b\": \"Album Name\", \"art\": \"/art/path.jpg\", \"id\": \"azuracast_unique_id\" },\n  { \"a\": \"Another Artist\", \"t\": \"Another Track\", \"b\": \"\", \"art\": null, \"url\": \"/api/station/1/request/abc123\" }\n]\n```\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `a`   | yes      | Artist name |\n| `t`   | yes      | Track title |\n| `b`   | no       | Album name |\n| `art` | no       | Album art URL (absolute or relative) |\n| `id`  | yes*     | AzuraCast unique song ID (used to build request URL) |\n| `url` | yes*     | OR a full request URL path (takes priority over `id`) |\n\n*One of `id` or `url` is required per track.\n\nThe catalog is cached in IndexedDB on the client and refreshed every 6 hours. See `catalog.example.json` for a sample.\n\n### Generating your catalog\n\nAzuraCast doesn't expose a single \"all songs\" endpoint. Common approaches:\n- Export from AzuraCast's media manager and transform with a script\n- Query AzuraCast's API station media endpoints\n- Build a cron job that regenerates the JSON periodically\n\n## Theming\n\nAll 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`.\n\n```css\n:root {\n  --bg: #060608;        /* Page background */\n  --cyan: #00ffea;      /* Primary accent */\n  --magenta: #ff00ff;   /* Secondary accent */\n  --text: #d8d8dc;      /* Body text */\n  --dim: #5a5a66;       /* Muted text */\n  --panel: #0c0c10;     /* Panel backgrounds */\n  --border: #1c1c24;    /* Panel borders */\n  /* ...plus surface, danger, spacing, and size tokens */\n}\n```\n\n## Architecture\n\n```\nindex.html          — markup (edit branding and copy here)\noffline.html        — shown when service worker can't reach the server\nmanifest.json       — PWA manifest (update name, icons, colors)\nsw.js               — service worker (network-first JS/CSS, cache-first icons)\ncss/style.css       — all styles, fully tokenized via :root custom properties\njs/\n  config.js         — single config file (START HERE when forking)\n  utils.js          — shared helpers (fmtTime, fixArtUrl, escHtml)\n  player.js         — core player: streaming, now-playing, progress, history, visualizer\n  request.js        — song catalog search with IndexedDB caching\n  mutiny.js         — vote-to-skip feature (optional, needs backend)\n  messages.js       — listener message drop (optional, needs backend)\n  about.js          — FAQ panel toggle\n  share.js          — Web Share / clipboard share\ndeploy.sh           — deployment script (configure for your server)\n```\n\nAll JS modules are IIFE-wrapped — no globals leak except `STATION` (config) and `shareStation` (share helper).\n\n## Deployment\n\nThe included `deploy.sh` is configured for KPAB's Pi server. The canonical production path is `/home/pibulus/pibulus-os/www/html/kpab`.\n\nTo use it for your setup:\n\n1. Set `PI_HOST` env var to your `user@host`\n2. Update the `DEST` path in the script to your web root\n3. Ensure SSH key auth is configured (no passwords in the script)\n\nLegacy 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.\n\nOr just copy the files to any static host. No build step required.\n\n## Browser Support\n\nWorks in all modern browsers. Key features and their fallbacks:\n- **IndexedDB** (catalog cache): falls back to in-memory array\n- **BroadcastChannel** (cross-tab polling): gracefully ignored if unavailable\n- **Media Session API** (lock screen controls): ignored if unavailable\n- **Service Worker** (offline/caching): site works without it, just no offline support\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpibulus%2Fkpab-fm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpibulus%2Fkpab-fm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpibulus%2Fkpab-fm/lists"}