feat: initial commit — RangerHQ Tuner v0.1.0 (Tier 1 MVP)
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.
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
// RangerHQ Tuner — Service Worker.
|
||||
// Job: open the offscreen audio document on demand and route messages
|
||||
// between the popup (UI) and the offscreen document (audio engine).
|
||||
// We hold no state here — Chrome will kill this worker at any time.
|
||||
|
||||
const OFFSCREEN_PATH = 'src/offscreen/offscreen.html';
|
||||
|
||||
async function ensureOffscreen() {
|
||||
// hasDocument is the official MV3 way to check. Optional-chained
|
||||
// for older Chrome safety (we still require 116+ via the manifest).
|
||||
const exists = await chrome.offscreen.hasDocument?.();
|
||||
if (exists) return;
|
||||
await chrome.offscreen.createDocument({
|
||||
url: OFFSCREEN_PATH,
|
||||
reasons: ['AUDIO_PLAYBACK'],
|
||||
justification: 'Persistent audio playback for internet radio streams.',
|
||||
});
|
||||
}
|
||||
|
||||
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
||||
// Only react to messages targeted at the service worker.
|
||||
if (msg.target !== 'sw') return;
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
await ensureOffscreen();
|
||||
// Re-route the message to the offscreen document.
|
||||
const response = await chrome.runtime.sendMessage({
|
||||
...msg,
|
||||
target: 'offscreen',
|
||||
});
|
||||
sendResponse(response);
|
||||
} catch (err) {
|
||||
sendResponse({ ok: false, error: err.message });
|
||||
}
|
||||
})();
|
||||
|
||||
return true; // keep the channel open for async sendResponse
|
||||
});
|
||||
Reference in New Issue
Block a user