- 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.
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.
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
- GET_VIDEO_STATE now returns allVideos[] with summary per video element
- Copy report shows markdown table when multiple videos on page
- Table includes: resolution, muted, paused, readyState, duration, and marks selected target
- Helps diagnose Prime Video scenarios where preview vs main video both exist
- findVideo() now scores all video elements by size + unmuted + duration
- Fixes Prime Video selecting 0x0 placeholder instead of actual player
- Fix history entries showing '?' by using h.action instead of h.event/h.type
- Update Prime Video status in TESTED_SERVICES.md to partial support
- Copy Logs button now generates full Markdown debug report (system, tab, connection, video, history, logs)
- Enhanced Dev tab with 20+ video state fields (network, dimensions, error, shadow DOM, platform detection)
- Platform auto-detection (YouTube, Netflix, Twitch, Prime Video, Disney+, Hulu, HBO, Vimeo, Dailymotion)
- 'No video found' diagnostic mode with hints
- Convert mockup from inline <span lang> to {{MOCK_*}} template vars (all 6 languages)
- New TwoPointZero branding: icons (16/32/48/96/128), favicons (PNG 16/32 + apple-touch + 192)
- Fix logo vertical centering via display:contents on picture wrappers
- Increase popup logo to 48px, website nav logo to 64px
- AVIF quality 70->80, speed 6->4, remove min 3KB threshold
- Add 32+96 icon sizes to manifest
- Remove amazon. from tab blacklist (unblocks Prime Video)
- Update TESTED_SERVICES.md: mark Prime Video as non-functional
- Update CONTRIBUTING.md with Copy Debug Report workflow
- Add currentServerUrl tracking: only disconnect/reconnect when server URL actually
changes, otherwise reuse existing connection and just switch rooms
- Add resolveServerUrl() helper for consistent URL resolution across handlers
- forceDisconnect() now resets currentServerUrl to null
- CONNECT and WEB_JOIN_REQUEST handlers: smart comparison before reconnecting
- Add generateRoomId(): human-readable 'ADJECTIVE-NOUN-Number' format (e.g. HAPPY-KOALA-16)
- Replace Math.random() room IDs with generateRoomId() in joinBtn and handleCreateRoom()
- Expand USERNAME_ADJECTIVES: +16 words (Turbo, Zen, Pixel, Cyber, Solar, etc.)
- Expand USERNAME_NOUNS: +12 words (Yeti, Goblin, Pirate, Ninja, Wizard, Storm, etc.)
- Add emoji mappings for all new words
- WEB_JOIN_REQUEST handler: forceDisconnect+connect instead of reusing old socket
(same bug as CONNECT: JOIN_ROOM was sent to official server instead of custom)
- joinBtn handler: generate random password when roomId is empty and password empty
(previously created rooms without passwords when using the advanced join button)
- Auto-copy invite link when creating room via joinBtn (consistent with Create Room button)
- 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
- Create shared/names.js as single source of truth for emoji maps, noun
lists, adjectives, and username generation (215 animal emoji entries)
- Remove duplicated inline lists from popup.js and background.js; both
now import getAvatarForName / generateUsername from shared/names.js
- Add names.js to the build script sync list so it stays DRY across
extension builds
- Fix missing cat emoji: CoolCat now correctly resolves to 🐱
- Sort emoji map keys by length at lookup time to prevent substring
false-matches (e.g. 'caterpillar' before 'cat')
The noise filter used naive String.includes() on the full URL, causing
blacklist entry 'x.com' to match netflix.com (since 'netflix.com'
contains 'x.com' as substring). This made Netflix tabs disappear when
the filter was enabled.
Fixed by extracting the URL hostname and matching at domain boundaries:
- Domain entries (x.com): hostname === domain || endsWith('.' + domain)
- Prefix entries (amazon.): startsWith || includes('.' + domain)
- Keyword entries (jira): substring fallback on full URL
Release v1.7.5
init() called updatePeerList() directly but never set lastKnownPeers.
On the first PEER_UPDATE message (heartbeat, play/pause, any state
change), detectPeerChanges() saw lastKnownPeers=[] and treated ALL
peers including self as newly joined — triggering 'name joined the room'
toast on every action while the popup was open.
- FORCE_SYNC_TIMEOUT in shared/constants.js was 5000 but all code uses
8500ms. Update constant to 8500 and reference it in background.js
instead of hardcoded values (4 occurrences)
- Add errorToken counter in popup showError() so stale 5s timeout
doesn't clear styling of a newer error that arrived in between
- Fix EVENT_ACK handler indentation in server/index.js to match
surrounding socket.on handlers
- Add 10s timeout to ensureState() so extension doesn't hang forever if
chrome.storage.session.get() never calls back (storage API failure)
- Skip emit(LEAVE_ROOM) in leaveOldRoomIfSwitching when socket is down;
server already cleaned up via disconnect handler, avoid queued no-op
- Persist cleared peers to storage in socket.onclose to prevent stale
peer list restoration on service worker restart
- Store and clean up forceSyncReset setTimeout in popup unload handler
and when force_sync_execute completes