From f1dae0ef4e025d34e23d0f8417fd1e667a3f5776 Mon Sep 17 00:00:00 2001 From: Timo <6156589+Shik3i@users.noreply.github.com> Date: Wed, 22 Apr 2026 11:04:51 +0200 Subject: [PATCH] chore: final integration polish - harden join ux, refine connection state, and sanitize logs --- extension/background.js | 7 +++--- extension/content.js | 56 ++++++++++++++++++++++++----------------- extension/popup.js | 19 ++++++++++---- 3 files changed, 51 insertions(+), 31 deletions(-) diff --git a/extension/background.js b/extension/background.js index 9162e6a..0a2f59e 100644 --- a/extension/background.js +++ b/extension/background.js @@ -227,7 +227,8 @@ function broadcastConnectionStatus(status) { } function updateBadgeStatus() { - const status = socket ? (socket.readyState === WebSocket.OPEN ? 'connected' : (isConnecting || socket.readyState === WebSocket.CONNECTING ? 'connecting' : 'disconnected')) : 'disconnected'; + const isConnected = socket && socket.readyState === WebSocket.OPEN && isNamespaceJoined; + const status = isConnected ? 'connected' : (isConnecting || (socket && socket.readyState === WebSocket.CONNECTING) ? 'connecting' : 'disconnected'); if (reconnectFailed) { chrome.action.setBadgeText({ text: 'ERR' }); @@ -309,7 +310,6 @@ function addToHistory(action, senderId) { // --- Event Handlers --- function handleServerEvent(event, data) { - // console.log(`[RECV] ${event}`, data); switch (event) { case EVENTS.ROOM_DATA: @@ -473,7 +473,8 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { reconnectDelay = 1000; connect(); } else if (message.type === 'GET_STATUS') { - let status = socket ? (socket.readyState === WebSocket.OPEN ? 'connected' : (isConnecting || socket.readyState === WebSocket.CONNECTING ? 'connecting' : 'disconnected')) : 'disconnected'; + const isConnected = socket && socket.readyState === WebSocket.OPEN && isNamespaceJoined; + let status = isConnected ? 'connected' : (isConnecting || (socket && socket.readyState === WebSocket.CONNECTING) ? 'connecting' : 'disconnected'); if (reconnectFailed) status = 'reconnect_failed'; sendResponse({ status, peerId, peers: currentRoom ? currentRoom.peers : [] }); // Global return true at the end handles this diff --git a/extension/content.js b/extension/content.js index 3223f91..fd0226a 100644 --- a/extension/content.js +++ b/extension/content.js @@ -7,6 +7,17 @@ if (window.koalaSyncInjected) return; window.koalaSyncInjected = true; + // Local Protocol Constants (Mirroring shared/constants.js) + const EVENTS = { + PLAY: "play", + PAUSE: "pause", + SEEK: "seek", + FORCE_SYNC_PREPARE: "force_sync_prepare", + FORCE_SYNC_ACK: "force_sync_ack", + FORCE_SYNC_EXECUTE: "force_sync_execute", + PEER_STATUS: "peer_status" + }; + let lastTargetState = null; let targetStateTimeout = null; @@ -40,11 +51,11 @@ const ytButton = document.querySelector('.ytp-play-button'); if (ytButton) { const isCurrentlyPlaying = !video.paused; - if ((action === 'play' && !isCurrentlyPlaying) || (action === 'pause' && isCurrentlyPlaying)) { - setTargetState(action === 'play' ? 'playing' : 'paused'); + if ((action === EVENTS.PLAY && !isCurrentlyPlaying) || (action === EVENTS.PAUSE && isCurrentlyPlaying)) { + setTargetState(action === EVENTS.PLAY ? 'playing' : 'paused'); ytButton.click(); } - if (action === 'seek') video.currentTime = data.targetTime; + if (action === EVENTS.SEEK) video.currentTime = data.targetTime; return; } } @@ -53,26 +64,26 @@ const twitchButton = document.querySelector('[data-a-target="player-play-pause-button"]'); if (twitchButton) { const isCurrentlyPlaying = !video.paused; - if ((action === 'play' && !isCurrentlyPlaying) || (action === 'pause' && isCurrentlyPlaying)) { - setTargetState(action === 'play' ? 'playing' : 'paused'); + if ((action === EVENTS.PLAY && !isCurrentlyPlaying) || (action === EVENTS.PAUSE && isCurrentlyPlaying)) { + setTargetState(action === EVENTS.PLAY ? 'playing' : 'paused'); twitchButton.click(); } - if (action === 'seek') video.currentTime = data.targetTime; + if (action === EVENTS.SEEK) video.currentTime = data.targetTime; return; } } // Fallback for native HTML5 - if (action === 'play') { + if (action === EVENTS.PLAY) { setTargetState('playing'); video.play().catch((e) => { console.warn('KoalaSync playback prevented:', e); setTargetState(null); }); - } else if (action === 'pause') { + } else if (action === EVENTS.PAUSE) { setTargetState('paused'); video.pause(); - } else if (action === 'seek') { + } else if (action === EVENTS.SEEK) { video.currentTime = data.targetTime; } } catch (e) { @@ -114,13 +125,13 @@ if (message.type === 'SERVER_COMMAND') { const { action, payload } = message; - if (action === 'play') { - tryMediaAction('play'); - } else if (action === 'pause') { - tryMediaAction('pause'); - } else if (action === 'seek') { - tryMediaAction('seek', payload); - } else if (action === 'force_sync_prepare') { + if (action === EVENTS.PLAY) { + tryMediaAction(EVENTS.PLAY); + } else if (action === EVENTS.PAUSE) { + tryMediaAction(EVENTS.PAUSE); + } else if (action === EVENTS.SEEK) { + tryMediaAction(EVENTS.SEEK, payload); + } else if (action === EVENTS.FORCE_SYNC_PREPARE) { if (!payload || payload.targetTime === undefined) return; const video = findVideo(); if (video) { @@ -131,8 +142,8 @@ chrome.runtime.sendMessage({ type: 'FORCE_SYNC_ACK' }); }); } - } else if (action === 'force_sync_execute') { - tryMediaAction('play'); + } else if (action === EVENTS.FORCE_SYNC_EXECUTE) { + tryMediaAction(EVENTS.PLAY); } } }); @@ -142,7 +153,7 @@ const video = findVideo(); if (!video) return; - const eventState = action === 'play' ? 'playing' : (action === 'pause' ? 'paused' : null); + const eventState = action === EVENTS.PLAY ? 'playing' : (action === EVENTS.PAUSE ? 'paused' : null); if (eventState && lastTargetState === eventState) { setTargetState(null); // Consume the match @@ -162,9 +173,9 @@ }); } - const handlePlay = () => reportEvent('play'); - const handlePause = () => reportEvent('pause'); - const handleSeeked = () => reportEvent('seek'); + const handlePlay = () => reportEvent(EVENTS.PLAY); + const handlePause = () => reportEvent(EVENTS.PAUSE); + const handleSeeked = () => reportEvent(EVENTS.SEEK); let lastVideoSrc = null; @@ -195,7 +206,6 @@ const currentSrc = video.currentSrc || video.src; if (!video.dataset.koalaAttached || (lastVideoSrc && currentSrc && lastVideoSrc !== currentSrc)) { - console.log('KoalaSync: Video element attached or recycled.'); setupListeners(); } } diff --git a/extension/popup.js b/extension/popup.js index ae8ef97..56beba8 100644 --- a/extension/popup.js +++ b/extension/popup.js @@ -515,17 +515,26 @@ chrome.runtime.onMessage.addListener((msg) => { updatePeerList(msg.peers); } else if (msg.type === 'CONNECTION_STATUS') { applyConnectionStatus(msg.status); + if (msg.status === 'disconnected' || msg.status === 'reconnect_failed') { + elements.joinBtn.disabled = false; + elements.joinBtn.textContent = 'Join / Create Room'; + } } else if (msg.type === 'HISTORY_UPDATE') { updateHistory(msg.history); } else if (msg.type === 'ROOM_LIST') { updateRoomList(msg.rooms); } else if (msg.type === 'LOG_UPDATE' && msg.log && msg.log.type === 'error') { showError(msg.log.message); - } else if (msg.type === 'JOIN_STATUS' && msg.success) { - // Final confirmation of join from background - chrome.storage.sync.get(['roomId', 'password', 'useCustomServer', 'serverUrl'], (data) => { - updateUI(data.roomId, data.password, data.useCustomServer, data.serverUrl); - }); + } else if (msg.type === 'JOIN_STATUS') { + if (msg.success) { + // Final confirmation of join from background + chrome.storage.sync.get(['roomId', 'password', 'useCustomServer', 'serverUrl'], (data) => { + updateUI(data.roomId, data.password, data.useCustomServer, data.serverUrl); + }); + } else { + // Join failed: reset UI state + updateUI(null, null); + } } });