// ==UserScript== // @name UOOC 学习助手_szu_v2 // @namespace https://github.com/xiaochai-123 // @version 1.1 // @description 自动静音、二倍速、失焦不断播、自动连播、自动答题(视频中非测验)。跨章节递归自动播放可开关,学习好帮手。 // @license GPL // @match *://www.uooc.net.cn/* // @grant none // @downloadURL none // ==/UserScript== (function () { "use strict"; // ================= 新增递归开关UI ================= function initRecursiveControlUI() { if (document.getElementById('uooc-recursive-btn')) return; //防止重复 const uiBox = document.createElement('div'); uiBox.id = 'uooc-recursive-btn'; uiBox.style.position = 'fixed'; uiBox.style.right = '30px'; uiBox.style.bottom = '40px'; uiBox.style.zIndex = '9999'; uiBox.style.background = '#fff'; uiBox.style.border = '1px solid #eee'; uiBox.style.borderRadius = '8px'; uiBox.style.boxShadow = '0 2px 8px rgba(0,0,0,0.15)'; uiBox.style.padding = '8px 16px'; uiBox.style.userSelect = 'none'; uiBox.style.fontSize = '14px'; uiBox.style.color = '#222'; uiBox.innerHTML = ` 递归刷课 [已开启] `; document.body.appendChild(uiBox); const btn = document.getElementById('uooc-recursive-switch'); const statusSpan = document.getElementById('uooc-recursive-status'); // 切换递归刷课状态 btn.onclick = function () { autoRecursiveFlag = !autoRecursiveFlag; if (autoRecursiveFlag) { btn.style.background = "#4caf50"; statusSpan.textContent = "[已开启]"; statusSpan.style.color = "green"; // 立即尝试递归 setTimeout(() => { startUltimateCourseRush(); }, 100); } else { btn.style.background = "#aaa"; statusSpan.textContent = "[已关闭]"; statusSpan.style.color = "red"; } }; // 可拖动 let isDragging = false, startX, startY; uiBox.onmousedown = function (e) { isDragging = true; startX = e.clientX - uiBox.offsetLeft; startY = e.clientY - uiBox.offsetTop; document.onmousemove = function (e) { if (isDragging) { uiBox.style.right = "auto"; uiBox.style.bottom = "auto"; uiBox.style.left = Math.max(e.clientX - startX, 0) + "px"; uiBox.style.top = Math.max(e.clientY - startY, 0) + "px"; } }; document.onmouseup = function () { isDragging = false; document.onmousemove = null; document.onmouseup = null; }; }; } // ================= 自动播放、倍速、静音 ================= function keepPlaying() { const video = document.getElementById("player_html5_api"); if (video) { video.muted = true; video.playbackRate = 2; if (video.paused && !video.ended) video.play(); } const playBtn = document.querySelector(".vjs-big-play-button"); if (playBtn) playBtn.click(); } setInterval(keepPlaying, 200); // ================= 自动答题优化 ================= let lastQuizQuestion = null; function autoAnswerQuiz() { let quizLayer = document.querySelector("#quizLayer"); if (quizLayer && quizLayer.style.display !== "none") { try { let videoDiv = document.querySelector("div[uooc-video]"); if (!videoDiv) return; let source = videoDiv.getAttribute("source"); if (!source) return; let quizList = JSON.parse(source).quiz || []; let quizQuestionElem = document.querySelector(".smallTest-view .ti-q-c"); if (!quizQuestionElem) return; let quizQuestion = quizQuestionElem.innerHTML.trim(); if (lastQuizQuestion === quizQuestion && quizLayer.classList.contains("answered")) { autoCloseQuizLayer(quizLayer); return; } let quizIndex = quizList.findIndex(q => q.question === quizQuestion); if (quizIndex === -1) return; let quizAnswer = eval(quizList[quizIndex].answer); let quizOptions = quizLayer.querySelector("div.ti-alist"); if (quizOptions) { for (let ans of quizAnswer) { let labelIndex = ans.charCodeAt() - "A".charCodeAt(); let opt = quizOptions.children[labelIndex]; if (opt) opt.click(); } let btn = quizLayer.querySelector("button"); if (btn) btn.click(); quizLayer.classList.add("answered"); lastQuizQuestion = quizQuestion; console.log("自动答题已完成:", quizQuestion, quizAnswer.toString()); autoCloseQuizLayer(quizLayer); } } catch (error) { console.log("自动答题发生错误:", error); } } else { lastQuizQuestion = null; let answeredLayer = document.querySelector("#quizLayer.answered"); if (answeredLayer) answeredLayer.classList.remove("answered"); } } function autoCloseQuizLayer(quizLayer) { if (!quizLayer) return; let btnClose = quizLayer.querySelector(".layui-layer-btn0") || quizLayer.querySelector(".layui-layer-close") || quizLayer.querySelector(".layer-close") || quizLayer.querySelector("button[type=button]") || quizLayer.parentElement?.querySelector(".layui-layer-btn0"); if (btnClose) btnClose.click(); setTimeout(() => { if (quizLayer && quizLayer.style.display !== "none") { if (btnClose) btnClose.click(); } }, 500); } setInterval(autoAnswerQuiz, 500); // ================= 跨章节递归连播刷课核心(已整合连播功能) ================= function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function clearShader() { let shaders = document.querySelectorAll("div.layui-layer-shade"); shaders.forEach(shader => shader.remove()); } // 查找当前活跃的视频节点 function findCurrentVideoNode() { let current = document.querySelector('.basic.active'); if (current) return current; current = document.querySelector('.video-list li.current, .chapter-list li.current, .menu li.current, li.active, li.selected'); if (current) return current; return null; } // 查找当前章节的下一个视频节点 function findNextVideoInSameChapter(currentNode) { if (!currentNode) return null; // 找到当前章节的容器 let chapterContainer = currentNode.closest('ul, .chapter-list, .video-list'); if (!chapterContainer) return null; // 在当前章节内查找下一个视频节点 let allVideoNodes = Array.from(chapterContainer.querySelectorAll('li, .basic')); let currentIndex = allVideoNodes.indexOf(currentNode); if (currentIndex === -1 || currentIndex >= allVideoNodes.length - 1) { return null; // 已经是当前章节的最后一个视频 } // 查找下一个有效的视频节点 for (let i = currentIndex + 1; i < allVideoNodes.length; i++) { let nextNode = allVideoNodes[i]; if (nextNode.querySelector('.icon-video, span.icon-video') || nextNode.classList.contains('taskpoint') && !nextNode.innerText.includes("测验")) { return nextNode; } } return null; } // 播放下一个视频(同一章节内) function playNextVideoInChapter() { let current = findCurrentVideoNode(); let next = findNextVideoInSameChapter(current); if (next) { let clickTarget = next.querySelector('a') || next; clickTarget.click(); console.log('播放同一章节的下一个视频'); setTimeout(() => { const video = document.getElementById('player_html5_api'); if (video) { video.muted = true; video.playbackRate = 2; video.play(); } }, 300); // 加速 return true; // 成功找到并播放下一个视频 } // 本章节已无后续视频 return false; } // 修改后的等待视频播放完毕函数(加速递归:视频结束后只等待500毫秒) function waitForVideoCompletion() { return new Promise(resolve => { const video = document.getElementById('player_html5_api'); if (!video) { resolve(); return; } // 绑定结束事件 video._recursiveResolve = resolve; video.onended = function() { console.log('视频播放结束,等待0.5秒后继续'); setTimeout(() => { if (video._recursiveResolve) { video._recursiveResolve(); } }, 500); // 递归刷课加速 }; // 设置视频参数并播放 video.muted = true; video.playbackRate = 2; const playBtn = document.querySelector(".vjs-big-play-button"); if (playBtn) playBtn.click(); // 如果视频已经在播放,设置一个超时检查 setTimeout(() => { if (video.ended && video._recursiveResolve) { video._recursiveResolve(); } }, 200); }); } // 查找当前大章节点 function findCurrentChapter() { const currentVideoNode = findCurrentVideoNode(); if (!currentVideoNode) return null; // 向上查找当前大章 let node = currentVideoNode; while (node && node.parentElement) { if (node.parentElement.classList.contains('rank-1') || node.classList.contains('rank-1-item')) { return node; } node = node.parentElement; } return null; } // 从当前大章开始递归查找未完成内容 async function searchUncompleteFromCurrentChapter() { const catalogRoot = document.querySelector("ul.rank-1"); if (!catalogRoot) return; const chapters = Array.from(catalogRoot.children); const currentChapter = findCurrentChapter(); let startIndex = 0; if (currentChapter) { // 找到当前大章在章节列表中的位置 startIndex = chapters.indexOf(currentChapter); if (startIndex === -1) startIndex = 0; } console.log(`从第${startIndex + 1}个大章开始递归`); // 从当前大章开始遍历 for (let i = startIndex; i < chapters.length; i++) { const chapter = chapters[i]; await checkActive(chapter); } } // 检查并播放活跃章节 async function checkActive(catalog) { let children = catalog.children; let elem = catalog?.firstElementChild; if (elem && elem.classList.contains("uncomplete") && !elem.innerText.includes("测试")) { let iElement = elem.getElementsByTagName("i")[0]; if (iElement && iElement.classList.contains("icon-xiangxia")) { elem.click(); } await sleep(200); // 展开章节后递归更快 for (let i = 1; i < children.length; i++) { if (children[i].tagName === "DIV" && children[i]?.firstElementChild && !children[i].firstElementChild.classList.contains("complete")) { let spanElem = children[i].firstElementChild.children[1]; if (spanElem && spanElem.classList.contains("taskpoint") && !spanElem.innerText.includes("测验")) { // 点击播放当前视频 children[i].firstElementChild.click(); clearShader(); // 等待当前视频播放完毕 await waitForVideoCompletion(); // 播放同一章节的后续视频 while (playNextVideoInChapter()) { await waitForVideoCompletion(); } } } else if (children[i].tagName === "UL") { await searchUncomplete(children[i]); } } } } // 原有的递归函数(保持兼容) async function searchUncomplete(query) { let catalog = query.children; for (let i = 0; i < catalog.length; i++) { await checkActive(catalog[i]); } } // 启动递归播放 - 从当前大章开始 async function startUltimateCourseRush() { if (!autoRecursiveFlag) return; //加递归开关判断 await searchUncompleteFromCurrentChapter(); } let autoRecursiveFlag = true; // 默认开启,可被UI改动 // 主启动逻辑,检测章节播放结束并递归 $(document).ready(function () { initRecursiveControlUI(); setTimeout(() => { autoRecursiveFlag = true; startUltimateCourseRush(); }, 800); // 启动加速 // 每隔400ms检测是否需要递归继续刷课 setInterval(async function () { if (autoRecursiveFlag) { // 检测是否已经没有正在播放的视频且页面没有未完成内容 const video = document.getElementById('player_html5_api'); if ((!video || video.ended) && !document.querySelector(".basic.active")) { // 继续从当前大章开始递归查找下一个未完成章节 await startUltimateCourseRush(); } } }, 400); // 检测刷课加速 setInterval(bindVideoEnded, 400); // 连播检测加速 }); // 修复:绑定视频结束后跳到下一个章节的小节逻辑 function bindVideoEnded() { const video = document.getElementById('player_html5_api'); if (video && !video._autoNextBound) { video._autoNextBound = true; video.onended = function () { console.log('视频播放结束,检查是否有下一个视频'); if (!playNextVideoInChapter()) { // 如果没有下一个视频,允许递归到下一个小节 setTimeout(() => { if(autoRecursiveFlag){ startUltimateCourseRush(); } }, 500); // 连播结束递归加速 } }; } } })();