雨课堂阻止自动暂停播放

阻止雨课堂视频在失去焦点时自动暂停

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

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

})();