// ==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));
})
})();