console.log("Content script starting..."); (function () { // 检查是否为 HTML 文档 if (document.documentElement?.nodeName.toLowerCase() !== 'html') { console.log("Not an HTML document, content script will not run"); return; } // 代理操作类型常量 const ProxyActionType = { SET_PROXY_CONFIG: "SET_PROXY_CONFIG", CLEAR_PROXY_CONFIG: "CLEAR_PROXY_CONFIG", GET_PROXY_STATUS: "GET_PROXY_STATUS", GET_PROXY_CONFIGS: "GET_PROXY_CONFIGS", UPDATE_PROXY_CONFIG: "UPDATE_PROXY_CONFIG", }; // 在文件顶部添加常量声明 const YAK_ICON_URL = chrome.runtime.getURL("/images/yak.svg"); // 添加一个通用的消息发送函数 async function sendMessageWithRetry(message, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await chrome.runtime.sendMessage(message); } catch (error) { console.warn(`Attempt ${i + 1} failed:`, error); if (i === maxRetries - 1) { throw error; } // 等待一小段时间后重试 await new Promise((resolve) => setTimeout(resolve, 500)); } } } // 获取当前代理状态 async function getCurrentProxy() { try { const response = await sendMessageWithRetry({ action: ProxyActionType.GET_PROXY_STATUS, }); if (!response || !response.success) { console.log("No valid response from background script"); return {enable: false, proxy: "", currentMode: "direct"}; } const status = response.data; console.log("Proxy status from background:", status); // 返回当前模式 return { enable: status.enabled, proxy: status.mode === "system" ? "system" : "", currentMode: status.mode || "direct", // 使用 mode 来判断当前激活的代理 }; } catch (error) { console.error("Error getting proxy status:", error); return {enable: false, proxy: "", currentMode: "direct"}; } } // 获取所有代理配置 async function getProxyConfigs() { try { const response = await sendMessageWithRetry({ action: ProxyActionType.GET_PROXY_CONFIGS, }); if (!response) { console.log("No response from background script"); return []; } if (!response.success) { console.error("Error in response:", response.error); return []; } return response.data || []; } catch (error) { console.error("Error getting proxy configs:", error); return []; } } // 切换代理 async function switchProxy(config) { try { console.log("Switching proxy:", config); // 根据配置类型构建正确的配置对象 let proxyConfig; if (config.proxyType === "system") { proxyConfig = { id: "system", name: "[系统代理]", proxyType: "system", enabled: true, }; } else if (config.proxyType === "direct") { proxyConfig = { id: "direct", name: "[直接连接]", proxyType: "direct", enabled: false, }; } else { proxyConfig = { ...config, enabled: true, }; } // 发送配置更改消息 await sendMessageWithRetry({ action: ProxyActionType.SET_PROXY_CONFIG, config: proxyConfig, }); await PanelManager.updatePanel(); } catch (error) { console.error("Error switching proxy:", error); } } // 清除代理 async function clearProxy() { try { const response = await sendMessageWithRetry({ action: ProxyActionType.SET_PROXY_CONFIG, config: { id: "direct", name: "[直接连接]", proxyType: "direct", enabled: false, }, }); console.log("Clear proxy response:", response); // 使用 PanelManager 的 updatePanel 方法 await PanelManager.updatePanel(); } catch (error) { console.error("Error clearing proxy:", error); } } // 修改 PanelManager const PanelManager = { panel: null, messageListener: null, _updating: false, _updateQueue: Promise.resolve(), _currentState: null, // 用于跟踪当前状态 _lastUpdate: null, // 添加最后更新时间戳 _lastState: null, _pollingInterval: null, isDragging: false, startY: 0, currentY: 0, init() { // 确保 document.body 存在 if (!document.body) { console.log("Body not ready, waiting..."); this.waitForBody(); return; } if (this.panel) { console.log("Panel already exists, updating..."); this.updatePanel(); return; } console.log("Creating new panel..."); this.createPanel(); }, // 添加等待 body 的方法 waitForBody() { if (document.body) { this.init(); return; } console.log("Setting up MutationObserver for body"); const observer = new MutationObserver((mutations, obs) => { if (document.body) { console.log("Body found via observer"); obs.disconnect(); this.init(); } }); observer.observe(document.documentElement, { childList: true, subtree: true, }); }, createPanel() { if (!document.body) { console.log("Body not available during panel creation"); return; } // 创建容器 const container = document.createElement("div"); container.id = "yakit-proxy-panel"; // 添加高z-index确保在页面最上层 container.style.zIndex = "2147483647"; // 创建 shadow DOM const shadow = container.attachShadow({mode: "open"}); // 添加样式 const style = document.createElement("style"); style.textContent = ` /* 重置所有样式以避免宿主页面的CSS影响 */ .yak-proxy-root * { all: initial; box-sizing: border-box !important; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important; line-height: normal !important; color: initial !important; font-size: 14px !important; text-align: left !important; margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; text-decoration: none !important; width: auto !important; height: auto !important; min-width: auto !important; min-height: auto !important; max-width: none !important; max-height: none !important; background: none !important; } .floating-panel { position: fixed !important; top: 30% !important; right: 0 !important; transform: translateY(-30%) !important; background: white !important; z-index: 2147483647 !important; width: 50px !important; height: 40px !important; overflow: hidden !important; transition: width 0.2s cubic-bezier(0.4, 0, 0.2, 1), height 0.2s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.2s ease !important; box-sizing: border-box !important; } /* 吸附状态 */ .floating-panel:not(.expanded):not(.dragging) { border-radius: 50px 0 0 50px !important; box-shadow: -4px 0 20px rgba(0,0,0,0.15) !important; border: 1px solid #eee !important; border-right: none !important; } /* 拖动状态 */ .floating-panel.dragging { cursor: grabbing !important; user-select: none !important; opacity: 0.95 !important; transition: none !important; } .floating-panel.dragging * { cursor: grabbing !important; } .floating-panel:active { cursor: grabbing !important; } .floating-panel .panel-header { cursor: grab !important; } .floating-panel .panel-header:active { cursor: grabbing !important; } /* 吸附状态悬浮时 */ .floating-panel:not(.expanded):hover { width: 120px !important; background: #fff7e6 !important; border-color: #ffd591 !important; } /* 展开状态 - 立即应用圆角变化 */ .floating-panel.expanded { width: 180px !important; height: auto !important; max-height: 400px !important; border-radius: 8px 0 0 8px !important; box-shadow: -2px 0 10px rgba(0,0,0,0.1) !important; border: 1px solid #eee !important; border-right: none !important; /* 展开时立即应用新的圆角 */ transition: width 0.2s cubic-bezier(0.4, 0, 0.2, 1), height 0.2s cubic-bezier(0.4, 0, 0.2, 1), border-radius 0s, background-color 0.2s ease !important; } .panel-header { height: 40px !important; min-height: 40px !important; display: flex !important; align-items: center !important; padding: 0 8px !important; cursor: pointer !important; user-select: none !important; } /* 吸附状态的头部 */ .floating-panel:not(.expanded) .panel-header { background: transparent !important; } /* 展开状态的头部 */ .floating-panel.expanded .panel-header { background: #f8f9fa !important; border-bottom: 1px solid #eee !important; } .header-content { display: flex !important; align-items: center !important; flex: 1 !important; overflow: hidden !important; } /* 优化图标大小过渡 */ .yak-icon { width: 36px !important; height: 36px !important; min-width: 36px !important; object-fit: contain !important; filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1)) !important; transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important; } .floating-panel.expanded .yak-icon { width: 24px !important; height: 24px !important; min-width: 24px !important; } .active-proxy-info { display: flex !important; align-items: center !important; margin-left: 8px !important; white-space: nowrap !important; overflow: hidden !important; text-overflow: ellipsis !important; color: #ff6b00 !important; font-size: 13px !important; font-weight: 500 !important; } .active-proxy-info span:first-child { margin-right: 6px !important; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.1)) !important; } .active-proxy-info span:nth-child(2) { color: #333 !important; } .panel-content { display: none !important; background: white !important; overflow-y: auto !important; max-height: 360px !important; opacity: 0 !important; transition: opacity 0.2s ease !important; } .floating-panel.expanded .panel-content { display: block !important; opacity: 1 !important; } .panel-content::-webkit-scrollbar { width: 4px !important; } .panel-content::-webkit-scrollbar-track { background: #f5f5f5 !important; } .panel-content::-webkit-scrollbar-thumb { background: #ddd !important; border-radius: 4px !important; } .panel-content::-webkit-scrollbar-thumb:hover { background: #ccc !important; } .proxy-item { display: flex !important; align-items: center !important; padding: 8px 12px !important; cursor: pointer !important; transition: all 0.2s !important; white-space: nowrap !important; position: relative !important; } .proxy-item:hover { background: #fff7e6 !important; } .proxy-item.active { background: #fff7e6 !important; color: #ff6b00 !important; } .proxy-item.active span { color: #ff6b00 !important; } .proxy-item span:first-child { margin-right: 8px !important; font-size: 16px !important; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.1)) !important; } .proxy-item span { color: #333 !important; } .proxy-status { position: absolute !important; right: 12px !important; width: 6px !important; height: 6px !important; border-radius: 50% !important; background: #52c41a !important; box-shadow: 0 0 4px rgba(82,196,26,0.3) !important; } .proxy-item.active .proxy-status { background: #ff6b00 !important; box-shadow: 0 0 4px rgba(255,107,0,0.3) !important; } .divider { height: 1px !important; background: #f0f0f0 !important; margin: 4px 0 !important; } .action-button { display: flex !important; align-items: center !important; padding: 8px 12px !important; cursor: pointer !important; transition: all 0.2s !important; white-space: nowrap !important; color: #666 !important; } .action-button:hover { background: #fff7e6 !important; color: #ff6b00 !important; } .action-button:hover span { color: #ff6b00 !important; } .action-button span:first-child { margin-right: 8px !important; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.1)) !important; } .action-button span { color: #666 !important; } `; // 创建面板内容 const panel = document.createElement("div"); panel.className = "floating-panel yak-proxy-root"; panel.innerHTML = `