// ==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 联系群主
' + '
' + '4、个人合作或教务处理加作者QQ:640105435' + '
'; bodyWrap.appendChild(statusBar); panel.appendChild(bodyWrap); /* ---------- 注入自定义开关(滑块)样式 ---------- */ var styleTag = document.createElement('style'); styleTag.textContent = [ '#study-helper-panel input[type="checkbox"]::before{content:"";position:absolute;width:14px;height:14px;background:#fff;border-radius:50%;top:3px;left:3px;transition:all .25s;box-shadow:0 1px 3px rgba(0,0,0,.3);}', '#study-helper-panel input[type="checkbox"]:checked{background:linear-gradient(90deg,#6366F1,#8B5CF6)!important;}', '#study-helper-panel input[type="checkbox"]:checked::before{left:21px;}', '#study-helper-panel label:hover{background:rgba(255,255,255,0.07)!important;}', '#study-helper-panel [data-speed].speed-active{background:linear-gradient(135deg,#6366F1 0%,#8B5CF6 100%)!important;color:#fff!important;border-color:transparent!important;box-shadow:0 4px 12px rgba(99,102,241,.35);}' ].join(''); document.head.appendChild(styleTag); document.body.appendChild(panel); } // ====== 主入口 ====== function MainRun() { if (location.href.indexOf('display') !== -1) { InjectPanel(); autoMuteVideo(); // 自动静音(先执行,尽早生效) autoPlayVideo(); autoNextPage(); // 延迟一点等 video 元素就绪再设置倍速 setTimeout(function () { setSpeed(speedValue); }, 500); // 兜底:若 video 后出现再设一次倍速 + 静音 var tryCnt = 0; var t = setInterval(function () { tryCnt++; var v = document.querySelector('video'); if (v) { if (v.playbackRate !== speedValue) v.playbackRate = speedValue; if (autoMuteEnabled && !v.muted) v.muted = true; } if (tryCnt >= 15) clearInterval(t); }, 1500); } } MainRun(); })();