Move extractEpisodeId() and sameEpisode() to shared episode-utils.js.
background.js imports via ES module. content.js (IIFE) receives injected
copy via build-extension.js marker replacement, eliminating duplication.
- 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.
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.
- Prevent concurrent connect() by removing isConnecting reset from
forceDisconnect(); the guard in connect() now reliably blocks
re-entry since no external caller can defeat it.
- Reset isConnecting at end of connect() so subsequent calls can
proceed without waiting for the async '40' handler.
- Clear connectIntent and cancel reconnect timer on server ERROR
when no currentRoom exists, preventing infinite reconnect loops
after failed join attempts (e.g. wrong password via invite link).
- Move connectIntent assignment after !roomId guard in
WEB_JOIN_REQUEST to avoid clobbering existing intent on invalid
input.
- Broadcast JOIN_STATUS failure to popup and bridge tabs when
WEB_JOIN_REQUEST receives an invalid room ID, so the website
join page receives feedback instead of hanging forever.
- Clear joinBtnTimeout on CONNECTION_STATUS connected/disconnected
to avoid stale timeout error messages in the popup.
After LEAVE_ROOM or idle-leave, reconnectAttempts was not reset.
GET_STATUS would return 'reconnecting' instead of 'disconnected',
showing wrong status in popup and leaving Retry button visible.
Lazy-connect introduces a new state where the user clicks 'Raum erstellen'
and the WebSocket takes 1-2s to establish (previously always pre-connected).
The old 15s blind timeout would re-enable the button while background was
still connecting, causing silent no-op clicks. Now polls GET_STATUS and
extends the window if still connecting.
- Add connectIntent flag to gate all reconnect attempts
- Only auto-connect on startup if roomId exists in storage
- Close socket + stop reconnect after leaveRoom or idleLeave
- Preserve existing behavior 1:1 when actively in a room
- Guard force-sync state and peer list clearing during transient disconnects
- Guard WEB_JOIN_REQUEST against empty sanitized roomId
Adds application-level ping/pong between extension and relay server.
Extension sends PING every 15s, server echoes PONG. Round-trip time
displayed in Status tab (green/yellow/red color-coded).
Server also forwards PING with target peerId and routes PONG back,
enabling future peer-to-peer ping without server restart.
Extension already responds to incoming peer PINGs.
See CHANGELOG.md for details.
- Fixed episode guard regex to support Sxx:Exx title format (Jellyfin/Emby)
and any non-alphanumeric separator between season and episode numbers
- Migrated username, roomId, password, serverUrl, useCustomServer from
chrome.storage.sync to chrome.storage.local for per-device isolation,
preventing automatic cross-device room joins with duplicate names
- Added one-time migration from sync to local for existing users