// ==UserScript== // @name 江西新余学院-成教继续教育-柠檬文才-全自动刷课助手(jw.wencaischool.net/xyxy) // @version 1.0.0 // @description 新余学院继续教育专用版(柠檬文才系统):全自动刷视频+自动切换章节+倍速,静音/自动播放 // @author 晓晓 // @match *://jw.wencaischool.net/xyxy/* // @match *://learning.wencaischool.net/* // @match *://site.wencaischool.net/* // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @run-at document-end // @license MIT // ==/UserScript== (function () { 'use strict'; var STATUS_KEY = 'xyxy_running'; var SETTINGS_KEY = 'xyxy_speed_settings'; function getRunning() { return GM_getValue(STATUS_KEY, false); } function setRunning(v) { GM_setValue(STATUS_KEY, v); } var defaults = { speed: 2, muted: true, autoplay: true, autonext: true }; var S = Object.assign({}, defaults, GM_getValue(SETTINGS_KEY, {})); function save() { GM_setValue(SETTINGS_KEY, S); } function log(msg, type) { type = type || 'info'; var prefix = { error: '❌', success: '✅', warning: '⚠️' }[type] || '🔍'; console.log(prefix, msg); var el = document.querySelector('#xyxy-log'); if (el) { var t = new Date().toLocaleTimeString('zh-CN', { hour12: false }); el.value += '[' + t + '] ' + msg + '\n'; el.scrollTop = el.scrollHeight; } } // ==================== UI面板 ==================== function $1(s) { return document.querySelector(s); } function createPanel() { var existing = $1('#xyxy-panel'); if (existing) existing.remove(); var isRunning = getRunning(); var el = document.createElement('div'); el.id = 'xyxy-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 = '
' + '🎂' + '
新余学院续教学习
' + '
' + (isRunning ? '● 运行中' : '○ 已暗停') + '
' + '
' + '
倍速: ' + S.speed + 'x
' + '' + '
0.5x16x
' + '
' + '' + '' + '' + '
' + '
等待启动
' + '
' + '
' + '
' + '' + '
' + '' + '
' + '💬 ' + 'wkds995' + ' 客服微信' + '
'; document.body.appendChild(el); // 启动/暂停 $1('#xyxy-btn-toggle').addEventListener('click', function () { if (getRunning()) { setRunning(false); $1('#xyxy-badge').textContent = '○ 已暂停'; $1('#xyxy-badge').style.background = '#6b7280'; this.textContent = '▶ 开始刷课'; this.style.background = '#1890ff'; updateStatus('已暂停', 'warning'); } else { setRunning(true); $1('#xyxy-badge').textContent = '● 运行中'; $1('#xyxy-badge').style.background = '#10b981'; this.textContent = '⏸ 暂停刷课'; this.style.background = '#ef4444'; updateStatus('开始刷课...', 'success'); } }); // 倍速滑块 $1('#xyxy-speed').addEventListener('input', function () { S.speed = parseFloat(this.value); $1('#xyxy-speed-val').textContent = S.speed + 'x'; save(); applySpeed(); log('倍速: ' + S.speed + 'x', 'success'); }); // 静音 $1('#xyxy-muted-btn').addEventListener('click', function () { S.muted = !S.muted; this.style.background = S.muted ? '#ef4444' : '#374151'; this.innerHTML = S.muted ? '☕ 静音' : '🔊 有声'; save(); applyMuted(); log(S.muted ? '已静音' : '开启声音'); }); // 自动播放 $1('#xyxy-ap-btn').addEventListener('click', function () { S.autoplay = !S.autoplay; this.style.background = S.autoplay ? '#10b981' : '#374151'; this.innerHTML = S.autoplay ? '▶ 自动' : '⏸ 手动'; save(); log(S.autoplay ? '自动播放开启' : '手动播放'); }); // 自动切换 $1('#xyxy-next-btn').addEventListener('click', function () { S.autonext = !S.autonext; this.style.background = S.autonext ? '#3b82f6' : '#374151'; this.innerHTML = S.autonext ? '➤ 自动切换' : '⏮ 手动切换'; save(); log(S.autonext ? '自动切换章节开启' : '手动切换章节'); }); } function updateStatus(text, type) { var el = $1('#xyxy-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 updateProgress(text) { var el = $1('#xyxy-progress'); if (el) el.textContent = text; } function updateChapter(text) { var el = $1('#xyxy-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('在iframe[' + i + ']中找到视频', 'info'); return v; } } catch (e) {} } var videos = document.querySelectorAll('video'); for (var j = 0; j < videos.length; j++) { if (videos[j].offsetParent !== null || videos[j].style.display !== 'none') return videos[j]; } return videos.length > 0 ? videos[0] : null; } function applySpeed() { var v = findVideo(); if (v && Math.abs(v.playbackRate - S.speed) > 0.01) v.playbackRate = S.speed; } function applyMuted() { var v = findVideo(); if (v) v.muted = S.muted; } // ==================== 章节检测(柠檬文才标准结构)==================== 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 + '] 找到 ' + sections.length + ' 个 .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 + '] 访问失败: ' + e.message, 'warning'); } } return allChapters; } function findNextChapter() { var chapters = findChapters(); if (chapters.length === 0) return null; var currentIndex = -1; for (var i = 0; i < chapters.length; i++) { if (chapters[i].isActive) { currentIndex = i; break; } } if (currentIndex === -1 || currentIndex >= chapters.length - 1) return null; var next = chapters[currentIndex + 1]; updateChapter('当前: ' + chapters[currentIndex].text.substring(0, 20) + '\n下一章: ' + next.text.substring(0, 20)); 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('已暂停(点击"开始刷课"继续)', 'warning'); return; } var v = findVideo(); if (!v) { if (counter % 60 === 0) updateStatus('未检测到视频,请进入视频播放页面', 'warning'); return; } if (v.src && v.src !== lastVideoSrc) { log('视频切换: ' + (lastVideoSrc ? '新视频' : '首次检测'), 'info'); lastVideoSrc = v.src; videoFinished = false; retryCount = 0; } if (Math.abs(v.playbackRate - S.speed) > 0.01) applySpeed(); if (v.muted !== S.muted) v.muted = S.muted; if (S.autoplay && v.paused && !v.ended && v.readyState >= 2) { v.play().catch(function (e) { log('播放失败: ' + e.message, 'error'); }); updateStatus('正在播放', '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; updateProgress('📊 ' + pct + '% | ' + cm + ':' + String(cs).padStart(2, '0') + ' / ' + tm + ':' + String(ts).padStart(2, '0') + ' | ' + S.speed + 'x ' + (v.muted ? '🔇' : '🔊')); if (cur >= total - 2 && !videoFinished && S.autonext && !switchCooldown) { videoFinished = true; updateStatus('视频即将完成,准备切换下一章...', 'warning'); trySwitchNextChapter(); } } } function trySwitchNextChapter() { var next = findNextChapter(); if (next) { updateStatus('点击下一章', 'success'); switchCooldown = true; retryCount = 0; try { next.click(); next.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window })); } catch (e) {} setTimeout(function () { switchCooldown = false; }, 15000); } else { if (retryCount < 5) { retryCount++; log('第 ' + retryCount + ' 次重试...', 'warning'); setTimeout(function () { if (videoFinished) trySwitchNextChapter(); }, 2000); } else { updateStatus('已完成所有章节(或未找到下一章)', 'success'); retryCount = 0; } } } // ==================== 入口 ==================== function main() { log('新余学院继续教育刷课助手 v1.0 已启动', 'success'); log('当前倍速: ' + S.speed + 'x | 静音: ' + (S.muted?'是':'否') + ' | 自动: ' + (S.autoplay?'是':'否') + ' | 自动切换: ' + (S.autonext?'是':'否'), 'info'); createPanel(); setInterval(mainLoop, 500); if (getRunning()) { updateStatus('正在刷课...', 'success'); } } if (document.readyState === 'complete') { main(); } else { window.addEventListener('load', main); } })();