您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
阻止雨课堂视频在失去焦点时自动暂停
// ==UserScript== // @name 雨课堂阻止自动暂停播放 // @name:en Yuketang Anti Auto Pause // @name:es Evitar pausa automática en Yuketang // @namespace https://tampermonkey.net/ // @version 1.0 // @description 阻止雨课堂视频在失去焦点时自动暂停 // @description:en Prevent Yuketang videos from auto-pausing when window loses focus // @description:es Evita que los vídeos de Yuketang se pausen automáticamente al perder el foco de la ventana // @author Anonym // @match https://*.yuketang.cn/* // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; console.log('🚀 雨课堂防暂停解决方案 v1.0'); console.log(''); // 防止重复执行 if (window.YuketangAntiPause) { console.log('⚠️ 防暂停脚本已在运行中'); return; } // 标记脚本已运行 window.YuketangAntiPause = { version: '1.0', status: 'active', stats: { videoPausePrevented: 0, eventBlocked: 0, startTime: new Date() }, // 面板控制函数 togglePanel: () => { console.log('🔧 togglePanel 被调用'); const panel = document.getElementById('yuketang-anti-pause-panel'); const content = document.getElementById('panel-content'); const mini = document.getElementById('panel-mini'); if (!panel || !content || !mini) { console.log('❌ 找不到面板元素'); return; } if (content.style.display === 'none') { // 展开面板 console.log('🔧 展开面板'); content.style.display = 'block'; mini.style.display = 'none'; panel.style.padding = '12px'; panel.style.minWidth = '160px'; panel.style.opacity = '1'; } else { // 最小化面板 console.log('🔧 最小化面板'); content.style.display = 'none'; mini.style.display = 'block'; panel.style.padding = '8px'; panel.style.minWidth = '32px'; panel.style.opacity = '0.5'; } } }; const stats = window.YuketangAntiPause.stats; // ==================== 核心功能区域 ==================== // 1. 视频暂停拦截 - 最重要的功能 console.log('🎯 正在保护视频播放...'); const protectVideos = () => { const videos = document.querySelectorAll('video'); videos.forEach((video, index) => { if (!video._antiPauseProtected) { const originalPause = video.pause; video.pause = function () { stats.videoPausePrevented++; console.log(`🛡️ 阻止视频${index + 1}暂停 (第${stats.videoPausePrevented}次)`); return Promise.resolve(); }; video._antiPauseProtected = true; console.log(`✅ 已保护视频${index + 1}`); } }); return videos.length; }; const videoCount = protectVideos(); if (videoCount === 0) { console.log('⏳ 暂未发现视频,将持续监控...'); } // 2. 页面可见性伪装 - 核心欺骗机制 console.log('🎭 正在伪装页面可见性...'); // 伪装document.hidden try { Object.defineProperty(document, 'hidden', { get: () => false, configurable: true }); Object.defineProperty(document, 'visibilityState', { get: () => 'visible', configurable: true }); console.log('✅ 页面可见性伪装成功'); } catch (e) { console.log('⚠️ 页面可见性伪装失败:', e.message); } // 3. jQuery事件拦截 - 雨课堂特有机制 if (window.$ && window.$.fn && window.$.fn.trigger) { console.log('🔧 正在设置jQuery事件拦截...'); const originalTrigger = window.$.fn.trigger; let controlToggleCount = 0; let lastToggleLogTime = 0; window.$.fn.trigger = function (event, data) { if (typeof event === 'string') { // 拦截所有暂停相关事件 if (event.includes('pause') && !event.includes('toggle')) { stats.eventBlocked++; console.log(`🚫 拦截暂停事件: "${event}"`); return this; } // 控制toggle事件日志频率 if (event === 'control.toggle') { controlToggleCount++; const now = Date.now(); if (now - lastToggleLogTime > 5000) { console.log(`🔄 已处理${controlToggleCount}次control.toggle事件`); lastToggleLogTime = now; } } } return originalTrigger.call(this, event, data); }; console.log('✅ jQuery事件拦截设置完成'); } else { console.log('⚠️ 未检测到jQuery,跳过相关拦截'); } // 4. 事件监听器保护 console.log('🛡️ 正在设置事件监听器保护...'); // 清理现有的危险事件处理器 const dangerousEvents = ['onblur', 'onfocus', 'onvisibilitychange', 'onpagehide', 'onpageshow']; dangerousEvents.forEach(event => { if (window[event]) { window[event] = null; console.log(`🧹 清理了window.${event}`); } }); // 拦截新的事件监听器添加 const originalAddEventListener = EventTarget.prototype.addEventListener; EventTarget.prototype.addEventListener = function (type, listener, options) { const blockedEvents = ['visibilitychange', 'blur', 'focus', 'pagehide', 'pageshow']; if (blockedEvents.includes(type)) { console.log(`🚫 阻止添加事件监听器: ${type}`); return; } return originalAddEventListener.call(this, type, listener, options); }; console.log('✅ 事件监听器保护设置完成'); // ==================== 监控和恢复机制 ==================== // 5. 定期检查和恢复视频播放 const keepVideoPlaying = () => { const videos = document.querySelectorAll('video'); videos.forEach((video, index) => { if (video.paused && !video.ended && video.readyState >= 2) { console.log(`🔄 自动恢复视频${index + 1}播放`); video.play().catch(() => { }); } }); // 检查新视频 if (videos.length > videoCount) { protectVideos(); } }; setInterval(keepVideoPlaying, 3000); // 6. 状态监控面板 console.log('📊 正在创建状态监控面板...'); const createStatusPanel = () => { // 移除旧面板 const existingPanel = document.getElementById('yuketang-anti-pause-panel'); if (existingPanel) { existingPanel.remove(); } const panel = document.createElement('div'); panel.id = 'yuketang-anti-pause-panel'; panel.innerHTML = ` <div id="panel-content"> <div style="font-weight: bold; color: #fff; margin-bottom: 4px;"> 🛡️ 雨课堂防暂停 v1.0 </div> <div id="panel-stats" style="font-size: 11px; line-height: 1.3;"></div> <div style="margin-top: 6px;"> <button id="minimize-btn" style="padding: 2px 6px; font-size: 10px; border: none; border-radius: 2px; cursor: pointer;"> 最小化 </button> </div> </div> <div id="panel-mini" style="display: none; text-align: center; font-size: 16px; line-height: 1;"> 🛡️ </div> `; panel.style.cssText = ` position: fixed; top: 20px; right: 20px; background: linear-gradient(135deg, #4CAF50, #45a049); color: white; padding: 12px; border-radius: 8px; font-size: 12px; font-family: Arial, sans-serif; z-index: 999999; min-width: 160px; box-shadow: 0 4px 12px rgba(0,0,0,0.3); backdrop-filter: blur(10px); border: 1px solid rgba(255,255,255,0.2); cursor: pointer; transition: all 0.3s ease; `; document.body.appendChild(panel); // 添加事件监听器 const minimizeBtn = document.getElementById('minimize-btn'); if (minimizeBtn) { minimizeBtn.addEventListener('click', (e) => { e.stopPropagation(); console.log('🔧 点击了最小化按钮'); window.YuketangAntiPause.togglePanel(); }); } // 添加面板点击事件(用于最小化状态下的展开) panel.addEventListener('click', (e) => { const mini = document.getElementById('panel-mini'); if (mini && mini.style.display !== 'none') { console.log('🔧 点击了最小化面板'); window.YuketangAntiPause.togglePanel(); } }); // 更新状态信息 const updateStats = () => { const statsEl = document.getElementById('panel-stats'); if (statsEl) { const runTime = Math.floor((new Date() - stats.startTime) / 1000); statsEl.innerHTML = ` 状态: <span style="color: #90EE90;">● 运行中</span><br> 运行时间: ${runTime}秒<br> 拦截暂停: ${stats.videoPausePrevented}次<br> 阻止事件: ${stats.eventBlocked}次<br> 页面焦点: ${document.hasFocus() ? '✓ 有' : '✗ 无'} `; } }; setInterval(updateStats, 2000); updateStats(); console.log('✅ 状态监控面板创建完成'); }; createStatusPanel(); // 7. 错误处理 window.addEventListener('error', (e) => { if (e.message && e.message.includes('pause')) { console.log('🛡️ 拦截暂停相关错误'); e.preventDefault(); } }, true); // ==================== 启动完成 ==================== console.log(''); console.log('🎉 雨课堂防暂停终极解决方案启动完成!'); console.log(''); console.log('🔧 已启用功能:'); console.log(' ✅ 视频暂停拦截'); console.log(' ✅ 页面可见性伪装'); console.log(' ✅ jQuery事件拦截'); console.log(' ✅ 事件监听器保护'); console.log(' ✅ 自动恢复播放'); console.log(' ✅ 状态监控面板'); console.log(' ✅ 优化日志输出'); console.log(''); console.log('💡 现在可以安全地切换窗口或标签页,视频将继续播放!'); console.log('📱 右上角的绿色面板显示实时状态信息'); console.log(''); })();