超星学习通PDF下载器

自动检测超星学习通中的PDF文件并添加下载按钮

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         超星学习通PDF下载器
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  自动检测超星学习通中的PDF文件并添加下载按钮
// @author       Hungry Shark
// @match        https://mooc1.chaoxing.com/*
// @match        https://*.chaoxing.com/*
// @icon         https://s1.chu0.com/src/img/png/df/df6f0a1cb5834e1499253980756986ce.png?e=2051020800&token=1srnZGLKZ0Aqlz6dk7yF4SkiYf4eP-YrEOdM1sob:A8wAfloBVYeZ5nxCWRV3GRyerd8=
// @grant        GM_xmlhttpRequest
// @grant        GM_download
// @connect      mooc1.chaoxing.com
// @connect      cldisk.com
// @connect      s3.cldisk.com
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // 存储检测到的PDF信息
    let pdfInfo = null;
    let checkInterval = null;

    // 创建下载按钮
    function createDownloadButton() {
        // 如果按钮已存在,先移除
        const existingButton = document.getElementById('pdf-download-btn');
        if (existingButton) {
            existingButton.remove();
        }

        const downloadBtn = document.createElement('button');
        downloadBtn.id = 'pdf-download-btn';
        downloadBtn.innerHTML = '📥 下载PDF';
        downloadBtn.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            z-index: 10000;
            padding: 10px 15px;
            background: #4CAF50;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 14px;
            font-weight: bold;
            box-shadow: 0 2px 10px rgba(0,0,0,0.2);
            transition: all 0.3s ease;
        `;

        downloadBtn.addEventListener('mouseenter', function() {
            this.style.background = '#45a049';
            this.style.transform = 'scale(1.05)';
        });

        downloadBtn.addEventListener('mouseleave', function() {
            this.style.background = '#4CAF50';
            this.style.transform = 'scale(1)';
        });

        downloadBtn.addEventListener('click', downloadPDF);
        document.body.appendChild(downloadBtn);
    }

    // 下载PDF文件
    function downloadPDF() {
        if (!pdfInfo || !pdfInfo.pdf) {
            alert('未找到PDF文件链接');
            return;
        }

        const filename = pdfInfo.filename || 'download.pdf';
        const pdfFilename = filename.replace(/\.[^/.]+$/, "") + '.pdf';

        try {
            // 使用GM_download下载文件
            GM_download({
                url: pdfInfo.pdf,
                name: pdfFilename,
                onload: function() {
                    console.log('PDF下载成功:', pdfFilename);
                    showNotification('PDF下载成功!', 'success');
                },
                onerror: function(error) {
                    console.error('PDF下载失败:', error);
                    showNotification('PDF下载失败,请重试', 'error');

                    // 如果GM_download失败,尝试使用备用方法
                    fallbackDownload(pdfInfo.pdf, pdfFilename);
                }
            });
        } catch (e) {
            console.error('GM_download错误:', e);
            // 使用备用下载方法
            fallbackDownload(pdfInfo.pdf, pdfFilename);
        }
    }

    // 备用下载方法
    function fallbackDownload(url, filename) {
        const a = document.createElement('a');
        a.href = url;
        a.download = filename;
        a.target = '_blank';
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        showNotification('正在打开PDF下载链接...', 'info');
    }

    // 显示通知
    function showNotification(message, type) {
        const notification = document.createElement('div');
        notification.textContent = message;
        notification.style.cssText = `
            position: fixed;
            top: 80px;
            right: 20px;
            z-index: 10001;
            padding: 10px 15px;
            background: ${type === 'success' ? '#4CAF50' : type === 'error' ? '#f44336' : '#2196F3'};
            color: white;
            border-radius: 5px;
            font-size: 14px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.2);
            transition: all 0.3s ease;
        `;

        document.body.appendChild(notification);

        setTimeout(() => {
            notification.style.opacity = '0';
            setTimeout(() => {
                if (notification.parentNode) {
                    notification.parentNode.removeChild(notification);
                }
            }, 300);
        }, 3000);
    }

    // 监听XMLHttpRequest请求
    function interceptXHR() {
        const originalOpen = XMLHttpRequest.prototype.open;
        const originalSend = XMLHttpRequest.prototype.send;

        XMLHttpRequest.prototype.open = function(method, url, ...args) {
            this._url = url;
            return originalOpen.apply(this, [method, url, ...args]);
        };

        XMLHttpRequest.prototype.send = function(...args) {
            this.addEventListener('load', function() {
                if (this._url && this._url.includes('/ananas/status/') && this.status === 200) {
                    try {
                        const response = JSON.parse(this.responseText);
                        if (response.pdf && response.status === 'success') {
                            console.log('检测到PDF文件:', response);
                            pdfInfo = response;
                            createDownloadButton();
                        }
                    } catch (e) {
                        console.log('解析响应失败:', e);
                    }
                }
            });
            return originalSend.apply(this, args);
        };
    }

    // 监听Fetch请求
    function interceptFetch() {
        const originalFetch = window.fetch;
        window.fetch = function(...args) {
            return originalFetch.apply(this, args).then(response => {
                const url = args[0];
                if (typeof url === 'string' && url.includes('/ananas/status/')) {
                    response.clone().json().then(data => {
                        if (data.pdf && data.status === 'success') {
                            console.log('检测到PDF文件(Fetch):', data);
                            pdfInfo = data;
                            createDownloadButton();
                        }
                    }).catch(() => {});
                }
                return response;
            });
        };
    }

    // 定期检查页面中是否包含PDF链接
    function checkForPDFLinks() {
        // 检查iframe中的内容
        const iframes = document.querySelectorAll('iframe');
        iframes.forEach(iframe => {
            try {
                const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
                const links = iframeDoc.querySelectorAll('a[href*=".pdf"], embed[src*=".pdf"]');
                if (links.length > 0 && !pdfInfo) {
                    links.forEach(link => {
                        const pdfUrl = link.href || link.src;
                        if (pdfUrl.includes('.pdf')) {
                            pdfInfo = {
                                pdf: pdfUrl,
                                filename: pdfUrl.split('/').pop() || 'document.pdf'
                            };
                            createDownloadButton();
                        }
                    });
                }
            } catch (e) {
                // 跨域限制,无法访问iframe内容
            }
        });

        // 检查直接嵌入的PDF
        const embedPDF = document.querySelector('embed[type="application/pdf"]');
        if (embedPDF && embedPDF.src && !pdfInfo) {
            pdfInfo = {
                pdf: embedPDF.src,
                filename: 'embedded.pdf'
            };
            createDownloadButton();
        }
    }

    // 初始化
    function init() {
        console.log('超星学习通PDF下载器已启动');

        // 拦截XHR请求
        interceptXHR();

        // 拦截Fetch请求
        interceptFetch();

        // 定期检查PDF链接
        checkInterval = setInterval(checkForPDFLinks, 2000);

        // 初始检查
        setTimeout(checkForPDFLinks, 1000);
    }

    // 页面加载完成后初始化
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

    // 清理定时器
    window.addEventListener('beforeunload', function() {
        if (checkInterval) {
            clearInterval(checkInterval);
        }
    });

})();