湖南开放大学自动刷课(2025最新版(2024-2025都适用))

解决自动播放被阻止问题,确保视频持续播放,60分钟自动刷新,拦截弹窗,自动完成所有课程。有疑问可留言

// ==UserScript==
// @name         湖南开放大学自动刷课(2025最新版(2024-2025都适用))
// @namespace    http://tampermonkey.net/
// @version      2.3
// @description  解决自动播放被阻止问题,确保视频持续播放,60分钟自动刷新,拦截弹窗,自动完成所有课程。有疑问可留言
// @author       唐跃翔
// @match        *.hnsydwpx.cn/*
// @grant        GM_addStyle
// @grant        GM_log
// @grant        GM_notification
// @grant        GM_setValue
// @grant        GM_getValue
// @run-at       document-idle
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // 配置参数
    const config = {
        checkInterval: 5000,
        interactionWait: 3000,
        maxRetry: 300,
        debugMode: true,
        countdownDuration: 60*60 // 60分钟(秒数)
    };

    // 添加UI指示器
    GM_addStyle(`
  .script-indicator {
            position: fixed;
            top: 20px;
            right: 20px;
            background: linear-gradient(135deg, rgba(0,0,0,0.8), #B8860B);
            color: white;
            padding: 15px 22px;
            border-radius: 10px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.4);
            z-index: 9999;
            font-size: 25px;
        }
        .script-indicator.error {
            background: #F44336;
        }

        .pro-label {
            position: absolute;
            bottom: -10px;
            right: 10px;
            background: rgba(0, 0, 0, 0.5);
            color: #FFD700;
            padding: 5px 10px;
            border-radius: 5px;
            font-size: 14px;
            font-weight: bold;
            opacity: 0.8;
        }

        .countdown-display {
            font-size: 14px;
            margin-top: 5px;
            opacity: 0.8;
        }
    `);

    const indicator = document.createElement('div');
    indicator.className = 'script-indicator';
    indicator.innerHTML = '阿唐的刷课脚本已经启动啦<div class="pro-label">Pro</div> <div class="countdown-display"></div>';
    document.body.appendChild(indicator);

    // 倒计时管理器
    class CountdownManager {
        constructor() {
            this.timer = null;
            this.startTime = null;
            this.remaining = GM_getValue('countdownRemaining', config.countdownDuration);
            this.init();
        }

        init() {
            this.updateDisplay();
            if (!GM_getValue('countdownRunning', false)) {
                GM_setValue('countdownRunning', true);
                this.startTime = Date.now();
                this.start();
            } else {
                const elapsed = Math.floor((Date.now() - GM_getValue('countdownStartTime')) / 1000);
                this.remaining = Math.max(config.countdownDuration - elapsed, 0);
                this.start();
            }
        }

        start() {
            GM_setValue('countdownStartTime', Date.now());
            this.timer = setInterval(() => {
                this.remaining--;
                GM_setValue('countdownRemaining', this.remaining);

                if (this.remaining <= 0) {
                    this.handleTimeout();
                    return;
                }

                this.updateDisplay();
            }, 1000);
        }

        updateDisplay() {
            const minutes = Math.floor(this.remaining / 60);
            const seconds = this.remaining % 60;
            indicator.querySelector('.countdown-display').textContent =
                `下次刷新: ${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
        }

        handleTimeout() {
            clearInterval(this.timer);
            GM_setValue('countdownRunning', false);
            GM_setValue('countdownRemaining', config.countdownDuration);

            if (1) {
                this.notify('60分钟倒计时结束,返回课程中心');
                window.location.href = 'https://www.hnsydwpx.cn/mineCourse';
            } else {
                // 如果在课程中心页面则重新开始倒计时
                this.remaining = config.countdownDuration;
                this.init();
            }
        }

        notify(message) {
            if (config.debugMode) {
                GM_notification({
                    title: `[倒计时通知]`,
                    text: message,
                    timeout: 5000
                });
            }
        }
    }


    // 解决自动播放问题的视频控制器
    class VideoController {
        constructor() {
            this.player = null;
            this.retryCount = 0;
            this.isWaitingInteraction = false;
            this.init();
        }

        async init() {
            try {
                this.player = await this.waitForElement('#coursePlayer video');
                this.addFakeInteractionLayer();
                this.startMonitoring();
                this.notify('视频控制器已启动');
            } catch (error) {
                this.notify(`初始化失败: ${error.message}`, 'error');
                indicator.classList.add('error');
                indicator.textContent = '脚本初始化失败';
            }
        }

        // 添加伪交互层解决自动播放限制
        addFakeInteractionLayer() {
            GM_addStyle(`
                .interaction-overlay {
                    position: fixed;
                    top: 0;
                    left: 0;
                    width: 100%;
                    height: 100%;
                    background: transparent;
                    z-index: 9998;
                    cursor: pointer;
                }
                .interaction-notice {
                    position: fixed;
                    bottom: 80px;
                    right: 20px;
                    background: rgba(0,0,0,0.7);
                    color: white;
                    padding: 10px 15px;
                    border-radius: 4px;
                    z-index: 9999;
                    max-width: 300px;
                    font-size: 14px;
                    text-align: center;
                    box-shadow: 0 2px 10px rgba(0,0,0,0.5);
                }
            `);

            // 创建覆盖层
            const overlay = document.createElement('div');
            overlay.className = 'interaction-overlay';
            overlay.onclick = () => this.handleUserInteraction();
            document.body.appendChild(overlay);

            // 添加提示
            const notice = document.createElement('div');
            notice.className = 'interaction-notice';
            notice.innerHTML = '点击页面任意位置激活自动播放功能<br><small>3秒后自动尝试播放</small>';
            document.body.appendChild(notice);

            this.isWaitingInteraction = true;
            setTimeout(() => {
                if (this.isWaitingInteraction) {
                    this.handleUserInteraction();
                    notice.innerHTML = '已自动激活播放功能';
                    setTimeout(() => notice.remove(), 2000);
                }
            }, config.interactionWait);
        }

        // 处理用户交互
        handleUserInteraction() {
            if (!this.isWaitingInteraction) return;

            this.isWaitingInteraction = false;
            document.querySelector('.interaction-overlay')?.remove();
            document.querySelector('.interaction-notice')?.remove();

            // 首次播放需要用户触发
            this.playVideo().then(() => {
                this.notify('用户交互后自动播放已启动');
            }).catch(error => {
                this.notify(`交互后播放失败: ${error}`, 'error');
            });
        }

        // 开始监控
        startMonitoring() {
            this.monitorInterval = setInterval(() => {
                if (!this.isWaitingInteraction && this.player.paused && !this.player.ended) {
                    this.playVideo();
                }
            }, config.checkInterval);

            // 监听视频事件
            this.player.addEventListener('pause', () => {
                if (!this.isWaitingInteraction) {
                    this.notify('检测到视频暂停,尝试恢复');
                    this.playVideo();
                    removeSpecificOverlays();
                }
            });

            this.player.addEventListener('ended', () => {
                this.notify('当前视频播放完毕');
                this.nextChapter();
            });
        }

        // 播放视频(处理自动播放限制)
        async playVideo() {
            if (this.retryCount >= config.maxRetry) {
                this.notify('达到最大重试次数,请手动点击播放', 'error');
                GM_notification({
                    title: '自动播放被阻止',
                    text: '请手动点击播放按钮',
                    timeout: 5000
                });
                indicator.classList.add('error');
                indicator.textContent = '自动播放被阻止';
                return;
            }

            try {
                const playPromise = this.player.play();

                if (playPromise !== undefined) {
                    await playPromise;
                    this.retryCount = 0;
                    this.notify('不用慌,视频已经播放成功啦!哈哈ヾ(≧▽≦*)o');
                    indicator.classList.remove('error');
                    indicator.innerHTML = '阿唐刷课机运行中……<div class="pro-label">Pro</div> <div class="countdown-display"></div>';
                }
            } catch (error) {
                this.retryCount++;
                this.notify(`播放失败 (${this.retryCount}/${config.maxRetry}): ${error}`, 'error');

                // 尝试通过点击按钮播放
                const playBtn = await this.waitForElement('.xgplayer-play', document, 1000).catch(() => null);
                if (playBtn) {
                    playBtn.click();
                    this.notify('已尝试点击播放按钮');
                }

                // 直接尝试静音播放
                if (this.retryCount >= 1) {
                    this.player.muted = true;
                    this.player.play().catch(e => this.notify(`静音播放也失败: ${e}`, 'error'));
                }
            }
        }

        // 切换到下一章节
        nextChapter() {
            const items = document.querySelectorAll('li[data-v-290b612e]');
            for (let item of items) {
                const progress = item.querySelector('.progress')?.textContent.trim();
                if (progress === '0%') {
                    item.click();
                    this.notify(`切换到未完成章节: ${item.querySelector('.name').textContent}`);
                    // 点击后等待视频加载并开始播放
                    setTimeout(() => this.playVideo(), 2000);
                    return;
                }
            }
            this.notify('所有章节已完成,返回课程中心');
            window.location.href = 'https://www.hnsydwpx.cn/mineCourse';
        }

        // 等待元素出现
        waitForElement(selector, parent = document, timeout = 10000) {
            return new Promise((resolve, reject) => {
                const startTime = Date.now();
                const check = () => {
                    const el = parent.querySelector(selector);
                    if (el) {
                        resolve(el);
                    } else if (Date.now() - startTime < timeout) {
                        setTimeout(check, 500);
                    } else {
                        reject(new Error(`元素未找到: ${selector}`));
                    }
                };
                check();
            });
        }

        // 弹窗通知
        notify(message, type = 'info') {
            if (config.debugMode) {
                GM_notification({
                    title: `[唐跃翔的视频控制]`,
                    text: message,
                    timeout: 5000
                });
            }
        }
    }

    function removeSpecificOverlays() {
            // 获取所有匹配的元素
            const overlays = document.querySelectorAll('.el-overlay');

            // 遍历并删除每个元素
            overlays.forEach(overlay => {
                // 检查内部是否有特定的内容

                        overlay.remove();


            });
        }



    // 页面初始化
    function check2425(items,index) {
        items[index].click();
        setTimeout(() => {
            //先检查元素是否存在
            const lists = document.querySelectorAll('.el-tab-pane .el-row .list_title');
            let button;
            if (lists.length) {
                if(index)console.log('2024年章节未完成,程序优先学习2024年章节!');
                for (let list of lists){
                    let text;
                    if((text = list.querySelector('.el-progress__text span').innerText) === '100%')continue;
                    console.log('第一个未学完的视频进度为:',text);
                    button = list.querySelector('button');
                    try {
                        button.click();break;
                    } catch (clickError) {
                        console.log('点击操作失败:', clickError);

                    }
                }
            } else {
                console.log('2024已经完成,学习2025年课程!');
                if(!index)console.log('全部完成啦!');
                else check2425(items,0);
            }

            new VideoController();
        },2000);
    }

    function init() {
         // 初始化倒计时
        new CountdownManager();


        // 只在对视频页面启用
        if (location.pathname.includes('/videoPlayback') ||
            location.pathname.includes('/getcourseDetails')) {
            new VideoController();
        }else if(!(location.pathname.includes('/mineCourse'))){
           window.location.href = 'https://www.hnsydwpx.cn/mineCourse';
        }else if(location.pathname.includes('/mineCourse')){
            setTimeout(() => {
                console.log('go to my course');
                const items = document.querySelectorAll('.years div[data-v-6a18900e]');
                check2425(items,1);
            }, 2000);
        }
    }

    // 启动脚本
    if (document.readyState === 'complete') {
        init();
    } else {
        window.addEventListener('load', init);
    }
})();