// ==UserScript== // @name 网站自动签到 // @namespace https://docs.scriptcat.org/ // @version 0.3.0 // @description 我自用的网站自动签到工具 // @author Linch // @match https://framehdr.com/* // @match https://www.kungal.com/* // @match https://www.acfun.cn/* // @match https://www.hdsay.net/* // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js // @grant GM_addStyle // @grant GM_getResourceText // @grant GM_xmlhttpRequest // @grant unsafeWindow // @grant GM_getValue // @grant GM_setValue // @grant GM.deleteValue // @grant GM_registerMenuCommand // @grant GM_openInTab // @tag AcFun // @tag 帧影 // @tag framehdr // @tag 鲲Galgame // @tag kungal // @tag 自动签到 // @run-at document-end // @noframes // @license MIT // ==/UserScript== // 一个轻量级的 message 提示实现 class MessageService { constructor() { // 创建一个容器来放所有的提示 this.container = document.createElement('div'); this.container.style.cssText = ` position: fixed; top: 20px; left: 50%; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; z-index: 9999; `; document.body.appendChild(this.container); } show(text, type = 'success') { const p = document.createElement('p'); // 基础的样式,你可以按需调整颜色、大小等 const bgColor = type === 'success' ? '#52c41a' : '#ff4d4f'; p.style.cssText = ` margin: 10px; padding: 10px 20px; background-color: ${bgColor}; color: #fff; border-radius: 4px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); font-size: 14px; animation: fadeIn 0.3s; `; p.textContent = text; this.container.appendChild(p); // 3秒后自动消失 setTimeout(() => { if (p.parentNode) { p.style.opacity = '0'; p.style.transition = 'opacity 0.3s'; setTimeout(() => p.remove(), 300); } }, 3000); } } (function() { 'use strict'; function getRandom(array) { if (array.length === 0) { return undefined; // 数组为空时返回 undefined } const randomIndex = Math.floor(Math.random() * array.length); return array[randomIndex]; } /** * 封装 GM_xmlhttpRequest 为 Promise * @template T - 期望的响应数据类型 * @param {GMTypes.XHRDetails} options - GM_xmlhttpRequest 的配置选项 * @returns {Promise} 直接返回解析后的 JSON 数据 * @throws {Error} 当 HTTP 状态非 2xx 或 JSON 解析失败时抛出错误 */ function gmRequest(options) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ ...options, onload: (resp) => { if (resp.status === 401) { reject(new Error(NEED_LOGIN)); return; } let data; try { data = JSON.parse(resp.responseText); } catch { data = resp.responseText; // 降级为原始文本 } if (resp.status >= 200 && resp.status < 300) { resolve(data); // 成功:返回解析后的数据 } else { // 失败:reject 包含状态码和响应体 const err = new Error(`HTTP ${resp.status}`); err.status = resp.status; err.responseData = data; // 携带响应内容 reject(err); } }, onerror: (err) => reject(new Error(`网络错误:${err.error || err}`)) }); }); } class HDSayModule { static parseSignStatus(htmlString) { const parser = new DOMParser(); const doc = parser.parseFromString(htmlString, 'text/html'); // 1. 获取两个状态元素 const greenSpan = Array.from(doc.querySelectorAll('span')).find( span => span.textContent.trim().includes('今日已签到') ); const graySpan = Array.from(doc.querySelectorAll('span')).find( span => span.textContent.trim().includes('今日未签到') ); // 2. 优先检查绿色元素:如果没有 display:none 说明已签到 if (greenSpan) { const greenStyle = greenSpan.getAttribute('style') || ''; if (!greenStyle.includes('display:none')) { return true; // ✅ 已签到 } } // 3. 备用检查灰色元素:如果灰色是隐藏的(display:none),说明已签到 if (graySpan) { const grayStyle = graySpan.getAttribute('style') || ''; if (grayStyle.includes('display:none')) { return true; // ✅ 已签到 } } // 4. 否则视为未签到 return false; } static getRandomMood() { const moods = ['1', '3', '10', '4', '5', '8', '9']; return getRandom(moods); } static getVerificationToken(htmlString) { const parser = new DOMParser(); const doc = parser.parseFromString(htmlString, 'text/html'); const tokenInput = doc.querySelector('form#fm_MemberSign input[name="__RequestVerificationToken"]'); return tokenInput ? tokenInput.value : null; } } const message = new MessageService(); var NEED_LOGIN="您还未登录,登录后自动签到"; var SITES = [ // 帧影 framehdr { name: "帧影 framehdr", test: function(h) { return h.endsWith('framehdr.com/') || h.endsWith('framehdr.com/index.php'); }, run: function() { window.setTimeout(async function(){ const preload = unsafeWindow._ckPreload; if (!preload) { message.show(NEED_LOGIN, 'error'); return; } const hasCheckedToday = preload.has_checked_today; const points = preload.points || 0; const totalDays = preload.total_days || 0; const continuousDays = preload.continuous_days || 0; if (hasCheckedToday) { message.show(`今日已签到,📊 当前积分: ${points},累计签到: ${totalDays} 天,连续签到: ${continuousDays} 天`); return; } let csrfToken = preload.csrf_token || unsafeWindow._ckCsrfToken || ''; try { if (!csrfToken) { const now = new Date(); const year = now.getFullYear(); const month = now.getMonth() + 1; const initData = await gmRequest({ method: 'GET', url: `https://framehdr.com/api/checkin.php?action=init&year=${year}&month=${month}` }); csrfToken = initData.data.csrf_token; } const formData = new URLSearchParams(); formData.append('csrf_token', csrfToken); const checkInData = await gmRequest({ method: 'POST', url: 'https://framehdr.com/api/checkin.php?action=checkin', data: formData, responseType: 'json' }); if (checkInData.code === 0 && checkInData.success) { message.show('🎉 签到成功!'); } else { message.show(`⚠️ ${checkInData.message}`, 'error'); } } catch (err){ message.show(`⚠️ 签到失败:${err.message}`, 'error'); } }, 1000); } }, // 鲲Galgame { name: "鲲Galgame", test: function(h){ return h.indexOf("kungal") !== -1; }, run: function(){ window.setTimeout(async () => { try { await gmRequest({ method: 'GET', url: `https://www.kungal.com/api/auth/me` }); await gmRequest({ method: 'POST', url: `https://www.kungal.com/api/user/check-in`, }); message.show('🎉 签到成功!'); } catch (err) { message.show(`⚠️ ${err.responseData?.message || err.message}`, 'error'); } }, 2000); }}, // Acfun { name: "Acfun", test: function(h){ return h.indexOf("acfun.cn") !== -1 && h.indexOf("acfun.cn/login") === -1 && h.indexOf("acfun.cn/reg"); }, run: function(){ window.setTimeout(async () => { try { await gmRequest({ method: 'GET', url: `https://www.acfun.cn/rest/pc-direct/user/personalBasicInfo`, }); const data = await gmRequest({ method: 'GET', url: 'https://www.acfun.cn/rest/pc-direct/user/signIn', }); message.show(`🎉 ${data.msg}`); } catch (err) { message.show(`⚠️ ${err.responseData?.message || err.message}`, 'error'); } }, 2000); } }, // HDSay高清乐园 { name: "HDSay.net", test: function(h){ return h.indexOf("hdsay.net") !== -1 }, run: function() { window.setTimeout(async () => { try { const userId = unsafeWindow.abp?.session?.userId; if (!userId) { message.show(NEED_LOGIN, 'error'); return; } const signPage = await gmRequest({ method: 'GET', url: `https://www.hdsay.net/member/sign` }); const checked = HDSayModule.parseSignStatus(signPage); if (checked) { message.show('⚠️ 今日已签到', 'error'); return; } const verificationToken = HDSayModule.getVerificationToken(signPage); if (!verificationToken) { message.show(`⚠️ 获取授权码失败,无法签到`, 'error'); return; } const moodWords = await gmRequest({ method: 'GET', url: `https://www.hdsay.net/api/services/app/PublicBasicDict/GetBasicDictItemsByCode?code=MoodWords&_=${new Date().getTime()}`, }); const moodWord = getRandom(moodWords.result); const preSign = await gmRequest({ method: 'GET', url: `https://www.hdsay.net/api/services/app/ForumMemberSign/GetNewWithUserId?userId=${userId}&_=${new Date().getTime()}` }); if (!preSign.success) { message.show(`⚠️ ${preSign.error?.message || preSign.error}`, 'error'); } const payload = Object.assign({}, preSign.result, { mood: HDSayModule.getRandomMood(), moodWords: moodWord.value, __RequestVerificationToken: verificationToken }); const signResult = await gmRequest({ method: 'POST', url: `https://www.hdsay.net/api/services/app/ForumMemberSign/Create`, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Accept-Language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7', 'X-Requested-With': 'XMLHttpRequest', 'Origin': 'https://www.hdsay.net', 'Referer': 'https://www.hdsay.net/member/sign', 'X-Xsrf-Token': unsafeWindow.abp.security?.antiForgery?.getToken() }, data: JSON.stringify(payload) }); if (!signResult.success) { message.show(`⚠️ 签到失败:${signResult.error?.message || signResult.error}`, 'error'); return; } message.show(`🎉 签到成功:[${signResult.result.moodName}] ${signResult.result.moodWords}`); } catch (err) { message.show(`⚠️ ${err.responseData?.message || err.message}`, 'error'); } }, 2000); } } ]; var href = window.location.href; for (var i = 0; i < SITES.length; i++) { if (SITES[i].test(href)) { SITES[i].run(); return; } } })();