${
`
`.repeat(num)
}
`;
// 移除最后一个多出的gap
Array.from(article.querySelectorAll(".gap")).at(-1).remove();
return article;
}
function setGap(height) {
let style = wk$(".wk-settings")[0].innerHTML;
wk$(".wk-settings")[0].innerHTML = style.replace(
/[.]gap.*?{.*?height:.+?;/s,
`.gap { height: ${parseInt(height)}px;`
);
}
function setGapGUI() {
let now = getComputedStyle(wk$(".gap")[0]).height;
let new_h = prompt(`当前间距:${now}\n请输入新间距:`);
if (new_h) {
setGap(new_h);
}
}
/**
* 处理svg的url
* @param {string} svg_url
*/
async function handleSVGurl(svg_url) {
let resp = await fetch(svg_url);
let data = await resp.text();
let sep = " sep + svg_text);
console.log(`共 ${svg_texts.length} 张图片`);
let article = _createDiv(data);
let boxes = article.querySelectorAll(".svg-box");
boxes.forEach((obj, i) => {
let blob = new Blob([svg_texts[i]], {type: "image/svg+xml"});
let url = URL.createObjectURL(blob);
obj.data = url;
URL.revokeObjectURL(blob);
});
let body = wk$("body")[0];
body.innerHTML = "";
body.appendChild(article);
utils.createBtns();
utils.setBtnEvent(utils.hideBtnThenPrint, [], "btn_1", "打印页面到PDF");
utils.setBtnEvent(setGapGUI, [], "btn_2", "重设页间距");
utils.toggleBtnStatus("btn_2");
console.log("请按下【CTRL + P】以打印页面");
}
/**
* 取得图片下载地址
* @param {string} fname
* @param {string} path
* @returns
*/
function getImgUrl(fname, path) {
if (!fname) {
throw new Error("URL Param `fname` does not exist.");
}
return location.href
.replace(/[?].+?&ssig/, "?ssig")
.replace("?", path + "?");
}
/**
* 下载整个图片包
* @param {string} img_url
* @returns
*/
async function getData(img_url) {
let resp = await fetch(img_url);
let buffer = await resp.arrayBuffer();
return new Uint8Array(buffer);
}
/**
* 分切图片包为若干图片
* @param {Uint8Array} data 多张图片合集数据包
* @returns {Array
} 图片列表
*/
function parseData(data) {
// 判断图像类型/拿到文件头
let head = data.slice(0, 10);
// let type = getImgType(head);
let sep = head.join() + ",";
// 切断,重组,格式转换
return data.join().split(sep).slice(1).map(
val => new Uint8Array((sep + val).split(","))
);
}
/**
* 图像Uint8数组列表合并然后导出PDF
* @param {string} fname
* @param {Array} img_data_list
*/
async function imgDataArrsToPDF(fname, img_data_list) {
let cover_blob = new Blob([img_data_list[0]]);
let cover = await createImageBitmap(cover_blob);
utils.saveCanvasesToPDF(
img_data_list,
fname,
cover.width,
cover.height
);
}
async function exportPDF() {
let fname = utils.getUrlParam("fname");
let path = utils.getUrlParam("path");
let img_url = getImgUrl(fname, path);
// 处理svg
if (path.includes(".svg")) {
document.title = fname;
await handleSVGurl(img_url);
return;
}
// 处理常规图像
let data = await getData(img_url);
let img_data_list = parseData(data);
console.log(`共 ${img_data_list.length} 张图片`);
await imgDataArrsToPDF(fname, img_data_list);
}
function showHints() {
wk$("h1")[0].textContent = "wk 温馨提示";
wk$("p")[0].innerHTML = [
"下载 270 页的 PPT (70 MB) 需要约 30 秒",
"请耐心等待,无需反复点击按钮",
"如果很久没反应,请加 QQ 群反馈问题"
].join("
");
wk$("hr")[0].nextSibling.textContent = "403 Page Hostaged By Wenku Doc Downloader";
}
/**
* 爱问文库下载策略
*/
async function ishareData() {
// 显示提示
showHints();
// 创建按钮区
utils.createBtns();
// btn_1: 识别文档类型 -> 导出PDF
exportPDF = await utils.recTime(exportPDF);
utils.setBtnEvent(exportPDF, [], "btn_1", "下载并导出PDF");
}
/**
* 清理并打印得力文库的文档页
*/
function printPageDeliwenku() {
// 移除页面上的无关元素
let selector = ".hr-wrap, #readshop, .nav_uis, .bookdesc, #boxright, .QQ_S1, .QQ_S, #outer_page_more, .works-manage-box.shenshu, .works-intro, .mt10.related-pic-box, .mt10.works-comment, .foot_nav, .siteInner";
let elem_list = document.querySelectorAll(selector);
for (let elem of elem_list) {
utils.tryToRemoveElement(elem);
}
// 修改页间距
let outer_pages = document.getElementsByClassName("outer_page");
for (let page of outer_pages) {
page.style.marginBottom = "20px";
}
// 使文档居中
alert("建议使用:\n偏移量: 3\n缩放: 112\n请上下滚动页面,确保每页内容都加载完成以避免空白页\n如果预览时有空白页或文末有绿色按钮,请取消打印重试");
if (!utils.centerDoc("#boxleft", "3")) {
return; // 如果输入非法,终止函数调用
}
// 打印文档
utils.hideBtnThenPrint();
}
/**
* 点击“继续阅读”,适用性:得力文库
*/
function readAllDeliwenku() {
// 点击“同意并开始预览全文”
let start_btn = document.getElementsByClassName("pre_button")[0];
let display = start_btn.parentElement.parentElement.style.display;
// 如果该按钮显示着,则点击,然后滚动至页面底部,最后终止函数
if (!display) {
start_btn.children[0].click();
setTimeout(() => {
scroll(0, document.body.scrollHeight);
}, 200);
return;
}
// 增强按钮点击效果
utils.enhanceBtnClickReaction();
let read_all_btn = document.getElementsByClassName("fc2e")[0];
let display2 = read_all_btn.parentElement.parentElement.style.display;
// 继续阅读
if (display2 !== "none") {
// 获取input元素
let cur_page = document.querySelector("#pageNumInput");
let page_old = cur_page.value;
let page_max = cur_page.parentElement.nextElementSibling.textContent.replace(" / ", "");
// 跳转到尾页
utils.jump2pageNo(cur_page, page_max, "keydown");
// 跳转回来
utils.jump2pageNo(cur_page, page_old, "keydown");
// 切换按钮准备导出
} else {
// 推荐导出图片链接
utils.modifyBtnText("btn_2", null, true);
// 隐藏按钮
utils.toggleBtnStatus("btn_1");
// 显示按钮
utils.toggleBtnStatus("btn_2");
utils.toggleBtnStatus("btn_3");
// btn_3 橙色按钮
utils.setBtnEvent(printPageDeliwenku, [], "btn_3", "打印页面到PDF");
}
}
/**
* 得力文库文档下载策略
*/
function deliwenku() {
// 创建脚本启动按钮1、2
utils.createBtns();
// btn_1: 展开文档
utils.setBtnEvent(readAllDeliwenku, [], "btn_1");
// btn_2: 导出图片链接
utils.setBtnEvent(() => {
if (confirm("确定每页内容都加载完成了吗?")) {
utils.savePicUrls('.inner_page div');
}
}, [], "btn_2", "导出图片链接");
// 尝试关闭页面弹窗
try { document.querySelector("div[title=点击关闭]").click(); } catch (e) { console.log(0); }
// 解除打印限制
utils.allowPrint();
}
function readAll360Doc() {
// 展开文档
document.querySelector(".article_showall a").click();
// 隐藏按钮
utils.toggleBtnStatus("btn_1");
// 显示按钮
utils.toggleBtnStatus("btn_2");
utils.toggleBtnStatus("btn_3");
}
function saveText_360Doc() {
// 捕获图片链接
let images = document.querySelectorAll("#artContent img");
let content = [];
for (let i = 0; i < images.length; i++) {
let src = images[i].src;
content.push(`图${i+1},链接:${src}`);
}
// 捕获文本
let text = document.querySelector("#artContent").textContent;
content.push(text);
// 保存纯文本文档
let title = document.querySelector("#titiletext").textContent;
utils.createAndDownloadFile(`${title}.txt`, content.join("\n"));
}
function printPage360Doc() {
// # 清理并打印360doc的文档页
// ## 移除页面上无关的元素
let selector = ".fontsize_bgcolor_controler, .atfixednav, .header, .a_right, .article_data, .prev_next, .str_border, .youlike, .new_plbox, .str_border, .ul-similar, #goTop2, #divtort, #divresaveunder, .bottom_controler, .floatqrcode";
let elem_list = document.querySelectorAll(selector);
let under_doc_1, under_doc_2;
try {
under_doc_1 = document.querySelector("#bgchange p.clearboth").nextElementSibling;
under_doc_2 = document.querySelector("#bgchange").nextElementSibling.nextElementSibling;
} catch (e) { console.log(); }
// 执行移除
for (let elem of elem_list) {
utils.tryToRemoveElement(elem);
}
utils.tryToRemoveElement(under_doc_1);
utils.tryToRemoveElement(under_doc_2);
// 执行隐藏
document.querySelector("a[title]").style.display = "none";
// 使文档居中
alert("建议使用:\n偏移量: 20\n缩放: 默认\n");
if (!utils.centerDoc(".a_left", "20")) {
return; // 如果输入非法,终止函数调用
}
// 隐藏按钮,然后打印页面
utils.hideBtnThenPrint();
}
/**
* 360doc个人图书馆下载策略
*/
function doc360() {
// 创建按钮区
utils.createBtns();
// btn_1: 展开文档
utils.setBtnEvent(readAll360Doc, [], "btn_1");
// btn_2: 导出纯文本
utils.setBtnEvent(saveText_360Doc, [], "btn_2", "导出纯文本");
// btn_3: 打印页面到PDF
utils.setBtnEvent(() => {
if (confirm("确定每页内容都加载完成了吗?")) {
printPage360Doc();
}
}, [], "btn_3", "打印页面到PDF");
}
/**
* 查找出所有未被捕获的页码,并返回列表
* @returns 未捕获页码列表
*/
function getMissedPages() {
let all = []; // 全部页码
for (let i = 0; i < window.mbaJS.max_page; i++) {
all[i] = i + 1;
}
let missed = []; // 未捕获页码
let possessed = Array.from(window.mbaJS.canvases_map.keys()); // 已捕获页面
// 排除并录入未捕获页码
for (let num of all) {
if (!possessed.includes(`page${num}`)) {
missed.push(num);
}
}
return missed;
}
/**
* 根据键中的id数字对map排序
* @param {Map} elems_map
* @returns sorted_map
*/
function sortMapByID(elems_map) {
// id形式:page2
let elems_arr = Array.from(elems_map);
elems_arr.sort((item1, item2) => {
// 从key中取出id
let id1 = parseInt(item1[0].replace("page", ""));
let id2 = parseInt(item2[0].replace("page", ""));
// 升序排序
return id1 - id2;
});
// 返回排序好的map
return new Map(elems_arr);
}
/**
* 存储动态加载的canvas元素、textContent
*/
function storeElements_MBA() {
let canvases_map = window.mbaJS.canvases_map;
let texts_map = window.mbaJS.texts_map;
let quality = window.mbaJS.quality;
document.querySelectorAll(".page[data-loaded=true]").forEach(
(elem) => {
let capture = (elem) => {
// (1) 存储页面为canvas图形
let canvas, data_base64;
// 导出canvas数据防止丢失
try {
// 存储canvas
canvas = elem.querySelector("canvas[id*=page]");
if (window.mbaJS.only_text) {
data_base64 = null;
} else {
data_base64 = canvas.toDataURL("image/jpeg", quality);
}
} catch (e) {
// utils.sleep(500);
return;
}
// 增量录入map
let id = canvas.id; // id的形式:page2
if (!canvases_map.has(id)) {
canvases_map.set(id, data_base64);
}
// 确定canvas长宽
if (!window.mbaJS.only_text && !window.mbaJS.width) {
window.mbaJS.width = parseInt(canvas.width);
window.mbaJS.height = parseInt(canvas.height);
}
// (2) 存储text
let text = elem.textContent;
if (!texts_map.has(id)) {
texts_map.set(id, text);
}
};
setTimeout(capture, 500, elem);
});
if (canvases_map.size === window.mbaJS.max_page) {
// 根据id排序
window.mbaJS.canvases_map = sortMapByID(window.mbaJS.canvases_map);
window.mbaJS.texts_map = sortMapByID(window.mbaJS.texts_map);
window.mbaJS.finished = true;
window.onscroll = null;
}
}
/**
* 将canvas转为jpeg,然后导出PDF
* @param {Array} base64_list canvas元素列表
* @param {String} title 文档标题
*/
function saveCanvasesToPDF_MBA(base64_list, title) {
let width = window.mbaJS.width;
let height = window.mbaJS.height;
console.log(`canvas数据:宽: ${width}px,高: ${height}px`);
// 如果文档第一页的宽比长更大,则landscape,否则portrait
let orientation = width > height ? 'l' : 'p';
let pdf = new jspdf.jsPDF(orientation, 'px', [height, width]);
// 保存每一页文档到每一页pdf
let i = 0;
for (let base64 of base64_list) {
i += 1;
pdf.addImage(base64, 'JPEG', 0, 0, width, height);
// 如果当前不是文档最后一页,则需要添加下一个空白页
if (i < window.mbaJS.max_page) {
pdf.addPage();
}
}
// 导出文件
pdf.save(`${title}.pdf`);
}
/**
* 判断文档页是否收集完毕,当不行时给出提示
* @returns boolean
*/
function ready2use() {
removeAds(); // 顺便清理广告
// 如果是首次点击按钮,给出提示
if (window.mbaJS.first_hint) {
let hint = [
"如果浏览速度过快,比如:",
"当前页面还没完全加载好就滚动页面去看下一页",
"那就极有可能导致导出的PDF有空白页或文本有缺漏",
"由防范技术的干扰,该功能目前很不好用,见谅"
].join("\n");
alert(hint);
window.mbaJS.first_hint = false;
}
// 如果文档页没有收集完,给出提示
if (!window.mbaJS.finished) {
let hint = [
"仍有内容未加载完,无法使用该功能",
"建议从头到尾慢速地再浏览一遍",
"以下是没有加载完成页面的页码:",
getMissedPages().join(",")
];
alert(hint.join("\n"));
return false;
}
return true;
}
/**
* 用捕获好的canvas转jpg,生成PDF
* @returns
*/
function canvas2PDF_mba() {
if (!ready2use()) {
return;
}
let canvases = window.mbaJS.canvases_map.values();
// 导出PDF
let title = document.title.split("-")[0].trim();
saveCanvasesToPDF_MBA(canvases, title);
}
/**
* 拼合捕获好的文本,保存到txt文件
* @returns
*/
function saveText_mba() {
if (!ready2use()) {
return;
}
let content = Array.from(window.mbaJS.texts_map.values());
let title = document.title.split("-")[0].trim();
utils.createAndDownloadFile(`${title}.txt`, content.join("\n"));
}
/**
* 移除广告
*/
function removeAds() {
document.querySelectorAll(".doc-ad").forEach((ad_elem) => {
utils.tryToRemoveElement(ad_elem);
});
}
function mbalib_() {
// 移除广告和左侧工具栏
removeAds();
let tool_bar = document.querySelector(".tool-bar");
utils.tryToRemoveElement(tool_bar);
// 创建按钮
utils.createBtns();
// 隐藏按钮
utils.toggleBtnStatus("btn_1");
// 显示按钮
utils.toggleBtnStatus("btn_2");
utils.toggleBtnStatus("btn_3");
utils.toggleBtnStatus("btn_4");
// 取得页数
let max_page = parseInt(document.querySelector("#numPages").textContent.replace("/ ", ""));
// 为导出内容提供全局变量,便于动态收集文档页元素的存取
window.mbaJS = {
max_page: max_page,
texts_map: new Map(), // id: text
canvases_map: new Map(), // id: canvas_data_base64
quality: 1, // canvas转jpg的质量
width: null, // canvas宽度(px)
height: null,
finished: false, // 是否收集完了全部文档页元素
first_hint: true,
scroll_count: 0, // 用于统计累计触发scroll的次数,
only_text: false // 是否仅捕获文本
};
// 跟随浏览,动态收集页面元素
window.onscroll = () => {
storeElements_MBA();
};
// 跟随浏览,动态收集页面元素
utils.scrollFunc(storeElements_MBA, window.mbaJS, 20, 50, "mba元素: 收集");
// 绑定事件
utils.setBtnEvent(saveText_mba, [], "btn_2", "导出纯文本(不稳定)");
utils.setBtnEvent(canvas2PDF_mba, [], "btn_3", "导出PDF(不稳定)");
// 根据页数决定按钮功能:<40页,导出文本+导出pdf,>40页:导出文本
let btn_text, aim_btn, hint;
if (max_page > 40) {
btn_text = "失效说明";
aim_btn = "btn_3";
hint = [
"页数超过40,脚本无效",
"只能使用导出文本功能",
"而此脚本会使页面内容加载明显变慢,建议禁用"
];
utils.setBtnEvent(
() => {
utils.toggleBtnsSec();
window.onscroll = null;
},
[],
"btn_4",
"临时禁用脚本"
);
} else {
btn_text = "空白页说明";
aim_btn = "btn_4";
hint = [
"导致空白页的原因如下",
"加载该页的时间超过2秒 / 明显等待",
"而此脚本会使页面内容加载明显变慢,如果影响严重请禁用"
];
}
utils.setBtnEvent(() => {
alert(hint.join("\n"));
}, [], aim_btn, btn_text);
}
function mbalib() {
setTimeout(mbalib_, 2000);
}
/**
* 判断是否进入预览模式
* @returns Boolean
*/
function isInPreview() {
let p_elem = document.querySelector("#preview_tips");
if (p_elem.style.display === "none") {
return true;
}
return false;
}
/**
* 判断是否展开了全文
* @returns Boolean
*/
function isNoMorePage() {
let read_more = document.querySelector("#ntip2");
if (read_more.style.display === "none") {
return true;
}
return false;
}
/**
* 确保进入预览模式
*/
async function ensureInPreview() {
if (!isInPreview()) {
// 如果没有进入预览,则先进入
document.querySelector(".pre_button a").click();
await utils.sleep(500);
}
}
/**
* 展开全文预览,当展开完成后再次调用时,返回true
* @returns
*/
async function unfoldAll() {
await ensureInPreview();
if (isNoMorePage()) {
// 如果全文展开了,则切换按钮,然后退出
utils.toggleBtnStatus("btn_1");
utils.toggleBtnStatus("btn_2");
return true;
}
// 跳转到最后一页,以展开全文
let cur_page = document.querySelector("#pageNumInput");
utils.jump2pageNo(cur_page, "999", "keydown");
}
/**
* 取得最大页码(最大20)
* @returns {number} 页码int
*/
function getPageCounts$2() {
let counts_str = document.querySelector(".counts").textContent;
let counts = counts_str.match(/[0-9]{1,3}/)[0];
if (counts > 20) {
counts = 20; // 最多免费预览20页,所以设置最大页码20
}
return parseInt(counts);
}
/**
* 取得全部文档页面的链接,返回urls;如果有页面未加载,则返回null
* @returns Array | null
*/
function getImgUrls() {
let pages = document.querySelectorAll("[id*=pageflash_]");
// 尚未浏览完全部页面,返回null
if (pages.length < window.dugenJS.page_counts) {
return null;
}
// 浏览完全部页面,返回urls
let urls = [];
pages.forEach((page) => {
let url = page.querySelector("img").src;
urls.push(url);
});
return urls;
}
/**
* 返回当前未加载页面的页码
* @returns not_loaded
*/
function getNotloadedPages() {
// 已经取得的页码
let pages = document.querySelectorAll("[id*=pageflash_]");
let loaded = new Set();
pages.forEach((page) => {
let id = page.id.split("_")[1];
id = parseInt(id);
loaded.add(id);
});
// 未取得的页码
let not_loaded = [];
for (let i = 1; i <= window.dugenJS.page_counts; i++) {
if (!loaded.has(i)) {
not_loaded.push(i);
}
}
return not_loaded;
}
function WantImgUrls() {
let res = getImgUrls();
// 页面尚未加载完
if (res === null) {
let hints = [
"尚未加载完全部页面",
"以下页面需要浏览并加载:",
getNotloadedPages().join(",")
];
alert(hints.join("\n"));
return;
}
// 页面全部加载完
utils.createAndDownloadFile("urls.csv", res.join("\n"));
}
/**
* dugen文档下载策略
*/
async function dugen() {
await ensureInPreview();
// 全局对象
window.dugenJS = {
page_counts: getPageCounts$2() // 最大页码(int)
};
// 创建按钮区
utils.createBtns();
// 绑定监听器
// 按钮1:展开文档
utils.setBtnEvent(unfoldAll, [], "btn_1");
// 按钮2:导出图片链接
utils.setBtnEvent(WantImgUrls, [], "btn_2", "导出图片链接");
}
/**
* 取得文档类型
* @returns {String} 文档类型str
*/
function getDocType() {
let type_elem = document.querySelector(".title .icon.icon-format");
// ["icon", "icon-format", "icon-format-doc"]
let cls_str = type_elem.classList[2];
// "icon-format-doc"
let type = cls_str.split("-")[2];
return type;
}
/**
* 判断文档类型是否为type_list其中之一
* @returns 是否为type
*/
function isTypeof(type_list) {
let type = getDocType();
if (type_list.includes(type)) {
return true;
}
return false;
}
/**
* 判断文档类型是否为PPT
* @returns 是否为PPT
*/
function isPPT() {
return isTypeof(["ppt", "pptx"]);
}
/**
* 判断文档类型是否为Excel
* @returns 是否为Excel
*/
function isEXCEL() {
return isTypeof(["xls", "xlsm", "xlsx"]);
}
/**
* 取得最大页码
* @returns {Number} 最大页码
*/
function getPageCounts$1() {
let page_counts_str = document.querySelector(".intro-list").textContent;
let page_counts = parseInt(page_counts_str.match(/(?<=约 )[0-9]{1,3}(?=页)/)[0]);
return page_counts;
}
/**
* 取得未加载页面的页码
* @param {Set} loaded 已加载的页码集合
* @returns {Array} not_loaded 未加载页码列表
*/
function getNotLoaded(loaded) {
let not_loaded = [];
let page_counts = window.book118JS.page_counts;
for (let i = 1; i <= page_counts; i++) {
if (!loaded.has(i)) {
not_loaded.push(i);
}
}
return not_loaded;
}
/**
* 取得全部文档页的url
* @returns [<是否全部加载>, <未加载页码列表>|]
*/
function getUrls() {
let loaded = new Set(); // 存储已加载页面的页码
let urls = []; // 存储已加载页面的图形src
// 收集已加载页面的url
document.querySelectorAll("div[data-id]").forEach((div) => {
let src = div.querySelector("img").src;
if (src) {
// "1": "https://view-cache.book118.com/..."
loaded.add(parseInt(div.getAttribute("data-id")));
urls.push(src);
}
});
// 如果所有页面加载完毕
if (loaded.size === window.book118JS.page_counts) {
return [true, urls];
}
// 否则收集未加载页面的url
return [false, getNotLoaded(loaded)];
}
/**
* 展开全文
*/
function readAll() {
window.preview.jump(999);
}
/**
* btn_2: 导出图片链接
*/
function wantUrls() {
let [flag, res] = getUrls();
// 页面都加载完毕,下载urls
if (flag) {
utils.createAndDownloadFile("urls.csv", res.join("\n"));
return;
}
// 没有加载完,提示出未加载好的页码
let hints = [
"仍有页面没有加载",
"请浏览并加载如下页面:",
res.join(",")
];
alert(hints.join("\n"));
}
/**
* 打开PPT预览页面
*/
function openPPTpage() {
window.preview.getSrc();
let openPPT = () => {
let ppt_src = document.querySelector("iframe.preview-iframe").src;
utils.openInNewTab(ppt_src);
window.preview.close();
};
setTimeout(openPPT, 1000);
}
/**
* 原创力文档(非PPT或Excel)下载策略
*/
function book118_CommonDoc() {
// 创建全局对象
window.book118JS = {
doc_type: getDocType(),
page_counts: getPageCounts$1()
};
// 处理非PPT文档
// 创建按钮组
utils.createBtns();
// 绑定监听器到按钮
// 按钮1:展开文档
utils.setBtnEvent(() => {
readAll();
utils.toggleBtnStatus("btn_1");
utils.toggleBtnStatus("btn_2");
}, [], "btn_1");
// 按钮2:导出图片链接
utils.setBtnEvent(wantUrls, [], "btn_2", "导出图片链接");
}
/**
* 取得PPT文档最大页码
* @returns PPT文档最大页码int
*/
function getPageCountsPPT() {
let counts_str = document.querySelector("#PageCount").textContent;
let counts = parseInt(counts_str);
// console.log(`get page counts: ${counts}`);
return counts;
}
/**
* 取得当前的页码
* @returns {Number} this_page
*/
function getThisPage() {
let this_page = document.querySelector("#PageIndex").textContent;
this_page = parseInt(this_page);
return this_page;
}
/**
* 点击下一动画直到变成下一页,再切回上一页
* @param {Number} next_page 下一页的页码
*/
async function __nextFrameUntillNextPage(next_page) {
// 如果已经抵达下一页,则返回上一页
let this_page = getThisPage();
// 最后一页直接退出
if (next_page > getPageCountsPPT()) {
return;
}
// 不是最后一页,但完成了任务
else if (this_page === next_page) {
document.querySelector(".btmLeft").click();
await utils.sleep(500);
return;
}
// 否则递归的点击下一动画
document.querySelector(".btmRight").click();
await utils.sleep(500);
await __nextFrameUntillNextPage(next_page);
}
/**
* 确保当前页面是最后一帧动画
*/
async function ensurePageLoaded() {
// 取得当前页码和下一页页码
let this_page = getThisPage();
let next_page = this_page + 1;
// 开始点击下一页按钮,直到变成下一页,再点击上一页按钮来返回
await __nextFrameUntillNextPage(next_page);
}
/**
* (异步)转换当前视图为canvas,添加到book118JS.canvases中。在递归终止时显示btn_2。
*/
async function docView2Canvas() {
await ensurePageLoaded();
// 取得页码
let cur_page = getThisPage();
// 取得视图元素,计数从0开始
let doc_view = document.querySelector(`#view${cur_page-1}`);
// 转化为canvas
let canvas_promise = html2canvas(doc_view);
console.log(canvas_promise); // 打印信息以检查状况
await canvas_promise.then((canvas) => {
// 保存canvas到全局对象
window.book118JS.canvases.push(canvas);
// 打印日志
console.log(`wk: ${cur_page} complete`);
});
// 如果到最后一页
let page_counts = getPageCountsPPT();
// console.log(`docView2Canvas: cur_page: ${cur_page}, page_counts: ${page_counts}`);
if (cur_page === page_counts) {
// 终止递归,并且显示导出PDF按钮
utils.toggleBtnStatus("btn_2");
return;
}
// 否则下一次递归(继续捕获下一页)
document.querySelector(".pgRight").click();
await utils.sleep(500);
await docView2Canvas();
}
/**
* 将捕获的canvases合并并导出为pdf
* @returns
*/
function canvases2pdf() {
// 已经捕获的页面数量
let stored_amount = window.book118JS.canvases.length;
// 总页面数量
let page_counts = window.book118JS.page_counts;
// 校验数量
let diff = page_counts - stored_amount;
if (diff > 0) {
alert(`缺失了 ${diff} 页,可以过一会再点击该按钮试试。`);
if (!confirm("是否仍要导出PDF?")) {
// 不坚持导出PDF的情况
return;
}
}
// 导出PDF
let canvases = window.book118JS.canvases;
// 取得宽高
let model = canvases[0];
let width = model.width;
let height = model.height;
// 取得标题然后导出pdf
utils.saveCanvasesToPDF(canvases, "原创力PPT文档", width, height);
}
/**
* 原创力文档(PPT)下载策略
*/
function book118_PPT() {
// 创建全局对象
window.book118JS = {
page_counts: getPageCountsPPT(),
canvases: [] // 存储每页文档转化的canvas
};
// 创建按钮区
utils.createBtns();
// 绑定监听器到按钮1
utils.setBtnEvent(() => {
let hints = [
"正在为文档“截图”,请耐心等待过程完成,不要操作",
"“截图”会有额外一层黑边,原因未知,暂无法处理,烦请谅解"
];
alert(hints.join("\n"));
// 隐藏按钮1
utils.toggleBtnStatus("btn_1");
// 开始捕获页面(异步)
docView2Canvas(window.book118JS.page_counts);
}, [], "btn_1", "捕获页面");
// 为按钮2绑定监听器
utils.setBtnEvent(canvases2pdf, [], "btn_2", "导出PDF");
}
/**
* 取得当前页面的excel,返回csv string
* @returns {String} csv
*/
function excel2CSV() {
let table = [];
let rows = document.querySelectorAll("tr[id]");
// 遍历行
for (let row of rows) {
let csv_row = [];
// 遍历列(单元格)
for (let cell of row.querySelectorAll("td[class*=fi], td.tdrl")) {
// 判断单元格是否存储图片
let img = cell.querySelector("img");
if (img) {
// 如果是图片,保存图片链接
csv_row.push(img.src);
} else {
// 否则保存单元格文本
csv_row.push(cell.textContent);
}
}
table.push(csv_row.join(","));
}
let csv = table.join("\n");
csv = csv.replace(/\n{2,}/g, "\n");
return csv;
}
/**
* 下载当前表格内容,保存为csv(utf-8编码)
*/
function wantEXCEL() {
let file_name = "原创力表格_UTF-8.csv";
utils.createAndDownloadFile(file_name, excel2CSV());
}
/**
* 在Excel预览页面给出操作提示
*/
function help() {
let hints = [
"【导出表格到CSV】只能导出当前sheet,",
"如果有多张sheet请在每个sheet上用按钮分别导出CSV。",
"CSV是一种简单的表格格式,可以被Excel打开,",
"并转为 xls 或 xlsx 格式存储,",
"但CSV本身不能存储图片,所以用图片链接代替,请自行下载图片",
"",
"本功能导出的CSV文件无法直接用Excel打开,因为中文会乱码。",
"有两个办法:",
"1. 打开Excel,选择【数据】,选择【从文本/CSV】,",
" 选择文件,【文件原始格式】选择【65001: Unicode(UTF-8)】,选择【加载】。",
"2. 用【记事本】打开CSV文件,【文件】->【另存为】->",
" 【编码】选择【ANSI】->【保存】。现在可以用Excel直接打开它了。"
];
alert(hints.join("\n"));
}
/**
* 原创力文档(EXCEL)下载策略
*/
function book118_EXCEL() {
// 创建按钮区
utils.createBtns();
// 绑定监听器到按钮
utils.setBtnEvent(wantEXCEL, [], "btn_1", "导出表格到CSV");
utils.setBtnEvent(help, [], "btn_2", "使用说明");
// 显示按钮
utils.toggleBtnStatus("btn_2");
}
/**
* 打开Excel预览页面
*/
function openEXCELpage() {
openPPTpage();
}
/**
* 原创力文档下载策略
*/
function book118() {
let host = window.location.hostname;
if (host === 'max.book118.com') {
if (isEXCEL()) {
utils.createBtns();
utils.setBtnEvent(openEXCELpage, [], "btn_1", "导出EXCEL");
} else if (isPPT()) {
utils.createBtns();
utils.setBtnEvent(openPPTpage, [], "btn_1", "导出PPT");
} else {
book118_CommonDoc();
}
} else if (host === "view-cache.book118.com") {
book118_PPT();
} else if (host.match(/view[0-9]{1,3}.book118.com/)) {
book118_EXCEL();
} else {
console.log(`wk: Unknown host: ${host}`);
}
}
// test url: https://openstd.samr.gov.cn/bzgk/gb/newGbInfo?hcno=E86BBCE32DA8E67F3DA04ED98F2465DB
/**
* 绘制0x0的bmp, 作为请求失败时返回的page
* @returns {Promise} blank_page
*/
async function blankBMP() {
let canvas = document.createElement("canvas");
[canvas.width, canvas.height] = [0, 0];
return createImageBitmap(canvas);
}
/**
* resp导出bmp
* @param {string} page_url
* @param {Promise | ImageBitmap} pms_or_bmp
* @returns {Promise} page
*/
async function respToPage(page_url, pms_or_bmp) {
let center = globalThis.gb688JS;
// 此时是bmp
if (pms_or_bmp instanceof ImageBitmap) {
return pms_or_bmp;
}
// 第一次下载, 且无人处理
if (!center.pages_status.get(page_url)) {
// 处理中, 设为占用
center.pages_status.set(page_url, 1);
// 处理
let resp;
try {
resp = await pms_or_bmp;
} catch(err) {
console.log("下载页面失败");
console.error(err);
return blankBMP();
}
let page_blob = await resp.blob();
let page = await createImageBitmap(page_blob);
center.pages.set(page_url, page);
// 处理结束, 设为释放
center.pages_status.set(page_url, 0);
return page;
}
// 有人正在下载且出于处理中
while (center.pages_status.get(page_url)) {
await utils.sleep(500);
}
return center.pages.get(page_url);
}
/**
* 获得PNG页面
* @param {string} page_url
* @returns {Promise} bmp
*/
async function getPage(page_url) {
// 如果下载过, 直接返回缓存
let pages = globalThis.gb688JS.pages;
if (pages.has(page_url)) {
return respToPage(page_url, pages.get(page_url));
}
// 如果从未下载过, 就下载
let resp = fetch(page_url, {
"headers": {
"accept": "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8",
"proxy-connection": "keep-alive"
},
"referrer": location.href,
"referrerPolicy": "strict-origin-when-cross-origin",
"body": null,
"method": "GET",
"mode": "cors",
"credentials": "include"
});
pages.set(page_url, resp);
return respToPage(page_url, resp);
}
/**
* 返回文档页div的裁切和粘贴位置信息: [[cut_x, cut_y, paste_x%, paset_y%],...]
* @param {HTMLDivElement} page_div 文档页元素
* @returns {Array>} positions
*/
function getPostions(page_div) {
let positions = [];
Array.from(page_div.children).forEach(span => {
// 'pdfImg-3-8' -> {left: 30%; top: 80%;}
let paste_pos = span.className.split("-").slice(1).map(
v => parseInt(v) / 10
);
// '-600px 0px' -> [600, 0]
let cut_pos = span.style.backgroundPosition.split(" ").map(
v => Math.abs(parseInt(v))
);
positions.push([...cut_pos, ...paste_pos]);
});
return positions;
}
/**
* 取得文档页的图像url
* @param {HTMLDivElement} page_div
* @returns {string} url
*/
function getPageURL(page_div) {
// 拿到目标图像url
let path = location.pathname.split("/").slice(0, -1).join("/");
let prefix = location.origin + path + "/";
let url = page_div.getAttribute("bg");
if (!url) {
// 'url("viewGbImg?fileName=VS72l67k0jw5g3j0vErP8DTsnWvk5QsqnNLLxaEtX%2FM%3D")'
url = page_div.children[0].style.backgroundImage.split('"')[1];
}
return prefix + url;
}
/**
* 下载目标图像并拆解重绘, 返回canvas
* @param {number} i 第 i 页 (从0开始)
* @param {HTMLDivElement} page_div
* @returns {Promise} [页码, Canvas]
*/
async function getAndDrawPage(i, page_div) {
// 拿到目标图像
let url = getPageURL(page_div);
let page = await getPage(url);
// 绘制空白A4纸背景
let [page_w, page_h] = [1190, 1680];
let bg = document.createElement("canvas");
bg.width = page_w; // 注意canvas作为取景框的大小
bg.height = page_h; // 如果不设置等于一个很小的取景框
let bg_ctx = bg.getContext("2d");
bg_ctx.fillStyle = "white";
bg_ctx.fillRect(0, 0, page_w, page_h);
// 逐个区块剪切取出并粘贴
// wk$("#viewer .page").forEach(page_div => {
getPostions(page_div).forEach(pos => {
bg_ctx.drawImage(
page, // image source
pos[0], // source x
pos[1], // source y
120, // source width
169, // source height
pos[2] * page_w, // destination x = left: x%
pos[3] * page_h, // destination y = top: y%
120, // destination width
169 // destination height
);
});
// });
return [i, bg];
}
/**
* 页面批量请求、裁剪重绘, 合成PDF并下载
*/
async function turnPagesToPDF() {
// 渲染每页
let tasks = [];
wk$("#viewer .page").forEach((page_div, i) => {
tasks.push(
getAndDrawPage(i, page_div)
);
});
// 等待每页渲染完成后,排序
let results = await Promise.all(tasks);
results.sort((prev, next) => prev[0] - next[0]);
// 合并为PDF并导出
utils.saveCanvasesToPDF(
results.map(item => item[1]),
// '在线预览|GB 14023-2022'
document.title.split("|")[1]
);
}
/**
* 提示预估下载耗时,然后下载
*/
function hintThenDownload$1() {
// '/93'
let page_num = parseInt(wk$("#numPages")[0].textContent.slice(1));
let estimate = Math.ceil(page_num / 3);
alert(`页数: ${page_num},预计花费: ${estimate}秒;如遇网络异常可能更久\n请勿反复点击按钮;如果无法导出请 QQ 群反馈`);
turnPagesToPDF();
}
/**
* gb688文档下载策略
*/
async function gb688() {
// 创建全局对象
globalThis.gb688JS = {
pages: new Map(), // {url: bmp}
pages_status: new Map() // {url: 0或1} 0释放, 1占用
};
// 创建按钮区
utils.createBtns();
// 绑定监听器
// 按钮1:导出PDF
turnPagesToPDF = await utils.recTime(turnPagesToPDF);
utils.setBtnEvent(hintThenDownload$1, [], "btn_1", "导出PDF");
}
function getPageCounts() {
// " / 39"
let counts_str = wk$(".counts")[0].textContent.split("/")[1];
let counts = parseInt(counts_str);
return counts > 20 ? 20 : counts;
}
/**
* 返回图片基础路径
* @returns {string} base_url
*/
function getImgBaseURL() {
return wk$("#dp")[0].value;
}
function* genImgURLs() {
let counts = getPageCounts();
let base_url = getImgBaseURL();
for (let i=1; i<=counts; i++) {
yield base_url + `${i}.gif`;
}
}
/**
* 下载图片,转为canvas,合并为PDF并下载
*/
function fetchThenExportPDF() {
let url_vendor = genImgURLs();
// db2092-2014-河北特种设备使用安全管理规范_安全文库网safewk.com
let title = document.title.split("_")[0];
return utils.imgUrlsToPDF(url_vendor, title);
}
/**
* 提示预估下载耗时,然后下载
*/
async function hintThenDownload() {
let hint = [
"只能导出可预览的页面(最多20页)",
"请勿短时间反复点击按钮,导出用时大约不到 10 秒",
"点完后很久没动静请至 QQ 群反馈"
];
alert(hint.join("\n"));
await fetchThenExportPDF();
}
/**
* safewk文档下载策略
*/
async function safewk() {
// 创建按钮区
utils.createBtns();
// 绑定监听器
// 按钮1:导出PDF
hintThenDownload = await utils.recTime(hintThenDownload);
utils.setBtnEvent(hintThenDownload, [], "btn_1", "导出PDF");
}
/**
* 主函数:识别网站,执行对应文档下载策略
*/
function main() {
// 显示当前位置
let host = window.location.host;
console.log(`当前host: ${host}`);
// 挂载工具包到全局
window.user_utils = utils;
console.log("wk: user_utils已经挂载到全局");
// 主任务
if (host.includes("docin.com")) {
docin();
} else if (host === "swf.ishare.down.sina.com.cn") {
ishareData();
} else if (host.includes("ishare.iask")) {
ishare();
} else if (host === "www.deliwenku.com") {
deliwenku();
} else if (host === "www.doc88.com") {
doc88();
} else if (host === "www.360doc.com") {
doc360();
} else if (host === "doc.mbalib.com") {
mbalib();
} else if (host === "www.dugen.com") {
dugen();
} else if (host === "c.gb688.cn") {
gb688();
} else if (host === "www.safewk.com") {
safewk();
} else if (host.includes("book118.com")) {
book118();
} else {
console.log("匹配到了无效网页");
}
}
function loadExternalScripts() {
let urls = [
"https://cdn.staticfile.org/FileSaver.js/2.0.5/FileSaver.min.js",
"https://cdn.staticfile.org/jszip/3.7.1/jszip.min.js",
"https://cdn.staticfile.org/jspdf/2.5.1/jspdf.umd.min.js",
"https://cdn.staticfile.org/html2canvas/1.4.1/html2canvas.min.js",
];
for (let url of urls) {
utils.addScript2HTML(url);
let temp = url.split("/");
let n = temp.length;
let module_name = temp[n - 1];
console.log(`${module_name}模块已经加载`);
}
}
if (options.activation_test) {
alert(`Wenku Doc Downloader 已经生效!\n当前网址:\n${window.location.host}`);
}
// 根据配置选择:是否默认显示
if (!options.show_buttons) {
utils.toggleBtnsSec();
}
if (options.cli_mode) {
loadExternalScripts();
setTimeout(main, 2000);
} else if (options.fast_mode) {
utils.manipulateElem("body", main);
} else {
window.onload = main;
}
})();