- 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
- Add renderEmpty() helper with icons and hints for peers/history/logs/rooms
- Implement onboarding tour (4 steps) with overlay, dots, skip/next
- Dev tab logs only poll when tab is visible (isDevTabVisible flag)
- Expand username generation from 12/12 to 30/30 adjective-noun pairs
- Update ROADMAP.md to remove implemented features
- popup.js: guard peers/state.acks in updateLastActionUI()
- popup.js: guard state.duration in refreshDebugInfo()
- popup.js: guard elements.lobbyPeerStatus in updateLobbyUI()
- background.js: use Array.isArray() for currentRoom.peers.length checks
Adds a new toggleable feature that detects episode transitions via
mediaTitle mutation (loadeddata/MutationObserver), pauses the video,
and waits for all room peers to load the same episode before
executing a coordinated Force Sync play at 0:00.
Protocol:
- Add EPISODE_LOBBY and EPISODE_READY events to shared/constants.js
- Add EPISODE_LOBBY_TIMEOUT (60s) constant
- Relay both new events in server/index.js
Content Script (content.js):
- Layered detection: loadeddata + MutationObserver src-change + heartbeat
- Debounced onEpisodeTransition() sends signal ONLY; no eager pause
- PAUSE_FOR_LOBBY handler pauses only after background confirms feature enabled
- startLobbyPoll() polls title match without premature pause for non-initiators
- checkAndReportLobbyReady() pauses and sends EPISODE_READY_LOCAL on match
- CONTENT_BOOT recovery for re-injection after hard navigation
Background (background.js):
- Episode lobby state persisted in chrome.storage.session with recovery
- EPISODE_CHANGED: checks setting, creates lobby, sends PAUSE_FOR_LOBBY to tab
- EPISODE_LOBBY/READY server event handlers with dedup logic
- 60s timeout cancels lobby (Option B) with Chrome failure notification
- Peer departure handled: removes from readyPeers, re-checks completion
- executeEpisodeLobby() reuses existing Force Sync pipeline at targetTime 0.0
- Lobby cleared on LEAVE_ROOM; status exposed in GET_STATUS
Popup:
- Auto-Sync Next Episode toggle in Settings tab (default: off, opt-in)
- Episode Lobby status card in Sync tab with peer readiness display
- LOBBY_UPDATE message handler for real-time UI updates
Bumps APP_VERSION and manifest to 1.2.0