Selecting an anime tab took long enough that it read as broken. Measured against the two anime fixtures, the cost was three multiplying blocks, none of which was doing useful work. The visibility handshake ran on every page with more than one frame, including pages where no frame had a video at all. Its only purpose is to rank and exclude video candidates, so with nothing to rank it was several seconds of pure waiting per attempt. It is now skipped unless a candidate exists. Its pass count was fixed at four, the worst-case same-origin nesting depth. It now scales to the depth actually observed, which is two on these players, and each surplus pass was a full round trip across every frame. The retry budget was spent waiting for a video that no frame had. Retrying cannot conjure one, and the injected monitor promotes the real player within a fraction of a second of it appearing, so the loop stops instead — and only retries when the sweep itself came back thin, which is the case a second pass can actually fix. Both probe timeouts were also far too generous. inspectMediaFrame and the monitor injection are synchronous DOM work: a live frame answers in tens of milliseconds and anything slower is a frame being torn down, which is exactly what an ad slot is. 2000ms down to 750ms; a frame dropped there is re-probed on the next attempt and reports itself through its monitor anyway. Measured, calm page then heavy ad churn: selection 2.5s / 2.6s (was 2.5s / 7.2s, and ~12s before this series) promotion 0.34s / 2.7s (was 0.35s / 6.4s, and ~15s before this series) The remaining time is the injection chain itself, not discovery. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.jsonis the source manifest. The build script creates browser-specificmanifest.jsonfiles indist/chrome/anddist/firefox/.background.jsis the long-lived coordinator: WebSocket client, room state, host-control authority, heartbeat, reconnects, tab selection, and content-script injection.content.jsruns in the selected video tab. It detects video state, applies remote play/pause/seek, handles episode transitions, and applies local audio processing.popup.htmlandpopup.jsimplement the visible extension UI.extension/shared/is generated bynpm run build:extensionfrom the rootshared/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-onlymode 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, anduk.
Tab Overview
- Room: Select official/custom server, create or join rooms, view peers, share invite links, and manage Host Control when supported by the relay.
- Sync: Select the video tab, send play/pause/seek/force-sync actions, and view episode lobby state.
- Settings: Configure username, title sharing, noise filtering, auto episode sync, notifications, language, and audio options.
- Status: Inspect connection state, latency, video debug info, history, and logs for bug reports.
- Dev: Hidden developer-only controls shown for the
KoalaDevusername.
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 loaddist/chrome. - Firefox: open
about:debugging, choose This Firefox, and loaddist/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.jssynchronous 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.jsas 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 |