Greasy Fork is available in English.
自动静音、二倍速、失焦不断播、自动连播、自动答题(视频中非测验)。跨章节递归自动播放可开关,学习好帮手。
当前为
// ==UserScript==
// @name UOOC 学习助手_szu_v2
// @namespace https://github.com/xiaochai-123
// @version 1.1
// @description 自动静音、二倍速、失焦不断播、自动连播、自动答题(视频中非测验)。跨章节递归自动播放可开关,学习好帮手。
// @license GPL
// @match *://www.uooc.net.cn/*
// @grant 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 = `
<span>递归刷课</span>
<button id="uooc-recursive-switch" style="margin-left:12px; background:#4caf50; color:#fff; border:none; border-radius:5px; padding:4px 14px; cursor:pointer;">开启</button>
<span id="uooc-recursive-status" style="margin-left:8px;color:green;">[已开启]</span>
`;
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); // 连播结束递归加速
}
};
}
}
})();