Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec0f342ee4 | ||
|
|
f231657560 | ||
|
|
40f335331b | ||
|
|
9c52bc4178 | ||
|
|
226e4fbbf9 | ||
|
|
99d1d1fe92 |
No files matched your search
@@ -4,6 +4,62 @@ B站评论助手 版本历史。下载:https://dl.88531.cn/bili.html ·
|
||||
|
||||
---
|
||||
|
||||
## v1.10.7 · 2026-10-21
|
||||
|
||||
### ✨ 新功能
|
||||
- **关掉购买页也不会丢卡**:订单号自动存在本地(30 分钟内有效),重新打开购买页会**自动恢复上次未完成的订单并继续查询支付结果**,套餐也会自动选回
|
||||
- 拿到卡密/激活成功后自动清除本地待处理订单,不会残留旧订单
|
||||
|
||||
---
|
||||
|
||||
## v1.10.6 · 2026-10-21
|
||||
|
||||
### ✨ 新功能
|
||||
- 购买页订单一直「等待支付中」时,**30 秒后自动出现「付款后没反应」帮助面板**,给出两条明确出路:
|
||||
- **🔁 立即刷新核对**:马上向授权系统重查一次订单(不用等下一轮 5 秒轮询)
|
||||
- **🔄 重新下单(换新二维码)**:本页订单 15 分钟有效,扫过期码/旧订单码会付不上,一键生成新单
|
||||
- 帮助面板同时说明:付款通知通常几秒到 1 分钟内自动到达,**请勿重复付款**;等待超过 120 秒会提示留好订单号与微信/支付宝交易号
|
||||
- 下单后立刻先查一次订单状态,不再干等 5 秒
|
||||
|
||||
### 🔧 优化
|
||||
- 轮询拆成单次查询函数,定时器与手动刷新共用同一逻辑,行为一致
|
||||
|
||||
---
|
||||
|
||||
## v1.10.5 · 2026-10-20
|
||||
|
||||
### ✨ 新功能
|
||||
- 侧边栏顶部标题旁显示**当前版本号**(半透明白色胶囊,如 `B站评论助手 v1.10.5`),直接读 manifest,升级后自动跟着变、不用改代码
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
|
||||
### 🔧 调整
|
||||
- 侧边栏「🤖 没有模型?注册即送额度」**移到 LLM 配置正上方**——原先它卡在授权区和评论记录之间,和 LLM 之间隔着一大块,现在配模型时一眼就能看到注册送额度的入口
|
||||
|
||||
---
|
||||
|
||||
## v1.10.1 · 2026-10-20
|
||||
|
||||
### ✨ 新功能
|
||||
|
||||
+56
-1
@@ -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();
|
||||
|
||||
@@ -113,6 +113,20 @@ h2 {
|
||||
|
||||
.tip { margin-top: 12px; font-size: 12px; color: #999; }
|
||||
|
||||
/* 「付款后没反应」的帮助面板:给用户明确出口,而不是干等 */
|
||||
.pay-help { margin-top: 10px; padding: 12px 14px; background: #fff8e6; border: 1px solid #ffd98a;
|
||||
border-radius: 8px; font-size: 13px; line-height: 1.7; }
|
||||
.pay-help .ph-title { font-weight: bold; color: #8a5a00; margin-bottom: 6px; }
|
||||
.pay-help .ph-list { margin: 0 0 10px; padding-left: 18px; color: #6b4a00; }
|
||||
.pay-help .ph-list li { margin-bottom: 3px; }
|
||||
.ph-btns { display: flex; gap: 8px; flex-wrap: wrap; }
|
||||
.ph-btn { flex: 1 1 150px; min-height: 38px; border: none; border-radius: 7px; cursor: pointer;
|
||||
background: linear-gradient(90deg, #00a1d6, #0077a3); color: #fff; font-weight: bold;
|
||||
font-size: 13px; padding: 8px 10px; }
|
||||
.ph-btn.ghost { background: #fff; color: #0077a3; border: 1px solid #00a1d6; }
|
||||
.ph-btn:hover { filter: brightness(1.05); }
|
||||
.ph-tip { margin: 8px 0 0; color: #a06b00; font-size: 12px; min-height: 1em; }
|
||||
|
||||
.order-status {
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
|
||||
@@ -34,6 +34,18 @@
|
||||
<section id="order-panel" hidden>
|
||||
<h2><span class="num">3</span> 订单状态</h2>
|
||||
<div id="order-status" class="order-status">等待创建订单…</div>
|
||||
<div id="pay-help" class="pay-help" hidden>
|
||||
<div class="ph-title">付款后这里一直没动静?</div>
|
||||
<ul class="ph-list">
|
||||
<li>付款通知一般<b>几秒到 1 分钟</b>内自动到达,到达后会自动显示卡密,<b>请不要重复付款</b>。</li>
|
||||
<li>本页订单 <b>15 分钟</b>内有效;扫<b>过期二维码</b>或其他订单的码会付不上,需要重新下单拿新码。</li>
|
||||
</ul>
|
||||
<div class="ph-btns">
|
||||
<button type="button" id="ph-refresh" class="ph-btn">🔁 立即刷新核对</button>
|
||||
<button type="button" id="ph-renew" class="ph-btn ghost">🔄 重新下单(换新二维码)</button>
|
||||
</div>
|
||||
<p class="ph-tip" id="ph-tip"></p>
|
||||
</div>
|
||||
<div id="card-box" class="card-box" hidden>
|
||||
<div class="cb-title"><span class="cb-dot"></span>你的卡密</div>
|
||||
<div class="cb-key"><code id="cb-key-text"></code></div>
|
||||
|
||||
@@ -4,6 +4,33 @@ let packages = [];
|
||||
let selected = null;
|
||||
let orderNo = null;
|
||||
let pollTimer = null;
|
||||
let lastPayType = null; // 记住当前支付方式,「重新下单」时直接复用
|
||||
let payHelpShown = false;
|
||||
let helpTipStage = 0; // 1=30秒提示 2=120秒提示;同阶段不重复覆盖刚点出来的反馈
|
||||
const PENDING_KEY = 'biliBuyPendingOrder';
|
||||
|
||||
/** 订单号落本地:关掉页面再回来也能接着查卡,不会「付了钱拿不到码」 */
|
||||
function savePending() {
|
||||
try {
|
||||
localStorage.setItem(PENDING_KEY, JSON.stringify({
|
||||
orderNo, payType: lastPayType,
|
||||
cardTypeId: selected ? selected.id : null, at: Date.now()
|
||||
}));
|
||||
} catch (e) { /* 隐私模式下不可用则忽略 */ }
|
||||
}
|
||||
|
||||
function clearPending() {
|
||||
try { localStorage.removeItem(PENDING_KEY); } catch (e) {}
|
||||
}
|
||||
|
||||
function readPending(maxAgeMs) {
|
||||
try {
|
||||
const d = JSON.parse(localStorage.getItem(PENDING_KEY) || 'null');
|
||||
if (!d || !d.orderNo) return null;
|
||||
if (!d.at || Date.now() - d.at > maxAgeMs) { clearPending(); return null; }
|
||||
return d;
|
||||
} catch (e) { return null; }
|
||||
}
|
||||
|
||||
function esc(s) {
|
||||
return String(s == null ? '' : s).replace(/[&<>"']/g, (c) => ({
|
||||
@@ -60,8 +87,10 @@ function selectPackage(id) {
|
||||
|
||||
async function createOrder(payType) {
|
||||
if (!selected) return;
|
||||
lastPayType = payType;
|
||||
$('order-panel').hidden = false;
|
||||
$('order-panel').scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
hidePayHelp();
|
||||
const status = $('order-status');
|
||||
status.className = 'order-status pending';
|
||||
status.textContent = '⏳ 正在创建订单…';
|
||||
@@ -74,6 +103,7 @@ async function createOrder(payType) {
|
||||
if (!res || !res.ok) throw new Error((res && res.message) || '创建订单失败');
|
||||
|
||||
orderNo = res.order.orderNo;
|
||||
savePending();
|
||||
status.textContent = `订单 ${orderNo}(¥${res.order.amount})已创建,正在打开支付页面…`;
|
||||
if (res.payUrl) window.open(res.payUrl, '_blank');
|
||||
startPolling();
|
||||
@@ -83,11 +113,11 @@ async function createOrder(payType) {
|
||||
}
|
||||
}
|
||||
|
||||
function startPolling() {
|
||||
if (pollTimer) clearInterval(pollTimer);
|
||||
let attempts = 0;
|
||||
pollTimer = setInterval(async () => {
|
||||
attempts++;
|
||||
let attempts = 0;
|
||||
|
||||
/** 单次订单查询:5 秒轮询与「立即刷新核对」按钮共用同一段逻辑 */
|
||||
async function queryOrderOnce() {
|
||||
attempts++;
|
||||
if (attempts > 240) {
|
||||
clearInterval(pollTimer);
|
||||
pollTimer = null;
|
||||
@@ -105,10 +135,13 @@ function startPolling() {
|
||||
if (res.activated) {
|
||||
clearInterval(pollTimer);
|
||||
pollTimer = null;
|
||||
clearPending();
|
||||
showActivated(res);
|
||||
} else if (res.cardKey) {
|
||||
clearInterval(pollTimer);
|
||||
pollTimer = null;
|
||||
hidePayHelp();
|
||||
clearPending();
|
||||
const status = $('order-status');
|
||||
status.className = 'order-status error';
|
||||
status.innerHTML = '✗ <b>已支付并已发卡</b>,但自动激活未成功(' +
|
||||
@@ -126,14 +159,100 @@ function startPolling() {
|
||||
'</b> 付款状态为已支付,<b>权益不会丢失</b>:继续等会自动发放,或凭此订单号联系客服补发。';
|
||||
}
|
||||
} else {
|
||||
const waited = attempts * 5;
|
||||
const status = $('order-status');
|
||||
status.className = 'order-status pending';
|
||||
status.textContent = '⏳ 等待支付中…(订单 ' + orderNo + ',已等待 ' + attempts * 5 + ' 秒)';
|
||||
status.textContent = '⏳ 等待支付中…(订单 ' + orderNo + ',已等待 ' + waited + ' 秒)';
|
||||
// 30 秒还没动静就主动给出口(付款通知丢失 / 扫了过期码 / 实际没扣款)
|
||||
if (waited >= 30) showPayHelp(waited);
|
||||
}
|
||||
} catch (e) {
|
||||
/* 单次查询失败不中断轮询 */
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function startPolling() {
|
||||
if (pollTimer) clearInterval(pollTimer);
|
||||
attempts = 0;
|
||||
hidePayHelp();
|
||||
queryOrderOnce(); // 先立刻查一次,不干等 5 秒
|
||||
pollTimer = setInterval(queryOrderOnce, 5000);
|
||||
}
|
||||
|
||||
/** 付款迟迟没动静时给出路,别让用户对着「等待支付中」干等 */
|
||||
function showPayHelp(waited) {
|
||||
const box = $('pay-help');
|
||||
if (!box) return;
|
||||
box.hidden = false;
|
||||
payHelpShown = true;
|
||||
const tip = $('ph-tip');
|
||||
if (!tip) return;
|
||||
const stage = waited >= 120 ? 2 : 1;
|
||||
if (tip.textContent && stage <= helpTipStage) return; // 不覆盖用户刚点「刷新」得到的反馈
|
||||
helpTipStage = stage;
|
||||
if (stage === 2) {
|
||||
tip.textContent = '已等待 ' + waited + ' 秒仍未确认支付。若你确已完成付款:请勿重复支付,留好订单号 ' +
|
||||
(orderNo || '') + ' 与微信/支付宝交易号;若二维码是旧的/已过期,点「重新下单」换一个新码再付。';
|
||||
} else {
|
||||
tip.textContent = '正在等待付款通知…已完成付款的话,点「立即刷新核对」可以马上重查一次。';
|
||||
}
|
||||
}
|
||||
|
||||
function hidePayHelp() {
|
||||
const box = $('pay-help');
|
||||
if (box) box.hidden = true;
|
||||
payHelpShown = false;
|
||||
helpTipStage = 0;
|
||||
const tip = $('ph-tip');
|
||||
if (tip) tip.textContent = '';
|
||||
}
|
||||
|
||||
/** 打开购买页时恢复上次未完成的订单:关掉页面也不会「付了钱拿不到码」 */
|
||||
function resumePending() {
|
||||
const d = readPending(30 * 60 * 1000);
|
||||
if (!d) return;
|
||||
orderNo = d.orderNo;
|
||||
if (d.payType) lastPayType = d.payType;
|
||||
if (d.cardTypeId && !selected) {
|
||||
const p = packages.find((x) => String(x.id) === String(d.cardTypeId));
|
||||
if (p) {
|
||||
selected = p;
|
||||
document.querySelectorAll('.package').forEach((el) => {
|
||||
el.classList.toggle('active', el.dataset.id === String(d.cardTypeId));
|
||||
});
|
||||
$('chosen-package').innerHTML = `已选商品:<b>${esc(p.name)}</b> 价格 <b>¥${esc(p.price)}</b> ${esc(durationText(p.duration_days))}`;
|
||||
$('step-pay').hidden = false;
|
||||
}
|
||||
}
|
||||
$('order-panel').hidden = false;
|
||||
const st = $('order-status');
|
||||
st.className = 'order-status pending';
|
||||
st.textContent = '⏳ 已恢复上次未完成的订单 ' + orderNo + ',正在查询支付结果…';
|
||||
startPolling();
|
||||
}
|
||||
|
||||
function wirePayHelp() {
|
||||
const rf = $('ph-refresh'), rn = $('ph-renew');
|
||||
if (rf) rf.addEventListener('click', async () => {
|
||||
const tip = $('ph-tip');
|
||||
if (tip) tip.textContent = '正在向授权系统核对…';
|
||||
await queryOrderOnce();
|
||||
const box = $('pay-help');
|
||||
if (!box || box.hidden || !tip) return; // 已出卡激活就不必再提示
|
||||
tip.textContent = '已于 ' + new Date().toLocaleTimeString() +
|
||||
' 重新核对:仍未确认支付。若你确已完成付款请勿重复支付(通知可能延迟);二维码过期就点「重新下单」。';
|
||||
});
|
||||
if (rn) rn.addEventListener('click', () => {
|
||||
if (!selected) {
|
||||
const tip = $('ph-tip');
|
||||
if (tip) tip.textContent = '请先在上方重新选择套餐,再选支付方式生成新订单。';
|
||||
const sp = $('step-package');
|
||||
if (sp) sp.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
return;
|
||||
}
|
||||
if (pollTimer) { clearInterval(pollTimer); pollTimer = null; }
|
||||
createOrder(lastPayType || 'wxpay');
|
||||
});
|
||||
}
|
||||
|
||||
/** 支付成功后立刻把卡密展示给用户(含自动激活失败的场景) */
|
||||
@@ -148,12 +267,22 @@ function showCardBox(key, activated) {
|
||||
}
|
||||
|
||||
function showActivated(res) {
|
||||
hidePayHelp();
|
||||
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.innerHTML = `
|
||||
<div class="ok-title">✓ 支付成功,已自动激活</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>`;
|
||||
}
|
||||
|
||||
@@ -187,4 +316,5 @@ $('cb-copy') && $('cb-copy').addEventListener('click', async () => {
|
||||
$('cb-copy-tip').textContent = ok ? '已复制,可直接粘贴到侧边栏激活' : '复制失败,请手动长按选择卡密';
|
||||
});
|
||||
|
||||
loadPackages();
|
||||
wirePayHelp();
|
||||
loadPackages().then(resumePending);
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "B站评论助手",
|
||||
"version": "1.10.1",
|
||||
"version": "1.10.7",
|
||||
"description": "B站网页版关键词评论助手:按搜索关键词找视频,默认模拟真人(打开视频页、滚到评论区、逐字输入、点发布),也可快速API直发;支持下载当前页视频;带防重复记录、可中断执行与页面实时进度浮层。",
|
||||
"permissions": ["storage", "tabs", "scripting", "sidePanel", "downloads", "declarativeNetRequest", "alarms"],
|
||||
"host_permissions": [
|
||||
|
||||
+20
-11
@@ -6,9 +6,18 @@
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { width: 100%; min-height: 100vh; font-family: "PingFang SC","Microsoft YaHei","Noto Sans CJK SC",sans-serif; font-size: 13px; color: #222; }
|
||||
header { background: #00A1D6; color: #fff; padding: 10px 12px; font-weight: bold; font-size: 14px; }
|
||||
/* 标题旁的版本号:读 manifest,不写死,升级后自动跟着变 */
|
||||
.hdr-ver { display:inline-block; margin-left:6px; padding:1px 7px; border-radius:10px;
|
||||
background:rgba(255,255,255,.22); font-size:11px; font-weight:normal; vertical-align:middle; }
|
||||
.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; }
|
||||
.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; }
|
||||
.lbl { font-size: 11px; color: #888; margin-bottom: 5px; }
|
||||
input[type=text], input[type=password], input[type=number], select {
|
||||
@@ -45,15 +54,15 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>B站评论助手</header>
|
||||
<header>B站评论助手<span id="hdrVer" class="hdr-ver"></span></header>
|
||||
|
||||
<div id="licSec" style="padding:8px 12px;border-bottom:1px solid #eee;background:#fafbfc">
|
||||
<div style="display:flex;align-items:center;gap:6px">
|
||||
<span id="licIcon" style="font-size:14px">⏳</span>
|
||||
<span id="licText" style="font-size:13px;font-weight:bold;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">授权检查中…</span>
|
||||
<a id="licBuy" style="color:#e91e63;font-weight:bold;text-decoration:underline;cursor:pointer;white-space:nowrap">购买授权 →</a>
|
||||
<div style="display:flex;align-items:flex-start;gap:6px">
|
||||
<span id="licIcon" style="font-size:14px;line-height:1.45">⏳</span>
|
||||
<span id="licText" style="font-size:13px;font-weight:bold;flex:1;line-height:1.45;word-break:break-word">授权检查中…</span>
|
||||
</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="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">
|
||||
@@ -64,11 +73,6 @@
|
||||
<div id="licMachine" style="font-size:10px;color:#bbb;margin-top:4px;cursor:pointer" title="点击复制机器码">机器码:<span id="machineIdText">…</span>(点击复制)</div>
|
||||
</div>
|
||||
|
||||
<div class="promo">
|
||||
<span>🤖 没有模型?注册即送额度</span>
|
||||
<a id="promoLink">ai.88531.cn 注册 →</a>
|
||||
</div>
|
||||
|
||||
<div class="sec">
|
||||
<div class="lbl">📊 评论记录</div>
|
||||
<div class="statRow">
|
||||
@@ -79,6 +83,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="promo">
|
||||
<span>🤖 没有模型?注册即送额度</span>
|
||||
<a id="promoLink">ai.88531.cn 注册 →</a>
|
||||
</div>
|
||||
|
||||
<div class="sec">
|
||||
<div class="lbl">LLM 配置(自动保存,仅 AI 模式需要)</div>
|
||||
<input type="text" id="baseUrl" placeholder="https://ai.88531.cn/v1">
|
||||
|
||||
+6
-1
@@ -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";
|
||||
@@ -617,6 +618,10 @@ function refreshCustomVisibility() {
|
||||
// ============ 初始化 ============
|
||||
|
||||
async function init() {
|
||||
const hv = $("hdrVer");
|
||||
if (hv) {
|
||||
try { hv.textContent = "v" + chrome.runtime.getManifest().version; } catch (e) { hv.textContent = ""; }
|
||||
}
|
||||
let saved = {};
|
||||
try { saved = (await chrome.storage.local.get("settings")).settings || {}; } catch (e) {}
|
||||
settings = Object.assign({}, DEFAULTS, saved);
|
||||
|
||||
Reference in new issue
Block a user