Greasy Fork镜像 还支持 简体中文。

小雅爬爬爬

爬取课件url

目前為 2024-05-10 提交的版本,檢視 最新版本

// ==UserScript==
// @name        小雅爬爬爬
// @match      *://ccnu.ai-augmented.com/*
// @grant       none
// @description 爬取课件url
// @license MIT
// @author     Yi
// @version    1.1.0
// @namespace  https://gf.qytechs.cn/users/1268039
// ==/UserScript==

(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;

// 附件下载实现细节
function parseContent() {
    console.oldLog("::parseContent");

    var download_url = 'https://ccnu.ai-augmented.com/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 file_name = course_resources[i].name;
        if (course_resources[i].mimetype) {
            fetch(download_url + course_resources[i].quote_id).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.style.display = 'flex';
                    file_container.style.alignItems = 'center';

                    // 创建勾选框
                    var checkbox = document.createElement('input');
                    checkbox.type = '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 = 'link-style'; // 应用初始样式
                    file_info.style.textDecoration = 'none'; // 去掉下划线
                    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_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 = 'space-between';
                    file_container.style.alignItems = 'center';
                    file_container.style.display = 'flex';

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

                    // 将包含勾选框和链接的容器添加到下载列表
                    download_list.append(file_container);
                }
            }).catch(function(e) {
                console.oldLog('!!error', e);
            });
        }
    }
}

// 在文档中创建一个容器来放置所有下载进度条
let downloadsContainer = document.getElementById('downloadsContainer');
if (!downloadsContainer) {
    downloadsContainer = document.createElement('div');
    downloadsContainer.id = 'downloadsContainer';
    downloadsContainer.style.position = 'fixed';
    downloadsContainer.style.bottom = '10px';
    downloadsContainer.style.left = '50%';
    downloadsContainer.style.transform = 'translateX(-50%)';
    downloadsContainer.style.zIndex = '9999';
    downloadsContainer.style.backgroundColor = '#FFF3E0';
    downloadsContainer.style.boxShadow = '0 4px 6px rgba(255, 165, 0, 0.3)';
    downloadsContainer.style.borderRadius = '8px';
    downloadsContainer.style.padding = '15px';
    downloadsContainer.style.width = 'auto';
    downloadsContainer.style.maxWidth = '500px';
    downloadsContainer.style.boxSizing = 'border-box';
    downloadsContainer.style.margin = '0 auto';
    downloadsContainer.style.border = '1px solid #FFD180';

    // 设置最大高度限制和溢出滚动
    downloadsContainer.style.maxHeight = '400px'; // 根据实际需求调整此值
    downloadsContainer.style.overflowY = 'auto'; // 当内容超出容器时显示垂直滚动条

    document.body.appendChild(downloadsContainer);
    // 创建 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/21dfc4c5-2d42-4f18-b67b-e3c8e50a2ce5/YYdHUeyfW2.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);
}

// 初始化拖动功能的变量
let isDragging = false;
let dragStartX = 0;
let dragStartY = 0;

// 函数:开始拖动
function dragStart(e) {
    // 记录初始拖动位置
    isDragging = true;
    dragStartX = e.clientX - downloadsContainer.getBoundingClientRect().left;
    dragStartY = e.clientY - downloadsContainer.getBoundingClientRect().top;
    document.addEventListener('mousemove', dragMove);
    document.addEventListener('mouseup', dragEnd);
}

// 函数:拖动时调用
function dragMove(e) {
    if (!isDragging) return; // 如果不是拖动状态,则退出
    // 计算容器新的位置
    let leftPos = e.clientX - dragStartX;
    let topPos = e.clientY - dragStartY;

    // 更新容器位置
    downloadsContainer.style.left = `${leftPos}px`;
    downloadsContainer.style.top = `${topPos}px`;
    downloadsContainer.style.bottom = 'auto'; // 当开始拖动时,移除bottom样式以允许自由定位
    downloadsContainer.style.transform = 'none'; // 移除transform样式,因为已经改为绝对定位
}

// 函数:停止拖动时调用
function dragEnd() {
    // 更新状态
    isDragging = false;
    document.removeEventListener('mousemove', dragMove);
    document.removeEventListener('mouseup', dragEnd);
}

// 添加鼠标按下时的事件监听器来初始化拖拽
downloadsContainer.addEventListener('mousedown', dragStart);

function updateDownloadsContainerVisibility() {
    downloadsContainer.style.display = downloadsContainer.children.length > 0 ? 'block' : 'none';
}

function courseDownload(file_url, file_name) {
    const downloadsContainer = document.getElementById('downloadsContainer');
    downloadsContainer.style.display = 'block';

    // 创建进度条相关元素。
    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 到 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.remove();
        delete window.abortControllers[file_name];
        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; }
            }
        `;
        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];
    }

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


        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);
                downloadsContainer.removeChild(progressContainer);
                updateDownloadsContainerVisibility(); // 确保定义了这个函数来更新下载容器元素的显示
                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();
            updateDownloadsContainerVisibility(); // 确保定义了这个函数来更新下载容器元素的显示
        });
    });
}

window.showList = 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>`; // 使用 transform: scaleX(-1); 实现水平翻转
        lottieContainer.style.position = "absolute";
        lottieContainer.style.top = "50%";
        lottieContainer.style.right = "0";
        lottieContainer.style.transform = "translateY(-50%)"; // 垂直居中
        lottieContainer.style.zIndex = "-1"; // 确保它在内容之后作为背景

        download_list.style.position = "relative"; // 确保下载列表具有相对位置
        download_list.appendChild(lottieContainer); // 将动画容器插入为子元素
    }

    // 创建或获取容器,用于并排放置搜索框和快速筛选下拉框
    var container = document.getElementById("searchAndFilterContainer");
    if (!container) {
        container = document.createElement("div");
        container.id = "searchAndFilterContainer";
        container.style.display = "flex"; // 应用 Flexbox 布局
        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 = '1px solid #ddd';
        searchInput.style.borderRadius = '4px';
        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 = '1px solid #ddd';
        quickFilterSelect.style.borderRadius = '4px';

        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); // 将快速筛选下拉框添加到容器中
    }

    // 检查是否已存在全选复选框
    var existingSelectAllCheckbox = document.getElementById("selectAllCheckbox");
    if (!existingSelectAllCheckbox) {
        // 创建全选复选框
        var selectAllCheckbox = document.createElement('input');
        selectAllCheckbox.type = 'checkbox';
        selectAllCheckbox.id = 'selectAllCheckbox';
        selectAllCheckbox.style.marginRight = '10px';

        var selectAllLabel = document.createElement('label');
        selectAllLabel.htmlFor = 'selectAllCheckbox';
        selectAllLabel.textContent = '全选';
        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.alignItems = 'center';
        checkboxContainer.style.justifyContent = 'space-between';
        checkboxContainer.style.padding = '5px 10px';
        checkboxContainer.style.borderBottom = '2px solid #fcbb34'; // 用主题颜色画分隔线
        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;
                    // 手动触发 change 事件
                    var event = new Event('change', {
                        'bubbles': true, // 使事件冒泡
                        'cancelable': true // 使事件可以被取消
                    });
                    checkbox.dispatchEvent(event);
                }
            });
        });
    }

    if (download_list.style.display == "none") {
        download_list.style.display = "flex";
        download_list.style.overflowY = "auto"; // 添加垂直滚动条
        download_list.style.backgroundColor = "#ffffff";
        download_list.style.maxHeight = "300px"; // 设置最大高度,根据需要调整
    } else {
        download_list.style.display = "none";
    }

    // 检查是否已经创建了批量下载按钮
    var existingbulkDownloadButton = document.getElementById("bulkDownloadButton");
    if (!existingbulkDownloadButton) {
        // 检查是否已经创建了批量下载按钮
        var existingBulkDownloadButton = document.getElementById("bulkDownloadButton");
        if (!existingBulkDownloadButton) {
            // 添加批量下载按钮
            window.bulkDownloadButton = document.createElement('button');
            window.bulkDownloadButton.innerHTML = '批量下载';
            window.bulkDownloadButton.id = "bulkDownloadButton";
            window.bulkDownloadButton.title = '点击下载所选文件'; // 添加提示文本
            window.bulkDownloadButton.style = `
            position: fixed;
            top: 20px;
            right: 20px;
            background-color: #fcbb34;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 5px;
            cursor: pointer;
            box-shadow: 0 2px 4px rgba(0,0,0,0.2);
            transition: background-color 0.3s, transform 0.3s;
        `;

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

            window.bulkDownloadButton.addEventListener('mouseout', function() {
                this.style.transform = 'scale(1)';
                this.style.backgroundColor = '#fcbb34';
            });
        }
        window.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.textContent;
                    var file_url = link.href;

                    // 调用下载函数
                    courseDownload(file_url, file_name);
                }
            });
        });

        // 将批量下载按钮添加到下载列表
        download_list.appendChild(window.bulkDownloadButton);
    }
}

function filterList(keyword) {
    keyword = keyword.toLowerCase();
    var files = document.querySelectorAll("#download_list a");
    files.forEach(function(file) {
        var container = file.parentElement;
        var fileName = file.textContent.toLowerCase();
        var checkbox = container.querySelector("input[type='checkbox']");
        if (fileName.includes(keyword)) {
            container.style.display = "";
            checkbox.setAttribute('data-visible', 'true');
        } else {
            container.style.display = "none";
            checkbox.setAttribute('data-visible', 'false'); // 当文件被过滤掉时,设置复选框为不可见
        }
    });
}

function filterListByCategory(categoryValue) {
    var files = document.querySelectorAll("#download_list a");
    var extensions = categoryValue.split(',').map(ext => ext.trim()); // 通过逗号分隔并移除空格得到后缀名数组

    files.forEach(function(file) {
        var container = file.parentElement;
        var checkbox = container.querySelector("input[type='checkbox']");
        // 提取文件扩展名
        var fileName = file.textContent.toLowerCase();
        var fileExtension = fileName.slice(((fileName.lastIndexOf(".") - 1) >>> 0) + 2);

        // 检查文件扩展名是否在分类中
        var isVisible = categoryValue === "" || extensions.includes(fileExtension);
        container.style.display = isVisible ? "" : "none";
        checkbox.setAttribute('data-visible', isVisible.toString());
    });

    // 如果快速筛选后,全选复选框仍然选中,且不对应任何选项时,取消其勾选状态
    var selectAllCheckbox = document.getElementById('selectAllCheckbox');
    if (selectAllCheckbox && selectAllCheckbox.checked) {
        var anyCheckboxVisible = Array.from(document.querySelectorAll("#download_list input[type='checkbox']")).some(checkbox => checkbox.getAttribute('data-visible') === 'true');
        if (!anyCheckboxVisible) {
            selectAllCheckbox.checked = false;
        }
    }
}

function add_download_button() {
    // 全局变量用于保存批量下载按钮
    window.bulkDownloadButton = null;
    var down_button = document.createElement('div');
    down_button.innerHTML = `
<div id="download_list" style="z-index:999;backdrop-filter: blur(10px);border: 2px solid #fcbb34;border-radius: 5px;display: none;padding: 20px;flex-direction: column;align-items: flex-start;">
    <h3 style="color:#fcbb34; font-weight:bold;">课程附件清单</h3>
</div>
<dotlottie-player src="https://lottie.host/67403f9b-b050-4414-9307-1096cb6088f2/lb6v8cv81d.json" background="transparent" speed="1" style="width: 100px; height: 100px; margin: -15px;" loop autoplay onclick="showList()"></dotlottie-player>
`;

    // 添加下载图标的样式
    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);

    down_button.style.cssText = `
  position: fixed;
  right: 20px;
  bottom: -5px;
  z-index: 9000;
  cursor: pointer;
`;

    // 确保已经有这样的代码来设置图标的悬停动画
    var existingStyles = document.getElementById('download-icon-styles');
    if (!existingStyles) {
        document.head.appendChild(downloadIconStyle);
    }
    document.body.appendChild(down_button);
}

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

    // 定义快速筛选的类别选项
    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" },
        { 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.showList();
                break; // 处理完毕后退出循环
            }
        }
    });

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

    // 添加下载按钮并延迟显示
    setTimeout(() => {
        add_download_button();
    }, 2000);
};


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

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


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

// 初始化列表样式
function initializeListStyles(element) {
    element.style.position = "fixed";
    element.style.top = "10px";
    element.style.right = "0";
    element.style.width = "350px";
    element.style.height = "10%";
    element.style.overflow = "auto";
    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.style.borderRadius = "10px";
    // 为元素添加动画效果,悬停时放大
    element.style.transition = "transform 0.3s";
    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>";
    // 添加 draggable 属性,可拖动
    element.setAttribute("draggable", "true");
    // 添加 resize 属性,可调整大小
    element.style.resize = "both";
    // 创建一个容器来存放Lottie动画
    var lottieContainer = document.createElement('div');
    lottieContainer.style.position = "absolute";
    lottieContainer.style.top = "-20px";
    lottieContainer.style.left = "95px";
    lottieContainer.style.width = "120%";
    lottieContainer.style.height = "120%";
    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: 100%; height: 100%;");
    lottiePlayer.setAttribute('loop', "");
    lottiePlayer.setAttribute('autoplay', "");

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

    // 将动画容器添加为列表元素的子元素
    element.appendChild(lottieContainer);
    // 添加拖动事件监听器
    element.addEventListener("dragstart", function(e) {
        // 设置拖动元素的透明度
        e.target.style.opacity = "0.5";
        // 设置拖动元素的 id
        e.dataTransfer.setData("text/plain", e.target.id);
        // 记录拖动元素的初始位置和鼠标的初始位置
        e.target.startX = e.clientX;
        e.target.startY = e.clientY;
        e.target.offsetX = e.target.offsetLeft;
        e.target.offsetY = e.target.offsetTop;
    });
    element.addEventListener("drag", function(e) {
        // 如果鼠标的位置有效,根据鼠标的移动距离,更新拖动元素的位置
        if (e.clientX > 0 && e.clientY > 0) {
            e.target.style.left = e.target.offsetX + e.clientX - e.target.startX + "px";
            e.target.style.top = e.target.offsetY + e.clientY - e.target.startY + "px";
        }
    });
    element.addEventListener("dragend", function(e) {
        // 恢复拖动元素的透明度
        e.target.style.opacity = "1";
    });
    document.body.appendChild(element);
}

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

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

    isDownloading = true;

    // 清除之前的预览链接元素
    if (previewLink) {
        previewLink.parentNode.removeChild(previewLink);
        previewLink = null;
    }
    var xhr = new XMLHttpRequest();
    xhr.open("GET", url, true);
    xhr.onload = function () {
        // 如果响应的文本中包含一个以 http 或 https 开头的 URL,将其添加到列表中
        // 在此之前,先将响应的文本中的 "}}" 和引号替换为空字符串,去掉多余的符号
        var text = xhr.responseText.replace("}}", "").replace(/"/g, "");
        var match = text.match(/(http|https):\/\/\S+/);
        var titleBannerElement = document.querySelector('.common_node_content_banner h5.title');
        var content;

        if (titleBannerElement && titleBannerElement.getAttribute('title')) {
            content = titleBannerElement.getAttribute('title').trim();
        } else {
            content = titleBannerElement.textContent.trim();
        }

        if (match) {
            // 如果预览链接不存在,则创建
            if (!previewLink) {
                previewLink = document.createElement("a");
                previewLink.style.background = "#06566f";
                // 使用背景剪裁
                previewLink.style.webkitBackgroundClip = "text";
                previewLink.style.backgroundClip = "text";
                // 设置文字颜色为透明以使渐变可见
                previewLink.style.color = "transparent";
                previewLink.style.fontFamily = "'微软雅黑', 'Microsoft YaHei', sans-serif";
                previewLink.style.fontWeight = "bold";
                // 悬停时的样式变化
                previewLink.addEventListener('mouseover', () => {
                    previewLink.style.backgroundColor = '#ffffff'; // 更改背景色
                });
                previewLink.addEventListener('mouseout', () => {
                    previewLink.style.backgroundColor = '#06566f'; // 恢复背景色

                });
                // 将预览链接添加到列表中
                list.appendChild(previewLink);
                list.appendChild(document.createElement("br"));
            }
            // 更新预览链接的属性
            previewLink.href = match[0];
            previewLink.target = "_blank";
            previewLink.textContent = content;
            // 添加点击事件监听器,在点击时进行下载
            previewLink.addEventListener("click", function (event) {
                event.preventDefault(); // 阻止默认的点击行为
                // 直接使用 courseDownload 函数进行下载
                courseDownload(match[0], content);
            });
        }
        isDownloading = false;

        // 将新创建的元素插入到列表的最前面
        var titleElement = list.querySelector("h3");
        if (titleElement) {
            list.insertBefore(previewLink, titleElement.nextSibling);
        } else {
            list.appendChild(previewLink);
        }
    }
    xhr.send();
}

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址