学习通自动刷视频

学习通自动播放、防暂停(无视答题弹窗)、自动下一节功能且跳过章节测试

// ==UserScript==
// @name         学习通自动刷视频
// @version      1.0
// @description  学习通自动播放、防暂停(无视答题弹窗)、自动下一节功能且跳过章节测试
// @author       hu89h
// @match        https://mooc1.chaoxing.com/mycourse/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=chaoxing.com
// @grant        none
// @license MIT
// @namespace https://greasyfork.org/users/1398926
// ==/UserScript==

(function () {
    'use strict';

    // 全局变量
    let video = null;
    let isAutoNextEnabled = false;
    let lastVideoUrl = "";
    let retryCount = 0; // 新增重试计数器
    const MAX_RETRY = 3; // 最大重试次数
    // UI样式
    const style = document.createElement('style');
    style.innerHTML = `
        .h_Bbutton {
            transition: all 0.3s linear;
            position: fixed;
            padding: 10px;
            border: none;
            background: linear-gradient(45deg, #0219f2, #c804ea);
            color: #fffae5;
            border-radius: 5px;
            box-shadow: 8px 4px 10px 3px #ccc;
            cursor: pointer;
            font-weight: bold;
            width: 120px;
            z-index: 10000;
        }
        .h_Bbutton:active {
            transform: translateY(2px);
        }
        .h_Bbutton:hover {
            opacity: 0.8;
        }
        .bottom_text {
            position: fixed;
            bottom: 0;
            left: 0;
            background-color: #51f;
            color: #fffae5;
            padding: 3px 5px;
            font-size: 12px;
            border-radius: 3px;
            z-index: 10000;
        }
    `;
    document.head.appendChild(style);

    // 创建防暂停按钮
    const stopPauseButton = document.createElement('button');
    stopPauseButton.className = 'h_Bbutton';
    stopPauseButton.innerHTML = '防暂停';
    stopPauseButton.style.bottom = '30px';
    stopPauseButton.style.left = '20px';
    document.body.appendChild(stopPauseButton);

    // 创建自动下一节按钮
    const autoNextButton = document.createElement('button');
    autoNextButton.className = 'h_Bbutton';
    autoNextButton.innerHTML = '自动下一节';
    autoNextButton.style.bottom = '80px';
    autoNextButton.style.left = '20px';
    document.body.appendChild(autoNextButton);

    // 状态显示
    const statusText = document.createElement('div');
    statusText.className = 'bottom_text';
    statusText.innerText = '脚本已加载';
    document.body.appendChild(statusText);

    // 安全执行函数包装器
    function safeExecute(fn) {
        return function() {
            try {
                fn();
                return true;
            } catch(e) {
                console.error('执行错误:', e);
                statusText.innerText = '错误: ' + e.message;
                return false;
            }
        };
    }

    // 监听控制台消息
    function setupConsoleObserver() {
        // 保存原始的console.log方法
        const originalLog = console.log;

        // 重写console.log以拦截消息
        console.log = function() {
            // 调用原始方法,保持正常打印
            originalLog.apply(console, arguments);

            // 检查是否是目标消息
            const message = Array.from(arguments).join(' ');
            if (message.includes("学习是一种信仰") || message.includes("v9")) {
                console.log("检测到页面动态加载,尝试重新初始化视频...");
                statusText.innerText = '检测到页面变化,重新初始化...';

                // 延迟执行初始化,给页面一些时间加载
                setTimeout(() => {
                    initVideo();
                }, 2000);
            }
        };
    }

    // 监听URL变化(另一种检测方式)
    function setupUrlChangeObserver() {
        // 创建一个定时器检查URL变化
        setInterval(() => {
            try {
                // 尝试获取当前播放的视频URL
                const currentIframe = document.querySelectorAll('iframe')[0];
                if (!currentIframe) return;

                const innerIframe = currentIframe.contentWindow.document.querySelectorAll('iframe')[0];
                if (!innerIframe) return;

                const currentVideo = innerIframe.contentWindow.document.querySelector('video');
                if (!currentVideo) return;

                const currentSrc = currentVideo.src || currentVideo.currentSrc;

                // 如果视频URL变化,说明已切换到新视频
                if (currentSrc && currentSrc !== lastVideoUrl) {
                    console.log("检测到视频URL变化,重新初始化...");
                    statusText.innerText = '检测到新视频,重新初始化...';
                    lastVideoUrl = currentSrc;

                    // 重新初始化视频
                    initVideo();
                }
            } catch (e) {
                console.error("URL变化检测失败", e);
            }
        }, 3000);
    }

    // 监听DOM变化(用于检测视频播放器的变化)
    function setupDomChangeObserver() {
        // 创建一个MutationObserver实例,在DOM变化时检查视频
        const observer = new MutationObserver((mutations) => {
            for (const mutation of mutations) {
                if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                    // 节点添加,可能是新视频加载
                    setTimeout(() => {
                        const currentVideo = getVideoElement();
                        if (currentVideo && currentVideo !== video) {
                            console.log("检测到DOM变化,发现新视频元素");
                            statusText.innerText = '检测到DOM变化,重新初始化...';
                            initVideo();
                        }
                    }, 1000);
                }
            }
        });

        // 开始观察document的变化,包括子树
        observer.observe(document, { childList: true, subtree: true });
    }

    // 获取视频元素(抽取为独立函数方便复用)
    function getVideoElement() {
        try {
            let iframe = document.querySelectorAll('iframe')[0];
            if (!iframe) return null;

            let iframeDoc = iframe.contentWindow.document;
            let innerIframe = iframeDoc.querySelectorAll('iframe')[0];
            if (!innerIframe) return null;

            let innerIframeDoc = innerIframe.contentWindow.document;
            return innerIframeDoc.querySelector('video');
        } catch (e) {
            console.error("获取视频元素失败", e);
            return null;
        }
    }

    // 初始化视频
    function initVideo() {
        try {
            let iframe = document.querySelectorAll('iframe')[0];
            if (!iframe) throw new Error('找不到主iframe');

            let iframeDoc = iframe.contentWindow.document;
            let innerIframe = iframeDoc.querySelectorAll('iframe')[0];
            if (!innerIframe) throw new Error('找不到内部iframe');

            let innerIframeDoc = innerIframe.contentWindow.document;

            // 尝试点击播放按钮
            let playButton = innerIframeDoc.querySelector('.vjs-big-play-button');
            if (playButton) {
                console.log("发现播放按钮,点击播放...");
                playButton.click();
            }

            // 获取视频元素
            video = innerIframeDoc.querySelector('video');

            if (video) {
                console.log("视频已加载");
                statusText.innerText = '视频已加载';

                // 保存当前视频URL
                lastVideoUrl = video.src || video.currentSrc;

                // 启用防暂停
                enableStopPause();

                // 如果之前启用了自动下一节,则继续启用
                if (isAutoNextEnabled) {
                    enableAutoNext(true);
                }

                // 自动播放(静音以避开浏览器限制)
                video.muted = true;
                video.play().then(() => {
                    statusText.innerText = '视频已自动播放';
                }).catch(e => {
                    console.error('自动播放失败:', e);
                    statusText.innerText = '自动播放失败,请手动点击';
                });

                return true;
            } else {
                console.log("未找到视频元素");
                statusText.innerText = '未找到视频,自动跳转下一节';
                clickNextChapter();
                return false;
            }
        } catch (e) {
            console.error("初始化视频失败", e);
            statusText.innerText = '初始化失败: ' + e.message;
            return false;
        }
    }
// 新增通用下一节点击方法
function clickNextChapter() {
    let nextButtons = document.querySelectorAll('.nextChapter');
    if (nextButtons.length > 0) {
        nextButtons[0].click();
        console.log('已点击通用下一节按钮');
        statusText.innerText = '已跳转下一节,尝试重新初始化...';

        // 延迟后重新初始化
        setTimeout(() => {
            initVideo();
        }, 3000);
    } else {
        console.warn('找不到通用的下一节按钮');
        statusText.innerText = '错误:找不到下一节按钮';
    }
}

    // 防暂停功能
    function enableStopPause() {
        if (!video) return false;

        // 重写pause方法
        video.pause = function() {
            console.log('暂停被阻止');
            statusText.innerText = '已阻止视频暂停';
        };

        stopPauseButton.style.background = 'linear-gradient(45deg, #02c2f2, #04ea1c)';
        stopPauseButton.innerHTML = '防暂停已启用';
        return true;
    }

    // 自动下一节功能
    function enableAutoNext(keepState = false) {
        if (!video) return false;

        if (!keepState) {
            isAutoNextEnabled = !isAutoNextEnabled;
        }

        if (isAutoNextEnabled) {
            // 先移除之前可能的监听器,避免重复
            video.removeEventListener('ended', clickNextVideo);
            // 添加视频结束事件监听
            video.addEventListener('ended', clickNextVideo);
            autoNextButton.style.background = 'linear-gradient(45deg, #02c2f2, #04ea1c)';
            autoNextButton.innerHTML = '自动下一节已启用';
            statusText.innerText = '自动下一节已启用';
        } else {
            // 移除视频结束事件监听
            video.removeEventListener('ended', clickNextVideo);
            autoNextButton.style.background = 'linear-gradient(45deg, #0219f2, #c804ea)';
            autoNextButton.innerHTML = '自动下一节';
            statusText.innerText = '自动下一节已禁用';
        }

        return true;
    }

    // 点击下一节视频
        function clickNextVideo() {
        // 优先查找新版本"下一节"按钮
        let nextButton = document.querySelector('a.nextChapter');

        // 如果找不到则尝试旧版按钮
        if (!nextButton) {
            nextButton = document.getElementById('prevNextFocusNext');
        }

        if (nextButton) {
            nextButton.click();
            console.log("已点击下一节按钮");
            statusText.innerText = '正在跳转到下一节...';
            retryCount = 0; // 重置计数器

            // 增强型初始化检测
            const initAfterJump = () => {
                if (!initVideo()) {
                    if (retryCount < MAX_RETRY) {
                        retryCount++;
                        console.log(`初始化失败,正在第${retryCount}次重试...`);
                        statusText.innerText = `正在第${retryCount}次尝试加载...`;
                        setTimeout(initAfterJump, 3000);
                    } else {
                        console.log("超过最大重试次数,尝试强制跳转");
                        statusText.innerText = '内容加载异常,建议手动操作';
                        // 强制跳转作为最后手段
                        document.querySelector('a.nextChapter')?.click();
                    }
                }
            };

            // 首次延迟检测
            setTimeout(initAfterJump, 5000);
        } else {
            statusText.innerText = '未找到有效的下一节按钮';
            console.error('未找到下一节按钮');
            // 尝试通过课程结构跳转
            tryCourseStructureJump();
        }
    }

    // 新增课程结构跳转方法
    function tryCourseStructureJump() {
        // 查找课程目录中的已完成章节
        const courseItems = document.querySelectorAll('.chapter_item');
        if (courseItems.length > 0) {
            // 查找最近未完成的章节
            const currentItem = Array.from(courseItems).find(item =>
                item.querySelector('.posCatalog_icon')?.classList.contains('currents')
            );

            if (currentItem) {
                const nextItem = currentItem.nextElementSibling;
                if (nextItem) {
                    const link = nextItem.querySelector('a');
                    if (link) {
                        console.log("通过课程目录跳转到下一节");
                        link.click();
                        statusText.innerText = '通过目录跳转中...';
                        return true;
                    }
                }
            }
        }
        return false;
    }

    // 绑定按钮事件
    stopPauseButton.onclick = safeExecute(() => {
        if (!video) {
            if (!initVideo()) {
                alert('请确保视频已加载');
                return;
            }
        }
        enableStopPause();
    });

    autoNextButton.onclick = safeExecute(() => {
        if (!video) {
            if (!initVideo()) {
                alert('请确保视频已加载');
                return;
            }
        }
        enableAutoNext();
    });

    // 初始化所有监听器
    function initAllObservers() {
        // 设置控制台监听
        setupConsoleObserver();
        // 设置URL变化监听
        setupUrlChangeObserver();
        // 设置DOM变化监听
        setupDomChangeObserver();
    }

    // 页面加载完成后自动初始化
    const initInterval = setInterval(() => {
        if (initVideo()) {
            clearInterval(initInterval);
            console.log('视频初始化成功');
            statusText.innerText = '视频初始化成功';
            initAllObservers();
        } else if (retryCount >= MAX_RETRY) {
            clearInterval(initInterval);
            statusText.innerText = '初始化失败,请检查页面';
        }
    }, 2000);

    // 立即初始化观察器(不等待视频加载)
    initAllObservers();
})();