Files
personal82555 540f506c78 feat: v1.7.9 试用72h+100条额度+到期降级+24h优惠码;v1.7.8 移除图片回复模式
注:本提交由 Gitee v1.7.7 基线重建(原 GitHub 仓库账号暂停、源码包已丢),重建后经真机功能测试与 v1.7.9 行为一致。
2026-10-17 22:01:13 +08:00

788 lines
28 KiB
JavaScript
Raw Permalink 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.
// 后台脚本
// 点击工具栏图标 → 直接在浏览器右侧打开/收起侧边栏(而不是弹窗)
if (chrome.sidePanel && chrome.sidePanel.setPanelBehavior) {
chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true }).catch((error) => {
console.log('设置侧边栏行为失败:', error);
});
}
// 默认自定义模型配置(OpenAI 兼容接口)
const DEFAULT_AI = {
apiBaseUrl: 'https://ai.88531.cn/v1',
model: 'mimo-v2.6-flash'
};
// ===== CardAuth 授权系统配置 =====
const AUTH_BASE = 'https://auth.88531.cn';
const AUTH_PROJECT_ID = 3;
const AUTH_API_KEY = 'ak_bbf83b76df8219388d7f60b9e67c7db2';
const CLIENT_VERSION = '1.7.9';
const TRIAL_MS = 72 * 60 * 60 * 1000; // 试用 72 小时(3 天)
const TRIAL_QUOTA = 100; // 试用期最多 100 条评论(时间/条数先到先停,防止白嫖薅量)
const GRACE_DAILY = 3; // 试用到期不硬锁:每天保留 3 条体验额度
const PROMO = { code: 'XHS24H', percent: 20, windowMs: 24 * 60 * 60 * 1000 }; // 到期后 24 小时限时优惠(8 折)
// ===== 试用用量统计(时间/条数额度 + 到期降级都读这里) =====
function todayStr() {
const d = new Date();
return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`;
}
async function getUsage() {
const { trialUsage } = await chrome.storage.local.get(['trialUsage']);
const u = trialUsage && typeof trialUsage === 'object' ? trialUsage : {};
return {
total: Number(u.total) || 0,
day: u.day || '',
dayCount: Number(u.dayCount) || 0,
quotaHitAt: Number(u.quotaHitAt) || 0,
trialEndedAt: Number(u.trialEndedAt) || 0
};
}
async function saveUsage(u) {
await chrome.storage.local.set({ trialUsage: u });
}
// 把用户填写的地址规范化为完整的 chat/completions 端点
function buildChatCompletionsUrl(baseUrl) {
let base = String(baseUrl || '').trim() || DEFAULT_AI.apiBaseUrl;
base = base.replace(/\/+$/, '');
if (/\/chat\/completions$/i.test(base)) {
return base;
}
if (!/\/v\d+$/i.test(base)) {
base += '/v1'; // 未带版本号时自动补 /v1(如 https://api.deepseek.com)
}
return base + '/chat/completions';
}
// 构造请求体
function buildChatBody(model, prompt, maxTokens) {
return {
model: model,
messages: [{ role: 'user', content: prompt }],
temperature: 0.7,
max_tokens: maxTokens,
presence_penalty: 0,
frequency_penalty: 0,
// 思考型模型(mimo / DeepSeek-R1 等)会先写 reasoning_content,
// 不关思考时正文容易被 max_tokens 截断 → 返回空。
// 支持的端点直接关掉思考;不支持的端点会报 400,下面自动去掉该参数重试
thinking: { type: 'disabled' }
};
}
// 从各种 OpenAI 兼容返回结构里取正文(兼容 content 字符串 / 分段数组 / text / output_text 等)
function extractChatContent(data) {
if (!data || typeof data !== 'object') return '';
const pick = (value) => {
if (typeof value === 'string') return value.trim();
if (Array.isArray(value)) {
return value.map(part => {
if (typeof part === 'string') return part;
if (part && typeof part === 'object') return part.text || part.content || '';
return '';
}).join('').trim();
}
return '';
};
try {
const choice = Array.isArray(data.choices) ? data.choices[0] : null;
if (choice) {
const fromMessage = choice.message ? pick(choice.message.content) : '';
if (fromMessage) return fromMessage;
const fromText = pick(choice.text);
if (fromText) return fromText;
}
return pick(data.output_text) || pick(data.output);
} catch (error) {
return '';
}
}
chrome.runtime.onInstalled.addListener(() => {
console.log('小红书自动评论助手已安装');
// 初始化存储
chrome.storage.local.get(['expandContent', 'commentText', 'apiKey', 'aiPrompt', 'apiBaseUrl', 'modelName'], (result) => {
if (result.expandContent === undefined) {
chrome.storage.local.set({ expandContent: true });
}
if (!result.commentText) {
chrome.storage.local.set({ commentText: '👍 赞!' });
}
if (!result.apiKey) {
chrome.storage.local.set({ apiKey: '' });
}
// 自定义模型配置:默认使用 ai.88531.cn/v1 的 mimo-v2.6-flash
if (!result.apiBaseUrl) {
chrome.storage.local.set({ apiBaseUrl: DEFAULT_AI.apiBaseUrl });
}
if (!result.modelName) {
chrome.storage.local.set({ modelName: DEFAULT_AI.model });
}
if (!result.aiPrompt) {
const defaultPrompt = '根据笔记内容来生成符合笔记的评论。最后只需要输出评论内容,不要输出你的推理,不要输出任何与评论无关的内容,不要输出#相关的内容,不要输出笔记关键词相关的内容。评论不要超过300字。这个是小红书的笔记内容:\n\n{{content}}\n\n';
chrome.storage.local.set({ aiPrompt: defaultPrompt });
}
});
// 授权系统:登记安装(计入后台安装统计)+ 初始化试用期 + 拉公告
authOnInstalled();
});
// 浏览器启动 / 服务工作线程重启时恢复定时任务
chrome.runtime.onStartup?.addListener?.(() => {
setupAuthAlarms();
});
// ===== CardAuth 授权系统 =====
// 统一请求封装(CardAuth 统一响应: {code, message, data})
async function authFetch(path, { method = 'GET', body = null, needKey = false } = {}) {
const headers = { 'Content-Type': 'application/json' };
if (needKey) headers['X-Api-Key'] = AUTH_API_KEY;
const response = await fetch(AUTH_BASE + path, {
method,
headers,
body: body ? JSON.stringify(body) : undefined
});
let json = {};
try {
json = await response.json();
} catch (error) {
json = {};
}
return {
ok: response.ok && json.code === 200,
status: response.status,
code: json.code,
message: json.message || `HTTP ${response.status}`,
data: json.data
};
}
// 获取/生成设备指纹(授权绑定与安装统计的唯一标识)
async function getDeviceId() {
const result = await chrome.storage.local.get(['deviceId']);
if (result.deviceId) return result.deviceId;
const deviceId = 'EXT-' + crypto.randomUUID();
await chrome.storage.local.set({ deviceId });
console.log('已生成设备指纹:', deviceId);
return deviceId;
}
// 安装初始化:试用期起点 + 设备指纹 + 安装上报 + 公告
async function authOnInstalled() {
try {
const result = await chrome.storage.local.get(['trialStartedAt']);
if (!result.trialStartedAt) {
await chrome.storage.local.set({ trialStartedAt: Date.now() });
console.log('试用期开始(3 天 · 上限 ' + TRIAL_QUOTA + ' 条)');
}
} catch (error) {
console.error('初始化试用期失败:', error);
}
setupAuthAlarms();
try {
await authCheckUpdate(); // 后台计入安装统计 + 检查更新
} catch (error) {
console.error('安装上报失败:', error);
}
try {
await authGetAnnouncements();
} catch (error) {
console.error('拉取公告失败:', error);
}
// 已有卡密则静默复验
try {
const { licenseState } = await chrome.storage.local.get(['licenseState']);
if (licenseState && licenseState.cardKey && licenseState.valid) {
await authVerify(licenseState.cardKey);
}
} catch (error) {
console.error('启动时授权复验失败:', error);
}
}
// 注册定时任务:心跳/复验/公告/更新检查
function setupAuthAlarms() {
if (!chrome.alarms) return;
chrome.alarms.create('authHeartbeat', { periodInMinutes: 30 });
chrome.alarms.create('authVerify', { periodInMinutes: 10 });
chrome.alarms.create('authAnnounce', { periodInMinutes: 60 });
chrome.alarms.create('authUpdateCheck', { periodInMinutes: 60 });
}
chrome.alarms?.onAlarm?.addListener(async (alarm) => {
try {
if (alarm.name === 'authHeartbeat') {
await authHeartbeat();
} else if (alarm.name === 'authVerify') {
const { licenseState } = await chrome.storage.local.get(['licenseState']);
if (licenseState && licenseState.cardKey && licenseState.valid) {
await authVerify(licenseState.cardKey);
}
} else if (alarm.name === 'authAnnounce') {
await authGetAnnouncements();
} else if (alarm.name === 'authUpdateCheck') {
await authCheckUpdate();
}
} catch (error) {
console.error('授权定时任务失败:', alarm.name, error);
}
});
// 安装上报 / 检查更新(后台「安装统计」自动记录)
async function authCheckUpdate() {
const machineId = await getDeviceId();
const { licenseState } = await chrome.storage.local.get(['licenseState']);
const body = {
machine_id: machineId,
client_version: CLIENT_VERSION,
device_info: navigator.userAgent.includes('Edg/') ? 'Edge 插件' : 'Chrome 插件'
};
if (licenseState && licenseState.cardKey) body.card_key = licenseState.cardKey;
const res = await authFetch('/api/public/installations/check-update', {
method: 'POST',
body,
needKey: true
});
if (res.ok && res.data) {
const updateInfo = {
updateAvailable: !!res.data.update_available,
updateRequired: !!res.data.update_required,
latestVersion: res.data.latest_version || '',
downloadUrl: res.data.download_url || '',
changelog: res.data.changelog || '',
isForce: !!res.data.is_force,
checkedAt: Date.now()
};
await chrome.storage.local.set({ updateInfo });
console.log('更新检查:', updateInfo.updateAvailable ? `发现 ${updateInfo.latestVersion}` : '已是最新');
}
return res;
}
// 心跳:更新「最后上线」时间
async function authHeartbeat() {
const machineId = await getDeviceId();
const { licenseState } = await chrome.storage.local.get(['licenseState']);
const body = {
machine_id: machineId,
client_version: CLIENT_VERSION
};
if (licenseState && licenseState.cardKey) body.card_key = licenseState.cardKey;
return authFetch('/api/public/installations/heartbeat', {
method: 'POST',
body,
needKey: true
});
}
// 授权验证:cardKey 存在则校验并更新缓存;首次调用即绑定设备
async function authVerify(cardKey) {
const key = String(cardKey || '').trim();
if (!key) return { ok: false, message: '卡密不能为空' };
const machineId = await getDeviceId();
const res = await authFetch('/api/public/verify', {
method: 'POST',
body: {
card_key: key,
machine_id: machineId,
client_version: CLIENT_VERSION,
device_info: '小红书评论插件 ' + CLIENT_VERSION
},
needKey: true
});
if (!res.ok) {
// 网络/服务异常时不清除现有授权,仅报错
return { ok: false, message: res.message || '验证失败' };
}
const data = res.data || {};
const licenseState = {
valid: !!data.valid,
cardKey: key,
message: data.message || '',
expireTime: data.expire_time || '',
isPermanent: !!data.is_permanent,
remainingDays: data.remaining_days ?? null,
boundAt: data.bound_at || '',
verifiedAt: Date.now()
};
await chrome.storage.local.set({ licenseState });
console.log('授权验证:', licenseState.valid ? '有效' : '无效', licenseState.message);
return { ok: true, licenseState };
}
// 拉取公告并缓存
async function authGetAnnouncements() {
const res = await authFetch('/api/public/announcements');
if (res.ok && res.data) {
const announcements = {
list: res.data.list || [],
popup: res.data.popup || [],
fetchedAt: Date.now()
};
await chrome.storage.local.set({ announcements });
return { ok: true, announcements };
}
return { ok: false, message: res.message || '拉取公告失败' };
}
// 读取授权状态(valid授权 > 72 小时试用 > 到期降级体验,不硬锁)
async function authGetStatus() {
const { licenseState, trialStartedAt } = await chrome.storage.local.get(['licenseState', 'trialStartedAt']);
if (licenseState && licenseState.valid) {
return {
state: 'authorized',
license: {
expireTime: licenseState.expireTime,
isPermanent: licenseState.isPermanent,
remainingDays: licenseState.remainingDays,
cardKey: licenseState.cardKey
}
};
}
const start = trialStartedAt || Date.now();
if (!trialStartedAt) {
await chrome.storage.local.set({ trialStartedAt: start });
}
const usage = await getUsage();
const trialEndAt = start + TRIAL_MS;
const timeUp = Date.now() >= trialEndAt;
const quotaReached = usage.quotaHitAt > 0;
// 试用期内:时间没到 且 评论额度没用完
if (!timeUp && !quotaReached) {
return {
state: 'trial',
remainingMs: trialEndAt - Date.now(),
remainingHours: Math.max(1, Math.ceil((trialEndAt - Date.now()) / 3600000)),
trialEndAt,
quotaTotal: TRIAL_QUOTA,
quotaUsed: usage.total,
quotaLeft: Math.max(0, TRIAL_QUOTA - usage.total)
};
}
// 到期(时间到 或 额度用完)→ 降级体验:不硬锁,保留数据 + 每天 3 条 + 24h 限时优惠
if (!usage.trialEndedAt) {
usage.trialEndedAt = quotaReached && usage.quotaHitAt ? usage.quotaHitAt : trialEndAt;
await saveUsage(usage);
}
const today = todayStr();
const dayCount = usage.day === today ? usage.dayCount : 0;
const dayLeft = Math.max(0, GRACE_DAILY - dayCount);
const promoLeftMs = Math.max(0, usage.trialEndedAt + PROMO.windowMs - Date.now());
return {
state: 'grace',
trialEndedAt: usage.trialEndedAt,
graceDaily: GRACE_DAILY,
dayCount,
dayLeft,
quotaTotal: TRIAL_QUOTA,
quotaUsed: usage.total,
promo: {
code: PROMO.code,
percent: PROMO.percent,
promoLeftMs,
active: promoLeftMs > 0
}
};
}
// 每成功一条评论调用一次:试用期扣 100 条额度;到期后扣每日 3 条;授权用户不计
// 返回 allowed=false 时调用方应立即停止本轮任务
async function usageTick() {
const { licenseState } = await chrome.storage.local.get(['licenseState']);
if (licenseState && licenseState.valid) {
return { allowed: true, state: 'authorized' };
}
const { trialStartedAt } = await chrome.storage.local.get(['trialStartedAt']);
const start = trialStartedAt || Date.now();
const usage = await getUsage();
const inTrial = Date.now() < start + TRIAL_MS && !usage.quotaHitAt;
if (inTrial) {
usage.total += 1;
if (usage.total >= TRIAL_QUOTA && !usage.quotaHitAt) {
usage.quotaHitAt = Date.now();
usage.trialEndedAt = usage.quotaHitAt;
}
await saveUsage(usage);
const quotaLeft = Math.max(0, TRIAL_QUOTA - usage.total);
return {
allowed: quotaLeft > 0,
state: quotaLeft > 0 ? 'trial' : 'grace',
quotaLeft,
message: quotaLeft > 0 ? '' :
`试用额度 ${TRIAL_QUOTA} 条已用完,已自动停止;到期后每天仍可体验 ${GRACE_DAILY} 条`
};
}
// 降级期:每日额度
const today = todayStr();
if (usage.day !== today) {
usage.day = today;
usage.dayCount = 0;
}
usage.dayCount += 1;
usage.total += 1;
await saveUsage(usage);
const dayLeft = Math.max(0, GRACE_DAILY - usage.dayCount);
return {
allowed: dayLeft > 0,
state: 'grace',
dayCount: usage.dayCount,
graceDaily: GRACE_DAILY,
dayLeft,
message: dayLeft > 0 ? '' :
`今日 ${GRACE_DAILY} 条体验额度已用完(明天恢复),购买授权解锁无限量`
};
}
// 创建购买订单(contact_info 带机器码 → 支付成功后系统自动发卡绑定)
async function authCreateOrder(payType) {
const pay = payType === 'wxpay' ? 'wxpay' : 'alipay';
// 取项目第一个套餐
const typesRes = await authFetch(`/api/public/projects/${AUTH_PROJECT_ID}/card-types`);
if (!typesRes.ok || !Array.isArray(typesRes.data) || typesRes.data.length === 0) {
return { ok: false, message: '暂无在售套餐,请稍后再试' };
}
const cardType = typesRes.data[0];
const machineId = await getDeviceId();
const price = Number(cardType.price);
// 试用到期 24 小时内下单自动带限时优惠码(服务端按折扣重算实付金额)
const status = await authGetStatus();
const useCoupon = !!(status.state === 'grace' && status.promo && status.promo.active);
const orderBody = () => ({
project_id: AUTH_PROJECT_ID,
card_type_id: cardType.id,
amount: price,
pay_type: pay,
contact_info: `MACHINE:${machineId}`,
...(useCoupon ? { coupon_code: PROMO.code } : {})
});
let res = await authFetch('/api/public/orders', { method: 'POST', body: orderBody() });
let couponApplied = useCoupon;
if (!res.ok && useCoupon) {
// 优惠码异常也不能挡住下单:去掉优惠码重试一次
console.log('优惠码下单失败,改用原价重试:', res.message);
const retryBody = orderBody();
delete retryBody.coupon_code;
res = await authFetch('/api/public/orders', { method: 'POST', body: retryBody });
couponApplied = false;
}
if (!res.ok || !res.data) {
return { ok: false, message: res.message || '创建订单失败' };
}
// 记录进行中的订单,便于侧边栏恢复轮询(金额优先用服务端实付金额)
const serverPay = res.data.pay_amount != null ? Number(res.data.pay_amount) : null;
const fallbackPay = couponApplied ? Math.max(0.01, Math.round(price * (1 - PROMO.percent / 100) * 100) / 100) : price;
const pendingOrder = {
orderNo: res.data.order_no,
payType: pay,
amount: serverPay != null ? serverPay : fallbackPay,
originalPrice: price,
couponCode: couponApplied ? PROMO.code : '',
packageName: cardType.name || '',
createdAt: Date.now()
};
await chrome.storage.local.set({ pendingOrder });
return { ok: true, order: pendingOrder, payUrl: res.data.pay_url };
}
// 查询订单(支付+自动发卡后返回 card_key;拿到卡密自动激活)
async function authQueryOrder(orderNo) {
const res = await authFetch(`/api/public/orders/query?order_no=${encodeURIComponent(orderNo)}`);
if (!res.ok || !res.data) {
return { ok: false, message: res.message || '订单查询失败' };
}
const data = res.data;
const result = {
ok: true,
paid: data.status === 'paid' || !!data.card_key,
status: data.status,
cardKey: data.card_key || '',
expireTime: data.expire_time || ''
};
// 自动发卡成功 → 自动激活绑定本机
if (result.cardKey) {
const verifyRes = await authVerify(result.cardKey);
result.activated = !!(verifyRes.ok && verifyRes.licenseState && verifyRes.licenseState.valid);
result.licenseState = verifyRes.licenseState;
if (result.activated) {
await chrome.storage.local.remove(['pendingOrder']);
}
}
return result;
}
// 监听来自内容脚本的消息
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'getCurrentNote') {
handleGetCurrentNote(request, sendResponse);
return true; // 保持消息通道开放
}
if (request.action === 'saveNote') {
handleSaveNote(request.noteData, sendResponse);
return true; // 保持消息通道开放
}
if (request.action === 'callAiApi') {
handleCallAiApi(request, sendResponse);
return true; // 保持消息通道开放
}
if (request.action === 'getNotes') {
handleGetNotes(sendResponse);
return true;
}
if (request.action === 'deleteNote') {
handleDeleteNote(request.noteId, sendResponse);
return true;
}
// ===== 授权系统消息 =====
if (request.action === 'authStatus') {
authGetStatus().then((status) => sendResponse({ ok: true, status }));
return true;
}
if (request.action === 'usageTick') {
usageTick().then((data) => sendResponse({ ok: true, data }));
return true;
}
if (request.action === 'authActivate') {
authVerify(request.cardKey).then((res) => sendResponse(res));
return true;
}
if (request.action === 'authCreateOrder') {
authCreateOrder(request.payType).then((res) => sendResponse(res));
return true;
}
if (request.action === 'authQueryOrder') {
authQueryOrder(request.orderNo).then((res) => sendResponse(res));
return true;
}
if (request.action === 'authGetAnnouncements') {
authGetAnnouncements().then((res) => sendResponse(res)).catch((error) => {
sendResponse({ ok: false, message: error.message });
});
return true;
}
if (request.action === 'authCheckUpdate') {
authCheckUpdate()
.then(async () => {
const { updateInfo } = await chrome.storage.local.get(['updateInfo']);
sendResponse({ ok: true, updateInfo: updateInfo || null });
})
.catch((error) => sendResponse({ ok: false, message: error.message }));
return true;
}
});
// 调用自定义模型(OpenAI 兼容接口),由后台执行以规避页面 CORS / 混合内容限制
async function handleCallAiApi(request, sendResponse) {
const apiKey = String(request.apiKey || '').trim();
if (!apiKey) {
sendResponse({ ok: false, error: '未配置API密钥' });
return;
}
const url = buildChatCompletionsUrl(request.baseUrl);
const model = String(request.model || '').trim() || DEFAULT_AI.model;
const prompt = String(request.prompt || '');
const maxTokens = Number(request.maxTokens) > 0 ? Number(request.maxTokens) : 300;
const timeoutMs = Number(request.timeoutMs) > 0 ? Number(request.timeoutMs) : 90000;
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
const body = buildChatBody(model, prompt, maxTokens);
const sendOnce = async (payload) => {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
},
body: JSON.stringify(payload),
signal: controller.signal
});
let data = {};
try {
data = await response.json();
} catch (parseError) {
data = {};
}
return { response: response, data: data };
};
let result = await sendOnce(body);
// 400/422:端点不认某些参数,按报错修正后重试一次
if (!result.response.ok && (result.response.status === 400 || result.response.status === 422)) {
const message = (result.data && result.data.error && result.data.error.message) || '';
let repaired = false;
if (body.thinking && /thinking|unknown|unrecognized|extra|invalid|not allowed|parameter/i.test(message)) {
delete body.thinking;
repaired = true;
}
if (body.max_tokens && /max_tokens/i.test(message) && /max_completion_tokens|unknown|unrecognized|invalid|not allowed/i.test(message)) {
body.max_completion_tokens = body.max_tokens;
delete body.max_tokens;
repaired = true;
}
if (repaired) {
console.log('参数不被端点接受,修正后重试:', message);
result = await sendOnce(body);
}
}
if (!result.response.ok) {
sendResponse({
ok: false,
status: result.response.status,
error: (result.data && result.data.error && result.data.error.message) || `HTTP ${result.response.status}`,
url: url,
model: model
});
return;
}
let content = extractChatContent(result.data);
// 正文为空:基本是 max_tokens 被思考过程吃掉 → 提高上限重试一次
if (!content) {
const choice = result.data && Array.isArray(result.data.choices) ? result.data.choices[0] : null;
const truncated = !!(choice && choice.finish_reason === 'length');
const hasReasoning = !!(choice && choice.message && typeof choice.message.reasoning_content === 'string' && choice.message.reasoning_content.length > 0);
if (truncated || hasReasoning) {
body.max_tokens = Math.max(4096, maxTokens * 4);
console.log('正文为空,提高 max_tokens 到', body.max_tokens, '重试');
result = await sendOnce(body);
if (result.response.ok) {
content = extractChatContent(result.data);
}
}
if (!content) {
sendResponse({
ok: false,
error: hasReasoning
? '模型只返回了思考过程,没有返回正文(可提高 max_tokens 或换非思考型模型)'
: 'AI返回的内容为空',
url: url,
model: model
});
return;
}
}
sendResponse({ ok: true, content: content, url: url, model: model });
} catch (error) {
sendResponse({
ok: false,
error: error.name === 'AbortError' ? `请求超时(${Math.round(timeoutMs / 1000)}秒)` : error.message,
url: url,
model: model
});
} finally {
clearTimeout(timer);
}
}
async function handleGetCurrentNote(request, sendResponse) {
try {
sendResponse({
success: true,
message: '获取当前笔记成功'
});
} catch (error) {
console.error('获取当前笔记失败:', error);
sendResponse({ success: false, error: error.message });
}
}
async function handleSaveNote(request, sendResponse) {
try {
sendResponse({ success: true, message: '保存笔记成功' });
} catch (error) {
console.error('保存笔记失败:', error);
sendResponse({ success: false, error: error.message });
}
}
async function handleGetNotes(sendResponse) {
try {
sendResponse({
success: true,
notes: [],
tags: []
});
} catch (error) {
console.error('获取笔记失败:', error);
sendResponse({ success: false, error: error.message });
}
}
async function handleDeleteNote(request, sendResponse) {
try {
sendResponse({ success: true, message: '删除笔记成功' });
} catch (error) {
console.error('删除笔记失败:', error);
sendResponse({ success: false, error: error.message });
}
}
// 存储变化监听
chrome.storage.onChanged.addListener((changes, namespace) => {
if (namespace === 'local') {
console.log('存储数据发生变化:', changes);
}
});
// 标签页更新监听
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.status === 'complete' && tab.url && tab.url.includes('xiaohongshu.com')) {
// 当小红书页面加载完成时,可以在这里执行一些操作
console.log('小红书页面加载完成');
}
});