Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c52bc4178 | ||
|
|
226e4fbbf9 |
No files matched your search
@@ -4,6 +4,26 @@ B站评论助手 版本历史。下载:https://dl.88531.cn/bili.html ·
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## v1.10.4 · 2026-10-20
|
||||||
|
|
||||||
|
### 🔧 调整
|
||||||
|
- 侧边栏授权状态**不再被截断**:去掉 `nowrap + ellipsis`,像「免费试用中 · 剩余 71:59:27 · 还可评论 12 条」这种长状态现在完整换行显示,不再变成 `…还可评...`
|
||||||
|
- **「购买授权」改成独占一行的醒目按钮**(渐变粉红底 + 白字 + 阴影,通栏 40px 高),不再挤在状态行右侧当一个小链接
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v1.10.3 · 2026-10-20
|
||||||
|
|
||||||
|
### 🐛 修复
|
||||||
|
- **买完仍显示试用倒计时**:授权系统的自动发卡只把卡密标成「已使用」并绑定机器码,**从不写入授权表**,而插件原来只查授权表 → 已购用户永远查不到自己的授权、倒计时照旧。现在插件改用**本地记住的卡密直接向卡密系统校验**(`/public/verify`,它读的是卡表),拿到真实授权状态与到期时间
|
||||||
|
- **到期时间显示成「永久」**:购买页原先是 `到期时间 || '永久'` 兜底,而订单接口根本不返回到期时间 → **买 1 天也显示永久**。现在到期时间只在服务端明确给出时才显示,「永久」只在卡类型确为永久时出现
|
||||||
|
|
||||||
|
### ✨ 新功能
|
||||||
|
- 激活成功后插件**永久记住这张卡**(换机绑定或过期时自动清除),不再依赖服务端授权表
|
||||||
|
- 侧边栏已授权状态显示**套餐名 + 真实到期时间**:`已授权 · 1天试用 · 到期 2026-10-21 23:06:36`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## v1.10.2 · 2026-10-20
|
## v1.10.2 · 2026-10-20
|
||||||
|
|
||||||
### 🔧 调整
|
### 🔧 调整
|
||||||
|
|||||||
+56
-1
@@ -125,6 +125,36 @@ async function checkLicense() {
|
|||||||
offline = true; // 网络/超时 → 放行
|
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"]);
|
const st = await chrome.storage.local.get(["trialStart", "trialComments"]);
|
||||||
let trialStart = Number(st.trialStart) || 0;
|
let trialStart = Number(st.trialStart) || 0;
|
||||||
if (!trialStart) {
|
if (!trialStart) {
|
||||||
@@ -146,6 +176,7 @@ async function checkLicense() {
|
|||||||
offline: offline,
|
offline: offline,
|
||||||
realAuthorized: authorized,
|
realAuthorized: authorized,
|
||||||
expire: expire,
|
expire: expire,
|
||||||
|
cardInfo: cardInfo,
|
||||||
machine: machine,
|
machine: machine,
|
||||||
trialStart: trialStart,
|
trialStart: trialStart,
|
||||||
trialEnd: trialEnd,
|
trialEnd: trialEnd,
|
||||||
@@ -172,7 +203,27 @@ async function activateCard(cardKey) {
|
|||||||
}, 12000);
|
}, 12000);
|
||||||
const d = (r && r.data) || {};
|
const d = (r && r.data) || {};
|
||||||
if (r && r.code === 200 && d.valid) {
|
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) || "激活失败" };
|
return { ok: false, message: (d && d.message) || (r && r.message) || "激活失败" };
|
||||||
}
|
}
|
||||||
@@ -623,6 +674,10 @@ async function authQueryOrder(orderNo) {
|
|||||||
const act = await activateCard(out.cardKey);
|
const act = await activateCard(out.cardKey);
|
||||||
out.activated = !!(act && act.ok);
|
out.activated = !!(act && act.ok);
|
||||||
out.message = (act && act.message) || "";
|
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) {
|
if (out.activated) {
|
||||||
await chrome.storage.local.remove(["pendingOrder"]);
|
await chrome.storage.local.remove(["pendingOrder"]);
|
||||||
await clearOrderAlarm();
|
await clearOrderAlarm();
|
||||||
|
|||||||
@@ -149,11 +149,20 @@ function showCardBox(key, activated) {
|
|||||||
|
|
||||||
function showActivated(res) {
|
function showActivated(res) {
|
||||||
const status = $('order-status');
|
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 = '到期时间:<b>永久</b>';
|
||||||
|
else if (exp) expireLine = '到期时间:<b>' + esc(exp) + '</b>';
|
||||||
|
else if (plan) expireLine = '套餐:<b>' + esc(plan) + '</b>(实际到期时间以插件侧边栏「已授权 · 到期 …」为准)';
|
||||||
|
else expireLine = '到期时间:以插件侧边栏显示为准';
|
||||||
status.className = 'order-status success';
|
status.className = 'order-status success';
|
||||||
status.innerHTML = `
|
status.innerHTML = `
|
||||||
<div class="ok-title">✓ 支付成功,已自动激活</div>
|
<div class="ok-title">✓ 支付成功,已自动激活</div>
|
||||||
<div class="ok-line">卡密:<b>${esc(res.cardKey || '')}</b></div>
|
<div class="ok-line">卡密:<b>${esc(res.cardKey || '')}</b></div>
|
||||||
<div class="ok-line">到期时间:${esc(res.expireTime || '永久')}</div>
|
<div class="ok-line">${expireLine}</div>
|
||||||
<div class="ok-line muted">回到插件侧边栏即可使用全部功能(本机已授权)。</div>`;
|
<div class="ok-line muted">回到插件侧边栏即可使用全部功能(本机已授权)。</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"name": "B站评论助手",
|
"name": "B站评论助手",
|
||||||
"version": "1.10.2",
|
"version": "1.10.4",
|
||||||
"description": "B站网页版关键词评论助手:按搜索关键词找视频,默认模拟真人(打开视频页、滚到评论区、逐字输入、点发布),也可快速API直发;支持下载当前页视频;带防重复记录、可中断执行与页面实时进度浮层。",
|
"description": "B站网页版关键词评论助手:按搜索关键词找视频,默认模拟真人(打开视频页、滚到评论区、逐字输入、点发布),也可快速API直发;支持下载当前页视频;带防重复记录、可中断执行与页面实时进度浮层。",
|
||||||
"permissions": ["storage", "tabs", "scripting", "sidePanel", "downloads", "declarativeNetRequest", "alarms"],
|
"permissions": ["storage", "tabs", "scripting", "sidePanel", "downloads", "declarativeNetRequest", "alarms"],
|
||||||
"host_permissions": [
|
"host_permissions": [
|
||||||
|
|||||||
+11
-5
@@ -9,6 +9,12 @@
|
|||||||
.promo { display:flex; align-items:center; justify-content:space-between; gap:8px;
|
.promo { display:flex; align-items:center; justify-content:space-between; gap:8px;
|
||||||
background: linear-gradient(90deg,#00A1D6,#FB7299); color:#fff; padding: 8px 12px; font-size: 13px; }
|
background: linear-gradient(90deg,#00A1D6,#FB7299); color:#fff; padding: 8px 12px; font-size: 13px; }
|
||||||
.promo a { color:#fff; font-weight:bold; text-decoration:underline; cursor:pointer; }
|
.promo a { color:#fff; font-weight:bold; text-decoration:underline; cursor:pointer; }
|
||||||
|
/* 购买授权:独占一行的醒目按钮(授权文字不再和它抢同一行,避免状态被截断) */
|
||||||
|
.buy-btn { display:block; margin-top:8px; padding:10px 12px; border-radius:7px;
|
||||||
|
background:linear-gradient(90deg,#e91e63,#FB7299); color:#fff; font-size:14px;
|
||||||
|
font-weight:bold; text-align:center; text-decoration:none; cursor:pointer;
|
||||||
|
box-shadow:0 2px 6px rgba(251,114,153,.35); }
|
||||||
|
.buy-btn:active { opacity:.85; }
|
||||||
.sec { padding: 10px 12px; border-bottom: 1px solid #eee; }
|
.sec { padding: 10px 12px; border-bottom: 1px solid #eee; }
|
||||||
.lbl { font-size: 11px; color: #888; margin-bottom: 5px; }
|
.lbl { font-size: 11px; color: #888; margin-bottom: 5px; }
|
||||||
input[type=text], input[type=password], input[type=number], select {
|
input[type=text], input[type=password], input[type=number], select {
|
||||||
@@ -48,12 +54,12 @@
|
|||||||
<header>B站评论助手</header>
|
<header>B站评论助手</header>
|
||||||
|
|
||||||
<div id="licSec" style="padding:8px 12px;border-bottom:1px solid #eee;background:#fafbfc">
|
<div id="licSec" style="padding:8px 12px;border-bottom:1px solid #eee;background:#fafbfc">
|
||||||
<div style="display:flex;align-items:center;gap:6px">
|
<div style="display:flex;align-items:flex-start;gap:6px">
|
||||||
<span id="licIcon" style="font-size:14px">⏳</span>
|
<span id="licIcon" style="font-size:14px;line-height:1.45">⏳</span>
|
||||||
<span id="licText" style="font-size:13px;font-weight:bold;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">授权检查中…</span>
|
<span id="licText" style="font-size:13px;font-weight:bold;flex:1;line-height:1.45;word-break:break-word">授权检查中…</span>
|
||||||
<a id="licBuy" style="color:#e91e63;font-weight:bold;text-decoration:underline;cursor:pointer;white-space:nowrap">购买授权 →</a>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="licSub" style="font-size:11px;color:#888;margin-top:3px"></div>
|
<div id="licSub" style="font-size:11px;color:#888;margin-top:3px;line-height:1.5"></div>
|
||||||
|
<a id="licBuy" class="buy-btn">🛒 购买授权 · 解锁不限时不限量</a>
|
||||||
<div id="updMsg" style="display:none;font-size:12px;color:#005f8b;background:#e6f6fd;border:1px solid #9ed8f0;border-radius:4px;padding:4px 8px;margin-top:6px"></div>
|
<div id="updMsg" style="display:none;font-size:12px;color:#005f8b;background:#e6f6fd;border:1px solid #9ed8f0;border-radius:4px;padding:4px 8px;margin-top:6px"></div>
|
||||||
<div id="licNotice" style="display:none;font-size:12px;color:#7a5c00;background:#fff8e1;border:1px solid #ffe082;border-radius:4px;padding:4px 8px;margin-top:6px;line-height:1.5"></div>
|
<div id="licNotice" style="display:none;font-size:12px;color:#7a5c00;background:#fff8e1;border:1px solid #ffe082;border-radius:4px;padding:4px 8px;margin-top:6px;line-height:1.5"></div>
|
||||||
<div id="licActRow" style="display:none;margin-top:6px;align-items:center;gap:6px">
|
<div id="licActRow" style="display:none;margin-top:6px;align-items:center;gap:6px">
|
||||||
|
|||||||
+2
-1
@@ -152,7 +152,8 @@ function refreshCustomVisibility() {
|
|||||||
actRow.style.display = "none";
|
actRow.style.display = "none";
|
||||||
} else if (lic.authorized) {
|
} else if (lic.authorized) {
|
||||||
icon.textContent = "✅";
|
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";
|
text.style.color = "#0a7";
|
||||||
sub.textContent = "感谢支持!全部功能可用";
|
sub.textContent = "感谢支持!全部功能可用";
|
||||||
actRow.style.display = "none";
|
actRow.style.display = "none";
|
||||||
|
|||||||
Reference in new issue
Block a user