From 51a5f43130b951d09f30eab21546ff4da2af56c8 Mon Sep 17 00:00:00 2001 From: Timo <6156589+Shik3i@users.noreply.github.com> Date: Wed, 22 Apr 2026 11:22:31 +0200 Subject: [PATCH] feat: add username support and fix invitation link server parsing --- extension/background.js | 31 ++++++++++++++++++++++++------- extension/bridge.js | 6 ++++-- extension/popup.html | 5 +++++ extension/popup.js | 14 ++++++++++++-- server/index.js | 15 ++++++++++----- website/app.js | 9 ++++++++- 6 files changed, 63 insertions(+), 17 deletions(-) diff --git a/extension/background.js b/extension/background.js index 0b4e627..4698a04 100644 --- a/extension/background.js +++ b/extension/background.js @@ -64,7 +64,8 @@ async function getSettings() { useCustomServer: data.useCustomServer || false, roomId: data.roomId || '', password: data.password || '', - targetTabId: data.targetTabId || null + targetTabId: data.targetTabId || null, + username: data.username || '' }); }); }); @@ -184,6 +185,7 @@ async function connect() { roomId: settings.roomId, password: settings.password, peerId, + username: settings.username, protocolVersion: PROTOCOL_VERSION }); } @@ -251,11 +253,18 @@ function showNotification(senderName, action) { action === 'seek' ? 'seeked the video' : action === 'force_sync_execute' ? 'synchronized everyone' : action; + // Find username in current room if available + let displayName = senderName || 'A peer'; + if (currentRoom && currentRoom.peers) { + const peer = currentRoom.peers.find(p => (p.peerId || p) === senderName); + if (peer && peer.username) displayName = peer.username; + } + chrome.notifications.create(`sync_${Date.now()}`, { type: 'basic', iconUrl: 'icons/icon128.png', title: 'KoalaSync', - message: `${senderName || 'A peer'} ${label}.`, + message: `${displayName} ${label}.`, priority: 1 }); } @@ -375,7 +384,7 @@ function handleServerEvent(event, data) { if (currentRoom) { if (data.status === 'joined') { if (!currentRoom.peers.find(p => (p.peerId || p) === data.peerId)) { - currentRoom.peers.push({ peerId: data.peerId, tabTitle: data.tabTitle }); + currentRoom.peers.push({ peerId: data.peerId, username: data.username, tabTitle: data.tabTitle }); chrome.runtime.sendMessage({ type: 'PEER_UPDATE', peers: currentRoom.peers }).catch(() => {}); } } else if (data.status === 'left') { @@ -387,10 +396,11 @@ function handleServerEvent(event, data) { if (peer) { if (typeof peer === 'object') { peer.tabTitle = data.tabTitle; + peer.username = data.username; } else { // Migration: replace string with object const idx = currentRoom.peers.indexOf(peer); - currentRoom.peers[idx] = { peerId: data.peerId, tabTitle: data.tabTitle }; + currentRoom.peers[idx] = { peerId: data.peerId, username: data.username, tabTitle: data.tabTitle }; } chrome.runtime.sendMessage({ type: 'PEER_UPDATE', peers: currentRoom.peers }).catch(() => {}); } @@ -511,8 +521,13 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { socket.send(`42${JSON.stringify([EVENTS.GET_ROOMS])}`); } } else if (message.type === 'WEB_JOIN_REQUEST') { - const { roomId, password } = message; - chrome.storage.sync.set({ roomId, password }, () => { + const { roomId, password, useCustomServer, serverUrl } = message; + chrome.storage.sync.set({ + roomId, + password, + useCustomServer: !!useCustomServer, + serverUrl: serverUrl || '' + }, () => { connect(); // We wait for status update in handleServerEvent }); @@ -558,7 +573,9 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { currentTabTitle = sender.tab.title ? sender.tab.title.substring(0, 50) : null; } // Peer status heartbeat from content script - emit(EVENTS.PEER_STATUS, { ...message.payload, peerId, tabTitle: currentTabTitle }); + getSettings().then(settings => { + emit(EVENTS.PEER_STATUS, { ...message.payload, peerId, username: settings.username, tabTitle: currentTabTitle }); + }); } return true; // Keep channel open for async responses }); diff --git a/extension/bridge.js b/extension/bridge.js index ca8a8ef..309eb6d 100644 --- a/extension/bridge.js +++ b/extension/bridge.js @@ -9,11 +9,13 @@ document.documentElement.dataset.koalasyncInstalled = 'true'; // 2. Listen for Join Requests from the Website window.addEventListener('KOALASYNC_JOIN_REQUEST', (e) => { - const { roomId, password } = e.detail; + const { roomId, password, useCustomServer, serverUrl } = e.detail; chrome.runtime.sendMessage({ type: 'WEB_JOIN_REQUEST', roomId, - password + password, + useCustomServer, + serverUrl }); }); diff --git a/extension/popup.html b/extension/popup.html index 1aacfb8..1c7965d 100644 --- a/extension/popup.html +++ b/extension/popup.html @@ -205,6 +205,11 @@
+
+ + +
+
diff --git a/extension/popup.js b/extension/popup.js index ad4d494..48a68f4 100644 --- a/extension/popup.js +++ b/extension/popup.js @@ -25,6 +25,7 @@ const elements = { serverCustom: document.getElementById('serverCustom'), roomId: document.getElementById('roomId'), password: document.getElementById('password'), + username: document.getElementById('username'), joinBtn: document.getElementById('joinBtn'), leaveBtn: document.getElementById('leaveBtn'), roomInfo: document.getElementById('roomInfo'), @@ -53,10 +54,11 @@ let lastPeersJson = null; // --- Initialization --- async function init() { // Load Settings - const data = await chrome.storage.sync.get(['serverUrl', 'useCustomServer', 'roomId', 'password', 'targetTabId', 'filterNoise']); + const data = await chrome.storage.sync.get(['serverUrl', 'useCustomServer', 'roomId', 'password', 'targetTabId', 'filterNoise', 'username']); elements.serverUrl.value = data.serverUrl || ''; elements.roomId.value = data.roomId || ''; elements.password.value = data.password || ''; + elements.username.value = data.username || ''; elements.filterNoise.checked = data.filterNoise !== false; if (data.useCustomServer) { @@ -121,12 +123,16 @@ function updatePeerList(peers) { const html = peers.map(p => { const id = escapeHtml(typeof p === 'object' ? p.peerId : p); + const username = (typeof p === 'object' && p.username) ? escapeHtml(p.username) : ''; const titleText = (typeof p === 'object' && p.tabTitle) ? escapeHtml(p.tabTitle) : ''; + + const nameLabel = username ? `${username} (${id})` : `👤 ${id}`; const title = titleText ? `
${titleText}
` : ''; + return `
- 👤 ${id} + ${nameLabel} ${id === escapeHtml(localPeerId) ? 'YOU' : ''}
${title} @@ -333,6 +339,10 @@ elements.serverUrl.addEventListener('input', () => { chrome.storage.sync.set({ serverUrl: elements.serverUrl.value }); }); +elements.username.addEventListener('change', () => { + chrome.storage.sync.set({ username: elements.username.value }); +}); + elements.serverUrl.addEventListener('change', () => { let url = elements.serverUrl.value.trim(); if (url && !url.includes('://')) { diff --git a/server/index.js b/server/index.js index 99d012f..ebbe94b 100644 --- a/server/index.js +++ b/server/index.js @@ -154,7 +154,7 @@ io.on('connection', (socket) => { return; } if (!payload || typeof payload.roomId !== 'string') return; - const { roomId, password, peerId, protocolVersion } = payload; + const { roomId, password, peerId, username, protocolVersion } = payload; try { // Protocol check if (protocolVersion !== '1.0.0') { @@ -237,10 +237,10 @@ io.on('connection', (socket) => { socket.join(roomId); room.peers.add(socket.id); room.peerIds.set(socket.id, peerId); - room.peerData.set(socket.id, { peerId, tabTitle: null }); + room.peerData.set(socket.id, { peerId, username: username || null, tabTitle: null }); socketToRoom.set(socket.id, { roomId, peerId }); - socket.to(roomId).emit(EVENTS.PEER_STATUS, { peerId, status: 'joined' }); + socket.to(roomId).emit(EVENTS.PEER_STATUS, { peerId, username: username || null, status: 'joined' }); socket.emit(EVENTS.ROOM_DATA, { roomId, peers: Array.from(room.peers).map(sid => room.peerData.get(sid)) @@ -275,8 +275,13 @@ io.on('connection', (socket) => { if (room) { room.lastActivity = Date.now(); // Update metadata if it's a peer_status (heartbeat) - if (eventName === EVENTS.PEER_STATUS && data.tabTitle) { - room.peerData.set(socket.id, { peerId: mapping.peerId, tabTitle: data.tabTitle }); + if (eventName === EVENTS.PEER_STATUS && (data.tabTitle || data.username)) { + const existing = room.peerData.get(socket.id) || { peerId: mapping.peerId }; + room.peerData.set(socket.id, { + ...existing, + username: data.username || existing.username, + tabTitle: data.tabTitle || existing.tabTitle + }); } } socket.to(mapping.roomId).emit(eventName, { ...data, senderId: mapping.peerId }); diff --git a/website/app.js b/website/app.js index 678fa06..4c8b8e2 100644 --- a/website/app.js +++ b/website/app.js @@ -61,6 +61,8 @@ document.addEventListener('DOMContentLoaded', () => { if (parts.length >= 3) { const roomId = parts[1]; const password = parts[2]; + const serverFlag = parts[3] || '0'; + const serverUrl = parts[4] ? decodeURIComponent(parts[4]) : ''; if (isJoinPage) { const displayRoom = document.getElementById('display-room-id'); @@ -103,7 +105,12 @@ document.addEventListener('DOMContentLoaded', () => { e.target.textContent = 'JOINING...'; e.target.disabled = true; window.dispatchEvent(new CustomEvent('KOALASYNC_JOIN_REQUEST', { - detail: { roomId, password } + detail: { + roomId, + password, + useCustomServer: serverFlag === '1', + serverUrl: serverUrl + } })); } });