// ==UserScript==
// @name 深圳终身学习平台自动刷课助手(完整版)
// @namespace https://github.com/cxcs
// @version 2.5.0
// @description 自动播放、静音、智能答题(试错直到正确)、自动跳转下一节,支持刷新恢复
// @author CxCS
// @match https://www.0755tt.com/*
// @tag 刷课
// ==/UserScript==
(function () {
'use strict';
// 防止重复注入
if (window.__GD_AUTO_SCRIPT_ACTIVE__) return;
window.__GD_AUTO_SCRIPT_ACTIVE__ = true;
// ---------- 状态变量 ----------
let isRunning = true; // 脚本运行开关
let hasAttemptedJump = false; // 防止重复跳转
let answering = false; // 答题锁,防止并发
const triedMap = new Map(); // 记录每道题已尝试的选项值
// ---------- 控制面板(UI) ----------
const panelContainer = document.createElement('div');
panelContainer.id = 'gd-auto-panel-container';
panelContainer.style.cssText = `
position: fixed;
top: 10px;
left: 10px;
z-index: 999999;
`;
const fullPanel = document.createElement('div');
fullPanel.id = 'gd-auto-full-panel';
fullPanel.innerHTML = `
深圳公需课助手
自动刷课 v2.5
自动播放·静音·答题·跳转
`;
const collapseButton = document.createElement('button');
collapseButton.id = 'gd-collapse-btn';
collapseButton.innerText = '⚙️';
collapseButton.style.cssText = `
width: 36px; height: 36px; border-radius: 50%; background: #2c3e50; color: white; border: none; cursor: pointer; box-shadow: 0 2px 6px rgba(0,0,0,0.3); font-size: 14px; display: none;
`;
panelContainer.appendChild(fullPanel);
panelContainer.appendChild(collapseButton);
document.body.appendChild(panelContainer);
const toggleBtn = fullPanel.querySelector('#gd-toggle');
const startBtn = fullPanel.querySelector('#gd-start');
const stopBtn = fullPanel.querySelector('#gd-stop');
let isCollapsed = false;
function updateButtons() {
startBtn.style.display = isRunning ? 'none' : 'block';
stopBtn.style.display = isRunning ? 'block' : 'none';
}
toggleBtn.onclick = () => {
isCollapsed = true;
fullPanel.style.display = 'none';
collapseButton.style.display = 'block';
};
collapseButton.onclick = () => {
isCollapsed = false;
collapseButton.style.display = 'none';
fullPanel.style.display = 'block';
};
startBtn.onclick = () => {
isRunning = true;
hasAttemptedJump = false;
answering = false;
triedMap.clear();
updateButtons();
console.log('[刷课助手] 已启动');
};
stopBtn.onclick = () => {
isRunning = false;
updateButtons();
console.log('[刷课助手] 已暂停');
};
updateButtons();
// ---------- 核心功能函数 ----------
/** 静音视频 */
function muteVideo() {
const video = document.querySelector('video');
if (video) {
video.muted = true;
video.volume = 0;
}
}
/** 强制播放(处理自动播放被阻止) */
function forcePlay() {
const video = document.querySelector('video');
if (!video) return;
video.muted = true;
video.volume = 0;
try {
const p = video.play();
if (p && typeof p.catch === 'function') {
p.catch(e => {
if (e.name !== 'NotAllowedError' && e.name !== 'AbortError') {
console.warn('[刷课助手] 播放失败:', e);
}
});
}
} catch (e) {
if (e.name !== 'NotAllowedError') console.warn('[刷课助手] play() 错误:', e);
}
}
/** 检测当前章节是否完成,并跳转下一节 */
function checkAndJump() {
if (!isRunning || hasAttemptedJump) return;
const currentItem = document.querySelector('.cus_chapter_item_active');
if (!currentItem) return;
const finishedSpan = currentItem.querySelector('.cus_duration_finished');
if (!finishedSpan) return;
console.log('[刷课助手] 当前章节已完成,尝试跳转下一节...');
hasAttemptedJump = true;
const allItems = Array.from(document.querySelectorAll('.cus_chapter_item'));
const currentIndex = allItems.indexOf(currentItem);
if (currentIndex === -1) return;
for (let i = currentIndex + 1; i < allItems.length; i++) {
const next = allItems[i];
const isFinished = next.querySelector('.cus_duration_finished') !== null;
const isActive = next.classList.contains('cus_chapter_item_active');
if (!isFinished && !isActive) {
console.log('[刷课助手] 找到下一未完成章节,点击跳转');
next.click();
setTimeout(() => { hasAttemptedJump = false; }, 5000);
return;
}
}
console.log('[刷课助手] 未找到后续未完成章节,可能全部完成');
setTimeout(() => { hasAttemptedJump = false; }, 300000);
}
/** 智能答题(带试错) */
function handleAnswerDialog() {
if (!isRunning || answering) return;
// 查找可见的答题弹窗(标题为“开始答题”)
const dialogs = document.querySelectorAll('.el-dialog');
let dialog = null;
for (let d of dialogs) {
if (d.offsetParent !== null) { // 真正可见
dialog = d;
break;
}
}
if (!dialog) return;
const titleEl = dialog.querySelector('.el-dialog__title');
if (!titleEl || !titleEl.textContent.includes('开始答题')) return;
// 提取题目
const questionEl = dialog.querySelector('.time_question_item');
if (!questionEl) return;
const questionText = questionEl.textContent.trim();
const questionKey = questionText;
// 获取选项
const radioGroup = dialog.querySelector('.el-radio-group');
if (!radioGroup) return;
const radios = radioGroup.querySelectorAll('.el-radio');
if (radios.length === 0) return;
// 读取选项值
const optionValues = [];
radios.forEach(radio => {
const input = radio.querySelector('input[type="radio"]');
if (input && input.value !== undefined) optionValues.push(input.value);
});
if (optionValues.length < 2) return;
// 已尝试列表
let tried = triedMap.get(questionKey) || [];
if (tried.length >= optionValues.length) {
triedMap.delete(questionKey);
tried = [];
}
// 选择策略:优先选 '1'(正确),若已尝试则选 '0',否则选未尝试的
let selectedValue = null;
if (optionValues.includes('1') && !tried.includes('1')) {
selectedValue = '1';
} else if (optionValues.includes('0') && !tried.includes('0')) {
selectedValue = '0';
} else {
for (let val of optionValues) {
if (!tried.includes(val)) {
selectedValue = val;
break;
}
}
}
if (!selectedValue) {
triedMap.delete(questionKey);
selectedValue = optionValues[0];
}
// 选中 radio
let targetRadio = null;
radios.forEach(radio => {
const input = radio.querySelector('input[type="radio"]');
if (input && input.value === selectedValue) targetRadio = radio;
});
if (!targetRadio) return;
const inputEl = targetRadio.querySelector('input[type="radio"]');
if (!inputEl.checked) {
inputEl.checked = true;
inputEl.dispatchEvent(new Event('change', { bubbles: true }));
inputEl.dispatchEvent(new Event('click', { bubbles: true }));
}
// 查找确定按钮
let confirmBtn = dialog.querySelector('.el-dialog__footer .el-button--primary');
if (!confirmBtn) {
const buttons = dialog.querySelectorAll('button, .el-button');
for (let btn of buttons) {
if (btn.textContent.trim().includes('确定')) {
confirmBtn = btn;
break;
}
}
}
if (!confirmBtn) return;
// 锁定并提交
answering = true;
confirmBtn.click();
confirmBtn.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
confirmBtn.dispatchEvent(new MouseEvent('mouseup', { bubbles: true }));
// 记录本次尝试
const currentTried = triedMap.get(questionKey) || [];
if (!currentTried.includes(selectedValue)) {
currentTried.push(selectedValue);
triedMap.set(questionKey, currentTried);
}
// 等待 3.5 秒后检查弹窗是否仍可见
setTimeout(() => {
if (dialog.offsetParent !== null) {
// 弹窗仍在 → 答错,重试
console.log('[刷课助手] 答错,切换选项重试');
answering = false;
setTimeout(() => { handleAnswerDialog(); }, 500);
} else {
// 弹窗关闭 → 答题成功
console.log('[刷课助手] 答题正确');
triedMap.delete(questionKey);
answering = false;
hasAttemptedJump = false; // 重置跳转标志
}
}, 3500);
}
/** 关闭其他通用弹窗(如提示框) */
function closeDialogs() {
const confirmBtn = document.querySelector('.messager-button .l-btn, .layui-layer-btn a, .modal-footer button');
if (confirmBtn && confirmBtn.offsetParent && /确定|关闭|知道了/i.test(confirmBtn.innerText)) {
confirmBtn.click();
return true;
}
return false;
}
// ---------- 启动初始任务 ----------
setTimeout(muteVideo, 3000);
setTimeout(forcePlay, 1000);
// ---------- 主循环(每秒执行) ----------
setInterval(() => {
if (!isRunning) return;
forcePlay();
handleAnswerDialog();
checkAndJump();
closeDialogs();
}, 1500);
// ---------- 保持页面活跃(每5秒派发事件) ----------
setInterval(() => {
if (!isRunning) return;
['mousemove', 'mousedown', 'mouseup', 'keydown', 'click'].forEach(type => {
document.dispatchEvent(new Event(type, { bubbles: true, cancelable: true }));
});
window.focus();
}, 5000);
console.log('[刷课助手] 脚本已加载,开始自动刷课');
})();