// ==UserScript== // @name 燕京理工英华学堂自动看网课 // @version 1.4 // @description 英华学堂自动看网课,自动识别验证码,界面美观,功能丰富。支持用户注册登录、签到、金币经验系统。 // @author Sheng // @email // @match *://mooc.yit.edu.cn/user/node* // @match *://mooc.yinghuaonline.com/user/node* // @match *://zxshixun.yit.edu.cn/user/node* // @match *://gyxy.yit.edu.cn/user/node* // @match *://mooc.yit.edu.cn/user/index* // @match *://mooc.yinghuaonline.com/user/index* // @match *://zxshixun.yit.edu.cn/user/index* // @match *://gyxy.yit.edu.cn/user/index* // @iconURL // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @license MIT // @connect 119.8.102.43 // @connect 119.8.102.43:5000 // @connect api-app.api5dao.eu.org // @require https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js // @require https://cdn.bootcdn.net/ajax/libs/font-awesome/6.4.0/js/all.min.js // ==/UserScript== // 视频元素 let videoElement = null; // 监视器 let checkCaptchaTimer = null; // 容器文本 let containerTextElement = null; // 验证码弹窗 let layuiLayerContent = null; // 课程表 let links = null; // 当前课程位置 let current = 0; // 计时 let timerCnt = 0; // 版本 let version = "1.4" // 日志记录 let logs = []; // 是否静音 let isMuted = GM_getValue('isMuted', true); // 悬浮窗可见性 let isVisible = GM_getValue('isVisible', true); // 是否启用自动播放 let autoPlayEnabled = GM_getValue('autoPlayEnabled', true); // 当前进度 let currentProgress = 0; // 总进度 let totalProgress = 0; // 主题颜色 let themeColor = GM_getValue('themeColor', 'red'); // API配置 const API = { BASE_URL: 'https://api-app.api5dao.eu.org/api', APP_ID: '10007', // 应用ID DEVICE_ID: generateDeviceId(), // 生成设备ID }; // 用户信息 let userInfo = { loggedIn: false, id: GM_getValue('userId', ''), username: GM_getValue('username', ''), userToken: GM_getValue('userToken', ''), nickname: GM_getValue('nickname', ''), avatar: GM_getValue('avatar', ''), money: GM_getValue('money', 0), exp: GM_getValue('exp', 0), lastSignTime: GM_getValue('lastSignTime', ''), isSigned: GM_getValue('isSigned', false), continuityDays: GM_getValue('continuityDays', 0), seriesDays: GM_getValue('seriesDays', 0), inviteCode: GM_getValue('inviteCode', ''), lastUpdateTime: GM_getValue('lastUpdateTime', 0) }; // 学习统计 let studyStats = { todayStudyTime: GM_getValue('todayStudyTime', 0), totalStudyTime: GM_getValue('totalStudyTime', 0), earnedCoins: GM_getValue('earnedCoins', 0), earnedExp: GM_getValue('earnedExp', 0), lastStudyDate: GM_getValue('lastStudyDate', ''), studyStartTime: 0 }; // 常量 const CONSTANTS = { COINS_PER_HOUR: 0, // 每小时获得金币数 COST_PER_HOUR: 5, // 每小时消耗金币数 DAILY_SIGN_COINS: 15, // 每日签到金币数 INVITE_COINS: 180, // 邀请好友金币数 STUDY_TIME_UNIT: 60 * 60, // 1小时(秒) STUDY_EXP_PER_HOUR: 10, // 每小时获得经验值 UPDATE_INTERVAL: 60 * 1000, // 用户信息更新间隔(毫秒) MAX_UNREAD_MESSAGES: 99, // 最大未读消息数显示 AUTO_RECORD_STUDY_HOURS: true // 是否自动累计听课时长(默认开启) }; // 生成设备ID function generateDeviceId() { const storedDeviceId = GM_getValue('deviceId', ''); if (storedDeviceId) { return storedDeviceId; } // 生成随机设备ID const randomId = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); GM_setValue('deviceId', randomId); return randomId; } // 检查当前日期 function checkCurrentDate() { const today = new Date().toLocaleDateString(); // 如果是新的一天,重置每日学习时间 if (today !== studyStats.lastStudyDate) { studyStats.todayStudyTime = 0; studyStats.lastStudyDate = today; userInfo.isSigned = false; saveStudyStats(); GM_setValue('isSigned', false); } } // 修改学习统计的初始化方法,绑定到学号 function loadStudyStats() { const studentId = GM_getValue('studentId', ''); if (studentId) { // 如果有学号,使用学号作为键 studyStats.todayStudyTime = GM_getValue(`${studentId}_todayStudyTime`, 0); studyStats.totalStudyTime = GM_getValue(`${studentId}_totalStudyTime`, 0); studyStats.earnedCoins = GM_getValue(`${studentId}_earnedCoins`, 0); studyStats.earnedExp = GM_getValue(`${studentId}_earnedExp`, 0); studyStats.lastStudyDate = GM_getValue(`${studentId}_lastStudyDate`, ''); // 同步总学习时间和累计听课时长 const localStudyHours = GM_getValue(`${studentId}_localStudyHours`, 0); // 将小时转换为秒 const totalStudyTimeInSeconds = localStudyHours * 3600; // 如果本地记录的听课时长大于总学习时间,则同步总学习时间 if (totalStudyTimeInSeconds > studyStats.totalStudyTime) { studyStats.totalStudyTime = totalStudyTimeInSeconds; GM_setValue(`${studentId}_totalStudyTime`, totalStudyTimeInSeconds); } } else { // 没有学号,使用默认值 studyStats.todayStudyTime = GM_getValue('todayStudyTime', 0); studyStats.totalStudyTime = GM_getValue('totalStudyTime', 0); studyStats.earnedCoins = GM_getValue('earnedCoins', 0); studyStats.earnedExp = GM_getValue('earnedExp', 0); studyStats.lastStudyDate = GM_getValue('lastStudyDate', ''); } studyStats.studyStartTime = 0; } // 修改保存学习统计的方法,绑定到学号 function saveStudyStats() { const studentId = GM_getValue('studentId', ''); if (studentId) { // 如果有学号,使用学号作为键 GM_setValue(`${studentId}_todayStudyTime`, studyStats.todayStudyTime); GM_setValue(`${studentId}_totalStudyTime`, studyStats.totalStudyTime); GM_setValue(`${studentId}_earnedCoins`, studyStats.earnedCoins); GM_setValue(`${studentId}_earnedExp`, studyStats.earnedExp); GM_setValue(`${studentId}_lastStudyDate`, studyStats.lastStudyDate); // 同步累计听课时长(小时) const totalStudyHours = Math.floor(studyStats.totalStudyTime / 3600); GM_setValue(`${studentId}_localStudyHours`, totalStudyHours); } else { // 没有学号,使用通用键 GM_setValue('todayStudyTime', studyStats.todayStudyTime); GM_setValue('totalStudyTime', studyStats.totalStudyTime); GM_setValue('earnedCoins', studyStats.earnedCoins); GM_setValue('earnedExp', studyStats.earnedExp); GM_setValue('lastStudyDate', studyStats.lastStudyDate); // 同步通用累计听课时长 const totalStudyHours = Math.floor(studyStats.totalStudyTime / 3600); GM_setValue('localStudyHours', totalStudyHours); } } // 保存用户信息 function saveUserInfo() { GM_setValue('userId', userInfo.id); GM_setValue('username', userInfo.username); GM_setValue('userToken', userInfo.userToken); GM_setValue('nickname', userInfo.nickname); GM_setValue('avatar', userInfo.avatar); GM_setValue('money', userInfo.money); GM_setValue('exp', userInfo.exp); GM_setValue('lastSignTime', userInfo.lastSignTime); GM_setValue('isSigned', userInfo.isSigned); GM_setValue('continuityDays', userInfo.continuityDays); GM_setValue('seriesDays', userInfo.seriesDays); GM_setValue('inviteCode', userInfo.inviteCode); GM_setValue('lastUpdateTime', userInfo.lastUpdateTime); } // 格式化日期时间 function formatDateTime(date) { const d = date ? new Date(date) : new Date(); return d.toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }).replace(/\//g, '-'); } // 检查登录状态 function checkLoginStatus() { userInfo.loggedIn = !!(userInfo.id && userInfo.username && userInfo.userToken); if (userInfo.loggedIn) { // 如果登录信息存在,检查是否需要更新用户信息 const now = Date.now(); if (now - userInfo.lastUpdateTime > CONSTANTS.UPDATE_INTERVAL) { updateUserInfo(); } } return userInfo.loggedIn; } // API请求基本函数 function apiRequest(endpoint, data, successCallback, errorCallback) { const formData = new FormData(); // 添加公共参数 formData.append('appid', API.APP_ID); formData.append('device', API.DEVICE_ID); // 添加请求数据 for (const key in data) { if (data.hasOwnProperty(key) && data[key] !== undefined) { formData.append(key, data[key]); } } GM_xmlhttpRequest({ method: 'POST', url: `${API.BASE_URL}/${endpoint}`, data: formData, responseType: 'json', timeout: 10000, onload: function(response) { if (response.status === 200) { const result = response.response; if (result.code === 200) { successCallback && successCallback(result); } else { showNotification('请求失败', result.msg || '未知错误'); errorCallback && errorCallback(result); } } else { showNotification('网络错误', `状态码: ${response.status}`); errorCallback && errorCallback({code: response.status, msg: '网络错误'}); } }, onerror: function(error) { showNotification('请求错误', error.message || '未知错误'); errorCallback && errorCallback({code: 500, msg: error.message || '请求错误'}); }, ontimeout: function() { showNotification('请求超时', '服务器响应超时'); errorCallback && errorCallback({code: 408, msg: '请求超时'}); } }); } // 用户登录 function userLogin(username, password, callback) { apiRequest( 'Login', { username: username, password: password }, function(result) { // 登录成功,保存用户信息 userInfo.loggedIn = true; userInfo.id = result.data.id; userInfo.username = result.data.username; userInfo.userToken = result.data.usertoken; userInfo.lastUpdateTime = Date.now(); saveUserInfo(); showNotification('登录成功', `欢迎回来,${userInfo.username}!`); // 获取完整用户信息 updateUserInfo(); callback && callback(true, result); }, function(error) { callback && callback(false, error); } ); } // 用户注册 function userRegister(username, password, email, phone, callback) { const now = Math.floor(Date.now() / 1000); apiRequest( 'Register', { username: username, password: password, useremail: email, phone: phone, regcodetime: now }, function(result) { showNotification('注册成功', '请登录您的账号'); callback && callback(true, result); }, function(error) { callback && callback(false, error); } ); } // 获取用户信息 function updateUserInfo(callback) { if (!userInfo.id && !userInfo.username) { callback && callback(false, {code: 401, msg: '未登录'}); return; } apiRequest( 'getUserInfo', { id: userInfo.id, username: userInfo.username }, function(result) { // 更新用户信息 userInfo.nickname = result.data.nickname; userInfo.avatar = result.data.usertx; userInfo.money = result.data.money; userInfo.exp = result.data.exp; userInfo.lastSignTime = result.data.signlasttime; userInfo.isSigned = result.data.sign; userInfo.continuityDays = result.data.continuity_days; userInfo.seriesDays = result.data.series_days; userInfo.inviteCode = result.data.invitecode; userInfo.lastUpdateTime = Date.now(); saveUserInfo(); updateUserPanel(); callback && callback(true, result); }, function(error) { callback && callback(false, error); } ); } // 用户签到 function userSignIn(callback) { if (!checkLoginStatus()) { showLoginModal(); callback && callback(false, {code: 401, msg: '请先登录'}); return; } apiRequest( 'UserSign', { id: userInfo.id, username: userInfo.username }, function(result) { userInfo.isSigned = true; userInfo.lastSignTime = formatDateTime(); userInfo.continuityDays++; userInfo.seriesDays++; userInfo.money += CONSTANTS.DAILY_SIGN_COINS; userInfo.lastUpdateTime = Date.now(); saveUserInfo(); updateUserPanel(); showNotification('签到成功', `恭喜获得${CONSTANTS.DAILY_SIGN_COINS}金币!`); addSystemMessage('签到成功', `您已成功签到,获得${CONSTANTS.DAILY_SIGN_COINS}金币,当前连续签到${userInfo.continuityDays}天`); callback && callback(true, result); }, function(error) { callback && callback(false, error); } ); } // 生成邀请码 function generateInviteCode(callback) { if (!checkLoginStatus()) { // 直接跳转到用户页面获取信息 const host = window.location.host; const userPageUrl = `https://${host}/user/index`; // 保存当前页面URL作为返回地址 const currentUrl = window.location.href; localStorage.setItem('returnUrl', currentUrl); // 显示通知 showNotification('请先登录', '跳转到用户页面获取信息...'); // 延迟跳转 setTimeout(() => { window.location.href = userPageUrl; }, 1000); callback && callback(false, {code: 401, msg: '请先登录'}); return; } apiRequest( 'Getinvitecode', { id: userInfo.id, username: userInfo.username, usertoken: userInfo.userToken }, function(result) { userInfo.inviteCode = result.data; saveUserInfo(); showNotification('生成成功', `您的邀请码是:${userInfo.inviteCode}`); callback && callback(true, result); }, function(error) { callback && callback(false, error); } ); } // 使用邀请码 function useInviteCode(inviteCode, callback) { if (!checkLoginStatus()) { // 直接跳转到用户页面获取信息 const host = window.location.host; const userPageUrl = `https://${host}/user/index`; // 保存当前页面URL作为返回地址 const currentUrl = window.location.href; localStorage.setItem('returnUrl', currentUrl); // 显示通知 showNotification('请先登录', '跳转到用户页面获取信息...'); // 延迟跳转 setTimeout(() => { window.location.href = userPageUrl; }, 1000); callback && callback(false, {code: 401, msg: '请先登录'}); return; } apiRequest( 'Invitation', { id: userInfo.id, username: userInfo.username, usertoken: userInfo.userToken, invitecode: inviteCode }, function(result) { userInfo.money += CONSTANTS.INVITE_COINS; saveUserInfo(); updateUserPanel(); showNotification('邀请成功', `使用邀请码成功,获得${CONSTANTS.INVITE_COINS}金币!`); callback && callback(true, result); }, function(error) { callback && callback(false, error); } ); } // 获取邀请排行榜 function getInviteRanking(callback) { apiRequest( 'GetinviterList', { limit: 10, sortOrder: 'desc' }, function(result) { callback && callback(true, result); }, function(error) { callback && callback(false, error); } ); } // 获取未读消息 function getUnreadMessages(callback) { if (!checkLoginStatus()) { callback && callback(false, {code: 401, msg: '请先登录'}); return; } apiRequest( 'getunreadMessage', { userid: userInfo.id, username: userInfo.username }, function(result) { callback && callback(true, result); }, function(error) { callback && callback(false, error); } ); } // 获取消息列表 function getMessageList(page, type, callback) { if (!checkLoginStatus()) { callback && callback(false, {code: 401, msg: '请先登录'}); return; } apiRequest( 'getmessagelist', { userid: userInfo.id, username: userInfo.username, type: type, limit: 10, page: page }, function(result) { callback && callback(true, result); }, function(error) { callback && callback(false, error); } ); } // 标记消息已读 function markMessagesAsRead(type, callback) { if (!checkLoginStatus()) { callback && callback(false, {code: 401, msg: '请先登录'}); return; } apiRequest( 'updatemsgstate', { userid: userInfo.id, username: userInfo.username, type: type }, function(result) { callback && callback(true, result); }, function(error) { callback && callback(false, error); } ); } // 添加系统消息(本地) function addSystemMessage(title, content) { // 将系统消息添加到本地存储 const messages = GM_getValue('localMessages', []); messages.unshift({ title: title, content: content, time: formatDateTime(), read: false }); // 限制本地消息数量 if (messages.length > 50) { messages.pop(); } GM_setValue('localMessages', messages); } // 获取本地消息 function getLocalMessages() { return GM_getValue('localMessages', []); } // 标记本地消息已读 function markLocalMessagesAsRead() { const messages = GM_getValue('localMessages', []); messages.forEach(message => { message.read = true; }); GM_setValue('localMessages', messages); } // 修改记录学习时间函数,同步累计听课时长 function recordStudyTime() { if (!videoElement || videoElement.paused) return; const now = Math.floor(Date.now() / 1000); if (studyStats.studyStartTime === 0) { studyStats.studyStartTime = now; return; } const elapsed = now - studyStats.studyStartTime; if (elapsed <= 0) return; // 更新学习时间 studyStats.todayStudyTime += elapsed; studyStats.totalStudyTime += elapsed; // 计算获得的金币和经验 const earnedCoins = Math.floor(elapsed / CONSTANTS.STUDY_TIME_UNIT * CONSTANTS.COINS_PER_HOUR); const earnedExp = Math.floor(elapsed / CONSTANTS.STUDY_TIME_UNIT * CONSTANTS.STUDY_EXP_PER_HOUR); if (earnedCoins > 0 && checkLoginStatus()) { // 增加金币和经验 userInfo.money += earnedCoins; userInfo.exp += earnedExp; saveUserInfo(); // 更新统计 studyStats.earnedCoins += earnedCoins; studyStats.earnedExp += earnedExp; // 调用听课API,每小时调用一次,但仅当开启了自动累计听课时长时 // 当总学习时间新增了一个小时整数部分时触发 const newTotalHours = Math.floor(studyStats.totalStudyTime / CONSTANTS.STUDY_TIME_UNIT); const oldTotalHours = Math.floor((studyStats.totalStudyTime - elapsed) / CONSTANTS.STUDY_TIME_UNIT); if (newTotalHours > oldTotalHours && CONSTANTS.AUTO_RECORD_STUDY_HOURS) { listenClass(); } else { // 即使没有触发listenClass,也要保存学习统计,以同步听课时长 saveStudyStats(); } // 显示通知 if (earnedCoins >= CONSTANTS.COINS_PER_HOUR) { showNotification('获得奖励', `学习奖励:${earnedCoins}金币,${earnedExp}经验值`); addSystemMessage('学习奖励', `您通过学习获得了${earnedCoins}金币和${earnedExp}经验值`); } } else { // 即使没有获得金币,也要保存学习统计,以同步听课时长 saveStudyStats(); } // 重置学习开始时间 studyStats.studyStartTime = now; updateUserPanel(); } // 修改获取听课时长函数,使用学号关联的本地存储 function getStudyHours(callback) { try { const studentId = GM_getValue('studentId', ''); let localStudyHours; if (studentId) { // 从学号关联的本地存储获取累计听课时长 localStudyHours = GM_getValue(`${studentId}_localStudyHours`, 0); } else { // 如果没有学号,则使用通用的存储 localStudyHours = GM_getValue('localStudyHours', 0); } // 同步本地记录的总学习时间(秒)与听课时长(小时) if (studentId && studyStats.totalStudyTime > 0) { const totalStudyHours = Math.floor(studyStats.totalStudyTime / 3600); if (totalStudyHours > localStudyHours) { localStudyHours = totalStudyHours; GM_setValue(`${studentId}_localStudyHours`, localStudyHours); } } // 模拟API返回格式 const result = { code: 0, msg: '获取成功', data: { study: localStudyHours } }; // 调用回调函数,返回成功状态和结果 callback && callback(true, result); } catch (error) { console.error('获取听课时长失败:', error); callback && callback(false, {code: 500, msg: '读取本地存储失败'}); } } // 修改听课API函数,更新与学号关联的累计时长 function listenClass() { // 如果关闭了自动累计听课时长,则跳过此功能 if (!CONSTANTS.AUTO_RECORD_STUDY_HOURS) { addText("已关闭听课时长累计功能,继续观看课程..."); return; } if (!checkLoginStatus()) { return; } // 检查用户金币是否足够 if (userInfo.money < CONSTANTS.COST_PER_HOUR) { showNotification('金币不足', '您的金币不足,请签到或邀请好友获取更多金币'); // 添加带有按钮的提示信息 const lowCoinsMsg = `
您的金币不足${CONSTANTS.COST_PER_HOUR}个,无法继续累计听课时长
${!userInfo.isSigned ? '' : '今日已签到'}
`; addText(lowCoinsMsg); // 添加快捷按钮事件 $('#quickSignBtn').on('click', function() { userSignIn(); }); $('#quickInviteBtn').on('click', function() { showSettingsModal(); // 切换到邀请标签 setTimeout(() => { $('.tab-btn[data-tab="invite"]').click(); }, 100); }); // 添加关闭时长累计的按钮事件 $('#disableRecordBtn').on('click', function() { CONSTANTS.AUTO_RECORD_STUDY_HOURS = false; GM_setValue('AUTO_RECORD_STUDY_HOURS', false); showNotification('已关闭时长累计', '您可以继续观看课程,但不会累计听课时长'); addText("已关闭听课时长累计功能,您可以继续观看课程"); $(this).prop('disabled', true).text('已关闭'); }); return; } addText(`正在提交听课时长并扣除${CONSTANTS.COST_PER_HOUR}金币...`); // 准备API请求参数 const studentId = GM_getValue('studentId', ''); // 实际调用API apiRequest( 'listenclass', { userid: userInfo.id, username: userInfo.username, usertoken: userInfo.userToken, studentid: studentId, coin: CONSTANTS.COST_PER_HOUR }, function(result) { // API请求成功 // 扣除本地金币记录 userInfo.money -= CONSTANTS.COST_PER_HOUR; saveUserInfo(); updateUserPanel(); try { // 从本地存储获取当前累计听课时长 let currentStudyHours; if (studentId) { currentStudyHours = GM_getValue(`${studentId}_localStudyHours`, 0); } else { currentStudyHours = GM_getValue('localStudyHours', 0); } // 增加1小时听课时长 currentStudyHours += 1; // 保存更新后的累计听课时长到本地存储 if (studentId) { GM_setValue(`${studentId}_localStudyHours`, currentStudyHours); } else { GM_setValue('localStudyHours', currentStudyHours); } // 同步更新总学习时间(秒) studyStats.totalStudyTime = currentStudyHours * 3600; saveStudyStats(); // 成功消息 addText(`成功调用API累计听课时长并消耗${CONSTANTS.COST_PER_HOUR}金币,获得1小时听课时长,当前累计听课时长:${currentStudyHours}小时,剩余${userInfo.money}金币`); showNotification('累计听课成功', `获得1小时听课时长,当前累计时长:${currentStudyHours}小时`); // 添加系统消息 addSystemMessage('听课时长累计', `已成功累计1小时听课时长,消耗${CONSTANTS.COST_PER_HOUR}金币`); } catch (error) { console.error('更新本地听课时长记录失败:', error); addText(`API调用成功但更新本地听课时长记录失败: ${error.message}`); } }, function(error) { // API请求失败 console.error('听课API请求失败:', error); addText(`调用听课API失败: ${error.msg || '未知错误'}`); showNotification('听课失败', '无法连接到服务器,请检查网络连接'); } ); } // 开始记录学习时间 function startRecordingStudyTime() { if (studyStats.studyStartTime === 0) { studyStats.studyStartTime = Math.floor(Date.now() / 1000); // 每分钟记录一次学习时间 setInterval(recordStudyTime, 60 * 1000); } } // 获取当前课程 function getCurrent() { links = $('a[target="_self"]'); links.each((index, item) => { if ($(item).hasClass("on")) { current = index; return false; } }); totalProgress = links.length; currentProgress = current + 1; updateProgressBar(); } // 下一个视频 async function playNext() { clearInterval(checkCaptchaTimer); if (current === links.length - 1) { addText("最后一个已看完!"); showNotification("课程完成", "所有视频已观看完毕!"); } else { addText("准备播放下一个视频..."); await pause(3); links[current + 1].click(); } } // 输入验证码 async function inputCaptcha() { if (layuiLayerContent.length && layuiLayerContent.is(':visible')) { addText("验证码弹窗出现,准备填写验证码..."); await pause(2, 5) // 获取图片 let imgs = layuiLayerContent.find("img") let img = imgs[0].style.opacity === '0' ? imgs[1] : imgs[0] // 图片转base64 let canvas = document.createElement("canvas"); let ctx = canvas.getContext("2d"); canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0, img.width, img.height); let code = canvas.toDataURL("image/png").split("base64,")[1]; // 调用接口,识别验证码 let ans = await getCode(code) // 获取input,填入验证码 let inputs = layuiLayerContent.find("input") let input = inputs[0].style.display === 'none' ? inputs[1] : inputs[0] $(input).mousedown() input.value = ans // 点击开始播放按钮 await pause(2, 5) // 尝试点击开始播放按钮 try { const playButton = $('.layui-layer-btn0'); if (playButton.length) { // 方法1:直接点击DOM元素 if (playButton[0] && typeof playButton[0].click === 'function') { playButton[0].click(); } // 方法2:使用jQuery点击 playButton.trigger('click'); addText("已尝试点击开始播放按钮"); // 等待验证码弹窗消失 let waitCount = 0; while (layuiLayerContent.is(':visible') && waitCount < 10) { await pause(1); waitCount++; } // 重新开始视频检测 checkCaptchaTimer = setInterval(playVideo, 1000); // 如果验证码弹窗依然可见,刷新页面 if (layuiLayerContent.is(':visible')) { addText("验证码弹窗未关闭,刷新页面..."); await pause(2); location.reload(); return; } // 如果视频存在,尝试直接播放 if (videoElement) { try { videoElement.play(); } catch (e) { addText("视频播放失败:" + e.message); } } } else { addText("未找到开始播放按钮,尝试刷新页面..."); await pause(2); location.reload(); // 刷新当前页面 } } catch (error) { addText("点击按钮时出错:" + error.message); await pause(2); location.reload(); } } } // 使用sw1128的接口,油猴链接:https://greasyfork.org/zh-CN/scripts/459260 function getCode(code) { return new Promise((resolve, reject) => { const datas = { "ImageBase64": String(code), } GM_xmlhttpRequest({ method: "POST", url: "http://119.8.102.43:5000/get_captcha", data: JSON.stringify(datas), headers: { "Content-Type": "application/json", }, responseType: "json", timeout: 10000, ontimeout: async function (e) { addText("验证码获取超时,刷新页面..."); await pause(3) location.reload(); // 刷新当前页面 }, onload: function (response) { if (response.status == 200) { let result = response.response["message"]; addText("识别结果:" + result); return resolve(result); } else { let result = JSON.parse(response.response)["message"]; addText(result); } }, onerror: function (error) { addText(`${error.statusText} ${error.status} - 出错了`) }, }); }); } // 格式化时间 function formatTime(seconds) { const mins = Math.floor(seconds / 60); const secs = Math.floor(seconds % 60); return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; } // 播放视频,同时检测验证码 async function playVideo() { timerCnt++; // 更新进度信息 updateProgressBar(); if (timerCnt % 5 === 0) { addText("等待加载,已加载:" + timerCnt + "秒"); } if (timerCnt > 20) { addText("加载超时,刷新页面"); showNotification("加载超时", "正在刷新页面,请稍候..."); location.reload(); return; } if (!videoElement) { if (links && links[current] && links[current].title && links[current].title === "考试") { addText("课程已看完,自动停止!"); showNotification("课程完成", "所有视频已观看完毕!"); clearInterval(checkCaptchaTimer); } else { getVideoElement(); } return; } // 验证码弹窗 layuiLayerContent = $('.layui-layer-content'); if (layuiLayerContent.length > 0 && layuiLayerContent.is(':visible')) { clearInterval(checkCaptchaTimer); showNotification("验证码", "检测到验证码,正在自动识别..."); await inputCaptcha(); return; } // 检测视频是否加载成功且暂停 if (videoElement.paused) { try { await videoElement.play(); if (videoElement.readyState === 4) { const message = containerTextElement.text().includes("视频加载完成") ? "请将浏览器置于前台运行。(若学时会增加可忽略)" : "视频加载完成,准备播放"; addText(message); } } catch (e) { addText("视频播放失败:" + e.message); // 如果播放失败,尝试重新获取视频元素 getVideoElement(); } } else { timerCnt = 0; } } // 暂停函数 function pause(start, end = undefined) { let delay = start; if (end) { delay = Math.floor(Math.random() * (end - start)) + start; addText(`等待 ${delay} 秒后继续...`); } return new Promise(resolve => { setTimeout(() => { resolve(); }, delay * 1000); // 将秒转换为毫秒 }); } // 添加交互显示 const addContainer = () => { const container = $('
'); // 构建标题栏 const header = $(`
燕京理工自动看网课 v${version}
`); // 构建主体内容 const content = $('
'); // 用户信息面板(默认隐藏,登录后显示) const userPanel = $(` `); // 登录注册按钮(未登录时显示) const authButtons = $(`
`); // 构建进度条 const progressSection = $(`
加载中...
`); // 构建控制按钮 const controlsSection = $(`
`); // 构建日志区域 const logSection = $(`
运行日志
`); // 构建提示信息 const tipSection = $(`
如果开启了系统代理,请先关闭
请允许跨域资源请求以识别验证码
如需累计学时,请保持浏览器在前台运行
登录账号可获取金币奖励、签到福利
`); // 构建底部信息 const footerSection = $(` `); // 组装所有部分 - 移除themeSection content.append(userPanel, authButtons, progressSection, controlsSection, logSection, tipSection, footerSection); container.append(header, content); // 将容器添加到页面 $("body").append(container); // 设置容器的可拖动性 header.on("mousedown", function(event) { if ($(event.target).closest('.panel-controls').length === 0) { const initialX = event.clientX; const initialY = event.clientY; const initialLeft = container.offset().left; const initialTop = container.offset().top; function onMouseMove(event) { container.css({ left: initialLeft + (event.clientX - initialX) + 'px', top: initialTop + (event.clientY - initialY) + 'px' }); } function onMouseUp() { $(document).off('mousemove', onMouseMove); $(document).off('mouseup', onMouseUp); } $(document).on('mousemove', onMouseMove); $(document).on('mouseup', onMouseUp); } }); // 设置容器的可缩放性 const resizer = $('
'); container.append(resizer); resizer.on("mousedown", function(event) { const initialX = event.clientX; const initialWidth = container.width(); function onMouseMove(event) { const newWidth = initialWidth + (event.clientX - initialX); if (newWidth >= 300) { container.css('width', newWidth + 'px'); } } function onMouseUp() { $(document).off('mousemove', onMouseMove); $(document).off('mouseup', onMouseUp); } $(document).on('mousemove', onMouseMove); $(document).on('mouseup', onMouseUp); }); // 储存日志容器元素 containerTextElement = $('#logContainer'); // 设置事件监听器 $('#toggleVisibilityButton').on('click', togglePanelVisibility); $('#closeButton').on('click', minimizePanel); $('#autoPlayButton').on('click', toggleAutoPlay); $('#muteButton').on('click', toggleMute); $('#skipButton').on('click', playNext); $('#restartButton').on('click', restartVideo); $('#clearLogButton').on('click', clearLogs); $('#settingsButton').on('click', showSettingsModal); // 用户相关按钮事件 $('#loginButton').on('click', function() { // 直接跳转到用户页面获取信息 const host = window.location.host; const userPageUrl = `https://${host}/user/index`; // 保存当前页面URL作为返回地址 const currentUrl = window.location.href; localStorage.setItem('returnUrl', currentUrl); // 显示通知 showNotification('正在授权', '跳转到用户页面获取信息...'); // 延迟跳转 setTimeout(() => { window.location.href = userPageUrl; }, 1000); }); $('#registerButton').on('click', function() { // 直接跳转到用户页面获取信息 const host = window.location.host; const userPageUrl = `https://${host}/user/index`; // 保存当前页面URL作为返回地址 const currentUrl = window.location.href; localStorage.setItem('returnUrl', currentUrl); // 显示通知 showNotification('正在授权', '跳转到用户页面获取信息...'); // 延迟跳转 setTimeout(() => { window.location.href = userPageUrl; }, 1000); }); $('#signInButton').on('click', userSignIn); $('#messageButton').on('click', showMessageCenter); // 初始化UI状态 updateMuteButton(); changeTheme(themeColor); if (!isVisible) { togglePanelVisibility(); } // 检查登录状态并更新UI updateUserPanel(); // 调用更新用户面板,根据登录状态显示或隐藏按钮 } // 最小化面板 function minimizePanel() { $('.yjlt-auto-player').addClass('minimized'); showMinimizedIndicator(); } // 显示最小化指示器 function showMinimizedIndicator() { const indicator = $(`
`); $('body').append(indicator); indicator.on('click', function() { $('.yjlt-auto-player').removeClass('minimized'); $(this).remove(); }); } // 重启当前视频 function restartVideo() { if (videoElement) { videoElement.currentTime = 0; videoElement.play(); addText("已重新开始当前视频"); } } // 清空日志 function clearLogs() { containerTextElement.empty(); logs = []; addText("日志已清空"); } // 添加交互文本 const addText = text => { const timestamp = new Date().toLocaleTimeString(); const logEntry = `
[${timestamp}] ${text}
`; containerTextElement.append(logEntry); containerTextElement.scrollTop(containerTextElement[0].scrollHeight); // 保存日志 logs.push({ time: timestamp, text: text }); // 限制日志数量 if (logs.length > 100) { logs.shift(); } } // 添加样式 const addStyle = () => { const style = $(""); style.prop('type', 'text/css'); style.html(` :root { --primary-color: #1e88e5; --secondary-color: #64b5f6; --background-gradient: linear-gradient(135deg, #42a5f5 0%, #1976d2 100%); --text-color: #333; --light-text: #fff; --border-radius: 8px; --shadow: 0 4px 20px rgba(0, 0, 0, 0.15); --panel-bg: #fff; --section-bg: #f5f7fa; --success-color: #4caf50; --warning-color: #ff9800; --danger-color: #f44336; } .yjlt-auto-player { position: fixed; top: 50px; right: 20px; width: 380px; font-family: "PingFang SC", "Microsoft YaHei", sans-serif; z-index: 9999999; background-color: var(--panel-bg); box-shadow: var(--shadow); border-radius: var(--border-radius); transition: all 0.3s ease; overflow: hidden; } .yjlt-auto-player.minimized { transform: translateX(400px); } .panel-header { background: var(--background-gradient); color: var(--light-text); padding: 12px 15px; display: flex; justify-content: space-between; align-items: center; cursor: move; user-select: none; } .panel-title { font-weight: 600; font-size: 16px; display: flex; align-items: center; gap: 8px; } .version-tag { background: rgba(255, 255, 255, 0.2); padding: 2px 6px; border-radius: 12px; font-size: 12px; font-weight: normal; } .panel-controls { display: flex; gap: 5px; } .header-btn { background: none; border: none; color: var(--light-text); cursor: pointer; width: 24px; height: 24px; border-radius: 4px; display: flex; align-items: center; justify-content: center; transition: background 0.2s; } .header-btn:hover { background: rgba(255, 255, 255, 0.2); } .panel-content { padding: 15px; } /* 用户面板 */ .user-panel { margin-bottom: 15px; border-radius: var(--border-radius); overflow: hidden; background-color: var(--section-bg); } .user-info { padding: 12px; display: flex; align-items: center; } .user-avatar { width: 50px; height: 50px; border-radius: 50%; overflow: hidden; } .user-avatar img { width: 100%; height: 100%; object-fit: cover; } .user-details { margin-left: 12px; flex: 1; } .user-name { font-weight: 600; font-size: 16px; margin-bottom: 4px; } .user-stats { display: flex; gap: 12px; font-size: 13px; color: #555; } .user-actions { display: flex; gap: 8px; } .user-btn { background-color: var(--primary-color); color: white; border: none; border-radius: 4px; padding: 5px 10px; font-size: 12px; cursor: pointer; display: flex; align-items: center; gap: 4px; transition: all 0.2s; } .user-btn:hover { background-color: var(--secondary-color); } .user-btn:disabled { background-color: #ccc; cursor: not-allowed; } .badge { position: absolute; top: -5px; right: -5px; background-color: var(--danger-color); color: white; border-radius: 10px; padding: 0px 5px; font-size: 10px; min-width: 15px; min-height: 15px; display: flex; align-items: center; justify-content: center; } /* 登录注册按钮 */ .auth-buttons { display: flex; gap: 10px; margin-bottom: 15px; } .auth-btn { flex: 1; background-color: var(--section-bg); color: var(--text-color); border: none; border-radius: var(--border-radius); padding: 10px; font-size: 14px; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 8px; transition: all 0.2s; } .auth-btn:hover { background-color: var(--secondary-color); color: white; } /* 进度条 */ .progress-section { margin-bottom: 15px; } .progress-container { height: 8px; background-color: #e0e0e0; border-radius: 4px; overflow: hidden; margin-bottom: 8px; } .progress-bar { height: 100%; background-color: var(--primary-color); transition: width 0.3s ease; width: 0%; } .progress-text { font-size: 14px; color: var(--text-color); text-align: center; } /* 视频进度 */ .video-progress-info { margin-bottom: 15px; background-color: var(--section-bg); border-radius: var(--border-radius); padding: 12px; } .video-progress-container { height: 8px; background-color: #e0e0e0; border-radius: 4px; overflow: hidden; margin-bottom: 8px; } .video-progress-bar { height: 100%; background-color: var(--primary-color); transition: width 0.3s ease; width: 0%; } .video-time { font-size: 13px; color: var(--text-color); text-align: center; } /* 控制按钮 */ .controls-section { display: flex; gap: 10px; margin-bottom: 15px; justify-content: center; } .control-btn { border: none; background-color: var(--section-bg); color: var(--text-color); padding: 8px 12px; border-radius: 4px; cursor: pointer; font-weight: 500; transition: all 0.2s; min-width: 40px; display: flex; align-items: center; justify-content: center; } .control-btn:hover { background-color: var(--secondary-color); color: var(--light-text); } .btn-success { background-color: var(--success-color); color: var(--light-text); } .btn-danger { background-color: var(--danger-color); color: var(--light-text); } /* 日志区域 */ .log-section { background-color: var(--section-bg); border-radius: var(--border-radius); padding: 12px; margin-bottom: 15px; } .log-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .log-title { font-size: 14px; font-weight: 500; color: var(--text-color); display: flex; align-items: center; gap: 5px; } .log-btn { background: none; border: none; color: var(--text-color); cursor: pointer; padding: 4px 8px; border-radius: 4px; font-size: 12px; transition: all 0.2s; } .log-btn:hover { background-color: rgba(0, 0, 0, 0.1); } .log-container { max-height: 150px; overflow-y: auto; padding: 10px; background-color: #fff; border-radius: 4px; border: 1px solid #e0e0e0; font-size: 13px; line-height: 1.5; } .log-entry { margin-bottom: 6px; border-bottom: 1px dashed #eee; padding-bottom: 6px; } .log-time { color: var(--primary-color); font-weight: 500; margin-right: 6px; } /* 提示区域 */ .tip-section { background-color: var(--section-bg); border-radius: var(--border-radius); padding: 12px; margin-bottom: 15px; } .tip-item { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-size: 13px; color: var(--text-color); } .tip-item i { color: var(--primary-color); } /* 底部信息 */ .footer-section { font-size: 12px; color: #888; text-align: center; margin-top: 10px; display: flex; justify-content: space-between; } /* 缩放手柄 */ .resizer { position: absolute; bottom: 0; right: 0; width: 15px; height: 15px; cursor: nwse-resize; background: transparent; } .resizer::after { content: ''; position: absolute; right: 3px; bottom: 3px; width: 5px; height: 5px; border-right: 2px solid var(--primary-color); border-bottom: 2px solid var(--primary-color); } /* 最小化指示器 */ .minimized-indicator { position: fixed; right: 20px; top: 50px; width: 40px; height: 40px; border-radius: 50%; background: var(--background-gradient); display: flex; align-items: center; justify-content: center; color: #fff; cursor: pointer; box-shadow: var(--shadow); z-index: 9999999; animation: pulse 2s infinite; } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.1); } 100% { transform: scale(1); } } /* 通知 */ .custom-notification { position: fixed; top: 20px; right: 20px; max-width: 300px; background-color: var(--panel-bg); border-left: 4px solid var(--primary-color); border-radius: 4px; padding: 15px; box-shadow: var(--shadow); z-index: 9999999; transform: translateX(350px); opacity: 0; transition: all 0.3s ease; } .custom-notification.show { transform: translateX(0); opacity: 1; } .notification-title { font-weight: 600; margin-bottom: 5px; color: var(--primary-color); } .notification-message { font-size: 14px; color: var(--text-color); } /* 模态框 */ .yjlt-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); z-index: 10000000; display: flex; align-items: center; justify-content: center; opacity: 0; visibility: hidden; transition: all 0.3s ease; } .yjlt-modal.show { opacity: 1; visibility: visible; } .modal-content { width: 90%; max-width: 500px; max-height: 80vh; background-color: var(--panel-bg); border-radius: var(--border-radius); box-shadow: var(--shadow); overflow: hidden; transform: scale(0.9); transition: transform 0.3s ease; } .yjlt-modal.show .modal-content { transform: scale(1); } .modal-header { padding: 15px; background: var(--background-gradient); color: var(--light-text); display: flex; justify-content: space-between; align-items: center; } .modal-header h3 { margin: 0; font-size: 18px; font-weight: 600; } .modal-close-btn { background: none; border: none; color: var(--light-text); font-size: 24px; cursor: pointer; line-height: 1; } .modal-body { padding: 20px; max-height: calc(80vh - 120px); overflow-y: auto; } .modal-footer { padding: 15px; display: flex; justify-content: flex-end; gap: 10px; border-top: 1px solid #eee; } .modal-btn { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; } .btn-primary { background-color: var(--primary-color); color: white; } .btn-text { background: none; color: var(--primary-color); } /* 表单 */ .form-group { margin-bottom: 15px; } .form-group label { display: block; margin-bottom: 5px; font-weight: 500; } .form-group input { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; } .form-error { color: var(--danger-color); font-size: 14px; margin-top: 10px; } /* 开关 */ .switch { position: relative; display: inline-block; width: 40px; height: 20px; } .switch input { opacity: 0; width: 0; height: 0; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: .4s; } .slider:before { position: absolute; content: ""; height: 16px; width: 16px; left: 2px; bottom: 2px; background-color: white; transition: .4s; } input:checked + .slider { background-color: var(--primary-color); } input:checked + .slider:before { transform: translateX(20px); } .slider.round { border-radius: 20px; } .slider.round:before { border-radius: 50%; } /* 设置 */ .tabs { display: flex; flex-direction: column; } .tab-header { display: flex; overflow-x: auto; border-bottom: 1px solid #eee; margin-bottom: 15px; } .tab-btn { padding: 10px 15px; border: none; background: none; cursor: pointer; font-size: 14px; font-weight: 500; color: #666; border-bottom: 2px solid transparent; transition: all 0.2s; } .tab-btn.active { color: var(--primary-color); border-bottom-color: var(--primary-color); } .tab-pane { display: none; } .tab-pane.active { display: block; } .setting-item { display: flex; justify-content: space-between; align-items: center; padding: 10px 0; border-bottom: 1px solid #eee; } .setting-item:last-child { border-bottom: none; } /* 主题选择按钮样式 */ .theme-options { display: flex; gap: 10px; } .theme-btn { width: 24px; height: 24px; border-radius: 50%; border: 2px solid transparent; cursor: pointer; transition: all 0.2s; } .theme-btn[data-theme="blue"] { background: linear-gradient(135deg, #42a5f5 0%, #1976d2 100%); } .theme-btn[data-theme="green"] { background: linear-gradient(135deg, #66bb6a 0%, #2e7d32 100%); } .theme-btn[data-theme="purple"] { background: linear-gradient(135deg, #ab47bc 0%, #6a1b9a 100%); } .theme-btn[data-theme="orange"] { background: linear-gradient(135deg, #ffa726 0%, #ef6c00 100%); } .theme-btn[data-theme="red"] { background: linear-gradient(135deg, #ef5350 0%, #c62828 100%); } .theme-btn.active { border-color: #333; transform: scale(1.1); } .stats-info { margin-top: 10px; font-size: 14px; color: #666; } .stats-info p { margin: 5px 0; } .account-info { text-align: center; } .user-profile { margin-bottom: 20px; } .profile-avatar { width: 80px; height: 80px; border-radius: 50%; margin-bottom: 10px; } .account-details { text-align: left; background-color: var(--section-bg); padding: 15px; border-radius: var(--border-radius); margin-bottom: 20px; } .account-details p { margin: 8px 0; display: flex; justify-content: space-between; } .setting-btn { padding: 8px 16px; border: none; background-color: var(--primary-color); color: white; border-radius: 4px; cursor: pointer; font-size: 14px; transition: all 0.2s; } .setting-btn:hover { background-color: var(--secondary-color); } .not-logged { text-align: center; padding: 20px; } .auth-actions { margin-top: 20px; display: flex; justify-content: center; gap: 15px; } /* 邀请 */ .invite-section { margin-bottom: 30px; } .invite-section h3 { margin-top: 0; } .invite-code { background-color: var(--section-bg); padding: 15px; border-radius: var(--border-radius); margin: 15px 0; display: flex; align-items: center; justify-content: space-between; } .generate-invite { text-align: center; margin: 15px 0; } .use-invite { margin-top: 20px; } .use-invite .form-group { display: flex; gap: 10px; } .use-invite input { flex: 1; } .invite-ranking h3 { margin-top: 0; } .ranking-list { display: flex; flex-direction: column; gap: 10px; } .ranking-item { display: flex; align-items: center; padding: 10px; background-color: var(--section-bg); border-radius: var(--border-radius); } .rank-num { width: 30px; height: 30px; border-radius: 50%; background-color: #ddd; display: flex; align-items: center; justify-content: center; font-weight: bold; margin-right: 10px; } .rank-1 .rank-num { background-color: gold; color: #333; } .rank-2 .rank-num { background-color: silver; color: #333; } .rank-3 .rank-num { background-color: #cd7f32; color: white; } .rank-avatar { width: 40px; height: 40px; border-radius: 50%; overflow: hidden; margin-right: 10px; } .rank-avatar img { width: 100%; height: 100%; object-fit: cover; } .rank-info { flex: 1; } .rank-name { font-weight: 500; } .rank-count { font-size: 12px; color: #666; } .loading-text, .empty-text { text-align: center; padding: 20px; color: #666; } /* 消息中心 */ .message-center { display: flex; flex-direction: column; height: 100%; } .message-tabs { display: flex; overflow-x: auto; border-bottom: 1px solid #eee; margin-bottom: 15px; } .message-tab { padding: 10px 15px; border: none; background: none; cursor: pointer; font-size: 14px; white-space: nowrap; color: #666; border-bottom: 2px solid transparent; transition: all 0.2s; } .message-tab.active { color: var(--primary-color); border-bottom-color: var(--primary-color); } .message-list { flex: 1; overflow-y: auto; margin-bottom: 15px; } .message-item { padding: 15px; border-bottom: 1px solid #eee; background-color: #fff; } .message-item.unread { background-color: rgba(30, 136, 229, 0.05); border-left: 3px solid var(--primary-color); } .message-header { display: flex; justify-content: space-between; margin-bottom: 10px; } .message-title { font-weight: 500; display: flex; align-items: center; gap: 8px; } .message-type { padding: 2px 6px; background-color: var(--section-bg); border-radius: 4px; font-size: 12px; font-weight: normal; } .message-time { font-size: 12px; color: #999; } .message-content { font-size: 14px; line-height: 1.5; color: #333; } .message-pagination { display: flex; justify-content: space-between; align-items: center; padding: 10px 0; border-top: 1px solid #eee; } .pagination-btn { padding: 5px 10px; border: none; background-color: var(--section-bg); color: var(--text-color); border-radius: 4px; cursor: pointer; font-size: 14px; transition: all 0.2s; } .pagination-btn:disabled { background-color: #eee; color: #999; cursor: not-allowed; } /* 关于 */ .about-section { text-align: center; } .about-section h3 { margin-top: 0; } .feature-list { text-align: left; margin-top: 20px; } .feature-list ul { padding-left: 20px; } .feature-list li { margin-bottom: 5px; } /* 警告消息样式 */ .warn-message { background-color: #fff8e1; border-left: 3px solid #ffc107; padding: 10px; margin: 5px 0; border-radius: 4px; } .warn-actions { display: flex; gap: 10px; margin-top: 8px; } .warn-btn { background-color: var(--primary-color); color: white; border: none; border-radius: 4px; padding: 5px 10px; font-size: 12px; cursor: pointer; transition: all 0.2s; } .warn-btn:hover { background-color: var(--secondary-color); } /* 信息提示框 */ .info-box { background-color: #e3f2fd; border-left: 3px solid var(--primary-color); padding: 10px; margin: 5px 0; border-radius: 4px; font-size: 14px; } .info-box p { margin: 5px 0; } .info-box .note { font-size: 12px; color: #666; font-style: italic; } /* 按钮样式 */ .btn-outline { background-color: transparent !important; border: 1px solid var(--primary-color) !important; color: var(--primary-color) !important; } .btn-outline:hover { background-color: var(--primary-color) !important; color: white !important; } .user-panel .remaining-time { margin-top: 2px; font-size: 12px; color: #555; } .user-panel .remaining-time.warning { color: #f44336; } .user-panel .remaining-time i { margin-right: 4px; } `); $('body').append(style); } // 切换视频静音状态 function toggleMute() { if (videoElement) { isMuted = !isMuted; videoElement.muted = isMuted; GM_setValue('isMuted', isMuted); updateMuteButton(); } } // 更新静音按钮状态 function updateMuteButton() { const muteIcon = isMuted ? 'fa-volume-mute' : 'fa-volume-up'; $('#muteButton i').attr('class', 'fas ' + muteIcon); } // 切换自动播放 function toggleAutoPlay(forceEnable) { // 如果提供了forceEnable参数,则强制设置自动播放状态 if (forceEnable !== undefined) { autoPlayEnabled = forceEnable; } else { // 否则切换状态 autoPlayEnabled = !autoPlayEnabled; } // 保存状态到GM存储 GM_setValue('autoPlayEnabled', autoPlayEnabled); if (autoPlayEnabled) { checkCaptchaTimer = setInterval(playVideo, 1000); $('#autoPlayButton').removeClass('btn-danger').addClass('btn-success'); $('#autoPlayButton i').removeClass('fa-pause').addClass('fa-play'); addText("自动播放已启用"); // 如果视频存在且暂停,则开始播放 if (videoElement && videoElement.paused) { videoElement.play(); } } else { clearInterval(checkCaptchaTimer); $('#autoPlayButton').removeClass('btn-success').addClass('btn-danger'); $('#autoPlayButton i').removeClass('fa-play').addClass('fa-pause'); addText("自动播放已暂停"); // 如果视频存在且正在播放,则暂停 if (videoElement && !videoElement.paused) { videoElement.pause(); } } } // 更新进度条 function updateProgressBar() { const percentage = Math.floor((currentProgress / totalProgress) * 100); $('#progressBar').css('width', percentage + '%'); $('#progressText').text(`进度: ${currentProgress}/${totalProgress} (${percentage}%)`); } // 显示通知 function showNotification(title, message) { const notification = $('
'); notification.html(`
${title}
${message}
`); $('body').append(notification); setTimeout(() => { notification.addClass('show'); setTimeout(() => { notification.removeClass('show'); setTimeout(() => notification.remove(), 500); }, 3000); }, 100); } // 切换主题颜色 function changeTheme(color) { themeColor = color; GM_setValue('themeColor', color); const cssVars = { 'blue': { 'primary': '#1e88e5', 'secondary': '#64b5f6', 'background': 'linear-gradient(135deg, #42a5f5 0%, #1976d2 100%)' }, 'green': { 'primary': '#43a047', 'secondary': '#81c784', 'background': 'linear-gradient(135deg, #66bb6a 0%, #2e7d32 100%)' }, 'purple': { 'primary': '#8e24aa', 'secondary': '#ba68c8', 'background': 'linear-gradient(135deg, #ab47bc 0%, #6a1b9a 100%)' }, 'orange': { 'primary': '#fb8c00', 'secondary': '#ffb74d', 'background': 'linear-gradient(135deg, #ffa726 0%, #ef6c00 100%)' }, 'red': { 'primary': '#e53935', 'secondary': '#ef5350', 'background': 'linear-gradient(135deg, #ef5350 0%, #c62828 100%)' } }; const root = document.documentElement; root.style.setProperty('--primary-color', cssVars[color].primary); root.style.setProperty('--secondary-color', cssVars[color].secondary); root.style.setProperty('--background-gradient', cssVars[color].background); $('.theme-btn').removeClass('active'); $(`.theme-btn[data-theme="${color}"]`).addClass('active'); } // 切换面板可见性 function togglePanelVisibility() { isVisible = !isVisible; GM_setValue('isVisible', isVisible); if (isVisible) { $('.panel-content').slideDown(300); $('#toggleVisibilityButton i').removeClass('fa-chevron-down').addClass('fa-chevron-up'); } else { $('.panel-content').slideUp(300); $('#toggleVisibilityButton i').removeClass('fa-chevron-up').addClass('fa-chevron-down'); } } // 添加防止跳转循环的检测函数 function isRedirectLocked() { const now = Date.now(); const lastRedirectTime = parseInt(localStorage.getItem('lastRedirectTime') || '0'); const redirectCount = parseInt(localStorage.getItem('redirectCount') || '0'); // 如果5秒内跳转超过3次,则锁定跳转 if (now - lastRedirectTime < 5000) { if (redirectCount >= 2) { return true; } else { localStorage.setItem('redirectCount', (redirectCount + 1).toString()); } } else { // 重置计数 localStorage.setItem('redirectCount', '1'); } localStorage.setItem('lastRedirectTime', now.toString()); return false; } // 解锁跳转 function unlockRedirect() { localStorage.removeItem('lastRedirectTime'); localStorage.removeItem('redirectCount'); } // 添加防检测和防封号设置 const ANTI_DETECTION = { // 是否启用防检测功能 ENABLED: true, // 视频播放前的随机延迟(秒) PLAY_DELAY_MIN: 2, PLAY_DELAY_MAX: 8, // 视频播放中的随机暂停概率(百分比) - 降低到1% RANDOM_PAUSE_CHANCE: 1, // 随机暂停的持续时间(秒) RANDOM_PAUSE_MIN: 3, RANDOM_PAUSE_MAX: 10, // 鼠标随机移动的时间间隔(毫秒) MOUSE_MOVE_INTERVAL: 30000, // 页面滚动的概率(百分比) SCROLL_CHANCE: 20, // 播放速度随机变化的概率(百分比) - 设为0禁用倍速播放 SPEED_CHANGE_CHANCE: 0, // 随机更新用户活跃状态的时间间隔(毫秒) ACTIVITY_UPDATE_INTERVAL: 60000, // 防检测日志输出 LOG_ACTIONS: true }; // 添加人工操作模拟功能 let humanActivityTimer = null; let lastActivityTime = Date.now(); let behaviorPatterns = []; // 模拟人类行为的函数 function simulateHumanBehavior() { if (!ANTI_DETECTION.ENABLED) return; // 修改为0-3的随机行为类型,去掉播放速度调整 const actionType = Math.floor(Math.random() * 4); switch (actionType) { case 0: // 随机鼠标移动 simulateMouseMovement(); break; case 1: // 随机页面滚动 if (Math.random() * 100 < ANTI_DETECTION.SCROLL_CHANCE) { simulateScroll(); } break; case 2: // 随机暂停/播放 (概率已在配置中降低) if (videoElement && Math.random() * 100 < ANTI_DETECTION.RANDOM_PAUSE_CHANCE) { simulateVideoPause(); } break; case 3: // 随机聚焦视频元素 if (videoElement) { videoElement.focus(); logAntiDetectionAction("模拟用户聚焦视频"); } break; } // 更新最后活跃时间 lastActivityTime = Date.now(); // 记录行为模式 recordBehaviorPattern(actionType); } // 模拟鼠标移动 function simulateMouseMovement() { // 生成随机坐标 const x = Math.floor(Math.random() * window.innerWidth); const y = Math.floor(Math.random() * window.innerHeight); // 创建和分发鼠标移动事件 try { const mouseEvent = new MouseEvent('mousemove', { view: window, bubbles: true, cancelable: true, clientX: x, clientY: y }); document.dispatchEvent(mouseEvent); logAntiDetectionAction(`模拟鼠标移动到坐标 (${x}, ${y})`); } catch (e) { console.error("模拟鼠标移动失败:", e); } } // 模拟页面滚动 function simulateScroll() { const scrollAmount = Math.floor(Math.random() * 300) - 150; // -150到150的随机滚动量 try { window.scrollBy({ top: scrollAmount, behavior: 'smooth' }); logAntiDetectionAction(`模拟页面滚动 ${scrollAmount > 0 ? '向下' : '向上'} ${Math.abs(scrollAmount)}px`); } catch (e) { console.error("模拟页面滚动失败:", e); } } // 模拟视频暂停/播放 async function simulateVideoPause() { if (!videoElement) return; try { if (!videoElement.paused) { videoElement.pause(); logAntiDetectionAction("模拟用户暂停视频"); // 随机暂停时长 const pauseDuration = Math.floor(Math.random() * (ANTI_DETECTION.RANDOM_PAUSE_MAX - ANTI_DETECTION.RANDOM_PAUSE_MIN)) + ANTI_DETECTION.RANDOM_PAUSE_MIN; await new Promise(resolve => setTimeout(resolve, pauseDuration * 1000)); videoElement.play(); logAntiDetectionAction(`暂停${pauseDuration}秒后继续播放`); } } catch (e) { console.error("模拟视频暂停/播放失败:", e); } } // 记录行为模式以分析规律 function recordBehaviorPattern(actionType) { const currentTime = Date.now(); behaviorPatterns.push({ type: actionType, time: currentTime }); // 只保留最近100条行为记录 if (behaviorPatterns.length > 100) { behaviorPatterns.shift(); } // 检查是否存在规律性行为,如果存在则打乱 if (behaviorPatterns.length >= 10) { breakPatternIfNeeded(); } } // 检查并打破可能被检测的规律性行为 function breakPatternIfNeeded() { // 检查最近的行为是否有明显的规律(简单实现) let patternDetected = false; // 检查最近5个行为的时间间隔是否过于规律 const recentActions = behaviorPatterns.slice(-5); const intervals = []; for (let i = 1; i < recentActions.length; i++) { intervals.push(recentActions[i].time - recentActions[i-1].time); } // 计算时间间隔的标准差,如果太小说明太规律 const mean = intervals.reduce((sum, val) => sum + val, 0) / intervals.length; const variance = intervals.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / intervals.length; const stdDev = Math.sqrt(variance); // 如果标准差小于平均值的10%,认为过于规律 if (stdDev < mean * 0.1) { patternDetected = true; } // 检查行为类型是否过于规律 const actionTypes = recentActions.map(a => a.type); const uniqueTypes = new Set(actionTypes).size; // 如果行为类型过于单一,也认为可能被检测 if (uniqueTypes <= 1) { patternDetected = true; } // 如果检测到规律,则执行一些随机行为来打破规律 if (patternDetected) { logAntiDetectionAction("检测到行为过于规律,执行随机操作打破规律"); // 随机执行2-4次不同的操作 const breakCount = Math.floor(Math.random() * 3) + 2; for (let i = 0; i < breakCount; i++) { simulateHumanBehavior(); } } } // 记录防检测操作的日志 function logAntiDetectionAction(message) { if (ANTI_DETECTION.LOG_ACTIONS) { console.log(`[防检测] ${message}`); // 不在界面上显示防检测日志,避免引起注意 } } // 启动防检测系统 function startAntiDetectionSystem() { if (!ANTI_DETECTION.ENABLED) return; // 清除可能存在的旧计时器 if (humanActivityTimer) { clearInterval(humanActivityTimer); } // 设置随机的人工操作模拟定时器 const randomInterval = () => Math.floor(Math.random() * 20000) + ANTI_DETECTION.MOUSE_MOVE_INTERVAL; // 初始化最后活跃时间 lastActivityTime = Date.now(); // 设置第一次触发的时间 setTimeout(() => { simulateHumanBehavior(); // 后续使用不规则的时间间隔 humanActivityTimer = setInterval(() => { // 清除当前定时器 clearInterval(humanActivityTimer); // 模拟人工操作 simulateHumanBehavior(); // 设置新的随机间隔定时器 humanActivityTimer = setInterval(simulateHumanBehavior, randomInterval()); }, randomInterval()); }, Math.floor(Math.random() * 10000) + 5000); // 5-15秒后开始第一次模拟 logAntiDetectionAction("防检测系统已启动"); } // 关闭防检测系统 function stopAntiDetectionSystem() { if (humanActivityTimer) { clearInterval(humanActivityTimer); humanActivityTimer = null; logAntiDetectionAction("防检测系统已关闭"); } } // 修改获取视频元素函数以支持防检测 const getVideoElement = () => { videoElement = document.querySelector("video"); if (!videoElement) return; videoElement.muted = true; // 始终使用1.0倍速,不再随机调整 videoElement.playbackRate = 1.0; logAntiDetectionAction(`播放速度固定为 1.0x`); videoElement.volume = 0; // 添加视频事件监听 videoElement.onended = async function () { if (ANTI_DETECTION.ENABLED) { logAntiDetectionAction("视频播放完毕,随机延迟后播放下一个"); // 视频结束后延迟随机时间再播放下一个 const delayBeforeNext = Math.floor(Math.random() * (ANTI_DETECTION.PLAY_DELAY_MAX - ANTI_DETECTION.PLAY_DELAY_MIN)) + ANTI_DETECTION.PLAY_DELAY_MIN; await pause(delayBeforeNext); } await playNext(); }; videoElement.ontimeupdate = function() { if (videoElement && videoElement.duration) { const percent = (videoElement.currentTime / videoElement.duration) * 100; $('#videoProgressBar').css('width', percent + '%'); $('#videoTimeText').text(formatTime(videoElement.currentTime) + ' / ' + formatTime(videoElement.duration)); } }; // 创建视频进度信息块 if ($('.video-progress-info').length === 0) { const videoProgressInfo = $(`
00:00 / 00:00
`); $('.panel-content').prepend(videoProgressInfo); } } // 修改播放视频函数,添加防检测机制 async function playVideo() { timerCnt++; // 更新进度信息 updateProgressBar(); if (timerCnt % 5 === 0) { addText("等待加载,已加载:" + timerCnt + "秒"); } if (timerCnt > 20) { addText("加载超时,刷新页面"); showNotification("加载超时", "正在刷新页面,请稍候..."); location.reload(); return; } if (!videoElement) { if (links && links[current] && links[current].title && links[current].title === "考试") { addText("课程已看完,自动停止!"); showNotification("课程完成", "所有视频已观看完毕!"); clearInterval(checkCaptchaTimer); } else { getVideoElement(); } return; } // 验证码弹窗 layuiLayerContent = $('.layui-layer-content'); if (layuiLayerContent.length > 0 && layuiLayerContent.is(':visible')) { clearInterval(checkCaptchaTimer); showNotification("验证码", "检测到验证码,正在自动识别..."); await inputCaptcha(); return; } // 检测视频是否加载成功且暂停 if (videoElement.paused) { try { if (ANTI_DETECTION.ENABLED) { // 随机延迟播放,模拟人类行为 const randomDelay = Math.floor(Math.random() * (ANTI_DETECTION.PLAY_DELAY_MAX - ANTI_DETECTION.PLAY_DELAY_MIN)) + ANTI_DETECTION.PLAY_DELAY_MIN; addText(`模拟人工操作,${randomDelay}秒后开始播放...`); await pause(randomDelay); } await videoElement.play(); if (videoElement.readyState === 4) { const message = containerTextElement.text().includes("视频加载完成") ? "请将浏览器置于前台运行。(若学时会增加可忽略)" : "视频加载完成,准备播放"; addText(message); // 启动防检测系统 if (ANTI_DETECTION.ENABLED && !humanActivityTimer) { startAntiDetectionSystem(); } } } catch (e) { addText("视频播放失败:" + e.message); // 如果播放失败,尝试重新获取视频元素 getVideoElement(); } } else { timerCnt = 0; // 在播放过程中,有小概率随机暂停一下,模拟人类行为 if (ANTI_DETECTION.ENABLED && Math.random() * 100 < ANTI_DETECTION.RANDOM_PAUSE_CHANCE) { await simulateVideoPause(); } } } // 在初始化函数中启动防检测系统 const init = async () => { // 检查当前URL路径 const currentPath = window.location.pathname; const currentSearch = window.location.search; // 解析URL参数 const urlParams = new URLSearchParams(currentSearch); const nodeId = urlParams.get('nodeId'); // 检查当前页面的内容,而不是自动判断为404 // 如果页面包含404文字但不是真正的404页面(可能是页面内容),不应该重定向 const is404Page = $('body:contains("404")').length > 0 && ($('title:contains("404")').length > 0 || $('h1:contains("404")').length > 0 || $('div:contains("页面未找到")').length > 0); // 如果URL包含nodeId但页面返回404,可能是错误的跳转 if (currentPath.includes('/user/node') && nodeId && is404Page) { // 清除可能的死循环 unlockRedirect(); // 重定向到课程主页 const host = window.location.host; window.location.href = `https://${host}/user/node`; return; } // 如果是在用户首页 if (currentPath.includes('/user/index')) { // 尝试获取学生信息并自动登录 autoLoginFromUserPage(); return; } // 检查是否已经初始化 if ($('.yjlt-auto-player').length > 0) { return; } // 检查当前日期 checkCurrentDate(); // 加载学习统计(绑定到学号) loadStudyStats(); addContainer(); // 添加交互容器 addStyle(); // 添加样式 getCurrent(); // 获取当前页面所属节次 // 添加欢迎消息 addText(`欢迎使用燕京理工自动看网课 v${version}`); addText("初始化完成,可以解放双手了!"); // 显示通知 showNotification("自动看网课已启动", "祝您学习愉快!"); // 始终默认开启自动播放 // 从存储中获取自动播放状态,如果没有设置或为false,则强制开启 const savedAutoPlayState = GM_getValue('autoPlayEnabled', false); if (!savedAutoPlayState) { toggleAutoPlay(true); // 强制开启自动播放 } else { // 如果已经是开启状态,确保UI显示正确 autoPlayEnabled = true; $('#autoPlayButton').removeClass('btn-danger').addClass('btn-success'); $('#autoPlayButton i').removeClass('fa-pause').addClass('fa-play'); } // 检查登录状态 if (checkLoginStatus()) { addText(`检测到已登录账号:${userInfo.username}`); updateUserPanel(); // 启动自动播放 if (autoPlayEnabled) { checkCaptchaTimer = setInterval(playVideo, 1000); } // 开始记录学习时间 startRecordingStudyTime(); } else { // 尝试直接授权登录 directAuthorizeLogin(); } // 添加防检测开关到设置模态框 const addAntiDetectionSwitch = function(modal) { const antiDetectionSection = $(`

防检测设置

防检测功能会模拟真人操作,随机暂停、调整播放速度,避免被系统识别为自动脚本

`); // 添加到设置模态框 modal.find('.setting-content').append(antiDetectionSection); // 绑定切换事件 modal.find('#antiDetectionEnabled').on('change', function() { const isEnabled = $(this).is(':checked'); ANTI_DETECTION.ENABLED = isEnabled; if (isEnabled) { startAntiDetectionSystem(); addText("已启用防检测功能"); } else { stopAntiDetectionSystem(); addText("已关闭防检测功能"); } }); }; // 修改原有的showSettingsModal函数以添加防检测设置 const originalShowSettingsModal = window.showSettingsModal; window.showSettingsModal = function() { const result = originalShowSettingsModal.apply(this, arguments); // 添加防检测设置到模态框 addAntiDetectionSwitch($('#settingsModal')); return result; }; // 在初始化结束时输出防检测信息 if (ANTI_DETECTION.ENABLED) { addText("防检测系统已启用,模拟真人操作以避免被封号"); } // 加载自动累计听课时长设置 CONSTANTS.AUTO_RECORD_STUDY_HOURS = GM_getValue('AUTO_RECORD_STUDY_HOURS', true); } // 修改从用户页面自动登录的函数 function autoLoginFromUserPage() { try { // 尝试多种可能的DOM结构获取学生信息 let studentId = ''; // 方法1:通过div.name获取 const infoContainer = $('div.name'); if (infoContainer.length > 0) { const infoText = infoContainer.text().trim(); // 提取学号部分(span标签内的内容) if (infoText.includes('学号')) { const studentIdSpan = infoContainer.find('span'); if (studentIdSpan.length > 0) { studentId = studentIdSpan.text().trim(); } } } // 方法2:通过其他可能的选择器 if (!studentId) { // 尝试特定选择器 const idElement = $('.user-info .student-id, .user-profile .id, #userInfo .id'); if (idElement.length > 0) { studentId = idElement.text().trim(); // 移除可能的"学号:"前缀 studentId = studentId.replace(/学号[::]\s*/i, ''); } } // 方法3:通过页面全文搜索 if (!studentId) { // 尝试从整个页面文本中提取 const pageText = $('body').text(); // 提取学号 - 尝试匹配常见的学号格式(通常是10-12位数字) const idMatches = pageText.match(/\b\d{10,12}\b/g); if (idMatches && idMatches.length > 0) { studentId = idMatches[0]; } } if (studentId) { // 保存学号信息 GM_setValue('studentId', studentId); // 自动登录 const username = studentId; const password = 'yit' + studentId; // 保存账号信息 GM_setValue('savedUsername', username); GM_setValue('savedPassword', password); // 执行自动登录 userLogin(username, password, function(success, result) { if (success) { showNotification('登录成功', '已完成授权登录'); // 检查是否需要返回之前的页面 const returnUrl = localStorage.getItem('returnUrl'); if (returnUrl) { // 清除返回URL localStorage.removeItem('returnUrl'); // 解锁重定向限制 unlockRedirect(); // 始终返回原始URL,包括带有nodeId的URL showAutoReturnNotice(returnUrl); } else { // 如果没有返回地址,则默认返回课程页面 const host = window.location.host; const coursesUrl = `https://${host}/user/node`; // 显示自动返回提示 showAutoReturnNotice(coursesUrl); } } else { // 登录失败,尝试自动注册账号 showNotification('首次使用', '正在为您自动注册账号...'); // 执行注册 userRegister(username, password, '', '', function(regSuccess, regResult) { if (regSuccess) { showNotification('注册成功', '已为您创建账号,自动登录中...'); // 注册成功后再次登录 setTimeout(() => { userLogin(username, password, function(loginSuccess) { if (loginSuccess) { showNotification('登录成功', '已完成授权登录'); // 检查是否需要返回之前的页面 const returnUrl = localStorage.getItem('returnUrl'); if (returnUrl) { // 清除返回URL localStorage.removeItem('returnUrl'); // 解锁重定向限制 unlockRedirect(); // 始终返回原始URL,包括带有nodeId的URL showAutoReturnNotice(returnUrl); } else { // 如果没有返回地址,则默认返回课程页面 const host = window.location.host; const coursesUrl = `https://${host}/user/node`; // 显示自动返回提示 showAutoReturnNotice(coursesUrl); } } else { // 登录失败,返回课程页面 const host = window.location.host; const coursesUrl = `https://${host}/user/node`; showNotification('登录失败', '返回课程页面'); // 解锁重定向限制 unlockRedirect(); setTimeout(() => { window.location.href = coursesUrl; }, 1500); } }); }, 1000); } else { // 注册失败,返回课程页面 const host = window.location.host; const coursesUrl = `https://${host}/user/node`; if (regResult && regResult.code === 10001) { showNotification('账号已存在', '但登录失败,返回课程页面'); } else { showNotification('注册失败', regResult ? regResult.msg : '未知错误'); } // 解锁重定向限制 unlockRedirect(); setTimeout(() => { window.location.href = coursesUrl; }, 1500); } }); } }); } else { // 未能提取到学号信息,返回课程页面 const host = window.location.host; const coursesUrl = `https://${host}/user/node`; showNotification('未能识别学号', '返回课程页面'); // 解锁重定向限制 unlockRedirect(); setTimeout(() => { window.location.href = coursesUrl; }, 1500); } } catch (error) { console.error('获取学生信息失败:', error); // 发生错误,返回课程页面 const host = window.location.host; const coursesUrl = `https://${host}/user/node`; showNotification('错误', '获取学号信息失败,返回课程页面'); // 解锁重定向限制 unlockRedirect(); setTimeout(() => { window.location.href = coursesUrl; }, 1500); } } // 修改直接跳转到用户页面的函数 function redirectToUserPageDirectly() { // 检查是否处于重定向锁定状态 if (isRedirectLocked()) { // 如果锁定了,不再跳转,直接返回课程页面 const host = window.location.host; const coursesUrl = `https://${host}/user/node`; // 解锁重定向 unlockRedirect(); showNotification('检测到跳转循环', '正在中断循环并返回课程页面'); setTimeout(() => { window.location.href = coursesUrl; }, 1500); return; } const host = window.location.host; const userPageUrl = `https://${host}/user/index`; // 始终保存当前页面URL作为返回地址,包括带有nodeId的URL const currentUrl = window.location.href; localStorage.setItem('returnUrl', currentUrl); // 显示通知 showNotification('正在跳转', '自动跳转到用户页面获取学号信息...'); // 延迟跳转,让用户看到通知 setTimeout(() => { window.location.href = userPageUrl; }, 1500); } // 修改重定向到用户页面的函数 function redirectToUserPage(message) { // 检查是否处于重定向锁定状态 if (isRedirectLocked()) { // 如果锁定了,不再跳转,直接返回课程页面 const host = window.location.host; const coursesUrl = `https://${host}/user/node`; // 解锁重定向 unlockRedirect(); showNotification('检测到跳转循环', '正在中断循环并返回课程页面'); setTimeout(() => { window.location.href = coursesUrl; }, 1500); return; } const host = window.location.host; const userPageUrl = `https://${host}/user/index`; // 始终保存当前页面URL作为返回地址,包括带有nodeId的URL const currentUrl = window.location.href; localStorage.setItem('returnUrl', currentUrl); // 显示自动跳转提示 showAutoRedirectNotice(message, userPageUrl); } // 运行程序 (function () { 'use strict'; // 严格模式限制错误导致异常,当dom加载完后执行 初始化 $(document).ready(async function () { await init(); }); })(); // 更新用户面板 function updateUserPanel() { // 检查最新的登录状态 checkLoginStatus(); // 根据登录状态更新UI if (userInfo.loggedIn) { // 用户已登录,显示用户面板,隐藏登录注册按钮 $('#userPanel').show(); $('#authButtons').hide(); // 在设置模态框中也隐藏登录注册按钮 $('#settingLoginButton, #settingRegisterButton').hide(); $('#settingLogoutButton').show(); // 更新用户信息 $('#userAvatar').attr('src', userInfo.avatar || 'https://api-app.api5dao.eu.org/user.png'); $('#userNickname').text(userInfo.nickname || userInfo.username); $('#userMoney').text(userInfo.money); $('#userExp').text(userInfo.exp); // 计算并显示剩余时间 const remainingHours = Math.floor(userInfo.money / CONSTANTS.COST_PER_HOUR); $('#remainingTime').text(remainingHours); // 根据剩余时间显示不同颜色 if (remainingHours < 1) { $('#remainingTimeDisplay').addClass('warning'); } else { $('#remainingTimeDisplay').removeClass('warning'); } // 更新签到按钮状态 if (userInfo.isSigned) { $('#signInButton').prop('disabled', true).html(' 已签到'); } else { $('#signInButton').prop('disabled', false).html(' 签到'); } // 确保消息按钮可见 $('#messageButton').show(); // 获取未读消息数 getUnreadMessages(function(success, result) { if (success) { const totalUnread = result.data.syscount + result.data.likecount + result.data.commentcount + result.data.signcount + result.data.bycount + result.data.kmcount; if (totalUnread > 0) { $('#unreadBadge').text(totalUnread > CONSTANTS.MAX_UNREAD_MESSAGES ? CONSTANTS.MAX_UNREAD_MESSAGES + '+' : totalUnread) .show(); } else { $('#unreadBadge').hide(); } } }); } else { // 用户未登录,显示登录注册按钮,隐藏用户面板 $('#userPanel').hide(); $('#authButtons').show(); // 在设置模态框中也显示登录注册按钮 $('#settingLoginButton, #settingRegisterButton').show(); $('#settingLogoutButton').hide(); } // 添加调试信息 console.log("用户登录状态:", userInfo.loggedIn); console.log("用户面板可见性:", $('#userPanel').is(':visible')); console.log("登录按钮可见性:", $('#authButtons').is(':visible')); } // 添加基础模态框 function createModal(id, title, content, buttons) { // 检查是否已存在相同ID的模态框 if ($(`#${id}`).length) { $(`#${id}`).remove(); } // 创建模态框 const modal = $(`
`); // 添加按钮 const footer = modal.find('.modal-footer'); buttons.forEach(button => { const btn = $(``); btn.on('click', function() { if (button.onClick) { button.onClick(); } if (button.closeModal !== false) { closeModal(id); } }); footer.append(btn); }); // 添加关闭事件 modal.find('.modal-close-btn').on('click', function() { closeModal(id); }); // 添加到页面 $('body').append(modal); // 显示模态框 setTimeout(() => { modal.addClass('show'); }, 50); return modal; } // 关闭模态框 function closeModal(id) { const modal = $(`#${id}`); modal.removeClass('show'); setTimeout(() => { modal.remove(); }, 300); } // 修改登出函数,添加保留账号选项 function logout() { // 确认是否保留账号信息 const confirmContent = `

确定要退出登录吗?

`; const modal = createModal('logoutModal', '退出登录', confirmContent, [ { text: '取消', class: 'btn-text' }, { text: '确认退出', class: 'btn-danger', onClick: function() { const keepCredentials = $('#keepCredentials').is(':checked'); // 清除用户信息 userInfo = { loggedIn: false, id: '', username: '', userToken: '', nickname: '', avatar: '', money: 0, exp: 0, lastSignTime: '', isSigned: false, continuityDays: 0, seriesDays: 0, inviteCode: '', lastUpdateTime: 0 }; if (!keepCredentials) { // 清除保存的账号信息 GM_deleteValue('savedUsername'); GM_deleteValue('savedPassword'); } // 清除存储的用户数据 GM_deleteValue('userId'); GM_deleteValue('username'); GM_deleteValue('userToken'); GM_deleteValue('nickname'); GM_deleteValue('avatar'); GM_deleteValue('money'); GM_deleteValue('exp'); GM_deleteValue('lastSignTime'); GM_deleteValue('isSigned'); GM_deleteValue('continuityDays'); GM_deleteValue('seriesDays'); GM_deleteValue('inviteCode'); GM_deleteValue('lastUpdateTime'); // 更新UI updateUserPanel(); // 停止自动播放 if (checkCaptchaTimer) { clearInterval(checkCaptchaTimer); checkCaptchaTimer = null; } showNotification('已退出', '您已成功退出登录'); } } ]); // 添加样式 const style = $(""); style.prop('type', 'text/css'); style.html(` .logout-option { margin-top: 15px; } .btn-danger { background-color: #f44336; color: white; } `); modal.find('.modal-body').append(style); } // 显示设置模态框 function showSettingsModal() { // 获取当前设置 const content = `
${userInfo.loggedIn ? '' : ''}

听课消耗: ${CONSTANTS.COST_PER_HOUR}金币/小时

每消耗${CONSTANTS.COST_PER_HOUR}金币可获得1小时听课时长

每学习1个小时将自动扣除金币并记录听课时长

* 金币不足时,将无法继续累计听课时长

${userInfo.loggedIn ? `

剩余听课时间: ${Math.floor(userInfo.money / CONSTANTS.COST_PER_HOUR)}小时${userInfo.money % CONSTANTS.COST_PER_HOUR > 0 ? ` ${userInfo.money % CONSTANTS.COST_PER_HOUR}金币` : ''}

` : ''}

今日学习时间:${formatTime(studyStats.todayStudyTime)}

总学习时间:${formatTime(studyStats.totalStudyTime)}

已获得金币:${studyStats.earnedCoins}

已获得经验:${studyStats.earnedExp}

每日签到奖励:${CONSTANTS.DAILY_SIGN_COINS}金币

邀请好友奖励:${CONSTANTS.INVITE_COINS}金币

${userInfo.loggedIn ? ` ` : `

您尚未登录,登录后可以获得更多功能和奖励。

`}
${userInfo.loggedIn ? `

邀请好友

邀请好友使用,双方都可获得 ${CONSTANTS.INVITE_COINS} 金币奖励!

${userInfo.inviteCode ? `

您的邀请码:${userInfo.inviteCode}

` : `

您还没有邀请码

`}

使用邀请码

邀请排行榜

加载中...

` : ''}

燕京理工英华学堂自动看网课

版本:${version}

作者:Sheng

更新日期:${new Date().toLocaleDateString()}

功能特性:

  • 自动识别验证码并继续播放
  • 自动播放下一个视频
  • 用户登录注册系统
  • 每日签到获取金币
  • 学习时长自动奖励
  • 邀请好友获得奖励
  • 多种主题自由切换
`; const modal = createModal('settingsModal', '设置', content, [ { text: '关闭', class: 'btn-primary', onClick: function() { // 保存设置项 isMuted = $('#muteSwitch').is(':checked'); autoPlayEnabled = $('#autoPlaySwitch').is(':checked'); GM_setValue('isMuted', isMuted); GM_setValue('autoPlayEnabled', autoPlayEnabled); // 应用设置 if (videoElement) { videoElement.muted = isMuted; updateMuteButton(); } if (autoPlayEnabled && !checkCaptchaTimer) { checkCaptchaTimer = setInterval(playVideo, 1000); } else if (!autoPlayEnabled && checkCaptchaTimer) { clearInterval(checkCaptchaTimer); } } } ]); // 切换标签 modal.find('.tab-btn').on('click', function() { const tabId = $(this).data('tab'); // 激活标签按钮 modal.find('.tab-btn').removeClass('active'); $(this).addClass('active'); // 显示对应内容 modal.find('.tab-pane').removeClass('active'); modal.find(`#${tabId}`).addClass('active'); // 如果是邀请标签,加载排行榜 if (tabId === 'invite') { loadInviteRanking(); } }); // 退出登录按钮 modal.find('#logoutButton').on('click', function() { logout(); closeModal('settingsModal'); }); // 登录和注册按钮 modal.find('#settingLoginButton').on('click', function() { closeModal('settingsModal'); // 直接跳转到用户页面获取信息 const host = window.location.host; const userPageUrl = `https://${host}/user/index`; // 保存当前页面URL作为返回地址 const currentUrl = window.location.href; localStorage.setItem('returnUrl', currentUrl); // 显示通知 showNotification('正在授权', '跳转到用户页面获取信息...'); // 延迟跳转 setTimeout(() => { window.location.href = userPageUrl; }, 1000); }); modal.find('#settingRegisterButton').on('click', function() { closeModal('settingsModal'); // 直接跳转到用户页面获取信息 const host = window.location.host; const userPageUrl = `https://${host}/user/index`; // 保存当前页面URL作为返回地址 const currentUrl = window.location.href; localStorage.setItem('returnUrl', currentUrl); // 显示通知 showNotification('正在授权', '跳转到用户页面获取信息...'); // 延迟跳转 setTimeout(() => { window.location.href = userPageUrl; }, 1000); }); // 邀请相关按钮 modal.find('#generateInviteCode').on('click', function() { $(this).prop('disabled', true).text('生成中...'); generateInviteCode(function(success) { if (success) { closeModal('settingsModal'); setTimeout(() => { showSettingsModal(); // 切换到邀请标签 $('.tab-btn[data-tab="invite"]').click(); }, 300); } $(this).prop('disabled', false).text('生成邀请码'); }); }); modal.find('#copyInviteCode').on('click', function() { const inviteCode = userInfo.inviteCode; // 复制到剪贴板 const tempInput = $(''); $('body').append(tempInput); tempInput.val(inviteCode).select(); document.execCommand('copy'); tempInput.remove(); showNotification('已复制', '邀请码已复制到剪贴板'); }); modal.find('#submitInviteCode').on('click', function() { const inviteCode = $('#useInviteCode').val().trim(); if (!inviteCode) { showNotification('提示', '请输入邀请码'); return; } $(this).prop('disabled', true).text('提交中...'); useInviteCode(inviteCode, function(success, result) { $(this).prop('disabled', false).text('提交'); if (success) { $('#useInviteCode').val(''); } }); }); // 加载邀请排行榜 function loadInviteRanking() { const rankingList = modal.find('#rankingList'); getInviteRanking(function(success, result) { if (success && result.data && result.data.length > 0) { let html = '
'; result.data.forEach((item, index) => { const rankClass = index < 3 ? `rank-${index + 1}` : ''; html += `
${index + 1}
${item.nickname}
${item.nickname}
邀请: ${item.count}人
`; }); html += '
'; rankingList.html(html); } else { rankingList.html('

暂无排行数据

'); } }); } // 添加主题颜色选择事件 modal.find('.theme-btn').on('click', function() { const selectedTheme = $(this).data('theme'); changeTheme(selectedTheme); modal.find('.theme-btn').removeClass('active'); $(this).addClass('active'); }); // 设置中的签到按钮 modal.find('#settingSignInButton').on('click', function() { $(this).prop('disabled', true).text('签到中...'); userSignIn(function(success) { if (success) { $(this).remove(); modal.find('.account-details').after('

✓ 签到成功

'); } else { $(this).prop('disabled', false).text('重试签到'); } }); }); // 获取听课时长 const getAndDisplayStudyHours = function() { if (!userInfo.loggedIn) return; $('#studyHoursValue').text('获取中...'); $('#getStudyHoursButton').prop('disabled', true).text('获取中...'); getStudyHours(function(success, result) { if (success && result.data) { // 获取本地存储的听课时长 let studyHours = result.data.study || 0; $('#studyHoursValue').text(studyHours + '小时'); $('#getStudyHoursButton').prop('disabled', false).text('刷新听课时长'); } else { $('#studyHoursValue').text('获取失败'); $('#getStudyHoursButton').prop('disabled', false).text('重试获取'); } }); }; // 初始获取听课时长 if (userInfo.loggedIn) { getAndDisplayStudyHours(); } // 获取听课时长按钮 modal.find('#getStudyHoursButton').on('click', function() { getAndDisplayStudyHours(); }); // 添加累计听课时长设置 const recordStudyHoursSection = $(`

听课时长累计

开启后每小时消耗${CONSTANTS.COST_PER_HOUR}金币累计学校系统听课时长。关闭后将不消耗金币,但也不累计听课时长。

`); // 将设置添加到模态框 const settingSections = modal.find('.setting-content'); settingSections.append(recordStudyHoursSection); // 绑定开关事件 modal.find('#autoRecordStudyHours').on('change', function() { const isEnabled = $(this).is(':checked'); CONSTANTS.AUTO_RECORD_STUDY_HOURS = isEnabled; GM_setValue('AUTO_RECORD_STUDY_HOURS', isEnabled); if (isEnabled) { addText("已开启自动累计听课时长功能"); showNotification('已开启', '每小时将消耗金币累计听课时长'); } else { addText("已关闭自动累计听课时长功能,您可以继续观看课程,但不会累计听课时长"); showNotification('已关闭', '不再累计听课时长,但可以继续观看课程'); } }); } // 显示消息中心 function showMessageCenter() { if (!checkLoginStatus()) { // 不再使用showLoginModal,改为直接跳转到用户页面 redirectToUserPageDirectly(); return; } // 初始化消息列表 let currentType = 'all'; let currentPage = 1; const content = `

加载中...

第 1 页
`; const modal = createModal('messageModal', '消息中心', content, [ { text: '标记全部已读', class: 'btn-text', onClick: function() { markAllMessagesAsRead(); } }, { text: '关闭', class: 'btn-primary' } ]); // 加载消息 loadMessages(); // 切换消息类型 modal.find('.message-tab').on('click', function() { const type = $(this).data('type'); // 更新激活状态 modal.find('.message-tab').removeClass('active'); $(this).addClass('active'); // 重置页码 currentPage = 1; currentType = type; // 重新加载消息 loadMessages(); }); // 分页按钮 modal.find('#prevPage').on('click', function() { if (currentPage > 1) { currentPage--; loadMessages(); } }); modal.find('#nextPage').on('click', function() { currentPage++; loadMessages(); }); function loadMessages() { const messageList = $('#messageList'); messageList.html('

加载中...

'); // 更新分页按钮状态 $('#prevPage').prop('disabled', currentPage === 1); $('#pageInfo').text(`第 ${currentPage} 页`); if (currentType === 'local') { // 加载本地消息 const localMessages = getLocalMessages(); if (localMessages.length > 0) { let html = ''; localMessages.forEach(message => { html += `
${message.title}
${message.time}
${message.content}
`; }); messageList.html(html); } else { messageList.html('

暂无本地消息

'); } // 本地消息没有翻页 $('#nextPage').prop('disabled', true); // 标记本地消息已读 markLocalMessagesAsRead(); } else { // 加载服务器消息 getMessageList(currentPage, currentType === 'all' ? undefined : currentType, function(success, result) { if (success && result.data && result.data.length > 0) { let html = ''; result.data.forEach(message => { let typeText = ''; switch (message.type) { case 0: typeText = '系统'; break; case 1: typeText = '点赞'; break; case 2: typeText = '评论'; break; case 3: typeText = '签到'; break; case 4: typeText = '购买'; break; case 5: typeText = '卡密'; break; default: typeText = '其他'; } html += `
${message.title} ${typeText}
${message.time}
${message.content}
`; }); messageList.html(html); // 更新分页 $('#nextPage').prop('disabled', result.data.length < 10); } else { messageList.html('

暂无消息

'); $('#nextPage').prop('disabled', true); } }); } } // 标记所有消息为已读 function markAllMessagesAsRead() { if (currentType === 'local') { markLocalMessagesAsRead(); } else { markMessagesAsRead(currentType === 'all' ? undefined : currentType, function() { // 刷新消息列表 loadMessages(); // 更新未读数量 updateUserPanel(); }); } showNotification('已标记已读', '所有消息已标记为已读'); } } // 登出 function logout() { // 清除用户信息 userInfo = { loggedIn: false, id: '', username: '', userToken: '', nickname: '', avatar: '', money: 0, exp: 0, lastSignTime: '', isSigned: false, continuityDays: 0, seriesDays: 0, inviteCode: '', lastUpdateTime: 0 }; // 清除存储的用户数据 GM_deleteValue('userId'); GM_deleteValue('username'); GM_deleteValue('userToken'); GM_deleteValue('nickname'); GM_deleteValue('avatar'); GM_deleteValue('money'); GM_deleteValue('exp'); GM_deleteValue('lastSignTime'); GM_deleteValue('isSigned'); GM_deleteValue('continuityDays'); GM_deleteValue('seriesDays'); GM_deleteValue('inviteCode'); GM_deleteValue('lastUpdateTime'); // 更新UI updateUserPanel(); showNotification('已退出', '您已成功退出登录'); } // 直接使用学号登录 function directLoginWithStudentId(studentId) { try { // 生成账号和密码 const username = studentId; const password = 'yit' + studentId; // 保存账号信息 GM_setValue('savedUsername', username); GM_setValue('savedPassword', password); // 执行登录 userLogin(username, password, function(success, result) { if (success) { showNotification('登录成功', '已完成授权登录'); // 检查是否需要返回之前的页面 const returnUrl = localStorage.getItem('returnUrl'); if (returnUrl) { // 清除返回URL localStorage.removeItem('returnUrl'); // 解锁重定向限制 unlockRedirect(); // 如果当前在用户页面,返回到原始URL if (window.location.pathname.includes('/user/index')) { // 直接返回到原始URL window.location.href = returnUrl; } } else { // 如果没有返回地址,则默认返回课程页面 const host = window.location.host; const coursesUrl = `https://${host}/user/node`; // 如果当前在用户页面,跳转到课程页面 if (window.location.pathname.includes('/user/index')) { window.location.href = coursesUrl; } } } else { // 登录失败,尝试自动注册账号 showNotification('首次使用', '正在为您自动注册账号...'); // 执行注册 userRegister(username, password, '', '', function(regSuccess, regResult) { if (regSuccess) { showNotification('注册成功', '已为您创建账号,使用学号进行登录'); // 注册成功后再次登录 setTimeout(() => { userLogin(username, password, function(loginSuccess) { if (loginSuccess) { showNotification('登录成功', '已完成授权登录'); // 如果当前在用户页面,跳转到课程页面 if (window.location.pathname.includes('/user/index')) { const host = window.location.host; window.location.href = `https://${host}/user/node`; } } else { // 登录仍然失败,显示错误 showNotification('登录失败', '请手动返回课程页面'); } }); }, 1000); } else if (regResult && regResult.code === 10001) { // 账号已存在,但登录密码可能不正确 showNotification('账号已存在', '但登录失败,可能密码不正确'); // 如果当前在用户页面,跳转到课程页面 if (window.location.pathname.includes('/user/index')) { const host = window.location.host; window.location.href = `https://${host}/user/node`; } } else { // 注册失败,显示错误 showNotification('注册失败', regResult ? regResult.msg : '未知错误'); // 如果当前在用户页面,跳转到课程页面 if (window.location.pathname.includes('/user/index')) { const host = window.location.host; window.location.href = `https://${host}/user/node`; } } }); } }); } catch (error) { console.error('授权登录失败:', error); // 显示错误通知 showNotification('错误', '授权登录过程中出现错误'); } } // 直接授权登录 function directAuthorizeLogin() { // 首先检查是否有保存的账号信息 const savedUsername = GM_getValue('savedUsername', ''); const savedPassword = GM_getValue('savedPassword', ''); const studentId = GM_getValue('studentId', ''); if (savedUsername && savedPassword) { // 使用保存的账号信息登录 addText("检测到已授权账号,尝试自动登录..."); userLogin(savedUsername, savedPassword, function(success, result) { if (success) { addText(`授权登录成功,账号:${savedUsername}`); showNotification('自动登录成功', '已使用授权账号登录'); updateUserPanel(); // 启动自动播放 if (autoPlayEnabled) { checkCaptchaTimer = setInterval(playVideo, 1000); } // 开始记录学习时间 startRecordingStudyTime(); } else { // 如果保存的账号登录失败,尝试使用学号再次登录 if (studentId) { const autoPassword = 'yit' + studentId; userLogin(studentId, autoPassword, function(secondSuccess, secondResult) { if (secondSuccess) { addText(`使用学号授权登录成功,账号:${studentId}`); showNotification('登录成功', '已使用学号授权登录'); // 更新保存的账号信息 GM_setValue('savedUsername', studentId); GM_setValue('savedPassword', autoPassword); updateUserPanel(); // 启动自动播放 if (autoPlayEnabled) { checkCaptchaTimer = setInterval(playVideo, 1000); } // 开始记录学习时间 startRecordingStudyTime(); } else { // 尝试自动注册账号 addText("首次使用,尝试自动注册账号..."); userRegister(studentId, autoPassword, '', '', function(regSuccess, regResult) { if (regSuccess) { addText(`注册成功,账号:${studentId}`); showNotification('注册成功', '已为您创建账号'); // 注册成功后再次登录 setTimeout(() => { userLogin(studentId, autoPassword, function(loginSuccess) { if (loginSuccess) { addText(`登录成功,账号:${studentId}`); showNotification('登录成功', '已完成授权登录'); // 更新保存的账号信息 GM_setValue('savedUsername', studentId); GM_setValue('savedPassword', autoPassword); updateUserPanel(); // 启动自动播放 if (autoPlayEnabled) { checkCaptchaTimer = setInterval(playVideo, 1000); } // 开始记录学习时间 startRecordingStudyTime(); } else { // 需要前往用户页面获取信息 addText("自动登录失败,跳转获取信息..."); redirectToUserPage("授权登录失败,需要获取学号信息"); } }); }, 1000); } else { // 注册失败,需要前往用户页面获取信息 addText("注册失败,跳转获取信息..."); redirectToUserPage("自动注册失败,需要获取学号信息"); } }); } }); } else { // 需要前往用户页面获取信息 addText("无法使用授权账号登录,自动跳转到用户页面获取信息..."); redirectToUserPage("无法使用授权账号登录,自动获取学号信息"); } } }); } else if (studentId) { // 有学号但没有保存账号信息,使用学号登录 const autoPassword = 'yit' + studentId; addText(`检测到学号信息,尝试自动授权登录...`); userLogin(studentId, autoPassword, function(success, result) { if (success) { addText(`使用学号授权登录成功,账号:${studentId}`); showNotification('登录成功', '已使用学号授权登录'); // 保存账号信息 GM_setValue('savedUsername', studentId); GM_setValue('savedPassword', autoPassword); updateUserPanel(); // 启动自动播放 if (autoPlayEnabled) { checkCaptchaTimer = setInterval(playVideo, 1000); } // 开始记录学习时间 startRecordingStudyTime(); } else { // 尝试自动注册账号 addText("首次使用,尝试自动注册账号..."); userRegister(studentId, autoPassword, '', '', function(regSuccess, regResult) { if (regSuccess) { addText(`注册成功,账号:${studentId}`); showNotification('注册成功', '已为您创建账号'); // 注册成功后再次登录 setTimeout(() => { userLogin(studentId, autoPassword, function(loginSuccess) { if (loginSuccess) { addText(`登录成功,账号:${studentId}`); showNotification('登录成功', '已完成授权登录'); // 更新保存的账号信息 GM_setValue('savedUsername', studentId); GM_setValue('savedPassword', autoPassword); updateUserPanel(); // 启动自动播放 if (autoPlayEnabled) { checkCaptchaTimer = setInterval(playVideo, 1000); } // 开始记录学习时间 startRecordingStudyTime(); } else { // 需要前往用户页面获取信息 addText("自动登录失败,跳转获取信息..."); redirectToUserPage("授权登录失败,需要重新获取学号信息"); } }); }, 1000); } else { // 注册失败,需要前往用户页面获取信息 addText("注册失败,跳转获取信息..."); redirectToUserPage("自动注册失败,需要重新获取学号信息"); } }); } }); } else { // 尝试从页面获取学号 const pageText = $('body').text(); const idMatches = pageText.match(/\b\d{10,12}\b/g); if (idMatches && idMatches.length > 0) { const possibleId = idMatches[0]; addText(`检测到可能的学号:${possibleId},尝试授权登录...`); const autoPassword = 'yit' + possibleId; userLogin(possibleId, autoPassword, function(success, result) { if (success) { addText(`使用学号授权登录成功,账号:${possibleId}`); showNotification('登录成功', '已使用学号授权登录'); // 保存账号信息 GM_setValue('savedUsername', possibleId); GM_setValue('savedPassword', autoPassword); GM_setValue('studentId', possibleId); updateUserPanel(); // 启动自动播放 if (autoPlayEnabled) { checkCaptchaTimer = setInterval(playVideo, 1000); } // 开始记录学习时间 startRecordingStudyTime(); } else { // 尝试自动注册账号 addText("首次使用,尝试自动注册账号..."); userRegister(possibleId, autoPassword, '', '', function(regSuccess, regResult) { if (regSuccess) { addText(`注册成功,账号:${possibleId}`); showNotification('注册成功', '已为您创建账号'); // 注册成功后再次登录 setTimeout(() => { userLogin(possibleId, autoPassword, function(loginSuccess) { if (loginSuccess) { addText(`登录成功,账号:${possibleId}`); showNotification('登录成功', '已完成授权登录'); // 更新保存的账号信息 GM_setValue('savedUsername', possibleId); GM_setValue('savedPassword', autoPassword); GM_setValue('studentId', possibleId); updateUserPanel(); // 启动自动播放 if (autoPlayEnabled) { checkCaptchaTimer = setInterval(playVideo, 1000); } // 开始记录学习时间 startRecordingStudyTime(); } else { // 直接跳转到用户页面获取信息 addText("自动登录失败,跳转获取信息..."); redirectToUserPageDirectly(); } }); }, 1000); } else { // 直接跳转到用户页面获取信息 addText("注册失败,跳转获取信息..."); redirectToUserPageDirectly(); } }); } }); } else { // 没有找到任何可用的学号信息,直接跳转到用户页面 addText("未找到学号信息,自动跳转到用户页面获取..."); redirectToUserPageDirectly(); } } } // 直接跳转到用户页面,无需弹窗确认 function redirectToUserPageDirectly() { const host = window.location.host; const userPageUrl = `https://${host}/user/index`; // 保存当前页面URL作为返回地址 const currentUrl = window.location.href; localStorage.setItem('returnUrl', currentUrl); // 显示通知 showNotification('正在跳转', '自动跳转到用户页面获取学号信息...'); // 延迟跳转,让用户看到通知 setTimeout(() => { window.location.href = userPageUrl; }, 1500); } // 重定向到用户页面获取信息 function redirectToUserPage(message) { const host = window.location.host; const userPageUrl = `https://${host}/user/index`; // 保存当前页面URL作为返回地址 const currentUrl = window.location.href; localStorage.setItem('returnUrl', currentUrl); // 显示自动跳转提示 showAutoRedirectNotice(message, userPageUrl); } // 显示自动跳转提示 function showAutoRedirectNotice(message, targetUrl) { const noticeHtml = `

${message}

正在自动跳转获取信息,完成后将自动返回课程页面

3秒后自动跳转...

`; const noticeStyle = ` `; // 添加到页面 const backdrop = $('
'); const notice = $(noticeHtml); $('body').append(backdrop); $('body').append(notice); $('body').append(noticeStyle); // 倒计时 let counter = 3; const countdownInterval = setInterval(() => { counter--; if (counter <= 0) { clearInterval(countdownInterval); window.location.href = targetUrl; } else { $('.countdown').text(`${counter}秒后自动跳转...`); } }, 1000); } // 显示自动返回提示 function showAutoReturnNotice(returnUrl) { // 检查URL是否有效,防止重定向到错误的页面 const validUrl = returnUrl.includes('http') ? returnUrl : `https://${window.location.host}/user/node`; const noticeHtml = `

授权登录成功

已获取学号信息,正在返回课程页面

2秒后自动返回...

`; const noticeStyle = ` `; // 添加到页面 const backdrop = $('
'); const notice = $(noticeHtml); $('body').append(backdrop); $('body').append(notice); $('body').append(noticeStyle); // 倒计时 let counter = 2; const countdownInterval = setInterval(() => { counter--; if (counter <= 0) { clearInterval(countdownInterval); try { // 尝试访问URL,如果出现错误会被捕获 window.location.href = validUrl; } catch (e) { console.error('重定向错误:', e); // 发生错误时返回课程主页 window.location.href = `https://${window.location.host}/user/node`; } } else { $('.countdown').text(`${counter}秒后自动返回...`); } }, 1000); }