From cc0265c8360b3ec57ed1cdaa23f2e551b3316280 Mon Sep 17 00:00:00 2001 From: Koala <6156589+Shik3i@users.noreply.github.com> Date: Tue, 26 May 2026 17:42:11 +0200 Subject: [PATCH] v1.8.10: fix description length, solo peer detection, tab-close peer notify, lastHeartbeat guard, time interpolation stale guard --- extension/background.js | 37 ++++++++++++++++++++++++++++++++++-- extension/manifest.base.json | 4 ++-- extension/popup.js | 18 ++++++++++++++++-- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/extension/background.js b/extension/background.js index 46a37c5..07ae98c 100644 --- a/extension/background.js +++ b/extension/background.js @@ -706,7 +706,9 @@ function handleServerEvent(event, data) { if (!ignoreStatus) { peer.playbackState = data.playbackState !== undefined ? data.playbackState : peer.playbackState; peer.currentTime = data.currentTime !== undefined ? data.currentTime : peer.currentTime; - peer.lastHeartbeat = Date.now(); + if (data.playbackState !== undefined || data.currentTime !== undefined) { + peer.lastHeartbeat = Date.now(); + } } } else { // Migration: replace string peer with normalized object @@ -1169,7 +1171,8 @@ async function handleAsyncMessage(message, sender, sendResponse) { addToHistory(message.action, 'You'); const isNonEssentialEvent = message.action === EVENTS.PLAY || message.action === EVENTS.PAUSE || message.action === EVENTS.SEEK; - const hasOtherPeers = currentRoom && Array.isArray(currentRoom.peers) && currentRoom.peers.length > 0; + const otherCount = currentRoom && Array.isArray(currentRoom.peers) ? currentRoom.peers.filter(p => (typeof p === 'object' ? p.peerId : p) !== peerId).length : 0; + const hasOtherPeers = otherCount > 0; if (isNonEssentialEvent && !hasOtherPeers) { sendResponse({ status: 'ok_solo' }); @@ -1384,11 +1387,41 @@ async function handleAsyncMessage(message, sender, sendResponse) { // Tab removal listener chrome.tabs.onRemoved.addListener((tabId) => { if (tabId === currentTabId) { + const wasInRoom = !!currentRoom; currentTabId = null; currentTabTitle = null; chrome.storage.session.set({ currentTabId: null, currentTabTitle: null }); updateBadgeStatus(); addLog('Target tab closed.', 'warn'); + + if (wasInRoom) { + const roomAtClose = currentRoom; + getSettings().then(settings => { + if (currentRoom !== roomAtClose) return; + + emit(EVENTS.PEER_STATUS, { + peerId, + playbackState: 'paused', + currentTime: null, + mediaTitle: null, + username: settings.username, + tabTitle: null + }); + + if (currentRoom && Array.isArray(currentRoom.peers)) { + const me = currentRoom.peers.find(p => (p.peerId || p) === peerId); + if (me && typeof me === 'object') { + me.playbackState = 'paused'; + me.currentTime = null; + me.mediaTitle = null; + me.tabTitle = null; + me.lastHeartbeat = Date.now(); + if (storageInitialized) chrome.storage.session.set({ currentRoom }); + chrome.runtime.sendMessage({ type: 'PEER_UPDATE', peers: currentRoom.peers }).catch(() => {}); + } + } + }).catch(() => {}); + } } }); diff --git a/extension/manifest.base.json b/extension/manifest.base.json index df83162..b655783 100644 --- a/extension/manifest.base.json +++ b/extension/manifest.base.json @@ -1,8 +1,8 @@ { "manifest_version": 3, "name": "KoalaSync", - "version": "1.8.9", - "description": "Watch party extension to synchronize video playback on YouTube, Twitch, Netflix, Emby, Jellyfin, and any HTML5 site in real-time with friends.", + "version": "1.8.10", + "description": "Synchronize video playback on YouTube, Netflix, Emby, Jellyfin, and any HTML5 site in real-time with friends.", "permissions": [ "storage", "tabs", diff --git a/extension/popup.js b/extension/popup.js index 8f6505f..61386cc 100644 --- a/extension/popup.js +++ b/extension/popup.js @@ -334,7 +334,9 @@ function startInterpolation() { const peer = activePeers.find(p => p.peerId === peerId); if (peer && peer.playbackState === 'playing' && peer.currentTime != null && peer.lastHeartbeat) { const elapsed = (Date.now() - peer.lastHeartbeat) / 1000; - el.textContent = formatTime(peer.currentTime + elapsed); + if (elapsed < 45) { + el.textContent = formatTime(peer.currentTime + elapsed); + } } }); }, 1000); @@ -477,7 +479,9 @@ function updatePeerList(peers) { let displayTime = p.currentTime; if (p.playbackState === 'playing' && p.lastHeartbeat && p.currentTime != null) { const elapsed = (Date.now() - p.lastHeartbeat) / 1000; - displayTime += elapsed; + if (elapsed < 45) { + displayTime += elapsed; + } } timeSpan.textContent = formatTime(displayTime); statusLine.appendChild(timeSpan); @@ -1129,6 +1133,11 @@ elements.playBtn.addEventListener('click', () => { type: 'CONTENT_EVENT', action: EVENTS.PLAY, payload: {} + }, (response) => { + if (response && response.status === 'ok_solo') { + elements.playBtn.textContent = '▶ Play'; + elements.playBtn.disabled = false; + } }); // Safety reset: restore button after 2.5s in case no peers respond setTimeout(() => { @@ -1150,6 +1159,11 @@ elements.pauseBtn.addEventListener('click', () => { type: 'CONTENT_EVENT', action: EVENTS.PAUSE, payload: {} + }, (response) => { + if (response && response.status === 'ok_solo') { + elements.pauseBtn.textContent = '⏸ Pause'; + elements.pauseBtn.disabled = false; + } }); // Safety reset: restore button after 2.5s in case no peers respond setTimeout(() => {