diff --git a/README.md b/README.md index 50e0ac7..b977db7 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

Release Status - GitHub release + GitHub release License Firefox Add-on Chrome Extension @@ -14,7 +14,7 @@

KoalaSync is a lightweight Browser Extension and Relay Server for synchronized video playback on almost any website with a video element—YouTube, Twitch, Netflix, Emby, Jellyfin, and beyond. Built with a focus on Data Sovereignty and Performance.

-

New v2.4.5 Release! — See what's changed

+

New v2.4.6 Release! — See what's changed

### 🌟 Why KoalaSync? diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 8aa6869..259e29c 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to the KoalaSync browser extension and relay server. --- -## [v2.4.5] — 2026-06-23 +## [v2.4.6] — 2026-06-23 ### Fixed - **Room and settings are no longer stored in `chrome.storage.sync`** — Room ID, password, and username were being resurrected from synced storage on a fresh install (sync survives an uninstall in the user's Google account), which made the extension silently auto-connect to a dead room and appear permanently connected. `getSettings()` and all settings reads are now local-only, and legacy keys are actively purged from sync on install/update/startup. Only `onboardingComplete` and `dismissedHints` remain in sync. diff --git a/extension/background.js b/extension/background.js index 772d7f3..04b78e4 100644 --- a/extension/background.js +++ b/extension/background.js @@ -639,6 +639,12 @@ async function connect() { function broadcastConnectionStatus(status) { + // No room and no intent to connect → this isn't a failure, it's the normal + // resting state. Surface a distinct 'idle' status so the UI can say + // "ready to connect" instead of a misleading red "Disconnected". + if (status === 'disconnected' && !currentRoom && !connectIntent) { + status = 'idle'; + } chrome.runtime.sendMessage({ type: 'CONNECTION_STATUS', status }).catch(() => {}); updateBadgeStatus(); } @@ -1574,6 +1580,8 @@ async function handleAsyncMessage(message, sender, sendResponse) { const isConnected = socket && socket.readyState === WebSocket.OPEN && isNamespaceJoined; const isReconnecting = !isConnected && reconnectAttempts > 0; let status = isConnected ? 'connected' : (isConnecting || (socket && socket.readyState === WebSocket.CONNECTING) ? 'connecting' : (isReconnecting ? 'reconnecting' : 'disconnected')); + // Distinguish the normal "not in a room" resting state from a real drop. + if (status === 'disconnected' && !currentRoom && !connectIntent) status = 'idle'; sendResponse({ status, peerId, diff --git a/extension/locales/de.json b/extension/locales/de.json index 5a1c219..10a8a9f 100644 --- a/extension/locales/de.json +++ b/extension/locales/de.json @@ -143,6 +143,8 @@ "STATUS_CONNECTING": "Verbinde...", "STATUS_FAILED": "Fehlgeschlagen", "STATUS_DISCONNECTED": "Getrennt", + "STATUS_IDLE": "Bereit zum Verbinden", + "STATUS_IDLE_TOOLTIP": "KoalaSync ist bereit. Tritt einem Raum bei oder erstelle einen, um die Verbindung herzustellen und die Synchronisierung zu starten.", "BTN_STATE_JOINING": "🚀 Trete bei...", "BTN_STATE_RECONNECTING": "🔄 Verbinde erneut...", "BTN_STATE_PLAYING": "▶ Spiele ab...", diff --git a/extension/locales/en.json b/extension/locales/en.json index e69ad8c..789abff 100644 --- a/extension/locales/en.json +++ b/extension/locales/en.json @@ -143,6 +143,8 @@ "STATUS_CONNECTING": "Connecting...", "STATUS_FAILED": "Failed", "STATUS_DISCONNECTED": "Disconnected", + "STATUS_IDLE": "Ready to connect", + "STATUS_IDLE_TOOLTIP": "KoalaSync is ready. Join or create a room to connect and start syncing.", "BTN_STATE_JOINING": "🚀 Joining...", "BTN_STATE_RECONNECTING": "🔄 Reconnecting...", "BTN_STATE_PLAYING": "▶ Playing...", diff --git a/extension/locales/es.json b/extension/locales/es.json index 36c0a18..186678e 100644 --- a/extension/locales/es.json +++ b/extension/locales/es.json @@ -143,6 +143,8 @@ "STATUS_CONNECTING": "Conectando...", "STATUS_FAILED": "Error", "STATUS_DISCONNECTED": "Desconectado", + "STATUS_IDLE": "Listo para conectar", + "STATUS_IDLE_TOOLTIP": "KoalaSync está listo. Únete o crea una sala para conectarte y empezar a sincronizar.", "BTN_STATE_JOINING": "🚀 Uniéndose...", "BTN_STATE_RECONNECTING": "🔄 Reconectando...", "BTN_STATE_PLAYING": "▶ Reproduciendo...", diff --git a/extension/locales/fr.json b/extension/locales/fr.json index 0095d10..27db35b 100644 --- a/extension/locales/fr.json +++ b/extension/locales/fr.json @@ -143,6 +143,8 @@ "STATUS_CONNECTING": "Connexion...", "STATUS_FAILED": "Échec", "STATUS_DISCONNECTED": "Déconnecté", + "STATUS_IDLE": "Prêt à se connecter", + "STATUS_IDLE_TOOLTIP": "KoalaSync est prêt. Rejoignez ou créez un salon pour vous connecter et commencer la synchronisation.", "BTN_STATE_JOINING": "🚀 Connexion...", "BTN_STATE_RECONNECTING": "🔄 Reconnexion...", "BTN_STATE_PLAYING": "▶ Lecture...", diff --git a/extension/locales/it.json b/extension/locales/it.json index 7c7c059..5217462 100644 --- a/extension/locales/it.json +++ b/extension/locales/it.json @@ -143,6 +143,8 @@ "STATUS_CONNECTING": "Connessione in corso...", "STATUS_FAILED": "Errore", "STATUS_DISCONNECTED": "Disconnesso", + "STATUS_IDLE": "Pronto a connettersi", + "STATUS_IDLE_TOOLTIP": "KoalaSync è pronto. Entra o crea una stanza per connetterti e avviare la sincronizzazione.", "BTN_STATE_JOINING": "🚀 Entrando...", "BTN_STATE_RECONNECTING": "🔄 Riconnessione...", "BTN_STATE_PLAYING": "▶ In riproduzione...", diff --git a/extension/locales/ja.json b/extension/locales/ja.json index 77f3222..afa8ed2 100644 --- a/extension/locales/ja.json +++ b/extension/locales/ja.json @@ -143,6 +143,8 @@ "STATUS_CONNECTING": "接続中...", "STATUS_FAILED": "失敗", "STATUS_DISCONNECTED": "切断されました", + "STATUS_IDLE": "接続準備完了", + "STATUS_IDLE_TOOLTIP": "KoalaSyncの準備ができました。ルームに参加するか作成して接続し、同期を開始してください。", "BTN_STATE_JOINING": "🚀 参加中...", "BTN_STATE_RECONNECTING": "🔄 再接続中...", "BTN_STATE_PLAYING": "▶ 再生中...", diff --git a/extension/locales/ko.json b/extension/locales/ko.json index e3dc411..fd20147 100644 --- a/extension/locales/ko.json +++ b/extension/locales/ko.json @@ -143,6 +143,8 @@ "STATUS_CONNECTING": "연결 중...", "STATUS_FAILED": "실패", "STATUS_DISCONNECTED": "연결 끊김", + "STATUS_IDLE": "연결 준비 완료", + "STATUS_IDLE_TOOLTIP": "KoalaSync가 준비되었습니다. 방에 참여하거나 생성하여 연결하고 동기화를 시작하세요.", "BTN_STATE_JOINING": "🚀 참여 중...", "BTN_STATE_RECONNECTING": "🔄 재연결 중...", "BTN_STATE_PLAYING": "▶ 재생 중...", diff --git a/extension/locales/nl.json b/extension/locales/nl.json index 83c5583..cfef8a6 100644 --- a/extension/locales/nl.json +++ b/extension/locales/nl.json @@ -143,6 +143,8 @@ "STATUS_CONNECTING": "Verbinden...", "STATUS_FAILED": "Mislukt", "STATUS_DISCONNECTED": "Verbinding verbroken", + "STATUS_IDLE": "Gereed om te verbinden", + "STATUS_IDLE_TOOLTIP": "KoalaSync is gereed. Neem deel aan een kamer of maak er een aan om te verbinden en te synchroniseren.", "BTN_STATE_JOINING": "🚀 Deelnemen...", "BTN_STATE_RECONNECTING": "🔄 Opnieuw verbinden...", "BTN_STATE_PLAYING": "▶ Afspelen...", diff --git a/extension/locales/pl.json b/extension/locales/pl.json index 53f3ef3..a7fe42c 100644 --- a/extension/locales/pl.json +++ b/extension/locales/pl.json @@ -143,6 +143,8 @@ "STATUS_CONNECTING": "Łączenie...", "STATUS_FAILED": "Nieudane", "STATUS_DISCONNECTED": "Rozłączono", + "STATUS_IDLE": "Gotowy do połączenia", + "STATUS_IDLE_TOOLTIP": "KoalaSync jest gotowy. Dołącz do pokoju lub utwórz go, aby się połączyć i rozpocząć synchronizację.", "BTN_STATE_JOINING": "🚀 Dołączanie...", "BTN_STATE_RECONNECTING": "🔄 Ponowne łączenie...", "BTN_STATE_PLAYING": "▶ Odtwarzanie...", diff --git a/extension/locales/pt-BR.json b/extension/locales/pt-BR.json index 64b38eb..9a9c608 100644 --- a/extension/locales/pt-BR.json +++ b/extension/locales/pt-BR.json @@ -143,6 +143,8 @@ "STATUS_CONNECTING": "Conectando...", "STATUS_FAILED": "Falhou", "STATUS_DISCONNECTED": "Desconectado", + "STATUS_IDLE": "Pronto para conectar", + "STATUS_IDLE_TOOLTIP": "O KoalaSync está pronto. Entre ou crie uma sala para conectar e começar a sincronizar.", "BTN_STATE_JOINING": "🚀 Entrando...", "BTN_STATE_RECONNECTING": "🔄 Reconectando...", "BTN_STATE_PLAYING": "▶ Reproduzindo...", diff --git a/extension/locales/pt.json b/extension/locales/pt.json index e9da913..f5ab295 100644 --- a/extension/locales/pt.json +++ b/extension/locales/pt.json @@ -143,6 +143,8 @@ "STATUS_CONNECTING": "A ligar...", "STATUS_FAILED": "Falhou", "STATUS_DISCONNECTED": "Desligado", + "STATUS_IDLE": "Pronto para ligar", + "STATUS_IDLE_TOOLTIP": "O KoalaSync está pronto. Entre ou crie uma sala para ligar e iniciar a sincronização.", "BTN_STATE_JOINING": "🚀 A entrar...", "BTN_STATE_RECONNECTING": "🔄 A voltar a ligar...", "BTN_STATE_PLAYING": "▶ A reproduzir...", diff --git a/extension/locales/ru.json b/extension/locales/ru.json index 0e9abfb..f21e738 100644 --- a/extension/locales/ru.json +++ b/extension/locales/ru.json @@ -143,6 +143,8 @@ "STATUS_CONNECTING": "Подключение...", "STATUS_FAILED": "Ошибка", "STATUS_DISCONNECTED": "Отключено", + "STATUS_IDLE": "Готов к подключению", + "STATUS_IDLE_TOOLTIP": "KoalaSync готов. Присоединитесь к комнате или создайте её, чтобы подключиться и начать синхронизацию.", "BTN_STATE_JOINING": "🚀 Вход...", "BTN_STATE_RECONNECTING": "🔄 Переподключение...", "BTN_STATE_PLAYING": "▶ Запуск...", diff --git a/extension/locales/tr.json b/extension/locales/tr.json index fd7e4eb..43dd76a 100644 --- a/extension/locales/tr.json +++ b/extension/locales/tr.json @@ -143,6 +143,8 @@ "STATUS_CONNECTING": "Bağlanılıyor...", "STATUS_FAILED": "Başarısız", "STATUS_DISCONNECTED": "Bağlantı Kesildi", + "STATUS_IDLE": "Bağlanmaya hazır", + "STATUS_IDLE_TOOLTIP": "KoalaSync hazır. Bağlanmak ve senkronizasyonu başlatmak için bir odaya katılın veya oluşturun.", "BTN_STATE_JOINING": "🚀 Katılınıyor...", "BTN_STATE_RECONNECTING": "🔄 Yeniden bağlanılıyor...", "BTN_STATE_PLAYING": "▶ Oynatılıyor...", diff --git a/extension/locales/uk.json b/extension/locales/uk.json index ddc3a8d..9ab3c28 100644 --- a/extension/locales/uk.json +++ b/extension/locales/uk.json @@ -143,6 +143,8 @@ "STATUS_CONNECTING": "Підключення...", "STATUS_FAILED": "Не вдалося", "STATUS_DISCONNECTED": "Відключено", + "STATUS_IDLE": "Готовий до підключення", + "STATUS_IDLE_TOOLTIP": "KoalaSync готовий. Приєднайтеся до кімнати або створіть її, щоб підключитися та почати синхронізацію.", "BTN_STATE_JOINING": "🚀 Приєднуюсь...", "BTN_STATE_RECONNECTING": "🔄 Повторне підключення...", "BTN_STATE_PLAYING": "▶ Грає...", diff --git a/extension/locales/zh.json b/extension/locales/zh.json index 40ab7d4..f414d05 100644 --- a/extension/locales/zh.json +++ b/extension/locales/zh.json @@ -143,6 +143,8 @@ "STATUS_CONNECTING": "正在连接...", "STATUS_FAILED": "失败的", "STATUS_DISCONNECTED": "已断开连接", + "STATUS_IDLE": "已准备好连接", + "STATUS_IDLE_TOOLTIP": "KoalaSync 已准备就绪。加入或创建房间以连接并开始同步。", "BTN_STATE_JOINING": "🚀 正在加入...", "BTN_STATE_RECONNECTING": "🔄 正在重新连接...", "BTN_STATE_PLAYING": "▶ 播放中...", diff --git a/extension/manifest.base.json b/extension/manifest.base.json index cca35a4..07a3c6f 100644 --- a/extension/manifest.base.json +++ b/extension/manifest.base.json @@ -2,7 +2,7 @@ "manifest_version": 3, "default_locale": "en", "name": "KoalaSync", - "version": "2.4.5", + "version": "2.4.6", "description": "Synchronize video playback on YouTube, Netflix, Emby, Jellyfin, and any HTML5 site in real-time with friends.", "permissions": [ "storage", diff --git a/extension/popup.html b/extension/popup.html index 47411da..bb4fb4c 100644 --- a/extension/popup.html +++ b/extension/popup.html @@ -613,7 +613,10 @@
- Disconnected + + Disconnected + + diff --git a/extension/popup.js b/extension/popup.js index 5f5467f..3d94f60 100644 --- a/extension/popup.js +++ b/extension/popup.js @@ -16,6 +16,7 @@ const elements = { clearLogs: document.getElementById('clearLogs'), connDot: document.getElementById('connDot'), connText: document.getElementById('connText'), + connInfo: document.getElementById('connInfo'), connPing: document.getElementById('connPing'), serverUrl: document.getElementById('serverUrl'), serverOfficial: document.getElementById('serverOfficial'), @@ -245,9 +246,9 @@ async function init() { lastKnownPeers = res.peers || []; if (res.lastActionState) updateLastActionUI(res.lastActionState, res.peers); - // If user has a room configured but background is not connected, + // If user has a room configured but background is not connected (disconnected or idle), // trigger connection now — the popup opening is explicit user intent. - if (res.status === 'disconnected' && localData.roomId) { + if ((res.status === 'disconnected' || res.status === 'idle') && localData.roomId) { chrome.runtime.sendMessage({ type: 'CONNECT' }).catch(() => {}); applyConnectionStatus('connecting'); } @@ -818,19 +819,33 @@ async function populateTabs(providedPeers = null, providedTargetTabId = null) { } function applyConnectionStatus(status) { + // Coerce 'idle' to 'disconnected' if a room is actively configured. + // An 'idle' status with a configured room indicates the background + // worker dropped connection intent due to a server error. + if (status === 'idle' && elements.sectionActive && elements.sectionActive.style.display !== 'none') { + status = 'disconnected'; + } + const connected = status === 'connected'; const connecting = status === 'connecting'; const reconnecting = status === 'reconnecting'; + // 'idle' = not in a room and not trying to connect. This is the normal + // resting state (lazy connect), NOT an error — surface it neutrally. + const idle = status === 'idle'; if (elements.connDot) { elements.connDot.className = 'status-dot ' + (connected ? 'status-online' : ((connecting || reconnecting) ? 'status-online' : 'status-offline')); - + if (reconnecting) { elements.connDot.style.background = '#f59e0b'; elements.connDot.style.boxShadow = '0 0 8px #f59e0b'; } else if (connecting) { elements.connDot.style.background = '#fbbf24'; elements.connDot.style.boxShadow = '0 0 8px #fbbf24'; + } else if (idle) { + // Neutral grey — ready, not failed. + elements.connDot.style.background = '#9ca3af'; + elements.connDot.style.boxShadow = 'none'; } else if (!connected) { elements.connDot.style.background = '#ef4444'; elements.connDot.style.boxShadow = 'none'; @@ -841,7 +856,12 @@ function applyConnectionStatus(status) { } if (elements.connText) { - elements.connText.textContent = connected ? getMessage('STATUS_CONNECTED') : (reconnecting ? getMessage('STATUS_RECONNECTING') : (connecting ? getMessage('STATUS_CONNECTING') : getMessage('STATUS_DISCONNECTED'))); + elements.connText.textContent = connected ? getMessage('STATUS_CONNECTED') : (reconnecting ? getMessage('STATUS_RECONNECTING') : (connecting ? getMessage('STATUS_CONNECTING') : (idle ? getMessage('STATUS_IDLE') : getMessage('STATUS_DISCONNECTED')))); + } + + // Show the info "i" + tooltip only in the idle state. + if (elements.connInfo) { + elements.connInfo.style.display = idle ? '' : 'none'; } if (!connected) { updatePingDisplay(null); diff --git a/package.json b/package.json index 7c047b8..b569683 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "koalasync", - "version": "2.4.5", + "version": "2.4.6", "description": "KoalaSync Build Scripts", "private": true, "type": "module", diff --git a/shared/constants.js b/shared/constants.js index 7e60f7d..40ddbce 100644 --- a/shared/constants.js +++ b/shared/constants.js @@ -7,7 +7,7 @@ */ export const PROTOCOL_VERSION = "1.0.0"; -export const APP_VERSION = "2.4.5"; +export const APP_VERSION = "2.4.6"; export const OFFICIAL_SERVER_URL = 'wss://syncserver.koalastuff.net'; export const OFFICIAL_LANDING_PAGE_URL = 'https://sync.koalastuff.net'; diff --git a/website/template.html b/website/template.html index 0c1bc12..069e921 100644 --- a/website/template.html +++ b/website/template.html @@ -106,7 +106,7 @@ "priceCurrency": "EUR" }, "description": "{{SCHEMA_APP_DESC}}", - "softwareVersion": "2.4.5", + "softwareVersion": "2.4.6", "license": "https://opensource.org/licenses/MIT", "sameAs": "https://github.com/Shik3i/KoalaSync", "image": "https://sync.koalastuff.net/assets/NewLogoIcon.webp",