625 Commits

Author SHA1 Message Date
Timo 1b7be23b29 Document v2.5.2 release v2.5.2 2026-07-02 15:33:47 +02:00
KoalaDev 9ec0e9dd4e Merge pull request #19 from Shik3i/codex/netflix-seek-fix
[codex] Fix Netflix and Disney+ seek handling
2026-07-02 15:29:55 +02:00
Timo 9ac8c28442 Remove Disney+ DOM scraping fallback 2026-07-02 15:08:54 +02:00
Timo 076157fef1 Sync Disney+ via the page media player API (precise time + seek)
Disney+'s <video> is blob-relative (unusable as an absolute clock) and its
scrubber aria-value freezes during playback, so DOM scraping lagged and the
+/-10s button seek could neither reach far targets nor land precisely. The
real player hangs off the <disney-web-player> custom element as
`.mediaPlayer`, exposing seek(ms) and timeline.info (playhead/duration ms).

Since the isolated content world can't read that page object, route it
through the existing MAIN-world page-API bridge (as Netflix already does):

- page-api-seek-overrides.js: register a 'disney' provider.
- background.js installPageApiSeekBridge: seek Disney via mediaPlayer.seek(),
  and post the exact playhead/duration (seconds) to the content world every
  250ms. Both are gated on provider === 'disney'; Netflix path unchanged.
- content.js: cache the pushed playhead, prefer it in getDisneyPlusTimeline
  (DOM scraping stays as fallback), and check the page-API seek first in
  seekVideo. Outcome is identical for Netflix and generic sites.

Verified live on Disney+: reported time matches the player exactly and
seek lands within ~1s of the target.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 14:56:02 +02:00
Timo 236da46f5d Lift the 120s cap on Disney+ relative-seek so large seeks reach target
Disney+ has no absolute seek on its blob <video>, so absolute seeks are
translated into repeated clicks of the player's relative skip button. The
click count was capped at 12 (=120s at 10s/step), so any seek further than
two minutes away silently landed short — breaking absolute-position sync
(e.g. syncing to 5:00 from far away never arrived).

Derive the step size from the matched button's own label (10s default,
some UIs use 5/15/30) and issue enough clicks to cover the full delta,
bounded at a sane maximum.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 14:45:12 +02:00
Timo 2fbcbc4f83 Harden Disney+ time fallback against <video> element recreation
When the control overlay (and its live time readout) is briefly absent,
the old fallback recomputed the timeline from the raw blob-relative
video.currentTime via a cached scale/start. Disney recreates the <video>
element on some play/pause transitions, which resets currentTime, so that
math produced a wildly wrong time ("loses the time" after a pause).

The native clock advances 1:1 with real playback, so instead anchor the
last live UI position to video.currentTime and extrapolate by the elapsed
native delta. If the delta is negative or implausibly large (element
recreated / seek), freeze at the last known position rather than emitting
a garbage time.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 14:38:26 +02:00
Timo 8fe1c6dfbc Fix laggy Disney+ time by preferring the live "time remaining" indicator
Disney+ throttles the scrubber slider's aria-valuenow, so it can lag real
playback by several seconds (and its value snaps back when the control
overlay reappears on pause). The player's "time remaining" indicator,
however, updates live.

getDisneyPlusUiTimeline() now captures any element whose class/testid
mentions "remain", parses its clock text, and — when a reliable duration
is known — derives current = duration - remaining and prefers it over the
laggy slider value. Falls back to the previous behavior when no remaining
indicator is present.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 14:26:53 +02:00
Timo 51da169d69 Remove temporary Media Session interceptor and Video Event Log diagnostics
Clean up the exploratory Disney+ diagnostics now that the Shadow DOM
timeline/seek integration is in place:

- Remove Proposal 1 (Media Session interceptor): the background.js
  interceptor injection and the content.js message listener capturing
  __koalaMediaSessionCapture, plus the now-unused mediaSessionPosition
  reporting in content.js and popup.js.
- Remove Proposal 3 (Video Event Log): videoEventsLog, logVideoEvent(),
  the per-video event logging listeners, and the popup.html/popup.js UI.
- Keep Proposal 2 (DOM timestamp scraper) for ongoing diagnostics.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 14:18:50 +02:00
Timo a9f5c0b9bf TEMPORARY DIAGNOSTICS: Integrate querySelectorAllShadow in Disney+ specific functions 2026-07-02 13:45:36 +02:00
Timo 705fbc146b TEMPORARY DIAGNOSTICS: Upgrade DOM scraper to support Shadow DOM recursion 2026-07-02 13:42:25 +02:00
Timo 09d35f3e48 TEMPORARY DIAGNOSTICS: Implement Proposal 2 and 3 logs in Dev tools tab 2026-07-02 13:35:08 +02:00
Timo 32994aaaa5 Support dynamic Disney+ timeline offset/scale caching for accurate seek sync 2026-07-02 13:30:20 +02:00
Timo bea0f6925c Implement cached duration fallback and simulate keyboard events fallback for Disney+ seeks when controls are hidden 2026-07-02 13:27:53 +02:00
Timo 71fa6e7315 Support absolute seeks on Disney+ by automatically translating them to relative jumps 2026-07-02 13:25:11 +02:00
Timo 54b806d270 Fix Media Session listener scoping by moving it to root IIFE level in content.js 2026-07-02 13:23:14 +02:00
Timo 066d2c9407 Implement temporary Media Session interceptor diagnostics for Disney+ and restore Netflix sessionId lookup guard 2026-07-02 13:19:47 +02:00
Timo ce522e2ab7 Safeguard Netflix player session ID lookup in background.js 2026-07-02 13:01:14 +02:00
Timo 9cbeb661d6 Save baseline state with Disney+ seek adjustments and build identifier 2026-07-02 13:00:41 +02:00
Timo beda924b65 Fix DEV_SIMULATE_REMOTE_SEEK targetTime routing in background.js and add build identifier 2026-07-02 12:57:58 +02:00
KoalaDev 01762b0c2f Normalize shared tab titles 2026-07-02 10:20:25 +02:00
KoalaDev 0af22998c8 Handle target tab navigation reinjection 2026-07-02 10:02:31 +02:00
KoalaDev 52265e84eb Generalize page API seek overrides 2026-07-02 09:57:57 +02:00
KoalaDev 57cd071d58 Add hidden remote seek test controls 2026-07-02 09:50:39 +02:00
KoalaDev 8a21fbe07f Fix Netflix seek handling 2026-07-02 09:43:11 +02:00
KoalaDev 7781d418ba Merge pull request #17 from Shik3i/feat/protocol-rate-limit-vitest
feat: Protocol spec, rate limiting, vitest, and documentation
2026-07-02 00:17:01 +02:00
Timo c022f6f490 fix: harden leave room rate limiting 2026-07-02 00:14:55 +02:00
Timo 9fe83f89b2 fix: make protocol docs match implementation 2026-07-02 00:04:49 +02:00
Timo e51e8ae436 fix: move relay changelog notes to v2.5.1 2026-07-01 23:55:42 +02:00
Timo e74abd00f7 fix: keep linux optional deps in lockfile 2026-07-01 23:51:52 +02:00
Timo dab7368537 fix: repair PR verification and docs cleanup 2026-07-01 23:46:23 +02:00
Skrockle 463f871958 feat: Add protocol spec, rate limiting, vitest framework, and documentation
## Added
- **WebSocket Protocol Specification** (docs/PROTOCOL.md) - Complete reference
  for all 20+ events with payload schemas, rate limits, and edge cases
- **LEAVE_ROOM Rate Limiting** - 10 requests/socket/minute to prevent abuse
- **Vitest Testing Framework** - Modern test setup with coverage reporting
- **Host Control Mode Documentation** - Consolidated EN documentation
  (docs/host-control-mode.md) with references to internal implementation

## Changed
- **Graceful Shutdown** - Socket.IO clients properly disconnected during
  server shutdown (server/index.js)
- **CI Workflow** - Added test step with continue-on-error for gradual rollout
- **README** - Added protocol documentation link
- **CHANGELOG** - Updated with all new features and improvements

## Moved
- Internal documentation moved to docs/internal/ for better organization
- Host Control Mode docs consolidated from 4 files to 1 comprehensive guide

## Technical Details
- Protocol spec: 495 lines, covers all events from shared/constants.js
- Rate limiter: Follows existing pattern (checkAuthRate, checkEventRate)
- Vitest: 6 tests for rate limiter, all passing
- Documentation: Host Control Mode doc includes edge cases, testing checklist,
  architecture decisions
2026-07-01 23:27:30 +02:00
GitHub Action 1f5196e1e6 chore(release): update versions to v2.5.1 [skip ci] 2026-07-01 17:48:39 +00:00
Timo 003741a63f docs: add devops.md detailing release workflow v2.5.1 2026-07-01 19:47:31 +02:00
KoalaDev e644ab33cd Merge pull request #15 from Shik3i/codex/issue-13-title-privacy
feat(extension): add title privacy controls and settings
2026-07-01 19:43:46 +02:00
Timo 9006ebbc67 docs: remove temporary branch planning document 2026-07-01 19:40:57 +02:00
Timo e40017f053 Move privacy settings under username 2026-07-01 19:26:25 +02:00
Timo fa7eea54d8 Split tab and media title privacy controls 2026-07-01 19:21:38 +02:00
KoalaDev 04d2360814 Remove plan for splitting large JavaScript files
Removed the plan to split large JavaScript files into smaller modules due to prioritization changes.
2026-07-01 19:16:42 +02:00
Timo 29aba936ce Clarify tab and media title privacy setting 2026-07-01 18:58:39 +02:00
Timo 4bae88e107 Fix title privacy popup import 2026-07-01 18:50:09 +02:00
Skrockle 3e4b97b11a Fix: Remove redundant TITLE_PRIVACY_MODES array in popup.js
- Remove duplicate local TITLE_PRIVACY_MODES array definition
- Use Object.values(TITLE_PRIVACY_MODES).includes() for validation instead
- Keeps single source of truth in title-privacy.js

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-01 18:37:25 +02:00
Timo e555906553 fix(extension): harden title privacy edge cases 2026-06-29 13:43:10 +02:00
Timo 4f1335242c feat(extension): add shared title privacy modes 2026-06-29 13:35:34 +02:00
GitHub Action e683466bf0 chore(release): update versions to v2.5.0 [skip ci] 2026-06-29 10:58:06 +00:00
KoalaDev 788a3331d3 Merge pull request #14 from Shik3i/feature/host-control-mode
Prepare v2.5.0 host control release
v2.5.0
2026-06-29 12:55:57 +02:00
Timo 2d9b7bc099 Ignore Claude local files 2026-06-29 12:52:22 +02:00
Timo 717d37c693 Prepare v2.5.0 website release notes 2026-06-29 12:50:49 +02:00
KoalaDev 1f48e9df47 fix(popup): polish custom-server, host-control card & co-host UX
- Manual Connect: split the server picker into its own inset panel,
  visually separated from the Room ID / Password fields (they were
  welded together in one flat list).
- Custom server URL: stop auto-prepending ws:// — default to wss://
  for real hosts, ws:// only for localhost/127.0.0.1 (matches what
  the background already enforces; the displayed URL no longer lies).
- Host Control card: replace the raw native checkbox with the proper
  .toggle-switch slider used in Options; move the toggle row from a
  <label> to a <div> to avoid an illegally nested label.
- Co-host discoverability: owner-only hint in the Host Control card
  pointing to the participant list (new NOTICE_COHOST_HINT across all
  15 locales). Shown only when actionable: owner + co-host-capable
  relay + host-only active.
- Peer row: group right-side badges/actions into one container so they
  no longer scatter via space-between or collide with long names;
  restyle the give/revoke button (padding, weight, hover fill, tooltip).
- Gate promote/demote (and role badges) on host-only mode being ON,
  in addition to the existing owner-privilege check — roles are moot
  in 'everyone' mode, so no badge/button noise there.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 02:43:28 +02:00
KoalaDev adab684ed0 perf+fix: debounce seq persistence + role changes, null-clear stale peer state
- server: SET_PEER_ROLE now uses the same per-room 500ms debounce as
  SET_CONTROL_MODE (M-4), preventing a buggy/malicious host from
  thrashing the room's UI with rapid promote/demote bursts.
- server: PEER_STATUS relay treats explicit null as 'clear' for
  tabTitle/mediaTitle/currentTime, so the tab-close heartbeat actually
  zeroes out stale state on other peers instead of being silently
  preserved by the clamp fallback.
- background: _persistLastSeq is now trailing-debounced (500ms),
  cutting storage.session IPC writes from one-per-relayed-event to
  one-per-quiet-window in active rooms.
- locales: add missing TOAST_ID_REGENERATED to all 14 non-English
  locales (was blocking locale coverage test on main).
- test: H-1 force-sync demote test now waits out the debounce window
  to reflect real-world UI timing (a host cannot promote, run a
  force-sync, and demote inside 500ms).
2026-06-29 01:22:41 +02:00
KoalaDev e23f9ab226 fix: wire up Regenerate Peer ID button + remove arbitrary MAX_CONTROLLERS cap
Two pre-existing issues surfaced during audit follow-up:

1. popup.js bound elements.regenId but never attached a click handler —
   the 'Regenerate Peer ID' button has been dead UI since it was added
   (verified across full git history). Wired it up to send REGENERATE_ID;
   the background handler already did the right thing (rotate peerId,
   persist, force reconnect). The button is functional (regen ID on
   duplicate-identity errors), not privacy-theater — username is already
   user-changeable in settings, so it stays out of scope.

2. MAX_CONTROLLERS=10 was arbitrary. Payload math (25 controllers ×
   16-char IDs ≈ 500 bytes) is well under the 4KB maxHttpBufferSize,
   controllers.has() is O(1) on a Set, and 'just use everyone mode' is
   not a real answer when a host wants 12 controllers + 3 guests in a
   15-person room. Removed the cap entirely; the only real upper bound
   is MAX_PEERS_PER_ROOM (25).

Added TOAST_ID_REGENERATED to en.json — the i18n fallback merge
(Object.assign({}, enDict, targetDict)) covers the other 14 locales
automatically with English until they're translated.
2026-06-28 14:03:59 +02:00