您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
川大自动抢课脚本 - Web Worker优化版
// ==UserScript== // @name 四川大学自动抢课简单脚本 // @namespace http://tampermonkey.net/ // @version 1.02 // @description 川大自动抢课脚本 - Web Worker优化版 // @author Cloud Hypnos // @license GPL-3.0 // @match http://zhjw.scu.edu.cn/student/courseSelect/courseSelect/* // @match https://zhjw.scu.edu.cn/student/courseSelect/courseSelect/* // @grant none // @run-at document-end // ==/UserScript== (function() { 'use strict'; // 切换这里的值来改变配色: 'PINK' 或 'GREEN' const CURRENT_THEME = 'GREEN'; const THEMES = { PINK: { primary: '#ff6f91', primaryLight: '#ff8fa3', primaryDark: '#e6537c', success: '#4caf50', error: '#f44336', warning: '#ff9800', info: '#2196f3', gray: '#6c757d' }, GREEN: { primary: '#00c9a7', primaryLight: '#00d9b8', primaryDark: '#008f7a', success: '#4caf50', error: '#f44336', warning: '#ff9800', info: '#2196f3', gray: '#6c757d' } }; const THEME_COLORS = THEMES[CURRENT_THEME]; let isRunning = false; let isDragging = false; let dragOffset = { x: 0, y: 0 }; let queryCount = 0; let worker = null; let startTime = null; let timeInterval = null; // 创建Web Worker function createWorker() { const workerCode = ` let interval = null; self.addEventListener('message', function(e) { if (e.data.command === 'start') { if (interval) clearInterval(interval); interval = setInterval(() => { self.postMessage({ type: 'tick' }); }, e.data.interval || 600); } else if (e.data.command === 'stop') { if (interval) { clearInterval(interval); interval = null; } } }); `; const blob = new Blob([workerCode], { type: 'application/javascript' }); const workerUrl = URL.createObjectURL(blob); return new Worker(workerUrl); } // 创建控制面板 function createButton() { const panel = document.createElement('div'); panel.id = 'autoGrabPanel'; panel.innerHTML = ` <div style="display: flex; border-radius: 5px; overflow: hidden; box-shadow: 0 3px 12px rgba(0,0,0,0.2);"> <!-- 左侧拖动区域 --> <div id="dragArea" style=" width: 20px; background: linear-gradient(135deg, ${THEME_COLORS.primary} 0%, ${THEME_COLORS.primaryDark} 100%); cursor: move; display: flex; align-items: center; justify-content: center; padding: 6px 2px; user-select: none; transition: all 0.2s ease; " title="拖动"> <svg width="10" height="10" viewBox="0 0 24 24" fill="white" opacity="0.8"> <path d="M10 9h4V6h3l-5-5-5 5h3v3zm-1 1H6V7l-5 5 5 5v-3h3v-4zm14 2l-5-5v3h-3v4h3v3l5-5zm-9 3h-4v3H7l5 5 5-5h-3v-3z"/> </svg> </div> <!-- 右侧功能区域 --> <div style=" background: white; padding: 6px 8px; min-width: 120px; border: 1px solid #e0e0e0; border-left: none; "> <!-- 查询计数 --> <div id="queryCounter" style=" margin-bottom: 5px; font-size: 10px; color: #666; display: flex; align-items: center; justify-content: space-between; "> <span>查询: <span id="queryCount" style="font-weight: 700; color: ${THEME_COLORS.primary};">0</span></span> <span id="timeElapsed" style="display: none;">运行: <span id="runTime">0</span>s</span> </div> <!-- 主按钮 --> <button id="actionBtn" style=" width: 100%; padding: 6px 8px; background: linear-gradient(135deg, ${THEME_COLORS.primary} 0%, ${THEME_COLORS.primaryDark} 100%); color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 12px; font-weight: 700; transition: all 0.2s ease; box-shadow: 0 2px 6px rgba(0,0,0,0.15); line-height: 1; "> 开始抢课 </button> </div> </div> `; panel.style.cssText = ` position: fixed; top: 20px; right: 20px; z-index: 9999; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; `; document.body.appendChild(panel); setupDragEvents(panel); setupButtonEvents(); } // 设置拖动事件 function setupDragEvents(panel) { const dragArea = document.getElementById('dragArea'); dragArea.onmouseenter = function() { if (!isDragging) { dragArea.style.background = `linear-gradient(135deg, ${THEME_COLORS.primaryLight} 0%, ${THEME_COLORS.primary} 100%)`; } }; dragArea.onmouseleave = function() { if (!isDragging) { dragArea.style.background = `linear-gradient(135deg, ${THEME_COLORS.primary} 0%, ${THEME_COLORS.primaryDark} 100%)`; } }; dragArea.onmousedown = function(e) { isDragging = true; const rect = panel.getBoundingClientRect(); dragOffset.x = e.clientX - rect.left; dragOffset.y = e.clientY - rect.top; dragArea.style.background = `linear-gradient(135deg, ${THEME_COLORS.primaryDark} 0%, ${THEME_COLORS.primary} 100%)`; dragArea.style.transform = 'scale(0.95)'; document.body.style.cursor = 'move'; const overlay = document.createElement('div'); overlay.id = 'dragOverlay'; overlay.style.cssText = ` position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 9998; cursor: move; `; document.body.appendChild(overlay); e.preventDefault(); }; document.onmousemove = function(e) { if (isDragging) { panel.style.left = (e.clientX - dragOffset.x) + 'px'; panel.style.top = (e.clientY - dragOffset.y) + 'px'; panel.style.right = 'auto'; } }; document.onmouseup = function() { if (isDragging) { isDragging = false; dragArea.style.background = `linear-gradient(135deg, ${THEME_COLORS.primary} 0%, ${THEME_COLORS.primaryDark} 100%)`; dragArea.style.transform = 'scale(1)'; document.body.style.cursor = 'auto'; const overlay = document.getElementById('dragOverlay'); if (overlay) overlay.remove(); } }; document.oncontextmenu = function(e) { if (isDragging) { isDragging = false; dragArea.style.background = `linear-gradient(135deg, ${THEME_COLORS.primary} 0%, ${THEME_COLORS.primaryDark} 100%)`; dragArea.style.transform = 'scale(1)'; document.body.style.cursor = 'auto'; const overlay = document.getElementById('dragOverlay'); if (overlay) overlay.remove(); e.preventDefault(); return false; } }; } // 设置按钮事件 function setupButtonEvents() { const actionBtn = document.getElementById('actionBtn'); actionBtn.onclick = function(e) { e.stopPropagation(); toggleAutoGrab(); }; actionBtn.onmouseenter = function() { if (!isRunning) { this.style.transform = 'translateY(-1px)'; this.style.boxShadow = '0 3px 8px rgba(0,0,0,0.15)'; } }; actionBtn.onmouseleave = function() { this.style.transform = 'translateY(0)'; this.style.boxShadow = '0 2px 6px rgba(0,0,0,0.15)'; }; } // 更新按钮 function updateButton(text, color) { const actionBtn = document.getElementById('actionBtn'); if (actionBtn) { actionBtn.textContent = text; actionBtn.style.background = color.includes('gradient') ? color : `linear-gradient(135deg, ${color} 0%, ${color} 100%)`; } } // 更新查询计数和运行时间 function updateQueryCount() { queryCount++; const countElement = document.getElementById('queryCount'); if (countElement) { countElement.textContent = queryCount; } } function startTimer() { startTime = Date.now(); document.getElementById('timeElapsed').style.display = 'block'; timeInterval = setInterval(() => { if (startTime) { const elapsed = Math.floor((Date.now() - startTime) / 1000); document.getElementById('runTime').textContent = elapsed; } }, 1000); } function stopTimer() { startTime = null; if (timeInterval) { clearInterval(timeInterval); timeInterval = null; } document.getElementById('timeElapsed').style.display = 'none'; } function resetQueryCount() { queryCount = 0; const countElement = document.getElementById('queryCount'); if (countElement) { countElement.textContent = queryCount; } } // 查询课程并获取结果 function searchCourses() { return new Promise((resolve, reject) => { try { const iframe = document.querySelector("iframe"); if (!iframe || !iframe.contentWindow) { throw new Error('找不到iframe'); } const iframeWin = iframe.contentWindow; if (typeof iframeWin.guolv !== 'function') { throw new Error('找不到查询函数'); } const original$ = iframeWin.$; const originalAjax = original$.ajax; original$.ajax = function(options) { if (options.url && options.url.includes('/student/courseSelect/freeCourse/courseList')) { const originalSuccess = options.success; options.success = function(data) { original$.ajax = originalAjax; resolve(data); if (originalSuccess) { originalSuccess.call(this, data); } }; const originalError = options.error; options.error = function(xhr, status, error) { original$.ajax = originalAjax; reject(new Error(`查询失败: ${error}`)); if (originalError) { originalError.call(this, xhr, status, error); } }; } return originalAjax.call(this, options); }; iframeWin.guolv(1); setTimeout(() => { original$.ajax = originalAjax; reject(new Error('查询超时')); }, 8000); } catch (error) { reject(error); } }); } // 选中课程 function selectCourse(course) { try { const iframe = document.querySelector("iframe"); const iframeWin = iframe.contentWindow; if (typeof iframeWin.dealHiddenData !== 'function') { throw new Error('找不到选课函数'); } iframeWin.dealHiddenData(course, true); console.log(`选中课程: ${course.kcm} - ${course.skjs} (余量:${course.bkskyl})`); return true; } catch (error) { console.error('选中课程失败:', error); return false; } } // 提交选课 function submitCourse() { return new Promise((resolve, reject) => { const yzmArea = $("#yzm_area"); if (yzmArea.length > 0 && yzmArea.css("display") !== "none" && !$("#submitCode").val()) { reject(new Error('请先输入验证码')); return; } const originalAjax = $.ajax; $.ajax = function(options) { if (options.url && options.url.includes('checkInputCodeAndSubmit')) { const originalSuccess = options.success; const originalError = options.error; options.success = function(data) { $.ajax = originalAjax; if (originalSuccess) originalSuccess.call(this, data); if (data.result === 'ok') { resolve('选课成功'); } else { reject(new Error(data.result)); } }; options.error = function(xhr) { $.ajax = originalAjax; if (originalError) originalError.call(this, xhr); reject(new Error(`提交失败: ${xhr.status}`)); }; } return originalAjax.call(this, options); }; // 直接调用,不做判断 window.tijiao(); }); } // 主抢课逻辑 async function performGrab() { try { updateButton('查询中...', `linear-gradient(135deg, ${THEME_COLORS.warning} 0%, #f57c00 100%)`); updateQueryCount(); const data = await searchCourses(); if (!data || !data.rwRxkZlList || data.rwRxkZlList.length === 0) { updateButton('未找到课程', `linear-gradient(135deg, ${THEME_COLORS.gray} 0%, #495057 100%)`); console.log('未找到课程'); return false; } const availableCourse = data.rwRxkZlList.find(course => course.bkskyl > 0); if (!availableCourse) { updateButton('暂无余量', `linear-gradient(135deg, ${THEME_COLORS.gray} 0%, #495057 100%)`); console.log('暂无余量'); return false; } // 发现有余量的课程,立即停止Worker if (worker) { worker.postMessage({ command: 'stop' }); } updateButton('发现目标课程', `linear-gradient(135deg, ${THEME_COLORS.success} 0%, #388e3c 100%)`); console.log(`发现有余量课程: ${availableCourse.kcm}`); if (!selectCourse(availableCourse)) { updateButton('选中失败', `linear-gradient(135deg, ${THEME_COLORS.error} 0%, #d32f2f 100%)`); console.error('选中课程失败'); stopAutoGrab(); return false; } await new Promise(resolve => setTimeout(resolve, 500)); updateButton('提交中...', `linear-gradient(135deg, ${THEME_COLORS.warning} 0%, #f57c00 100%)`); const result = await submitCourse(); updateButton('✅ 选课成功', `linear-gradient(135deg, ${THEME_COLORS.success} 0%, #388e3c 100%)`); console.log(`✅ 选课成功: ${availableCourse.kcm} - ${availableCourse.skjs}`); stopAutoGrab(); return true; } catch (error) { if (error.message.includes('验证码')) { updateButton('需要验证码', `linear-gradient(135deg, ${THEME_COLORS.warning} 0%, #f57c00 100%)`); console.log('需要输入验证码'); stopAutoGrab(); alert('请输入验证码后重新开始'); return false; } else { updateButton('出现错误', `linear-gradient(135deg, ${THEME_COLORS.error} 0%, #d32f2f 100%)`); console.error('抢课出错:', error.message); stopAutoGrab(); return false; } } } // 开始/停止抢课 function toggleAutoGrab() { if (isRunning) { stopAutoGrab(); } else { startAutoGrab(); } } // 开始自动抢课 function startAutoGrab() { isRunning = true; resetQueryCount(); startTimer(); console.log('🚀 开始自动抢课'); updateButton('停止抢课', `linear-gradient(135deg, ${THEME_COLORS.error} 0%, #d32f2f 100%)`); // 初始化Web Worker if (!worker) { worker = createWorker(); worker.addEventListener('message', async function(e) { if (e.data.type === 'tick' && isRunning) { const success = await performGrab(); if (success) { // 抢课成功,Worker已在performGrab中停止 console.log('抢课成功,已停止Worker'); } } }); } // 立即执行一次 performGrab(); // 启动Worker定时器 const interval = Math.floor(Math.random() * 100 + 400); worker.postMessage({ command: 'start', interval: interval }); } // 停止自动抢课 function stopAutoGrab() { isRunning = false; stopTimer(); updateButton('开始抢课', `linear-gradient(135deg, ${THEME_COLORS.primary} 0%, ${THEME_COLORS.primaryDark} 100%)`); // 停止Worker if (worker) { worker.postMessage({ command: 'stop' }); } console.log('已停止抢课'); } // 初始化 function init() { const checkReady = setInterval(() => { const iframe = document.querySelector("iframe"); if (iframe && iframe.contentWindow && document.querySelector('#myTab4')) { clearInterval(checkReady); setTimeout(() => { createButton(); console.log('抢课脚本已就绪'); }, 1000); } }, 1000); } // 启动 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } // 页面卸载时清理Worker window.addEventListener('beforeunload', () => { if (worker) { worker.postMessage({ command: 'stop' }); worker.terminate(); } }); })();