// ==UserScript== // @name 巴中继续教育自动切课(低检测优化版) // @namespace http://tampermonkey.net/ // @version 0.4.0 // @description 跨大节自动切课+倍速隐藏+真人行为模拟,降低检测概率 // @author 自用辅助 // @match *://bzys.jjyxt.cn/* // @grant none // @run-at document-start // @license MIT // ==/UserScript== (function() { 'use strict'; // ========== 配置区 ========== const CONFIG = { targetPlaybackRate: 2.0, // 目标倍速,建议1.2-1.5更安全 rateFluctuation: 0.2, // 倍速随机波动幅度 rateStep: 0.1, skipSec: 10, autoResume: true, autoMuted: true, autoSkipPopup: true, // 随机暂停间隔(毫秒):6-15分钟 pauseIntervalMin: 360000, pauseIntervalMax: 900000, // 随机暂停时长(毫秒):1-3秒 pauseDurationMin: 1000, pauseDurationMax: 3000, // 切课延迟随机范围(毫秒) nextDelayMin: 1000, nextDelayMax: 4000, nextBtnKeywords: ['下一节', '下一课', '下一章节', '下一章', '继续学习', '下一个'], chapterSelector: '.chapter-item, .section-item, .course-item, li.course, .list-item', activeClass: 'active, current, playing, now, on' }; // ================================================= let videoDom = null; let domObserver = null; let isJumping = false; let toastTimer = null; let pauseTimer = null; // ========== 前置:劫持playbackRate隐藏真实倍速 ========== (function hidePlaybackRate() { const proto = HTMLMediaElement.prototype; const originalDesc = Object.getOwnPropertyDescriptor(proto, 'playbackRate'); if (!originalDesc) return; let realRate = 1.0; Object.defineProperty(proto, 'playbackRate', { get: function() { // 页面读取时返回1.0 return 1.0; }, set: function(value) { realRate = value; originalDesc.set.call(this, value); }, configurable: true, enumerable: true }); })(); // 悬浮提示 function showToast(text) { let toast = document.getElementById('helper-toast'); if (!toast) { toast = document.createElement('div'); toast.id = 'helper-toast'; toast.style.cssText = ` position: fixed; top: 80px; left: 50%; transform: translateX(-50%); background: rgba(0,0,0,0.75); color: #fff; padding: 8px 16px; border-radius: 6px; font-size: 14px; z-index: 99999; pointer-events: none; transition: opacity 0.3s; `; document.body.appendChild(toast); } toast.textContent = text; toast.style.opacity = '1'; clearTimeout(toastTimer); toastTimer = setTimeout(() => toast.style.opacity = '0', 1200); } // 右下角状态面板 function createStatusPanel() { let panel = document.getElementById('study-status-panel'); if (panel) return panel; panel = document.createElement('div'); panel.id = 'study-status-panel'; panel.style.cssText = ` position: fixed; right: 10px; bottom: 10px; background: rgba(0,0,0,0.65); color: #fff; padding: 10px; border-radius: 8px; font-size:12px; z-index:99998; min-width:140px; line-height:1.6; `; panel.innerHTML = `
【学习辅助状态】
目标倍速:${CONFIG.targetPlaybackRate}x
播放:00:00/00:00
静音:否
H=快捷键说明
`; document.body.appendChild(panel); return panel; } function updateStatusPanel() { if (!videoDom) return; const panel = createStatusPanel(); panel.querySelector('#rate-line').innerText = `目标倍速:${CONFIG.targetPlaybackRate}x`; panel.querySelector('#mute-line').innerText = `静音:${videoDom.muted ? "是" : "否"}`; const cur = formatTime(videoDom.currentTime); const total = formatTime(videoDom.duration || 0); panel.querySelector('#time-line').innerText = `播放:${cur}/${total}`; } function formatTime(s) { if (isNaN(s)) return "00:00"; let m = Math.floor(s / 60); let sec = Math.floor(s % 60); return `${String(m).padStart(2, '0')}:${String(sec).padStart(2, '0')}`; } function showHelpInfo() { const info = ` 快捷键列表: C:加速 +0.1 | X:减速 -0.1 Z:重置1倍速 | N:手动切下一课 ←→:进退${CONFIG.skipSec}秒 | 空格:播放/暂停 M:切换静音 | Ctrl↑↓:调音量 F:全屏 | H:关闭此提示 `.trim(); alert(info); } // 随机数工具 function random(min, max) { return Math.random() * (max - min) + min; } // 切课逻辑 function clickNextByButton() { const els = document.querySelectorAll('a, button, div[role="button"], span'); for (const el of els) { const txt = el.innerText?.trim() || ''; const match = CONFIG.nextBtnKeywords.some(k => txt.includes(k)); const vis = el.offsetParent !== null; const dis = el.disabled || el.classList.contains('disabled'); if (match && vis && !dis) { el.click(); return true; } } return false; } function clickNextByCatalog() { const items = Array.from(document.querySelectorAll(CONFIG.chapterSelector)); if (!items.length) return false; const activeCls = CONFIG.activeClass.split(',').map(c => c.trim()); let currItem = null; for (const cls of activeCls) { currItem = document.querySelector(`${CONFIG.chapterSelector}.${cls}`); if (currItem) break; } if (!currItem) currItem = items.find(i => i.innerText.match(/正在播放|学习中/)); if (!currItem) return false; const idx = items.indexOf(currItem); if (idx === -1) return false; const nextIdx = idx + 1; if (nextIdx >= items.length) { showToast('🎉 全部课程学习完毕'); return true; } items[nextIdx].click(); return true; } function goToNextChapter() { if (isJumping) return; isJumping = true; const delay = random(CONFIG.nextDelayMin, CONFIG.nextDelayMax); showToast(`${(delay/1000).toFixed(1)}秒后自动跳转下一课`); setTimeout(() => { clickNextByButton() || clickNextByCatalog(); setTimeout(() => isJumping = false, 3000); }, delay); } // 倍速控制(带随机波动) function setFluctuationRate() { if (!videoDom) return; const base = CONFIG.targetPlaybackRate; const fluct = CONFIG.rateFluctuation; const rate = base + random(-fluct, fluct); const finalRate = Math.max(0.5, Math.min(3, rate)); // 直接调用原生设置,不走被劫持的setter const originalDesc = Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'playbackRate'); originalDesc.set.call(videoDom, finalRate); } function adjustRate(delta) { if (!videoDom) return; CONFIG.targetPlaybackRate = Math.max(0.5, Math.min(3, CONFIG.targetPlaybackRate + delta)); setFluctuationRate(); showToast(`目标倍速:${CONFIG.targetPlaybackRate.toFixed(1)}x`); } // 随机暂停模拟真人 function startRandomPause() { clearTimeout(pauseTimer); const nextPause = random(CONFIG.pauseIntervalMin, CONFIG.pauseIntervalMax); pauseTimer = setTimeout(() => { if (!videoDom || videoDom.paused || isJumping) { startRandomPause(); return; } videoDom.pause(); const duration = random(CONFIG.pauseDurationMin, CONFIG.pauseDurationMax); setTimeout(() => { videoDom.play().catch(() => {}); startRandomPause(); }, duration); }, nextPause); } function videoSkip(sec) { if (!videoDom) return; videoDom.currentTime = Math.max(0, Math.min(videoDom.duration, videoDom.currentTime + sec)); showToast(sec>0 ? `前进${sec}秒` : `后退${Math.abs(sec)}秒`); } function togglePlay() { if (!videoDom) return; if(videoDom.paused) videoDom.play(); else videoDom.pause(); showToast(videoDom.paused ? "已暂停" : "开始播放"); } function toggleMute() { if (!videoDom) return; videoDom.muted = !videoDom.muted; showToast(videoDom.muted ? "已静音" : "取消静音"); } function volumeChange(delta) { if (!videoDom) return; videoDom.volume = Math.max(0, Math.min(1, videoDom.volume + delta)); showToast(`音量:${(videoDom.volume*100).toFixed(0)}%`); } function toggleFullscreen() { if (!videoDom) return; if(document.fullscreenElement) document.exitFullscreen(); else videoDom.requestFullscreen(); } // 视频绑定 function bindVideoEvent() { const videos = document.querySelectorAll('video'); if (!videos.length) return false; videoDom = videos[0]; videoDom.removeEventListener('ended', handleVideoEnd); videoDom.addEventListener('ended', handleVideoEnd); // 初始先1倍速播放5秒,再升到目标倍速 const originalDesc = Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'playbackRate'); originalDesc.set.call(videoDom, 1.0); setTimeout(() => { setFluctuationRate(); // 每4分钟刷新一次波动倍速 setInterval(setFluctuationRate, 240000); }, 5000); videoDom.muted = CONFIG.autoMuted; videoDom.autoplay = true; if (CONFIG.autoResume) { videoDom.removeEventListener('pause', handleVideoPause); videoDom.addEventListener('pause', handleVideoPause); } setInterval(updateStatusPanel, 1000); startRandomPause(); console.log(`[视频绑定完成] 目标倍速${CONFIG.targetPlaybackRate}x`); return true; } function handleVideoEnd() { goToNextChapter(); } function handleVideoPause() { if (isJumping) return; setTimeout(() => videoDom?.play().catch(() => {}), 800); } // 全局快捷键 function initHotkeys() { document.addEventListener('keydown', e => { const tag = document.activeElement?.tagName; if (['INPUT','TEXTAREA','SELECT'].includes(tag)) return; const key = e.key.toLowerCase(); if(e.ctrlKey){ if(key === 'arrowup') {e.preventDefault();volumeChange(0.1);return;} if(key === 'arrowdown') {e.preventDefault();volumeChange(-0.1);return;} } switch(key){ case 'c': e.preventDefault(); adjustRate(CONFIG.rateStep); break; case 'x': e.preventDefault(); adjustRate(-CONFIG.rateStep); break; case 'z': e.preventDefault(); CONFIG.targetPlaybackRate = 1; setFluctuationRate(); showToast("已重置为1倍速"); break; case 'n': e.preventDefault(); goToNextChapter(); break; case 'arrowleft': e.preventDefault(); videoSkip(-CONFIG.skipSec); break; case 'arrowright': e.preventDefault(); videoSkip(CONFIG.skipSec); break; case ' ': e.preventDefault(); togglePlay(); break; case 'm': e.preventDefault(); toggleMute(); break; case 'f': e.preventDefault(); toggleFullscreen(); break; case 'h': e.preventDefault(); showHelpInfo(); break; } }) } // 自动弹窗关闭 function autoSkipPopup() { if (!CONFIG.autoSkipPopup) return; const btns = document.querySelectorAll('button,a,.el-button,.confirm-btn'); btns.forEach(b=>{ const t = b.innerText?.trim()||''; if(['确定','知道了','继续','确认'].includes(t) && b.offsetParent) b.click(); }) } // DOM监听 function initObserver() { domObserver = new MutationObserver(()=>{ if(!videoDom || !document.body.contains(videoDom)) bindVideoEvent(); autoSkipPopup(); }) domObserver.observe(document.body,{childList:true,subtree:true}) } function init() { bindVideoEvent() || initObserver(); initHotkeys(); autoSkipPopup(); createStatusPanel(); console.log('[低检测优化版脚本加载完成,按H查看快捷键]'); } window.addEventListener('load', ()=>setTimeout(init, 1200)); if(['complete','interactive'].includes(document.readyState)) setTimeout(init, 1200); })();