// ==UserScript==
// @name 江苏开放大学自动刷课脚本
// @namespace http://tampermonkey.net/
// @version 1.6
// @description 江苏开放大学相关视频自动学习自动看视频程序【可加速及自动下一页】
// @author 一心向善
// @match http://xuexi.jsou.cn/jxpt-web/student/*
// @match https://xuexi.jsou.cn/jxpt-web/student/*
// @grant unsafeWindow
// @grant GM_setValue
// @grant GM_getValue
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// ====== 状态 ======
var autoPlayEnabled = GM_getValue('autoPlayEnabled', true);
var autoNextEnabled = GM_getValue('autoNextEnabled', true);
var autoMuteEnabled = GM_getValue('autoMuteEnabled', true); // 默认静音
var speedValue = GM_getValue('speedValue', 2);
// ====== 自动静音(默认开启)======
function autoMuteVideo() {
// 立即尝试一次
(function tryMute() {
var v = document.querySelector('video');
if (v) {
if (autoMuteEnabled) v.muted = true;
v.setAttribute('muted', autoMuteEnabled ? 'muted' : '');
}
})();
// 持续兜底:防止平台/浏览器自动取消静音或 video 异步加载
setInterval(() => {
var v = document.querySelector('video');
if (v && autoMuteEnabled && !v.muted) v.muted = true;
}, 800);
}
// ====== 自动播放 ======
function autoPlayVideo() {
if (!autoPlayEnabled) return;
setInterval(() => {
var video = document.querySelector('video');
if (video && video.paused) video.play();
}, 1000);
}
// ====== 倍速 ======
function setSpeed(speed) {
speedValue = speed;
GM_setValue('speedValue', speed);
var video = document.querySelector('video');
if (video) video.playbackRate = speed;
// 更新按钮高亮
document.querySelectorAll('[data-speed]').forEach(function (btn) {
if (parseFloat(btn.getAttribute('data-speed')) === speed) {
btn.classList.add('speed-active');
} else {
btn.classList.remove('speed-active');
}
});
}
// ====== 自动下一节 ======
function autoNextPage() {
if (!autoNextEnabled) return;
setInterval(() => {
var video = document.querySelector('video');
if (video && video.ended) {
// 查找多种可能的"下一节"按钮
var nextBtn = document.querySelector('.next-activity')
|| document.querySelector('[title="下一节"]')
|| document.querySelector('a[href*="next"]');
if (!nextBtn) {
var links = document.querySelectorAll('a');
for (var i = 0; i < links.length; i++) {
if (links[i].textContent && links[i].textContent.indexOf('下一节') !== -1) {
nextBtn = links[i];
break;
}
}
}
if (nextBtn) {
setTimeout(() => nextBtn.click(), 1500);
} else {
setTimeout(() => window.location.reload(), 1500);
}
}
}, 2000);
}
// ====== 控制面板注入(全新样式)======
function InjectPanel() {
/* ---------- 外层容器 ---------- */
var panel = document.createElement('div');
panel.id = 'study-helper-panel';
panel.style.cssText = [
'position:fixed',
'right:28px',
'bottom:28px',
'z-index:99999',
'width:300px',
'padding:0',
'background:linear-gradient(160deg, rgba(30,27,75,0.92) 0%, rgba(49,46,129,0.88) 100%)',
'backdrop-filter:blur(14px)',
'-webkit-backdrop-filter:blur(14px)',
'border:1px solid rgba(139,92,246,0.35)',
'border-radius:18px',
'box-shadow:0 20px 50px rgba(79,70,229,0.25), 0 0 0 1px rgba(255,255,255,0.04) inset',
'font-family:"PingFang SC","Microsoft YaHei",-apple-system,BlinkMacSystemFont,sans-serif',
'font-size:13px',
'color:#E5E7EB',
'line-height:1.6',
'overflow:hidden',
'user-select:none'
].join(';');
/* ---------- 拖拽(DOM Level 0 事件模型,与脚本一致,适配油猴沙盒环境)---------- */
var drag = false, ox = 0, oy = 0, moved = false, movedX = 0, movedY = 0;
var DRAG_THRESHOLD = 5; // 像素:超过阈值判定为拖拽(避免松手误触发折叠)
/* ---------- 顶部彩色标题条(作为拖动手柄)---------- */
var header = document.createElement('div');
header.style.cssText = [
'background:linear-gradient(90deg,#6366F1 0%,#8B5CF6 50%,#A78BFA 100%)',
'padding:14px 18px',
'cursor:move',
'display:flex',
'align-items:center',
'justify-content:space-between',
'font-weight:600',
'font-size:14px',
'color:#fff',
'letter-spacing:0.5px'
].join(';');
var titleLeft = document.createElement('span');
titleLeft.innerHTML = '● 学习辅助面板';
header.appendChild(titleLeft);
// 折叠按钮(独立按钮,不走拖拽)
var toggleBtn = document.createElement('span');
toggleBtn.textContent = '—';
toggleBtn.style.cssText = 'cursor:pointer;opacity:0.85;font-size:18px;line-height:1;padding:0 4px;';
var collapsed = false;
var bodyWrap = null;
toggleBtn.onclick = function () {
// 若刚发生过真正的拖动,不响应这次 click(避免拖完误折叠)
var dx = Math.abs(movedX), dy = Math.abs(movedY);
if (dx > DRAG_THRESHOLD || dy > DRAG_THRESHOLD) return;
collapsed = !collapsed;
if (bodyWrap) {
bodyWrap.style.display = collapsed ? 'none' : 'block';
toggleBtn.textContent = collapsed ? '+' : '—';
}
};
header.appendChild(toggleBtn);
panel.appendChild(header);
// ========= 核心拖拽:DOM Level 0 赋值方式(脚本同款,兼容性最强) =========
// 作用于整个 header(标题条区域),用闭包直接引用当前的 panel / toggleBtn
header.onmousedown = function (e) {
var t = e && e.target;
// 点在折叠按钮及其子节点上 → 不进入拖拽
if (t && toggleBtn && (t === toggleBtn || toggleBtn.contains(t))) return;
e = e || window.event;
// 阻止浏览器默认拖拽(文本选中/图片拖动)
if (e.preventDefault) e.preventDefault(); else e.returnValue = false;
if (e.stopPropagation) e.stopPropagation();
drag = true;
moved = false;
movedX = 0;
movedY = 0;
var rect = panel.getBoundingClientRect();
// 在 mousedown 瞬间就把 right/bottom 定位切换成 left/top,并锁位,避免首次跳点
panel.style.right = 'auto';
panel.style.bottom = 'auto';
panel.style.left = rect.left + 'px';
panel.style.top = rect.top + 'px';
// 计算鼠标相对 panel 左上角的偏移量
ox = (e.clientX || (e.touches && e.touches[0] && e.touches[0].clientX) || 0) - rect.left;
oy = (e.clientY || (e.touches && e.touches[0] && e.touches[0].clientY) || 0) - rect.top;
// 全局 mousemove:直接覆盖 document.onmousemove(与脚本一致,沙盒环境可靠)
var prevMove = document.onmousemove;
document.onmousemove = function (ev) {
if (!drag) { if (prevMove) return prevMove.apply(this, arguments); }
ev = ev || window.event;
var cx = ev.clientX || (ev.touches && ev.touches[0] && ev.touches[0].clientX) || 0;
var cy = ev.clientY || (ev.touches && ev.touches[0] && ev.touches[0].clientY) || 0;
var nx = cx - ox;
var ny = cy - oy;
movedX = nx - rect.left;
movedY = ny - rect.top;
// 视口边界保护
var w = panel.offsetWidth || 300;
var h = panel.offsetHeight || 200;
var maxX = Math.max(0, (window.innerWidth || document.documentElement.clientWidth) - w);
var maxY = Math.max(0, (window.innerHeight || document.documentElement.clientHeight) - h);
if (nx < 0) nx = 0; else if (nx > maxX) nx = maxX;
if (ny < 0) ny = 0; else if (ny > maxY) ny = maxY;
panel.style.left = nx + 'px';
panel.style.top = ny + 'px';
moved = true;
if (ev.preventDefault) ev.preventDefault();
};
// 全局 mouseup:结束拖拽,恢复之前的 onmousemove(若有)
var prevUp = document.onmouseup;
document.onmouseup = function () {
drag = false;
document.onmousemove = prevMove || null;
document.onmouseup = prevUp || null;
};
};
/* ---------- 主体内容 ---------- */
bodyWrap = document.createElement('div');
bodyWrap.style.cssText = 'padding:16px 18px 18px;';
// === 区块:播放控制 ===
var playSection = document.createElement('div');
playSection.style.marginBottom = '16px';
var playTitle = document.createElement('div');
playTitle.style.cssText = 'display:flex;align-items:center;gap:6px;margin-bottom:10px;color:#A5B4FC;font-weight:500;font-size:12px;';
playTitle.innerHTML = '播放行为';
playSection.appendChild(playTitle);
// 开关 1:自动播放
var sw1 = document.createElement('label');
sw1.style.cssText = 'display:flex;align-items:center;justify-content:space-between;padding:8px 10px;background:rgba(255,255,255,0.04);border:1px solid rgba(255,255,255,0.06);border-radius:10px;margin-bottom:8px;cursor:pointer;transition:all .2s;';
sw1.innerHTML = '▶ 自动续播视频';
var c1 = document.createElement('input');
c1.type = 'checkbox';
c1.checked = autoPlayEnabled;
c1.style.cssText = 'appearance:none;-webkit-appearance:none;width:38px;height:20px;background:#475569;border-radius:999px;position:relative;outline:none;cursor:pointer;transition:all .25s;vertical-align:middle;';
// 自定义 checkbox 样式规则(通过 innerHTML style)
c1.addEventListener('change', function () {
autoPlayEnabled = c1.checked;
GM_setValue('autoPlayEnabled', c1.checked);
// 视觉反馈
});
sw1.appendChild(c1);
playSection.appendChild(sw1);
// 开关 2:自动下一节
var sw2 = document.createElement('label');
sw2.style.cssText = 'display:flex;align-items:center;justify-content:space-between;padding:8px 10px;background:rgba(255,255,255,0.04);border:1px solid rgba(255,255,255,0.06);border-radius:10px;cursor:pointer;transition:all .2s;';
sw2.innerHTML = '⏩ 播完自动进入下一节';
var c2 = document.createElement('input');
c2.type = 'checkbox';
c2.checked = autoNextEnabled;
c2.style.cssText = 'appearance:none;-webkit-appearance:none;width:38px;height:20px;background:#475569;border-radius:999px;position:relative;outline:none;cursor:pointer;transition:all .25s;vertical-align:middle;';
c2.addEventListener('change', function () {
autoNextEnabled = c2.checked;
GM_setValue('autoNextEnabled', c2.checked);
});
sw2.appendChild(c2);
playSection.appendChild(sw2);
// 开关 3:自动静音
var sw3 = document.createElement('label');
sw3.style.cssText = 'display:flex;align-items:center;justify-content:space-between;padding:8px 10px;background:rgba(255,255,255,0.04);border:1px solid rgba(255,255,255,0.06);border-radius:10px;margin-top:8px;cursor:pointer;transition:all .2s;';
sw3.innerHTML = '🔇 视频自动静音(默认开启)';
var c3 = document.createElement('input');
c3.type = 'checkbox';
c3.checked = autoMuteEnabled;
c3.style.cssText = 'appearance:none;-webkit-appearance:none;width:38px;height:20px;background:#475569;border-radius:999px;position:relative;outline:none;cursor:pointer;transition:all .25s;vertical-align:middle;';
c3.addEventListener('change', function () {
autoMuteEnabled = c3.checked;
GM_setValue('autoMuteEnabled', c3.checked);
// 立即同步到当前视频
var v = document.querySelector('video');
if (v) v.muted = autoMuteEnabled;
});
sw3.appendChild(c3);
playSection.appendChild(sw3);
bodyWrap.appendChild(playSection);
// === 区块:倍速 ===
var speedSection = document.createElement('div');
speedSection.style.marginBottom = '8px';
var speedTitle = document.createElement('div');
speedTitle.style.cssText = 'display:flex;align-items:center;gap:6px;margin-bottom:10px;color:#A5B4FC;font-weight:500;font-size:12px;';
speedTitle.innerHTML = '播放速度';
speedSection.appendChild(speedTitle);
var speedBar = document.createElement('div');
speedBar.style.cssText = 'display:grid;grid-template-columns:repeat(5,1fr);gap:6px;';
[0.5, 1.0, 1.25, 1.5, 2.0].forEach(function (s) {
var btn = document.createElement('button');
btn.textContent = s + 'x';
btn.setAttribute('data-speed', s);
var isActive = Math.abs(parseFloat(s) - speedValue) < 0.001;
if (isActive) btn.classList.add('speed-active');
btn.style.cssText = [
'padding:7px 0',
'border-radius:9px',
'border:1px solid rgba(139,92,246,0.35)',
'background:rgba(255,255,255,0.04)',
'color:#C7D2FE',
'cursor:pointer',
'font-size:12px',
'font-weight:500',
'transition:all .2s',
'outline:none'
].join(';');
btn.addEventListener('mouseenter', function () {
if (!btn.classList.contains('speed-active')) {
btn.style.background = 'rgba(139,92,246,0.2)';
btn.style.color = '#fff';
}
});
btn.addEventListener('mouseleave', function () {
if (!btn.classList.contains('speed-active')) {
btn.style.background = 'rgba(255,255,255,0.04)';
btn.style.color = '#C7D2FE';
}
});
btn.addEventListener('click', function () { setSpeed(s); });
speedBar.appendChild(btn);
});
speedSection.appendChild(speedBar);
bodyWrap.appendChild(speedSection);
// === 基础功能说明 ===
var statusBar = document.createElement('div');
statusBar.style.cssText = 'margin-top:14px;padding:10px 12px;background:rgba(99,102,241,0.1);border:1px dashed rgba(139,92,246,0.4);border-radius:10px;font-size:11.5px;color:#C4B5FD;line-height:1.8;';
statusBar.innerHTML = ''
+ '基础功能:
'
+ '1、播放完毕自动下一页
'
+ '2、倍数可自由调节,建议最大调节到2倍即可;
'
+ '3、答题及线上实验实践、文件题等进群:949193546 联系群主
'
+ '