live-forum/server/admin/browser-extension/live-forum-cookie/background.js
2026-03-24 11:27:37 +08:00

335 lines
8.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 帅库之家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();