Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a697a2663 | ||
|
|
557f75fc54 |
No files matched your search
@@ -4,6 +4,21 @@ B站评论助手 版本历史。下载:https://dl.88531.cn/bili.html ·
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## v1.9.0 · 2026-10-14
|
||||||
|
|
||||||
|
### ✨ 新功能
|
||||||
|
- **试用策略改为 3 天 / 30 条评论,任一先到即止**:试用时长从 1 天延长到 3 天,同时设置 30 条评论上限。额度用完或时间到期,哪个先到就停哪个
|
||||||
|
- **价值时刻提示**:每批跑完直接显示「本批 N 条已发布,平均间隔 X 秒」,并同步刷新顶部横幅的剩余条数——让用户亲眼看到成果的同时看到还剩多少
|
||||||
|
- **到期后 24 小时折扣窗口**:试用结束后 24 小时内,面板横幅显示「24 小时内购买享 8 折」并倒计时;窗口关闭后恢复原价
|
||||||
|
- **过期只锁评论**:试用到期后仅锁定自动评论,搜索视频、AI 生成文案、下载当前页视频继续可用,用户不会被彻底踢走
|
||||||
|
|
||||||
|
### 🔧 调整
|
||||||
|
- 顶部横幅文案:试用中显示「剩余 X 时 · 还可评论 N 条」;额度用完与时间到期分别给出不同提示
|
||||||
|
- 试用计数只在未授权状态下累加,已激活用户不受任何影响
|
||||||
|
- 官网与 README 同步更新试用规则、折扣窗口说明
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## v1.8.1 · 2026-10-13
|
## v1.8.1 · 2026-10-13
|
||||||
|
|
||||||
### 🐛 修复
|
### 🐛 修复
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
Chrome/Edge 浏览器插件(Manifest V3):按**搜索关键词**找 B站视频,自动**评论**或**私信评论区用户**,也可**下载当前页视频**。直接复用你浏览器里的 B站登录态,**不需要手动填 Cookie**。
|
Chrome/Edge 浏览器插件(Manifest V3):按**搜索关键词**找 B站视频,自动**评论**或**私信评论区用户**,也可**下载当前页视频**。直接复用你浏览器里的 B站登录态,**不需要手动填 Cookie**。
|
||||||
|
|
||||||
- 官网 / 下载:https://dl.88531.cn/bili.html
|
- 官网 / 下载:https://dl.88531.cn/bili.html
|
||||||
- 夸克网盘:https://pan.quark.cn/s/95e3ee9d8e0f
|
- **最新版下载**:[GitHub Releases](https://github.com/personal82555/bili-auto-comment/releases/latest) · [Gitee Releases](https://gitee.com/jinghui111/bili-auto-comment/releases) · [夸克网盘](https://pan.quark.cn/s/95e3ee9d8e0f)
|
||||||
- 授权中心:https://auth.88531.cn · AI 模型 KEY:https://ai.88531.cn/
|
- 授权中心:https://auth.88531.cn · AI 模型 KEY:https://ai.88531.cn/
|
||||||
|
|
||||||
## 功能
|
## 功能
|
||||||
@@ -39,7 +39,7 @@ Chrome/Edge 浏览器插件(Manifest V3):按**搜索关键词**找 B站视
|
|||||||
- ✅ 输出真正的 mp4(Blob 带 MIME + 文件头魔数校验,CDN 回网页/错误页直接报错,不会存成 txt)
|
- ✅ 输出真正的 mp4(Blob 带 MIME + 文件头魔数校验,CDN 回网页/错误页直接报错,不会存成 txt)
|
||||||
|
|
||||||
### 授权与运维
|
### 授权与运维
|
||||||
- 🔑 1 天免费试用(倒计时精确到秒),卡密激活绑定本机永久可用;**下载视频不受授权限制**
|
- 🔑 3 天免费试用 / 30 条评论(任一先到即止,倒计时精确到秒并显示剩余条数),卡密激活绑定本机永久可用、不限量;试用到期后 24 小时内购买享 8 折;**过期只锁自动评论,搜索/AI 生成/下载视频不受影响**
|
||||||
- 📊 安装统计上报(仅机器码 + 版本,不碰B站账号),后台可看安装数与版本分布
|
- 📊 安装统计上报(仅机器码 + 版本,不碰B站账号),后台可看安装数与版本分布
|
||||||
- 📢 公告推送到面板顶部,有新版本时提示并跳官网
|
- 📢 公告推送到面板顶部,有新版本时提示并跳官网
|
||||||
- 🔁 可中断:随时 ⏹ 停止,停止标记跨页面刷新保留,发送前二次检查
|
- 🔁 可中断:随时 ⏹ 停止,停止标记跨页面刷新保留,发送前二次检查
|
||||||
@@ -48,7 +48,7 @@ Chrome/Edge 浏览器插件(Manifest V3):按**搜索关键词**找 B站视
|
|||||||
|
|
||||||
## 安装
|
## 安装
|
||||||
|
|
||||||
1. 解压 zip(或直接用解压后的目录)
|
1. 从 [Releases](https://github.com/personal82555/bili-auto-comment/releases/latest) 下载最新 zip 并解压(或直接用解压后的目录)
|
||||||
2. 打开 `chrome://extensions` → 打开右上角「开发者模式」
|
2. 打开 `chrome://extensions` → 打开右上角「开发者模式」
|
||||||
3. 「加载已解压的扩展程序」→ 选 `BiliKeywordComment` 目录
|
3. 「加载已解压的扩展程序」→ 选 `BiliKeywordComment` 目录
|
||||||
4. 打开 B站并登录,点工具栏图标打开侧边栏
|
4. 打开 B站并登录,点工具栏图标打开侧边栏
|
||||||
|
|||||||
+40
-7
@@ -69,7 +69,8 @@ reportInstall(false); // SW 启动即登记一次(同一浏览器只记一条
|
|||||||
const AUTH_BASE = "https://auth.88531.cn/api";
|
const AUTH_BASE = "https://auth.88531.cn/api";
|
||||||
const PROJECT_NAME = "B站评论插件";
|
const PROJECT_NAME = "B站评论插件";
|
||||||
const PROJECT_ID = 4;
|
const PROJECT_ID = 4;
|
||||||
const TRIAL_MS = 24 * 3600 * 1000; // 未授权试用1天
|
const TRIAL_MS = 72 * 3600 * 1000; // 未授权试用3天
|
||||||
|
const TRIAL_COMMENT_LIMIT = 30; // 试用期内最多30条评论,用完或到期任一先到即止
|
||||||
const CARD_API_KEY = "ak_ab99ed40b2296d6d2db06a4b5692b987";
|
const CARD_API_KEY = "ak_ab99ed40b2296d6d2db06a4b5692b987";
|
||||||
|
|
||||||
async function getMachineId() {
|
async function getMachineId() {
|
||||||
@@ -124,14 +125,21 @@ async function checkLicense() {
|
|||||||
offline = true; // 网络/超时 → 放行
|
offline = true; // 网络/超时 → 放行
|
||||||
}
|
}
|
||||||
|
|
||||||
const st = await chrome.storage.local.get("trialStart");
|
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) {
|
||||||
trialStart = Date.now();
|
trialStart = Date.now();
|
||||||
await chrome.storage.local.set({ trialStart: trialStart });
|
await chrome.storage.local.set({ trialStart: trialStart });
|
||||||
}
|
}
|
||||||
const trialEnd = trialStart + TRIAL_MS;
|
const trialEnd = trialStart + TRIAL_MS;
|
||||||
const leftMs = Math.max(0, trialEnd - Date.now());
|
const now = Date.now();
|
||||||
|
const leftMs = Math.max(0, trialEnd - now);
|
||||||
|
const usedComments = Number(st.trialComments) || 0;
|
||||||
|
const leftComments = Math.max(0, TRIAL_COMMENT_LIMIT - usedComments);
|
||||||
|
// 到期后24小时内购买享8折(折扣窗口从试用到期时刻起算)
|
||||||
|
const discountEnd = trialEnd + 24 * 3600 * 1000;
|
||||||
|
const inDiscount = leftMs <= 0 && now < discountEnd;
|
||||||
|
const discountLeftMs = inDiscount ? discountEnd - now : 0;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
authorized: authorized || offline, // offline 时视为放行
|
authorized: authorized || offline, // offline 时视为放行
|
||||||
@@ -141,7 +149,12 @@ async function checkLicense() {
|
|||||||
machine: machine,
|
machine: machine,
|
||||||
trialStart: trialStart,
|
trialStart: trialStart,
|
||||||
trialEnd: trialEnd,
|
trialEnd: trialEnd,
|
||||||
trialLeftMs: leftMs
|
trialLeftMs: leftMs,
|
||||||
|
trialCommentsUsed: usedComments,
|
||||||
|
trialCommentsLimit: TRIAL_COMMENT_LIMIT,
|
||||||
|
trialCommentsLeft: leftComments,
|
||||||
|
inDiscount: inDiscount,
|
||||||
|
discountLeftMs: discountLeftMs
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,12 +463,24 @@ async function sendWithRetry(tabId, msg, tries) {
|
|||||||
|
|
||||||
async function handleStartRun(p, sendResponse) {
|
async function handleStartRun(p, sendResponse) {
|
||||||
try {
|
try {
|
||||||
// 授权闸门:未授权且试用到期 → 拦截自动评论(下载视频不走这里,不受影响)
|
// 授权闸门:未授权时同时检查试用时长与试用条数(下载视频不走这里,不受影响)
|
||||||
const lic = await checkLicense();
|
const lic = await checkLicense();
|
||||||
if (!lic.authorized && lic.trialLeftMs <= 0) {
|
if (!lic.authorized) {
|
||||||
|
if (lic.trialLeftMs <= 0) {
|
||||||
sendResponse({ ok: false, error: "免费试用已到期,自动评论已锁定。购买卡密激活后即可继续使用(下载视频不受影响)" });
|
sendResponse({ ok: false, error: "免费试用已到期,自动评论已锁定。购买卡密激活后即可继续使用(下载视频不受影响)" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (lic.trialCommentsLeft <= 0) {
|
||||||
|
sendResponse({ ok: false, error: "试用期 " + lic.trialCommentsLimit + " 条评论已用完,购买卡密激活后不限量(下载视频不受影响)" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 试用中:把剩余额度写进任务配置,内容脚本发到额度会自动停
|
||||||
|
p.config = p.config || {};
|
||||||
|
p.config.trialQuota = lic.trialCommentsLeft;
|
||||||
|
if (Number(p.config.maxN) > lic.trialCommentsLeft) {
|
||||||
|
p.config.maxN = lic.trialCommentsLeft;
|
||||||
|
}
|
||||||
|
}
|
||||||
ACTIVE_TASK = null; // 本次点「开始」= 全新任务,作废残留的旧任务(旧任务会带着预生成的旧文案继续跑)
|
ACTIVE_TASK = null; // 本次点「开始」= 全新任务,作废残留的旧任务(旧任务会带着预生成的旧文案继续跑)
|
||||||
let tab = await findBiliTab();
|
let tab = await findBiliTab();
|
||||||
if (!tab) {
|
if (!tab) {
|
||||||
@@ -604,7 +629,15 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
|
|||||||
(async () => {
|
(async () => {
|
||||||
const h = await addRecord({ bvid: msg.bvid, title: msg.title, text: msg.text, keyword: msg.keyword, ts: msg.ts });
|
const h = await addRecord({ bvid: msg.bvid, title: msg.title, text: msg.text, keyword: msg.keyword, ts: msg.ts });
|
||||||
const s = statsOf(h);
|
const s = statsOf(h);
|
||||||
sendResponse({ ok: true, stats: { total: s.total, today: s.today, week: s.week } });
|
// 试用计数:每成功发一条评论消耗一次额度(仅未授权时计数)
|
||||||
|
let trialCommentsLeft = null;
|
||||||
|
const lic = await checkLicense();
|
||||||
|
if (!lic.realAuthorized && !lic.offline) {
|
||||||
|
const used = lic.trialCommentsUsed + 1;
|
||||||
|
await chrome.storage.local.set({ trialComments: used });
|
||||||
|
trialCommentsLeft = Math.max(0, lic.trialCommentsLimit - used);
|
||||||
|
}
|
||||||
|
sendResponse({ ok: true, stats: { total: s.total, today: s.today, week: s.week }, trialCommentsLeft: trialCommentsLeft });
|
||||||
})();
|
})();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-1
@@ -855,7 +855,11 @@
|
|||||||
function finish(task, ok, reason) {
|
function finish(task, ok, reason) {
|
||||||
clearTask();
|
clearTask();
|
||||||
running = false;
|
running = false;
|
||||||
relay({ type: "finished", ok: !!ok, reason: reason || "", done: task ? (task.sent || 0) : 0, failed: task ? (task.failed || 0) : 0 });
|
let avgGapSec = 0;
|
||||||
|
if (task && task.firstSentAt && task.lastSentAt && (task.sent || 0) >= 2) {
|
||||||
|
avgGapSec = Math.round((task.lastSentAt - task.firstSentAt) / ((task.sent || 1) - 1) / 1000);
|
||||||
|
}
|
||||||
|
relay({ type: "finished", ok: !!ok, reason: reason || "", done: task ? (task.sent || 0) : 0, failed: task ? (task.failed || 0) : 0, avgGapSec: avgGapSec });
|
||||||
step((ok ? "✅ " : "⏹ ") + (reason || (ok ? "执行完成" : "已停止")), ok ? "ok" : "fail");
|
step((ok ? "✅ " : "⏹ ") + (reason || (ok ? "执行完成" : "已停止")), ok ? "ok" : "fail");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -966,6 +970,11 @@
|
|||||||
const doDm = (what === "dm" || what === "both");
|
const doDm = (what === "dm" || what === "both");
|
||||||
|
|
||||||
if (doComment) {
|
if (doComment) {
|
||||||
|
// 试用额度检查:发到额度就自动停,不用等用户发现
|
||||||
|
if (cfg.trialQuota != null && (task.sent || 0) >= cfg.trialQuota) {
|
||||||
|
finish(task, true, "试用期 " + cfg.trialQuota + " 条额度已用完,购买卡密激活后不限量");
|
||||||
|
return;
|
||||||
|
}
|
||||||
step("评论[" + (SRC_LABEL[video.src] || "模板") + "]:" + text.slice(0, 30) + (text.length > 30 ? "…" : ""));
|
step("评论[" + (SRC_LABEL[video.src] || "模板") + "]:" + text.slice(0, 30) + (text.length > 30 ? "…" : ""));
|
||||||
|
|
||||||
const r = await sendOne(video, text, cfg.sendMode !== "api");
|
const r = await sendOne(video, text, cfg.sendMode !== "api");
|
||||||
@@ -974,6 +983,8 @@
|
|||||||
|
|
||||||
if (r.ok) {
|
if (r.ok) {
|
||||||
step(r.verified ? "✅ 评论成功" : "⚠️ 已发送但未在页面确认,记为已评论", r.verified ? "ok" : "fail");
|
step(r.verified ? "✅ 评论成功" : "⚠️ 已发送但未在页面确认,记为已评论", r.verified ? "ok" : "fail");
|
||||||
|
if (!task.firstSentAt) task.firstSentAt = Date.now();
|
||||||
|
task.lastSentAt = Date.now();
|
||||||
await recordOne(task, video, text, true);
|
await recordOne(task, video, text, true);
|
||||||
} else {
|
} else {
|
||||||
step("❌ 失败:" + r.error, "fail");
|
step("❌ 失败:" + r.error, "fail");
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"name": "B站评论助手",
|
"name": "B站评论助手",
|
||||||
"version": "1.8.1",
|
"version": "1.9.0",
|
||||||
"description": "B站网页版关键词评论助手:按搜索关键词找视频,默认模拟真人(打开视频页、滚到评论区、逐字输入、点发布),也可快速API直发;支持下载当前页视频;带防重复记录、可中断执行与页面实时进度浮层。",
|
"description": "B站网页版关键词评论助手:按搜索关键词找视频,默认模拟真人(打开视频页、滚到评论区、逐字输入、点发布),也可快速API直发;支持下载当前页视频;带防重复记录、可中断执行与页面实时进度浮层。",
|
||||||
"permissions": ["storage", "tabs", "scripting", "sidePanel", "downloads", "declarativeNetRequest"],
|
"permissions": ["storage", "tabs", "scripting", "sidePanel", "downloads", "declarativeNetRequest"],
|
||||||
"host_permissions": [
|
"host_permissions": [
|
||||||
|
|||||||
+26
-6
@@ -157,11 +157,25 @@ function refreshCustomVisibility() {
|
|||||||
sub.textContent = "感谢支持!全部功能可用";
|
sub.textContent = "感谢支持!全部功能可用";
|
||||||
actRow.style.display = "none";
|
actRow.style.display = "none";
|
||||||
if (buy) buy.style.display = "none";
|
if (buy) buy.style.display = "none";
|
||||||
} else if (lic.trialLeftMs > 0) {
|
} else if (lic.trialLeftMs > 0 && lic.trialCommentsLeft > 0) {
|
||||||
icon.textContent = "🎁";
|
icon.textContent = "🎁";
|
||||||
text.textContent = "免费试用中 · 剩余 " + fmtRemain(lic.trialLeftMs);
|
text.textContent = "免费试用中 · 剩余 " + fmtRemain(lic.trialLeftMs) + " · 还可评论 " + lic.trialCommentsLeft + " 条";
|
||||||
text.style.color = "#e67e22";
|
text.style.color = "#e67e22";
|
||||||
sub.textContent = "未授权可试用 1 天,购买卡密激活后不限时使用";
|
sub.textContent = "未授权可试用 3 天 / 30 条评论,购买卡密激活后不限时不限量";
|
||||||
|
actRow.style.display = "flex";
|
||||||
|
if (buy) buy.style.display = "";
|
||||||
|
} else if (lic.trialLeftMs > 0 && lic.trialCommentsLeft <= 0) {
|
||||||
|
icon.textContent = "🎁";
|
||||||
|
text.textContent = "试用期 " + lic.trialCommentsLimit + " 条评论已用完";
|
||||||
|
text.style.color = "#e67e22";
|
||||||
|
sub.textContent = "剩余时间还有效,但评论额度已用完;购买卡密激活后不限量(下载视频不受影响)";
|
||||||
|
actRow.style.display = "flex";
|
||||||
|
if (buy) buy.style.display = "";
|
||||||
|
} else if (lic.inDiscount) {
|
||||||
|
icon.textContent = "⏰";
|
||||||
|
text.textContent = "试用已到期 · 24 小时内购买享 8 折(剩 " + fmtRemain(lic.discountLeftMs) + ")";
|
||||||
|
text.style.color = "#e67e22";
|
||||||
|
sub.textContent = "折扣窗口关闭后恢复原价,别错过";
|
||||||
actRow.style.display = "flex";
|
actRow.style.display = "flex";
|
||||||
if (buy) buy.style.display = "";
|
if (buy) buy.style.display = "";
|
||||||
} else {
|
} else {
|
||||||
@@ -180,7 +194,7 @@ function refreshCustomVisibility() {
|
|||||||
licState.trialLeftMs = Math.max(0, left);
|
licState.trialLeftMs = Math.max(0, left);
|
||||||
if (left <= 0) { renderLicense(); if (licTimer) { clearInterval(licTimer); licTimer = null; } return; }
|
if (left <= 0) { renderLicense(); if (licTimer) { clearInterval(licTimer); licTimer = null; } return; }
|
||||||
const text = $("licText");
|
const text = $("licText");
|
||||||
if (text) text.textContent = "免费试用中 · 剩余 " + fmtRemain(left);
|
if (text) text.textContent = "免费试用中 · 剩余 " + fmtRemain(left) + " · 还可评论 " + licState.trialCommentsLeft + " 条";
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadLicense() {
|
async function loadLicense() {
|
||||||
@@ -517,9 +531,15 @@ function refreshCustomVisibility() {
|
|||||||
function onFinished(ev) {
|
function onFinished(ev) {
|
||||||
setRunning(false);
|
setRunning(false);
|
||||||
if (ev.ok) {
|
if (ev.ok) {
|
||||||
const msg = "执行完成:成功 " + (ev.done || 0) + " 条" + (ev.failed ? ",失败 " + ev.failed + " 条" : "");
|
let msg = "本批 " + (ev.done || 0) + " 条已发布";
|
||||||
|
if (ev.avgGapSec > 0) msg += ",平均间隔 " + ev.avgGapSec + " 秒";
|
||||||
|
if (ev.failed) msg += ",失败 " + ev.failed + " 条";
|
||||||
setStatus(msg);
|
setStatus(msg);
|
||||||
log("✅ " + msg, "ok");
|
log("🎉 " + msg, "ok");
|
||||||
|
// 试用中:刷新授权横幅,让用户立刻看到剩余额度
|
||||||
|
if (licState && !licState.authorized && !licState.offline) {
|
||||||
|
loadLicense();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const msg = ev.reason || "执行未完成";
|
const msg = ev.reason || "执行未完成";
|
||||||
setStatus(msg, true);
|
setStatus(msg, true);
|
||||||
|
|||||||
Reference in new issue
Block a user