Files
KoalaSync/extension
Timo 096775d39f fix(extension): make anime-style nested players selectable again
Reproduced against the live yummyanime.tv layout, which is:

  top (no video)
  ├── visible same-origin wrapper 830x498 -> cross-origin player
  ├── hidden same-origin wrapper    0x0   -> cross-origin mirror
  └── hidden cross-origin trailer   0x0

Three things kept that page from ever settling on a target.

Equally-ranked players were a hard failure. Several mirrors or dubs loaded at
once is an ordinary layout for these sites, and refusing to activate made them
unusable. The resolver now holds the top frame and waits for one of them to
start playing, which is the signal that breaks the tie.

Inconclusive probes moved the target. A page whose players are still loading
resolves differently from one call to the next, and every difference triggered
a full teardown and reinjection, so activation never finished — the popup sat
on "activating" with nothing in the log. A probe that finds no video now leaves
the target where it is.

The visibility handshake expired mid-probe. Its listener lived 1000ms while the
probe sequence is six separate executeScript round trips; on a heavy page it
was gone before the answer arrived, leaving every frame's visibility unknown —
the exact state that makes two players look equal. It now outlives the sequence.

A settled failure also no longer reports itself as "activating".

Covered by two fixtures built from the real page: one where the player exists
up front, and one where the host only creates it on play, asserting the target
is promoted into the deep cross-origin frame without touching the popup again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 00:47:29 +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