// ==UserScript== // @name 江西专技学习网-江西师范大学-全自动倍速播放刷课助手(zjpt.jxnu.edu.cn) // @version 1.0.0 // @description 江西专技学习网(江西师范大学)专用版:倍速播放+静音+自动播放+记忆进度,兼容公需课/专业课所有视频 // @author 晓晓 // @match https://zjpt.jxnu.edu.cn/* // @match https://zjpt-web.jxnu.edu.cn/* // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @run-at document-end // @license MIT // ==/UserScript== (function () { 'use strict'; var SETTINGS_KEY = 'zjpt_speed_settings'; var defaults = { speed: 2, muted: true, autoplay: true, remember: true }; var S = Object.assign({}, defaults, GM_getValue(SETTINGS_KEY, {})); function save() { GM_setValue(SETTINGS_KEY, S); } // ==================== 工具 ==================== function $1(s, ctx) { return (ctx || document).querySelector(s); } function $A(s, ctx) { return Array.from((ctx || document).querySelectorAll(s)); } function log(msg) { var el = $1('#zjpt-log'); if (el) { var t = new Date().toLocaleTimeString('zh-CN', { hour12: false }); el.value += '[' + t + '] ' + msg + '\n'; el.scrollTop = el.scrollHeight; } console.log('[江西专技]', msg); } // 遍历shadow root function* getShadowRoots(root) { if (!root) return; var walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT); var node; while (node = walker.nextNode()) { if (node.shadowRoot) { yield node.shadowRoot; yield* getShadowRoots(node.shadowRoot); } } } function qsa(selector, ctx) { ctx = ctx || document; var r = $A(selector, ctx); for (var sr of getShadowRoots(ctx)) { r = r.concat($A(selector, sr)); } return r; } // ==================== 视频控制 ==================== function applyToAllVideos(action) { qsa('video').forEach(function(v) { try { action(v); } catch (e) {} }); $A('iframe').forEach(function(frame) { try { qsa('video', (frame.contentDocument || frame.contentWindow.document)).forEach(action); } catch (e) {} }); } function applySpeed(v) { if (v.playbackRate !== S.speed) v.playbackRate = S.speed; } function applyMuted(v) { if (v.muted !== S.muted) v.muted = S.muted; } function applyAutoplay(v) { if (S.autoplay && v.paused && v.readyState >= 3) v.play().catch(function(){}); } function applyAll() { applyToAllVideos(function(v) { applySpeed(v); applyMuted(v); applyAutoplay(v); }); } // 记忆进度 function saveProgress() { if (!S.remember) return; qsa('video').forEach(function(v) { if (v.duration > 5 && v.currentTime > 1) { var key = 'zjpt_prog_' + location.host + '_' + v.src; GM_setValue(key, v.currentTime); } }); } function restoreProgress() { if (!S.remember) return; applyToAllVideos(function(v) { var key = 'zjpt_prog_' + location.host + '_' + v.src; var t = GM_getValue(key, 0); if (t > 1 && t < v.duration - 3) { v.currentTime = t; log('\u8bb0\u5fc6\u8fdb\u5ea6\u6062\u590d: ' + Math.floor(t/60) + '\u5206' + (t%60).toFixed(0) + '\u79d2'); } }); } // ==================== UI面板 ==================== function createPanel() { if ($1('#zjpt-panel')) return; var el = document.createElement('div'); el.id = 'zjpt-panel'; el.style.cssText = [ 'position:fixed;top:20px;right:20px;z-index:999999;', 'background:linear-gradient(135deg,#1a1a2e,#16213e);', 'color:#e0e0e0;padding:14px 18px;border-radius:12px;', 'min-width:300px;box-shadow:0 8px 32px rgba(0,0,0,0.5);', 'font-family:"PingFang SC","Microsoft YaHei",sans-serif;', 'border:1px solid rgba(255,255,255,0.08);font-size:13px;' ].join(''); el.innerHTML = '
' + '📚' + '
江西专技学习网
' + '
● 运行中
' + '
' + '
倍速: ' + S.speed + 'x
' + '' + '
0.5x16x
' + '
' + '' + '' + '
' + '
' + '' + '
' + '
未检测到视频
' + '
' + '' + '
' + '
' + '💬 ' + 'wkds995' + ' 客服微信' + '
'; document.body.appendChild(el); // 倍速滑块 $1('#zjpt-speed').addEventListener('input', function () { S.speed = parseFloat(this.value); $1('#zjpt-speed-val').textContent = S.speed + 'x'; save(); applyToAllVideos(applySpeed); log('\u500d\u901f\u8c03\u6572: ' + S.speed + 'x'); }); // 静音 $1('#zjpt-muted-btn').addEventListener('click', function () { S.muted = !S.muted; this.style.background = S.muted ? '#ef4444' : '#374151'; this.innerHTML = S.muted ? '☕ 已静音' : '🔊 开启声音'; save(); applyToAllVideos(applyMuted); log(S.muted ? '\u5df2\u9759\u97f3' : '\u5f00\u542f\u58f0\u97f3'); }); // 自动播放 $1('#zjpt-ap-btn').addEventListener('click', function () { S.autoplay = !S.autoplay; this.style.background = S.autoplay ? '#10b981' : '#374151'; this.innerHTML = S.autoplay ? '▶ 已自动' : '⏸ 手动'; save(); log(S.autoplay ? '\u81ea\u52a8\u64ad\u653e\u5f00\u542f' : '\u624b\u52a8\u64ad\u653e'); }); // 记忆进度 $1('#zjpt-rem-btn').addEventListener('click', function () { S.remember = !S.remember; this.style.background = S.remember ? '#3b82f6' : '#374151'; var cb = this.querySelector('input'); if (cb) cb.checked = S.remember; save(); log(S.remember ? '\u8bb0\u5fc6\u8fdb\u5ea6\u5f00\u542f' : '\u8bb0\u5fc6\u8fdb\u5ea6\u5173\u95ed'); }); } // 进度显示 function updateProgress() { var el = $1('#zjpt-progress'); if (!el) return; var videos = qsa('video'); if (videos.length === 0) { el.textContent = '\u672a\u68c0\u6d4b\u5230\u89c6\u9891'; return; } var parts = []; videos.forEach(function(v, i) { if (v.duration > 0) { var pct = Math.round((v.currentTime / v.duration) * 100); var cm = Math.floor(v.currentTime/60), cs = Math.floor(v.currentTime%60); var tm = Math.floor(v.duration/60), ts = Math.floor(v.duration%60); parts.push('\u89c6' + (i+1) + ': ' + pct + '% (' + cm + ':' + String(cs).padStart(2,'0') + '/' + tm + ':' + String(ts).padStart(2,'0') + ') ' + S.speed + 'x'); } }); el.textContent = parts.length > 0 ? parts.join(' | ') : '\u672a\u68c0\u6d4b\u5230\u89c6\u9891'; } // ==================== 主循环 ==================== var counter = 0, saved = false; function loop() { counter++; applyAll(); if (S.remember && counter % 20 === 0) saveProgress(); if (counter % 10 === 0) updateProgress(); if (!saved && counter === 5) { saved = true; restoreProgress(); log('\u8bb0\u5fc6\u8fdb\u5ea6\u5df2\u6062\u590d'); } } // ==================== 入口 ==================== function main() { createPanel(); log('\u6c5f\u897f\u4e13\u6280\u5b66\u4e60\u7f51 \u52a9\u624b v1.0 \u5df2\u542f\u52a8'); log('\u5f53\u524d\u500d\u7387: ' + S.speed + 'x | \u9759\u97f3: ' + (S.muted?'\u662f':'\u5426') + ' | \u81ea\u52a8: ' + (S.autoplay?'\u662f':'\u5426') + ' | \u8bb0\u5fc6: ' + (S.remember?'\u662f':'\u5426')); log('\u6ce8\u610f: \u672c\u811a\u672c\u4ec5\u9002\u7528\u4e8e jxnu.edu.cn \u57df'); setInterval(loop, 500); window.addEventListener('beforeunload', saveProgress); } if (document.readyState === 'complete') { main(); } else { window.addEventListener('load', main); } })();