// ==UserScript==
// @name 小雅爬爬爬
// @match *://ccnu.ai-augmented.com/*
// @grant none
// @description 爬取课件url
// @license MIT
// @author Yi
// @version 1.0.4
// @namespace https://greasyfork.org/users/1268039
// ==/UserScript==
// 定义要抓取的后缀名
var extensions = [".doc", ".pdf", ".docx", ".ppt", ".pptx", ".xls", ".xlsx"];
// 创建一个元素,用于显示抓取到的 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 = "300px";
element.style.height = "10%";
element.style.overflow = "auto";
element.style.zIndex = "9999";
element.style.padding = "10px";
// 添加闪烁动画样式
var style = document.createElement("style");
style.textContent = `
@keyframes blink {
25% {
opacity: 0;
}
}
.blink-animation {
animation: blink 1s 3 alternate; /* 持续时间1秒,总共3次,alternate表示交替进行 */
}
`;
document.head.appendChild(style);
// 为元素添加渐变背景色
element.style.background = "linear-gradient(to right bottom, #ffc700, #ffa500)";
// 为元素添加阴影效果
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";
// 添加拖动事件监听器
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.color = "#40a9ff";
previewLink.style.fontFamily = "'微软雅黑', 'Microsoft YaHei', sans-serif";
previewLink.style.fontStyle = "italic";
previewLink.style.fontWeight = "bold";
// 将预览链接添加到列表中
list.appendChild(previewLink);
list.appendChild(document.createElement("br"));
}
// 更新预览链接的属性
previewLink.href = match[0];
previewLink.target = "_blank";
previewLink.textContent = content;
// 添加闪烁动画效果
list.classList.add("blink-animation");
// 设置定时器,在3秒后清除动画
setTimeout(function() {
list.classList.remove("blink-animation");
}, 3000);
// 添加点击事件监听器,在点击时进行下载
previewLink.addEventListener("click", function (event) {
event.preventDefault(); // 阻止默认的点击行为
// 异步获取 Blob 对象
getBlob(match[0]).then(function (blob) {
// 使用自定义文件名进行下载
saveAs(blob, content);
});
});
}
isDownloading = false;
// 将新创建的元素插入到列表的最前面
var titleElement = list.querySelector("h3");
if (titleElement) {
list.insertBefore(previewLink, titleElement.nextSibling);
} else {
list.appendChild(previewLink);
}
}
xhr.send();
}
// 异步获取 Blob 对象的函数
function getBlob(url) {
return new Promise(resolve => {
const xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.responseType = "blob"; // 请求类型是 blob 类型
xhr.crossOrigin = "*"; // 解决跨域问题
xhr.onload = () => {
if (xhr.status === 200) {
resolve(xhr.response);
}
};
xhr.send();
});
}
// 下载文件并重新命名的函数
function saveAs(blob, filename) {
if (window.navigator.msSaveOrOpenBlob) {
navigator.msSaveBlob(blob, filename);
} else {
const link = document.createElement("a");
const body = document.querySelector("body");
link.href = window.URL.createObjectURL(blob);
link.download = filename; // 修改文件名
link.style.display = "none";
body.appendChild(link);
link.click();
body.removeChild(link);
window.URL.revokeObjectURL(link.href);
}
}