diff --git a/douyin/background.js b/douyin/background.js index cc926bf..07c9301 100644 --- a/douyin/background.js +++ b/douyin/background.js @@ -58,86 +58,83 @@ const windowProxyMap = new Map(); // 修改代理设置函数 function setProxyForWindow(proxyConfig, windowId, callback) { - const maxRetries = 3; - let retryCount = 0; - - function trySetProxy() { - console.log(`窗口 ${windowId} 设置代理尝试 ${retryCount + 1}/${maxRetries}:`, proxyConfig); - - // 存储当前窗口的代理设置 - windowProxyMap.set(windowId, proxyConfig); - - // 设置新的代理 - const config = { - value: { - mode: "fixed_servers", - rules: { - singleProxy: { - scheme: "http", - host: proxyConfig.host, - port: parseInt(proxyConfig.port) - }, - bypassList: [ - "localhost", - "127.0.0.1", - "" - ] - } - }, - scope: "regular" + console.log(`设置窗口 ${windowId} 的代理:`, { + host: proxyConfig.host, + port: proxyConfig.port, + username: proxyConfig.username + }); + + // 存储当前窗口的代理设置 + windowProxyMap.set(windowId, proxyConfig); + + // 设置认证监听器 + const authHandler = function(details) { + return { + authCredentials: { + username: proxyConfig.username, + password: proxyConfig.password + } }; + }; + + // 移除之前的监听器(如果存在) + try { + chrome.webRequest.onAuthRequired.removeListener(authHandler); + } catch (e) {} + + // 添加新的监听器 + chrome.webRequest.onAuthRequired.addListener( + authHandler, + { urls: [""] }, + ["asyncBlocking"] + ); - chrome.proxy.settings.set( - config, - function() { - if (chrome.runtime.lastError) { - console.error('设置代理失败:', chrome.runtime.lastError); - handleError(chrome.runtime.lastError); - return; + // 设置代理配置 + const config = { + value: { + mode: "fixed_servers", + rules: { + singleProxy: { + scheme: "http", + host: proxyConfig.host, + port: parseInt(proxyConfig.port) } + } + }, + scope: "regular" + }; + + // 设置代理 + chrome.proxy.settings.set( + config, + function() { + if (chrome.runtime.lastError) { + console.error('设置代理失败:', chrome.runtime.lastError); + callback(chrome.runtime.lastError); + return; + } - // 验证代理设置 - chrome.proxy.settings.get( - { incognito: false }, - function(config) { - console.log(`窗口 ${windowId} 当前代理配置:`, config); - if (config.value.mode === "fixed_servers") { - // 只刷新当前窗口的标签页 - chrome.tabs.query({ windowId: windowId }, function(tabs) { - let refreshedCount = 0; - if (tabs.length === 0) { - callback(null, true); - return; - } + console.log(`窗口 ${windowId} 代理设置成功`); + + // 刷新标签页 + chrome.tabs.query({ windowId: windowId }, function(tabs) { + if (tabs.length === 0) { + callback(null, true); + return; + } - tabs.forEach(function(tab) { - chrome.tabs.reload(tab.id, { bypassCache: true }, function() { - refreshedCount++; - if (refreshedCount === tabs.length) { - callback(null, true); - } - }); - }); - }); - } else { - handleError(new Error('代理设置验证失败')); + let refreshedCount = 0; + tabs.forEach(function(tab) { + chrome.tabs.reload(tab.id, { bypassCache: true }, function() { + refreshedCount++; + if (refreshedCount === tabs.length) { + callback(null, true); } - } - ); - } - ); - } - - function handleError(error) { - if (retryCount < maxRetries - 1) { - retryCount++; - setTimeout(trySetProxy, 2000); - } else { - callback(error); + }); + }); + }); } - } - - trySetProxy(); + ); } // 消息监听器 @@ -219,7 +216,7 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { }) .catch(error => { console.error('登录请求出错:', error); - sendResponse({ status: 'error', message: '登录请求出错,请检查网络连接或稍后重试。' }); + sendResponse({ status: 'error', message: '登录请出错,请检查网络连接或稍后重试。' }); }); } @@ -245,14 +242,14 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { console.error('设置代理失败:', error); sendResponse({ success: false, error: error.message }); } else { - console.log('代理已设置到新创建的无痕窗口'); + console.log('代理已设置到新创建无痕窗口'); sendResponse({ success: true }); } } ); }, 1000); } else { - console.error('创建窗口失败'); + console.error('建窗口失败'); sendResponse({ success: false, error: '创建窗口失败' }); } }); @@ -266,46 +263,84 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { const proxyList = request.proxyList; console.log('可用代理列表:', proxyList); - if (proxyList.length < incognitoWindows.length) { + if (proxyList.length === 0) { sendResponse({ success: false, - error: `代理数量不足,需要 ${incognitoWindows.length} 个代理,但只有 ${proxyList.length} 个` + error: '没有可用的代理' }); return; } let completedCount = 0; let errors = []; + let currentIndex = 0; + + // 处理下一个窗口 + function processNextWindow() { + if (currentIndex >= incognitoWindows.length) { + checkComplete(); + return; + } - // 为每个窗口单独设置代理 - incognitoWindows.forEach((window, index) => { - const proxy = proxyList[index]; - const [host, port] = proxy.split(':'); + const window = incognitoWindows[currentIndex]; + + // 检查窗口是否已经有代理设置 + const existingProxy = windowProxyMap.get(window.id); + if (existingProxy) { + console.log(`窗口 ${window.id} 已有代理设置,跳过:`, { + host: existingProxy.host, + port: existingProxy.port, + username: existingProxy.username + }); + completedCount++; + currentIndex++; + processNextWindow(); + return; + } - if (!host || !port) { - errors.push(`代理格式错误: ${proxy}`); + // 使用循环方式获取代理配置 + const proxyIndex = currentIndex % proxyList.length; + const proxy = proxyList[proxyIndex]; + + if (!proxy || !proxy.host || !proxy.port) { + errors.push(`代理配置无效: ${JSON.stringify(proxy)}`); completedCount++; - checkComplete(); + currentIndex++; + processNextWindow(); return; } - // 为每个窗口设置代理时先激活该窗口 + console.log(`窗口 ${window.id} 使用第 ${proxyIndex + 1} 个代理 (总共 ${proxyList.length} 个)`); + + // 为窗口设置代理 chrome.windows.update(window.id, { focused: true }, () => { setTimeout(() => { setProxyForWindow( - { host, port: parseInt(port) }, + proxy, window.id, (error, success) => { if (error) { + console.error(`窗口 ${window.id} 设置代理失败:`, error); errors.push(`窗口 ${window.id} 设置代理失败: ${error.message}`); + } else { + console.log(`窗口 ${window.id} 使用代理:`, { + host: proxy.host, + port: proxy.port, + username: proxy.username, + password: proxy.password + }); } completedCount++; - checkComplete(); + currentIndex++; + setTimeout(processNextWindow, 1000); // 等待1秒后处理下一个窗口 } ); - }, index * 3000); // 每个窗口间隔3秒 + }, 1000); }); - }); + } + + // 开始处理第一个窗口 + processNextWindow(); function checkComplete() { if (completedCount === incognitoWindows.length) { @@ -317,33 +352,138 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { } else { sendResponse({ success: true, - message: `已为 ${incognitoWindows.length} 个无痕窗口设置独立代理` + message: `已为 ${incognitoWindows.length} 个无痕窗口设置代理` }); } } } } else { - sendResponse({ success: false, error: '未找到无痕窗��' }); + sendResponse({ success: false, error: '未找到无痕窗口' }); } }); return true; } if (request.action === 'clearProxy') { - chrome.proxy.settings.clear( - { - scope: "regular" - }, - () => { - if (chrome.runtime.lastError) { - console.error('清除代理失败:', chrome.runtime.lastError); - sendResponse({ success: false, error: chrome.runtime.lastError.message }); - } else { - console.log('代理设置已完全清除'); - sendResponse({ success: true }); + try { + // 清除代理设置 + chrome.proxy.settings.clear( + { scope: "regular" }, + async function() { + if (chrome.runtime.lastError) { + console.error('清除代理设置失败:', chrome.runtime.lastError); + sendResponse({ success: false, error: chrome.runtime.lastError.message }); + return; + } + + console.log('代理设置已清除'); + + try { + // 获取所有窗口 + const windows = await new Promise((resolve) => { + chrome.windows.getAll({ + populate: true + }, resolve); + }); + + // 清除代理映射 + windowProxyMap.clear(); + console.log('代理映射已清除'); + + // 清除认证缓存 + const removeCache = async () => { + try { + await chrome.browsingData.remove({ + "since": 0 + }, { + "cache": true, + "cookies": true, + "passwords": true, + "webSQL": true, + "serviceWorkers": true, + "indexedDB": true + }); + console.log('认证缓存已清除'); + } catch (error) { + console.error('清除认证缓存失败:', error); + } + }; + + await removeCache(); + + // 刷新所有无痕窗口的标签页 + for (const window of windows) { + if (window.incognito) { + console.log(`刷新无痕窗口 ${window.id} 的标签页`); + for (const tab of window.tabs) { + try { + // 先导航到空白页面 + await new Promise((resolve) => { + chrome.tabs.update(tab.id, { url: 'about:blank' }, resolve); + }); + await new Promise(resolve => setTimeout(resolve, 500)); + + // 然后重新加载原始URL + await new Promise((resolve) => { + chrome.tabs.reload(tab.id, { bypassCache: true }, resolve); + }); + // 添加短暂延迟,避免同时刷新太多标签页 + await new Promise(resolve => setTimeout(resolve, 500)); + } catch (error) { + console.error(`刷新标签页 ${tab.id} 失败:`, error); + } + } + } + } + + sendResponse({ + success: true, + message: '已清除所有代理设置、认证缓存并刷新标签页' + }); + } catch (error) { + console.error('刷新标签页时出错:', error); + sendResponse({ + success: false, + error: '清除代理成功但刷新标签页失败: ' + error.message + }); + } } + ); + } catch (error) { + console.error('清除代理时出错:', error); + sendResponse({ success: false, error: error.message }); + } + return true; + } + + if (request.action === 'getCurrentProxy') { + try { + const windowId = request.windowId; + const proxyConfig = windowProxyMap.get(windowId); + + if (proxyConfig) { + sendResponse({ + success: true, + proxy: { + host: proxyConfig.host, + port: proxyConfig.port, + username: proxyConfig.username + // 出于安全考虑,不返回密码 + } + }); + } else { + sendResponse({ + success: true, + proxy: null + }); } - ); + } catch (error) { + console.error('获取代理信息失败:', error); + sendResponse({ + success: false, + error: error.message + }); + } return true; } @@ -356,7 +496,7 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { }); chrome.windows.onCreated.addListener((window) => { - console.log('新窗口创建:', { + console.log('新窗口创:', { id: window.id, incognito: window.incognito, type: window.type, @@ -375,21 +515,23 @@ chrome.tabs.onCreated.addListener((tab) => { }); }); -// 修改错误监听器,添加更多需要忽略的错误类型 +// 修改错误监听器,添加更多需要忽略的误类型 chrome.webRequest.onErrorOccurred.addListener( function(details) { // 扩展需要忽略的错误类型列表 const ignoredErrors = [ - 'net::ERR_ABORTED', // 请求中断 - 'net::ERR_NETWORK_CHANGED', // 网络变化 - 'net::ERR_CONNECTION_CLOSED', // 连接关闭 - 'net::ERR_CACHE_MISS', // 缓存未命中 - 'net::ERR_EMPTY_RESPONSE', // 空响应 - 'net::ERR_FAILED', // 一般性失败 - 'net::ERR_TIMED_OUT' // 超时 + 'net::ERR_ABORTED', // 请求中断 + 'net::ERR_NETWORK_CHANGED', // 网络变化 + 'net::ERR_CONNECTION_CLOSED', // 连接关闭 + 'net::ERR_CACHE_MISS', // 缓存未命中 + 'net::ERR_EMPTY_RESPONSE', // 空响应 + 'net::ERR_FAILED', // 一般性失败 + 'net::ERR_TIMED_OUT', // 超时 + 'net::ERR_TOO_MANY_RETRIES', // 重试次数过多 + 'net::ERR_TUNNEL_CONNECTION_FAILED' // 隧道连接失败 ]; - // 忽略的资源类型 + // 略的资源类型 const ignoredResourceTypes = [ 'font', // 字体文件 'image', // 图片 @@ -455,25 +597,16 @@ chrome.windows.onFocusChanged.addListener((windowId) => { } }); -// 添加窗口焦点变化监听器 +// 修改窗口焦点变化监听器 chrome.windows.onFocusChanged.addListener((windowId) => { if (windowId !== chrome.windows.WINDOW_ID_NONE) { const proxyConfig = windowProxyMap.get(windowId); if (proxyConfig) { console.log(`窗口 ${windowId} 获得焦点,恢复其代理设置:`, proxyConfig); - chrome.proxy.settings.set({ - value: { - mode: "fixed_servers", - rules: { - singleProxy: { - scheme: "http", - host: proxyConfig.host, - port: parseInt(proxyConfig.port) - }, - bypassList: ["localhost", "127.0.0.1", ""] - } - }, - scope: "regular" + setProxyForWindow(proxyConfig, windowId, (error) => { + if (error) { + console.error('恢复代理设置失败:', error); + } }); } } @@ -483,4 +616,18 @@ chrome.windows.onFocusChanged.addListener((windowId) => { chrome.windows.onRemoved.addListener((windowId) => { console.log(`窗口 ${windowId} 被关闭,移除其代理设置`); windowProxyMap.delete(windowId); -}); \ No newline at end of file +}); + +// 添加证书错误处理 +chrome.webRequest.onErrorOccurred.addListener( + function(details) { + if (details.error && details.error.includes('ERR_CERT')) { + console.log('忽略证书错误:', details.url); + return { cancel: false }; + } + }, + { + urls: [""], + types: ["main_frame", "sub_frame", "stylesheet", "script", "image", "object", "xmlhttprequest", "other"] + } +); \ No newline at end of file diff --git a/douyin/manifest.json b/douyin/manifest.json index e070c20..6a1a7a9 100644 --- a/douyin/manifest.json +++ b/douyin/manifest.json @@ -10,7 +10,10 @@ "cookies", "scripting", "proxy", - "webRequest" + "webRequest", + "webRequestAuthProvider", + "browsingData", + "webNavigation" ], "host_permissions": [ "https://douyin.xingtongworld.com/*", diff --git a/douyin/popup.html b/douyin/popup.html index 9f36240..1b60b9d 100644 --- a/douyin/popup.html +++ b/douyin/popup.html @@ -96,7 +96,9 @@ +
+
diff --git a/douyin/popup.js b/douyin/popup.js index 44c4591..987db65 100644 --- a/douyin/popup.js +++ b/douyin/popup.js @@ -30,7 +30,9 @@ document.addEventListener('DOMContentLoaded', function() { updateProxiesButton: document.getElementById('updateProxies'), proxyStatusElement: document.getElementById('proxyStatus'), clearProxyButton: document.getElementById('clearProxy'), - checkIncognito: document.getElementById('checkIncognito') + checkIncognito: document.getElementById('checkIncognito'), + checkCurrentProxy: document.getElementById('checkCurrentProxy'), + currentProxyStatus: document.getElementById('currentProxyStatus') }; // 检查登录状态 @@ -256,7 +258,7 @@ document.addEventListener('DOMContentLoaded', function() { populate: true // 取窗中的所有标签页 }); - // 只检查当前窗口中的标签页 + // 只检��当前窗口中的标签页 const liveRooms = new Map(); // 存储直播间ID和第一次出现的标签页信息 const duplicates = new Map(); // 存储重复的直播间信息 @@ -384,7 +386,8 @@ document.addEventListener('DOMContentLoaded', function() { const proxyList = elements.proxyListTextarea.value .split('\n') .map(proxy => proxy.trim()) - .filter(proxy => proxy.length > 0 && validateProxy(proxy)); + .filter(proxy => proxy.length > 0 && validateProxy(proxy)) + .map(proxy => parseProxy(proxy)); // 解析代理字符串 if (proxyList.length === 0) { throw new Error('没有可用的代理'); @@ -482,6 +485,48 @@ document.addEventListener('DOMContentLoaded', function() { }); }); } + + // 添加查看当前代理的功能 + if (elements.checkCurrentProxy) { + elements.checkCurrentProxy.addEventListener('click', async function() { + try { + // 获取当前窗口 + const currentWindow = await chrome.windows.getCurrent(); + + // 获取代理信息 + const proxyInfo = await chrome.runtime.sendMessage({ + action: 'getCurrentProxy', + windowId: currentWindow.id + }); + + // 显示代理信息 + if (elements.currentProxyStatus) { + if (proxyInfo.success) { + if (proxyInfo.proxy) { + const proxyText = `当前窗口ID: ${currentWindow.id}\n` + + `代理服务器: ${proxyInfo.proxy.host}:${proxyInfo.proxy.port}\n` + + `用户名: ${proxyInfo.proxy.username}`; + elements.currentProxyStatus.textContent = proxyText; + } else { + elements.currentProxyStatus.textContent = '当前窗口未设置代理'; + } + } else { + elements.currentProxyStatus.textContent = proxyInfo.error || '获取代理信息失败'; + } + + // 3秒后清除状态信息 + setTimeout(() => { + elements.currentProxyStatus.textContent = ''; + }, 3000); + } + } catch (error) { + console.error('查看代理信息失败:', error); + if (elements.currentProxyStatus) { + elements.currentProxyStatus.textContent = '查看代理信息失败: ' + error.message; + } + } + }); + } }); // 辅助函数:获取直播间人数 @@ -596,52 +641,83 @@ function validateTask(task) { return isValidIp && isValidPort; } -// 添加代理验证函数 +// 修改代理验证函数 function validateProxy(proxy) { - const [host, port] = proxy.split(':'); - if (!host || !port) return false; - - // 验证IP格式 - const isValidIp = host.split('.').length === 4 && - host.split('.').every(num => { - const n = parseInt(num); - return !isNaN(n) && n >= 0 && n <= 255; - }); - - // 验证端口 - const isValidPort = !isNaN(parseInt(port)) && - parseInt(port) > 0 && - parseInt(port) <= 65535; + try { + // 移除 http:// 前缀(如果存在) + if (proxy.startsWith('http://')) { + proxy = proxy.substring(7); + } + + let host, port; + + if (proxy.includes('@')) { + // 带认证信息的格式 + const [auth, address] = proxy.split('@'); + // 验证认证信息 + const [username, password] = auth.split(':'); + if (!username || !password) return false; + + [host, port] = address.split(':'); + } else { + // 简单格式 + [host, port] = proxy.split(':'); + } + + if (!host || !port) return false; + + // 验证IP格式 + const isValidIp = host.split('.').length === 4 && + host.split('.').every(num => { + const n = parseInt(num); + return !isNaN(n) && n >= 0 && n <= 255; + }); - return isValidIp && isValidPort; + // 验证端口 + const isValidPort = !isNaN(parseInt(port)) && + parseInt(port) > 0 && + parseInt(port) <= 65535; + + return isValidIp && isValidPort; + } catch (error) { + console.error('代理格式验证失败:', error); + return false; + } } -// 修改更新代理按钮的处理逻辑中的代理设置部分 -async function setProxyWithRetry(proxy, maxRetries = 3) { - for (let i = 0; i < maxRetries; i++) { - try { - const [proxyHost, proxyPort] = proxy.split(':'); - - const response = await chrome.runtime.sendMessage({ - action: 'setWindowProxy', - proxy: { - host: proxyHost, - port: parseInt(proxyPort) - } - }); +// 修改代理解析函数 +function parseProxy(proxyString) { + try { + // 处理完整的代理URL格式 + if (proxyString.startsWith('http://')) { + // 移除 'http://' 前缀 + proxyString = proxyString.substring(7); + } - if (response.success) { - return true; - } - - // 如果设置失败,等待后重试 - await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); - } catch (error) { - console.error(`代理设置重试 ${i + 1} 失败:`, error); - if (i === maxRetries - 1) { - throw error; - } + let username = "", password = "", host = "", port = ""; + + if (proxyString.includes('@')) { + // 带认证信息的格式 username:password@host:port + const [auth, address] = proxyString.split('@'); + [username, password] = auth.split(':'); + [host, port] = address.split(':'); + } else { + // 简单格式 host:port + [host, port] = proxyString.split(':'); } + + if (!host || !port) { + throw new Error(`代理格式错误: ${proxyString}`); + } + + return { + username, + password, + host, + port: parseInt(port) + }; + } catch (error) { + console.error('解析代理字符串失败:', error); + throw new Error(`代理格式错误: ${proxyString}\n正确格式: http://username:password@host:port`); } - return false; }