您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在页面上增加按钮,直接下载课件原文件,一键合并下载章节所有课件
// ==UserScript== // @name 华文慕课课件下载助手 // @namespace http://tampermonkey.net/ // @version 1.0.0 // @description 在页面上增加按钮,直接下载课件原文件,一键合并下载章节所有课件 // @author goudanZ1 // @license MIT // @match https://www.chinesemooc.org/student/term_section_list.php* // @match https://www.chinesemooc.org/student/term_courseware_preview.php* // @icon https://www.chinesemooc.org/favicon.ico // @require https://unpkg.com/[email protected]/dist/pdf-lib.min.js // @grant none // @run-at document-end // ==/UserScript== (function () { 'use strict'; const { PDFDocument } = PDFLib; // Create a temporary element and download the file from url function downloadFile(fileUrl, fileName) { const link = document.createElement('a'); link.href = fileUrl; link.download = fileName; link.click(); } /* PREVIEW NODE: (term_courseware_preview.php) <h2 class="pagecont-header-title"> --- node 【课件】***.pdf </h2> */ function getFileName_pr(node) { return node.textContent.split('【课件】').pop().trim(); } function getFileUrl_pr(previewDoc) { return previewDoc.querySelector('#iframeViewPdf').src.split('file=').pop(); } function downloadFunc_pr(node, downloadBtn) { downloadBtn.textContent = '正在获取下载链接……'; downloadFile(getFileUrl_pr(document), getFileName_pr(node)); } /* COURSEWARE NODE: (term_section_list.php) <li class="second-list"> <div class="list-left"> --- node <a target="_blank" href="****"> --- previewUrl <div class="icon-file"><img></div> <div class="type">课件</div> <div class="title-name">****.pdf</div> --- fileName </a> </div> <div class="list-right"><a>下载</a></div> </li> */ function getFileName_cw(node) { return node.querySelector('a div.title-name').textContent.trim(); } // Get the source url of the file async function getFileUrl_cw(node) { const previewUrl = node.querySelector('a').href; try { const previewResponse = await fetch(previewUrl); const previewHtml = await previewResponse.text(); const parser = new DOMParser(); const previewDoc = parser.parseFromString(previewHtml, 'text/html'); return getFileUrl_pr(previewDoc); } catch (error) { alert('获取 ' + getFileName_cw(node) + ' 链接失败:' + error); return null; } } async function downloadFunc_cw(node, downloadBtn) { downloadBtn.textContent = '正在获取下载链接……'; const fileUrl = await getFileUrl_cw(node); if (!fileUrl) { return; } downloadFile(fileUrl, getFileName_cw(node)); } /* CHAPTER NODE: (term_section_list.php) <dl class="first-card"> <dt class="first-head active"> <div class="tag-wrap"> --- node <p class="num">*</p> <p class="tag">***</p> </div> <div class="first-retract"><img><span>收起</span></div> </dt> <dd class="second-card"> ... </dl> */ // Get courseware nodes from the descendants of a chapter node function getCoursewareChildren_ch(node) { const entryNodes = node.parentNode.parentNode.querySelectorAll('li.second-list div.list-left'); return Array.from(entryNodes).filter(node => node.querySelector('a div.type').textContent.trim() === '课件'); } // Use the chapter name as the name of the merged PDF file function getFileName_ch(node) { return node.querySelector('p.num').textContent.trim() + '-' + node.querySelector('p.tag').textContent.trim() + '.pdf'; } // Get an array of the source urls of all files in this chapter async function getFileUrls_ch(node) { const coursewareChildren = getCoursewareChildren_ch(node); const fileUrls = []; for (const coursewareNode of coursewareChildren) { // Don't use forEach, forEach isn't compatible with 'await' const url = await getFileUrl_cw(coursewareNode); if (url) { fileUrls.push(url); } } return fileUrls; } // For PDFs in one chapter, merge them into one (reference: https://pdf-lib.js.org/#copy-pages) async function mergePDFsAndDownload(fileUrls, fileName, downloadBtn) { if (fileUrls.length === 0) { return; } const mergedDoc = await PDFDocument.create(); for (const [index, url] of fileUrls.entries()) { downloadBtn.textContent = `正在合并第 ${index + 1} 份文件……`; const pdfResponse = await fetch(url); const pdfBytes = await pdfResponse.arrayBuffer(); const pdfDoc = await PDFDocument.load(pdfBytes); const pages = await mergedDoc.copyPages(pdfDoc, pdfDoc.getPageIndices()); pages.forEach(page => mergedDoc.addPage(page)); } downloadBtn.textContent = '合并完成,正在生成下载链接……'; const mergedBytes = await mergedDoc.save(); const blob = new Blob([mergedBytes], { type: 'application/pdf' }); const objectUrl = URL.createObjectURL(blob); downloadFile(objectUrl, fileName); URL.revokeObjectURL(objectUrl); } async function downloadFunc_ch(node, downloadBtn) { downloadBtn.textContent = '正在获取所有文件地址,请耐心等待……'; const fileUrls = await getFileUrls_ch(node); await mergePDFsAndDownload(fileUrls, getFileName_ch(node), downloadBtn); } // Create a download button as the last child of node and trigger downloadFunc when clicking it function createDownloadBtn(node, text, downloadFunc) { const downloadBtn = document.createElement('button'); downloadBtn.textContent = text; downloadBtn.style.cssText = 'margin-left: 15px; padding: 3px 8px; border: 1.5px solid #707070; border-radius: 5px; background-color:e9e9e9; cursor: pointer'; downloadBtn.onclick = async function () { downloadBtn.disabled = true; // downloadBtn.textContent = '正在获取下载链接……'; await downloadFunc(node, downloadBtn); downloadBtn.disabled = false; downloadBtn.textContent = text; }; node.appendChild(downloadBtn); } const url = window.location.href; if (url.startsWith('https://www.chinesemooc.org/student/term_courseware_preview.php')) { const node = document.querySelector('h2.pagecont-header-title'); createDownloadBtn(node, '下载原文件', downloadFunc_pr); } else if (url.startsWith('https://www.chinesemooc.org/student/term_section_list.php')) { const chapterNodes = document.querySelectorAll('dt.first-head div.tag-wrap'); var coursewareNodes = []; chapterNodes.forEach(node => { const coursewareChildren = getCoursewareChildren_ch(node); if (coursewareChildren.length > 0) { coursewareNodes = coursewareNodes.concat(coursewareChildren); createDownloadBtn(node, '下载本章所有课件的合并文件', downloadFunc_ch); } }); coursewareNodes.forEach(node => { createDownloadBtn(node, '下载原文件', downloadFunc_cw); }); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址