// ==UserScript== // @name 江西水利职业学院-成教-柠檬文才-全自动刷课助手(site.wencaischool.net) // @version 1.0.0 // @description wencaischool.net 全自动刷视频+自动切换章节,支持倍速/静音 // @author 晓晓 // @match *://learning.wencaischool.net/* // @match *://site.wencaischool.net/* // @match *://*.wencaischool.net/* // @grant GM_getValue // @grant GM_setValue // ==/UserScript== (function () { 'use strict'; if (window.__jxslHelper) { console.log('已有脚本在运行,跳过'); return; } var STATUS_KEY = 'jxsl_running'; function getRunning() { return GM_getValue(STATUS_KEY, false); } function setRunning(v) { GM_setValue(STATUS_KEY, v); } var config = { speed: parseFloat(localStorage.getItem('jxsl_speed')) || 1.0, autoPlay: true, autoNext: true, debug: true }; function log(msg, type) { type = type || 'info'; if (!config.debug && type === 'info') return; var prefix = { error: '❌', success: '✅', warning: '⚠️' }[type] || '🔍'; console.log(prefix, msg); } function $1(s) { return document.querySelector(s); } // ==================== UI面板 ==================== function createPanel() { var existing = $1('#jxsl-panel'); if (existing) existing.remove(); var isRunning = getRunning(); var el = document.createElement('div'); el.id = 'jxsl-panel'; el.innerHTML = '
' + '
' + '🎓' + '
江西水利职业学院刷课助手
' + '
' + (isRunning ? '● 运行中' : '○ 已暂停') + '
' + '
' + '
播放速度 (最高16x):
' + '' + '
' + '' + '' + '
' + '
运行中
' + '
' + '
' + '' + '
' + '💬 ' + 'wkds995' + ' 客服微信' + '
' + '
'; document.body.appendChild(el); // 拖拽 var dragEl = $1('#jxsl-drag'); var isDragging = false, startX, startY, origX, origY; dragEl.addEventListener('mousedown', function (e) { isDragging = true; startX = e.clientX; startY = e.clientY; origX = dragEl.offsetLeft; origY = dragEl.offsetTop; }); document.addEventListener('mousemove', function (e) { if (!isDragging) return; var dx = e.clientX - startX, dy = e.clientY - startY; var newX = Math.max(0, Math.min(origX + dx, window.innerWidth - dragEl.offsetWidth)); var newY = Math.max(0, Math.min(origY + dy, window.innerHeight - dragEl.offsetHeight)); dragEl.style.left = newX + 'px'; dragEl.style.top = newY + 'px'; dragEl.style.right = 'auto'; }); document.addEventListener('mouseup', function () { isDragging = false; }); // 速度选择 $1('#jxsl-speed').value = config.speed; $1('#jxsl-speed').addEventListener('change', function () { config.speed = parseFloat(this.value); localStorage.setItem('jxsl_speed', config.speed); applySpeed(); updateStatus('\u901f\u5ea6: ' + config.speed + 'x', 'success'); }); $1('#jxsl-autoplay').addEventListener('change', function () { config.autoPlay = this.checked; }); $1('#jxsl-autonext').addEventListener('change', function () { config.autoNext = this.checked; }); // 启动/暂停按钮 $1('#jxsl-btn-toggle').addEventListener('click', function () { if (getRunning()) { setRunning(false); var badge = $1('#jxsl-badge'); if (badge) { badge.textContent = '\u25cb \u5df2\u6697\u505c'; badge.style.background = '#6b7280'; } this.textContent = '\u25b6 \u5f00\u59cb\u5237\u8bfe'; this.style.background = '#1890ff'; updateStatus('\u5df2\u6697\u505c', 'warning'); } else { setRunning(true); var badge = $1('#jxsl-badge'); if (badge) { badge.textContent = '\u25cf \u8fd0\u884c\u4e2d'; badge.style.background = '#10b981'; } this.textContent = '\u23f8 \u6682\u505c\u5237\u8bfe'; this.style.background = '#ef4444'; updateStatus('\u6b63\u5728\u5237\u8bfe...', 'success'); } }); } function updateStatus(text, type) { var el = $1('#jxsl-status'); if (!el) return; el.textContent = text; var colors = { success: '#4ade80', warning: '#fbbf24', error: '#ef4444', info: '#60a5fa' }; el.style.color = colors[type] || '#4ade80'; log(text, type); } function updateInfo(text) { var el = $1('#jxsl-info'); if (el) el.textContent = text; } function updateChapter(text) { var el = $1('#jxsl-chapter'); if (el) el.textContent = text; } // ==================== 视频检测 ==================== function findVideo() { var frames = document.querySelectorAll('iframe'); for (var i = 0; i < frames.length; i++) { try { var v = frames[i].contentDocument.querySelector('video'); if (v) { log('\u5728iframe[' + i + ']\u4e2d\u627e\u5230\u89c6\u9891', 'success'); return v; } } catch (e) {} } var videos = document.querySelectorAll('video'); if (videos.length > 0) { for (var j = 0; j < videos.length; j++) { if (videos[j].offsetParent !== null || videos[j].style.display !== 'none') return videos[j]; } return videos[0]; } return null; } function applySpeed() { var v = findVideo(); if (v) v.playbackRate = config.speed; } // ==================== 章节检测 ==================== function findChapters() { var allChapters = []; var frames = document.querySelectorAll('iframe'); for (var fi = 0; fi < frames.length; fi++) { try { var doc = frames[fi].contentDocument; var sections = doc.querySelectorAll('.childSection'); log('iframe[' + fi + '] \u627e\u5230 ' + sections.length + ' \u4e2a .childSection', 'info'); for (var k = 0; k < sections.length; k++) { var sec = sections[k]; var style = window.getComputedStyle(sec); if (style.display === 'none' || style.visibility === 'hidden') continue; var text = (sec.textContent || '').trim(); if (!text || text.length < 5) continue; var numMatch = text.match(/(\d+\.\d+\.\d+)/); if (!numMatch) continue; var isActive = false; if (location.href.includes(numMatch[1])) isActive = true; var children = sec.querySelectorAll('*'); for (var c = 0; c < children.length; c++) { var bg = (window.getComputedStyle(children[c]).backgroundColor || '').toLowerCase(); if (bg.includes('blue') || bg.includes('33, 150, 243') || bg.includes('30, 144')) { isActive = true; break; } } var cn = (sec.className || '').toLowerCase(); if (cn.includes('active') || cn.includes('current') || cn.includes('playing')) isActive = true; allChapters.push({ element: sec, text: text.substring(0, 80), num: numMatch[1], isActive: isActive }); } } catch (e) { log('iframe[' + fi + '] \u8bbf\u95ee\u5931\u8d25: ' + e.message, 'warning'); } } return allChapters; } function findNextChapter() { var chapters = findChapters(); if (chapters.length === 0) { updateStatus('\u672a\u627e\u5230\u7ae0\u8282', 'error'); return null; } var currentIndex = -1; for (var i = 0; i < chapters.length; i++) { if (chapters[i].isActive) { currentIndex = i; break; } } if (currentIndex === -1) { updateStatus('\u672a\u8bc6\u522b\u5f53\u524d\u7ae0\u8282', 'warning'); return null; } if (currentIndex >= chapters.length - 1) { updateStatus('\u5df2\u5b8c\u6210\u6240\u6709\u7ae0\u8282', 'success'); return null; } var next = chapters[currentIndex + 1]; updateChapter('\u5f53\u524d: ' + chapters[currentIndex].text.substring(0, 25) + '\n\u4e0b\u4e00\u7ae0: ' + next.text.substring(0, 25)); return next.element; } // ==================== 主循环 ==================== var counter = 0; var videoFinished = false; var switchCooldown = false; var retryCount = 0; var lastVideoSrc = ''; function mainLoop() { counter++; if (!getRunning()) { if (counter % 120 === 0) updateStatus('\u5df2\u6697\u505c', 'warning'); return; } var v = findVideo(); if (!v) { if (counter % 60 === 0) { updateStatus('\u672a\u68c0\u6d4b\u5230\u89c6\u9891', 'warning'); updateInfo('\u8bf7\u8fdb\u5165\u89c6\u9891\u64ad\u653e\u9875\u9762'); } return; } if (v.src && v.src !== lastVideoSrc) { log('\u89c6\u9891\u5207\u6362: ' + (lastVideoSrc ? '\u65b0\u89c6\u9891' : '\u9996\u6b21\u68c0\u6d4b'), 'info'); lastVideoSrc = v.src; videoFinished = false; retryCount = 0; } if (Math.abs(v.playbackRate - config.speed) > 0.01) applySpeed(); if (config.autoPlay && v.paused && !v.ended && v.readyState >= 2) { v.play().catch(function (e) { log('\u64ad\u653e\u5931\u8d25: ' + e.message, 'error'); }); updateStatus('\u6b63\u5728\u64ad\u653e', 'success'); videoFinished = false; } if (v.duration && !isNaN(v.duration)) { var cur = Math.floor(v.currentTime); var total = Math.floor(v.duration); var pct = Math.floor((cur / total) * 100); var cm = Math.floor(cur / 60), cs = cur % 60, tm = Math.floor(total / 60), ts = total % 60; updateInfo('\u2705 ' + pct + '% | ' + cm + ':' + String(cs).padStart(2, '0') + ' / ' + tm + ':' + String(ts).padStart(2, '0') + ' | ' + config.speed + 'x'); if (cur >= total - 2 && !videoFinished && config.autoNext && !switchCooldown) { videoFinished = true; updateStatus('\u89c6\u9891\u5373\u5c06\u5b8c\u6210\uff0c\u51c6\u5907\u5207\u6362...', 'warning'); trySwitchNextChapter(); } } } function trySwitchNextChapter() { var next = findNextChapter(); if (next) { updateStatus('\u70b9\u51fb\u4e0b\u4e00\u7ae0', 'success'); switchCooldown = true; retryCount = 0; try { next.click(); var evt = new MouseEvent('click', { bubbles: true, cancelable: true, view: window }); next.dispatchEvent(evt); } catch (e) {} setTimeout(function () { switchCooldown = false; }, 15000); } else { if (retryCount < 5) { retryCount++; log('\u7b2c ' + retryCount + ' \u6b21\u91cd\u8bd5...', 'warning'); setTimeout(function () { if (videoFinished) trySwitchNextChapter(); }, 2000); } else { updateStatus('\u672a\u627e\u5230\u4e0b\u4e00\u7ae0', 'error'); retryCount = 0; } } } function init() { log('\u521d\u59cb\u5316...', 'info'); createPanel(); setInterval(mainLoop, 500); updateStatus('\u811a\u672c\u5df2\u542f\u52a8', 'success'); } if (document.readyState === 'complete') { init(); } else { window.addEventListener('load', init); } window.__jxslHelper = { config: config, version: '1.0.0' }; })();