Chrome MV3 extension, browser-resident sibling to rangerhq-radio (WP plugin). Plays SomaFM via the chrome.offscreen API + a source- adapter pattern at src/sources/. Architecture highlights: - Audio runs in offscreen document — SW would get killed. - Source-adapter pattern locks Tier 1 contract (RadioSource interface in src/sources/base-source.js). Adding a network = drop a file + register one line in src/sources/index.js. - Vanilla JS, no build step. Pure ES modules. - No telemetry, no third-party JS. Outbound only to somafm.com. - Narrow permissions: offscreen + storage + somafm.com host_perms. No tabs, no <all_urls>, no webRequest. 22 files, ~30 min build following the saved plan at ~/.ranger-memory/projects/rangerhq-tuner-plan.md. Tier 2 + Tier 3 (Web Store submission) not started.
4.8 KiB
Changelog
All notable changes to RangerHQ Tuner are documented here. Format: Keep a Changelog 1.1.0 — versioning: SemVer.
[Unreleased]
Planned — New Tab Page override (Tier 2.5)
- Replace Chrome's default New Tab Page with a RangerHQ-branded version that surfaces the player, current track, and a quick-station picker.
- Adds
chrome_url_overrides.newtabtomanifest.jsonpointing atsrc/newtab/newtab.html. - Reuses the popup's CSS palette + source-adapter pattern — no new architectural concepts.
[0.1.0] — 2026-06-08
Added — Tier 1 MVP (Buddy is alive — er, Tuner is alive)
Buddy's browser cousin lives. First release of RangerHQ Tuner — a Chrome Manifest V3 extension that plays SomaFM internet radio from your toolbar. Sibling to rangerhq-radio (the WordPress version live on wp.org since 2026-06-04). Same brand idea, different surface: WP version lives in admin pages, Chrome version lives one toolbar-click away no matter what you're doing.
Architecture
- Manifest V3 — uses the
chrome.offscreenAPI to host the<audio>element in a hidden document. Service workers can't host audio in MV3 (they get killed when idle), so a one-off offscreen document is the only supported pattern. Working code insrc/offscreen/offscreen.js+src/background/service-worker.js. - Source-adapter pattern at
src/sources/— every radio network is a single file conforming to theRadioSourceinterface inbase-source.js. Adding a new network = drop a new file + register one line insrc/sources/index.js. Popup, SW, and offscreen never know which network is which. - Vanilla JS, no build step — pure ES modules loaded directly. No webpack, no Vite, no
npm install. Same ethos as the RangerHQ WP family (hand-rolled PHP). - No telemetry, no third-party JS — everything is local. Only outbound network calls are to SomaFM's public endpoints (catalogue + stream metadata).
Features
- Toolbar popup showing a searchable SomaFM station list (~150 channels) with artwork, name, and genre.
- Play / Pause / Volume controls. Volume persists across browser restarts.
- Last station picked is remembered — Tuner remembers where you left off.
- Now-playing metadata displayed from SomaFM's per-channel song history endpoint.
- Catalogue cached in
chrome.storage.localfor 6 hours to make popup re-opens instant. - Audio continues after popup closes — the offscreen document owns the playback, popup is just a view.
- RangerHQ helmet icon in the Chrome toolbar (resized from
src/assets/img/ranger.pngto 16/32/48/128 PNGs with a dark#1a221cpadded background that matches the popup palette).
Files (22 created)
rangerhq-tuner/
├── manifest.json
├── README.md
├── CHANGELOG.md
├── .gitignore
└── src/
├── assets/
│ ├── icons/icon-{16,32,48,128}.png (toolbar icons)
│ └── img/ranger.png (master helmet logo, 257×275)
├── background/service-worker.js (message router only)
├── offscreen/offscreen.{html,js} (audio host — the MV3 gotcha solved)
├── popup/popup.{html,css,js} (the toolbar UI)
├── sources/
│ ├── base-source.js (RadioSource interface contract)
│ ├── somafm.js (first concrete adapter)
│ └── index.js (registry)
└── lib/
├── messages.js (type + target constants)
└── playlist-parser.js (.pls parser)
Manifest permissions (narrow on purpose)
"permissions": ["offscreen", "storage"],
"host_permissions": ["https://somafm.com/*", "https://*.somafm.com/*"]
No tabs, no <all_urls>, no webRequest. Smallest permission ask possible = easiest Web Store review.
Architecture / status
- Tier 1 MVP — shipped this commit.
- Tier 2 (planned) — full UX polish, favourites via
chrome.storage.sync, now-playing polling loop,.m3uparser,.crxpackaging, second source adapter stub. - Tier 3 (planned) — Chrome Web Store submission. See
~/.ranger-memory/docs/for the per-family submission checklist; Chrome Web Store specifics tracked in the user's memory underreference_chrome_web_store_rules.
Why this exists
David has Chrome open essentially all day. The WP version of RangerHQ Radio requires going to admin pages to use; the toolbar version is one click away regardless of context. Same code-level effort, dramatically higher daily-use payoff. The "best thing we done so far" verdict on first sound (2026-06-08 evening) confirmed the bet.