diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e4eb88..dd48302 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ B站评论助手 版本历史。下载:https://dl.88531.cn/bili.html ·  --- +## v1.10.3 · 2026-10-20 + +### 🐛 修复 +- **买完仍显示试用倒计时**:授权系统的自动发卡只把卡密标成「已使用」并绑定机器码,**从不写入授权表**,而插件原来只查授权表 → 已购用户永远查不到自己的授权、倒计时照旧。现在插件改用**本地记住的卡密直接向卡密系统校验**(`/public/verify`,它读的是卡表),拿到真实授权状态与到期时间 +- **到期时间显示成「永久」**:购买页原先是 `到期时间 || '永久'` 兜底,而订单接口根本不返回到期时间 → **买 1 天也显示永久**。现在到期时间只在服务端明确给出时才显示,「永久」只在卡类型确为永久时出现 + +### ✨ 新功能 +- 激活成功后插件**永久记住这张卡**(换机绑定或过期时自动清除),不再依赖服务端授权表 +- 侧边栏已授权状态显示**套餐名 + 真实到期时间**:`已授权 · 1天试用 · 到期 2026-10-21 23:06:36` + +--- + ## v1.10.2 · 2026-10-20 ### 🔧 调整 diff --git a/background.js b/background.js index ac0c358..8b5cd9a 100644 --- a/background.js +++ b/background.js @@ -125,6 +125,36 @@ async function checkLicense() { offline = true; // 网络/超时 → 放行 } + // 兜底:卡密直验。自动发卡不写 ca_authorizations,上面的查询对已购用户恒为空; + // 用本地记住的卡密直接调 /public/verify(它读 ca_cards,返回真实到期时间)。 + let cardInfo = null; + if (!authorized) { + try { + const saved = await chrome.storage.local.get(["activeCardKey"]); + const key = String(saved.activeCardKey || "").trim(); + if (key) { + const v = await authFetch("/public/verify", { + method: "POST", + headers: { "Content-Type": "application/json", "X-Api-Key": CARD_API_KEY }, + body: JSON.stringify({ + card_key: key, + machine_id: machine, + client_version: chrome.runtime.getManifest().version + }) + }, 12000); + const vd = (v && v.data) || {}; + if (v && v.code === 200 && vd.valid) { + authorized = true; + expire = vd.expire_time || ""; + cardInfo = { type: vd.type || "", expireTime: expire, isPermanent: !!vd.is_permanent, remainingDays: vd.remaining_days }; + } else if (v && v.code === 200 && vd.valid === false) { + // 换机绑定或已过期:清掉本地卡密,别每次都拿废卡打接口 + await chrome.storage.local.remove(["activeCardKey", "activeCardInfo"]); + } + } + } catch (e) { /* 直验失败不影响试用判定 */ } + } + const st = await chrome.storage.local.get(["trialStart", "trialComments"]); let trialStart = Number(st.trialStart) || 0; if (!trialStart) { @@ -146,6 +176,7 @@ async function checkLicense() { offline: offline, realAuthorized: authorized, expire: expire, + cardInfo: cardInfo, machine: machine, trialStart: trialStart, trialEnd: trialEnd, @@ -172,7 +203,27 @@ async function activateCard(cardKey) { }, 12000); const d = (r && r.data) || {}; if (r && r.code === 200 && d.valid) { - return { ok: true, message: d.message || "激活成功", days: d.duration_days || 0 }; + // 记住这张卡:CardAuth 的自动发卡只把 ca_cards 标成 used 并绑定机器码, + // 从不写 ca_authorizations,所以 /public/authorizations/query 对已购用户恒为空。 + // 插件自己留着卡密,才能持续向 /public/verify 校验真实授权状态。 + const key = String(cardKey || "").trim(); + await chrome.storage.local.set({ + activeCardKey: key, + activeCardInfo: { + type: d.type || "", + durationDays: Number(d.duration_days) || 0, + expireTime: d.expire_time || "", + isPermanent: !!d.is_permanent, + activatedAt: Date.now() + } + }); + return { + ok: true, message: d.message || "激活成功", + days: d.duration_days || 0, + cardType: d.type || "", + expireTime: d.expire_time || "", + isPermanent: !!d.is_permanent + }; } return { ok: false, message: (d && d.message) || (r && r.message) || "激活失败" }; } @@ -623,6 +674,10 @@ async function authQueryOrder(orderNo) { const act = await activateCard(out.cardKey); out.activated = !!(act && act.ok); out.message = (act && act.message) || ""; + // /public/orders/query 不返回到期时间,verify 返回的才是真值——别用「永久」兜底 + out.expireTime = (act && act.expireTime) || ""; + out.isPermanent = !!(act && act.isPermanent); + out.planName = d.card_type_name || ""; if (out.activated) { await chrome.storage.local.remove(["pendingOrder"]); await clearOrderAlarm(); diff --git a/buy.js b/buy.js index 2f1c6b4..8815304 100644 --- a/buy.js +++ b/buy.js @@ -149,11 +149,20 @@ function showCardBox(key, activated) { function showActivated(res) { const status = $('order-status'); + const permanent = !!res.isPermanent; + const exp = String(res.expireTime || '').trim(); + const plan = String(res.planName || '').trim(); + // 绝不默认「永久」:到期时间只在服务端明确给出时才显示 + let expireLine; + if (permanent) expireLine = '到期时间:永久'; + else if (exp) expireLine = '到期时间:' + esc(exp) + ''; + else if (plan) expireLine = '套餐:' + esc(plan) + '(实际到期时间以插件侧边栏「已授权 · 到期 …」为准)'; + else expireLine = '到期时间:以插件侧边栏显示为准'; status.className = 'order-status success'; status.innerHTML = `
✓ 支付成功,已自动激活
卡密:${esc(res.cardKey || '')}
-
到期时间:${esc(res.expireTime || '永久')}
+
${expireLine}
回到插件侧边栏即可使用全部功能(本机已授权)。
`; } diff --git a/manifest.json b/manifest.json index e78b239..7a30023 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "B站评论助手", - "version": "1.10.2", + "version": "1.10.3", "description": "B站网页版关键词评论助手:按搜索关键词找视频,默认模拟真人(打开视频页、滚到评论区、逐字输入、点发布),也可快速API直发;支持下载当前页视频;带防重复记录、可中断执行与页面实时进度浮层。", "permissions": ["storage", "tabs", "scripting", "sidePanel", "downloads", "declarativeNetRequest", "alarms"], "host_permissions": [ diff --git a/sidepanel.js b/sidepanel.js index 7c979b9..04772b4 100644 --- a/sidepanel.js +++ b/sidepanel.js @@ -152,7 +152,8 @@ function refreshCustomVisibility() { actRow.style.display = "none"; } else if (lic.authorized) { icon.textContent = "✅"; - text.textContent = "已授权" + (lic.expire ? " · 到期 " + lic.expire : "(长期)"); + const planTag = (lic.cardInfo && lic.cardInfo.type) ? " · " + lic.cardInfo.type : ""; + text.textContent = "已授权" + planTag + (lic.expire ? " · 到期 " + lic.expire : "(长期)"); text.style.color = "#0a7"; sub.textContent = "感谢支持!全部功能可用"; actRow.style.display = "none";