mirror of
https://github.com/Shik3i/KoalaSync.git
synced 2026-08-24 17:56:27 +00:00
fix(extension): harden target frame recovery and switching
This commit is contained in:
+37
-24
@@ -468,12 +468,12 @@ async function init() {
|
||||
|
||||
// Keep a denied selection visible while Chrome waits for the user
|
||||
// to grant access; it becomes active automatically after approval.
|
||||
await populateTabs(res.peers, getSelectedTargetTabId(res));
|
||||
await populateTabs(res.peers, res.targetTabId);
|
||||
|
||||
// Render lobby status if active
|
||||
if (res.episodeLobby) updateLobbyUI(res.episodeLobby, res.peers);
|
||||
|
||||
if (res.status === 'connected' && !getSelectedTargetTabId(res) && localData.roomId) {
|
||||
if (res.status === 'connected' && normalizeTabId(res.targetTabId) === null && localData.roomId) {
|
||||
const syncTabBtn = document.querySelector('.tab-btn[data-tab="tab-sync"]');
|
||||
if (syncTabBtn) syncTabBtn.click();
|
||||
showSelectVideoHint();
|
||||
@@ -647,15 +647,6 @@ function handleTargetTabResponse(response) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function getSelectedTargetTabId(status) {
|
||||
return status?.selectedTargetTabId
|
||||
?? status?.requestedTargetTabId
|
||||
?? status?.targetTabId
|
||||
?? status?.pendingTargetTabId
|
||||
?? status?.activatingTargetTabId
|
||||
?? null;
|
||||
}
|
||||
|
||||
function selectTargetTab(tabId, tabTitle) {
|
||||
return new Promise(resolve => {
|
||||
chrome.runtime.sendMessage({ type: 'SET_TARGET_TAB', tabId, tabTitle }, response => {
|
||||
@@ -691,7 +682,7 @@ async function refreshTargetAccessState() {
|
||||
}
|
||||
await populateTabs(
|
||||
status.peers,
|
||||
getSelectedTargetTabId(status)
|
||||
status.targetTabId
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1231,14 +1222,14 @@ async function populateTabs(providedPeers = null, providedTargetTabId = null) {
|
||||
const blacklistDomains = getEffectiveBlacklistDomains(await readBlacklistOverrides());
|
||||
const isFilterActive = data.filterNoise !== false;
|
||||
|
||||
let currentTargetTabId = providedTargetTabId;
|
||||
let currentTargetTabId = normalizeTabId(providedTargetTabId);
|
||||
if (currentTargetTabId === null) {
|
||||
const status = await new Promise(r => chrome.runtime.sendMessage({ type: 'GET_STATUS' }, r));
|
||||
if (chrome.runtime.lastError) {
|
||||
if (populateTabsToken !== token) return;
|
||||
currentTargetTabId = null;
|
||||
} else {
|
||||
currentTargetTabId = getSelectedTargetTabId(status);
|
||||
currentTargetTabId = status?.targetTabId ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1269,7 +1260,7 @@ async function populateTabs(providedPeers = null, providedTargetTabId = null) {
|
||||
|
||||
const filteredTabs = tabs.filter(tab => {
|
||||
if (!tab.url || tab.url.startsWith('chrome://')) return false;
|
||||
if (isFilterActive && tab.id !== parseInt(currentTargetTabId)) {
|
||||
if (isFilterActive && currentTargetTabId !== null && tab.id !== currentTargetTabId) {
|
||||
if (isUrlBlacklisted(tab.url, blacklistDomains)) return false;
|
||||
}
|
||||
return true;
|
||||
@@ -1320,7 +1311,7 @@ async function populateTabs(providedPeers = null, providedTargetTabId = null) {
|
||||
// Sort: 1. Current tab first, 2. Matches, 3. Rest alphabetically
|
||||
const options = Array.from(elements.targetTab.options);
|
||||
const placeholder = options.shift();
|
||||
const currentTabId = currentTargetTabId ? parseInt(currentTargetTabId) : null;
|
||||
const currentTabId = currentTargetTabId;
|
||||
|
||||
options.sort((a, b) => {
|
||||
const aId = parseInt(a.value);
|
||||
@@ -1340,7 +1331,7 @@ async function populateTabs(providedPeers = null, providedTargetTabId = null) {
|
||||
elements.targetTab.appendChild(placeholder);
|
||||
options.forEach(opt => elements.targetTab.appendChild(opt));
|
||||
|
||||
if (currentTargetTabId) {
|
||||
if (currentTargetTabId !== null) {
|
||||
elements.targetTab.value = currentTargetTabId;
|
||||
} else {
|
||||
const matchOpt = options.find(o => o.textContent.includes('⭐ MATCH:'));
|
||||
@@ -1754,7 +1745,7 @@ if (elements.langSelector) {
|
||||
} else {
|
||||
hideSiteAccessNotice();
|
||||
}
|
||||
await populateTabs(res.peers, getSelectedTargetTabId(res));
|
||||
await populateTabs(res.peers, res.targetTabId);
|
||||
if (res.episodeLobby) updateLobbyUI(res.episodeLobby, res.peers);
|
||||
} else {
|
||||
applyConnectionStatus('disconnected');
|
||||
@@ -2103,7 +2094,7 @@ elements.forceSyncBtn.addEventListener('click', async () => {
|
||||
elements.forceSyncBtn.disabled = true;
|
||||
|
||||
const status = await new Promise(r => chrome.runtime.sendMessage({ type: 'GET_STATUS' }, r));
|
||||
if (chrome.runtime.lastError || !status || !status.targetTabId) {
|
||||
if (chrome.runtime.lastError || !status || status.targetReady !== true || normalizeTabId(status.targetTabId) === null) {
|
||||
elements.forceSyncBtn.disabled = false;
|
||||
return;
|
||||
}
|
||||
@@ -2169,7 +2160,8 @@ elements.forceSyncBtn.addEventListener('click', async () => {
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
resolve(normalizeTabId(currentStatus?.targetTabId) === tabId);
|
||||
resolve(currentStatus?.targetReady === true
|
||||
&& normalizeTabId(currentStatus?.targetTabId) === tabId);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2588,8 +2580,9 @@ elements.copyLogs.addEventListener('click', () => {
|
||||
logs = logs || [];
|
||||
history = history || [];
|
||||
|
||||
const videoPromise = (status && status.targetTabId)
|
||||
? new Promise(resolve => chrome.runtime.sendMessage({ type: 'GET_VIDEO_STATE', tabId: status.targetTabId }, resolve))
|
||||
const targetTabId = normalizeTabId(status.targetTabId);
|
||||
const videoPromise = (targetTabId !== null && status.targetReady === true)
|
||||
? new Promise(resolve => chrome.runtime.sendMessage({ type: 'GET_VIDEO_STATE', tabId: targetTabId }, resolve))
|
||||
: Promise.resolve(null);
|
||||
|
||||
videoPromise.then(rawVideo => {
|
||||
@@ -2609,6 +2602,11 @@ elements.copyLogs.addEventListener('click', () => {
|
||||
lines.push(`- **User Agent:** ${userAgent}`);
|
||||
lines.push('');
|
||||
|
||||
lines.push('## Target');
|
||||
lines.push(`- **Target Tab ID:** ${targetTabId ?? 'none'}`);
|
||||
lines.push(`- **Activation:** ${safe(status.targetActivationState, 'unknown')}`);
|
||||
lines.push('');
|
||||
|
||||
// ── Tab ──
|
||||
if (rawVideo) {
|
||||
lines.push('## Tab');
|
||||
@@ -2661,7 +2659,9 @@ elements.copyLogs.addEventListener('click', () => {
|
||||
// ── Video ──
|
||||
lines.push('## Video');
|
||||
if (!rawVideo) {
|
||||
lines.push('- *No tab selected / communication failed*');
|
||||
lines.push(targetTabId !== null
|
||||
? '- *Target tab selected; video communication is not ready yet*'
|
||||
: '- *No tab selected / communication failed*');
|
||||
} else if (!vs.found) {
|
||||
lines.push('- **Found:** \u274C NO VIDEO ELEMENT');
|
||||
if (vs.videoCount != null) lines.push(`- **Video Tags:** ${vs.videoCount}`);
|
||||
@@ -2801,11 +2801,24 @@ function refreshDebugInfo() {
|
||||
if (!devTab || devTab.style.display === 'none') return;
|
||||
|
||||
chrome.runtime.sendMessage({ type: 'GET_STATUS' }, (res) => {
|
||||
if (!res || !res.targetTabId) {
|
||||
if (!res || normalizeTabId(res.targetTabId) === null) {
|
||||
if (res?.targetActivationState === 'activating' || res?.targetActivationState === 'access_required') {
|
||||
if (elements.videoDebug) {
|
||||
elements.videoDebug.textContent = getMessage('DEBUG_TARGET_ACTIVATING');
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (elements.videoDebug) elements.videoDebug.textContent = getMessage('DEBUG_NO_TAB');
|
||||
return;
|
||||
}
|
||||
|
||||
if (res.targetReady !== true) {
|
||||
if (elements.videoDebug) {
|
||||
elements.videoDebug.textContent = getMessage('DEBUG_TARGET_ACTIVATING');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Request direct state from the content script via background
|
||||
chrome.runtime.sendMessage({ type: 'GET_VIDEO_STATE', tabId: res.targetTabId }, (state) => {
|
||||
if (!state || (!state.found && state.error)) {
|
||||
|
||||
Reference in New Issue
Block a user