- 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>
- 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).
- 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>
The host-control desync dialog and the "watching on your own" badge were
hardcoded English — content.js has no i18n loader. Background does, so it now
resolves the strings (GET_HCM_STRINGS: loadLocale + getMessage) and content
fetches them on init with English fallbacks, re-rendering the badge if it was
already shown. The dialog body is now generic (dropped the paused/jumped verb)
to keep translation clean across languages.
Adds 6 keys (HCM_DIALOG_TITLE/BODY/STAY/SOLO, HCM_BADGE_SOLO/RESYNC) translated
across all 15 popup locales.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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
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>
Add two new languages (uk, zh / zh_CN) across the extension and website:
register them in SUPPORTED_LANGUAGES, the Chrome _locales map, the website
build/lang-init/app routing, hreflang/og/schema tags and language selectors.
Fix systematic machine-translation word-sense errors in the new zh/uk
locales (e.g. zh "Status"=地位→状态, "Leave Room"=留出空间→离开房间,
"Play"=玩→播放, "Seek"=寻找→跳转, audio Attack/Release/Knee; uk "Play"=Грати
→Відтворити, "Clear"=ЯСНО→Очистити, "Open"=ВІДЧИНЕНО→Відкрити, peers
"Однолітки"→"Учасники"), translate remaining English leftovers (Room ID,
Custom) and normalise terminology. All 15 locales pass test-locales.cjs.
Note: popup.html and website/template.html also carry the language-selector
additions here; their Ko-Fi→Support label text is part of the branding change.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Fix: CONNECT/RETRY_CONNECT always force-disconnect before reconnecting
(prevents JOIN_ROOM going to official server when custom is selected)
- Add forceDisconnect() helper: clears socket, eventQueue, episodeLobby,
expectedAcksCount, broadcast status, persists cleanup to storage
- Fix: save useCustomServer to storage on Join Room click (no race condition)
- Fix: trigger RETRY_CONNECT on server mode toggle and custom URL change
- Fix: show error when Custom selected but no URL entered (no silent fallback)
- Fix: button label changed to 'Join / Create Room' in all 6 locales
- Rewrite scheduleReconnect() for two-phase strategy:
Phase 1 (aggressive): 500ms-5s backoff, max 20 attempts or 5 minutes
Phase 2 (slow): retry every 5 minutes indefinitely, never give up
- Persist reconnectAttempts/reconnectStartTime/reconnectFailed to session storage
- Remove 'reconnect_failed' status; slow mode shows as 'reconnecting' with retry button
- Add scheduleReconnect() call on offline path to continue retry cycle