Files
KoalaSync/extension
KoalaDev cb84709358 fix(popup): render lobby peer names as text, not markup
Peer usernames are remote-controlled and were interpolated into an
innerHTML string in updateLobbyUI. The server only truncates them to 30
chars, so a peer could inject markup into everyone else's popup: enough
to load a remote image (leaking viewer IPs) or spoof readiness badges.
Inline handlers were already blocked by the MV3 default CSP.

Build the peer items with the DOM API, matching the pattern the sibling
peer list already uses.

Add the two checks that would have caught this before upload:
- eslint no-unsanitized, which reproduces the AMO warning at lint time
- addons-linter on the built XPI in verify-release, with
  --warnings-as-errors since it exits 0 on warnings and AMO rejects them

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 05:57:38 +02:00
..
2026-06-04 15:33:06 +02:00

KoalaSync Browser Extension

This directory contains the Manifest V3 browser extension for Chrome and Firefox. It owns the popup UI, background service worker, content-script video control, invitation bridge, audio processing, and all browser-local settings.

Where You Are

  • manifest.base.json is the source manifest. The build script creates browser-specific manifest.json files in dist/chrome/ and dist/firefox/.
  • background.js is the long-lived coordinator: WebSocket client, room state, host-control authority, heartbeat, reconnects, tab selection, and content-script injection.
  • content.js runs in the selected video tab. It detects video state, applies remote play/pause/seek, handles episode transitions, and applies local audio processing.
  • popup.html and popup.js implement the visible extension UI.
  • extension/shared/ is generated by npm run build:extension from the root shared/ directory. Do not edit it directly.

Key Features

  • Manifest V3: Service-worker architecture with session persistence and explicit keep-alive handling.
  • Pure Vanilla JS: No extension runtime dependencies and no bundler inside extension/.
  • On-Demand Connection: The service worker connects only while the user intends to be in a room.
  • Host Control & Co-Hosts: Hosts can switch a room into host-only mode and grant controller rights to trusted peers.
  • Episode Auto-Sync: Title/episode changes can open a lobby so peers resume together once everyone is ready.
  • Smart Matching & Title Privacy: Matching video tabs are highlighted, while tab/media title sharing can be reduced or disabled.
  • Audio Processing: Optional local compressor settings live in the dedicated audio options page.
  • Status Diagnostics: The Status tab exposes connection state, ping, video debug data, action history, and copyable logs.
  • Dynamic i18n: 15 languages are supported: en, de, fr, es, it, nl, pl, pt, pt-BR, tr, ru, ja, ko, zh, and uk.

Tab Overview

  1. Room: Select official/custom server, create or join rooms, view peers, share invite links, and manage Host Control when supported by the relay.
  2. Sync: Select the video tab, send play/pause/seek/force-sync actions, and view episode lobby state.
  3. Settings: Configure username, title sharing, noise filtering, auto episode sync, notifications, language, and audio options.
  4. Status: Inspect connection state, latency, video debug info, history, and logs for bug reports.
  5. Dev: Hidden developer-only controls shown for the KoalaDev username.

Privacy & Permissions

KoalaSync requires <all_urls> host permission so it can detect and control <video> elements on arbitrary sites.

  • No browsing history is collected or uploaded.
  • Room credentials and user settings are stored locally with chrome.storage.
  • No analytics, external scripts, external fonts, or tracking libraries are used by the extension.
  • Audio processing is local to the selected tab.
  • Title privacy controls decide whether tab/media titles are shared with room peers.

Installation

From the repository root:

npm install
npm run build:extension

Then load the generated bundle:

  • Chrome/Chromium: open chrome://extensions/, enable Developer Mode, and load dist/chrome.
  • Firefox: open about:debugging, choose This Firefox, and load dist/firefox/manifest.json.

Development

Run the build whenever shared protocol files or extension packaging inputs change:

npm run build:extension

The build copies shared/constants.js, shared/blacklist.js, shared/names.js, and shared/README.md into extension/shared/, injects synchronous constants into content.js, generates browser manifests, and creates zip artifacts in dist/.

Useful focused checks from the repository root:

node -c extension/background.js
node -c extension/content.js
node -c extension/popup.js
node scripts/test-episode-utils.mjs
node scripts/test-title-privacy.mjs
node scripts/test-audio-settings.mjs
node scripts/test-locales.cjs

For the full suite, run:

npm run verify

Do Not Break

  • Keep content.js synchronous and IIFE-based; it cannot import ES modules directly.
  • Keep the injection markers used by scripts/build-extension.cjs.
  • Keep protocol names in shared/constants.js as the source of truth.
  • Keep extension runtime dependencies at zero unless the project explicitly decides to introduce a bundler.
  • Keep all extension assets self-hosted.

Module Structure

File Purpose
background.js Service worker: WebSocket protocol, room state, host control, tab/content routing, reconnects
content.js Video detection/control, audio processing, episode transition, host-only guest behavior
popup.js Popup UI: room join/create, tabs, settings, peer list, status, diagnostics
popup.html Popup markup, tabs, onboarding, status/debug surfaces
bridge.js Invitation bridge injected into sync.koalastuff.net
episode-utils.js Shared episode-title parser imported by background and injected into content at build time
title-privacy.js Tab/media title privacy modes and sanitization helpers
audio-options.html / audio-options.js / audio-options.css Dedicated local audio-processing settings page
page-api-seek-overrides.js Page-level seek bridge for site-specific player APIs
modules/tab-manager.js Tab lifecycle helper used by the background service worker
i18n.js Dynamic locale loader and DOM translation helper
locales/ Runtime popup translations
_locales/ Browser-store manifest translations
shared/ Generated mirror of root shared constants, blacklist, names, and README