Greasy Fork is available in English.
自动静音、二倍速、失焦不断播、自动连播、自动答题(视频中非测验)。递归可开关,答题后彻底删除所有弹窗/遮罩,包括所有layui-layer-shade视频区域遮挡,保证学习区域无障碍。
当前为
// ==UserScript==
// @name UOOC 学习助手_szu_v2
// @namespace https://github.com/xiaochai-123
// @version 1.2
// @description 自动静音、二倍速、失焦不断播、自动连播、自动答题(视频中非测验)。递归可开关,答题后彻底删除所有弹窗/遮罩,包括所有layui-layer-shade视频区域遮挡,保证学习区域无障碍。
// @license GPL
// @match *://www.uooc.net.cn/*
// @grant none
// ==/UserScript==
(function () {
"use strict";
// 自动播放和倍速静音
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, 500);
// 强力弹窗和遮罩清理函数,无条件每0.8秒清理所有遮罩和弹窗
setInterval(() => {
// 清除所有layui弹窗遮罩
document.querySelectorAll('.layui-layer-shade').forEach(e => e.remove());
// 清除所有layui弹窗本体
document.querySelectorAll('.layui-layer.layui-layer-page').forEach(e => e.remove());
// 清除视频区域遮罩
document.querySelectorAll('.vjs-mask').forEach(e => e.remove());
// 清理答题内容被拉到视频下方
let quizDom = document.querySelector(".smallTest-view");
if (quizDom && quizDom.offsetTop > 600) {
quizDom.style.display = "none";
}
// 可拓展其它遮罩类名,按需添加
}, 800);
// 自动答题
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")) {
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());
}
} catch (error) {
console.log("自动答题发生错误:", error);
}
} else {
lastQuizQuestion = null;
let answeredLayer = document.querySelector("#quizLayer.answered");
if (answeredLayer) answeredLayer.classList.remove("answered");
}
}
setInterval(autoAnswerQuiz, 500);
// ======= 递归连播开关和核心 =======
let autoRecursiveFlag = false;
let controlBtn = document.createElement("button");
controlBtn.innerText = "递归刷课:关闭";
controlBtn.style.position = "fixed";
controlBtn.style.top = "140px";
controlBtn.style.right = "30px";
controlBtn.style.zIndex = "9999";
controlBtn.style.background = "#00796b";
controlBtn.style.color = "#fff";
controlBtn.style.border = "none";
controlBtn.style.padding = "11px 22px";
controlBtn.style.borderRadius = "8px";
controlBtn.style.cursor = "pointer";
controlBtn.style.boxShadow = "0 2px 12px rgba(0,0,0,0.18)";
controlBtn.style.userSelect = "none";
controlBtn.onclick = function () {
autoRecursiveFlag = !autoRecursiveFlag;
controlBtn.innerText = "递归上课:" + (autoRecursiveFlag ? "开启" : "关闭");
if (autoRecursiveFlag) {
startUltimateCourseRush();
}
};
document.body.appendChild(controlBtn);
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
function clearShader() {
document.querySelectorAll("div.layui-layer-shade").forEach(shader => shader.remove());
document.querySelectorAll('.vjs-mask').forEach(e => e.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();
setTimeout(() => {
const video = document.getElementById('player_html5_api');
if (video) {
video.muted = true;
video.playbackRate = 2;
video.play();
}
}, 1000);
return true;
}
return false;
}
function waitForVideoCompletion() {
return new Promise(resolve => {
const video = document.getElementById('player_html5_api');
if (!video) {
resolve();
return;
}
video._recursiveResolve = resolve;
video.onended = function() {
setTimeout(() => {
if (video._recursiveResolve) {
video._recursiveResolve();
}
}, 1500);
};
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();
}
}, 500);
});
}
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;
}
for (let i = startIndex; i < chapters.length; i++) {
await checkActive(chapters[i]);
}
}
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(500);
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();
}
$(document).ready(function () {
setTimeout(() => { if (autoRecursiveFlag) startUltimateCourseRush(); }, 1000);
setInterval(async function () {
if (autoRecursiveFlag) {
const video = document.getElementById('player_html5_api');
if ((!video || video.ended) && !document.querySelector(".basic.active")) {
await startUltimateCourseRush();
}
}
}, 800);
setInterval(bindVideoEnded, 800);
});
function bindVideoEnded() {
const video = document.getElementById('player_html5_api');
if (video && !video._autoNextBound) {
video._autoNextBound = true;
video.onended = function () {
if (autoRecursiveFlag) {
if (!playNextVideoInChapter()) {
setTimeout(() => {startUltimateCourseRush();}, 1500);
}
}
};
}
}
})();