// ==UserScript==
// @name 江西智慧教育平台-教师培训-继续教育刷课助手(www.jx.smartedu.cn)
// @namespace http://tampermonkey.net/
// @version 1.0
// @description 江西智慧教育平台全自动刷课助手,支持手动加速、批量秒过、弹窗屏蔽,客服微信wkds995
// @author 晓晓
// @match *://*.jx.smartedu.cn/*
// @grant GM_getValue
// @grant GM_setValue
// @run-at document-start
// @license MIT
// ==/UserScript==
(function() {
'use strict';
console.log('[国家智慧教育平台刷课助手 v1.0] 启动');
(function(){
function injectStyles() {
if (document.getElementById('xx-popup-styles')) return;
var s = document.createElement('style');
s.id = 'xx-popup-styles';
s.textContent = [
'.xx-mask{position:fixed;inset:0;background:rgba(0,0,0,0.75);z-index:99999998;display:flex;align-items:center;justify-content:center;}',
'.xx-box{background:#181c2b;border-radius:16px;border:1px solid rgba(255,255,255,0.12);padding:28px;color:#fff;font-family:system-ui,-apple-system,sans-serif;}',
'.xx-box h2{margin:0 0 18px;font-size:18px;text-align:center;border-bottom:1px solid rgba(255,255,255,0.1);padding-bottom:14px;color:#fff;}',
'.xx-content{line-height:1.8;font-size:14px;color:#e2e8f0;}',
'.xx-content p{margin:6px 0;}',
'.xx-footer{margin-top:22px;text-align:center;}',
'.xx-btn{padding:11px 36px;border:none;border-radius:10px;cursor:pointer;font-size:14px;font-weight:600;transition:opacity .2s;}',
'.xx-btn:hover{opacity:0.88;}',
'.xx-btn-primary{background:linear-gradient(135deg,#6a11cb,#2575fc);color:#fff;}',
'.xx-btn-secondary{background:rgba(255,255,255,0.08);color:#aaa;border:1px solid rgba(255,255,255,0.15);}',
'.xx-donate{width:360px;}',
'.xx-donate h3{margin:0 0 14px;font-size:16px;text-align:center;letter-spacing:.5px;color:#fff;}',
'.xx-wechat-label{text-align:center;font-size:13px;color:#c9d1d9;margin-bottom:10px;letter-spacing:1px;}',
'.xx-qr-wrap{width:220px;height:220px;background:#fff;border-radius:12px;margin:0 auto 12px;display:flex;align-items:center;justify-content:center;overflow:hidden;}',
'.xx-qr-wrap img{width:200px;height:200px;border-radius:8px;object-fit:cover;}',
'.xx-donate-desc{font-size:12px;color:#c9d1d9;margin-bottom:16px;text-align:center;line-height:1.6;}'
].join('');
document.head.appendChild(s);
}
function createGuidePopup(items, btnText, onClose) {
if (document.querySelector('.xx-guide-mask')) return;
btnText = btnText || '我已知晓';
onClose = onClose || function(){};
injectStyles();
var lines = items.map(function(item){
var icon = item.ok !== false ? '\u2705' : '\u26a0\ufe0f';
return '
' + icon + ' ' + item.text + '
';
}).join('');
var mask = document.createElement('div');
mask.className = 'xx-mask xx-guide-mask';
mask.innerHTML = [
'',
'
📖 脚本使用须知
',
'
' + lines + '
',
'
'
].join('');
document.body.appendChild(mask);
function close(){ mask.remove(); onClose(); }
mask.querySelector('.guide-close-btn').onclick = close;
mask.onclick = function(e){ if(e.target === mask) close(); };
}
function createDonatePopup(wxQrUrl, desc, onClose) {
if (document.querySelector('.xx-donate-mask')) return;
onClose = onClose || function(){};
injectStyles();
var descHtml = desc ? '' + desc + '
'
: '自愿打赏,您的支持是持续更新的动力
';
var mask = document.createElement('div');
mask.className = 'xx-mask xx-donate-mask';
mask.innerHTML = [
'',
'
\💰 感谢支持脚本持续维护更新
',
'
微信支付
',
'
',
descHtml,
'
'
].join('');
document.body.appendChild(mask);
function close(){ mask.remove(); onClose(); }
mask.querySelector('.donate-close-btn').onclick = close;
mask.onclick = function(e){ if(e.target === mask) close(); };
}
window.__popupTemplate = { guide: createGuidePopup, donate: createDonatePopup };
})();
// ===================== 核心功能代码 =====================
const bypassRestrictions = () => {
Object.defineProperty(document, 'visibilityState', { value: 'visible', writable: false });
Object.defineProperty(document, 'hidden', { value: false, writable: false });
const stopProp = e => e.stopImmediatePropagation();
window.addEventListener('visibilitychange', stopProp, true);
window.addEventListener('blur', stopProp, true);
window.addEventListener('seeking', stopProp, true);
window.addEventListener('seeked', stopProp, true);
};
bypassRestrictions();
const sleep = ms => new Promise(r => setTimeout(r, ms));
function getRoot() {
const head = document.querySelector('micro-app-head, #micro-app-head');
if (head && head.shadowRoot) return head.shadowRoot;
const micro = document.querySelector('micro-app');
if (micro && micro.shadowRoot) {
const inner = micro.shadowRoot.querySelector('micro-app-head, #micro-app-head');
return inner?.shadowRoot || micro.shadowRoot;
}
return document;
}
function closePopups() {
document.querySelectorAll('button, div, span, i, a').forEach(el => {
const text = el.innerText?.trim() || '';
const cls = el.className?.baseVal || el.className || '';
if (/关闭|取消|知道了|确定|继续|重播|再播|倍速|暂停学习|close|cancel/i.test(text) ||
/el-message-box__close|el-dialog__close|vjs-close-button|close-btn/i.test(cls)) {
if (el.offsetWidth > 0) el.click();
}
});
['.el-message-box__wrapper', '.el-dialog__wrapper', '.vjs-modal-dialog', '.course-video-reload', '.speed-popup',
'[class*="dialog"]', '[class*="modal"]'].forEach(sel => {
document.querySelectorAll(sel).forEach(el => {
if (getComputedStyle(el).display !== 'none') {
el.style.display = 'none';
const closeBtn = el.querySelector('[class*="close"]');
if (closeBtn) closeBtn.click();
}
});
});
}
function startPopupObserver() {
const observer = new MutationObserver(mutations => {
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
if (node.nodeType === 1) {
if (node.matches?.('.el-message-box__wrapper, .el-dialog__wrapper, .vjs-modal-dialog, .course-video-reload, .speed-popup, [class*="dialog"], [class*="modal"]')) {
node.style.display = 'none';
closePopups();
}
if (node.querySelectorAll) {
node.querySelectorAll('.el-message-box__wrapper, .el-dialog__wrapper, .vjs-modal-dialog, .course-video-reload, .speed-popup, [class*="dialog"], [class*="modal"]').forEach(p => {
p.style.display = 'none';
closePopups();
});
}
}
}
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
function isIconFinished(icon) {
return icon && icon.classList.contains('icon_checkbox_fill');
}
function maintainVideoSettings(video) {
if (!video) return;
if (video.muted !== true) video.muted = true;
if (video.playbackRate !== 16.0) video.playbackRate = 16.0;
if (video.paused && !video.ended) video.play().catch(() => {});
if (!video._pauseIntercepted) {
video.pause = function() {
if (video.currentTime < video.duration - 0.5) return;
HTMLMediaElement.prototype.pause.apply(this, arguments);
};
video._pauseIntercepted = true;
}
}
const initExtremeController = () => {
let loopTimer = null;
let isNextTriggered = false;
const checkIsItemFinished = () => {
const activeItem = document.querySelector('.active, .is-active, .playing, .current, li[class*="active"], div[class*="active"]');
if (!activeItem) return false;
const icon = activeItem.querySelector('i.icon_checkbox_linear, i.icon_checkbox_fill');
if (icon && icon.classList.contains('icon_checkbox_fill')) return true;
if (activeItem.classList.contains('complete') || activeItem.classList.contains('finished')) return true;
return false;
};
const doInstantPass = () => {
const video = document.querySelector('video');
if (!video) return;
video.muted = true;
if (video.playbackRate !== 16.0) video.playbackRate = 16.0;
if (video.duration && video.currentTime < video.duration - 0.8) {
video.currentTime = video.duration - 0.5;
}
if (video.paused) video.play().catch(() => {});
if (!video.hasPauseIntercepted) {
video.pause = function() {
if (video.currentTime < video.duration - 1) return;
HTMLMediaElement.prototype.pause.apply(this, arguments);
};
video.hasPauseIntercepted = true;
}
closePopups();
if (!isNextTriggered && checkIsItemFinished()) {
console.log("✅ 识别完成标记,2秒后下一节");
isNextTriggered = true;
setTimeout(() => {
playNextVideo();
isNextTriggered = false;
}, 2000);
}
};
const clickPopups = () => {
const popupTexts = ["继续学习", "确定", "我知道了", "继续", "确认"];
document.querySelectorAll('button, div, span, a').forEach(el => {
if (popupTexts.includes(el.innerText.trim()) && el.offsetWidth > 0) el.click();
});
};
const playNextVideo = () => {
const activeItem = document.querySelector('.active, .is-active, .playing, .current');
if (activeItem) {
const allList = Array.from(document.querySelectorAll('.video-item, .lesson-item, li, div[class*="item"]'));
const curIdx = allList.indexOf(activeItem);
if (curIdx !== -1 && curIdx + 1 < allList.length) {
allList[curIdx + 1].click();
return;
}
}
const nextKeywords = ["下一节", "下一课", "下一集", "下一页"];
const allButtons = document.querySelectorAll('button, a, div, span');
for (let btn of allButtons) {
if (nextKeywords.some(kw => btn.innerText.includes(kw)) && btn.offsetWidth > 0) {
btn.click();
break;
}
}
};
if (loopTimer) clearInterval(loopTimer);
loopTimer = setInterval(() => {
doInstantPass();
clickPopups();
}, 1500);
};
async function expandAll() {
const root = getRoot();
const collapsed = root.querySelectorAll('.fish-collapse-item:not(.fish-collapse-item-active), .el-collapse-item:not(.is-active)');
for (const item of collapsed) {
const header = item.querySelector('.fish-collapse-item__header, .fish-collapse-header, .el-collapse-item__header, [class*="collapse-header"]');
if (header) header.click();
await sleep(400);
}
if (!document.getElementById('expand-style')) {
const style = document.createElement('style');
style.id = 'expand-style';
style.textContent = '.fish-collapse-item__wrap, .el-collapse-item__wrap { display:block!important; height:auto!important; }';
document.head.appendChild(style);
}
}
function getVideoItems() {
const root = getRoot();
const icons = root.querySelectorAll('i.icon_checkbox_linear, i.icon_checkbox_fill');
const items = [];
icons.forEach(icon => {
const parent = icon.closest('div[class*="item"], li, div[class*="row"]') || icon.parentElement;
if (!parent) return;
const isFinished = isIconFinished(icon);
const text = parent.innerText.trim().split('\n')[0].substring(0, 60);
items.push({ el: parent, icon, isFinished, text });
});
return [...new Map(items.map(v => [v.el, v])).values()];
}
function clickItem(item) {
const clickable = item.el.querySelector('a, button, [onclick]') || item.el;
clickable.click();
}
async function batchPlayVideoAndWait(item) {
let video = null;
for (let i = 0; i < 30; i++) {
video = document.querySelector('video');
if (video) break;
await sleep(500);
}
if (!video) return false;
const maintInterval = setInterval(() => {
closePopups();
maintainVideoSettings(video);
}, 1000);
return new Promise(resolve => {
const onEnded = () => {
clearInterval(maintInterval);
video.removeEventListener('ended', onEnded);
let tries = 0;
const check = setInterval(() => {
closePopups();
if (isIconFinished(item.icon) || ++tries >= 6) {
clearInterval(check);
resolve(true);
}
}, 500);
};
video.addEventListener('ended', onEnded);
setTimeout(() => {
clearInterval(maintInterval);
video.removeEventListener('ended', onEnded);
resolve(false);
}, 600000);
});
}
let batchRunning = false;
let batchPaused = false;
let batchSignal = { running: false };
async function batchLoop() {
setBatchStatus('扫描目录...');
await expandAll();
const items = getVideoItems();
const unfinished = items.filter(i => !i.isFinished);
if (unfinished.length === 0) {
setBatchStatus('所有课程已完成');
batchRunning = false;
batchSignal.running = false;
updateBatchButton(false);
return;
}
let i = 0;
while (i < unfinished.length && batchSignal.running) {
while (batchPaused && batchSignal.running) {
await sleep(500);
}
if (!batchSignal.running) break;
const item = unfinished[i];
setBatchStatus(`▶ ${item.text} (${i+1}/${unfinished.length})`);
clickItem(item);
await sleep(2000);
await batchPlayVideoAndWait(item);
await sleep(3000);
i++;
}
setBatchStatus('批量完成');
batchRunning = false;
batchSignal.running = false;
updateBatchButton(false);
}
function startBatch() {
if (batchRunning) {
batchPaused = !batchPaused;
setBatchStatus(batchPaused ? '已暂停' : '继续中...');
updateBatchButton(batchRunning && !batchPaused);
return;
}
batchRunning = true;
batchPaused = false;
batchSignal.running = true;
updateBatchButton(true);
batchLoop();
}
function stopBatch() {
batchSignal.running = false;
batchRunning = false;
batchPaused = false;
setBatchStatus('批量已停止');
}
let manualRunning = false;
let manualPaused = false;
let manualInterval = null;
let manualResolve = null;
async function manualLoop() {
let video = document.querySelector('video');
if (!video) {
setManualStatus('未找到视频');
manualRunning = false;
updateManualButton(false);
return;
}
manualInterval = setInterval(() => {
if (!manualPaused) {
closePopups();
maintainVideoSettings(video);
}
}, 1000);
return new Promise(resolve => {
manualResolve = resolve;
const onEnded = () => {
clearInterval(manualInterval);
video.removeEventListener('ended', onEnded);
setManualStatus('手动加速完成');
manualRunning = false;
updateManualButton(false);
resolve();
};
video.addEventListener('ended', onEnded);
setTimeout(() => {
clearInterval(manualInterval);
video.removeEventListener('ended', onEnded);
setManualStatus('超时停止');
manualRunning = false;
updateManualButton(false);
resolve();
}, 600000);
});
}
function startManual() {
if (manualRunning) {
manualPaused = !manualPaused;
setManualStatus(manualPaused ? '已暂停' : '继续加速中...');
updateManualButton(manualRunning && !manualPaused);
return;
}
manualRunning = true;
manualPaused = false;
updateManualButton(true);
manualLoop();
}
function stopManual() {
if (manualInterval) clearInterval(manualInterval);
if (manualResolve) manualResolve();
manualRunning = false;
manualPaused = false;
setManualStatus('已停止');
}
let statusDom, batchStatusDom, manualStatusDom;
let batchBtn, manualBtn;
function setStatus(msg) {
if (statusDom) statusDom.innerText = msg;
}
function setBatchStatus(msg) {
if (batchStatusDom) batchStatusDom.innerText = msg;
}
function setManualStatus(msg) {
if (manualStatusDom) manualStatusDom.innerText = msg;
}
function updateBatchButton(active) {
if (!batchBtn) return;
if (!batchRunning) {
batchBtn.textContent = '🚀 开始批量秒过';
batchBtn.style.background = 'linear-gradient(135deg, #6a11cb, #2575fc)';
} else if (batchPaused) {
batchBtn.textContent = '▶ 继续批量秒过';
batchBtn.style.background = 'linear-gradient(135deg, #f39c12, #e67e22)';
} else {
batchBtn.textContent = '⏸ 暂停批量秒过';
batchBtn.style.background = 'linear-gradient(135deg, #e74c3c, #c0392b)';
}
}
function updateManualButton(active) {
if (!manualBtn) return;
if (!manualRunning) {
manualBtn.textContent = '🎯 开始手动加速';
manualBtn.style.background = 'linear-gradient(135deg, #6a11cb, #2575fc)';
} else if (manualPaused) {
manualBtn.textContent = '▶ 继续手动加速';
manualBtn.style.background = 'linear-gradient(135deg, #f39c12, #e67e22)';
} else {
manualBtn.textContent = '⏸ 暂停手动加速';
manualBtn.style.background = 'linear-gradient(135deg, #e74c3c, #c0392b)';
}
}
function createUI() {
if (document.getElementById('master-panel')) return;
const style = document.createElement('style');
style.textContent = `
.master-panel {
background: rgba(18, 22, 40, 0.85);
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
border: 1px solid rgba(255, 255, 255, 0.15);
border-radius: 24px;
color: #fff;
font-family: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;
box-shadow: 0 30px 50px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.05) inset;
padding: 24px;
width: 320px;
position: fixed;
z-index: 999999;
left: 24px;
top: 100px;
transition: all 0.2s ease;
}
.master-panel:hover {
border-color: rgba(255, 255, 255, 0.25);
box-shadow: 0 35px 60px rgba(0, 0, 0, 0.7), 0 0 0 1px rgba(255, 255, 255, 0.08) inset;
}
.master-title {
font-size: 18px;
font-weight: 700;
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 10px;
}
.master-title::before {
content: '';
width: 4px;
height: 22px;
background: linear-gradient(180deg, #6a11cb, #2575fc);
border-radius: 2px;
}
.master-btn {
background: linear-gradient(135deg, #6a11cb, #2575fc);
border: none;
border-radius: 14px;
color: white;
padding: 14px 18px;
font-weight: 600;
cursor: pointer;
width: 100%;
margin-bottom: 12px;
font-size: 13px;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
letter-spacing: 0.3px;
position: relative;
overflow: hidden;
}
.master-btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px rgba(37, 117, 252, 0.4);
}
.master-btn:active {
transform: translateY(0px);
}
.status-line {
font-size: 11px;
color: #a0b4cc;
margin-top: 10px;
word-break: break-all;
padding: 8px 12px;
background: rgba(255,255,255,0.05);
border-radius: 8px;
line-height: 1.4;
}
.auto-indicator {
display: inline-flex;
align-items: center;
gap: 4px;
background: rgba(39, 174, 96, 0.15);
color: #2ecc71;
padding: 2px 8px;
border-radius: 20px;
font-size: 10px;
font-weight: 600;
}
.donate-btn{
background:linear-gradient(135deg,#27ae60,#2ecc71) !important;
color:#fff !important;
}
.donate-btn:hover{
color:#ffdd66 !important;
}
`;
document.head.appendChild(style);
const html = `
⚡ 江西智慧教育
自动下一集已开启
客服微信:wkds995
`;
const panel = document.createElement('div');
panel.id = 'master-panel';
panel.innerHTML = html;
document.body.appendChild(panel);
manualStatusDom = document.getElementById('manual-status');
batchStatusDom = document.getElementById('batch-status');
manualBtn = document.getElementById('manual-btn');
batchBtn = document.getElementById('batch-btn');
const donateBtn = document.getElementById('donate-btn');
manualBtn.onclick = startManual;
batchBtn.onclick = startBatch;
donateBtn.onclick = ()=> window.__popupTemplate.donate('https://i.postimg.cc/QdhkjkFG/wxpay.png', '自愿打赏,您的支持是持续更新的动力');
manualBtn.addEventListener('dblclick', stopManual);
batchBtn.addEventListener('dblclick', stopBatch);
}
// ===================== 初始化入口 =====================
window.addEventListener('load', () => {
setTimeout(() => {
initExtremeController();
startPopupObserver();
// 标准弹窗:启动说明 → 关闭后显示控制面板
var T = window.__popupTemplate;
T.guide([
{ ok: true, text: '脚本说明:本脚本仅作为辅助,自行承担全部使用风险' },
{ ok: true, text: '速度控制:需自行判断,合理控制速度,规避风控' },
{ ok: true, text: '💰打赏按钮:自愿支持,不影响脚本任何功能' },
{ ok: false, text: '请保持页面前台运行,不要频繁刷新页面' }
], '我已知晓', createUI);
}, 2000);
});
let activeUrl = location.href;
setInterval(() => {
if (location.href !== activeUrl) {
activeUrl = location.href;
setTimeout(()=>{
initExtremeController();
// 页面内切换课程,不再连续弹出双弹窗,只运行挂机功能
}, 2000);
}
}, 1500);
})();