feat: rank player candidates by ordered signals, add browser E2E suite

The weighted score summed incomparable units, so size could outvote traits
that disqualify an element outright. Measured on a real page: a display:none
preload reports its full 1080p intrinsic size and scored 2073600, beating a
visible unmuted player at 509920.

Selection now compares an ordered list of signals, highest priority first:
has a source, is rendered, is not a silent background loop, rendered size
bucket, is playing, has controls, duration. Rendered size replaces intrinsic
resolution, and mute state is gone from the ranking entirely: it is a viewer
preference, not evidence about which element is the player.

It stays a ranking rather than a filter, so a page of only bad candidates
still yields one and findVideo never returns null where a video exists.

The new tests/e2e suite runs the shipped finder against real fixture pages
and drives the packed extension for injection, reinjection and remote
play/pause/seek into a first-party frame. All five scoring scenarios fail
against the previous implementation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
KoalaDev
2026-08-14 07:23:12 +02:00
parent 79a2204a97
commit 36e1291d2c
30 changed files with 781 additions and 29 deletions
+5
View File
@@ -11,6 +11,11 @@ All notable changes to the KoalaSync browser extension and relay server.
- **Extension: Editable Hide-Clutter list** — Adds a validated, deduplicated domain editor in Settings, prefilled with the shipped blacklist, with a defaults reset and per-device persistence in `chrome.storage.local`. The editor groups entries into your own and the shipped defaults, and only your changes are stored, so domains added to the shipped list in later versions still reach you without overriding what you removed or added. Lists saved by an earlier version are migrated automatically.
- **Extension: Independent default audio boost** — Adds a configurable `020 dB` output gain in half-decibel steps. The boost works with or without the compressor and applies live to the selected video tab.
- **Testing: Browser E2E smoke suite** — Adds a local Playwright suite (`npm run test:e2e`) that runs the shipped video finder against real fixture pages and drives the packed extension end to end: injection into the target tab, reinjection after navigation, and remote play, pause and seek applied to a player inside a first-party frame. Runs as its own CI job so `npm run verify` stays browser-free.
### Changed
- **Extension: Rebuilt player selection** — Replaces the weighted score with an ordered list of signals, so a video that cannot be the player (no source, not rendered) is never picked just for being large. Rendered size now decides instead of intrinsic resolution, a video that is actually playing wins between equally sized players, silent looping background videos are demoted, and mute state no longer influences the choice at all.
### Fixed
- **Extension: Google Drive tab selection** — A broad parent domain in the Hide-Clutter list no longer hides a host that has its own supported player path, so Drive videos stay selectable while the filter is on. An exact entry for the host itself still filters it.
- **Extension: Debug report frame visibility** — Video counts now include players inside same-origin frames and the report states whether the selected video sits in a frame.
+5 -6
View File
@@ -57,13 +57,12 @@
- **Possible approach:** Add an opt-in frame bridge (`allFrames: true` injection) where child frames announce detected videos to the top frame, and the top frame routes remote play/pause/seek commands to the active child video. Needs a frame-election rule so ad frames cannot claim the session.
- **Status:** Same-origin part completed; cross-origin frame bridge still open. Not needed for current Emby behavior.
### Local extension E2E smoke tests
### Sync a second video source per room
- **Priority:** P2
- **Category:** Testing / Release Confidence
- **Background:** The release verification covers unit tests, server integration, syntax, lint, audits, and builds, but it does not currently run a real browser extension flow. A small local E2E smoke suite would catch regressions in content-script injection, tab navigation reinjection, remote seek handling, and iframe player support.
- **Possible approach:** Add a separate local-only Playwright smoke command that loads the unpacked extension, opens two controlled video pages, and verifies play/pause/seek through the actual extension path. Keep it outside `npm run verify` until it is stable enough for CI.
- **Status:** Backlog, recommended before larger content-script or frame-bridge changes.
- **Priority:** P3
- **Category:** Compatibility / Player Selection
- **Background:** Detection picks exactly one `<video>` per tab. Pages that legitimately show two players side by side (a lecture feed plus slides, a multi-camera stream) can only ever sync one of them.
- **Status:** Backlog, no demand yet. Listed so the single-player assumption in the ranking is a recorded decision rather than an accident.
---