702
图床 tuchuang.mochu.cc.cd
每天打开论坛自动帮你完成签到,再也不用手动点了 ✅
Ctrl + S 保存即可javascript// ==UserScript==
// @name 女仆论坛自动签到
// @namespace http://tampermonkey.net/
// @version 4.0
// @description 自动完成 bbs.bt.sb 侧边栏及日历弹窗的两步签到
// @author mochu
// @match *://bbs.bt.sb/*
// @icon https://bbs.bt.sb/favicon.ico
// @grant none
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
// ═══════════════════════════════════════════
// 配 置 区
// ═══════════════════════════════════════════
const CONFIG = {
maxClicks: 3, // 最多点击次数(侧边栏1次 + 弹窗1次 + 容错1次)
maxWaitSec: 30, // 最长等待秒数,超时就放弃
pollMs: 1200, // 轮询间隔(毫秒)
debug: false // 开启后在 console 输出详细日志
};
// ═══════════════════════════════════════════
// 工 具 函 数
// ═══════════════════════════════════════════
const TAG = '[女仆签到]';
const log = (...args) => console.log(TAG, ...args);
const dbg = (...args) => CONFIG.debug && console.log(TAG, '[DBG]', ...args);
/** 今天的日期字符串,用于 localStorage 去重 */
function todayKey() {
const d = new Date();
return `checkin_${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`;
}
/** 页面内弹出一个小提示(右上角浮层,3 秒后自动消失) */
function showToast(msg, color = '#52c41a') {
const el = document.createElement('div');
Object.assign(el.style, {
position: 'fixed', top: '16px', right: '16px', zIndex: '99999',
padding: '12px 22px', borderRadius: '10px',
background: color, color: '#fff',
fontSize: '14px', fontWeight: '600',
boxShadow: '0 4px 16px rgba(0,0,0,.18)',
opacity: '0', transform: 'translateY(-12px)',
transition: 'all .35s ease', pointerEvents: 'none'
});
el.textContent = msg;
document.body.appendChild(el);
requestAnimationFrame(() => {
el.style.opacity = '1';
el.style.transform = 'translateY(0)';
});
setTimeout(() => {
el.style.opacity = '0';
el.style.transform = 'translateY(-12px)';
setTimeout(() => el.remove(), 400);
}, 3200);
}
/**
* 在可见元素中查找纯文本完全匹配 target 的元素
* 优先返回层级最深(最内层)的匹配,避免误点父容器
*/
function findVisibleByText(target) {
const all = document.querySelectorAll('button, a, span, div, p, label');
const hits = [];
for (const el of all) {
// 只看自身直属文本,排除子元素干扰
const ownText = Array.from(el.childNodes)
.filter(n => n.nodeType === Node.TEXT_NODE)
.map(n => n.textContent.trim())
.join('')
.replace(/\s+/g, '');
// 也兼容只有一个子元素且子元素包含目标文字的情况
const innerText = el.textContent.trim().replace(/\s+/g, '');
const matched = ownText === target || (innerText === target && el.children.length === 0);
if (matched && el.offsetParent !== null) {
hits.push(el);
}
}
return hits;
}
/** 获取真正可点击的最近祖先(button > a > 自身) */
function clickable(el) {
return el.closest('button') || el.closest('a') || el;
}
// ═══════════════════════════════════════════
// 主 逻 辑
// ═══════════════════════════════════════════
function run() {
// —— 1. 今日已签到过就跳过(同一浏览器同一天内不重复执行) ——
if (localStorage.getItem(todayKey())) {
dbg('今日已在 localStorage 中标记签到完成,跳过。');
return;
}
let clicks = 0;
let elapsed = 0;
let timer = null;
function stop(reason) {
clearInterval(timer);
dbg('停止轮询:', reason);
}
timer = setInterval(() => {
elapsed += CONFIG.pollMs;
// —— 2. 检测"已签到"状态 ——
const doneHits = findVisibleByText('已签到');
if (doneHits.length > 0) {
localStorage.setItem(todayKey(), '1');
log('✅ 签到成功!');
showToast('✅ 女仆论坛 · 今日签到完成');
stop('已签到');
return;
}
// —— 3. 超时保护 ——
if (elapsed >= CONFIG.maxWaitSec * 1000) {
log('⏰ 等待超时,可能未登录或签到按钮不存在。');
showToast('⏰ 签到超时,请检查登录状态', '#faad14');
stop('超时');
return;
}
// —— 4. 点击次数保护 ——
if (clicks >= CONFIG.maxClicks) {
log('⚠️ 已达最大点击次数,等待页面响应...');
// 不立即停止,继续等"已签到"状态出现
return;
}
// —— 5. 查找并点击"签到"按钮 ——
const signBtns = findVisibleByText('签到');
if (signBtns.length > 0) {
// 优先点击最后一个(弹窗内的按钮一般在 DOM 尾部)
const target = clickable(signBtns[signBtns.length - 1]);
clicks++;
log(`🖱️ 第 ${clicks} 次点击 →`, target.tagName, target.className || '');
target.click();
} else {
dbg(`等待签到按钮出现... (${Math.round(elapsed / 1000)}s)`);
}
}, CONFIG.pollMs);
// —— 6. 兜底:页面卸载前清理定时器 ——
window.addEventListener('beforeunload', () => stop('页面卸载'));
}
// —— 入口:等 DOM 完全就绪后再启动 ——
if (document.readyState === 'complete') {
setTimeout(run, 800);
} else {
window.addEventListener('load', () => setTimeout(run, 800));
}
})();
✅ 女仆论坛 · 今日签到完成debug: false 改成 debug: true,然后按 F12 打开控制台查看有问题欢迎回帖交流 👋