天天忘记签到,现在好了,访问自动签到!!!哈哈😄
// ==UserScript==
// @name 大佬论坛(dalao.net)静默自动签到(修复版)
// @namespace https://www.dalao.net/
// @version 0.1.1
// @description 访问 dalao.net 时自动执行每日签到(不弹窗、不打扰)
// @author www.evan.xin
// @match https://www.dalao.net/*
// @run-at document-idle
// @grant GM_getValue
// @grant GM_setValue
// ==/UserScript==
(function () {
'use strict';
const DEBUG = false; // true: 控制台输出调试信息
const log = (...args) => DEBUG && console.log('[dalao-auto-signin]', ...args);
// 仅在主域 + 顶层页面运行,避免 iframe / 资源请求等
if (location.hostname !== 'www.dalao.net') return;
if (window.top !== window.self) return;
// 一天只跑一次(本地记录,避免每次刷新都请求)
const today = new Date();
const todayKey = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
const lastRun = GM_getValue('lastRun', '');
if (lastRun === todayKey) {
log('already ran today:', todayKey);
return;
}
// 简单 sleep
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
// 解析类似 JSON 的响应(Content-Type 可能不是 application/json)
const safeJsonParse = (text) => {
try {
return JSON.parse(text);
} catch (e) {
return null;
}
};
// 判断是否登录(尽量宽松:只要页面上出现账号设置/退出/头像等任一)
const isLoggedIn = () => {
const hasAccountSettings = !!document.querySelector('a[title="个人账号设置"], a[href*="my.htm"], a[href*="user-"], a[href*="/my-"]');
const hasLogout = !!document.querySelector('a[href*="logout"], a[href*="/logout"], a[title*="退出"], a:has(span[aria-label="logout"])');
const hasAvatar = !!document.querySelector('img.avatar, img[alt*="avatar"], .avatar img');
return hasAccountSettings || hasLogout || hasAvatar;
};
// 是否存在“签到入口”(用于减少未登录时的无意义请求;但不作为硬条件)
const hasSigninEntry = () => {
return (
!!document.querySelector('#nav-signin') ||
!!document.querySelector('a[href*="signin.htm"], a[href*="/signin"], a[onclick*="signin"], a[title*="签到"], a:contains("签到")')
);
};
// 由于 :contains 不是标准选择器,上面那条可能报错,兜底处理
const safeHasSigninEntry = () => {
try {
return hasSigninEntry();
} catch (e) {
// 退化:遍历链接文本
const links = Array.from(document.querySelectorAll('a'));
return links.some((a) => (a.textContent || '').includes('签到') || (a.getAttribute('href') || '').includes('signin'));
}
};
async function doSigninOnce() {
// 随机延迟,降低“刚打开页面就请求”的突兀感
const delay = 3000 + Math.floor(Math.random() * 7000);
await sleep(delay);
if (!isLoggedIn()) {
log('not logged in, skip');
return false;
}
// 如果页面上完全找不到签到相关入口,也先不浪费请求(可按需注释掉)
if (!safeHasSigninEntry()) {
log('no signin entry detected, skip');
return false;
}
// POST /signin.htm(站点逻辑通常是无 body)
let resp;
try {
resp = await fetch('https://www.dalao.net/signin.htm', {
method: 'POST',
credentials: 'include',
headers: {
'X-Requested-With': 'XMLHttpRequest',
// 某些站点会校验 referer
'Referer': location.href,
},
});
} catch (e) {
log('fetch error:', e);
return false;
}
const text = await resp.text();
const data = safeJsonParse(text);
log('signin response:', resp.status, data || text.slice(0, 200));
// 兼容不同字段名
const message = (data && (data.message ?? data.msg ?? data.mesg)) ? String(data.message ?? data.msg ?? data.mesg) : String(text);
// 成功/已签到都算完成,写入今日标记,避免重复请求
if (/签到成功|今日已签到|已经签到|已签到/.test(message) || (data && (data.code === 0 || data.ok === 1))) {
GM_setValue('lastRun', todayKey);
log('marked lastRun:', todayKey);
return true;
}
// 服务器返回 200 但 message 未匹配时,也别重复轰炸:
// 你可以把下面这一段注释掉,让它只在明确成功时才写入。
if (resp.ok) {
log('resp.ok but message not matched, keep lastRun unchanged');
}
return false;
}
// 失败重试:轻量两次(网络抖动时有用)
(async () => {
for (let i = 0; i < 2; i++) {
const ok = await doSigninOnce();
if (ok || GM_getValue('lastRun', '') === todayKey) break;
await sleep(2000 + Math.floor(Math.random() * 3000));
}
})();
})();
直接贴到油猴脚本中即可。有问题🤨随时交流!!!
𝐌𝐢.𝐂𝐃 ✕ 𝐁𝐎𝐁𝐎𝐉𝐈
给楼主投上 1 枚硬币
当前您的硬币余额:0