您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
U校园挂机脚本。自动处理"长时间未操作"弹窗,保持学习时长有效计算。
// ==UserScript== // @name U校园自动挂机脚本 // @namespace https://github.com/Yishun3762/UnipusAutoScript // @version 2.0.0 // @description U校园挂机脚本。自动处理"长时间未操作"弹窗,保持学习时长有效计算。 // @author AsagiYuumoya // @match *://*.unipus.cn/* // @match *://u.unipus.cn/* // @match *://ucontent.unipus.cn/* // @grant GM_addStyle // @license MIT // ==/UserScript== (function() { 'use strict'; // --- 配置 --- const CONFIG = { APP_NAME: 'U校园自动挂机', INACTIVITY_PROMPT_TEXT: '由于你长时间未操作,请点确定继续使用。', POPUP_CONFIRM_TEXT: '确定', DEFAULT_DURATION_MIN: 600, }; // --- 日志 --- class Logger { constructor(prefix) { this.prefix = `[${prefix}]`; } log(...args) { console.log(this.prefix, ...args); } warn(...args) { console.warn(this.prefix, ...args); } error(...args) { console.error(this.prefix, ...args); } } // --- 挂机处理器 --- class InactivityHandler { constructor(logger) { this.logger = logger; this.observer = null; this.timer = null; } start() { const check = this._checkAndClick.bind(this); // 立即检查一次 check(); // 使用 MutationObserver 监视弹窗出现 this.observer = new MutationObserver(check); this.observer.observe(document.body, { childList: true, subtree: true, }); // 同时使用 setInterval 作为备用方案 this.timer = setInterval(check, 2000); // 2秒检查一次 this.logger.log('长时间未操作检测已启动。'); } stop() { if (this.observer) { this.observer.disconnect(); this.observer = null; } if (this.timer) { clearInterval(this.timer); this.timer = null; } this.logger.log('长时间未操作检测已停止。'); } _checkAndClick() { try { const paragraphs = Array.from(document.querySelectorAll('p')); const targetNotice = paragraphs.find(p => p.textContent.includes(CONFIG.INACTIVITY_PROMPT_TEXT)); if (!targetNotice) return; const container = targetNotice.closest('div'); if (!container) return; // 查找按钮 const button = container.querySelector('button[id^="_mask_notice_id_"]') || Array.from(container.querySelectorAll('button')).find( btn => btn.textContent.includes(CONFIG.POPUP_CONFIRM_TEXT) ); if (button) { button.click(); this.logger.log('已自动点击按钮。'); } } catch (e) { this.logger.error('处理未操作提示时出错:', e); } } } // --- UI面板 --- class UIPanel { constructor(appName, defaultDuration) { this.appName = appName; this.defaultDuration = defaultDuration; this.callbacks = {}; this._injectCSS(); this._createPanel(); this._addEventListeners(); } on(event, callback) { this.callbacks[event] = callback; } getDuration() { const duration = parseInt(this.durationInput.value, 10); return isNaN(duration) || duration < 1 ? this.defaultDuration : duration; } updateState({ isRunning, elapsedTime = 0, statusText }) { this.statusText.textContent = statusText; this.elapsedTime.textContent = elapsedTime; if (isRunning) { this.startBtn.textContent = '停止挂机'; this.startBtn.classList.add('stop'); } else { this.startBtn.textContent = '开始挂机'; this.startBtn.classList.remove('stop'); } } _injectCSS() { GM_addStyle(` #unipus-auto-panel { position: fixed; top: 10px; right: 10px; background: rgba(255, 255, 255, 0.95); border: 1px solid #ccc; border-radius: 8px; padding: 15px; z-index: 9999; font-size: 14px; box-shadow: 0 4px 15px rgba(0,0,0,0.2); transition: all 0.3s ease; cursor: move; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; } #unipus-auto-panel.minimized { padding: 5px; width: auto; height: auto; } #unipus-auto-panel.minimized .controls { display: none; } #unipus-auto-panel h3 { margin: 0 0 10px 0; font-size: 16px; user-select: none; display: flex; justify-content: space-between; align-items: center; color: #333; } #unipus-auto-panel .toggle-btn { cursor: pointer; margin-left: 10px; font-size: 20px; width: 22px; height: 22px; line-height: 22px; text-align: center; color: #888; } #unipus-auto-panel .controls { display: flex; flex-direction: column; gap: 10px; } #unipus-auto-panel input[type="number"] { width: 100%; padding: 8px; box-sizing: border-box; border: 1px solid #ddd; border-radius: 4px; } #unipus-auto-panel button { padding: 8px 12px; cursor: pointer; background: #28a745; color: white; border: none; border-radius: 4px; font-size: 14px; transition: background 0.2s ease; } #unipus-auto-panel button:hover { background: #218838; } #unipus-auto-panel button.stop { background: #dc3545; } #unipus-auto-panel button.stop:hover { background: #c82333; } #unipus-auto-panel .status { margin-top: 8px; font-size: 12px; color: #555; line-height: 1.5; } #unipus-auto-panel .elapsed { font-weight: bold; color: #28a745; } `); } _createPanel() { const panel = document.createElement('div'); panel.id = 'unipus-auto-panel'; panel.innerHTML = ` <h3> <span class="title">${this.appName}</span> <span class="toggle-btn">-</span> </h3> <div class="controls"> <div> <label for="duration">挂机时长(分钟):</label> <input type="number" id="duration" min="1" value="${this.defaultDuration}"> </div> <button id="start-btn">开始挂机</button> <div class="status"> 状态: <span id="status-text">未运行</span><br> 已挂机: <span id="elapsed-time" class="elapsed">0</span> 分钟 </div> </div> `; document.body.appendChild(panel); this.panel = panel; this.durationInput = panel.querySelector('#duration'); this.startBtn = panel.querySelector('#start-btn'); this.statusText = panel.querySelector('#status-text'); this.elapsedTime = panel.querySelector('#elapsed-time'); } _addEventListeners() { this.startBtn.addEventListener('click', () => { const isRunning = this.startBtn.classList.contains('stop'); if (isRunning) { this.callbacks.stop && this.callbacks.stop(); } else { this.callbacks.start && this.callbacks.start(); } }); const toggleBtn = this.panel.querySelector('.toggle-btn'); toggleBtn.addEventListener('click', () => { this.panel.classList.toggle('minimized'); toggleBtn.textContent = this.panel.classList.contains('minimized') ? '+' : '-'; }); this._makeDraggable(); } _makeDraggable() { let isDragging = false; let offsetX, offsetY; const header = this.panel.querySelector('h3'); header.addEventListener('mousedown', (e) => { isDragging = true; offsetX = e.clientX - this.panel.getBoundingClientRect().left; offsetY = e.clientY - this.panel.getBoundingClientRect().top; this.panel.style.userSelect = 'none'; }); document.addEventListener('mousemove', (e) => { if (isDragging) { this.panel.style.left = `${e.clientX - offsetX}px`; this.panel.style.top = `${e.clientY - offsetY}px`; this.panel.style.right = 'auto'; } }); document.addEventListener('mouseup', () => { isDragging = false; this.panel.style.userSelect = 'auto'; }); } } // --- 主控制器 --- class MainController { constructor() { this.logger = new Logger(CONFIG.APP_NAME); this.inactivityHandler = new InactivityHandler(this.logger); this.uiPanel = new UIPanel(CONFIG.APP_NAME, CONFIG.DEFAULT_DURATION_MIN); this.isRunning = false; this.startTime = null; this.elapsedTimer = null; this.targetDuration = CONFIG.DEFAULT_DURATION_MIN; } init() { this.uiPanel.on('start', this.start.bind(this)); this.uiPanel.on('stop', this.stop.bind(this)); window.addEventListener('beforeunload', (e) => { if (this.isRunning) { e.preventDefault(); e.returnValue = ''; } }); this.logger.log('脚本已加载并初始化。'); } start() { if (this.isRunning) return; this.isRunning = true; this.targetDuration = this.uiPanel.getDuration(); this.startTime = new Date(); this.inactivityHandler.start(); // 每分钟更新一次UI时间 this.elapsedTimer = setInterval(this._updateElapsedTime.bind(this), 60000); this._updateElapsedTime(); // 立即更新一次 this.uiPanel.updateState({ isRunning: true, statusText: '运行中' }); this.logger.log(`挂机已启动, 目标时长: ${this.targetDuration}分钟`); } stop(reason = '用户手动停止') { if (!this.isRunning) return; this.isRunning = false; this.inactivityHandler.stop(); clearInterval(this.elapsedTimer); this.elapsedTimer = null; this.startTime = null; this.uiPanel.updateState({ isRunning: false, statusText: '未运行', elapsedTime: 0 }); this.logger.log(`挂机已停止。原因: ${reason}`); } _updateElapsedTime() { if (!this.startTime) return; const now = new Date(); const elapsedMinutes = Math.floor((now - this.startTime) / 60000); this.uiPanel.updateState({ isRunning: true, statusText: '运行中', elapsedTime: elapsedMinutes }); if (elapsedMinutes >= this.targetDuration) { this.stop(`达到目标时长 ${this.targetDuration} 分钟`); alert(`已完成设定的挂机时长: ${this.targetDuration}分钟!`); } } } // --- 启动脚本 --- function bootstrap() { try { new MainController().init(); } catch (e) { console.error(`[${CONFIG.APP_NAME}] 启动失败:`, e); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', bootstrap); } else { bootstrap(); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址