自动检测超星学习通中的PDF文件并添加下载按钮
// ==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);
}
});
})();