小雅爬爬爬

爬取小雅平台的课件

目前為 2024-07-06 提交的版本,檢視 最新版本

// ==UserScript==
// @name        小雅爬爬爬
// @match        https://*.ai-augmented.com/*
// @grant       none
// @description 爬取小雅平台的课件
// @license MIT
// @author     Yi
// @version    1.1.5
// @namespace  https://greasyfork.org/users/1268039
// ==/UserScript==

var isProgressBarVisible = true;
// 添加样式规则来更改 placeholder 的颜色
var styleSheet = document.createElement('style');
styleSheet.type = 'text/css';
styleSheet.innerText = `

#searchInput::placeholder {
  color: #ffa500;
}

.custom-checkbox {
  width: 20px;
  height: 20px;
  appearance: none;
  background-color: #fff;
  border: 2px solid #ffa500;
  border-radius: 4px;
  margin-right: 10px;
  outline: none;
  cursor: pointer;
  transition: background-color 0.3s ease, border-color 0.3s ease;
}

.custom-checkbox:checked {
  background-color: #ffa500;
  border-color: #ffa500;
}

.custom-checkbox:checked::before {
  content: '✓';
  display: block;
  text-align: center;
  line-height: 18px;
  color: #fff;
  font-size: 16px;
}

.custom-checkbox:hover {
  border-color: #ff8c00;
}

@keyframes flowingGradient {
  0% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}
`;
document.head.appendChild(styleSheet);

(function() {
    'use strict';

    // 动态导入dotlottie-player模块
    const script = document.createElement('script');
    script.src = 'https://unpkg.com/@dotlottie/player-component@latest/dist/dotlottie-player.mjs';
    script.type = 'module'; // 指定导入类型为module
    document.head.appendChild(script); // 将脚本添加到<head>中

    // 监听脚本的加载事件以确认导入成功
    script.onload = () => {
        console.log('dotlottie-player模块已导入成功!');
    };

    // 监听错误事件以确认导入失败
    script.onerror = () => {
        console.error('无法导入dotlottie-player模块!');
    };
})();

let course_resources;
let svgElementIds = [];
let originalOrder = null;

// 等待 iframe 加载完成
function waitForIframe(selector, callback) {
    const iframe = document.querySelector(selector);
    if (iframe && iframe.contentDocument.readyState === 'complete') {
        callback(iframe); // iframe 已加载,执行回调
    } else {
        setTimeout(() => waitForIframe(selector, callback), 50); // 等待 50ms 后重试
    }
}

// 获取 SVG 元素 ID (仅数字)
function getSvgElementIds(iframe) {
    const iframeDocument = iframe.contentDocument;
    const targetSvgElement = iframeDocument.querySelector("body > svg > g");
    const gElementsWithId = targetSvgElement.querySelectorAll("g[id]");

    // 过滤出纯数字 ID
    const numericIds = Array.from(gElementsWithId)
    .filter(element => /^\d+$/.test(element.id)) // 正则表达式匹配纯数字
    .map(element => element.id);
    return numericIds;
}

// 处理 iframe 的回调函数
function handleIframeLoad(iframe) {
    console.log("目标 iframe 已加载完成!");

    // 跨域处理
    try {
        svgElementIds = getSvgElementIds(iframe); // 更新外部作用域中的 svgElementIds
        console.log(svgElementIds);
    } catch (error) {
        console.error("无法访问 iframe 内容,可能存在跨域限制:", error);
    }
}

// 监视页面的变化
const observer = new MutationObserver((mutations) => {
    for (const mutation of mutations) {
        if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
            for (const node of mutation.addedNodes) {
                if (node.tagName === 'IFRAME') {
                    waitForIframe("#xy_app_content iframe", handleIframeLoad);
                }
            }
        }
    }
});

// 开始监视
observer.observe(document.body, { childList: true, subtree: true });

function parseContent() {
    console.oldLog("::parseContent");

    // 在解析课程内容前清除筛选条件
    window.currentSearchKeyword = '';
    window.currentFilterCategory = '';
    const searchInput = document.getElementById("searchInput");
    if (searchInput) {
        searchInput.value = '';
    }
    const quickFilterSelect = document.getElementById("quickFilterSelect");
    if (quickFilterSelect) {
        quickFilterSelect.selectedIndex = 0; // 选择 "全部"
    }

    var hostname = window.location.hostname;
    var download_url = 'https://' + hostname + '/api/jx-oresource/cloud/file_url/';
    var download_list = document.getElementById("download_list");
    download_list.innerHTML = '<h3 style="color:#fcbb34; font-weight:bold;">课程附件清单</h3>';

    for (let i in course_resources) {
        let resource = course_resources[i];
        let file_name = resource.name;
        let create_time = new Date(resource.created_at).toLocaleDateString();

        if (resource.mimetype) {
            const token = getCookie("HS-prd-access-token"); // 获取 token

            fetch(download_url + resource.quote_id, { // 添加 headers
                headers: {
                    Authorization: `Bearer ${token}`
        }
            })
                .then(function(response) {
                return response.json();
            })
                .then(function(data) {
                if (data.success) {
                    let file_url = data.data.url;

                    var file_container = document.createElement('div');
                    file_container.className = 'file-item';
                    file_container.style.display = 'flex';
                    file_container.style.alignItems = 'center';

                    var checkbox = document.createElement('input');
                    checkbox.type = 'checkbox';
                    checkbox.className = 'custom-checkbox';
                    checkbox.style.marginRight = '10px';
                    checkbox.setAttribute('data-visible', 'true');

                    var file_info = document.createElement('a');
                    file_info.innerHTML = file_name;
                    file_info.href = file_url;
                    file_info.target = "_blank";
                    file_info.className = 'download-link link-style'; // 添加'download-link'类
                    file_info.style.textDecoration = 'none';
                    file_info.title = `创建日期:${create_time}`;
                    file_info.setAttribute('data-created-at', resource.created_at);
                    file_info.setAttribute('data-origin-name', file_name); // 保存原始文件名称
                    file_info.setAttribute('data-resource-id', resource.id);
                    file_info.setAttribute('data-parent-id', resource.parent_id);
                    file_info.draggable = true; // 允许拖动
                    file_info.addEventListener('dragstart', (event) => {
                        event.dataTransfer.effectAllowed = 'move';
                        event.dataTransfer.setData('text/plain', file_url); // 保存下载地址
                        event.dataTransfer.setData('text/filename', file_name); // 保存文件名
                    });
                    file_info.style.display = 'inline-block';
                    file_info.style.padding = '5px 10px';
                    file_info.style.borderRadius = '5px'; // 添加圆角
                    file_info.style.transition = 'all 0.3s ease'; // 过渡效果,用于动画
                    // 鼠标悬停样式
                    file_info.addEventListener('mouseover', () => {
                        file_info.style.backgroundColor = '#FFD180'; // 背景变色
                        file_info.style.color = 'white'; // 文字颜色
                        file_info.style.boxShadow = '0 2px 5px rgba(0, 0, 0, 0.2)'; // 阴影效果
                    });
                    // 鼠标移出样式
                    file_info.addEventListener('mouseout', () => {
                        file_info.style.backgroundColor = 'transparent'; // 背景透明
                        file_info.style.color = '#007bff'; // 恢复文字颜色
                        file_info.style.boxShadow = 'none'; // 移除阴影
                    });
                    // 点击时的样式变化
                    file_info.addEventListener('mousedown', () => {
                        file_info.style.transform = 'scale(0.95)'; // 按下效果
                    });
                    file_info.addEventListener('mouseup', () => {
                        file_info.style.transform = 'scale(1)'; // 恢复原样
                    });

                    file_info.addEventListener('mouseover', () => {
                        file_info.style.textDecoration = 'underline';
                        file_info.style.color = '#000';
                        file_info.style.fontWeight = "bold";
                    });

                    file_info.addEventListener('mouseout', function() {
                        file_info.style.textDecoration = 'none';
                        file_info.style.color = '';
                    });

                    // 拦截点击事件
                    file_info.addEventListener('click', function(event) {
                        event.preventDefault(); // 阻止默认行为
                        courseDownload(file_url, file_name); // 调用下载函数
                    });

                    file_container.appendChild(checkbox);
                    file_container.appendChild(file_info);
                    file_container.style.borderBottom = '1px solid #eee';
                    file_container.style.fontWeight = "bold";
                    file_container.style.padding = '5px 10px';
                    file_container.style.justifyContent = 'flex-start';
                    file_container.style.alignItems = 'center';

                    console.oldLog('::parse', file_name, file_url);

                    download_list.append(file_container);
                }
            }).catch(function(e) {
                console.oldLog('!!error', e);
            });
        }
    }
}

let toggleButton;

// 在文档中创建一个容器来放置所有下载进度条
let downloadsContainer = document.getElementById('downloadsContainer');
if (!downloadsContainer) {
    downloadsContainer = document.createElement('div');
    downloadsContainer.id = 'downloadsContainer';
    downloadsContainer.style.position = 'fixed';
    downloadsContainer.style.bottom = '150px';
    downloadsContainer.style.left = '10px';
    downloadsContainer.style.right = 'auto';
    downloadsContainer.style.zIndex = '9999';
    downloadsContainer.style.backgroundColor = '#FFF3E0';
    downloadsContainer.style.boxShadow = '0 4px 8px 0 rgba(0, 0, 0, 0.2)';
    downloadsContainer.style.borderRadius = '8px';
    downloadsContainer.style.padding = '30px';
    downloadsContainer.style.width = 'auto';
    downloadsContainer.style.minWidth = '300px';
    downloadsContainer.style.boxSizing = 'border-box';
    downloadsContainer.style.margin = '0 auto';
    downloadsContainer.style.border = '1px solid #FFD180';
    // 应用过渡效果到 transform 属性
    downloadsContainer.style.transition = 'transform 0.3s ease-in-out';
    // 设置最大高度限制和溢出滚动
    downloadsContainer.style.maxHeight = '190px';
    downloadsContainer.style.overflowY = 'auto';
    downloadsContainer.style.transform = 'translateX(-90%)';
    downloadsContainer.addEventListener('dragover', function(e) {
        e.preventDefault(); // 阻止默认行为以允许拖放
        e.dataTransfer.dropEffect = 'move';
    });

    downloadsContainer.addEventListener('drop', function(e) {
        e.preventDefault(); // 阻止默认行为
        var downloadUrl = e.dataTransfer.getData('text/plain');
        var filename = e.dataTransfer.getData('text/filename');
        if (downloadUrl && filename) {
            courseDownload(downloadUrl, filename);
        }
    });

    // 创建收起/展示按钮
    toggleButton = document.createElement('button');
    toggleButton.title = '点击展开/收折进度条'
    toggleButton.textContent = '\u25BA'; // 初始为右箭头
    toggleButton.style.position = 'absolute';
    toggleButton.style.top = '50%';
    toggleButton.style.right = '8px';
    toggleButton.style.transform = 'translateY(-50%) rotate(0deg)';
    toggleButton.style.zIndex = '10000';
    toggleButton.style.border = 'none';
    toggleButton.style.boxShadow = '0 2px 4px 0 rgba(0, 0, 0, 0.24), 0 4px 5px 0 rgba(0, 0, 0, 0.19)'; // 添加层次感阴影
    toggleButton.style.background = 'linear-gradient(45deg, #FFC107, #FF9800)'; // 渐变背景
    toggleButton.style.borderRadius = '8px'; // 圆角
    toggleButton.style.padding = '4px 8px'; // 内边距
    toggleButton.style.paddingRight = '2px';
    toggleButton.style.paddingLeft = '2px';
    toggleButton.style.color = 'white'; // 按钮颜色为白色
    toggleButton.style.fontSize = '12px'; // 字体大小
    toggleButton.style.cursor = 'pointer';
    toggleButton.style.transition = 'background-color 0.3s, box-shadow 0.3s, transform 0.3s'; // 过渡效果
    toggleButton.style.textShadow = '0 0 0px transparent';

    toggleButton.onmouseover = function() {
        toggleButton.style.background = 'linear-gradient(45deg, #FFEB3B, #FFC107)'; // 悬停时的渐变背景
        toggleButton.style.boxShadow = '0 4px 8px 0 rgba(0, 0, 0, 0.24), 0 6px 10px 0 rgba(0, 0, 0, 0.19)'; // 悬停时增加阴影的层次和模糊度
        toggleButton.style.transform = 'translateY(-60%) rotate(0deg)'; // 按钮向上移动,增加点击感
    };

    toggleButton.onmouseout = function() {
        toggleButton.style.background = 'linear-gradient(45deg, #FFC107, #FF9800)'; // 正常时的渐变背景
        toggleButton.style.boxShadow = '0 2px 4px 0 rgba(0, 0, 0, 0.24), 0 4px 5px 0 rgba(0, 0, 0, 0.19)'; // 恢复正常阴影
        toggleButton.style.transform = 'translateY(-50%) rotate(0deg)'; // 恢复原位置
    };

    let isCollapsed = true; // 初始状态设为已收起

    toggleButton.onclick = function() {
        // 切换收起/展开状态
        isCollapsed = !isCollapsed;

        if (isCollapsed) {
            downloadsContainer.style.transform = `translateX(-90%)`;
            toggleButton.textContent = '\u25BA'; // 右箭头,表示容器已收起
        } else {
            downloadsContainer.style.transform = 'translateX(0)';
            toggleButton.textContent = '\u25C4'; // 左箭头,表示容器已展开
        }
        toggleButton.style.transform = 'translateY(-50%) rotate(360deg)'; // 旋转箭头
    };

    // 将收起/展示按钮添加到 downloadsContainer
    downloadsContainer.appendChild(toggleButton);

    // 创建 dotlottie-player 容器
    let lottieContainer = document.createElement('div');
    lottieContainer.style.position = 'absolute';
    lottieContainer.style.top = '0';
    lottieContainer.style.left = '0';
    lottieContainer.style.width = '100%';
    lottieContainer.style.height = '100%';
    lottieContainer.style.zIndex = '-1'; // 确保 lottie 在底层
    lottieContainer.innerHTML = `
        <dotlottie-player src="https://lottie.host/0500ecdb-7f3b-4f73-ab09-155a70f85ce3/ZCLltVc7A4.json"
                          background="transparent" speed="1"
                          style="width: 100%; height: 100%;" loop autoplay>
        </dotlottie-player>`;

    // 将 dotlottie-player 容器添加到 downloadsContainer 的顶部
    downloadsContainer.prepend(lottieContainer);
}
// 确保 downloadsContainer 被添加到文档中
if (!document.body.contains(downloadsContainer)) {
    document.body.appendChild(downloadsContainer);
}

function updateContainerPosition() {
    // 获取窗口的高度
    let windowHeight = window.innerHeight;

    // 计算容器的高度(包括内边距和边框)
    let downloadsContainerHeight = downloadsContainer.offsetHeight;

    // 获取当前容器的顶部位置
    let currentTop = downloadsContainer.getBoundingClientRect().top;

    // 如果容器底部将要超出屏幕,则向上移动容器
    if (currentTop + downloadsContainerHeight > windowHeight) {
        let newTop = windowHeight - downloadsContainerHeight - 10; // 留出10px的边距
        downloadsContainer.style.top = `${newTop}px`;
        downloadsContainer.style.bottom = 'auto';
    }
}

function updateIndicator() {
    let indicator = document.getElementById('progressIndicator');
    let progressBarCount = downloadsContainer.querySelectorAll('.progressBar').length;

    if (!indicator) {
        // 如果指示器不存在,创建指示器
        indicator = document.createElement('div');
        indicator.id = 'progressIndicator';
        indicator.style.position = 'absolute';
        indicator.style.top = '10px';
        indicator.style.right = '5px';
        indicator.style.backgroundColor = '#f00';
        indicator.style.backgroundImage = 'linear-gradient(to bottom right, #ffcc80, #ff8c00)';
        indicator.style.color = 'white';
        indicator.style.textShadow = '0px 1px 2px rgba(0, 0, 0, 0.7)'; // 添加文本阴影
        indicator.style.borderRadius = '50%';
        indicator.style.width = '20px';
        indicator.style.height = '20px';
        indicator.style.display = 'flex';
        indicator.style.alignItems = 'center';
        indicator.style.justifyContent = 'center';
        indicator.style.fontSize = '12px';
        indicator.style.fontWeight = 'bold';
        indicator.style.boxShadow = '0px 2px 4px rgba(0, 0, 0, 0.4)'; // 添加外阴影
        indicator.style.transition = 'background-color 0.3s, box-shadow 0.3s'; // 平滑变化的过渡效果
        downloadsContainer.appendChild(indicator);
    }
    // 更新指示器的文本,即使进度条数量为0也显示
    indicator.textContent = progressBarCount;
}

function updateDownloadsContainerVisibility() {
    // 检查是否存在除 lottieContainer、提示信息、收起按钮和指示器外的其他子元素
    const nonEmptyNodes = Array.from(downloadsContainer.children).filter(child => {
        return !child.classList.contains('slide-out') && child.tagName !== 'P' &&
            child !== downloadsContainer.firstChild && child !== toggleButton &&
            child.id !== 'progressIndicator';
    });

    if (nonEmptyNodes.length === 0) {
        if (!downloadsContainer.querySelector('p')) {
            let emptyText = document.createElement('p');
            emptyText.innerHTML = `
            暂无下载内容 ᓚᘏᗢ<br>
            <span style="font-size: 10px;">(可拖动文件下载)</span>
            `;
            emptyText.style.color = '#FF9800';
            emptyText.style.textAlign = 'center';
            emptyText.style.fontFamily = 'Microsoft YaHei';
            emptyText.style.fontSize = '16px';
            emptyText.style.fontWeight = 'bold';
            emptyText.style.padding = '20px';
            emptyText.style.marginTop = '15px';
            emptyText.style.borderRadius = '8px';
            emptyText.style.opacity = '0';
            emptyText.style.transition = 'opacity 1s ease-in-out, transform 1s';
            emptyText.style.transform = 'translateY(-20px)';
            emptyText.style.top = '50%';

            // 添加到DOM后触发动画
            setTimeout(() => {
                emptyText.style.opacity = '1';
                emptyText.style.transform = 'translateY(0)';
            }, 100);

            // 轻微上下浮动动画
            emptyText.animate([
                { transform: 'translateY(0)' },
                { transform: 'translateY(-10px)' },
                { transform: 'translateY(0)' }
            ], {
                duration: 3000,
                iterations: Infinity,
                easing: 'ease-in-out'
            });

            downloadsContainer.appendChild(emptyText);
        }
        // 显示或隐藏进度条容器基于 isProgressBarVisible 变量
        downloadsContainer.style.display = isProgressBarVisible ? 'block' : 'none';
    } else {
        let emptyText = downloadsContainer.querySelector('p');
        if (emptyText) {
            downloadsContainer.removeChild(emptyText);
        }
    }
    // 更新按钮可见性
    toggleButton.style.display = isProgressBarVisible ? 'block' : 'none';
}

updateIndicator()
updateDownloadsContainerVisibility();

function courseDownload(file_url, file_name) {
    const token = getCookie("HS-prd-access-token");
    const downloadsContainer = document.getElementById('downloadsContainer');
    // 创建进度条相关元素。
    let progressText = document.createElement('span');
    let progressBar = document.createElement('div');
    let progressBarContainer = document.createElement('div');
    let progressContainer = document.createElement('div');

    // 设置文本。
    progressText.innerText = `正在下载: ${file_name}`;
    progressText.style.color = '#FF9800';
    progressText.style.fontWeight = 'bold';
    progressText.style.fontSize = '16px';
    progressText.style.fontFamily = 'Microsoft YaHei';
    progressText.style.textShadow = '1px 1px 2px rgba(0, 0, 0, 0.1)';
    progressText.style.padding = '5px 0';
    progressText.style.borderRadius = '4px';
    // 设置progressBar。
    progressBar.style.height = '18px';
    progressBar.style.width = '0%';
    progressBar.style.borderRadius = '8px';
    progressBar.className = 'progressBar'

    // 设置progressBarContainer。
    progressBarContainer.style.background = '#E0E0E0';
    progressBarContainer.style.borderRadius = '8px';
    progressBarContainer.style.height = '18px';
    progressBarContainer.style.width = '100%';
    progressBarContainer.style.overflow = 'hidden';
    progressBarContainer.appendChild(progressBar);

    // 设置 progressContainer。
    progressContainer.style.display = 'flex';
    progressContainer.style.flexDirection = 'column'; // 子元素垂直排列
    progressContainer.style.alignItems = 'center'; // 子元素在交叉轴上居中对齐
    progressContainer.style.justifyContent = 'space-around'; // 子元素沿着主轴均匀分布
    progressContainer.appendChild(progressText);
    // 创建一个用来显示下载百分比的span元素
    let progressPercentText = document.createElement('span');
    progressPercentText.style.fontFamily = 'Arial Rounded MT Bold, Helvetica Rounded, Arial, sans-serif';
    progressPercentText.style.fontSize = '16px';
    progressPercentText.style.marginLeft = '10px'; // 与进度条保持一定距离
    progressPercentText.style.position = 'absolute';
    progressPercentText.style.left = '0';
    progressPercentText.style.top = '0';
    progressPercentText.style.width = '100%';
    progressPercentText.style.textAlign = 'center';
    progressPercentText.style.lineHeight = '18px';
    progressPercentText.style.zIndex = '1';
    // 调整字体粗细
    progressPercentText.style.fontWeight = 'bold';

    // 设置 progressBarContainer 的样式并添加到 progressContainer
    progressContainer.appendChild(progressBarContainer);

    // 插入用于显示百分比的 DOM 元素到 progressContainer
    progressBarContainer.style.position = 'relative'; // 相对定位,以便内部的百分比文本能正确定位
    progressBarContainer.appendChild(progressPercentText);
    progressContainer.classList.add('slide-in');

    updateIndicator()
    updateDownloadsContainerVisibility();

    // 添加 progressContainer 到 downloadsContainer
    downloadsContainer.appendChild(progressContainer);

    const controller = new AbortController();
    const signal = controller.signal;
    window.abortControllers = window.abortControllers || {};
    window.abortControllers[file_name] = controller;

    // 添加文件大小和停止按钮到一个新的横向排列的容器
    let controlContainer = document.createElement('div');
    controlContainer.style.display = 'flex';
    controlContainer.style.justifyContent = 'space-between';
    controlContainer.style.alignItems = 'center';
    controlContainer.style.width = '100%';

    // 创建文件大小显示元素
    let fileSizeSpan = document.createElement('span');
    // 设置样式为微软雅黑和圆润
    fileSizeSpan.style.fontFamily = 'Microsoft YaHei';
    fileSizeSpan.style.fontSize = '14px';
    fileSizeSpan.style.marginRight = 'auto';
    fileSizeSpan.style.fontWeight = 'bold';

    let stopButton = document.createElement('button');
    stopButton.textContent = '停止';
    stopButton.style.padding = '5px 10px';
    stopButton.style.border = 'none';
    stopButton.style.borderRadius = '5px';
    stopButton.style.backgroundColor = '#FF4136';
    stopButton.style.color = 'white';
    stopButton.style.cursor = 'pointer';
    stopButton.style.fontSize = '14px';
    stopButton.style.fontWeight = 'bold';
    stopButton.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.2)';
    stopButton.style.transition = 'transform 0.3s ease';
    stopButton.style.marginTop = '10px'; // 增加顶部外边距以调整与进度条的距离

    stopButton.onmouseover = function() {
        stopButton.style.transform = 'scale(1.2)';
    };

    stopButton.onmouseout = function() {
        stopButton.style.transform = 'scale(1)';
    };

    stopButton.onclick = function() {
        console.log(file_name + ' 的下载已经停止了');
        controller.abort();
        progressContainer.classList.replace('slide-in', 'slide-out');
        progressContainer.addEventListener('animationend', () => {
            progressContainer.remove();
            updateIndicator();
            updateDownloadsContainerVisibility();
        });
    };

    controlContainer.appendChild(fileSizeSpan);
    controlContainer.appendChild(stopButton);
    progressContainer.appendChild(controlContainer);

    let styleElement = document.getElementById('progress-bar-styles');
    if (!styleElement) {
        let styles = document.createElement('style');
        styles.id = 'progress-bar-styles';
        styles.textContent = `
        .progressBar {
            background-color: #FF9800;
            background-image: repeating-linear-gradient(
                45deg,
                rgba(255, 255, 255, 0.15) 25%,
                transparent 25%,
                transparent 50%,
                rgba(255, 255, 255, 0.15) 50%,
                rgba(255, 255, 255, 0.15) 75%,
                transparent 75%,
                transparent
            );
            background-size: 40px 40px;
            animation: moveBackground 2s linear infinite;
        }
        @keyframes moveBackground {
            from { background-position: 0 0; }
            to { background-position: 40px 0; }
        }
        .slide-in {
            animation: slideIn 0.5s ease-out forwards;
        }
        .slide-out {
            animation: slideOut 0.5s ease-in forwards;
        }
        @keyframes slideIn {
            from { transform: translateX(100%); opacity: 0; }
            to { transform: translateX(0); opacity: 1; }
        }
        @keyframes slideOut {
            from { transform: translateX(0); opacity: 1; }
            to { transform: translateX(100%); opacity: 0; }
        }
    `;
        document.head.appendChild(styles);
    }

    function bytesToSize(bytes) {
        const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
        if (bytes === 0) return '0 Byte';
        const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
        return (bytes / Math.pow(1024, i)).toFixed(2) + ' ' + sizes[i];
    }
    updateIndicator()
    updateDownloadsContainerVisibility();
    updateContainerPosition();

    // 使用fetch API开始下载文件
    fetch(file_url, {
        signal,
        headers: {
            Authorization: `Bearer ${token}`
    }
    })
        .then(response => {
        // 获取文件大小信息
        const contentLength = response.headers.get('Content-Length');
        if (contentLength) {
            // 更新文件大小显示
            const fileSize = bytesToSize(contentLength);
            fileSizeSpan.innerText = `文件大小: ${fileSize}`;
        } else {
            // 如果无法获取文件大小,则显示消息
            fileSizeSpan.innerText = `无法获取文件大小`;
            updateIndicator()
            updateDownloadsContainerVisibility();
        }


        const reader = response.body.getReader();
        let receivedBytes = 0;
        let chunks = [];

        reader.read().then(function processResult(result) {
            if (result.done) {
                // 下载完成后的处理
                const blob = new Blob(chunks, { type: 'application/octet-stream' });
                const downloadUrl = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = downloadUrl;
                a.download = file_name;
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                URL.revokeObjectURL(downloadUrl);
                progressContainer.classList.add('slide-out');
                progressContainer.addEventListener('animationend', () => {
                    progressContainer.remove();
                    updateIndicator(); // 更新指示器
                    updateDownloadsContainerVisibility(); // 刷新下载列表的可见性
                }, { once: true });
                return;
            }
            // 存储接收到的数据块
            chunks.push(result.value);
            receivedBytes += result.value.length;

            // 计算下载的百分比并更新UI
            let percentComplete = (receivedBytes / contentLength) * 100;
            progressBar.style.width = `${percentComplete.toFixed(2)}%`; // 更新进度条的宽度
            progressPercentText.innerText = `${percentComplete.toFixed(2)}%`;

            // 读取下一部分数据
            reader.read().then(processResult);
        })
            .catch(e => {
            // 下载失败或被中止时的处理
            if (e.name === 'AbortError') {
                console.error(`${file_name} 的下载被用户取消了`);
            } else {
                console.error(e);
            }
            progressContainer.remove();
            updateIndicator()
            updateDownloadsContainerVisibility();
        });
    });
}

window.currentSearchKeyword = '';
window.currentFilterCategory = '';

window.updateUI = function() {
    var download_list = document.getElementById("download_list");
    if (!document.getElementById("lottie-animation-container")) {
        var lottieContainer = document.createElement("div");
        lottieContainer.id = "lottie-animation-container";
        lottieContainer.innerHTML = `
        <dotlottie-player src="https://lottie.host/f6cfdc36-5c9a-4dac-bb71-149cdf2e7d92/VRIhn9vXE5.json"
                          background="transparent" speed="1"
                          style="width: 300px; height: 300px; transform: scaleX(-1);" loop autoplay>
        </dotlottie-player>`;
        lottieContainer.style.position = "absolute";
        lottieContainer.style.top = "50%";
        lottieContainer.style.right = "0";
        lottieContainer.style.transform = "translateY(-50%)";
        lottieContainer.style.zIndex = "-1";

        download_list.appendChild(lottieContainer);
    }

    // 为新创建的链接添加拖放事件监听器
    const fileLinks = document.querySelectorAll("#download_list .file-item a");
    fileLinks.forEach(fileLink => {
        fileLink.draggable = true;
        fileLink.addEventListener('dragstart', (event) => {
            event.dataTransfer.effectAllowed = 'move';
            event.dataTransfer.setData('text/plain', fileLink.href);
            event.dataTransfer.setData('text/filename', fileLink.getAttribute('data-origin-name'));
        });
    });

    var container = document.getElementById("searchAndFilterContainer");
    if (!container) {
        container = document.createElement("div");
        container.id = "searchAndFilterContainer";
        container.style.position = "relative"
        container.style.display = "flex";
        container.style.marginBottom = '10px';

        download_list.prepend(container);
    }

    var searchInput = document.getElementById("searchInput");
    if (!searchInput) {
        searchInput = document.createElement("input");
        searchInput.type = "text";
        searchInput.placeholder = "搜索文件名/后缀名";
        searchInput.id = "searchInput";
        searchInput.style.padding = '5px';
        searchInput.style.marginRight = '10px';
        searchInput.style.border = '2px solid #ffa500';
        searchInput.style.boxShadow = 'inset 0 1px 3px rgba(0,0,0,0.1)';
        searchInput.style.borderRadius = '4px';
        searchInput.style.outline = 'none';
        searchInput.style.color = '#ffa500';
        searchInput.style.fontWeight = 'bold';
        searchInput.style.backgroundColor = '#fffbe6';

        searchInput.addEventListener("input", function () {
            filterList(this.value);
        });
        container.appendChild(searchInput);
    }

    var quickFilterSelect = document.getElementById("quickFilterSelect");
    if (!quickFilterSelect) {
        quickFilterSelect = document.createElement("select");
        quickFilterSelect.id = "quickFilterSelect";
        quickFilterSelect.style.padding = '5px';
        quickFilterSelect.style.marginRight = '10px';
        quickFilterSelect.style.border = '2px solid #ffa500';
        quickFilterSelect.style.boxShadow = 'inset 0 1px 3px rgba(0,0,0,0.1)';
        quickFilterSelect.style.borderRadius = '4px';
        quickFilterSelect.style.outline = 'none';
        quickFilterSelect.style.cursor = 'pointer';
        quickFilterSelect.style.color = '#ffa500';
        quickFilterSelect.style.fontWeight = 'bold';
        quickFilterSelect.style.backgroundColor = '#fffbe6';
        window.quickFilters.forEach(function (filter) {
            var option = document.createElement("option");
            option.value = filter.value;
            option.text = filter.label;
            quickFilterSelect.appendChild(option);
        });
        quickFilterSelect.addEventListener("change", function () {
            filterListByCategory(this.value);
        });

        container.appendChild(quickFilterSelect);
    } else {
        quickFilterSelect.innerHTML = ''; // 清空已有的选项

        // 重新添加筛选选项
        window.quickFilters.forEach(function (filter) {
            var option = document.createElement("option");
            option.value = filter.value;
            option.text = filter.label;
            option.style.fontWeight = 'bold';
            quickFilterSelect.appendChild(option);
        });

        // 更新选中状态以匹配当前的筛选条件
        for (var i = 0; i < quickFilterSelect.options.length; i++) {
            if (quickFilterSelect.options[i].value === window.currentFilterCategory) {
                quickFilterSelect.selectedIndex = i;
                break;
            }
        }
    }

    // 添加排序下拉框
    var sortSelect = document.getElementById("sortSelect");
    if (!sortSelect) {
        // 如果还没有排序下拉框,则创建
        sortSelect = document.createElement("select");
        sortSelect.id = "sortSelect";
        // 修改排序下拉框样式
        sortSelect.style.padding = '5px';
        sortSelect.style.marginRight = '10px';
        sortSelect.style.border = '2px solid #ffa500';
        sortSelect.style.boxShadow = 'inset 0 1px 3px rgba(0,0,0,0.1)'; // 添加内部阴影效果
        sortSelect.style.borderRadius = '4px';
        sortSelect.style.outline = 'none';
        sortSelect.style.cursor = 'pointer';
        sortSelect.style.color = '#ffa500'; // 设置文本颜色
        sortSelect.style.fontWeight = 'bold';
        sortSelect.style.backgroundColor = '#fffbe6';

        // 添加排序选项
        var sortOptions = [
            { value: '', label: '排序方式' },
            { value: 'date_asc', label: '日期升序' },
            { value: 'date_desc', label: '日期降序' },
            { value: 'xiaoya_order', label: '小雅排序' }
        ];
        sortOptions.forEach(function (option) {
            var opt = document.createElement("option");
            opt.value = option.value;
            opt.text = option.label;
            opt.style.fontWeight = 'bold';
            sortSelect.appendChild(opt);
        });

        // 添加排序下拉框事件监听器
        sortSelect.addEventListener("change", function () {
            sortList(this.value); // 调用原有的日期排序函数
        });
        container.appendChild(sortSelect); // 将排序下拉框添加到容器中
    }

    var existingSelectAllCheckbox = document.getElementById("selectAllCheckbox");
    if (!existingSelectAllCheckbox) {
        var selectAllCheckbox = document.createElement('input');
        selectAllCheckbox.type = 'checkbox';
        selectAllCheckbox.className = 'custom-checkbox';
        selectAllCheckbox.id = 'selectAllCheckbox';
        selectAllCheckbox.style.marginRight = '10px';

        var selectAllLabel = document.createElement('label');
        selectAllLabel.htmlFor = 'selectAllCheckbox';
        selectAllLabel.textContent = '全选';
        selectAllLabel.style.fontWeight = 'bold';
        selectAllLabel.style.color = '#FFA500';
        selectAllLabel.style.userSelect = 'none';

        var checkboxContainer = document.createElement('div');
        checkboxContainer.appendChild(selectAllCheckbox);
        checkboxContainer.appendChild(selectAllLabel);
        download_list.prepend(checkboxContainer);
        checkboxContainer.style.display = 'flex';
        checkboxContainer.style.position = "relative"
        checkboxContainer.style.alignItems = 'center';
        checkboxContainer.style.padding = '5px 10px';
        checkboxContainer.style.marginBottom = '10px';

        selectAllCheckbox.addEventListener('change', function() {
            var checkboxes = document.querySelectorAll("#download_list input[type='checkbox']:not(#selectAllCheckbox)");
            checkboxes.forEach(function(checkbox) {
                if (checkbox.getAttribute('data-visible') === 'true') {
                    checkbox.checked = selectAllCheckbox.checked;
                    var event = new Event('change', {
                        'bubbles': true,
                        'cancelable': true
                    });
                    checkbox.dispatchEvent(event);
                }
            });
        });
    }

    var existingBulkDownloadButton = document.getElementById("bulkDownloadButton");
    if (!existingBulkDownloadButton) {
        var bulkDownloadButton = document.createElement('button');
        bulkDownloadButton.innerHTML = '<span style="font-weight: bold;">批量下载</span>';
        bulkDownloadButton.id = "bulkDownloadButton";
        bulkDownloadButton.title = '点击下载所选文件';
        bulkDownloadButton.style.cssText = `
    position: fixed;
    top: 15px;
    right: 15px;
    background: linear-gradient(90deg, #ffa500, #ff8c00, #ffa500);
    background-size: 200% 100%;
    animation: flowingGradient 3s ease infinite;
    color: white;
    border: none;
    padding: 10px 20px;
    border-radius: 5px;
    cursor: pointer;
    box-shadow: 0 2px 4px rgba(0,0,0,0.2);
    transition: filter 0.3s, transform 0.3s; /* 修改 transition 属性 */
  `;

        bulkDownloadButton.addEventListener('mouseover', function() {
            this.style.transform = 'scale(1.05)';
            this.style.backgroundColor = '#ffd564';
        });

        bulkDownloadButton.addEventListener('mouseout', function() {
            this.style.transform = 'scale(1)';
            this.style.backgroundColor = '#fcbb34';
        });

        bulkDownloadButton.addEventListener('click', function() {
            var checkboxes = document.querySelectorAll("#download_list input[type='checkbox']:checked");
            checkboxes.forEach(function(checkbox) {
                if (checkbox.checked && checkbox.getAttribute('data-visible') === 'true') {
                    var container = checkbox.closest('div');
                    var link = container.querySelector('a');
                    var file_name = link.getAttribute('data-origin-name'); // 使用原始文件名
                    var file_url = link.href;

                    courseDownload(file_url, file_name);
                }
            });
        });

        download_list.appendChild(bulkDownloadButton);
        window.bulkDownloadButton = bulkDownloadButton;
    }
}

function sortList(order) {
    const downloadList = document.getElementById("download_list");
    const items = Array.from(downloadList.querySelectorAll(".file-item"));

    // 构建文件夹 ID 到索引的映射(用于小雅排序)
    const folderIndexMap = {};
    svgElementIds.forEach((id, index) => {
        folderIndexMap[id] = index;
    });

    items.sort((a, b) => {
        const aParentId = a.querySelector('a').getAttribute('data-parent-id');
        const bParentId = b.querySelector('a').getAttribute('data-parent-id');
        const aId = a.querySelector('a').getAttribute('data-resource-id');
        const bId = b.querySelector('a').getAttribute('data-resource-id');

        if (order === 'xiaoya_order') {
            const aFolderIndex = folderIndexMap[aParentId] || Infinity;
            const bFolderIndex = folderIndexMap[bParentId] || Infinity;

            if (aFolderIndex !== bFolderIndex) {
                return aFolderIndex - bFolderIndex; // 不同文件夹,按文件夹顺序排序
            } else {
                return aId.localeCompare(bId); // 同一文件夹,按文件 ID 排序
            }
        } else {
            const aDate = new Date(a.querySelector('a').getAttribute('data-created-at'));
            const bDate = new Date(b.querySelector('a').getAttribute('data-created-at'));

            if (order === 'date_asc') {
                return aDate - bDate;
            } else if (order === 'date_desc') {
                return bDate - aDate;
            }
        }
    });

    items.forEach(item => downloadList.appendChild(item));

    // 重新应用筛选条件
    applyFilters();
}

window.toggleListVisibility = function() {
    var download_list = document.getElementById("download_list");

    // 切换列表的显示和隐藏
    if (download_list.style.maxHeight === '0px' || download_list.style.maxHeight === '') {
        // 展开列表
        download_list.style.maxHeight = "300px";
        download_list.style.opacity = "1";
        download_list.style.overflowY = "auto"; // 添加垂直滚动条
    } else {
        // 折叠列表
        download_list.style.maxHeight = "0";
        download_list.style.opacity = "0";
        download_list.style.overflowY = "hidden"; // 隐藏垂直滚动条
    }
}

function filterList(keyword) {
    window.currentSearchKeyword = keyword.toLowerCase(); // 保存当前搜索关键词
    // 更新搜索框的值
    const searchInput = document.getElementById("searchInput");
    if (searchInput) {
        searchInput.value = keyword;
    }

    applyFilters();
}

function filterListByCategory(categoryValue) {
    window.currentFilterCategory = categoryValue; // 保存当前分类
    applyFilters(); // 应用筛选和搜索
}

function applyFilters() {
    var searchKeyword = window.currentSearchKeyword;
    var filterCategory = window.currentFilterCategory;
    var extensions = filterCategory ? filterCategory.split(',').map(ext => ext.trim()) : [];

    var containers = document.querySelectorAll("#download_list .file-item");
    containers.forEach(function(container) {
        var file = container.querySelector("a");
        var checkbox = container.querySelector("input[type='checkbox']");
        var fileName = file.getAttribute('data-origin-name').toLowerCase();
        var fileExtension = fileName.slice(((fileName.lastIndexOf(".") - 1) >>> 0) + 2);

        var isSearchMatch = searchKeyword === '' || fileName.includes(searchKeyword);
        var isFilterMatch = filterCategory === "" || extensions.includes(fileExtension);

        var isVisible = isSearchMatch && isFilterMatch;
        container.style.display = isVisible ? "flex" : "none"; // 保持布局结构
        checkbox.setAttribute('data-visible', isVisible.toString());
    });

    const selectAllCheckbox = document.getElementById('selectAllCheckbox');
    if (selectAllCheckbox) {
        const visibleCheckboxes = Array.from(document.querySelectorAll("#download_list .file-item input[type='checkbox'][data-visible='true']"));
        const allVisibleChecked = visibleCheckboxes.every(checkbox => checkbox.checked);
        selectAllCheckbox.checked = visibleCheckboxes.length > 0 && allVisibleChecked;
    }
    // 检查筛选后是否还有可见的课件
    var visibleItems = document.querySelectorAll("#download_list .file-item[style*='display: flex']");
    // 获取下载列表容器
    var download_list = document.getElementById("download_list");
    // 获取已有的提示信息元素
    var noResultsMessage = download_list.querySelector('p');
    if (visibleItems.length === 0) {
        // 如果没有可见的课件
        if (!noResultsMessage) {
            // 如果提示信息元素不存在,则创建
            noResultsMessage = document.createElement('p');
            noResultsMessage.style.color = '#FFA500'; // 保持橙色
            noResultsMessage.style.textAlign = 'center';
            noResultsMessage.style.fontWeight = 'bold'; // 加粗字体
            noResultsMessage.innerHTML = '<span style="font-size: 1.2em;"><span style="color: red;">没有</span></span>课件( ´・・)ノ(._.`)';
            download_list.appendChild(noResultsMessage);
        }
    } else {
        // 如果有可见的课件,则移除之前的提示信息
        if (noResultsMessage) {
            download_list.removeChild(noResultsMessage);
        }
    }
}

function add_download_button() {
    // 创建下载图标容器
    var downloadIconContainer = document.createElement('div');
    downloadIconContainer.id = "download_icon_container";
    downloadIconContainer.innerHTML = `
        <dotlottie-player class="download-icon"
                          src="https://lottie.host/604bb467-91d8-46f3-a7ce-786e25f8fded/alw6gwjRdU.json"
                          background="transparent"
                          speed="1"
                          style="width: 60px; height: 60px; margin: -15px;"
                          loop autoplay onclick="toggleListVisibility()"
                          title="点击展开或关闭列表"></dotlottie-player>
    `;

    // 设置下载图标容器的样式
    downloadIconContainer.style.cssText = `
        position: fixed;
        right: 10px;
        bottom: 10px;
        z-index: 9000;
        cursor: pointer;
    `;

    // 创建下载列表容器
    var downloadListContainer = document.createElement('div');
    downloadListContainer.id = "download_list";
    downloadListContainer.style.cssText = `
        z-index: 999;
        backdrop-filter: blur(10px);
        border: 2px solid #fcbb34;
        border-radius: 5px;
        max-height: 0;
        overflow-y: hidden;
        padding: 20px;
        flex-direction: column;
        align-items: flex-start;
        transition: max-height 0.5s ease-in-out, opacity 0.5s ease-in-out;
        opacity: 0;
        position: fixed;
        right: 30px;
        bottom: 50px;
        background-color: white;
    `;
    downloadListContainer.innerHTML = `
  <h3 style="text-align: center;">
    <span style="
      background: linear-gradient(90deg, #ffa500, #ff8c00, #ffa500);
      background-size: 200% 100%;
      animation: flowingGradient 3s ease infinite;
      -webkit-background-clip: text;
      -webkit-text-fill-color: transparent;
      font-weight:bold;
    ">暂无课件♪(´▽`)</span>
  </h3>
  <br>
  <p style="text-align: center; font-size: 12px; color: #888; font-weight:bold;">(在课程首页才能获取到资源)</p>
`;

    // 添加下载图标的样式
    var downloadIconStyle = document.createElement('style');
    downloadIconStyle.innerHTML = `
  .download-icon {
    padding: 2px;
    margin: -20px;
    background-color: rgba(255, 255, 255, 0);
    border-radius: 10px;
    transition: transform 0.3s ease; // 确保动画效果的平滑过渡
    cursor: pointer;
  }

  .download-icon:hover {
    background-color: rgba(255, 255, 255, 0.3);
    transform: scale(1.1); // 悬停时放大
  }
`;


    document.head.appendChild(downloadIconStyle);
    document.body.appendChild(downloadIconContainer);
    document.body.appendChild(downloadListContainer);
}

// 获取cookie
function getCookie(name) {
    const value = `; ${document.cookie}`;
    const parts = value.split(`; ${name}=`);
    if (parts.length === 2) return parts.pop().split(';').shift();
}

function initializeControlPanel() {
    const controlPanel = document.createElement('div');
    const checkboxesContainer = document.createElement('div');
    const downloadInterfaceCheckbox = document.createElement('input');
    const downloadButtonCheckbox = document.createElement('input');
    const progressBarCheckbox = document.createElement('input');
    const toggleButton = document.createElement('button');
    const markReadButton = document.createElement('button');
    let isControlPanelVisible = false;

    // 创建Lottie动画播放器元素
    const lottiePlayer = document.createElement('dotlottie-player');
    lottiePlayer.setAttribute('src', "https://lottie.host/4f5910c1-63a3-4ffa-965c-7c0e46a29928/PCa2EgPj4N.json");
    lottiePlayer.setAttribute('background', 'transparent');
    lottiePlayer.setAttribute('speed', '1');
    lottiePlayer.style.width = '100%';
    lottiePlayer.style.height = '100%';
    lottiePlayer.style.position = 'absolute';
    lottiePlayer.style.zIndex = '-1';
    lottiePlayer.style.top = '0';
    lottiePlayer.style.left = '0';
    lottiePlayer.setAttribute('loop', '');
    lottiePlayer.setAttribute('autoplay', '');

    // 设置控制面板样式
    controlPanel.style.position = 'fixed';
    controlPanel.style.top = '210px';
    controlPanel.style.right = isControlPanelVisible ? '30px' : '-500px';
    controlPanel.style.zIndex = '10000';
    controlPanel.style.backgroundColor = '#fff';
    controlPanel.style.padding = '10px';
    controlPanel.style.borderRadius = '5px';
    controlPanel.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)';
    controlPanel.style.border = '1px solid #fcbb34';
    controlPanel.style.transition = 'right 0.3s ease-in-out';
    controlPanel.style.overflow = 'hidden';

    controlPanel.appendChild(lottiePlayer);

    // 创建流光线元素
    const glowingLine = document.createElement('div');
    glowingLine.style.position = 'relative';
    glowingLine.style.height = '3px';
    glowingLine.style.bottom = '22px';
    glowingLine.style.right = '10px';
    glowingLine.style.width = '110%';
    glowingLine.style.zIndex = '9000';
    glowingLine.style.background = 'linear-gradient(90deg, #ffa500, #ff8c00, #ffa500)';
    glowingLine.style.backgroundSize = '200% 100%';
    glowingLine.style.animation = 'flowingGradient 3s ease infinite';

    // 一键更新按钮
    const updateButton = document.createElement('button');
    updateButton.textContent = '检查更新';
    updateButton.style.marginTop = '10px';
    updateButton.style.padding = '8px 15px';
    updateButton.style.border = 'none';
    updateButton.style.borderRadius = '25px';
    updateButton.style.background = 'linear-gradient(90deg, #ffa500, #ff8c00, #ffa500)';
    updateButton.style.backgroundSize = '200% 100%';
    updateButton.style.animation = 'flowingGradient 3s ease infinite';
    updateButton.style.color = '#fff';
    updateButton.style.cursor = 'pointer';
    updateButton.style.fontWeight = 'bold';
    updateButton.style.fontSize = '16px';
    updateButton.style.transition = 'all 0.3s ease';
    updateButton.style.zIndex = '9999';

    // 悬停、点击效果
    updateButton.onmouseover = function() {
        updateButton.style.filter = 'brightness(1.2)'; // 悬停时增加亮度
        updateButton.style.boxShadow = '0px 4px 6px rgba(0, 0, 0, 0.2)';
        updateButton.style.transform = 'scale(1.05) translateY(-2px)';
    };

    updateButton.onmouseout = function() {
        updateButton.style.filter = 'brightness(1)'; // 恢复原始亮度
        updateButton.style.boxShadow = 'none';
        updateButton.style.transform = 'scale(1) translateY(0)';
    };

    updateButton.onmousedown = function() {
        updateButton.style.transform = 'scale(0.95) translateY(2px)'; // 点击时缩小并下移
    };

    updateButton.onmouseup = function() {
        updateButton.style.transform = 'scale(1.05) translateY(-2px)'; // 放开鼠标时恢复悬停效果
    };

    // 更新按钮容器,用于居中
    const updateButtonContainer = document.createElement('div');
    updateButtonContainer.style.display = 'flex';
    updateButtonContainer.style.justifyContent = 'center';
    updateButtonContainer.style.marginTop = '10px';

    updateButtonContainer.appendChild(updateButton);

    // 按钮悬停效果
    updateButton.onmouseover = function() {
        updateButton.style.transform = 'scale(1.15)';
    };
    updateButton.onmouseout = function() {
        updateButton.style.transform = 'scale(1)';
    };

    function compareVersions(currentVersion, latestVersion) {
        const currentParts = currentVersion.split('.').map(Number);
        const latestParts = latestVersion.split('.').map(Number);

        const maxLength = Math.max(currentParts.length, latestParts.length);

        for (let i = 0; i < maxLength; i++) {
            // 确保每个部分的位数相同
            const currentPart = String(currentParts[i] || 0).padStart(3, '0'); // 补零到3位
            const latestPart = String(latestParts[i] || 0).padStart(3, '0');

            if (latestPart > currentPart) {
                return -1; // 最新版本较大
            } else if (currentPart > latestPart) {
                return 1; // 当前版本较大
            }
        }

        return 0; // 版本相同
    }

    // 按钮点击事件:检查更新
    updateButton.onclick = function() {
        const scriptInfo = GM_info;
        const currentVersion = scriptInfo.script.version;

        // 构建元数据文件的 URL
        const metaURL = scriptInfo.script.downloadURL.replace(/\.user\.js$/, '.meta.js');

        fetch(metaURL)
            .then(response => response.text())
            .then(text => {
            console.log('Fetched meta data:', text); // 打印获取到的元数据内容

            const match = text.match(/\/\/\s*@version\s+([\d.]+)/);
            if (match && match[1]) {
                const latestVersion = match[1];

                // 使用修改后的版本比较函数
                const comparisonResult = compareVersions(currentVersion, latestVersion);

                if (comparisonResult < 0) {
                    if (confirm(`检测到新版本 ${latestVersion},是否立即更新?`)) {
                        window.location.href = scriptInfo.script.downloadURL;
                    }
                } else {
                    alert('当前已是最新版本!');
                }
            } else {
                throw new Error('无法从更新信息中提取版本号。');
            }
        })
            .catch(error => {
            console.error('更新检查失败:', error);
            alert('更新检查失败,请稍后再试。');
        });
    };


    // 定义按钮鼠标悬浮时的发光效果
    const hoverGlowName = 'hover-glow';
    const styleSheet = document.createElement('style');
    styleSheet.type = 'text/css';
    styleSheet.innerText = `
    @keyframes ${hoverGlowName} {
        from {
            box-shadow: 0 0 8px #fcbb34;
        }
        to {
            box-shadow: 0 0 20px #fcbb34, 0 0 30px #fcbb34;
        }
    }

    #toggleButton:hover {
        animation: ${hoverGlowName} 1s ease-in-out infinite alternate;
    }

    .switch {
        position: relative;
        display: inline-block;
        width: 40px;
        height: 20px;
    }

    .switch:hover .slider {
    transform: scale(1.1);
    animation: ${hoverGlowName} 1s ease-in-out infinite alternate;
    }

    .switch input {
        opacity: 0;
        width: 0;
        height: 0;
    }

    .slider {
        position: absolute;
        cursor: pointer;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background-color: #ccc;
        transition: background-color 0.4s, transform 0.4s ease;
        transition: 0.4s;
        border-radius: 20px;
    }

    .slider:before {
        position: absolute;
        content: "";
        height: 14px;
        width: 14px;
        left: 3px;
        bottom: 3px;
        background-color: white;
        transition: 0.4s;
        border-radius: 50%;
    }

    input:checked + .slider {
        background-color: #fcbb34;
    }

    input:checked + .slider:before {
        transform: translateX(20px);
    }
`;
    document.head.appendChild(styleSheet);

    // 设置切换按钮样式
    const gearIcon = document.createElement('span');
    gearIcon.textContent = '⚙️';
    gearIcon.style.fontSize = '16px'; // 保持与按钮相同的字体大小
    // 齿轮图标的样式
    gearIcon.style.transition = 'transform 0.3s ease';
    gearIcon.style.display = 'inline-block';
    gearIcon.style.verticalAlign = 'middle';
    // 将齿轮图标添加到按钮中
    toggleButton.appendChild(gearIcon);
    toggleButton.id = 'toggleButton';
    toggleButton.style.fontSize = '16px';
    toggleButton.title = '控制面板';
    toggleButton.style.position = 'fixed';
    toggleButton.style.top = '210px';
    toggleButton.style.right = '0';
    toggleButton.style.zIndex = '10001';
    toggleButton.style.backgroundColor = '#fcbb34';
    toggleButton.style.boxShadow = '0 4px 8px 0 rgba(0, 0, 0, 0.2)';
    toggleButton.style.color = '#fff';
    toggleButton.style.border = 'none';
    toggleButton.style.borderRadius = '5px 0 0 5px';
    toggleButton.style.padding = '10px';
    toggleButton.style.cursor = 'pointer';
    toggleButton.style.transition = 'right 0.3s ease-in-out, transform 0.3s ease';
    // 添加悬停效果
    toggleButton.style.transform = 'scale(1)'; // 默认比例
    toggleButton.addEventListener('mouseover', function() {
        toggleButton.style.transform = 'scale(1.1)'; // 悬停时放大
    });
    toggleButton.addEventListener('mouseout', function() {
        toggleButton.style.transform = 'scale(1)'; // 鼠标移出时恢复原大小
    });

    // 切换按钮点击事件
    toggleButton.addEventListener('click', function() {
        isControlPanelVisible = !isControlPanelVisible;
        controlPanel.style.right = isControlPanelVisible ? '40px' : '-500px';
        gearIcon.style.transform = 'rotate(360deg)';
        gearIcon.addEventListener('transitionend', function() {
            gearIcon.style.transform = 'none';
        }, { once: true });
    });

    // 初始化复选框状态
    function initializeCheckboxState(checkbox, index) {
        const savedState = localStorage.getItem(`checkbox-${index}`);
        checkbox.checked = savedState === null ? true : savedState === 'true';
        progressBarCheckbox.addEventListener('change', () => {
            isProgressBarVisible = progressBarCheckbox.checked;
            updateVisibility();
        });
    }

    // 保存复选框状态
    function saveCheckboxState(checkbox, index) {
        localStorage.setItem(`checkbox-${index}`, checkbox.checked);
    }

    // 初始化复选框
    [downloadInterfaceCheckbox, downloadButtonCheckbox, progressBarCheckbox].forEach((checkbox, index) => {
        checkbox.type = 'checkbox';
        initializeCheckboxState(checkbox, index); // 调用函数以应用保存的状态
        checkbox.id = `checkbox-${index}`;
        checkbox.style.display = 'none'; // 隐藏原始复选框

        const label = document.createElement('label');
        label.className = 'switch';
        label.htmlFor = `checkbox-${index}`;
        const slider = document.createElement('span');
        slider.className = 'slider';
        label.appendChild(checkbox);
        label.appendChild(slider);

        const labelText = document.createElement('span');
        labelText.textContent = ['右上角下载栏', '右下角下载栏', '左下角进度条'][index];
        labelText.style.color = '#fcbb34'; // 橙色文字
        labelText.style.marginRight = '10px';
        labelText.style.fontWeight = 'bold'; // 文字加粗
        labelText.style.verticalAlign = 'middle'; // 设置文字垂直居中

        checkbox.addEventListener('change', () => {
            if (index === 1) {
                updateDownloadListVisibility(); // 仅当右下角下载列表复选框变化时,调用此函数
            } else {
                updateVisibility(); // 否则调用一般的更新可见性函数
            }
            saveCheckboxState(checkbox, index); // 保存复选框状态
        });

        const container = document.createElement('div');
        container.style.display = 'flex';
        container.style.justifyContent = 'space-between';
        container.style.alignItems = 'center';
        container.appendChild(labelText);
        container.appendChild(label);

        checkboxesContainer.appendChild(container);
    });

    // 将复选框容器添加到控制面板中
    controlPanel.appendChild(checkboxesContainer);

    // 按钮用于标记所有消息为已读
    markReadButton.textContent = '已读所有消息';
    markReadButton.style.marginTop = '10px';
    markReadButton.style.padding = '5px 10px';
    markReadButton.style.border = 'none';
    markReadButton.style.borderRadius = '5px';
    markReadButton.style.backgroundColor = '#fcbb34'; // 橙色背景
    markReadButton.style.color = '#fff'; // 白色文字
    markReadButton.style.cursor = 'pointer';
    markReadButton.style.fontWeight = 'bold'; // 文字加粗
    markReadButton.style.transition = 'transform 0.3s ease'; // 平滑过渡效果

    // 按钮悬停效果
    markReadButton.onmouseover = function() {
        markReadButton.style.transform = 'scale(1.1)'; // 悬停时放大
    };
    markReadButton.onmouseout = function() {
        markReadButton.style.transform = 'scale(1)'; // 鼠标移出时恢复原大小
    };

    // 绑定点击事件处理函数
    markReadButton.onclick = function() {
        markAllMessagesAsRead();
    };
    controlPanel.appendChild(markReadButton);

    document.body.appendChild(controlPanel);
    document.body.appendChild(toggleButton);

    // 定义标记所有消息为已读的函数
    async function markAllMessagesAsRead() {
        const token = getCookie("HS-prd-access-token");
        const hostname = window.location.hostname;
        const pageSize = 20;
        const messageTypes = ["todo", "group", "personal", "system"];
        let hasUnreadMessages = false;

        // 遍历每种消息类型
        for (const messageType of messageTypes) {
            try {
                let pageIndex = 1;
                let unreadMessageIds = [];

                // 循环获取所有未读消息
                while (true) {
                    const apiUrl = `https://${hostname}/api/jx-iresource/message/im/${messageType}?page_size=${pageSize}&page_index=${pageIndex}&msg_status=0`;
                    const response = await fetch(apiUrl, {
                        headers: {
                            "Authorization": `Bearer ${token}`
          }
                    });

                    if (response.ok) {
                        const data = await response.json();
                        const messages = data.data.list;

                        if (messages.length === 0) {
                            break;
                        }
                        unreadMessageIds = unreadMessageIds.concat(messages.map(message => message.id));
                        pageIndex++;
                    } else {
                        console.error(`获取未读${messageType === 'todo' ? '待办' : messageType === 'group' ? '课程' : messageType === 'personal' ? '个人' : '系统'}消息失败:`, response.status, response.statusText);
                        alert(`获取未读${messageType === 'todo' ? '待办' : messageType === 'group' ? '课程' : messageType === 'personal' ? '个人' : '系统'}消息失败,请重试`);
                        return;
                    }
                }
                // 更新消息状态为已读
                if (unreadMessageIds.length > 0) {
                    hasUnreadMessages = true;
                    const updateResponse = await fetch(`https://${hostname}/api/jx-iresource/message/im/updateStatus`, {
                        method: "PUT",
                        headers: {
                            "Content-Type": "application/json",
                            "Authorization": `Bearer ${token}`
          },
                        body: JSON.stringify({
                            message_ids: unreadMessageIds,
                            status: 1
                        })
                    });

                    if (updateResponse.ok) {
                        console.log(`所有${messageType === 'todo' ? '待办' : messageType === 'group' ? '课程' : messageType === 'personal' ? '个人' : '系统'}消息已标记为已读`);
                    } else {
                        console.error(`标记${messageType === 'todo' ? '待办' : messageType === 'group' ? '课程' : messageType === 'personal' ? '个人' : '系统'}消息失败:`, updateResponse.status, updateResponse.statusText);
                        alert(`标记${messageType === 'todo' ? '待办' : messageType === 'group' ? '课程' : messageType === 'personal' ? '个人' : '系统'}消息失败,请重试`);
                        return;
                    }
                } else {
                    console.log(`没有未读${messageType === 'todo' ? '待办' : messageType === 'group' ? '课程' : messageType === 'personal' ? '个人' : '系统'}消息`);
                }
            } catch (error) {
                console.error('Error:', error);
                alert(`标记${messageType === 'todo' ? '待办' : messageType === 'group' ? '课程' : messageType === 'personal' ? '个人' : '系统'}消息失败,请重试`);
                return;
            }
        }
        if (hasUnreadMessages) {
            alert("所有消息已标记为已读");
        } else {
            console.log("没有未读消息");
            alert("没有未读消息");
        }
    }

    // 按钮用于清空所有消息
    const clearMessagesButton = document.createElement('button');
    clearMessagesButton.textContent = '清空所有消息';
    clearMessagesButton.style.marginTop = '10px';
    clearMessagesButton.style.marginLeft = '5px'; // 与标记已读按钮留出一些间隙
    clearMessagesButton.style.padding = '5px 10px';
    clearMessagesButton.style.border = 'none';
    clearMessagesButton.style.borderRadius = '5px';
    clearMessagesButton.style.backgroundColor = '#fcbb34'; // 橙色背景
    clearMessagesButton.style.color = '#fff'; // 白色文字
    clearMessagesButton.style.cursor = 'pointer';
    clearMessagesButton.style.fontWeight = 'bold'; // 文字加粗
    clearMessagesButton.style.transition = 'transform 0.3s ease'; // 平滑过渡效果

    // 按钮悬停效果
    clearMessagesButton.onmouseover = function() {
        clearMessagesButton.style.transform = 'scale(1.1)'; // 悬停时放大
    };
    clearMessagesButton.onmouseout = function() {
        clearMessagesButton.style.transform = 'scale(1)'; // 鼠标移出时恢复原大小
    };

    // 绑定点击事件处理函数
    clearMessagesButton.onclick = function() {
        // 弹出确认对话框
        if (confirm("确定要清空所有消息吗?该操作无法撤销。")) {
            clearAllMessages();
        }
    };
    controlPanel.appendChild(clearMessagesButton);
    addShowCourseNameText();
    addTipsDisplay();

    // 定义清空所有消息的函数
    async function clearAllMessages() {
        const token = getCookie("HS-prd-access-token");
        const hostname = window.location.hostname;
        const pageSize = 20;
        const messageTypes = ["todo", "group", "personal", "system"];
        let hasMessagesToClear = false;

        for (const messageType of messageTypes) {
            try {
                let pageIndex = 1;
                let messageIdsToClear = [];

                while (true) {
                    const apiUrl = `https://${hostname}/api/jx-iresource/message/im/${messageType}?page_size=${pageSize}&page_index=${pageIndex}&msg_status=0`;
                    const response = await fetch(apiUrl, {
                        headers: {
                            "Authorization": `Bearer ${token}`
          }
                    });

                    if (response.ok) {
                        const data = await response.json();
                        const messages = data.data.list;

                        if (messages.length === 0) {
                            break;
                        }

                        messageIdsToClear = messageIdsToClear.concat(messages.map(message => message.id));
                        pageIndex++;
                    } else {
                        console.error(`获取${messageType === 'todo' ? '待办' : messageType === 'group' ? '课程' : messageType === 'personal' ? '个人' : '系统'}消息失败:`, response.status, response.statusText);
                        alert(`获取${messageType === 'todo' ? '待办' : messageType === 'group' ? '课程' : messageType === 'personal' ? '个人' : '系统'}消息失败,请重试`);
                        return;
                    }
                }
                if (messageIdsToClear.length > 0) {
                    hasMessagesToClear = true;
                    const clearResponse = await fetch(`https://${hostname}/api/jx-iresource/message/im/selected/empty`, {
                        method: "POST",
                        headers: {
                            "Content-Type": "application/json",
                            "Authorization": `Bearer ${token}`
          },
                        body: JSON.stringify({
                            message_ids: messageIdsToClear
                        })
                    });

                    if (clearResponse.ok) {
                        console.log(`所有${messageType === 'todo' ? '待办' : messageType === 'group' ? '课程' : messageType === 'personal' ? '个人' : '系统'}消息已清空`);
                    } else {
                        const errorText = await clearResponse.text();
                        console.error(`清空${messageType === 'todo' ? '待办' : messageType === 'group' ? '课程' : messageType === 'personal' ? '个人' : '系统'}消息失败:`, errorText);
                        alert(`清空${messageType === 'todo' ? '待办' : messageType === 'group' ? '课程' : messageType === 'personal' ? '个人' : '系统'}消息失败: ${errorText}`);
                        return;
                    }
                }
            } catch (error) {
                console.error('Error:', error);
                alert(`清空${messageType === 'todo' ? '待办' : messageType === 'group' ? '课程' : messageType === 'personal' ? '个人' : '系统'}消息出错: ${error.message}`);
                return;
            }
        }
        if (hasMessagesToClear) {
            alert("所有消息已清空");
        } else {
            console.log("没有消息可清空");
            alert("没有消息可清空");
        }
    }

    // 获取课程名称
    function getCourseName() {
        const footer = document.querySelector('.img_footer');
        if (footer) {
            const groupNameElement = footer.querySelector('.group_name');
            if (groupNameElement) {
                return groupNameElement.textContent; // 返回课程名称
            }
        }
        return '未知'; // 如果没有找到课程名称,返回默认文本
    }

    function addShowCourseNameText() {
        const showCourseNameText = document.createElement('div');
        showCourseNameText.style.marginTop = '10px';
        showCourseNameText.style.marginLeft = '5px';
        showCourseNameText.style.backgroundColor = 'transparent';
        showCourseNameText.style.color = '#fcbb34';
        showCourseNameText.style.fontWeight = 'bold';
        showCourseNameText.style.maxWidth = '200px';

        const observer = new MutationObserver((mutations, obs) => {
            // 始终尝试更新课程名称
            const courseName = getCourseName();
            showCourseNameText.textContent = `当前课程:${courseName}`;
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true,
            attributes: false
        });

        controlPanel.appendChild(showCourseNameText);
    }

    function addTipsDisplay() {
        const tipsDisplay = document.createElement('div');
        tipsDisplay.id = 'tipsDisplay';
        // 设置样式
        tipsDisplay.style.padding = '10px';
        tipsDisplay.style.marginTop = '10px';
        tipsDisplay.style.backgroundColor = 'rgba(252, 187, 52, 0.2)'; // 浅橙色背景
        tipsDisplay.style.border = '1px solid #fcbb34'; // 橙色边框
        tipsDisplay.style.color = '#fcbb34'; // 橙色文字
        tipsDisplay.style.borderRadius = '5px';
        tipsDisplay.style.fontSize = '14px';
        tipsDisplay.style.fontWeight = 'bold';
        tipsDisplay.style.textAlign = 'center';
        tipsDisplay.style.position = 'relative'; // 用于动画定位
        tipsDisplay.style.overflow = 'hidden'; // 隐藏溢出的文本
        tipsDisplay.textContent = '右上角下载栏可下载单个文件。';
        tipsDisplay.style.opacity = '1';
        tipsDisplay.style.transform = 'translateY(0)';
        tipsDisplay.style.transition = 'opacity 0.5s, transform 0.5s';

        controlPanel.appendChild(tipsDisplay);
        controlPanel.appendChild(updateButtonContainer);
        controlPanel.appendChild(glowingLine);

        // 提示信息列表
        const tipsList = [
            '右上角下载栏可下载单个文件。',
            '右下角下载栏可下载多个文件。',
            '可拖动链接至左下角进行下载。',
            '进度条位于左下角折叠列表中。',
            '搜索栏也可搜索后缀名等信息。',
            '右上角支持文档和压缩包下载。',
            '浏览器可以直接右键下载图片。',
            '视频可使用其他现成插件下载。',
            '如有建议请在油猴反馈处留言。',
        ];

        // 当前显示的提示信息索引
        let currentTipIndex = 0;
        let intervalId; // 用于存储 setInterval 的 ID

        // 更换提示信息的函数
        function changeTip() {
            // 更新当前提示索引
            currentTipIndex = (currentTipIndex + 1) % tipsList.length;

            // 执行移出动画
            tipsDisplay.style.opacity = '0';
            tipsDisplay.style.transform = 'translateX(-100%)';
        }

        // 动画结束后更新提示文本并执行移入动画
        tipsDisplay.addEventListener('transitionend', () => {
            if (tipsDisplay.style.opacity === '0') {
                tipsDisplay.textContent = tipsList[currentTipIndex];
                tipsDisplay.style.opacity = '1';
                tipsDisplay.style.transform = 'translateX(100%)';

                requestAnimationFrame(() => {
                    tipsDisplay.style.transform = 'translateX(0)';
                });
            }
        });

        // 页面可见性变化时处理提示信息切换
        document.addEventListener('visibilitychange', () => {
            if (document.visibilityState === 'visible') {
                // 页面可见时,重新开始切换提示信息
                intervalId = setInterval(changeTip, 5000);
            } else {
                // 页面不可见时,停止切换提示信息
                clearInterval(intervalId);
            }
        });

        // 开始定时切换提示信息
        intervalId = setInterval(changeTip, 5000);
    }

    function updateVisibility() {
        const downloadInterface = document.getElementById('downloadInterface');
        const progressBarInterface = document.getElementById('downloadsContainer');
        const downloadIconContainer = document.getElementById('download_icon_container');
        const downloadListContainer = document.getElementById('download_list');

        if (downloadInterface) {
            downloadInterface.style.display = downloadInterfaceCheckbox.checked ? 'block' : 'none';
        }
        if (progressBarInterface) {
            const isVisible = progressBarCheckbox.checked;
            progressBarInterface.style.display = isVisible ? 'block' : 'none';
            isProgressBarVisible = isVisible; // 更新 isProgressBarVisible 的值
        }
    }

    let isFirstLoad = true;

    // 专门更新右下角下载列表可见性的函数
    function updateDownloadListVisibility() {
        const downloadIconContainer = document.getElementById('download_icon_container');
        const downloadListContainer = document.getElementById('download_list');
        const isVisible = downloadButtonCheckbox.checked;

        if (downloadIconContainer && downloadListContainer) {
            downloadIconContainer.style.display = isVisible ? 'block' : 'none';
            downloadListContainer.style.display = isVisible ? 'block' : 'none';
            downloadListContainer.style.opacity = isVisible ? '1' : '0';
            downloadListContainer.style.maxHeight = isVisible ? '300px' : '0';
        }
    }

    // 一开始就应用一次设置以匹配初始复选框状态
    updateVisibility();
    updateDownloadListVisibility();
}

window.onload = ()=> {
    add_download_button();
    initializeControlPanel();
    window.toggleListVisibility();
    console.oldLog = console.log;
    console.log = (...data) =>{
        if (data[0] == 'nodesToData')
        {
            course_resources = data[1];
            console.oldLog('::', course_resources);
            parseContent();
            return;
        }
        console.oldLog(...data);
    };

    // 定义快速筛选的类别选项
    window.quickFilters = [
        { label: "全部", value: "" },
        { label: "文档", value: "doc,docx,pdf,txt,odt,rtf,html,htm,xls,xlsx,ppt,pptx,odp" },
        { label: "图片", value: "jpg,jpeg,png,gif,bmp,tiff,svg,webp,tif" },
        { label: "压缩包", value: "zip,rar,7z,gz,bz2,tar" },
        // 可以继续添加其他类别
    ];

    window.abortControllers = {};

    // 创建一个 MutationObserver 实例
    const observer = new MutationObserver(function(mutationsList, observer) {
        // 在每次发生 DOM 变化时触发这个回调函数
        for(let mutation of mutationsList) {
            if (mutation.type === 'childList' && mutation.target.id === 'download_list') {
                // 重新添加搜索框和批量下载按钮
                window.updateUI();
                break; // 处理完毕后退出循环
            }
        }
    });

    // 配置需要观察的目标节点和观察的类型
    observer.observe(document.body, { childList: true, subtree: true });
};


// 定义要抓取的后缀名
var extensions = [".doc",".pdf",".docx",".ppt",".pptx",".xls",".xlsx",".txt",".odt",".rtf",".zip",".rar",".7z",".tar",".gz",".bz2",".xz"];

// 创建一个元素,用于显示抓取到的 URL
var list = document.createElement("div");
initializeListStyles(list);

// 添加CSS动画样式
var style = document.createElement('style');
style.innerHTML = `
@keyframes slideIn {
    from {
        opacity: 0;
        transform: translateX(100%);
    }
    to {
        opacity: 1;
        transform: translateX(0);
    }
}

@keyframes fadeOut {
    from {
        opacity: 1;
    }
    to {
        opacity: 0;
    }
}
`;
document.head.appendChild(style);

// 监听 xhr 请求,检查响应的 URL 是否符合条件
var open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
    var xhr = this;
    // 强制将所有请求设置为异步
    async = true;
    xhr.addEventListener("load", function() {
        // 如果 URL 包含指定的后缀名之一
        for (var i = 0; i < extensions.length; i++) {
            if (url.includes(extensions[i])) {
                // 发送一个新的 xhr 请求,获取真正的下载地址
                handleXhrResponse(url);
                break;
            }
        }
    });
    open.call(xhr, method, url, async, user, pass);
};

// 初始化列表样式
function initializeListStyles(element) {
    element.id = "downloadInterface";
    element.style.position = "fixed";
    element.style.top = "100px";
    element.style.right = "0";

    // 初始状态:缩成圆形,隐藏内容
    element.style.width = "50px";
    element.style.height = "50px";
    element.style.borderRadius = "50%";
    element.style.overflow = "hidden";
    element.style.transition = "all 0.3s ease-in-out";

    element.style.zIndex = "9997";
    element.style.padding = "10px";

    // 为元素添加渐变背景色
    element.style.background = "linear-gradient(270deg, #ffc700, #ff8c00, #ff6500)";
    element.style.backgroundSize = "400% 400%";

    // 添加动态背景动画的 CSS 规则
    var animStyle = document.createElement("style");
    animStyle.textContent = `
    @keyframes gradientBgAnimation {
      0% {
        background-position: 0% 50%;
      }
      50% {
        background-position: 100% 50%;
      }
      100% {
        background-position: 0% 50%;
      }
    }

    .dynamic-gradient {
      animation: gradientBgAnimation 15s ease infinite;
    }
  `;
    document.head.appendChild(animStyle);

    // 为元素添加动态渐变背景的类
    element.classList.add("dynamic-gradient");

    // 为元素添加阴影效果
    element.style.boxShadow = "0 4px 8px 0 rgba(0, 0, 0, 0.2)";

    // 为元素添加动画效果,悬停时放大
    element.addEventListener("mouseover", function() {
        element.style.transform = "scale(1.1)";
    });
    element.addEventListener("mouseout", function() {
        element.style.transform = "scale(1)";
    });

    element.innerHTML = "<h3><span style=\"font-family: '微软雅黑', 'Microsoft YaHei', sans-serif; font-weight: bold; font-style: italic; font-size: 16px;\">抓取到的课件</span></h3>";
    element.querySelector('h3').style.opacity = 0;

    // 创建一个容器来存放Lottie动画
    var lottieContainer = document.createElement('div');
    lottieContainer.style.position = "absolute";
    lottieContainer.style.transition = "all 0.3s ease-in-out"; // 添加 transition

    // Lottie 动画容器的初始位置和大小
    lottieContainer.style.width = "200%";
    lottieContainer.style.height = "200%";
    lottieContainer.style.left = "-60%";
    lottieContainer.style.top = "-45%";

    lottieContainer.style.overflow = "hidden";
    lottieContainer.style.zIndex = "9998";
    lottieContainer.style.pointerEvents = "none";

    // 创建并配置Lottie播放器
    var lottiePlayer = document.createElement('dotlottie-player');
    lottiePlayer.setAttribute('src', "https://lottie.host/995b71c8-b7aa-45b0-bb77-94b850da5d5d/dyezqbvtia.json");
    lottiePlayer.setAttribute('background', "transparent");
    lottiePlayer.setAttribute('speed', "1");
    lottiePlayer.setAttribute('style', "width: 125%; height: 100%; position: absolute; left: -12.5%;");
    lottiePlayer.setAttribute('loop', "");
    lottiePlayer.setAttribute('autoplay', "");

    // 将Lottie播放器添加到动画容器中
    lottieContainer.appendChild(lottiePlayer);

    // 将动画容器添加为列表元素的子元素
    element.appendChild(lottieContainer);

    // 点击事件:展开/收缩列表
    element.addEventListener("click", function() {
        if (element.style.width === "50px") {
            element.style.width = "350px";
            element.style.height = "10%";
            element.style.borderRadius = "10px";
            element.style.overflow = "auto";
            lottieContainer.style.width = "70%";
            lottieContainer.style.height = "100%";
            // 动态计算目标位置
            const targetLeft = element.offsetWidth - lottieContainer.offsetWidth + 120;
            const targetTop = -20;

            // 使用 transition 过渡
            lottieContainer.style.left = targetLeft + "px";
            lottieContainer.style.top = targetTop + "px";
            element.querySelector('h3').style.opacity = 1;
        } else {
            element.style.width = "50px";
            element.style.height = "50px";
            element.style.borderRadius = "50%";
            element.style.overflow = "hidden";
            // 缩小 Lottie 动画容器
            lottieContainer.style.width = "200%";
            lottieContainer.style.height = "200%";
            lottieContainer.style.left = "-60%";
            lottieContainer.style.top = "-45%";
            element.querySelector('h3').style.opacity = 0;
        }
    });
    document.body.appendChild(element);
}

// 全局变量,用于存储唯一的预览链接元素
var previewLink;
// 全局变量,用于标志是否有异步操作正在进行中
var isDownloading = false;

function handleXhrResponse(url) {
    if (isDownloading) {
        return; // 如果已经有下载在进行中,则跳过
    }

    isDownloading = true;
    const token = getCookie("HS-prd-access-token");

    var xhr = new XMLHttpRequest();
    xhr.open("GET", url, true);
    xhr.setRequestHeader("Authorization", `Bearer ${token}`);
    xhr.onload = function () {
        // 将响应的文本中的 "}}" 和引号替换为空字符串,去掉多余的符号
        var text = xhr.responseText.replace("}}", "").replace(/"/g, "");
        var match = text.match(/(http|https):\/\/\S+/);
        var content = document.title.split('|')[0].trim();

        if (match) {
            // 如果预览链接存在,先移除它并带动画效果
            if (previewLink) {
                previewLink.style.animation = "fadeOut 0.5s forwards";
                previewLink.addEventListener('animationend', function () {
                    if (previewLink && previewLink.parentNode) {
                        previewLink.parentNode.removeChild(previewLink);
                        previewLink = null;
                        createPreviewLink(match[0], content);
                    }
                });
            } else {
                createPreviewLink(match[0], content);
            }
        }
        isDownloading = false;
    }
    xhr.send();
}

// 检查是否已经存在预览链接,如果没有,则创建一个临时的提示预览链接
if (!previewLink || !document.contains(previewLink)) {
    createPreviewLink("#", "等待课件...( _ _)ノ|");
    previewLink.removeAttribute("href"); // 移除 href 属性使其不可点击
    previewLink.style.pointerEvents = "none"; // 确保用户无法与之交互
    previewLink.style.color = "#DDD"; // 将提示信息的颜色设置为浅灰色
}

function createPreviewLink(href, content) {
    // 清空列表中子元素之外所有元素
    while (list.childNodes.length > 2) {
        list.removeChild(list.lastChild);
    }
    // 如果存在旧的 previewLink,则更新其内容
    if (previewLink && document.contains(previewLink)) {
        previewLink.href = href;
        previewLink.textContent = content;
        previewLink.style.pointerEvents = ""; // 恢复交互
        previewLink.style.color = ""; // 恢复原有颜色
    } else {
        // 创建新预览链接
        previewLink = document.createElement("a");
        previewLink.style.background = "linear-gradient(to right, #ffffff, #ffecb3)";
        previewLink.style.backgroundClip = "text";
        previewLink.title = "点击以下载";
        previewLink.style.webkitBackgroundClip = "text";
        previewLink.style.color = "transparent";
        previewLink.style.fontFamily = "'微软雅黑', 'Microsoft YaHei', sans-serif";
        previewLink.style.fontWeight = "bold";
        previewLink.style.transition = "transform 0.3s, text-shadow 0.3s";
        previewLink.style.display = "inline-block";
        previewLink.style.position = "relative"; // 为动画设置定位

        // 为拖放功能添加拖动数据
        previewLink.draggable = true;
        previewLink.dataset.downloadUrl = href; // 设置下载网址
        previewLink.dataset.filename = content; // 设置文件名

        // 重新绑定拖动事件监听器
        previewLink.addEventListener('dragstart', (event) => {
            event.dataTransfer.effectAllowed = 'move';
            event.dataTransfer.setData('text/plain', previewLink.dataset.downloadUrl);
            event.dataTransfer.setData('text/filename', previewLink.dataset.filename);
        });

        // 悬停时的样式变化
        previewLink.addEventListener('mouseover', () => {
            previewLink.style.transform = "scale(1.05)"; // 轻微放大
            previewLink.style.textShadow = "0 0 8px rgba(255, 165, 0, 0.7)";
        });
        previewLink.addEventListener('mouseout', () => {
            previewLink.style.transform = "scale(1)"; // 恢复原样
            previewLink.style.textShadow = "none"; // 移除发光效果
        });
        // 点击时的样式变化
        previewLink.addEventListener('mousedown', () => {
            previewLink.style.transform = "scale(0.95)"; // 按下效果
        });
        previewLink.addEventListener('mouseup', () => {
            previewLink.style.transform = "scale(1.05)"; // 放开后放大效果
        });

        // 将预览链接添加到列表中
        list.appendChild(previewLink);
        list.appendChild(document.createElement("br"));

        // 更新预览链接的属性
        previewLink.href = href;
        previewLink.target = "_blank";
        previewLink.textContent = content;
        // 添加点击事件监听器,在点击时进行下载
        previewLink.addEventListener("click", function (event) {
            event.preventDefault(); // 阻止默认的点击行为
            // 直接使用 courseDownload 函数进行下载
            courseDownload(href, content);
        });

        // 添加动画效果
        previewLink.style.animation = "slideIn 0.5s forwards";
    }
}