// ==UserScript== // @name 原神激励领奖 // @namespace http://tampermonkey.net/ // @version 2025-06-19-v2 // @description B站原神激励活动自动领奖脚本,简洁高效的自动化工具 // @author You // @match https://www.bilibili.com/blackboard/new-award-exchange.html* // @icon https://www.google.com/s2/favicons?sz=64&domain=bilibili.com // @license MIT // @grant none // @downloadURL https://update.greasyfork.icu/scripts/538700/%E5%8E%9F%E7%A5%9E%E6%BF%80%E5%8A%B1%E9%A2%86%E5%A5%96.user.js // @updateURL https://update.greasyfork.icu/scripts/538700/%E5%8E%9F%E7%A5%9E%E6%BF%80%E5%8A%B1%E9%A2%86%E5%A5%96.meta.js // ==/UserScript== (function() { 'use strict'; // ========== 全局状态 ========== const state = { isAutoClicking: false, clickCount: 0, timers: { autoClick: null, timeUpdate: null, monitor: null } }; // ========== 配置管理 ========== const config = { interval: 500, // 默认点击间隔 autoRefresh: false, // 自动刷新开关 load() { this.interval = parseInt(localStorage.getItem('click-interval')) || 500; this.autoRefresh = localStorage.getItem('auto-refresh') === 'true'; }, save() { localStorage.setItem('click-interval', this.interval); localStorage.setItem('auto-refresh', this.autoRefresh); } }; // ========== 按钮管理 ========== const buttonManager = { selector: "#app > div > div.home-wrap.select-disable > section.tool-wrap > div.button.exchange-button", stopTexts: ["查看奖励", "每日库存已达上限", "暂无领取资格"], get element() { return document.querySelector(this.selector); }, get text() { return this.element?.textContent.trim() || ''; }, removeDisable() { const button = this.element; if (button) { button.classList.remove("disable"); console.log("Button disable class removed"); } }, shouldAutoClick() { return this.text === "领取奖励"; }, shouldInitialClick() { return this.text !== "查看奖励"; }, shouldStop() { return this.stopTexts.includes(this.text); }, click() { const button = this.element; if (button) { button.click(); return true; } return false; }, isVerificationPresent() { return document.querySelector("body > div.geetest_panel.geetest_wind > div.geetest_panel_box.geetest_no_logo.geetest_panelshowclick > div.geetest_panel_next") !== null; } }; // ========== 消息系统 ========== const messageSystem = { container: null, init() { if (!this.container) { this.container = document.createElement('div'); this.container.style.cssText = ` position: fixed; top: 20px; left: 20px; z-index: 10000; display: flex; flex-direction: column; gap: 10px; pointer-events: none; `; document.body.appendChild(this.container); } }, show(message, type = 'info', duration = 3000) { this.init(); const colors = { success: '#51CF66', info: '#339AF0', error: '#FF6B6B' }; const notification = document.createElement('div'); notification.textContent = message; notification.style.cssText = ` padding: 12px 20px; background-color: ${colors[type]}; color: white; border-radius: 8px; font-size: 14px; font-weight: bold; box-shadow: 0 4px 12px rgba(0,0,0,0.3); max-width: 300px; transform: translateX(-100%); opacity: 0; transition: all 0.3s ease-out; pointer-events: auto; `; this.container.appendChild(notification); // 动画显示 setTimeout(() => { notification.style.transform = 'translateX(0)'; notification.style.opacity = '1'; }, 10); // 自动移除 setTimeout(() => { notification.style.transform = 'translateX(-100%)'; notification.style.opacity = '0'; setTimeout(() => notification.remove(), 300); }, duration); } }; // ========== 时间显示 ========== const timeDisplay = { iframe: null, init() { // 创建隐藏iframe获取网络时间 this.iframe = document.createElement('iframe'); this.iframe.src = 'https://www.bjtime.net/'; this.iframe.style.cssText = 'position:absolute;top:-9999px;left:-9999px;width:1px;height:1px;opacity:0;'; document.body.appendChild(this.iframe); this.iframe.onload = () => this.startUpdate(); this.iframe.onerror = () => this.startLocalUpdate(); // 5秒超时使用本地时间 setTimeout(() => { const display = document.getElementById('time-display'); if (display && display.textContent === '00:00:00.000') { this.startLocalUpdate(); } }, 5000); }, startUpdate() { state.timers.timeUpdate = setInterval(() => { const timeEl = document.getElementById('time-display'); const dateEl = document.getElementById('date-display'); if (!timeEl || !dateEl) return; try { const iframeDoc = this.iframe.contentDocument; const timeElement = iframeDoc.querySelector('#cTime'); if (timeElement?.textContent) { const parts = timeElement.textContent.split(' '); if (parts.length >= 2) { dateEl.textContent = parts[0]; timeEl.textContent = parts[1]; this.checkAutoRefresh(parts[1]); return; } } } catch (e) { // 跨域错误,使用本地时间 } this.updateLocal(timeEl, dateEl); }, 100); }, startLocalUpdate() { state.timers.timeUpdate = setInterval(() => { const timeEl = document.getElementById('time-display'); const dateEl = document.getElementById('date-display'); if (timeEl && dateEl) { this.updateLocal(timeEl, dateEl); } }, 100); }, updateLocal(timeEl, dateEl) { const now = new Date(); const date = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0') + '-' + String(now.getDate()).padStart(2, '0'); const time = String(now.getHours()).padStart(2, '0') + ':' + String(now.getMinutes()).padStart(2, '0') + ':' + String(now.getSeconds()).padStart(2, '0') + '.' + String(now.getMilliseconds()).padStart(3, '0'); dateEl.textContent = date; timeEl.textContent = time; this.checkAutoRefresh(time); }, checkAutoRefresh(timeString) { if (!config.autoRefresh) return; // 检查是否为00:59:59 if (timeString.startsWith('00:59:59')) { messageSystem.show('即将到达1点,正在刷新页面准备领奖...', 'info'); this.cleanup(); setTimeout(() => window.location.reload(), 500); } }, cleanup() { if (state.timers.timeUpdate) { clearInterval(state.timers.timeUpdate); state.timers.timeUpdate = null; } } }; // ========== 自动点击控制 ========== const autoClicker = { start() { if (state.isAutoClicking) return; const button = buttonManager.element; if (!button) { messageSystem.show("找不到领奖按钮!", "error"); return; } state.isAutoClicking = true; state.clickCount = 0; ui.updateButton(); messageSystem.show(`开始自动领奖 (${config.interval}ms间隔)`, "success"); state.timers.autoClick = setInterval(() => { // 检查验证码 if (buttonManager.isVerificationPresent()) { console.log('Verification panel detected, skipping click'); return; } // 检查停止条件 if (buttonManager.shouldStop()) { this.stop(`${buttonManager.text} (总共点击 ${state.clickCount} 次)`); return; } // 执行点击 if (buttonManager.click()) { state.clickCount++; messageSystem.show(`第 ${state.clickCount} 次点击领奖`, "info", 1500); } else { this.stop(`按钮消失,已停止 (总共点击 ${state.clickCount} 次)`); } }, config.interval); // 30秒超时保护 setTimeout(() => { if (state.isAutoClicking) { this.stop(`自动领奖已超时停止 (总共点击 ${state.clickCount} 次)`); } }, 10000); }, stop(reason = null) { if (!state.isAutoClicking) return; if (state.timers.autoClick) { clearInterval(state.timers.autoClick); state.timers.autoClick = null; } state.isAutoClicking = false; ui.updateButton(); const message = reason || `已停止自动领奖 (总共点击 ${state.clickCount} 次)`; messageSystem.show(message, "info"); state.clickCount = 0; }, toggle() { if (state.isAutoClicking) { this.stop(); } else { this.start(); } } }; // ========== 监控系统 ========== const monitor = { hasAutoClicked: false, start() { state.timers.monitor = setInterval(() => { // 移除按钮禁用状态 buttonManager.removeDisable(); // 检查自动点击条件 if (!this.hasAutoClicked && buttonManager.shouldAutoClick()) { console.log('Auto-trigger detected: button text is "领取奖励"'); messageSystem.show('检测到"领取奖励",自动点击一次', 'success'); buttonManager.click(); this.hasAutoClicked = true; } // 检查页面错误 this.checkPageError(); }, 1000); }, checkPageError() { const errorDialog = document.querySelector('body > div.v-dialog > div.v-dialog__wrap > div > div.v-dialog__body'); if (errorDialog) { console.log('Error dialog detected, refreshing page...'); messageSystem.show('检测到页面错误,正在刷新...', 'info'); this.cleanup(); setTimeout(() => window.location.reload(), 100); } }, cleanup() { if (state.timers.monitor) { clearInterval(state.timers.monitor); state.timers.monitor = null; } } }; // ========== UI控制 ========== const ui = { panel: null, create() { this.panel = document.createElement("div"); this.panel.style.cssText = ` position: fixed; top: 2%; right: 2%; z-index: 9999; background: rgba(255, 255, 255, 0.95); border-radius: 8px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); backdrop-filter: blur(10px); min-width: 180px; display: flex; flex-direction: column; `; // 创建内容 this.panel.innerHTML = `
自动领奖
⋮⋮
1点自动领奖
00:00:00.000
2025-01-19
💡 进入页面后会自动点击一次
`; document.body.appendChild(this.panel); this.bindEvents(); this.updateSettings(); }, bindEvents() { // 控制按钮 document.getElementById('control-btn').onclick = () => autoClicker.toggle(); // 间隔选择 const intervalSelect = document.getElementById('interval-select'); intervalSelect.value = config.interval; intervalSelect.onchange = (e) => { config.interval = parseInt(e.target.value); config.save(); messageSystem.show(`点击间隔已设置为 ${config.interval}ms`, "info"); // 如果正在运行,重启 if (state.isAutoClicking) { autoClicker.stop(); setTimeout(() => autoClicker.start(), 100); } }; // 自动刷新开关 const refreshSwitch = document.getElementById('refresh-switch'); refreshSwitch.onclick = () => { config.autoRefresh = !config.autoRefresh; config.save(); this.updateSwitch(); messageSystem.show(`1点自动领奖已${config.autoRefresh ? '开启' : '关闭'}`, "info"); }; // 拖动功能 this.addDragFunctionality(); }, updateButton() { const btn = document.getElementById('control-btn'); if (btn) { if (state.isAutoClicking) { btn.textContent = "停止自动领奖"; btn.style.backgroundColor = "#FF6B6B"; } else { btn.textContent = "开始自动领奖"; btn.style.backgroundColor = "#00A1D6"; } } }, updateSwitch() { const switchEl = document.getElementById('refresh-switch'); const thumb = switchEl.firstElementChild; if (config.autoRefresh) { switchEl.style.backgroundColor = '#4CAF50'; thumb.style.left = '22px'; } else { switchEl.style.backgroundColor = '#ccc'; thumb.style.left = '2px'; } }, updateSettings() { document.getElementById('interval-select').value = config.interval; this.updateSwitch(); }, addDragFunctionality() { const titleBar = this.panel.firstElementChild; let isDragging = false; let startX, startY, startLeft, startTop; titleBar.onmousedown = (e) => { isDragging = true; startX = e.clientX; startY = e.clientY; const rect = this.panel.getBoundingClientRect(); startLeft = rect.left; startTop = rect.top; titleBar.style.cursor = 'grabbing'; e.preventDefault(); }; document.onmousemove = (e) => { if (!isDragging) return; let newLeft = startLeft + (e.clientX - startX); let newTop = startTop + (e.clientY - startY); // 边界检查 const maxLeft = window.innerWidth - this.panel.offsetWidth; const maxTop = window.innerHeight - this.panel.offsetHeight; newLeft = Math.max(0, Math.min(newLeft, maxLeft)); newTop = Math.max(0, Math.min(newTop, maxTop)); this.panel.style.left = newLeft + 'px'; this.panel.style.top = newTop + 'px'; this.panel.style.right = 'auto'; this.panel.style.bottom = 'auto'; }; document.onmouseup = () => { if (isDragging) { isDragging = false; titleBar.style.cursor = 'grab'; } }; } }; // ========== 初始化 ========== function init() { setTimeout(() => { config.load(); buttonManager.removeDisable(); ui.create(); timeDisplay.init(); monitor.start(); // 页面加载后立即检查自动点击 setTimeout(() => { if (buttonManager.shouldInitialClick()) { console.log('Initial auto-click triggered'); messageSystem.show('页面加载完成,自动点击一次', 'success'); buttonManager.click(); monitor.hasAutoClicked = true; } }, 100); console.log("Auto-click userscript initialized (v2)"); }, 100); } // ========== 页面加载检测 ========== if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } // ========== 页面卸载清理 ========== window.addEventListener('beforeunload', () => { Object.values(state.timers).forEach(timer => { if (timer) clearInterval(timer); }); timeDisplay.cleanup(); monitor.cleanup(); }); })();