Greasy Fork

Greasy Fork is available in English.

内蒙古继续教育网站自动刷课脚本 (整合版)

内蒙古继续教育网站自动刷课脚本,默认不自动播放,只检测已完成状态

// ==UserScript==
// @name         内蒙古继续教育网站自动刷课脚本 (整合版)
// @namespace    http://tampermonkey.net/
// @version      2025.04.22.02
// @description  内蒙古继续教育网站自动刷课脚本,默认不自动播放,只检测已完成状态
// @author       request101
// @match        *://*.chinahrt.cn/*
// @match        *://*.chinahrt.com/*
// @match        *://*.chinahrt.com.cn/*
// @match        *://*.chinaedu.net/*
// @match        *://*.nmgbfrc.chinahrt.cn/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';
    
    // 全局变量
    let globalVideoElement = null;
    let processedUrls = [];
    let playlist = [];
    let lastJumpTime = 0;
    const JUMP_COOLDOWN = 3000; // 3秒冷却时间
    let jumpRetryCount = 0;
    const MAX_JUMP_RETRIES = 3;
    
    // 配置
    const config = {
        autoPlay: false,     // 自动播放(默认关闭)
        mute: true,          // 静音
        drag: 5,             // 拖动时间(秒)
        speed: 1.5,          // 播放速度
        playMode: 'loop',    // 播放模式:loop(循环), single(单个)
        skipCompleted: true, // 跳过已完成课程
        debug: true          // 调试模式
    };
    
    // 初始化
    function init() {
        // 加载配置
        loadConfig();
        
        // 初始化样式
        initStyles();
        
        // 创建调试面板
        if (config.debug) {
            createDebugPanel();
        }
        
        // 初始化路由
        initRouter();
    }
    
    // 加载配置
    function loadConfig() {
        // 从localStorage加载配置
        const savedConfig = localStorage.getItem('chinahrtConfig');
        if (savedConfig) {
            try {
                const parsedConfig = JSON.parse(savedConfig);
                Object.assign(config, parsedConfig);
            } catch (e) {
                logDebugInfo('配置加载失败:', e);
            }
        }
        
        logDebugInfo('配置加载完成', config);
    }
    
    // 保存配置
    function saveConfig() {
        try {
            localStorage.setItem('chinahrtConfig', JSON.stringify(config));
            logDebugInfo('配置已保存');
        } catch (e) {
            logDebugInfo('配置保存失败:', e);
        }
    }
    
    // 增强的调试信息函数
    function logDebugInfo(message, data) {
        if (config.debug) {
            const timestamp = new Date().toISOString().substr(11, 8); // 获取时:分:秒
            
            if (data) {
                console.log(`[ChinaHRT调试 ${timestamp}] ${message}`, data);
            } else {
                console.log(`[ChinaHRT调试 ${timestamp}] ${message}`);
            }
            
            // 将日志添加到页面上的调试面板(如果存在)
            const debugPanel = document.getElementById('debug-panel');
            if (debugPanel) {
                const logEntry = document.createElement('div');
                logEntry.textContent = `${timestamp} - ${message}`;
                debugPanel.appendChild(logEntry);
                
                // 限制日志条目数量,避免过多
                while (debugPanel.children.length > 50) {
                    debugPanel.removeChild(debugPanel.firstChild);
                }
                
                // 自动滚动到底部
                debugPanel.scrollTop = debugPanel.scrollHeight;
            }
        }
    }
    
    // 跳转日志函数
    function logJumpInfo(message, data) {
        // 添加特殊标记,便于在日志中区分跳转相关信息
        logDebugInfo(`[跳转] ${message}`, data);
    }
    
    // 创建调试面板
    function createDebugPanel() {
        // 如果已存在,则不重复创建
        if (document.getElementById('debug-panel')) {
            return;
        }
        
        // 创建调试面板
        const debugPanel = document.createElement('div');
        debugPanel.id = 'debug-panel';
        debugPanel.style.cssText = `
            position: fixed;
            bottom: 10px;
            right: 10px;
            width: 400px;
            height: 200px;
            background-color: rgba(0, 0, 0, 0.8);
            color: #fff;
            font-family: monospace;
            font-size: 12px;
            padding: 10px;
            overflow-y: auto;
            z-index: 10000;
            border-radius: 5px;
            display: none;
        `;
        
        // 创建标题和控制按钮
        const header = document.createElement('div');
        header.style.cssText = `
            display: flex;
            justify-content: space-between;
            margin-bottom: 5px;
            border-bottom: 1px solid #555;
            padding-bottom: 5px;
        `;
        
        const title = document.createElement('span');
        title.textContent = '调试日志';
        
        const closeButton = document.createElement('button');
        closeButton.textContent = '关闭';
        closeButton.style.cssText = `
            background: none;
            border: none;
            color: #fff;
            cursor: pointer;
        `;
        closeButton.onclick = function() {
            debugPanel.style.display = 'none';
        };
        
        header.appendChild(title);
        header.appendChild(closeButton);
        debugPanel.appendChild(header);
        
        // 添加到页面
        document.body.appendChild(debugPanel);
        
        // 添加快捷键切换显示/隐藏
        document.addEventListener('keydown', function(e) {
            // Alt+D 切换调试面板
            if (e.altKey && e.key === 'd') {
                debugPanel.style.display = debugPanel.style.display === 'none' ? 'block' : 'none';
            }
            
            // Alt+J 触发跳转
            if (e.altKey && e.key === 'j') {
                logJumpInfo('用户手动触发跳转');
                handleCourseCompleted(true); // 强制跳转
            }
            
            // Alt+P 调试播放列表
            if (e.altKey && e.key === 'p') {
                debugPlaylist();
            }
        });
        
        return debugPanel;
    }
    
    // 调试播放列表
    function debugPlaylist() {
        logDebugInfo('播放列表调试信息:');
        logDebugInfo(`播放列表长度: ${playlist.length}`);
        
        for (let i = 0; i < playlist.length; i++) {
            logDebugInfo(`[${i}] ${playlist[i].title} - ${playlist[i].url}`);
        }
        
        // 获取当前URL
        const currentUrl = window.location.href;
        logDebugInfo(`当前URL: ${currentUrl}`);
        
        // 尝试查找当前URL在播放列表中的位置
        let found = false;
        for (let i = 0; i < playlist.length; i++) {
            if (isSameUrl(playlist[i].url, currentUrl)) {
                logDebugInfo(`当前URL在播放列表中的位置: ${i}`);
                found = true;
                break;
            }
        }
        
        if (!found) {
            logDebugInfo('当前URL不在播放列表中');
        }
    }
    
    // 初始化样式
    function initStyles() {
        logDebugInfo('初始化样式');
        
        const style = document.createElement('style');
        style.textContent = `
            .autoPlayBox { padding: 5px 10px; }
            .autoPlayBox .title {  color: blue; }
            .autoPlayBox label {  margin-right: 6px; display: inline-block; cursor: pointer; }
            .autoPlayBox label input {  margin-left: 4px; cursor: pointer; }
            .canPlaylist {  width: 300px;  height: auto;  position: fixed;  top: 20px;  background: rgba(255, 255, 255, 1);  left: 20px;  border: 1px solid #c1c1c1;  overflow-y: auto; z-index: 10000; padding: 10px; }
            .canPlaylist .oneClick {  margin: 0 auto;  width: 100%;  border: none;  padding: 6px 0;  background: linear-gradient(180deg, #4BCE31, #4bccf2);  height: 50px;  border-radius: 5px;  color: #FFF;  font-weight: bold;  letter-spacing: 4px;  font-size: 18px; cursor: pointer; }
            .canPlaylist .oneClear {  margin: 5px auto;  width: 100%;  border: none;  padding: 6px 0;  background: linear-gradient(180deg, #f24b4b, #f2994b);  height: 50px;  border-radius: 5px;  color: #FFF;  font-weight: bold;  letter-spacing: 4px;  font-size: 18px; cursor: pointer; }
            .canPlaylist .item {  border-bottom: 1px solid #c1c1c1;  padding: 8px;  line-height: 150%;  border-bottom: 1px solid #c1c1c1;  margin-bottom: 3px; }
            .canPlaylist .item .title {  font-size: 13px;  white-space: nowrap;  overflow: hidden;  text-overflow: ellipsis; }
            .canPlaylist .item .status {  font-size: 12px;  white-space: nowrap;  overflow: hidden;  text-overflow: ellipsis;  color: #c90000; }
            .canPlaylist .item .addBtn {  color: #FFF;  background-color: #4bccf2;  border: none;  padding: 5px 10px;  margin-top: 4px; cursor: pointer; }
            .canPlaylist .item .addBtn.remove {  background-color: #fd1952; }
            .dragBox {  padding: 5px 10px; }
            .dragBox .title {  color: blue; }
            .dragBox .remark {  font-size: 12px;  color: #fc1818; }
            .dragBox label {  margin-right: 6px; display: inline-block; cursor: pointer; }
            .dragBox label input {  margin-left: 4px; cursor: pointer; }
            .multiSegmentBox {  position: fixed;  right: 255px;  top: 0;  width: 250px;  height: 280px;  background-color: #FFF;  z-index: 9999;  border: 1px solid #ccc;  font-size: 12px; }
            .multiSegmentBox .tip {  border-bottom: 1px solid #ccc;  padding: 5px;  font-weight: bold;  color: red; }
            .multiSegmentBox .item {  font-size: 14px; }
            .multiSegmentBox label {  margin-right: 3px; display: inline-block; cursor: pointer; }
            .multiSegmentBox label input {  margin-left: 2px; cursor: pointer; }
            .muteBox {  padding: 5px 10px; }
            .muteBox .title {  color: blue; }
            .muteBox .remark {  font-size: 12px;  color: #fc1818; }
            .muteBox label {  margin-right: 6px; display: inline-block; cursor: pointer; }
            .muteBox label input {  margin-left: 4px; cursor: pointer; }
            .controllerBox {  position: fixed;  right: 0;  top: 0;  width: 250px;  height: 280px;  background-color: #FFF;  z-index: 9999;  border: 1px solid #ccc;  overflow-y: auto;  font-size: 12px; }
            .controllerBox .linksBox {  display: flex;  flex-wrap: wrap;  justify-content: space-between;  height: 30px;  line-height: 30px;  font-weight: bold;  border-bottom: 1px dotted; }
            .playlistBox {  position: fixed;  right: 0;  top: 290px;  width: 300px;  height: 450px;  background-color: #FFF;  z-index: 9999;  border: 1px solid #ccc;  overflow-y: auto; }
            .playlistBox .oneClear {  width: 100%;  border: none;  padding: 6px 0;  background: linear-gradient(180deg, #f24b4b, #f2994b);  height: 50px;  border-radius: 5px;  color: #FFF;  font-weight: bold;  letter-spacing: 4px;  font-size: 18px;  cursor: pointer;  margin-bottom: 5px; }
            .playlistBox .playlistItem {  display: flex;  justify-content: space-between;  align-items: center;  margin-bottom: 5px; padding: 5px; border-bottom: 1px solid #eee; }
            .playlistBox .playlistItem .child_title {  font-size: 13px;  overflow: hidden;  text-overflow: ellipsis;  width: 180px; display: block; max-height: 40px; }
            .playlistBox .playlistItem .child_remove {  color: #FFF;  background-color: #fd1952;  border: none;  padding: 5px 10px;  cursor: pointer; }
            .playlistBox .playlistItem .child_play {  color: #FFF;  background-color: #4BCE31;  border: none;  padding: 5px 10px;  cursor: pointer;  margin-right: 5px; }
            .speedBox {  padding: 5px 10px; }
            .speedBox .title {  color: blue; }
            .speedBox .remark {  font-size: 12px;  color: #fc1818; }
            .speedBox label {  margin-right: 6px; display: inline-block; cursor: pointer; }
            .speedBox label input {  margin-left: 4px; cursor: pointer; }
            .skipCompletedBox { padding: 5px 10px; }
            .skipCompletedBox .title { color: blue; }
            .skipCompletedBox label { margin-right: 6px; display: inline-block; cursor: pointer; }
            .skipCompletedBox label input { margin-left: 4px; cursor: pointer; }
            .tooltip { position: absolute; background: rgba(0,0,0,0.8); color: white; padding: 5px; border-radius: 3px; z-index: 10001; max-width: 300px; }
        `;
        
        document.head.appendChild(style);
        logDebugInfo('样式初始化完成');
    }
    
    // 初始化路由
    function initRouter() {
        logDebugInfo('初始化路由');
        
        // 获取当前页面类型
        const pageType = currentPageType();
        
        // 根据页面类型执行不同的初始化
        switch (pageType) {
            case 1: // 视频列表页面
                initVideoListPage();
                break;
            case 2: // 视频播放页面
                initVideoPlayPage();
                break;
            case 3: // 我的课程页面
                // 不需要任何功能框
                break;
            case 4: // 课程学习页面
                logDebugInfo('课程学习页面,只显示简化版UI');
                initSimplifiedCoursePage();
                break;
            default:
                // 其他页面不做处理
                break;
        }
    }
    
    // 获取当前页面类型
    function currentPageType() {
        const pathname = window.location.pathname;
        const href = window.location.href;
        
        logDebugInfo('检查页面类型', {pathname, href});
        
        // 适配内蒙古网站的视频播放页面
        if (pathname.includes("/onlineVideo.asp")) {
            logDebugInfo('当前页面类型: 视频播放页面');
            return 2; // 视频播放页面
        }
        
        // 特殊处理course_study.asp页面
        if (pathname.includes("/course_study.asp")) {
            logDebugInfo('当前页面类型: 课程学习页面');
            return 4; // 课程学习页面 - 只显示简化版UI
        }
        
        // 特殊处理myCourses.asp页面
        if (pathname.includes("/myCourses.asp")) {
            logDebugInfo('当前页面类型: 我的课程页面');
            return 3; // 我的课程页面 - 不需要任何功能框
        }
        
        logDebugInfo('当前页面类型: 其他页面');
        return 0; // 其他页面
    }
    
    // 初始化视频列表页面
    function initVideoListPage() {
        logDebugInfo('初始化视频列表页面');
        
        // 创建可播放列表
        createCanPlaylist();
        
        // 创建控制面板
        createControllerBox();
        
        // 创建播放列表
        createPlaylistBox();
    }
    
    // 初始化视频播放页面
    function initVideoPlayPage() {
        logDebugInfo('初始化视频播放页面');
        
        // 创建控制面板
        createControllerBox();
        
        // 创建播放列表
        createPlaylistBox();
        
        // 阻止网站自身的自动播放
        preventAutoplay();
        
        // 初始化视频播放器
        initVideoPlayer();
        
        // 设置完成状态检查器
        setupCompletionChecker();
        
        // 设置DOM变化监听器
        setupDOMChangeListener();
        
        // 初始检查完成状态
        setTimeout(() => {
            if (checkCourseCompleted()) {
                logDebugInfo('初始检查:检测到课程已完成');
                handleCourseCompleted();
            }
        }, 2000);
    }
    
    // 阻止网站自身的自动播放
    function preventAutoplay() {
        logDebugInfo('尝试阻止网站自身的自动播放');
        
        // 方法1:覆盖原生play方法
        try {
            const originalPlay = HTMLMediaElement.prototype.play;
            HTMLMediaElement.prototype.play = function() {
                if (config.autoPlay) {
                    return originalPlay.apply(this);
                } else {
                    logDebugInfo('阻止了自动播放尝试');
                    return new Promise((resolve, reject) => {
                        reject(new DOMException('自动播放被阻止', 'NotAllowedError'));
                    });
                }
            };
            logDebugInfo('成功覆盖原生play方法');
        } catch (e) {
            logDebugInfo('覆盖原生play方法失败:', e);
        }
        
        // 方法2:监听并阻止自动播放事件
        document.addEventListener('play', function(e) {
            if (!config.autoPlay && e.target.tagName.toLowerCase() === 'video') {
                logDebugInfo('检测到自动播放事件,尝试阻止');
                e.target.pause();
                e.preventDefault();
            }
        }, true);
        
        // 方法3:定期检查并暂停所有视频
        if (!config.autoPlay) {
            const pauseInterval = setInterval(() => {
                const videos = document.querySelectorAll('video');
                for (const video of videos) {
                    if (!video.paused && !config.autoPlay) {
                        logDebugInfo('检测到正在播放的视频,尝试暂停');
                        video.pause();
                    }
                }
            }, 500); // 每500毫秒检查一次
            
            // 30秒后清除定期检查
            setTimeout(() => {
                clearInterval(pauseInterval);
                logDebugInfo('已清除定期暂停检查');
            }, 30000);
        }
    }
    
    // 初始化简化版课程列表页面
    function initSimplifiedCoursePage() {
        logDebugInfo('初始化简化版课程列表页面');
        
        // 创建简化版可播放列表
        createSimplifiedCanPlaylist();
    }
    
    // 创建简化版可播放列表
    function createSimplifiedCanPlaylist() {
        logDebugInfo('创建简化版可播放列表');
        
        let playlist = document.createElement("div");
        playlist.id = "canPlaylist";
        playlist.className = "canPlaylist";
        playlist.style.position = "fixed";
        playlist.style.top = "20px";
        playlist.style.left = "20px";
        playlist.style.width = "auto";
        playlist.style.height = "auto";
        playlist.style.padding = "10px";
        playlist.style.zIndex = "10000";
        
        playlist.innerHTML = `
            <button class="oneClick">一键添加所有视频</button>
            <button class="oneClear">一键清空播放列表</button>
            <div id="status" style="margin-top: 10px; color: blue;"></div>
        `;
        
        // 添加事件监听器
        const oneClickBtn = playlist.querySelector('.oneClick');
        if (oneClickBtn) {
            oneClickBtn.addEventListener('click', function() {
                oneClickAddAllVideos();
                // 添加状态反馈
                const statusDiv = document.getElementById('status');
                if (statusDiv) {
                    statusDiv.textContent = '正在添加视频...';
                    setTimeout(() => {
                        statusDiv.textContent = '视频添加完成!';
                    }, 1000);
                }
            });
        }
        
        const oneClearBtn = playlist.querySelector('.oneClear');
        if (oneClearBtn) {
            oneClearBtn.addEventListener('click', function() {
                clearPlaylist();
                // 添加状态反馈
                const statusDiv = document.getElementById('status');
                if (statusDiv) {
                    statusDiv.textContent = '播放列表已清空!';
                }
            });
        }
        
        document.body.appendChild(playlist);
        logDebugInfo('简化版可播放列表已添加到页面');
        return playlist;
    }
    
    // 创建可播放列表
    function createCanPlaylist() {
        let playlist = document.createElement("div");
        playlist.id = "canPlaylist";
        playlist.className = "canPlaylist";
        
        playlist.innerHTML = `
            <button class="oneClick">一键添加所有视频</button>
            <button class="oneClear">一键清空播放列表</button>
            <div id="videoList"></div>
        `;
        
        // 添加事件监听器
        const oneClickBtn = playlist.querySelector('.oneClick');
        if (oneClickBtn) {
            oneClickBtn.addEventListener('click', oneClickAddAllVideos);
        }
        
        const oneClearBtn = playlist.querySelector('.oneClear');
        if (oneClearBtn) {
            oneClearBtn.addEventListener('click', clearPlaylist);
        }
        
        document.body.appendChild(playlist);
        return playlist;
    }
    
    // 创建控制面板
    function createControllerBox() {
        let controllerBox = document.createElement("div");
        controllerBox.className = "controllerBox";
        
        controllerBox.innerHTML = `
            <div class="linksBox">
                <a href="javascript:;" onclick="toggleBox('autoPlayBox')">自动播放</a>
                <a href="javascript:;" onclick="toggleBox('muteBox')">静音</a>
                <a href="javascript:;" onclick="toggleBox('speedBox')">倍速</a>
                <a href="javascript:;" onclick="toggleBox('dragBox')">拖动</a>
                <a href="javascript:;" onclick="toggleBox('skipCompletedBox')">跳过已完成</a>
            </div>
            <div id="autoPlayBox" class="autoPlayBox" style="display: none;">
                <div class="title">自动播放</div>
                <label><input type="radio" name="autoPlay" value="1" ${config.autoPlay ? 'checked' : ''}>开启</label>
                <label><input type="radio" name="autoPlay" value="0" ${!config.autoPlay ? 'checked' : ''}>关闭</label>
            </div>
            <div id="muteBox" class="muteBox" style="display: none;">
                <div class="title">静音</div>
                <label><input type="radio" name="mute" value="1" ${config.mute ? 'checked' : ''}>开启</label>
                <label><input type="radio" name="mute" value="0" ${!config.mute ? 'checked' : ''}>关闭</label>
            </div>
            <div id="speedBox" class="speedBox" style="display: none;">
                <div class="title">倍速</div>
                <label><input type="radio" name="speed" value="1" ${config.speed === 1 ? 'checked' : ''}>1.0</label>
                <label><input type="radio" name="speed" value="1.25" ${config.speed === 1.25 ? 'checked' : ''}>1.25</label>
                <label><input type="radio" name="speed" value="1.5" ${config.speed === 1.5 ? 'checked' : ''}>1.5</label>
                <label><input type="radio" name="speed" value="2" ${config.speed === 2 ? 'checked' : ''}>2.0</label>
            </div>
            <div id="dragBox" class="dragBox" style="display: none;">
                <div class="title">拖动</div>
                <div class="remark">每30秒拖动一次</div>
                <label><input type="radio" name="drag" value="0" ${config.drag === 0 ? 'checked' : ''}>关闭</label>
                <label><input type="radio" name="drag" value="5" ${config.drag === 5 ? 'checked' : ''}>5秒</label>
                <label><input type="radio" name="drag" value="10" ${config.drag === 10 ? 'checked' : ''}>10秒</label>
                <label><input type="radio" name="drag" value="30" ${config.drag === 30 ? 'checked' : ''}>30秒</label>
            </div>
            <div id="skipCompletedBox" class="skipCompletedBox" style="display: none;">
                <div class="title">跳过已完成</div>
                <label><input type="radio" name="skipCompleted" value="1" ${config.skipCompleted ? 'checked' : ''}>开启</label>
                <label><input type="radio" name="skipCompleted" value="0" ${!config.skipCompleted ? 'checked' : ''}>关闭</label>
            </div>
        `;
        
        document.body.appendChild(controllerBox);
        
        // 添加事件监听器
        window.toggleBox = function(boxId) {
            toggleBox(boxId);
        };
        
        document.querySelectorAll('input[name="autoPlay"]').forEach(input => {
            input.addEventListener('change', function() {
                config.autoPlay = this.value === '1';
                saveConfig();
                
                if (globalVideoElement) {
                    if (config.autoPlay) {
                        globalVideoElement.play().catch(e => {
                            logDebugInfo('自动播放失败:', e);
                        });
                    } else {
                        globalVideoElement.pause();
                    }
                }
            });
        });
        
        document.querySelectorAll('input[name="mute"]').forEach(input => {
            input.addEventListener('change', function() {
                config.mute = this.value === '1';
                saveConfig();
                
                if (globalVideoElement) {
                    globalVideoElement.muted = config.mute;
                }
            });
        });
        
        document.querySelectorAll('input[name="speed"]').forEach(input => {
            input.addEventListener('change', function() {
                config.speed = parseFloat(this.value);
                saveConfig();
                
                if (globalVideoElement) {
                    globalVideoElement.playbackRate = config.speed;
                }
            });
        });
        
        document.querySelectorAll('input[name="drag"]').forEach(input => {
            input.addEventListener('change', function() {
                config.drag = parseInt(this.value);
                saveConfig();
            });
        });
        
        document.querySelectorAll('input[name="skipCompleted"]').forEach(input => {
            input.addEventListener('change', function() {
                config.skipCompleted = this.value === '1';
                saveConfig();
            });
        });
        
        return controllerBox;
    }
    
    // 切换显示/隐藏控制面板中的盒子
    function toggleBox(boxId) {
        const box = document.getElementById(boxId);
        if (box) {
            const isVisible = box.style.display !== 'none';
            
            // 隐藏所有盒子
            document.querySelectorAll('.controllerBox > div:not(.linksBox)').forEach(div => {
                div.style.display = 'none';
            });
            
            // 如果当前盒子是可见的,则隐藏它;否则显示它
            box.style.display = isVisible ? 'none' : 'block';
        }
    }
    
    // 创建播放列表
    function createPlaylistBox() {
        let playlistBox = document.createElement("div");
        playlistBox.className = "playlistBox";
        
        playlistBox.innerHTML = `
            <button class="oneClear">一键清空播放列表</button>
            <div id="playlistItems"></div>
        `;
        
        document.body.appendChild(playlistBox);
        
        // 添加事件监听器
        const oneClearBtn = playlistBox.querySelector('.oneClear');
        if (oneClearBtn) {
            oneClearBtn.addEventListener('click', clearPlaylist);
        }
        
        // 加载播放列表
        loadPlaylist();
        
        return playlistBox;
    }
    
    // 增强的播放列表加载函数
    function loadPlaylist() {
        // 从localStorage加载播放列表
        const savedPlaylist = localStorage.getItem('chinahrtPlaylist');
        if (savedPlaylist) {
            try {
                playlist = JSON.parse(savedPlaylist);
                logDebugInfo('播放列表加载成功,包含 ' + playlist.length + ' 个课程');
                
                // 验证播放列表数据的有效性
                let validItems = 0;
                for (let i = 0; i < playlist.length; i++) {
                    if (playlist[i] && playlist[i].url && playlist[i].title) {
                        validItems++;
                    }
                }
                
                if (validItems === 0) {
                    logDebugInfo('播放列表中没有有效项目,尝试重建');
                    rebuildPlaylist();
                } else {
                    updatePlaylistUI();
                }
            } catch (e) {
                logDebugInfo('播放列表加载失败:', e);
                rebuildPlaylist();
            }
        } else {
            logDebugInfo('未找到保存的播放列表,尝试重建');
            rebuildPlaylist();
        }
    }
    
    // 自动重建播放列表
    function rebuildPlaylist() {
        logDebugInfo('开始重建播放列表');
        playlist = [];
        
        // 尝试从当前页面提取课程信息
        const courseLinks = document.querySelectorAll('a[href*="course_study.asp"], a[href*="onlineVideo.asp"]');
        if (courseLinks && courseLinks.length > 0) {
            for (const link of courseLinks) {
                const url = link.href;
                const title = link.textContent.trim();
                
                if (url && title && !processedUrls.includes(url)) {
                    playlist.push({ url, title });
                    processedUrls.push(url);
                    logDebugInfo('从页面添加课程到播放列表:', title);
                }
            }
        }
        
        // 保存重建的播放列表
        savePlaylist();
        updatePlaylistUI();
        
        logDebugInfo('播放列表重建完成,包含 ' + playlist.length + ' 个课程');
    }
    
    // 更新播放列表UI
    function updatePlaylistUI() {
        const playlistItems = document.getElementById('playlistItems');
        if (!playlistItems) return;
        
        // 清空播放列表UI
        playlistItems.innerHTML = '';
        
        // 添加播放列表项
        for (let i = 0; i < playlist.length; i++) {
            const item = playlist[i];
            
            const itemDiv = document.createElement('div');
            itemDiv.className = 'playlistItem';
            
            itemDiv.innerHTML = `
                <span class="child_title">${item.title}</span>
                <div>
                    <button class="child_play">播放</button>
                    <button class="child_remove">删除</button>
                </div>
            `;
            
            // 添加播放按钮事件
            const playButton = itemDiv.querySelector('.child_play');
            playButton.addEventListener('click', function() {
                window.location.href = item.url;
            });
            
            // 添加删除按钮事件
            const removeButton = itemDiv.querySelector('.child_remove');
            removeButton.addEventListener('click', function() {
                playlist.splice(i, 1);
                savePlaylist();
                updatePlaylistUI();
            });
            
            playlistItems.appendChild(itemDiv);
        }
    }
    
    // 保存播放列表
    function savePlaylist() {
        try {
            localStorage.setItem('chinahrtPlaylist', JSON.stringify(playlist));
            logDebugInfo('播放列表已保存,包含 ' + playlist.length + ' 个课程');
        } catch (e) {
            logDebugInfo('播放列表保存失败:', e);
        }
    }
    
    // 清空播放列表
    function clearPlaylist() {
        playlist = [];
        processedUrls = [];
        savePlaylist();
        updatePlaylistUI();
        logDebugInfo('播放列表已清空');
    }
    
    // 一键添加所有视频
    function oneClickAddAllVideos() {
        logDebugInfo('开始一键添加所有视频');
        
        // 清空已处理的URL列表
        processedUrls = [];
        
        // 尝试多种选择器来获取视频链接
        const selectors = [
            '#cc li a',                // 标准选择器
            '.ui-bxkc li a',           // 内蒙古网站特定选择器
            '.chapter-list li a',      // 通用选择器
            'a[href*="onlineVideo.asp"]', // 基于URL的选择器
            '.video-item a',           // 通用视频项选择器
            '#videoList a'             // 视频列表选择器
        ];
        
        let videoLinks = null;
        
        // 尝试每个选择器,直到找到视频链接
        for (const selector of selectors) {
            const elements = document.querySelectorAll(selector);
            if (elements && elements.length > 0) {
                videoLinks = elements;
                logDebugInfo(`使用选择器 "${selector}" 找到 ${elements.length} 个视频链接`);
                break;
            }
        }
        
        // 如果没有找到视频链接,尝试更通用的方法
        if (!videoLinks || videoLinks.length === 0) {
            // 尝试查找所有可能是视频链接的元素
            const allLinks = document.querySelectorAll('a');
            const possibleVideoLinks = Array.from(allLinks).filter(link => {
                const href = link.href || '';
                return href.includes('onlineVideo.asp') || href.includes('course_study.asp');
            });
            
            if (possibleVideoLinks.length > 0) {
                videoLinks = possibleVideoLinks;
                logDebugInfo(`使用通用方法找到 ${possibleVideoLinks.length} 个可能的视频链接`);
            }
        }
        
        // 如果仍然没有找到视频链接,返回
        if (!videoLinks || videoLinks.length === 0) {
            logDebugInfo('未找到视频链接');
            return;
        }
        
        // 处理每个视频链接
        for (const link of videoLinks) {
            const url = link.href;
            // 提取视频名称,去除可能的图标和状态文本
            let title = link.textContent.trim();
            title = title.replace(/已完成/g, '').trim();
            title = title.replace(/\s*\d+%\s*/g, '').trim();
            
            // 如果链接有效且不在已处理列表中
            if (url && title && !processedUrls.includes(url)) {
                // 添加到播放列表
                playlist.push({ url, title });
                processedUrls.push(url);
                logDebugInfo('添加视频到播放列表:', title);
            }
        }
        
        // 保存播放列表
        savePlaylist();
        
        // 更新播放列表UI
        updatePlaylistUI();
        
        logDebugInfo('一键添加所有视频完成,共添加 ' + playlist.length + ' 个视频');
    }
    
    // 初始化视频播放器
    function initVideoPlayer() {
        logDebugInfo('初始化视频播放器');
        
        // 查找视频元素
        const videoElements = document.querySelectorAll('video');
        if (!videoElements || videoElements.length === 0) {
            logDebugInfo('未找到视频元素,尝试等待视频加载');
            
            // 等待视频元素加载
            setTimeout(initVideoPlayer, 1000);
            return;
        }
        
        // 使用第一个视频元素
        const videoElement = videoElements[0];
        globalVideoElement = videoElement;
        
        logDebugInfo('找到视频元素:', videoElement);
        
        // 立即设置autoplay属性为false,防止首次加载时自动播放
        videoElement.autoplay = false;
        
        // 立即暂停视频,确保不会自动播放
        videoElement.pause();
        
        // 应用视频设置
        applyVideoSettings();
        
        // 添加视频事件监听器
        addVideoEventListeners(videoElement);
        
        // 如果配置了自动播放,尝试播放视频
        if (config.autoPlay) {
            videoElement.play().catch(e => {
                logDebugInfo('自动播放失败:', e);
                
                // 如果自动播放失败,尝试静音后再播放
                videoElement.muted = true;
                videoElement.play().catch(e => {
                    logDebugInfo('静音后自动播放仍然失败:', e);
                });
            });
        } else {
            logDebugInfo('自动播放已关闭,不自动播放视频');
            // 再次确保视频是暂停状态
            videoElement.pause();
        }
    }
    
    // 应用视频设置
    function applyVideoSettings() {
        if (!globalVideoElement) return;
        
        logDebugInfo('应用视频设置:', config);
        
        // 设置自动播放
        if (config.autoPlay) {
            globalVideoElement.autoplay = true;
            globalVideoElement.play().catch(e => {
                logDebugInfo('自动播放失败:', e);
                
                // 如果自动播放失败,尝试静音后再播放
                globalVideoElement.muted = true;
                globalVideoElement.play().catch(e => {
                    logDebugInfo('静音后自动播放仍然失败:', e);
                });
            });
        } else {
            globalVideoElement.autoplay = false;
            logDebugInfo('自动播放已关闭,视频将不会自动播放');
        }
        
        // 设置静音
        globalVideoElement.muted = config.mute;
        
        // 设置播放速度
        globalVideoElement.playbackRate = config.speed;
        
        // 设置拖动
        if (config.drag > 0) {
            // 每隔一段时间拖动视频
            setInterval(() => {
                if (globalVideoElement && !globalVideoElement.paused && globalVideoElement.duration > 0) {
                    // 计算新的播放位置
                    let newTime = globalVideoElement.currentTime + config.drag;
                    
                    // 确保不超过视频总时长
                    if (newTime < globalVideoElement.duration - 5) {
                        globalVideoElement.currentTime = newTime;
                    }
                }
            }, 30000); // 每30秒拖动一次
        }
    }
    
    // 增强的视频事件监听器
    function addVideoEventListeners(videoElement) {
        // 视频播放结束事件
        videoElement.addEventListener('ended', function() {
            logDebugInfo('视频播放结束');
            
            // 延迟检查,给页面状态更新的时间
            setTimeout(() => {
                // 检查课程是否已完成
                if (checkCourseCompleted()) {
                    logDebugInfo('视频结束:检测到完成状态');
                    handleCourseCompleted(true); // 强制跳转
                }
            }, 2000); // 增加延迟时间
        });
        
        // 视频时间更新事件
        videoElement.addEventListener('timeupdate', function() {
            // 只在视频接近结束时检查
            if (videoElement.duration > 0 && 
                videoElement.currentTime > 0 && 
                videoElement.currentTime / videoElement.duration > 0.95) {
                
                // 限制检查频率,避免频繁检查
                if (!videoElement._lastTimeUpdateCheck || 
                    Date.now() - videoElement._lastTimeUpdateCheck > 2000) {
                    
                    videoElement._lastTimeUpdateCheck = Date.now();
                    
                    // 检查是否已完成
                    if (checkCourseCompleted()) {
                        logDebugInfo('timeupdate事件:检测到完成状态');
                        handleCourseCompleted();
                    }
                }
            }
        });
        
        // 视频进度事件
        videoElement.addEventListener('progress', function() {
            // 检查是否已完成
            if (checkCourseCompleted()) {
                logDebugInfo('progress事件:检测到完成状态');
                handleCourseCompleted();
            }
        });
        
        // 视频错误事件
        videoElement.addEventListener('error', function(e) {
            logDebugInfo('视频播放错误:', e);
            
            // 尝试恢复播放
            setTimeout(() => {
                videoElement.load();
                if (config.autoPlay) {
                    videoElement.play();
                }
            }, 3000);
        });
        
        // 视频加载完成事件
        videoElement.addEventListener('loadedmetadata', function() {
            logDebugInfo('视频元数据加载完成,时长: ' + videoElement.duration + '秒');
            
            // 对于非常短的视频(小于5秒),可能是占位视频,直接视为完成
            if (videoElement.duration < 5) {
                logDebugInfo('视频时长小于5秒,可能是占位视频,直接视为完成');
                setTimeout(() => {
                    handleCourseCompleted();
                }, 1000);
            }
        });
    }
    
    // 设置完成状态检测
    function setupCompletionChecker() {
        logDebugInfo('设置完成状态检测');
        
        // 清除之前的检查间隔
        if (window.completionCheckInterval) {
            clearInterval(window.completionCheckInterval);
        }
        
        // 设置新的检查间隔
        window.completionCheckInterval = setInterval(() => {
            // 检查课程是否已完成
            if (checkCourseCompleted()) {
                logDebugInfo('定期检查:检测到完成状态');
                handleCourseCompleted();
            }
        }, 3000); // 每3秒检查一次
    }
    
    // 设置DOM变化监听器
    function setupDOMChangeListener() {
        // 创建MutationObserver
        const observer = new MutationObserver((mutations) => {
            // 检查是否有相关变化
            let hasRelevantChanges = false;
            
            for (const mutation of mutations) {
                // 检查是否有添加节点
                if (mutation.addedNodes.length > 0) {
                    for (const node of mutation.addedNodes) {
                        // 检查是否是元素节点
                        if (node.nodeType === Node.ELEMENT_NODE) {
                            // 检查是否包含完成状态相关的元素
                            if (node.id === 'jd_box' || 
                                node.classList.contains('pl30') ||
                                node.textContent.includes('已完成')) {
                                hasRelevantChanges = true;
                                break;
                            }
                        }
                    }
                }
                
                // 检查是否有属性变化
                if (!hasRelevantChanges && mutation.type === 'attributes') {
                    const target = mutation.target;
                    
                    // 检查是否是完成状态相关的属性变化
                    if (target.id === 'jd_box' || 
                        target.classList.contains('pl30') ||
                        (mutation.attributeName === 'class' && target.classList.contains('completed'))) {
                        hasRelevantChanges = true;
                    }
                }
                
                if (hasRelevantChanges) {
                    break;
                }
            }
            
            // 如果有相关变化,检查完成状态
            if (hasRelevantChanges) {
                logDebugInfo('检测到DOM变化,检查完成状态');
                
                // 延迟检查,给页面状态更新的时间
                setTimeout(() => {
                    if (checkCourseCompleted()) {
                        logDebugInfo('DOM变化后检测到完成状态');
                        handleCourseCompleted();
                    }
                }, 1000);
            }
        });
        
        // 开始观察
        observer.observe(document.body, {
            childList: true,
            attributes: true,
            subtree: true,
            attributeFilter: ['class', 'style', 'id']
        });
        
        // 保存观察器引用,以便后续可以停止观察
        window.domChangeObserver = observer;
        
        logDebugInfo('已设置DOM变化监听器');
    }
    
    // 检查课程是否已完成
    function checkCourseCompleted() {
        // 记录开始检测
        logDebugInfo('开始检测课程完成状态');
        
        // 记录所有检测方法的结果
        let detectionResults = [];
        
        // 方法1:检查jd_box元素
        const jdBox = document.getElementById('jd_box');
        const jdBoxResult = jdBox && jdBox.textContent.includes('已完成');
        detectionResults.push({method: 'jd_box', result: jdBoxResult});
        
        // 方法2:检查带pl30类的元素
        const pl30Elements = document.querySelectorAll('.pl30');
        let pl30Result = false;
        for (const element of pl30Elements) {
            if (element.textContent.includes('已完成')) {
                pl30Result = true;
                break;
            }
        }
        detectionResults.push({method: 'pl30', result: pl30Result});
        
        // 方法3:检查进度条
        const progressBars = document.querySelectorAll('.progress-bar, .progress');
        let progressBarResult = false;
        for (const progressBar of progressBars) {
            const style = window.getComputedStyle(progressBar);
            const width = parseFloat(style.width);
            const maxWidth = parseFloat(style.maxWidth) || 100;
            
            if (width / maxWidth >= 0.99) { // 如果进度达到99%
                progressBarResult = true;
                break;
            }
        }
        detectionResults.push({method: 'progress_bar', result: progressBarResult});
        
        // 方法4:检查状态文本
        const stateElements = document.querySelectorAll('.state, .status, .course-state, .course-status');
        let stateTextResult = false;
        for (const element of stateElements) {
            if (element.textContent.includes('已完成') || 
                element.textContent.includes('100%') ||
                element.textContent.includes('完成')) {
                stateTextResult = true;
                break;
            }
        }
        detectionResults.push({method: 'state_text', result: stateTextResult});
        
        // 方法5:检查完成图标
        const completedIcons = document.querySelectorAll('.completed-icon, .done-icon, .icon-completed, .icon-done');
        const completedIconResult = completedIcons.length > 0;
        detectionResults.push({method: 'completed_icon', result: completedIconResult});
        
        // 方法6:检查完成类
        const completedElements = document.querySelectorAll('.completed, .done, .finished');
        const completedClassResult = completedElements.length > 0;
        detectionResults.push({method: 'completed_class', result: completedClassResult});
        
        // 方法7:检查完成属性
        const elementsWithCompletedAttr = document.querySelectorAll('[data-completed="true"], [data-status="completed"], [data-state="completed"]');
        const completedAttrResult = elementsWithCompletedAttr.length > 0;
        detectionResults.push({method: 'completed_attr', result: completedAttrResult});
        
        // 方法8:检查全文
        const bodyText = document.body.textContent;
        const bodyTextResult = bodyText.includes('已完成学习') || 
                              bodyText.includes('学习已完成') || 
                              bodyText.includes('课程已完成');
        detectionResults.push({method: 'body_text', result: bodyTextResult});
        
        // 方法9:检查带有特定ID的元素
        const specificIdElements = [
            document.getElementById('complete-status'),
            document.getElementById('study-status'),
            document.getElementById('learning-status')
        ];
        let specificIdResult = false;
        for (const element of specificIdElements) {
            if (element && (
                element.textContent.includes('已完成') || 
                element.textContent.includes('100%') ||
                element.classList.contains('completed')
            )) {
                specificIdResult = true;
                break;
            }
        }
        detectionResults.push({method: 'specific_id', result: specificIdResult});
        
        // 方法10:检查内蒙古网站特定的完成标记
        const nmgSpecificElements = document.querySelectorAll('.ui-bxkc li a, .ui-bxkc li span');
        let nmgSpecificResult = false;
        for (const element of nmgSpecificElements) {
            if (element.textContent.includes('已完成') || 
                element.classList.contains('completed') ||
                element.classList.contains('done')) {
                nmgSpecificResult = true;
                break;
            }
        }
        detectionResults.push({method: 'nmg_specific', result: nmgSpecificResult});
        
        // 方法11:检查视频播放进度
        let videoProgressResult = false;
        if (globalVideoElement && globalVideoElement.duration > 0) {
            const progress = globalVideoElement.currentTime / globalVideoElement.duration;
            if (progress > 0.98) { // 如果进度超过98%
                videoProgressResult = true;
            }
        }
        detectionResults.push({method: 'video_progress', result: videoProgressResult});
        
        // 方法12:检查页面标题
        const titleResult = document.title.includes('已完成') || document.title.includes('100%');
        detectionResults.push({method: 'page_title', result: titleResult});
        
        // 记录检测结果
        logDebugInfo('完成状态检测结果:', detectionResults);
        
        // 记录每种方法的结果
        for (const result of detectionResults) {
            logDebugInfo(`方法 ${result.method}: ${result.result ? '已完成' : '未完成'}`);
        }
        
        // 计算有多少方法检测到完成
        const positiveResults = detectionResults.filter(r => r.result).length;
        
        // 如果至少两种方法检测到完成,直接确认完成
        if (positiveResults >= 2) {
            logDebugInfo('至少两种方法检测到完成,确认课程已完成');
            return true;
        }
        
        // 如果只有一种方法检测到完成,检查是哪种方法
        if (positiveResults === 1) {
            const positiveMethod = detectionResults.find(r => r.result).method;
            
            // 对于高可靠性的方法,可以单独确认完成
            const highReliabilityMethods = ['jd_box', 'pl30', 'progress_bar', 'state_text', 'nmg_specific'];
            if (highReliabilityMethods.includes(positiveMethod)) {
                logDebugInfo(`单一高可靠性方法 ${positiveMethod} 检测到完成,确认课程已完成`);
                return true;
            }
            
            // 对于其他方法,如果视频已接近结束,也可以确认完成
            if (globalVideoElement && globalVideoElement.duration > 0 && 
                globalVideoElement.currentTime / globalVideoElement.duration > 0.9) {
                logDebugInfo(`单一方法 ${positiveMethod} 检测到完成,且视频接近结束,确认课程已完成`);
                return true;
            }
        }
        
        // 特殊情况:如果视频已结束,也视为完成
        if (globalVideoElement && globalVideoElement.ended) {
            logDebugInfo('视频已结束,视为课程已完成');
            return true;
        }
        
        // 如果没有检测到完成
        logDebugInfo('未检测到课程完成状态');
        return false;
    }
    
    // 处理课程完成
    function handleCourseCompleted(forceJump = false) {
        logJumpInfo(`处理课程完成 (强制跳转: ${forceJump})`);
        
        // 检查是否在冷却期内
        const currentTime = Date.now();
        if (!forceJump && currentTime - lastJumpTime < JUMP_COOLDOWN) {
            logJumpInfo('跳转冷却中,忽略此次跳转请求');
            return;
        }
        
        // 如果是强制跳转,直接跳过确认
        if (forceJump) {
            logJumpInfo('强制跳转,跳过确认');
            lastJumpTime = currentTime;
            jumpToNextCourseWithRetry();
            return;
        }
        
        // 确认跳转
        if (confirmJump()) {
            logJumpInfo('跳转确认成功');
            lastJumpTime = currentTime;
            jumpToNextCourseWithRetry();
        } else {
            logJumpInfo('跳转确认失败,设置延迟重试');
            
            // 设置延迟重试
            setTimeout(() => {
                logJumpInfo('延迟重试跳转');
                if (confirmJump(true)) { // 延迟重试时强制确认
                    lastJumpTime = Date.now();
                    jumpToNextCourseWithRetry();
                }
            }, 5000); // 5秒后重试
        }
    }
    
    // 确认跳转
    function confirmJump(forceConfirm = false) {
        // 如果强制确认,直接返回true
        if (forceConfirm) {
            logJumpInfo('强制确认跳转');
            return true;
        }
        
        // 检查视频是否已结束
        const videoEnded = globalVideoElement && globalVideoElement.ended;
        if (videoEnded) {
            logJumpInfo('视频已结束,确认跳转');
            return true;
        }
        
        // 再次检查完成状态
        if (checkCourseCompleted()) {
            logJumpInfo('检测到完成状态,确认跳转');
            return true;
        }
        
        // 所有检查都未通过
        logJumpInfo('跳转确认失败');
        return false;
    }
    
    // 带重试的跳转
    function jumpToNextCourseWithRetry() {
        logJumpInfo(`尝试跳转到下一课程 (尝试次数: ${jumpRetryCount + 1}/${MAX_JUMP_RETRIES + 1})`);
        
        // 重置重试计数器(如果这是新的跳转尝试)
        if (window.lastJumpAttemptTime && Date.now() - window.lastJumpAttemptTime > 30000) {
            jumpRetryCount = 0;
        }
        
        // 记录本次尝试时间
        window.lastJumpAttemptTime = Date.now();
        
        // 尝试跳转
        jumpToNextCourse();
        
        // 设置重试
        if (jumpRetryCount < MAX_JUMP_RETRIES) {
            jumpRetryCount++;
            
            // 设置重试计时器
            setTimeout(() => {
                // 检查是否仍在同一页面
                if (window.location.href === window.lastJumpAttemptUrl) {
                    logJumpInfo(`跳转似乎失败,尝试重试 (${jumpRetryCount}/${MAX_JUMP_RETRIES})`);
                    jumpToNextCourseWithRetry();
                }
            }, 5000); // 5秒后重试
        } else {
            logJumpInfo(`达到最大重试次数 (${MAX_JUMP_RETRIES}),尝试其他方法`);
            jumpRetryCount = 0;
            
            // 尝试从播放列表中找到任何可用的课程
            const anyAvailableCourse = findAnyAvailableCourseInPlaylist();
            if (anyAvailableCourse) {
                logJumpInfo(`找到播放列表中的可用课程: ${anyAvailableCourse}`);
                setTimeout(() => {
                    window.location.href = anyAvailableCourse;
                }, 1000);
                return;
            }
            
            // 如果实在找不到任何课程,才尝试返回课程列表页面
            logJumpInfo('无法找到任何可用课程,返回课程列表页面');
            setTimeout(() => {
                // 使用历史记录返回,避免直接跳转到myCourses.asp
                history.back();
            }, 1000);
        }
        
        // 记录当前URL
        window.lastJumpAttemptUrl = window.location.href;
    }
    
    // 在播放列表中查找任何可用的课程
    function findAnyAvailableCourseInPlaylist() {
        logJumpInfo('尝试在播放列表中查找任何可用的课程');
        
        // 如果播放列表为空,尝试重新加载
        if (!playlist || playlist.length === 0) {
            logJumpInfo('播放列表为空,尝试重新加载');
            loadPlaylist();
            
            // 如果仍然为空,返回null
            if (!playlist || playlist.length === 0) {
                logJumpInfo('重新加载后播放列表仍为空');
                return null;
            }
        }
        
        // 获取当前URL
        const currentUrl = window.location.href;
        
        // 查找当前URL在播放列表中的索引
        let currentIndex = -1;
        for (let i = 0; i < playlist.length; i++) {
            if (isSameUrl(playlist[i].url, currentUrl)) {
                currentIndex = i;
                break;
            }
        }
        
        // 如果找到当前URL,优先返回下一个URL
        if (currentIndex !== -1 && currentIndex < playlist.length - 1) {
            return playlist[currentIndex + 1].url;
        }
        
        // 如果没有找到当前URL或当前URL是最后一个,返回第一个URL
        if (playlist.length > 0) {
            // 避免返回当前URL
            for (let i = 0; i < playlist.length; i++) {
                if (!isSameUrl(playlist[i].url, currentUrl)) {
                    return playlist[i].url;
                }
            }
        }
        
        // 如果实在找不到任何可用的课程,返回null
        return null;
    }
    
    // 跳转到下一课程
    function jumpToNextCourse() {
        logJumpInfo('开始跳转到下一课程');
        
        // 尝试跳转
        try {
            // 方法1:使用下一章节链接
            const nextChapterLink = getNextChapterLink();
            if (nextChapterLink) {
                logJumpInfo(`方法1:跳转到下一章节: ${nextChapterLink}`);
                
                // 使用setTimeout确保日志记录完成
                setTimeout(() => {
                    window.location.href = nextChapterLink;
                }, 100);
                return;
            }
            
            // 方法2:使用播放列表中的下一个课程
            const nextCourseInPlaylist = getNextCourseInPlaylist();
            if (nextCourseInPlaylist) {
                logJumpInfo(`方法2:跳转到播放列表中的下一个课程: ${nextCourseInPlaylist}`);
                
                // 使用setTimeout确保日志记录完成
                setTimeout(() => {
                    window.location.href = nextCourseInPlaylist;
                }, 100);
                return;
            }
            
            // 方法3:使用DOM操作点击下一课程链接
            if (clickNextCourseLink()) {
                logJumpInfo('方法3:通过点击下一课程链接跳转');
                return;
            }
            
            // 方法4:使用历史记录返回并刷新
            logJumpInfo('方法4:使用历史记录返回并刷新');
            setTimeout(() => {
                history.back();
                setTimeout(() => {
                    location.reload();
                }, 1000);
            }, 100);
        } catch (e) {
            logJumpInfo(`跳转失败: ${e.message}`);
            
            // 失败后尝试其他方法
            logJumpInfo(`跳转失败: ${e.message}`);
            
            // 尝试从播放列表中找到任何可用的课程
            const anyAvailableCourse = findAnyAvailableCourseInPlaylist();
            if (anyAvailableCourse) {
                logJumpInfo(`找到播放列表中的可用课程: ${anyAvailableCourse}`);
                setTimeout(() => {
                    window.location.href = anyAvailableCourse;
                }, 1000);
                return;
            }
            
            // 如果实在找不到任何课程,才尝试返回上一页
            logJumpInfo('无法找到任何可用课程,返回上一页');
            setTimeout(() => {
                history.back();
            }, 1000);
        }
    }
    
    // 通过DOM操作点击下一课程链接
    function clickNextCourseLink() {
        try {
            // 尝试查找各种可能的"下一课程"链接
            const nextLinkSelectors = [
                'a.next-course', 
                'a.next', 
                'a:contains("下一课程")', 
                'a:contains("下一章节")',
                '.ui-bxkc li.current + li a',
                '.course-list li.active + li a'
            ];
            
            for (const selector of nextLinkSelectors) {
                const links = document.querySelectorAll(selector);
                if (links.length > 0) {
                    logJumpInfo(`找到下一课程链接: ${selector}`);
                    links[0].click();
                    return true;
                }
            }
            
            return false;
        } catch (e) {
            logJumpInfo(`点击下一课程链接失败: ${e.message}`);
            return false;
        }
    }
    
    // 获取下一章节链接
    function getNextChapterLink() {
        try {
            // 尝试查找各种可能的章节链接
            const chapterLinkSelectors = [
                '.ui-bxkc li a',
                '.course-list li a',
                '.chapter-list li a',
                '#chapterList li a',
                '#cc li a'
            ];
            
            // 获取当前URL
            const currentUrl = window.location.href;
            
            // 查找所有章节链接
            let allChapterLinks = [];
            for (const selector of chapterLinkSelectors) {
                const links = document.querySelectorAll(selector);
                if (links.length > 0) {
                    allChapterLinks = Array.from(links);
                    break;
                }
            }
            
            // 如果没有找到章节链接,返回null
            if (allChapterLinks.length === 0) {
                return null;
            }
            
            // 查找当前章节的索引
            let currentIndex = -1;
            for (let i = 0; i < allChapterLinks.length; i++) {
                if (isSameUrl(allChapterLinks[i].href, currentUrl)) {
                    currentIndex = i;
                    break;
                }
            }
            
            // 如果找到当前章节,返回下一章节的链接
            if (currentIndex !== -1 && currentIndex < allChapterLinks.length - 1) {
                return allChapterLinks[currentIndex + 1].href;
            }
            
            return null;
        } catch (e) {
            logJumpInfo(`获取下一章节链接失败: ${e.message}`);
            return null;
        }
    }
    
    // 获取播放列表中的下一个课程
    function getNextCourseInPlaylist() {
        logJumpInfo('查找播放列表中的下一个课程');
        
        // 如果播放列表为空,尝试重新加载
        if (!playlist || playlist.length === 0) {
            logJumpInfo('播放列表为空,尝试重新加载');
            loadPlaylist();
            
            // 如果仍然为空,返回null
            if (!playlist || playlist.length === 0) {
                logJumpInfo('重新加载后播放列表仍为空');
                return null;
            }
        }
        
        // 获取当前URL
        const currentUrl = window.location.href;
        logJumpInfo(`当前URL: ${currentUrl}`);
        
        // 查找当前URL在播放列表中的索引
        let currentIndex = -1;
        
        // 方法1:完整URL匹配
        for (let i = 0; i < playlist.length; i++) {
            if (isSameUrl(playlist[i].url, currentUrl)) {
                currentIndex = i;
                logJumpInfo(`方法1:在播放列表中找到当前URL,索引: ${currentIndex}`);
                break;
            }
        }
        
        // 方法2:简化URL匹配(忽略查询参数)
        if (currentIndex === -1) {
            const simplifiedCurrentUrl = currentUrl.split('?')[0];
            for (let i = 0; i < playlist.length; i++) {
                const simplifiedPlaylistUrl = playlist[i].url.split('?')[0];
                if (simplifiedCurrentUrl === simplifiedPlaylistUrl) {
                    currentIndex = i;
                    logJumpInfo(`方法2:在播放列表中找到当前URL(简化匹配),索引: ${currentIndex}`);
                    break;
                }
            }
        }
        
        // 方法3:ID参数匹配
        if (currentIndex === -1) {
            const currentIdMatch = currentUrl.match(/[?&]id=(\d+)/);
            const currentGcidMatch = currentUrl.match(/[?&]gcid=(\d+)/);
            
            if (currentIdMatch || currentGcidMatch) {
                const currentId = currentIdMatch ? currentIdMatch[1] : null;
                const currentGcid = currentGcidMatch ? currentGcidMatch[1] : null;
                
                for (let i = 0; i < playlist.length; i++) {
                    const playlistUrl = playlist[i].url;
                    const playlistIdMatch = playlistUrl.match(/[?&]id=(\d+)/);
                    const playlistGcidMatch = playlistUrl.match(/[?&]gcid=(\d+)/);
                    
                    const playlistId = playlistIdMatch ? playlistIdMatch[1] : null;
                    const playlistGcid = playlistGcidMatch ? playlistGcidMatch[1] : null;
                    
                    if ((currentId && playlistId && currentId === playlistId) ||
                        (currentGcid && playlistGcid && currentGcid === playlistGcid)) {
                        currentIndex = i;
                        logJumpInfo(`方法3:在播放列表中找到当前URL(ID参数匹配),索引: ${currentIndex}`);
                        break;
                    }
                }
            }
        }
        
        // 如果找到当前URL,返回下一个URL
        if (currentIndex !== -1 && currentIndex < playlist.length - 1) {
            const nextUrl = playlist[currentIndex + 1].url;
            logJumpInfo(`找到下一个课程URL: ${nextUrl}`);
            return nextUrl;
        }
        
        logJumpInfo('在播放列表中没有找到下一个课程');
        return null;
    }
    
    // 判断两个URL是否相同
    function isSameUrl(url1, url2) {
        // 如果完全相同,直接返回true
        if (url1 === url2) {
            return true;
        }
        
        try {
            // 解析URL
            const parsedUrl1 = new URL(url1);
            const parsedUrl2 = new URL(url2);
            
            // 比较主机名和路径
            if (parsedUrl1.hostname !== parsedUrl2.hostname || 
                parsedUrl1.pathname !== parsedUrl2.pathname) {
                return false;
            }
            
            // 提取查询参数
            const params1 = new URLSearchParams(parsedUrl1.search);
            const params2 = new URLSearchParams(parsedUrl2.search);
            
            // 比较关键参数(id和gcid)
            const id1 = params1.get('id');
            const id2 = params2.get('id');
            const gcid1 = params1.get('gcid');
            const gcid2 = params2.get('gcid');
            
            // 如果两个URL都有id参数,比较id
            if (id1 && id2) {
                return id1 === id2;
            }
            
            // 如果两个URL都有gcid参数,比较gcid
            if (gcid1 && gcid2) {
                return gcid1 === gcid2;
            }
            
            // 如果没有关键参数,比较整个查询字符串
            return parsedUrl1.search === parsedUrl2.search;
        } catch (e) {
            // 如果URL解析失败,回退到简单比较
            return url1.split('?')[0] === url2.split('?')[0];
        }
    }
    
    // 初始化
    init();
})();