/** * 帅库之家Cookie管理 - 后台服务 */ // 导入MD5工具 importScripts('utils/md5.js'); // 平台配置 const PLATFORMS = { 'commerce': { name: '巨量百应-达人账号', urlPattern: /buyin\.jinritemai\.com/, cookieUrl: 'https://buyin.jinritemai.com', // 用于获取Cookie的URL loginUrl: 'https://buyin.jinritemai.com/mpa/account/institution-role-select' }, 'entertainment': { name: '字节联盟-主播排行', urlPattern: /union\.bytedance\.com/, cookieUrl: 'https://union.bytedance.com', // 用于获取Cookie的URL loginUrl: 'https://union.bytedance.com/open/portal/data/leaderboard?appId=3000' } }; // 默认配置 const DEFAULT_CONFIG = { serverUrl: 'https://api.skzhijia.com', apiKey: '', pollInterval: 5 // 分钟 }; // 状态缓存 let statusCache = {}; /** * 初始化 */ chrome.runtime.onInstalled.addListener(async () => { console.log('帅库之家Cookie管理插件已安装'); // 初始化存储 const config = await getConfig(); if (!config.serverUrl) { await chrome.storage.sync.set({ config: DEFAULT_CONFIG }); } // 设置定时轮询 await setupAlarm(); // 初始化图标 await updateIcon('gray'); }); /** * 监听定时器 */ chrome.alarms.onAlarm.addListener(async (alarm) => { if (alarm.name === 'pollStatus') { await pollCookieStatus(); } }); /** * 设置定时轮询 */ async function setupAlarm() { const config = await getConfig(); const interval = config.pollInterval || 5; // 清除现有定时器 await chrome.alarms.clear('pollStatus'); // 设置新定时器 chrome.alarms.create('pollStatus', { periodInMinutes: interval }); console.log(`定时轮询已设置: 每${interval}分钟`); } /** * 轮询Cookie状态 */ async function pollCookieStatus() { const config = await getConfig(); if (!config.serverUrl || !config.apiKey) { console.log('未配置服务器地址或API Key'); await updateIcon('gray'); return; } try { const response = await fetch(`${config.serverUrl}/api/crawler/cookie/status`, { method: 'GET', headers: { 'X-API-Key': config.apiKey, 'Content-Type': 'application/json' } }); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } const data = await response.json(); if (data.code === 200 && data.data) { statusCache = {}; let hasExpired = false; for (const item of data.data) { statusCache[item.code] = item; if (!item.isValid || item.lastRunStatus === 3) { hasExpired = true; } } // 更新图标 await updateIcon(hasExpired ? 'red' : 'green'); // 存储状态 await chrome.storage.local.set({ statusCache }); } } catch (error) { console.error('轮询Cookie状态失败:', error); await updateIcon('red'); } } /** * 获取指定平台的Cookie字符串 * 使用url参数获取该URL能访问到的所有Cookie(与浏览器实际发送请求时一致) */ async function getCookieStringForPlatform(code) { const platform = PLATFORMS[code]; if (!platform) { throw new Error('未知的平台代码'); } return new Promise((resolve, reject) => { // 使用url参数而不是domain,这样能获取到所有该URL可访问的Cookie chrome.cookies.getAll({ url: platform.cookieUrl }, (cookies) => { if (!cookies || cookies.length === 0) { reject(new Error('未找到Cookie,请先登录对应平台')); return; } console.log("获取到的Cookie数量:", cookies.length); // 直接拼接成 name=value; name2=value2 格式 const cookieString = cookies.map(c => `${c.name}=${c.value}`).join('; '); resolve(cookieString); }); }); } /** * 上传Cookie */ async function uploadCookie(code, manualCookieString = null) { const config = await getConfig(); const platform = PLATFORMS[code]; if (!platform) { throw new Error('未知的平台代码'); } if (!config.serverUrl || !config.apiKey) { throw new Error('请先配置服务器地址和API Key'); } // 获取Cookie字符串 (使用手动输入的或从浏览器获取) let cookieString; if (manualCookieString) { cookieString = manualCookieString.trim(); if (!cookieString) { throw new Error('Cookie字符串不能为空'); } } else { cookieString = await getCookieStringForPlatform(code); } const md5Hash = await computeMD5(cookieString); // 上传 const response = await fetch(`${config.serverUrl}/api/crawler/cookie/upload`, { method: 'POST', headers: { 'X-API-Key': config.apiKey, 'Content-Type': 'application/json' }, body: JSON.stringify({ code: code, cookieString: cookieString, md5: md5Hash, url: platform.loginUrl }) }); if (!response.ok) { const error = await response.text(); throw new Error(`上传失败: ${error}`); } const result = await response.json(); if (result.code !== 200) { throw new Error(result.msg || '上传失败'); } // 刷新状态 await pollCookieStatus(); return result.data; } /** * 计算MD5 */ async function computeMD5(text) { // 使用导入的md5函数 return md5(text); } /** * 更新图标 */ async function updateIcon(status) { const icons = { 'green': { '16': 'icons/icon-green-16.png', '32': 'icons/icon-green-32.png', '48': 'icons/icon-green-48.png', '128': 'icons/icon-green-128.png' }, 'red': { '16': 'icons/icon-red-16.png', '32': 'icons/icon-red-32.png', '48': 'icons/icon-red-48.png', '128': 'icons/icon-red-128.png' }, 'gray': { '16': 'icons/icon-gray-16.png', '32': 'icons/icon-gray-32.png', '48': 'icons/icon-gray-48.png', '128': 'icons/icon-gray-128.png' } }; try { await chrome.action.setIcon({ path: icons[status] || icons['gray'] }); } catch (error) { console.error('更新图标失败:', error); } } /** * 获取配置 */ async function getConfig() { const result = await chrome.storage.sync.get('config'); return result.config || DEFAULT_CONFIG; } /** * 保存配置 */ async function saveConfig(config) { await chrome.storage.sync.set({ config }); await setupAlarm(); } /** * 获取状态缓存 */ async function getStatusCache() { const result = await chrome.storage.local.get('statusCache'); return result.statusCache || statusCache; } /** * 消息处理 */ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { (async () => { try { switch (message.action) { case 'getConfig': sendResponse({ success: true, data: await getConfig() }); break; case 'saveConfig': await saveConfig(message.config); sendResponse({ success: true }); break; case 'getStatus': sendResponse({ success: true, data: await getStatusCache() }); break; case 'pollStatus': await pollCookieStatus(); sendResponse({ success: true, data: await getStatusCache() }); break; case 'uploadCookie': // 支持手动上传Cookie字符串 const result = await uploadCookie(message.code, message.cookieString); sendResponse({ success: true, data: result }); break; case 'getCookieString': // 获取指定平台的Cookie字符串 const cookieStr = await getCookieStringForPlatform(message.code); sendResponse({ success: true, data: cookieStr }); break; case 'openLogin': const platform = PLATFORMS[message.code]; if (platform) { chrome.tabs.create({ url: platform.loginUrl }); } sendResponse({ success: true }); break; default: sendResponse({ success: false, error: '未知操作' }); } } catch (error) { sendResponse({ success: false, error: error.message }); } })(); return true; // 保持消息通道开放 }); // 启动时执行一次轮询 pollCookieStatus();