Greasy Fork

来自缓存

Greasy Fork is available in English.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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