// ==UserScript==
// @name 国家中小学智慧教育平台教材PDF电子课本链接与下载工具
// @namespace https://greasyfork.org/zh-CN/scripts/466598
// @version 1.2.2
// @description 教材列表页与预览页添加了PDF按钮,免登录查看或下载电子课本与课外书籍,可批量下载
// @match *://basic.smartedu.cn/*
// @match *://www.zxx.edu.cn/*
// @grant none
// @downloadURL none
// ==/UserScript==
(function() {
'use strict';
let link;
if (window.location.href.startsWith("https://basic.smartedu.cn/tchMaterial/")) {
const pattern = /contentId=([a-zA-Z0-9_-]+)/; // 匹配 contentId 的正则表达式
const contentId = window.location.href.match(pattern)[1]; // 获取 contentId 的数值
link = `https://r3-ndr.ykt.cbern.com.cn/edu_product/esp/assets_document/${contentId}.pkg/pdf.pdf`;
// window.location.href = link; // 直接重定向到该网址,经测试可用
}
const maxTimeToCheck = 5000; // 最多检查 5000 毫秒,即 5 秒
let elapsedTime = 0;
function checkConfirmButtons() {
const confirmBtns = document.querySelector(".fish-modal-confirm-btns");
if (confirmBtns) {
// 去除阻碍
document.querySelector("body > div:nth-of-type(2)").remove(); // 去除遮罩
const body = document.querySelector("html > body"); // 去除 body 属性
body.removeAttribute("class");
body.removeAttribute("style");
// 添加阅读器
const name = document.querySelector("#main-content > div.content > div.web-breadcrumb > div > span:nth-child(3) > span.fish-breadcrumb-link")?.textContent;
const indexModuleWrapperECeCo = document.querySelector(".index-module_wrapper_ECeCo");
if (indexModuleWrapperECeCo) {
indexModuleWrapperECeCo.innerHTML = `
`;
}
// 全屏切换
const fullscreenBtn = document.querySelector(".tool-btn.fullscreen");
const courseDocument = document.querySelector(".course-document");
const htmlElement = document.querySelector("html");
fullscreenBtn.addEventListener("click", () => {
if (courseDocument.classList.contains("full-screen")) { // 当前处于"全屏状态",切换为"非全屏状态"
courseDocument.classList.remove("full-screen");
htmlElement.style.overflow = "";
} else { // 当前处于"非全屏状态",切换为"全屏状态"
courseDocument.classList.add("full-screen");
htmlElement.style.overflow = "hidden";
}
});
// 重定向至登录页
const toLogin = [
document.querySelector("#main-content > div.content > div.index-module_special-edu-detail_aH1Nr > div > div > div > div.index-module_header_tG-zz > div > div.index-module_assesment-detail_jhGLz > span"),
document.querySelector("#main-content > div.content > div.index-module_special-edu-detail_aH1Nr > div > div > div > div.index-module_header_tG-zz > div > div.index-module_extra_tUQog > div.index-module_like-wrap_NbyLe"),
document.querySelector("#main-content > div.content > div.index-module_special-edu-detail_aH1Nr > div > div > div > div.index-module_header_tG-zz > div > div.index-module_extra_tUQog > div.index-module_suggestion-wrap_s\\+Ii\\+")
];
toLogin.forEach(element => {
element.addEventListener("click", () => {
window.open("https://auth.smartedu.cn/uias/login/");
});
});
clearInterval(intervalId1); // 清除定时器
} else {
elapsedTime += 100;
if (elapsedTime >= maxTimeToCheck) {
clearInterval(intervalId1); // 清除定时器,停止检查
}
}
}
const intervalId1 = setInterval(checkConfirmButtons, 100); // 每隔 100 毫秒检查一次 fish-modal-confirm-btns 元素是否存在
function checkIndexModule() {
const container = document.querySelector(".index-module_extra_tUQog"); // 找到要添加按钮的容器元素
if (container) {
const div = document.createElement("div");
div.className = "Btns";
div.innerHTML = `📓 查看PDF📓 下载PDF`;
container.appendChild(div); // 将按钮添加到网页中
const element1 = document.querySelector("div.Btns > a.link");
if (element1) {
element1.addEventListener("mouseover", function() {
this.innerHTML = "📘 查看PDF";
this.style.color = "#226dec"; // 鼠标移入时修改元素的样式
});
element1.addEventListener("mouseout", function() {
this.innerHTML = "📓 查看PDF";
this.style.color = "#888"; // 鼠标移出时恢复原来的样式
});
element1.addEventListener("mousedown", function() {
this.innerHTML = "📘 查看PDF";
this.style.color = "#226dec"; // 鼠标按下时修改元素的样式
});
}
const element2 = document.querySelector("div.Btns > a.download");
if (element2) {
element2.addEventListener("click", function(event) { // 点击下载
var fileUrl = link;
var xhr = new XMLHttpRequest();
xhr.open("GET", fileUrl);
xhr.responseType = "blob";
xhr.onloadstart = function() { // 初始化进度
element2.innerText = "0%";
};
xhr.onprogress = function(event) {
if (event.lengthComputable) {
var progress = Math.round((event.loaded / event.total) * 100);
element2.innerText = "📓 下载中 (" + progress + "%)";
}
};
xhr.onload = function() {
if (xhr.status === 200) {
var blob = xhr.response;
var downloadLink = document.createElement("a");
downloadLink.href = URL.createObjectURL(blob);
downloadLink.download = document.querySelector(".index-module_title_bnE9V").innerText; // 文件名
downloadLink.dispatchEvent(new MouseEvent("click"));
element2.innerText = "📓 下载PDF"; // 下载完成后恢复按钮文字
}
};
xhr.send(); // 发送请求
});
}
clearInterval(intervalId2); // 清除定时器
} else {
elapsedTime += 100;
if (elapsedTime >= maxTimeToCheck) {
clearInterval(intervalId2); // 清除定时器,停止检查
}
}
}
const intervalId2 = setInterval(checkIndexModule, 100); // 每隔 100 毫秒检查一次 index-module_extra_tUQog 元素是否存在
if (window.location.href.startsWith("https://basic.smartedu.cn/schoolService/")) {
const originalFetch = window.fetch;
window.fetch = function (url, options) {
if (url.endsWith(".pdf")) {
// window.location.href = url;
const element1 = document.querySelector("div.Btns > a.link"); // 按钮 element1
element1 && (element1.href = url); // 修改 element1 的链接
link = url; // 修改 element2 的链接
}
return originalFetch(url, options);
};
}
function checkIndexModules() {
const item = document.querySelectorAll("li.index-module_item_GfOnF");
if (item) {
const img = document.querySelectorAll("div.index-module_cover_DGT6P > img");
let pdfArray = []; // 声明PDF空数组
for (let i = 0; i < img.length; i++) {
if (img[i]) {
const src = img[i].getAttribute("src");
let pdf;
if (src.includes("esp/assets/")) {
let extractedText = src.match(/assets\/(.*?)\./)[1];
pdf = `https://r3-ndr.ykt.cbern.com.cn/edu_product/esp/assets_document/${extractedText}.pkg/pdf.pdf`;
} else if (src.includes("esp/assets_document/")) {
let extractedText = src.match(/assets_document\/(.*?)\./)[1];
pdf = `https://r3-ndr.ykt.cbern.com.cn/edu_product/esp/assets_document/${extractedText}.pkg/pdf.pdf`;
} else if (src.includes("65/document/")) {
let extractedText = src.match(/document\/(.*?)\/image/)[1];
pdf = `https://v3.ykt.cbern.com.cn/65/document/${extractedText}/pdf.pdf`;
} else {
console.log("未识别链接");
}
if (pdf) {
pdfArray.push(pdf); // 将 pdf 添加到数组中
console.log(`pdf${i + 1}: ${pdf}`);
}
clearInterval(intervalId3); // 查找到 img,清除定时器停止检查
}
}
const content = document.querySelectorAll("div.index-module_content_KmLzG");
for (let i = 0; i < content.length; i++) {
if (content[i]) {
content[i].setAttribute("style", "width: 500px;"); // 统一 content 宽度
}
}
const contentName = document.querySelectorAll("div.index-module_line_LgJAC");
const added_PDF_btns = document.querySelectorAll("li.index-module_item_GfOnF > div.PDF-btns");
for (let i = 0; i < item.length; i++) {
if (item[i] && !added_PDF_btns[i] && pdfArray[i]) {
const PDF_btns = document.createElement("div"); // 创建 PDF_btns
PDF_btns.setAttribute("class", "PDF-btns");
PDF_btns.setAttribute("style", "width: 300px;");
PDF_btns.innerHTML = `
查看PDF
下载PDF
`;
item[i].appendChild(PDF_btns); // 将 PDF_btns 添加到父元素中
PDF_btns.addEventListener("click", function(event) { // 停止 PDF_btns 的点击事件向更上一层元素传播
event.stopPropagation();
});
const element2 = document.querySelectorAll("div.PDF-btns > a.fish-btn.fish-btn-primary")[i];
if (element2) {
element2.addEventListener("click", function(event) { // 点击下载
var fileUrl = pdfArray[i];
var xhr = new XMLHttpRequest();
xhr.open("GET", fileUrl);
xhr.responseType = "blob";
xhr.onloadstart = function() { // 初始化进度
element2.innerText = "下载中0%";
};
xhr.onprogress = function(event) {
if (event.lengthComputable) {
var progress = Math.round((event.loaded / event.total) * 100);
element2.innerText = "下载中 (" + progress + "%)";
}
};
xhr.onload = function() {
if (xhr.status === 200) {
var blob = xhr.response;
var downloadLink = document.createElement("a");
downloadLink.href = URL.createObjectURL(blob);
downloadLink.download = contentName[i].querySelector("span").getAttribute("title"); // 文件名
downloadLink.dispatchEvent(new MouseEvent("click"));
element2.innerText = "下载PDF"; // 下载完成后恢复按钮文字
}
};
xhr.send(); // 发送请求
});
}
}
}
} else {
elapsedTime += 100;
if (elapsedTime >= maxTimeToCheck) {
clearInterval(intervalId3); // 清除定时器,停止检查
}
}
}
let intervalId3 = setInterval(checkIndexModules, 100); // 每隔 100 毫秒检查一次
function doItAgain() {
clearInterval(intervalId3); // 防止多次启动定时器
elapsedTime = 0; // 逝去时间归零
intervalId3 = setInterval(checkIndexModules, 100); // 创建新的定时器以待调用
}
const observer = new MutationObserver(function(mutations) { // 创建一个MutationObserver
console.log("DOM树发生变化"); // 页面变化时执行的代码
doItAgain(); // 执行新的定时器
});
const config = { // 配置需要观察的内容
childList: true, // 监听子节点的变化
subtree: true // 监听所有后代节点的变化
};
observer.observe(document.body, config); // 将观察器绑定到根节点上
})();