// ==UserScript== // @name 学习通刷课助手-自动静音,防止鼠标移出暂停,章节结束自动跳转下一节 // @namespace http://tampermonkey.net/ // @version 1.0.7 // @description 学习通课程自动挂机,当前脚本支持课程视频播放完成,自动跳转下一小节,章节测试自动跳过,后台播放防止视频暂停。 // @author Sweek // @match *://*.chaoxing.com/* // @license GPLv3 // @icon https://www.google.com/s2/favicons?sz=64&domain=csdn.net // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @require https://code.jquery.com/jquery-2.1.4.min.js // ==/UserScript== GM_setValue("playbackRate", GM_getValue("playbackRate") || 1); GM_setValue("volume", GM_getValue("volume") || 0); // 定义全局变量 let currentTime = null // 当前视频当前播放节点 let duration = null // 当前视频总长度 let progress = null // 当前视频播放进度 let playbackRate = GM_getValue("playbackRate") // 当前视频播放倍速 let volume = GM_getValue("volume") // 当前视频音量 // 课程章节相关数据 let courseName = null // 当前课程名称 let courseId = null // 当前课程id let chapterInfo = [] // 当前课程所有章节数据 let currentChapterId = null // 当前所在章节id let currentChapterName = null // 当前所在章节名称 let allChapterName = [] // 所有章节名称 let currentChapterTabArr = [] // 当前页面所有的分栏 let currentChapterTabName = '' // 当前页面激活的分栏名称 let videoProgressId = '' // 定时监听页面内容监听事件 // 获取当前页面的 URL url = '' chapterId = '' let arrayEchelon = []; // 顺序执行梯队,初始化为空数组 const dealEvent = new Event("redeal", { bubbles: false, cancelable: false }); // 页面模板部分 // 页面模板部分 // 页面模板部分 // 页面样式 var popCSs = ` #my-window { position: fixed; top: 5px; left: 20px; width: 320px; height: auto; background-color: rgba(247, 247, 247, 1); border: 1px solid #fff; border-radius: 5px; z-index: 9999; overflow: hidden; padding: 0 5px 10px 0; font-family: fangsong; font-weight: bold; } #my-window .header { background-color: #4497fa; color: #fff; padding: 5px; font-size: 16px; font-family: 'fangsong'; font-weight: bold; border-radius: 5px; cursor: move; height: 25px; width: 320px; } #my-window .content { width: 320px; height: auto; } #my-window .content .content-title { height: 22px; width: 300px; background-color: #dadada; line-height: 22px; padding-left: 5px; font-size: 12px; font-family: 'fangsong'; font-weight: 600; boder-radius: 5px; border-left: 4px solid #2196f3; border-right: 4px solid #dadada; margin-top: 5px; border-radius: 3px; } #my-window .content .content-notice { height: 80px; width: 300px; overflow: auto; border: 1px solid gray; border-radius: 3px; padding: 5px; margin-top: 5px; font-size: 12px; font-weight: bold; } #my-window .content .content-process { height: 60px; width: 300px; overflow: auto; border: 1px solid gray; border-radius: 3px; padding: 5px; margin-top: 5px; } #my-window .content .content-log { height: 120px; width: 300px; overflow: auto; border: 1px solid gray; border-radius: 3px; padding: 5px; margin-top: 5px; } #my-window .content .content-set { height: 240px; width: 300px; overflow: auto; border: 1px solid gray; border-radius: 3px; padding: 5px; margin-top: 5px; } #my-window .content .content-set .content-set-content { width: 290px; display: flex; justify-content: space-between; border-top: 1px solid gray; border-bottom: 1px solid gray; padding: 5px 5px; } #my-window .content .content-set .content-set-content .control { width: 220px; height: 20px; display: flex; justify-content: space-between; } #my-window .content .content-set .content-set-content .control #playbackRateSelect { width: 220px; height: 20px; border-radius: 3px; border: 1px solid gray; font-size: 13px; font-family: fangsong; font-weight: bold; cursor: pointer; } #my-window .content .content-set .content-set-content .control #volumeSelect { width: 220px; height: 20px; border-radius: 3px; border: 1px solid gray; font-size: 13px; font-family: fangsong; font-weight: bold; cursor: pointer; } #my-window .content .content-set .content-set-content #email-input { width: 175px; height: 20px; border-radius: 3px; border: 1px solid gray; font-size: 13px; font-family: fangsong; font-weight: bold; } #my-window .content .content-set .content-set-content #save-btn { color: gray; width: 40px; height: 22px; border-radius: 3px; border: 1px solid gray; font-size: 13px; font-family: fangsong; font-weight: bold; cursor: pointer; } #save-btn:hover { background-color: #e3e3e3!important; } #my-window .resizer { position: absolute; bottom: 0; right: 0; width: 20px; height: 20px; background-color: #2196f3; cursor: se-resize; border-radius: 0px; z-index: 1; } #hide-btn { height: 25px; width: auto; float: right; margin-right: 10px; background-color: #fff; border: 1px solid gray; border-radius: 5px; font-size: 12px; padding: 0 5px; font-family: 'fangsong'; cursor: pointer; } #hide-btn:hover { background-color: #4497fa; color: #fff; } #hide-notice-btn { height: 20px; line-height: 20px; width: auto; background-color: #fff; border: 1px solid gray; border-radius: 3px; font-size: 12px; padding: 0 5px; font-family: 'fangsong'; cursor: pointer; float: right; } #hide-notice-btn:hover { background-color: gray; color: #fff; } #hide-process-btn { height: 20px; line-height: 20px; width: auto; background-color: #fff; border: 1px solid gray; border-radius: 3px; font-size: 12px; padding: 0 5px; font-family: 'fangsong'; cursor: pointer; float: right; } #hide-process-btn:hover { background-color: gray; color: #fff; } #hide-log-btn { height: 20px; line-height: 20px; width: auto; background-color: #fff; border: 1px solid gray; border-radius: 3px; font-size: 12px; padding: 0 5px; font-family: 'fangsong'; cursor: pointer; float: right; } #hide-log-btn:hover { background-color: gray; color: #fff; } #hide-set-btn { height: 20px; line-height: 20px; width: auto; background-color: #fff; border: 1px solid gray; border-radius: 3px; font-size: 12px; padding: 0 5px; font-family: 'fangsong'; cursor: pointer; float: right; } #hide-set-btn:hover { background-color: gray; color: #fff; } ` // 页面Html var popHtml = `
学习通助手[1.0.7]
公告
播放进度
执行日志
配置
[该邮箱地址用来登录app网站,该邮箱需要和网站注册邮箱保持一致,不可为空,填写完,点击保存,可在网站查看课程进度。]
[二维码:点击查看,微信扫码]
` // 初始化添加页面弹窗以及悬浮球 function initPopup() { // 添加CSS样式 GM_addStyle(popCSs); // 创建窗口元素 const myWindow = document.createElement("div"); myWindow.id = "my-window"; myWindow.innerHTML = popHtml; // 获取页面body元素 const body = document.getElementsByTagName("body")[0]; // 添加窗口和悬浮球到页面 body.appendChild(myWindow); // 绑定隐藏窗口按钮的click事件 const hideBtn = document.querySelector("#hide-btn"); hideBtn.addEventListener("click", hideWindow); // 绑定隐藏公告按钮的click事件 const hideNoticeBtn = document.querySelector("#hide-notice-btn"); hideNoticeBtn.addEventListener("click", hideNotice); // 绑定隐藏播放进度按钮的click事件 const hideProcessBtn = document.querySelector("#hide-process-btn"); hideProcessBtn.addEventListener("click", hideProcess); // 绑定隐藏日志按钮的click事件 const hideLogBtn = document.querySelector("#hide-log-btn"); hideLogBtn.addEventListener("click", hideLog); // 绑定隐藏日志按钮的click事件 const hideSetBtn = document.querySelector("#hide-set-btn"); hideSetBtn.addEventListener("click", hideSet); // 获取弹窗内容 var htmlContent = '
微信扫码微信扫码
'; // 点击链接显示弹窗 document.getElementById('Qcode').addEventListener('click', function() { showCustomPopup(htmlContent, 800, 400); }); // 获取头部元素 const header = myWindow.querySelector('.header'); // 处理移动事件 let isDragging = false; let mouseX = 0; let mouseY = 0; header.addEventListener('mousedown', function (e) { e.preventDefault(); isDragging = true; mouseX = e.clientX; mouseY = e.clientY; }); document.addEventListener('mousemove', function (e) { if (isDragging) { const deltaX = e.clientX - mouseX; const deltaY = e.clientY - mouseY; const newLeft = Math.min( Math.max(0, myWindow.offsetLeft + deltaX), window.innerWidth - myWindow.offsetWidth ); const newTop = Math.min( Math.max(0, myWindow.offsetTop + deltaY), window.innerHeight - myWindow.offsetHeight ); myWindow.style.left = newLeft + 'px'; myWindow.style.top = newTop + 'px'; mouseX = e.clientX; mouseY = e.clientY; } }); document.addEventListener('mouseup', function () { isDragging = false; }); document.getElementById('playbackRateSelect').addEventListener('change', function() { updatePlaybackRate(this.value); }); document.getElementById("playbackRateSelect").value = playbackRate; document.getElementById('volumeSelect').addEventListener('change', function() { updateVolume(this.value); }); document.getElementById("volumeSelect").value = volume; } // 当下拉框的值改变时,更新变量值 function updatePlaybackRate(val) { playbackRate = val GM_setValue("playbackRate", playbackRate); // 刷新页面 location.reload(); } // 当下拉框的值改变时,更新变量值 function updateVolume(val) { volume = val GM_setValue("volume", volume); // 刷新页面 location.reload(); } // 隐藏窗口函数 function hideWindow() { var myWindowContent = document.getElementById("my-window-content"); var showPop = myWindowContent.style.display if (showPop == '' || showPop == 'block') { myWindowContent.style.display = "none"; } else { myWindowContent.style.display = "block"; } } // 隐藏公告函数 function hideNotice() { var contentNotice = document.getElementById("content-notice"); var showPop = contentNotice.style.display if (showPop == '' || showPop == 'block') { contentNotice.style.display = "none"; } else { contentNotice.style.display = "block"; } } // 隐藏播放进度函数 function hideProcess() { var contentProcess = document.getElementById("content-process"); var showPop = contentProcess.style.display if (showPop == '' || showPop == 'block') { contentProcess.style.display = "none"; } else { contentProcess.style.display = "block"; } } // 隐藏日志函数 function hideLog() { var contentLog = document.getElementById("content-log"); var showPop = contentLog.style.display if (showPop == '' || showPop == 'block') { contentLog.style.display = "none"; } else { contentLog.style.display = "block"; } } // 隐藏设置函数 function hideSet() { var contentSet = document.getElementById("content-set"); var showPop = contentSet.style.display if (showPop == '' || showPop == 'block') { contentSet.style.display = "none"; } else { contentSet.style.display = "block"; } } function takeEmail() { // 获取邮箱输入框和保存按钮 const emailInput = document.getElementById("email-input"); const saveBtn = document.getElementById("save-btn"); // 当保存按钮被点击时 saveBtn.addEventListener("click", function() { // 获取输入的邮箱地址 const email = emailInput.value.trim(); // 检查邮箱地址是否有效 if (!isValidEmail(email)) { notify('请输入有效的邮箱地址!', 2500) return; } const url = 'https://www.sweek.top/api/checkEmailExists'; const data = { email }; if(email) { fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', // 声明请求主体的内容类型为 JSON }, body: JSON.stringify(data), // 将数据对象转换为 JSON 字符串并作为请求主体 }).then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); // 解析 JSON 响应数据 }).then(data => { if(data.exists){ // 将邮箱地址存储到本地存储中 GM_setValue("savedEmail", email); // 提示保存成功 notify('保存成功!课程信息将同步到该邮箱账号', 2500) } else { notify('邮箱账号尚未注册,请扫码前往留言信箱网站注册', 2500) } }).catch(error => { console.error('Error:', error); }); } }); // 页面加载时,尝试从本地存储中获取已保存的邮箱地址并反显到输入框中 const savedEmail = GM_getValue("savedEmail"); if (savedEmail) { emailInput.value = savedEmail; } } // 邮箱地址验证函数 function isValidEmail(email) { // 此处可以使用正则表达式等方式进行邮箱地址的验证 // 这里简单地判断邮箱是否包含 '@' 符号 return email.includes("@"); } // 封装页面组件方法 // 封装页面组件方法 // 封装页面组件方法 // 页面弹窗显示 function showCustomPopup(htmlContent, width, height) { // 创建弹窗容器 var popupContainer = document.createElement('div'); popupContainer.className = 'custom-popup-container'; // 设置弹窗容器样式 popupContainer.style.position = 'fixed'; popupContainer.style.top = '50px'; popupContainer.style.left = '0'; popupContainer.style.width = '100%'; popupContainer.style.height = 'calc(100% - 50px)'; popupContainer.style.display = 'flex'; popupContainer.style.justifyContent = 'center'; popupContainer.style.alignItems = 'center'; popupContainer.style.zIndex = '999999'; // 创建弹窗内容容器 var popupContent = document.createElement('div'); popupContent.className = 'custom-popup-content'; // 设置弹窗内容样式 popupContent.style.width = width + 'px'; popupContent.style.height = height + 'px'; popupContent.style.backgroundColor = '#fff'; popupContent.style.border = '1px solid #ccc'; popupContent.style.borderRadius = '5px'; popupContent.style.position = 'relative'; // 创建关闭按钮 var closeButton = document.createElement('button'); closeButton.innerHTML = '关闭'; closeButton.style.position = 'absolute'; closeButton.style.top = '5px'; closeButton.style.right = '5px'; closeButton.style.padding = '5px 10px'; closeButton.style.backgroundColor = '#ccc'; closeButton.style.border = 'none'; closeButton.style.borderRadius = '3px'; closeButton.style.cursor = 'pointer'; closeButton.style.fontFamily = 'Arial, sans-serif'; // 关闭按钮点击事件处理 closeButton.addEventListener('click', function() { popupContainer.remove(); }); // 设置弹窗内容 popupContent.innerHTML = htmlContent; // 将关闭按钮和弹窗内容添加到弹窗容器中 popupContent.appendChild(closeButton); popupContainer.appendChild(popupContent); // 将弹窗容器添加到页面中 document.body.appendChild(popupContainer); } // 页面通知提示 function notify(text, time) { // 创建通知元素 var notification = document.createElement('div'); notification.className = 'notification'; // 设置通知内容 notification.innerHTML = '

' + '学习通助手提示' + '

' + text + '

'; // 将通知添加到页面中 document.body.appendChild(notification); // 设置通知样式 notification.style.position = 'fixed'; notification.style.top = '50px'; notification.style.left = '-400px'; // 从左边弹出 notification.style.transform = 'translateY(-50%)'; // 垂直居中 notification.style.transition = 'left 0.5s ease-in-out'; // 添加过渡效果 notification.style.zIndex = '999999'; notification.style.backgroundColor = '#fff'; notification.style.border = '1px solid #ccc'; notification.style.padding = '10px'; notification.style.borderRadius = '5px'; notification.style.lineHeight = '25px'; // 等待一小段时间后,移动通知到左边 setTimeout(function() { notification.style.left = '20px'; // 移动到左边 }, 100); // 设置定时器,在指定时间后移除通知 setTimeout(function() { // 移动通知到左边以外 notification.style.left = '-400px'; // 等待过渡效果完成后,移除通知元素 setTimeout(function() { notification.remove(); }, 500); }, time); } // 添加执行日志 function addlog(str, color) { var _time = new Date().toLocaleTimeString() var contentLog = window.top.document.querySelector('.content-log'); var newContent = '

[' + _time + ']' + str + '


'; contentLog.innerHTML += newContent; // 将滚动条滚动到底部 contentLog.scrollTop = contentLog.scrollHeight; } /** 监听事件 */ document.addEventListener("redeal", () => { dealAnsEchelon(arrayEchelon); }); /** 初始化 */ function initAll() { // console.log('location.pathname:::+ ', location.pathname) if(location.pathname == '/mooc-ans/knowledge/cards') { addlog('正在获取当前页面的任务...'); const arrayAnsAll = document.querySelectorAll(".ans-attach-ct"); addlog(`当前页面任务数量为: ${Array.from(arrayAnsAll).length}`); const arrayAns = document.querySelectorAll('.ans-attach-ct:not(.ans-job-finished)'); const taskCount = arrayAns.length; // addlog(`找到的任务数量: ${taskCount}`); if (arrayAns && taskCount > 0) { try { const arrayType = getIframesType(arrayAns); console.log('任务类型数组:', arrayType); const arrayDocument = getAllIframesDocument(arrayAns); console.log('任务文档数组:', arrayDocument); arrayEchelon = distributeAns(arrayType, arrayDocument); // addlog(`当前页面待办任务数量为: ${arrayEchelon.length}`); // 触发处理任务的事件 document.dispatchEvent(dealEvent); } catch (error) { console.error("初始化过程中发生错误:", error); } } else { addlog("当前页面没有可处理的任务,直接跳过章节"); // 如果没有任务, skipChapter(); } } } // 获取任务属性 function getIframesType(arrayAns) { return Array.from(arrayAns) .map(ans => { const jsonStr = ans.querySelector("iframe")?.getAttribute("data"); if (!jsonStr) { console.warn("未找到 data 属性或 data 属性为空。"); return null; } try { const json = JSON.parse(jsonStr); // 根据需求获取任务类型 // 课程类型 if(json && json.type) { return json.type; } // 测试类型 if(json && json.worktype) { return json.worktype; } } catch (error) { console.warn("解析 JSON 失败:", error); return null; } }) .filter(type => type !== null); } // 获取任务 document function getAllIframesDocument(arrayAns) { return Array.from(arrayAns) .map(ans => ans.querySelector("iframe")?.contentWindow?.document) .filter(doc => doc !== undefined && doc !== null); } // 按任务属性映射处理函数 const handlerMap = { ".mp4": videoHandler, ".wmv": videoHandler, ".avi": videoHandler, ".mkv": videoHandler, ".flv": videoHandler, ".doc": pptxHandler, ".docx": pptxHandler, ".pptx": pptxHandler, ".pdf": pptxHandler, ".ppt": pptxHandler, ".mp3": audioHandler, ".wav": audioHandler }; // 按任务属性分配执行函数 function distributeAns(arrayType, arrayDocument) { return arrayType.map((type, index) => { const handler = handlerMap[type] || ignoreAns; return { document: arrayDocument[index], handler }; }); } // 处理单个任务 function dealSingleAns(singleAns) { if (singleAns && singleAns.handler && typeof singleAns.handler === 'function') { singleAns.handler(singleAns.document); } else { console.warn("无效的任务或处理函数。"); document.dispatchEvent(dealEvent); } } /** 工具函数 */ /** 工具函数 */ /** 工具函数 */ // 获取当前时间,年月日时分秒 function getCurrentDateTime() { var now = new Date(); var year = now.getFullYear(); var month = (now.getMonth() + 1).toString().padStart(2, '0'); // 月份从0开始,需要加1,并确保两位数格式 var day = now.getDate().toString().padStart(2, '0'); // 确保两位数格式 var hours = now.getHours().toString().padStart(2, '0'); // 确保两位数格式 var minutes = now.getMinutes().toString().padStart(2, '0'); // 确保两位数格式 var seconds = now.getSeconds().toString().padStart(2, '0'); // 确保两位数格式 return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } // 设置播放进度 function setVideoProcess(val1, val2, val3) { var _process = window.top.document.querySelector('#content-process'); var _time = getCurrentDateTime() var newContent = '

[' + _time + ']' + '


' + '播放进度:' + val1 + '


' + '视频长度:' + val2 + 's' + '/' +val3 + 's' + '

'; _process.innerHTML = newContent; } // 获取视频播放进度-定时监听页面内容进行下一步处理 function getVideoProgress() { // 同步课程进度 if(location.pathname == '/mycourse/studentstudy') { const emailInput = document.getElementById("email-input"); const email = emailInput.value.trim(); const url = 'https://www.sweek.top/api/checkEmailExists'; const data = { email }; if(email) { fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', // 声明请求主体的内容类型为 JSON }, body: JSON.stringify(data), // 将数据对象转换为 JSON 字符串并作为请求主体 }).then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); // 解析 JSON 响应数据 }).then(data => { if(data.exists){ syncCourseData() } else { var _async_time = window.top.document.querySelector('#async-time'); var newContent = `[同步课程信息失败,邮箱未注册]`; _async_time.innerHTML = newContent; } }).catch(error => { console.error('Error:', error); }); } // 脚本运行过程中如果弹出弹窗,发现后关闭-10s执行一次 const jobFinishTip = document.querySelector(".jobFinishTip"); const nextChapter = document.querySelector(".nextChapter"); if (jobFinishTip) { const computedStyle = getComputedStyle(jobFinishTip); if (computedStyle.display !== 'none') { nextChapter.click() } } } } // 获取页面url function getURLInfo() { if(location.pathname == '/mycourse/studentstudy') { url = location.href // 获取问号后面的部分 var queryString = url.split('?')[1]; // 将查询字符串拆分为参数对 var queryParams = queryString.split('&'); // 创建一个对象来存储参数 var params = {}; // 遍历参数对,将它们存储在对象中 queryParams.forEach(function(queryParam) { var parts = queryParam.split('='); var key = decodeURIComponent(parts[0]); var value = decodeURIComponent(parts[1]); params[key] = value; }); chapterId = params['chapterId'] courseId = params['courseId'] GM_setValue("courseId", courseId); } } // 获取当前页面章节小节的所有分栏 function getSubChapter() { try { if(location.pathname == '/mycourse/studentstudy') { var subChapter = window.top.document.querySelector('#prev_tab'); if(subChapter) { currentChapterTabArr = subChapter.querySelectorAll('li'); currentChapterTabArr.forEach(function(item) { if(item.className === 'active') { currentChapterTabName = item.innerText } }) } } } catch (error) { console.error('An error occurred:', error); // location.reload(); // 刷新页面 } } // 获取课程所有章节节点数据 function getChapterCodeInfo() { if(location.pathname === '/mooc-ans/knowledge/cards') { var chapter = window.top.document.querySelectorAll('.posCatalog_select') chapterInfo = chapter allChapterName=[] chapterInfo.forEach(function(item) { allChapterName.push({ id: item.id, title: item.innerText, active: item.classList.contains('posCatalog_active') ? 1 : 0, ifTitle: item.classList.contains('firstLayer') ? 1 : 0, status: item.childNodes[3]?.className == 'icon_Completed prevTips' ? 1 : 0 }) if (item.classList.contains('posCatalog_active')) { currentChapterId = item.id GM_setValue("currentChapterId", currentChapterId); currentChapterName = item.innerText GM_setValue("currentChapterName", currentChapterName); } }); GM_setValue("chapterInfo", JSON.parse(JSON.stringify(allChapterName))); addlog('当前章节为' + currentChapterName, 'green') } } // 获取公告数据 function getBoard() { fetch('https://www.sweek.top/api/board') .then(response => response.json()) .then(data => { // 在这里处理接收到的数据 var notice = document.querySelector('#content-notice'); notice.innerHTML = data.text }) .catch(error => { // 在这里处理错误 console.error('Error:', error); }); } // 同步课程数据至数据库 function syncCourseData() { const url = 'https://www.sweek.top/api/insertOrUpdateCourse'; const email = GM_getValue("savedEmail") const course_name = GM_getValue("courseName") const current_chapter_id = GM_getValue("currentChapterId") const current_chapter_name = GM_getValue("currentChapterName") const course_id = GM_getValue("courseId") const process = document.querySelector('#content-process').innerHTML const chapter_info = GM_getValue("chapterInfo") var chapter = window.top.document.querySelectorAll('.posCatalog_select') allChapterName = [] chapter.forEach(function(item) { allChapterName.push({ id: item.id, title: item.innerText, active: item.classList.contains('posCatalog_active') ? 1 : 0, ifTitle: item.classList.contains('firstLayer') ? 1 : 0, status: item.childNodes[3]?.className == 'icon_Completed prevTips' ? 1 : 0 }) if (item.classList.contains('posCatalog_active')) { currentChapterId = item.id GM_setValue("currentChapterId", currentChapterId); currentChapterName = item.innerText GM_setValue("currentChapterName", currentChapterName); } }); const data = { email, course_id: course_id || '', course_name: course_name || '测试', chapter: JSON.stringify(allChapterName), current_chapter: current_chapter_id + ',' + current_chapter_name, process }; // 播放异常刷新页面 // if(process.includes("NaN")) { // location.reload(); // 刷新页面 // return // } if(email && process) { fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', // 声明请求主体的内容类型为 JSON }, body: JSON.stringify(data), // 将数据对象转换为 JSON 字符串并作为请求主体 }).then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); // 解析 JSON 响应数据 }).then(data => { var _async_time = window.top.document.querySelector('#async-time'); var _time = getCurrentDateTime() var newContent = `[同步时间:${_time}]`; _async_time.innerHTML = newContent; }).catch(error => { console.error('Error:', error); }); } } /** 执行函数 */ // 直接跳过 function skipChapter() { addlog("跳过章节"); const chapterNext = window.top.document.querySelector("#prevNextFocusNext"); if (chapterNext) { chapterNext.click(); } else { // console.warn("未找到 #prevNextFocusNext 元素。"); } setTimeout(() => { const tip = document.querySelector(".maskDiv.jobFinishTip.maskFadeOut"); if (tip) { const tipNextChapter = document.querySelector(".jb_btn.jb_btn_92.fr.fs14.nextChapter"); tipNextChapter?.click(); } else { // console.warn("未找到完成提示或下一章节按钮。"); } setTimeout(() => { initAll(); // 注意:这里不再立即调用 dealAnsEchelon,而是依靠事件触发 }, 5000); }, 2000); } // 忽略任务 function ignoreAns() { addlog("无法处理, 忽略任务"); setTimeout(() => { document.dispatchEvent(dealEvent); }, 1500); } // 处理视频 function videoHandler(idocument) { addlog("处理视频任务中..."); const video = idocument.querySelector("video"); const videoPlayButton = idocument.querySelector(".vjs-big-play-button"); if (!video) { // console.log("未找到视频元素。"); // document.dispatchEvent(dealEvent); return; } // 播放视频 videoPlayButton?.click(); // 监听视频暂停事件并在暂停时继续播放 const handlePause = () => { // console.log("视频暂停,自动恢复播放..."); videoPlayButton?.click(); // 如果检测到弹窗,则点击隐藏 const modalDialog = idocument.querySelector(".vjs-modal-dialog-content"); const closeButton = idocument.querySelector(".vjs-done-button"); const ariaHiddenValue = modalDialog.getAttribute("aria-hidden"); if (modalDialog && closeButton && !ariaHiddenValue) { setTimeout(() => { closeButton?.click(); // console.log('模块弹窗已隐藏...') }, 2000); } }; // 设置播放倍速(延迟设置,确保视频已加载完成) video.addEventListener('loadeddata', () => { // 设置音量 video.volume = volume; addlog(`已将视频音量调节为${volume*100}%`); // 设置倍速 video.playbackRate = playbackRate; addlog(`已将视频倍速调节为${playbackRate}X`); }); video.addEventListener("pause", handlePause); // 监听视频播放结束事件,并在结束时触发 dealEvent,并且移除暂停事件监听 video.addEventListener("ended", () => { document.dispatchEvent(dealEvent); video.removeEventListener("pause", handlePause); }, { once: true }); // 同步显示视频进度 video.addEventListener("timeupdate", function() { let currentTime = video.currentTime; // 当前播放时间(以秒为单位) let duration = video.duration; // 视频总时长(以秒为单位) let progress = (currentTime / duration) * 100; // 计算播放进度百分比 setVideoProcess(progress.toFixed(2) + '%', currentTime.toFixed(0), duration.toFixed(0)); // 设置视频播放进度显示 }); // 10秒之后如果还没播放,执行点击播放按钮 setTimeout(() => { if (video.paused && !video.ended) { videoPlayButton?.click(); addlog('由于程序出错未自动播放,现重新模拟点击播放按钮...'); } }, 10000); } // 处理 PPT & PDF function pptxHandler(idocument) { // notify('等待PPT/PDF加载完成...', 5000) addlog("处理 PPT/PDF 任务中..."); const iframe = idocument.querySelector("iframe"); if (!iframe) { // console.warn("未找到嵌入的 iframe 元素。"); document.dispatchEvent(dealEvent); return; } const sDocument = iframe.contentWindow?.document; if (!sDocument) { // console.warn("无法获取 PPT/PDF 的文档内容。"); document.dispatchEvent(dealEvent); return; } const finalHeight = sDocument.documentElement.scrollHeight; let currentHeight = 0; const scrollStep = 400; // 每次滚动的高度 const scrollInterval = 1000; // 滚动的时间间隔(毫秒) const timer = setInterval(() => { if (currentHeight >= finalHeight) { clearInterval(timer); document.dispatchEvent(dealEvent); return; } currentHeight += scrollStep; sDocument.defaultView.scrollTo(0, currentHeight); }, scrollInterval); } // 处理音频 function audioHandler(idocument) { addlog("处理音频任务中..."); const audio = idocument.querySelector("audio"); const audioPlayButton = idocument.querySelector(".vjs-play-control.vjs-control.vjs-button"); if (!audio) { console.warn("未找到音频元素。"); document.dispatchEvent(dealEvent); return; } // 播放音频 audioPlayButton?.click(); // 监听音频播放结束事件 audio.addEventListener("ended", () => { document.dispatchEvent(dealEvent); }, { once: true }); // 监听音频暂停事件并在暂停时继续播放 audio.addEventListener("pause", () => { // console.log("音频暂停,自动恢复播放..."); audioPlayButton?.click(); }); } /** 任务梯队顺序处理 */ function dealAnsEchelon(arrayEchelon) { const remainingTasks = arrayEchelon.length; addlog(`待处理任务数量为: ${remainingTasks}`); if (remainingTasks === 0) { skipChapter(); return; } const nextTask = arrayEchelon.shift(); try { dealSingleAns(nextTask); } catch (error) { console.error("处理任务时发生错误:", error); // 继续处理下一个任务 dealAnsEchelon(arrayEchelon); } } // 方法执行入口 (function () { // 进入学习通弹出提示 if(location.pathname == '/base') { notify('已进入学习通首页,请进入课程,选择需要学习的课程', 5000) } // 进入课程弹出提示 if(location.pathname == '/mooc2-ans/mycourse/stu') { courseName = window.top.document.querySelector('.classDl .colorDeep').getAttribute('title') GM_setValue("courseName", courseName); notify('已进入课程:' + courseName + ',请选择需要学习的章节', 5000) } // 初始化显示页面弹窗 if(location.pathname == '/mycourse/studentstudy') { initPopup() // 获取公告数据 getBoard() // 邮箱操作 takeEmail() } // 获取页面章节节点数据 getChapterCodeInfo() // 获取当前页面章节小节的所有分栏 getSubChapter() // 获取页面url信息 getURLInfo() // 定时打印视频播放进度-定时监听页面内容进行下一步处理 videoProgressId = setInterval(() => { getVideoProgress() }, 10000); /** 执行代码 */ setTimeout(() => { initAll(); // 不再直接调用 dealAnsEchelon,这将由 initAll 中的事件触发 }, 1500); })();