介绍
控制面板在浏览器右下角的巨大❤

设定好运行持续时间点击开始就可以自动点赞了
源码
// ==UserScript==
// @name B站直播间自动点赞
// @namespace http://tampermonkey.net/
// @version 2.6
// @description B站直播间自动点赞
// @author 海问香
// @match https://live.bilibili.com/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// ---------- 全局唯一标记,防止脚本重复加载 ----------
if (window.__BILI_AUTO_LIKE_INSTALLED__) {
console.log('⏭️ 脚本已安装,跳过重复初始化');
return;
}
window.__BILI_AUTO_LIKE_INSTALLED__ = true;
// ---------- 仅在顶层窗口执行 ----------
if (window.top !== window.self) {
console.log('⏭️ 当前在 iframe 中,跳过创建面板');
return;
}
// ---------- 状态变量 ----------
let isRunning = false;
let count = 0;
let timer = null;
let stopTimeout = null;
let isExpanded = false;
// ---------- DOM 引用 ----------
let toggleBtn = null;
let panel = null;
let statusText = null;
let clickCountSpan = null;
let actionBtn = null;
let durationInput = null;
let modeRadios = null;
let testBtn = null;
// ---------- 工具函数:跨 iframe 查找元素 ----------
function findElementInAllFrames(selector) {
let el = document.querySelector(selector);
if (el) return el;
const iframes = document.querySelectorAll('iframe');
for (let iframe of iframes) {
try {
const doc = iframe.contentDocument || iframe.contentWindow.document;
if (doc) {
el = doc.querySelector(selector);
if (el) return el;
}
} catch (e) { /* 跨域忽略 */ }
}
return null;
}
// ---------- 获取点赞按钮(带等待) ----------
function getLikeButton() {
const selectors = [
'div.like-btn[data-type="dianzan.0.show"]',
'.like-btn[data-type="dianzan.0.show"]',
'.like-btn',
'[data-type="dianzan.0.show"]',
'.bili-live-like-btn'
];
for (let sel of selectors) {
const btn = findElementInAllFrames(sel);
if (btn) {
console.log(`✅ 找到点赞按钮(选择器:${sel})`, btn);
return btn;
}
}
console.warn('⚠️ 未找到点赞按钮');
return null;
}
// ---------- 等待按钮出现(无限等待) ----------
function waitForButton() {
return new Promise((resolve) => {
const check = () => {
const btn = getLikeButton();
if (btn) {
resolve(btn);
} else {
setTimeout(check, 500);
}
};
check();
});
}
// ---------- 执行点击 ----------
async function doClick() {
const btn = await waitForButton();
if (btn) {
['mousedown', 'mouseup', 'click'].forEach(type => {
const ev = new MouseEvent(type, {
bubbles: true,
cancelable: true,
view: window
});
btn.dispatchEvent(ev);
});
btn.click();
count++;
updatePanelStatus();
console.log(`👍 第 ${count} 次点击 (按钮)`);
} else {
// 备用键盘
const event = new KeyboardEvent('keydown', { key: 'k', bubbles: true });
document.dispatchEvent(event);
count++;
console.log(`👍 第 ${count} 次点击 (键盘 K)`);
updatePanelStatus();
}
}
// ---------- 测试点击 ----------
async function testClick() {
console.log('🔍 正在查找点赞按钮...');
const btn = await waitForButton();
if (btn) {
console.log('✅ 找到按钮,正在模拟点击...');
['mousedown', 'mouseup', 'click'].forEach(type => {
const ev = new MouseEvent(type, {
bubbles: true,
cancelable: true,
view: window
});
btn.dispatchEvent(ev);
});
btn.click();
console.log('✅ 点击完成,请观察点赞数是否增加');
} else {
console.error('❌ 未找到点赞按钮');
}
}
// ---------- 调度下一次点击 ----------
function scheduleNext() {
if (!isRunning) return;
const mode = document.querySelector('input[name="mode"]:checked');
let delay = (mode && mode.value === 'fast') ? 0.5 + Math.random() * 0.5 : 2 + Math.random() * 3;
timer = setTimeout(() => {
doClick().then(() => scheduleNext());
}, delay * 1000);
}
// ---------- 启动/停止 ----------
function startAuto() {
if (isRunning) return;
const durVal = parseFloat(durationInput.value);
if (isNaN(durVal) || durVal <= 0) {
alert('请输入有效的持续时间(分钟)');
return;
}
count = 0;
isRunning = true;
updatePanelStatus();
doClick().then(() => scheduleNext());
if (stopTimeout) clearTimeout(stopTimeout);
stopTimeout = setTimeout(() => {
if (isRunning) {
console.log(`⏰ 已运行 ${durVal} 分钟,自动停止`);
stopAuto();
}
}, durVal * 60 * 1000);
actionBtn.textContent = '停止点赞';
actionBtn.style.backgroundColor = '#f44336';
console.log(`▶️ 自动点赞已启动(模式:${getModeText()},持续 ${durVal} 分钟)`);
}
function stopAuto() {
if (!isRunning) return;
isRunning = false;
if (timer) { clearTimeout(timer); timer = null; }
if (stopTimeout) { clearTimeout(stopTimeout); stopTimeout = null; }
updatePanelStatus();
if (actionBtn) {
actionBtn.textContent = '开始点赞';
actionBtn.style.backgroundColor = '#4CAF50';
}
console.log(`⏹️ 自动点赞已停止,共点击 ${count} 次`);
}
function toggleAction() {
isRunning ? stopAuto() : startAuto();
collapsePanel();
}
function getModeText() {
const mode = document.querySelector('input[name="mode"]:checked');
return mode ? mode.value : 'slow';
}
function updatePanelStatus() {
if (statusText) {
statusText.textContent = isRunning ? '🟢 运行中' : '⏹ 已停止';
statusText.style.color = isRunning ? '#4CAF50' : '#aaa';
}
if (clickCountSpan) clickCountSpan.textContent = count + ' 次';
if (toggleBtn) {
toggleBtn.style.borderColor = isRunning ? '#4CAF50' : '#888';
toggleBtn.style.boxShadow = isRunning ? '0 0 10px rgba(76,175,80,0.6)' : 'none';
}
}
// ---------- 面板折叠/展开 ----------
function expandPanel() {
if (isExpanded) return;
isExpanded = true;
toggleBtn.style.display = 'none';
panel.style.display = 'block';
}
function collapsePanel() {
if (!isExpanded) return;
isExpanded = false;
panel.style.display = 'none';
toggleBtn.style.display = 'flex';
updatePanelStatus();
}
// ---------- 创建UI(防重入 + 强力清理) ----------
function createUI() {
// 防止并发创建
if (window.__BILI_CREATING_PANEL) {
console.warn('⚠️ 已有创建进程,跳过本次');
return;
}
window.__BILI_CREATING_PANEL = true;
// 停止所有正在运行的任务
if (isRunning) {
isRunning = false;
if (timer) { clearTimeout(timer); timer = null; }
if (stopTimeout) { clearTimeout(stopTimeout); stopTimeout = null; }
}
// 强力清理:移除所有可能残留的容器(按多种特征)
const candidates = document.querySelectorAll('[id*="auto-like"], [id*="bili-auto"], .auto-like-panel, [id="like-toggle"]');
candidates.forEach(el => {
// 避免误删其他元素,仅移除我们的容器及其父容器(如果父容器是 #auto-like-container)
if (el.id === 'auto-like-container' || el.id === 'like-toggle' || el.closest('#auto-like-container')) {
el.remove();
}
});
// 专门移除 #auto-like-container(包括可能嵌套的)
while (document.getElementById('auto-like-container')) {
document.getElementById('auto-like-container').remove();
}
// 重置引用
toggleBtn = panel = statusText = clickCountSpan = actionBtn = durationInput = modeRadios = testBtn = null;
count = 0;
isExpanded = false;
// ---------- 创建新容器 ----------
const container = document.createElement('div');
container.id = 'auto-like-container';
container.style.cssText = `
position: fixed;
bottom: 20px;
right: 20px;
z-index: 9999;
font-family: 'Microsoft YaHei', sans-serif;
font-size: 14px;
`;
// 折叠爱心
const toggle = document.createElement('div');
toggle.id = 'like-toggle';
toggle.style.cssText = `
width: 50px;
height: 50px;
border-radius: 50%;
background: #2d2d2d;
color: #ff6b6b;
font-size: 28px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
border: 2px solid #888;
box-shadow: 0 4px 12px rgba(0,0,0,0.4);
transition: all 0.2s;
user-select: none;
`;
toggle.textContent = '❤️';
toggle.title = '点击展开控制面板';
toggle.addEventListener('click', expandPanel);
container.appendChild(toggle);
toggleBtn = toggle;
// 展开面板
const panelDiv = document.createElement('div');
panelDiv.id = 'like-panel';
panelDiv.style.cssText = `
background: #2d2d2d;
color: #eee;
padding: 15px 20px;
border-radius: 10px;
width: 280px;
box-shadow: 0 4px 15px rgba(0,0,0,0.6);
border: 1px solid #555;
display: none;
`;
// 标题栏
const header = document.createElement('div');
header.style.cssText = 'display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;';
const title = document.createElement('span');
title.style.cssText = 'font-weight: bold; font-size: 16px;';
title.textContent = '🤖 自动点赞 v2.6';
const close = document.createElement('span');
close.textContent = '✕';
close.style.cssText = 'cursor: pointer; font-size: 18px; color: #aaa; transition: 0.2s;';
close.addEventListener('mouseenter', () => close.style.color = '#fff');
close.addEventListener('mouseleave', () => close.style.color = '#aaa');
close.addEventListener('click', collapsePanel);
header.appendChild(title);
header.appendChild(close);
// 状态
const statusDiv = document.createElement('div');
statusDiv.style.cssText = 'display: flex; justify-content: space-between; margin-bottom: 10px; font-size: 13px;';
const status = document.createElement('span');
status.id = 'panel-status';
status.textContent = '⏹ 已停止';
status.style.color = '#aaa';
const countSpan = document.createElement('span');
countSpan.id = 'panel-count';
countSpan.textContent = '0 次';
statusDiv.appendChild(status);
statusDiv.appendChild(countSpan);
statusText = status;
clickCountSpan = countSpan;
// 模式
const modeDiv = document.createElement('div');
modeDiv.style.cssText = 'margin-bottom: 8px;';
modeDiv.innerHTML = `
<label style="margin-right:10px;">模式:</label>
<label style="margin-right:10px; cursor:pointer;">
<input type="radio" name="mode" value="slow" checked> 慢速(2-5s)
</label>
<label style="cursor:pointer;">
<input type="radio" name="mode" value="fast"> 快速(0.5-1s)
</label>
`;
modeRadios = modeDiv.querySelectorAll('input[name="mode"]');
// 持续时间
const durationDiv = document.createElement('div');
durationDiv.style.cssText = 'display: flex; align-items: center; margin-bottom: 12px;';
const durLabel = document.createElement('label');
durLabel.textContent = '持续时间(分钟):';
durLabel.style.cssText = 'margin-right: 8px;';
const durInput = document.createElement('input');
durInput.type = 'number';
durInput.value = '5';
durInput.min = '0.5';
durInput.step = '0.5';
durInput.style.cssText = `
width: 70px;
padding: 4px 6px;
background: #444;
color: #fff;
border: 1px solid #666;
border-radius: 4px;
font-size: 13px;
`;
durationDiv.appendChild(durLabel);
durationDiv.appendChild(durInput);
durationInput = durInput;
// 操作按钮
const action = document.createElement('button');
action.id = 'action-btn';
action.textContent = '开始点赞';
action.style.cssText = `
width: 100%;
background: #4CAF50;
border: none;
color: #fff;
padding: 8px 0;
border-radius: 5px;
cursor: pointer;
font-size: 15px;
font-weight: bold;
transition: 0.2s;
margin-bottom: 6px;
`;
action.addEventListener('click', toggleAction);
actionBtn = action;
// 测试按钮
const test = document.createElement('button');
test.textContent = '🔍 测试点击';
test.style.cssText = `
width: 100%;
background: #ff9800;
border: none;
color: #fff;
padding: 5px 0;
border-radius: 5px;
cursor: pointer;
font-size: 13px;
transition: 0.2s;
`;
test.addEventListener('click', testClick);
testBtn = test;
panelDiv.appendChild(header);
panelDiv.appendChild(statusDiv);
panelDiv.appendChild(modeDiv);
panelDiv.appendChild(durationDiv);
panelDiv.appendChild(action);
panelDiv.appendChild(test);
container.appendChild(panelDiv);
panel = panelDiv;
document.body.appendChild(container);
collapsePanel();
// 释放创建锁
window.__BILI_CREATING_PANEL = false;
// 二次清理:延迟执行,确保没有多余的面板
setTimeout(() => {
const all = document.querySelectorAll('#auto-like-container');
if (all.length > 1) {
all.forEach((el, idx) => { if (idx > 0) el.remove(); });
console.log('🧹 二次清理,移除了多余面板');
}
}, 300);
console.log('✅ 自动点赞面板已加载(防重入版 v2.6)');
console.log('💡 面板右下角爱心可展开,点击“测试点击”可验证功能');
}
// ---------- 初始化 ----------
function init() {
if (document.body) {
createUI();
} else {
document.addEventListener('DOMContentLoaded', createUI);
}
}
init();
window.stopBiliLike = stopAuto;
console.log('💡 手动停止:输入 stopBiliLike()');
})();
评论
暂无评论