feat: Auto-Sync Next Episode v1.2.0

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
This commit is contained in:
Timo
2026-04-25 16:43:10 +02:00
parent 02afc193c6
commit 55c2d4ed0d
7 changed files with 511 additions and 11 deletions
+2 -1
View File
@@ -309,7 +309,8 @@ io.on('connection', (socket) => {
const relayEvents = [
EVENTS.PLAY, EVENTS.PAUSE, EVENTS.SEEK,
EVENTS.PEER_STATUS, EVENTS.FORCE_SYNC_PREPARE,
EVENTS.FORCE_SYNC_ACK, EVENTS.FORCE_SYNC_EXECUTE
EVENTS.FORCE_SYNC_ACK, EVENTS.FORCE_SYNC_EXECUTE,
EVENTS.EPISODE_LOBBY, EVENTS.EPISODE_READY
];
relayEvents.forEach(eventName => {