自动获取并合并PDF
- // ==UserScript==
- // @name Oxford Academic导出PDF
- // @namespace https://qinlili.bid
- // @version 1.0.0
- // @description 自动获取并合并PDF
- // @author 琴梨梨
- // @license WTFPL
- // @match https://academic.oup.com/edited-volume/*
- // @icon https://oup.silverchair-cdn.com/UI/app/img/v-638282418223920402/apple-touch-icon.png
- // @run-at document-idle
- // @require https://lib.baomitu.com/pdf-lib/1.17.1/pdf-lib.min.js#sha512-z8IYLHO8bTgFqj+yrPyIJnzBDf7DDhWwiEsk4sY+Oe6J2M+WQequeGS7qioI5vT6rXgVRb4K1UVQC5ER7MKzKQ==
- // @grant GM_xmlhttpRequest
- // @grant GM_registerMenuCommand
- // ==/UserScript==
- (async function() {
- //CODENAME:Carboxylate
- 'use strict';
- const config={
- //带目录导出,需要依赖闭源的PSPDFKIT,目前暂不可用,有待进一步开发
- writeOutline:false,
- //去除账号标识,开发中
- removeAccountInfo:false
- };
- GM.registerMenuCommand("原神,启动!", () => {
- location.href="https://ys.mihoyo.com/";
- });
- const dlFile = (link, name) => {
- let eleLink = document.createElement('a');
- eleLink.download = name;
- eleLink.style.display = 'none';
- eleLink.href = link;
- document.body.appendChild(eleLink);
- eleLink.click();
- document.body.removeChild(eleLink);
- };
- const loadScriptAsync = link => {
- return new Promise(resolve => {
- let script = document.createElement("script");
- script.src = link;
- script.onload = resolve;
- document.body.appendChild(script);
- });
- };
- switch(location.host){
- case("academic.oup.com"):{
- //文档详情页
- console.log("关注笙歌喵~关注帅比笙歌超可#OvO谢谢喵~");
- console.log("Carboxylate 1.0.0");
- const titleDiv=document.getElementsByClassName("book-bottom-section__title-wrap")[0];
- let dlBtn=document.createElement("button");
- dlBtn.innerText="下载全部PDF";
- titleDiv.appendChild(dlBtn);
- dlBtn.onclick=async ()=>{
- dlBtn.onclick=null;
- //阶段1:建立目录结构
- dlBtn.innerText="0% 分析目录结构";
- const catagory=document.getElementsByClassName("bookToc")[0];
- let parsedCatagory={
- title:document.getElementsByClassName("book-info__title")[0].innerText.trim(),
- author:document.getElementsByClassName("book-info__author-link")[0].innerText.trim(),
- chapters:[]
- };
- const parseChapter=(ele,depth)=>{
- if(ele.getElementsByClassName("collections-child-list").length==0||ele.getElementsByClassName("collections-child-list")[0].children.length==0){
- //顶级章节,直接处理
- [].forEach.call(ele.children,sub=>{
- if(sub.className=="tocLink"&&sub.tagName=="A"){
- //获取标题和链接
- parsedCatagory.chapters.push({
- title:(sub.getElementsByClassName("tocLink-label")[0]?sub.getElementsByClassName("tocLink-label")[0].innerText:"")+" "+sub.getElementsByClassName("tocLink-title")[0].innerText,
- link:sub.href,
- depth:depth,
- child:false,
- debug:sub
- });
- }
- })
- }else{
- //读取子章节
- parsedCatagory.chapters.push({
- title:(ele.getElementsByClassName("tocLink-label")[0]?ele.getElementsByClassName("tocLink-label")[0].innerText:"")+" "+ele.getElementsByClassName("tocLink-title")[0].innerText,
- link:null,
- depth:depth,
- child:true,
- debug:ele
- });
- //递归遍历
- [].forEach.call(ele.getElementsByTagName("ul")[0].getElementsByTagName("li"),ele=>{
- parseChapter(ele,depth+1);
- });
- }
- }
- [].forEach.call(catagory.children,ele=>{
- if(ele.tagName=="LI"){
- parseChapter(ele,0);
- }
- });
- console.log(parsedCatagory);
- //阶段2:解析PDF地址
- dlBtn.innerText="5% 解析PDF地址";
- let count=0;
- for(let chapter of parsedCatagory.chapters){
- if(chapter.child==false){
- //可下载的章节,需要解析地址
- let chapterRequest=await fetch(chapter.link, {
- "referrer": location.href,
- "method": "GET",
- "mode": "cors",
- "credentials": "include"
- });
- let chapterPage=await chapterRequest.text();
- const parser = new DOMParser();
- const chapterDoc = parser.parseFromString(chapterPage, "text/html");
- chapter.pdflink=chapterDoc.getElementsByClassName("at-pdfLink")[0].href;
- };
- count++;
- dlBtn.innerText=(5+25*count/parsedCatagory.chapters.length).toFixed(2)+"% 解析PDF地址["+count+"/"+parsedCatagory.chapters.length+"]";
- };
- console.log(parsedCatagory);
- //阶段3:分段下载PDF
- dlBtn.innerText="30% 下载PDF";
- count=0;
- for(let chapter of parsedCatagory.chapters){
- if(chapter.child==false){
- //异步跨域下载PDF
- function asyncFetch(){
- return new Promise(resolve => {
- let pic=GM_xmlhttpRequest({
- method: "GET", url: chapter.pdflink, responseType: "blob", onload: (res) => {
- console.log(res.response);
- chapter.pdffile=res.response;
- resolve();
- }
- })
- });
- }
- await asyncFetch();
- };
- count++;
- dlBtn.innerText=(30+60*count/parsedCatagory.chapters.length).toFixed(2)+"% 下载PDF["+count+"/"+parsedCatagory.chapters.length+"]";
- };
- console.log(parsedCatagory);
- //阶段4:合并PDF导出
- dlBtn.innerText="90% 合并PDF";
- const pdfDoc = await PDFLib.PDFDocument.create();
- count=0;
- pdfDoc.setTitle(parsedCatagory.title);
- pdfDoc.setAuthor(parsedCatagory.author);
- pdfDoc.setCreator("Carboxylate By QINLILI");
- pdfDoc.setCreationDate(new Date());
- pdfDoc.setModificationDate(new Date());
- //合并PDF并记录页码
- for(let chapter of parsedCatagory.chapters){
- if(chapter.child==false){
- //合并PDF
- const pdfObj=await PDFLib.PDFDocument.load(await chapter.pdffile.arrayBuffer());
- const copiedPages = await pdfDoc.copyPages(pdfObj, pdfObj.getPageIndices());
- copiedPages.forEach((page) => pdfDoc.addPage(page));
- chapter.pages=copiedPages.length;
- };
- count++;
- dlBtn.innerText=(90+6*count/parsedCatagory.chapters.length).toFixed(2)+"% 合并PDF["+count+"/"+parsedCatagory.chapters.length+"]";
- };
- console.log(parsedCatagory);
- //导出文件
- dlBtn.innerText="96% 写入目录";
- const mergedPdfFile = await pdfDoc.save();
- if(config.writeOutline){
- await loadScriptAsync("https://cdn.jsdelivr.net/npm/pspdfkit@2023.4.0/dist/pspdfkit.min.js");
- let foo=document.createElement("div");
- foo.className="foo";
- foo.style.width="100vw";
- foo.style.height="100vh";
- foo.style.display="none";
- document.body.appendChild(foo);
- let instance=await PSPDFKit.load({
- baseUrl:"https://cdn.jsdelivr.net/npm/pspdfkit@2023.4.0/dist/",
- document: mergedPdfFile.buffer,
- container:'.foo'
- });
- for(let chapter of parsedCatagory.chapters){
- const bookmark = new PSPDFKit.Bookmark({
- name: chapter.title,
- action: new PSPDFKit.Actions.GoToAction({ pageIndex: count })
- });
- await instance.create(bookmark);
- if(chapter.child==false){
- //小标题累计页码
- count+=chapter.pages;
- };
- };
- dlBtn.innerText="98% 导出文件 带目录导出耗时极长,请保持耐心";
- const documentBuffer = await instance.exportPDF();
- const pdfFile=new Blob([documentBuffer]);
- dlFile(URL.createObjectURL(pdfFile),parsedCatagory.title+".pdf")
- }else{
- dlBtn.innerText="98% 导出文件";
- const pdfFile=new Blob([mergedPdfFile]);
- dlFile(URL.createObjectURL(pdfFile),parsedCatagory.title+".pdf")
- };
- dlBtn.innerText="100% 下载成功";
- };
- break;
- };
- default:{
- break;
- }
- }
- })();