Commit Graph

144 Commits

Author SHA1 Message Date
Timo 750b47d32a fix(i18n): correct website and extension copy 2026-07-26 05:53:57 +02:00
Timo 63db02211b fix(chat): harden overlay interactions and notifications 2026-07-26 04:14:25 +02:00
Timo 9251ae6aff add dedicated chat settings 2026-07-26 02:12:28 +02:00
Timo 77790a279c fix(chat): preserve mixed-version compatibility 2026-07-26 01:02:20 +02:00
Timo e9d735cd39 Merge remote-tracking branch 'origin/main' into feature/textchat
# Conflicts:
#	extension/background.js
#	extension/popup.js
2026-07-19 20:32:24 +02:00
Timo fe13275b5d Harden host access recovery races 2026-07-15 13:31:56 +02:00
Timo 142153a131 Harden host access recovery for v2.6.2 2026-07-15 12:46:57 +02:00
Timo 7e7e60f267 Fix blocked website access and add troubleshooting page 2026-07-15 12:24:59 +02:00
KoalaDev 9e0d294758 fix(chat): harden client state and messaging 2026-07-15 08:40:27 +02:00
KoalaDev ee0d68d8d3 feat(chat): add client encryption and key lifecycle 2026-07-15 07:10:32 +02:00
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
Timo b987d13612 fix(extension): localize theme and appearance tooltips and selector options 2026-07-12 14:54:00 +02:00
Timo 0168484382 style(extension): unify control system and accessibility 2026-07-12 13:04:23 +02:00
Timo 104602edec fix(extension): unify status UX and theme design 2026-07-12 11:10:15 +02:00
Timo 986b2a6e56 style(extension): redesign settings and color system 2026-07-12 10:59:19 +02:00
KoalaDev 4fb8e0f53a style(extension): apply UI/UX audit enhancements, consolidate footers, and style capsule badges 2026-07-12 06:38:26 +02:00
KoalaDev bd33ea4804 feat(extension): implement accordion mutual exclusion behavior for settings details categories 2026-07-12 06:31:24 +02:00
Timo 04df35bbe6 Enhance forest scene with mid bamboo layer, butterflies, click confetti, and demo scene polish 2026-07-11 06:08:12 +02:00
KoalaDev 1f1844e99b Fix bamboo stalk taper and align stray colors to palette
The stalks used border-radius:50%, which renders a tall ellipse whose
ends taper to points, and unbounded parallax drift pushed them off the
bottom of the viewport on long pages. Rounded caps + 20% overscan +
a viewport-relative drift clamp keep them full-height while scrolling.

Sweep the remaining off-palette colors into the nature palette:
content-script overlays (slate grays), amber warnings/badges/star
accents (now terracotta) in popup, background badge and website
illustrations, and the support-heart red (now --danger).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 19:28:50 +02:00
KoalaDev aa52d319e1 Redesign website and extension with koala nature theme
v3.0.0 "The Greens Update" palette: forest-green oklch color system
(accent green + terracotta secondary) replaces the indigo/slate scheme
across the landing page and the extension popup/options. The blob
background becomes an animated bamboo forest overlay (parallax stalks,
falling leaves, canopy, ground mist, fireflies, light sweep, grain)
with prefers-reduced-motion support. Layout, structure and copy are
unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 19:18:40 +02:00
Timo 869c64171b Fix Disney+ force sync, seek, and HCM regressions for v2.5.3
The v2.5.2 Disney+ page-API integration leaked blob-relative <video>
time into force sync, seeks, and heartbeats when the page-API bridge
had no fresh data, so force sync on Disney+ appeared broken.

- getSyncCurrentTime/getSyncDuration now refuse native values on Disney+
  (return null/0) so stale bridge data degrades to a clean no-op instead
  of broadcasting garbage to peers. The get_current_time handler and
  episode/lobby/hcmIsLive paths are routed through the same accessor.
- Validate FORCE_SYNC_PREPARE/SEEK payloads as finite before relaying;
  the internal coercion no longer treats '' as 0.
- Stop double-routing FORCE_SYNC_PREPARE from the popup path (the
  generic popup route now covers only play/pause/seek).
- popup force-sync: exclude null/empty peer times from the jump-to-others
  median (Number(null)===0 was dragging the target to 0), guard against
  NaN end-to-end, clear the dangling reset timer on failure, and retry
  without re-injecting when the content script responds but the Disney+
  bridge has not yet delivered a finite time.
- hcmIsLive skips the native-duration live signal on Disney+ only,
  preserving YouTube/Twitch Infinity-duration live detection.

Disney-specific logic remains strictly gated to disneyplus.com; no
Netflix/YouTube/Twitch/generic path is affected.
2026-07-02 16:57:48 +02:00
Timo 9ac8c28442 Remove Disney+ DOM scraping fallback 2026-07-02 15:08:54 +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 09d35f3e48 TEMPORARY DIAGNOSTICS: Implement Proposal 2 and 3 logs in Dev tools tab 2026-07-02 13:35:08 +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 9cbeb661d6 Save baseline state with Disney+ seek adjustments and build identifier 2026-07-02 13:00:41 +02:00
KoalaDev 01762b0c2f Normalize shared tab titles 2026-07-02 10:20:25 +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
Timo fa7eea54d8 Split tab and media title privacy controls 2026-07-01 19:21:38 +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
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 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
KoalaDev 17ac5c0a6f fix(host-control-mode): adversarial audit — force-sync stall, desync/lobby, gate parity, BC tests
Audit fixes (each verified against the actual code path):

H-1 (server): track force-sync initiator on PREPARE; let the demoted
initiator's EXECUTE through the host-only gate so mid-sync demotion no
longer strands the whole room paused. Clear on EXECUTE/peer-leave.

M-1 (background): episode-lobby gate now uses !amController() for parity
with CONTENT_EVENT and server gates — co-hosts can drive the room and
initiate lobbies, not just the owner.

M-2/M-3 (popup/content/background): forceSyncReset respects hcmGuestLocked;
desynced guest skips EPISODE_LOBBY so they don't get frozen in pause after
lobby completion, and checkEpisodeLobbyCompletion excludes desynced peers
from the required count so they don't block the lobby.

M-4 (background): getHostSyncTarget clamps extrapolation to 2x heartbeat
interval so a stale host heartbeat can't snap the guest tens of seconds
past the host's real position.

L-1..L-4 (server/content/background/popup): clarify dedup comment re:
network-blip window, enforce desync invariant on SW-restore, add
forceSyncBtn guest-locked backstop, refresh badge text in place.

Backward compatibility (verified by BC-1..BC-4 regression tests):
- Old client ↔ new server: server adds fields only, never requires; old
  heartbeats stripped of desynced; host-only enforced server-side even
  when the client has no awareness.
- New client ↔ old server: empty capabilities → host-control UI hidden,
  all gates default to everyone, behavior byte-identical to pre-HCM.
- Mixed rooms: every pre-HCM event type relays cleanly in both directions.
2026-06-28 05:54:50 +02:00
KoalaDev 1ec2396c41 feat(co-host): popup UI — promote/demote, controller badges, controller-aware lock
- updateHostControlUI takes a state object now; role badge shows Host / Controller
  / Guest; remote-control lock uses amController (a co-host can drive, so their
  buttons aren't locked).
- Peer list: Host/Controller badges and, for the owner, a per-peer Give control /
  Revoke button (SET_PEER_ROLE). Shown only when the feature is active and the room
  is host-only or the viewer is the owner — no role noise for guests in normal rooms.
  Hidden entirely against a relay without the co-host capability.
- i18n: BADGE_CONTROLLER, BTN_GIVE_CONTROL, BTN_REVOKE_CONTROL across all 15 locales.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 03:45:00 +02:00
KoalaDev dfa0a3d03e fix(host-control-mode): audit findings — host dedup demotion, episode-lobby freeze, +cleanups
Findings recovered from the multi-agent audit (verification phase was cut off by a
usage limit; verified inline against the code):

HIGH:
- Host was demoted on peerId dedup (fast reconnect / second tab): the dedup path
  removes the old socket and the kicked socket's 'disconnect' both ran the
  host-leave fallback before the same peerId re-joined → room silently unlocked on
  every host network blip. Now skip the fallback while a join for that peerId is in
  flight (peerJoinLocks). Regression test added. (A long real disconnect still
  falls back — that's the deferred host-grace EC-10.)
- Episode auto-advance froze a gated guest: in host-only the guest's EPISODE_LOBBY
  is dropped server-side, but the guest still self-paused (PAUSE_FOR_LOBBY) waiting
  for readies that never came → 60s freeze. A host-only guest now skips creating a
  lobby (the host drives episode sync).

LOW / cleanup:
- GET_HCM_STRINGS could return a raw key name ("HCM_DIALOG_TITLE") if the locale
  dictionary failed to load (getMessage returns the key on miss) → omit it so
  content keeps its English fallback.
- hcmReset now also clears the snap-back cooldown + buffering grace, so a stale
  cooldown can't swallow the first snap-back after a room/host change.
- Popup play/pause labels reset on lock too (not just unlock), so a button can't
  freeze on "Playing…" when host-only activates mid-click.
- Fix a stale comment (heartbeat now carries 'desynced').

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 02:25:11 +02:00
KoalaDev 9963da2ebc feat(host-control-mode): explicit server capabilities for feature detection
Replace the implicit "hostPeerId present ⇒ feature supported" heuristic with an
explicit capabilities list the relay advertises in ROOM_DATA. Cleaner, self-
documenting, and the extensible hook for the planned co-host feature (owner
promotes guests to extra controllers) — a future 'co-host' capability + events
slot in without a protocol bump.

- shared: CAPABILITIES { HOST_CONTROL }.
- server: SERVER_CAPABILITIES advertised in ROOM_DATA.
- background: track serverCapabilities (empty against older relay), serverSupports(),
  thread hostControlSupported through GET_STATUS / GET_CONTROL_MODE / CONTROL_MODE.
- popup: gate the host-control card on the explicit capability instead of hostPeerId.

Backwards-compatible both ways: old relay omits the field → feature stays hidden
(no errors); old client ignores the field. WS test asserts ROOM_DATA advertises
the capability. Adds docs/host-control-mode-TESTING.md (beta-server setup, wss
caveat, two-new-clients note, verification checklist).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 04:48:45 +02:00
KoalaDev d26b95985d fix(host-control-mode): only show host-control card when meaningful
The card was rendered in every room with a "Guest" badge by default — confusing
in normal rooms, and outright misleading against a relay that doesn't yet support
host control (older server omits hostPeerId, so amHost is always false and nobody
is ever recognized as host).

Now the card shows only when it's meaningful: the host always sees it (to toggle
host-only), a guest sees it only while host-only is active, and it's hidden in a
normal "everyone" room and whenever the server doesn't advertise hostPeerId
(feature unavailable). Thread hostPeerId through updateHostControlUI to detect
server support.

Note: the feature still requires the relay to run the host-control server code;
this just makes the client degrade cleanly instead of showing a stray "Guest".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 01:29:00 +02:00
KoalaDev 58af258fd3 fix(host-control-mode): harden gates, close UX races, debounce toggles, surface desync state
Bis auf peerId-Auth (akzeptiert) alle Audit-Findings behoben:
- Snap-back spielt nicht mehr blind ab, wenn Host-Status unbekannt
- Teardown-Pfade broadcasten jetzt CONTROL_MODE → kein verwaistes Badge/Dialog
- Dialog-Timer bei Ersetzung sauber gecleart
- Server re-synchronisiert Sender bei nicht-Host-Reject
- Popup-Toggle revertiert bei Server-Ablehnung
- Desync-Zweig sendet keine Phantom-ACKs mehr an Host
- Toggle-Debouncing serverseitig (500ms pro Raum)
- Button-Text auf Unlock zurückgesetzt
- Live-Erkennung defensiver, Resync-Retry bei fehlendem Target, Badge-Retry

Neu: Host sieht 'Solo'-Badge für desyncte Gäste via PEER_STATUS-Heartbeat
(16 Sprachen, neuer i18n-Key BADGE_DESYNCED/TOOLTIP_PEER_DESYNCED)

Tests: H-5-Reject-Unicast, M-4-Debounce, Desync-Heartbeat-Relay
2026-06-26 13:09:34 +02:00
KoalaDev af9cf34f0b fix(extension): pre-test self-audit fixes for host control mode
- popup: lock remote-control buttons (Play/Pause/SYNC) for guests in host-only
  mode so clicks don't silently get gated and leave the button stuck; backstop
  guards in the handlers and the 2.5s safety reset respects the lock.
- content: rebuild the desync dialog + resync badge with the DOM API inside a
  Shadow DOM. innerHTML inline style="" attributes are stripped by strict
  style-src CSP (Netflix/YouTube/Disney+); CSSOM .style is CSP-safe and the
  shadow root isolates from page CSS.
- content: detect live-DVR in hcmIsLive() via a sliding seekable window
  (seekable.start(0) > 1), not just duration === Infinity (EC-15).

Records remaining audit items (snap-back thrash, join race, dialog i18n) in the
edge-case log for the device-testing pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 09:54:45 +02:00
KoalaDev 9006570bd1 feat(extension): host control toggle + role badge in popup (step 5)
Final wiring of host control mode — the user-facing UI:

- Active-room section gains a Host Control card: a Host/Guest role badge, a
  host-only toggle ("Only I can control playback") shown to the host, and a
  guest notice when the room is host-only.
- Toggle sends SET_CONTROL_MODE; UI refreshes from the server's CONTROL_MODE
  broadcast (with optimistic revert on failure). Card updates on GET_STATUS,
  CONTROL_MODE, and reconnect.
- i18n: 6 new keys (LABEL_HOST_CONTROL[_TOOLTIP], LABEL_HOST_ONLY_TOGGLE,
  NOTICE_HOST_CONTROLS, BADGE_HOST, BADGE_GUEST) translated across all 15
  popup locales.

Completes the feature end to end (server + background + content + popup).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 04:14:55 +02:00
KoalaDev 6276ee134c fix(ui): Correct false idle state on connection errors
Bump version to 2.4.6
2026-06-23 18:36:05 +02:00
KoalaDev a1bdcf4325 fix(extension): stop storing room/settings in chrome.storage.sync
Room ID, password, and username were resurrected from synced storage on a
fresh install (sync survives an uninstall in the user's Google account), which
made the extension silently auto-connect to a dead room and appear permanently
connected. getSettings() and all settings reads (popup, content, audio-options,
applyAudioSettingsToTab) are now local-only, and legacy keys are actively
purged from sync on install/update/startup. Only onboardingComplete and
dismissedHints remain in sync.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 17:38:36 +02:00
KoalaDev 36f494fa55 feat(extension): one-click invite button in empty peer list + v2.4.1 changelog
- "No peers yet" state now shows a localized "Copy invite link" button (reuses BTN_COPY_INVITE, present in all 13 locales) so users can share without hunting for the field
- Add v2.4.1 changelog entry covering the onboarding tour improvements, empty-state action, and the mobile landing-page fixes from this session

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 10:50:04 +02:00
KoalaDev b5b3885d19 feat(extension): finish onboarding tour with closing step & cleaner welcome
- Add the previously-orphaned 5th onboarding step (ONBOARDING_5) so the tour ends on a closing card instead of stopping at the username field
- Make step 1 a centered welcome card instead of spotlighting the logo; guard querySelector for target-less steps
- Fix stale static placeholders in popup.html (Step 1 of 3 -> 5, progress 33% -> 20%)

Verified ONBOARDING_5/DONE exist across all 13 locales; rendered with the longest (German) copy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 10:40:40 +02:00
Timo 91aa76e842 fix: revert premature isConnecting reset + remove popup disconnected flicker
- background.js: remove isConnecting=false at line 608 (was set before
  WebSocket handshake completed, defeating the guard for the entire
  CONNECTING phase). isConnecting is already properly reset in onclose,
  onopen/40 handler, catch block, and socket guard path.
- background.js: restore isConnecting=false in forceDisconnect() so
  subsequent connect() calls can proceed after intentional disconnect.
- popup.js: remove hardcoded applyConnectionStatus('disconnected') that
  caused a guaranteed red flicker on every popup open. Status is now
  set only by the async GET_STATUS response.
2026-06-16 10:44:57 +02:00
Timo 5f0a189451 fix(popup): trigger CONNECT when popup opens with saved roomId
If user has a room configured but the background is not connected
(e.g. service worker was killed, startup race, or stale state), the
popup now sends CONNECT on open. Previously it only called GET_STATUS
and showed 'disconnected' with 0 logs — the user had no way to know
whether the extension was working.
2026-06-16 10:35:13 +02:00