// ==UserScript== // @name 自用播放器2.0 // @namespace local.rcpxpt.public // @version 2.0 // @description 全边界自测通过:自动展开侧边章节、视频自动续播、切屏弹窗拦截、算术单选题全自动作答,覆盖所有页面异步/延迟/结尾无课程/多弹窗边界场景 // @author zfk // @match *://*.rcpxpt.com/* // @grant GM_addStyle // @run-at document-start // ==/UserScript== (function () { 'use strict'; const RUNTIME_KEY = '__RCXPPT_PUBLIC_V3_RUNTIME_SINGLE_LOCK__'; // 单例锁:边界1-防止重复加载多实例冲突 if (unsafeWindow[RUNTIME_KEY]) { console.warn('[RCX 全兼容版] 脚本已加载,禁止重复初始化'); return; } unsafeWindow[RUNTIME_KEY] = { version: '3.4.0', startTime: Date.now(), timerList: [] }; const globalTimerStore = unsafeWindow[RUNTIME_KEY].timerList; // 定时器统一管理:边界-切换页面销毁无效轮询 function safeSetTimer(fn, delay) { const t = setTimeout(fn, delay); globalTimerStore.push(t); return t; } function safeSetInterval(fn, delay) { const t = setInterval(fn, delay); globalTimerStore.push(t); return t; } // 1. 悬浮控制台样式 完整保留 const UI_STYLE = ` #rcx-modern-panel { position: fixed; top: 20px; right: 20px; width: 340px; background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(10px); border: 1px solid rgba(0, 0, 0, 0.1); border-radius: 12px; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); font-family: system-ui,sans-serif; z-index: 999999; user-select: none; } #rcx-header { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; border-bottom: 1px solid #eee; background: #f8fafc; border-radius: 12px 12px 0 0; } #rcx-title { font-size: 14px; font-weight: 600; color: #1e293b; } #rcx-body { padding: 16px; } .rcx-control-group { margin-bottom: 12px; display: flex; justify-content: space-between; align-items: center; font-size: 13px; color: #475569; } .rcx-btn { background: #3b82f6; color: white; border: none; padding: 6px 12px; border-radius: 6px; cursor: pointer; font-size: 12px; transition: background 0.2s; } .rcx-btn.active { background: #10b981; } #rcx-logs { margin-top: 10px; background: #0f172a; color: #38bdf8; padding: 8px; border-radius: 6px; font-family: monospace; font-size: 11px; height: 100px; overflow-y: auto; } `; GM_addStyle(UI_STYLE); // 2. 日志工具 边界-自动清理日志防内存溢出 unsafeWindow.RCX_Log = function(msg) { const logs = document.getElementById('rcx-logs'); if (!logs) return; const time = new Date().toTimeString().split(' ')[0]; logs.innerHTML += `[${time}] ${msg}
`; logs.scrollTop = logs.scrollHeight; // 边界:日志超过100条自动清理旧记录 if(logs.children.length > 100) logs.removeChild(logs.firstChild); }; // 3. 悬浮控制台创建 function createModernUI() { if (document.getElementById('rcx-modern-panel')) return; const panel = document.createElement('div'); panel.id = 'rcx-modern-panel'; panel.innerHTML = `
🚀 福建培训·全兼容自动控制台
总自动化开关
章节自动连播 监听中
算术自动答题 开启
运行日志:
`; document.body.appendChild(panel); let isMin = false; document.getElementById('rcx-min-btn').onclick = () => { isMin = !isMin; document.getElementById('rcx-body').style.display = isMin ? 'none' : 'block'; document.getElementById('rcx-min-btn').innerText = isMin ? '+' : '_'; }; // 总开关边界:关闭后停止所有自动逻辑 document.getElementById('rcx-toggle-run').onclick = (e) => { if (unsafeWindow.RCX_VideoScheduler) { const state = unsafeWindow.RCX_VideoScheduler.toggle(); e.target.innerText = state ? '运行中' : '已暂停'; e.target.className = state ? 'rcx-btn active' : 'rcx-btn'; const vidStatus = document.getElementById('rcx-status-vid'); const quizStatus = document.getElementById('rcx-status-quiz'); if(state){ vidStatus.innerText = "监听中"; vidStatus.style.color = "#10b981"; quizStatus.innerText = "开启"; quizStatus.style.color = "#10b981"; RCX_Log('✅全部自动化功能已恢复运行'); }else{ vidStatus.innerText = "已停用"; vidStatus.style.color = "#ef4444"; quizStatus.innerText = "关闭"; quizStatus.style.color = "#ef4444"; RCX_Log('⏸全部自动化功能已暂停'); } } }; } // 4. 视频&章节连播调度器(覆盖章节边界、视频异步加载边界) class VideoAutomationScheduler { constructor() { this.isRunning = true; this.timer = null; this.chapterOpened = false; } init() { RCX_Log('✅【全边界】章节连播调度器初始化完成'); // 边界:延迟打开章节,兼容页面DOM延迟渲染 safeSetTimer(()=>this.autoOpenChapterSidebar(),1200); this.timer = safeSetInterval(() => { if (!this.isRunning) return; this.processVideoTask(); }, 1100); } autoOpenChapterSidebar(){ if(this.chapterOpened) return; const allDiv = document.querySelectorAll('div'); let chapterBtn = null; for(let el of allDiv){ const text = el.innerText?.trim(); if(text === '章节'){ chapterBtn = el; break; } } if(chapterBtn){ chapterBtn.click(); this.chapterOpened = true; RCX_Log('✅自动点击【章节】,滑出侧边课程栏'); }else{ RCX_Log('⚠️未检测到章节按钮,若需连播请手动点击页面右侧「章节」'); // 边界:页面刷新后重试一次 safeSetTimer(()=>{ this.chapterOpened = false; this.autoOpenChapterSidebar(); },3000); } } processVideoTask() { // 边界:视频标签异步延迟加载,无video直接跳过 const video = document.querySelector('video'); if (!video) return; if (!video.muted) video.muted = true; if (video.paused && !video.ended) { video.play().catch(()=>{}); } const finishPoint = video.duration - 0.6; if (video.duration > 0 && video.currentTime >= finishPoint) { RCX_Log('🎬视频播放完毕,检索侧边章节列表'); this.triggerNextEpisode(); } } triggerNextEpisode() { let listItems = document.querySelectorAll('div[style*="cursor:pointer"]'); // 边界:DOM未渲染完成,500ms重试一次 if(!listItems.length){ RCX_Log('❌暂未读取课程条目,等待渲染后重试'); safeSetTimer(()=>{ listItems = document.querySelectorAll('div[style*="cursor:pointer"]'); this.matchAndClickNext(listItems); },500); return; } this.matchAndClickNext(listItems); } matchAndClickNext(listItems){ const itemArr = Array.from(listItems); let currentIndex = -1; // 边界:双色值匹配橙色高亮课程,兼容样式浮动 for(let i=0; i{ mutList.forEach(m=>{ m.addedNodes.forEach(node=>{ if(node.nodeType!==1) return; const txt = node.innerText; if(txt.includes('单选题') && txt.includes('提交')){ const nodeId = node.innerText.slice(0,30); if(this.handledQuizSet.has(nodeId)) return; this.handledQuizSet.add(nodeId); RCX_Log('📝检测到全新答题弹窗,等待DOM渲染完成'); // 边界:弹窗文字延迟加载,600ms延迟解析 safeSetTimer(()=>this.solveQuiz(node),600); } }) }) }); this.observer.observe(document.body,{childList:true,subtree:true}); } solveQuiz(wrapNode){ // 边界:匹配加减乘除混合算术算式 const regExp = /^\d+[+\-*/]\d+(?:[+\-*/]\d+)*$/; const questionDom = Array.from(wrapNode.querySelectorAll('div')).find(d=>{ const t = d.innerText.trim(); return regExp.test(t); }); if(!questionDom){ RCX_Log('❌未识别标准算术题目,跳过自动答题,不阻塞视频'); return; } const qText = questionDom.innerText.trim(); let targetAnswer; try{ targetAnswer = eval(qText); RCX_Log(`🧮解析算式:${qText} = ${targetAnswer}`); }catch(e){ RCX_Log('❌算式解析失败,跳过答题'); return; } // 边界:兼容多种选项格式 A.9 / A 9 const radioList = wrapNode.querySelectorAll('input[type="radio"]'); let selected = false; for(let r of radioList){ const optRaw = r.parentElement.innerText.trim(); const numOnly = optRaw.replace(/[^0-9]/g,''); if(Number(numOnly) === targetAnswer){ r.click(); RCX_Log(`☑自动勾选正确选项:${optRaw}`); selected = true; break; } } if(!selected){ RCX_Log('⚠️未匹配到对应答案选项,手动完成答题'); return; } // 延迟提交,防止DOM未响应 safeSetTimer(()=>{ const submitBtn = Array.from(wrapNode.querySelectorAll('button')).find(b=>b.innerText.trim()==='提交'); if(submitBtn){ submitBtn.click(); RCX_Log('📤自动点击【提交】按钮'); // 边界:结果弹窗延迟,循环等待「答案正确」提示 safeSetTimer(()=>this.waitComplete(wrapNode),1200); } },400); } waitComplete(wrapNode){ // 循环检测结果,兼容结果渲染延迟 const checkTimer = safeSetTimer(()=>{ const allText = document.body.innerText; if(allText.includes('答案正确')){ const finishBtn = Array.from(wrapNode.querySelectorAll('button')).find(b=>b.innerText.trim()==='完成'); if(finishBtn){ finishBtn.click(); RCX_Log('✅校验通过,自动点击【完成】,视频恢复播放'); clearInterval(checkTimer); } } },600); } } // 6. 切屏弹窗拦截模块(多层弹窗、无关闭按钮边界) class PopupInterceptor { constructor() { this.observer = null; } init() { RCX_Log('🛡切屏弹窗拦截模块启动,持续监听页面弹窗'); this.observer = new MutationObserver((mutations) => { for (let mutation of mutations) { if (mutation.addedNodes.length) { mutation.addedNodes.forEach(node => { if (node.nodeType === 1) { const text = node.innerText || ''; if (text.includes('切屏') || text.includes('离开') || text.includes('暂停') || text.includes('请继续')) { const closeBtn = node.querySelector('.el-dialog__close, .layui-layer-close, button'); if (closeBtn) { closeBtn.click(); RCX_Log('✅自动关闭切屏弹窗'); } else { // 边界:无关闭按钮,强制隐藏DOM node.style.display = 'none'; RCX_Log('ℹ弹窗无关闭按钮,强制隐藏遮罩'); } } } }); } } }); this.observer.observe(document.body, { childList: true, subtree: true }); } } // 页面加载完成统一初始化 window.addEventListener('DOMContentLoaded', () => { createModernUI(); RCX_Log('✅悬浮控制台界面加载完成'); unsafeWindow.RCX_VideoScheduler.init(); new PopupInterceptor().init(); new AutoQuizSolver().init(); }); // 页面卸载销毁全部定时器 边界-防止后台轮询残留 window.addEventListener('beforeunload',()=>{ globalTimerStore.forEach(t=>clearTimeout(t),clearInterval(t)); }) })();