// ==UserScript==
// @name 重庆人社|重庆继续教育|无报错控制台无报错+自动下一节
// @namespace http://tampermonkey.net/
// @version 1.5
// @description 仅指定域名生效,UI可拖动,视频最高15倍速,自动点下一节
// @author bka
// @match *://*.21tb.com/*
// @grant none
// @tag 21tb
// ==/UserScript==
(function() {
'use strict';
// 单例检查
if (document.getElementById("autoStudyUIContainer")) {
console.log('脚本已运行,无需重复注入');
return;
}
// 样式
const style = document.createElement('style');
style.textContent = `
#autoStudyUIContainer{
position:fixed;
top:70px;
right:15px;
z-index:99999999;
background:#fff;
border:1px solid #e5e7eb;
border-radius:10px;
padding:16px;
width:320px;
box-shadow:0 4px 20px rgba(0,0,0,0.15);
font-family:Microsoft YaHei,sans-serif;
user-select:none;
}
#uiDragHead{
text-align:center;
font-size:16px;
font-weight:bold;
color:#333;
margin:0 0 12px 0;
padding:4px 0;
cursor:move;
border-bottom:1px solid #eee;
}
.ui-item{
margin:12px 0;
font-size:14px;
color:#444;
}
#speedValue{
color:#f56c6c;
font-weight:bold;
margin:0 6px;
}
input[type="range"]{
width:180px;
margin:0 5px;
vertical-align:middle;
}
.btn-wrap{
text-align:center;
margin-top:15px;
}
.btn-wrap button{
padding:6px 12px;
margin:0 4px;
border:none;
border-radius:6px;
cursor:pointer;
font-size:13px;
transition:0.2s;
}
#startBtn{background:#67c23a;color:#fff;}
#stopBtn{background:#e6a23c;color:#fff;}
#closeBtn{background:#f56c6c;color:#fff;}
.btn-wrap button:hover{opacity:0.9;}
`;
document.head.appendChild(style);
// 悬浮UI
const uiBox = document.createElement('div');
uiBox.id = "autoStudyUIContainer";
uiBox.innerHTML = `
重庆继续教育无报错终极版
自动静音:
防页面休眠:
自动跳下一课:
视频倍速:
4.0倍
`;
document.body.appendChild(uiBox);
// 拖拽
const dragHead = document.getElementById('uiDragHead');
let isDrag = false;
let offsetX, offsetY;
dragHead.addEventListener('mousedown', (e) => {
isDrag = true;
offsetX = e.clientX - uiBox.getBoundingClientRect().left;
offsetY = e.clientY - uiBox.getBoundingClientRect().top;
uiBox.style.transition = 'none';
e.preventDefault();
});
document.addEventListener('mousemove', (e) => {
if (!isDrag) return;
let left = e.clientX - offsetX;
let top = e.clientY - offsetY;
const w = uiBox.offsetWidth, h = uiBox.offsetHeight;
left = Math.max(0, Math.min(left, window.innerWidth - w));
top = Math.max(0, Math.min(top, window.innerHeight - h));
uiBox.style.left = left + 'px';
uiBox.style.top = top + 'px';
});
document.addEventListener('mouseup', () => { isDrag = false; });
// ==================== 核心配置 ====================
let timer = null;
let isRunning = true;
let playSpeed = 4.0;
let wakeLock = null;
// 倍速
const speedRange = document.getElementById('speedRange');
const speedValue = document.getElementById('speedValue');
speedRange.addEventListener('input', () => {
playSpeed = parseFloat(speedRange.value);
speedValue.innerText = playSpeed.toFixed(1);
});
// 休眠
async function keepAwake() {
if (!document.getElementById('preventSleep').checked) return;
try { wakeLock = await navigator.wakeLock.request('screen'); } catch (e) {}
}
// 视频倍速 + 静音
function applyVideoConfig() {
document.querySelectorAll('video').forEach(v => {
v.playbackRate = playSpeed;
v.muted = document.getElementById('autoMute').checked;
});
}
// ==================== 修复:自动关闭完成弹窗(纯原生JS) ====================
function autoCloseFinishModal() {
const buttons = document.querySelectorAll('button, div[role="button"]');
for (const btn of buttons) {
if ((btn.innerText || '').trim() === '确定' && btn.offsetParent !== null) {
console.log("✅ 自动点击课程完成弹窗的「确定」按钮");
btn.click();
break;
}
}
}
// ==================== 你提供的 自动跳下一课 核心逻辑 ====================
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
const nextCourse = async (element) => {
if (!element || !element.innerText.includes('已完成')) return;
await sleep(1000);
const tmp = element.parentElement?.nextElementSibling;
const next_cap = element.parentElement?.parentElement?.parentElement?.nextElementSibling;
if (tmp) {
console.log("✅ 点击下一节");
tmp.click();
} else if (next_cap) {
console.log("✅ 点击下一章节");
next_cap.firstElementChild?.nextElementSibling?.firstElementChild?.click();
}
};
// 课程列表页:自动点击未完成课程(纯原生JS)
function autoStartUnfinishedCourse() {
// 先切换到「未完成」标签
const tabs = document.querySelectorAll('button, div[role="tab"]');
for (const tab of tabs) {
if ((tab.innerText || '').trim() === '未完成' && tab.offsetParent !== null) {
tab.click();
break;
}
}
// 找未完成课程卡片
const cards = document.querySelectorAll('div[class*="course"], div[class*="card"]');
for (const card of cards) {
if ((card.innerText || '').includes('未完成')) {
const img = card.querySelector('img');
if (img && img.offsetParent !== null) {
console.log("✅ 点击未完成课程卡片");
img.click();
return true;
}
}
}
return false;
}
// 定时检测课程状态
async function startAutoJump() {
if (!document.getElementById('autoJump').checked) return;
try {
const iframe = document.querySelector('.url-course-content')?.contentDocument;
if (!iframe) {
// 如果没有iframe,说明在课程列表页,直接自动点未完成课程
autoStartUnfinishedCourse();
return;
}
const active = iframe.querySelector('.active');
if (active) nextCourse(active);
} catch (e) {}
}
// ==================== 主循环 ====================
function mainLoop() {
autoCloseFinishModal(); // 先关弹窗
applyVideoConfig(); // 再设置倍速静音
startAutoJump(); // 再自动跳下一课/列表页
}
// 按钮
document.getElementById('startBtn').onclick = () => {
if (isRunning) return;
isRunning = true;
keepAwake();
timer = setInterval(mainLoop, 1000);
alert("✅ 启动成功:无报错版自动学习");
};
document.getElementById('stopBtn').onclick = () => {
isRunning = false;
clearInterval(timer);
if (wakeLock) wakeLock.release();
alert("⏸️ 已暂停");
};
document.getElementById('closeBtn').onclick = () => {
clearInterval(timer);
if (wakeLock) wakeLock.release();
uiBox.remove();
style.remove();
alert("❌ 已关闭");
};
// 启动
timer = setInterval(mainLoop, 1000);
keepAwake();
console.log("✅ 重庆继续教育无报错终极版加载完成,控制台无报错");
})();