Greasy Fork is available in English.

如意文档

所有文档平台免费文档下载

  1. // ==UserScript==
  2. // @name 如意文档
  3. // @namespace http://tampermonkey.net/
  4. // @version 6.0
  5. // @description 所有文档平台免费文档下载
  6. // @author ahonker999
  7. // @match https://jjg.spc.org.cn/resmea/view/stdonline
  8. // @match https://pro-img-brtm.baijiayun.com/*
  9. // @match https://hbba.sacinfo.org.cn/attachment/onlineRead/*
  10. // @match https://www.qzoffice.com/*
  11. // @match https://*.book118.com/*
  12. // @match https://*.renrendoc.com/*
  13. // @match https://*.docin.com/*
  14. // @match https://*.doc88.com/*
  15. // @match https://doc.mbalib.com/*
  16. // @match https://*.deliwenku.com/*
  17. // @match https://*.jinchutou.com/*
  18. // @match https://*.152files.goldhoe.com/*
  19. // @match https://www.nssi.org.cn/cssn/js/pdfjs/web/preview.jsp*
  20. // @match https://online.71nc.cn/*
  21. // @match http://114.251.111.103:18080/kfs/file/read/*
  22. // @match https://bulletin.cebpubservice.com/resource/ceb/js/pdfjs-dist/web/viewer.html*
  23. // @match http://121.36.94.83:9008/jsp/yishenqing/appladd/biaozhunfile/flash/previewImg.jsp*
  24. // @match http://rbtest.cnca.cn/cnca_kfs/file/read/*
  25. // @match https://*.mayiwenku.com/*
  26. // @match https://*.dugen.com/*
  27. // @match https://*.7cxk.com/*
  28. // @match https://ishare.iask.com/*
  29. // @match https://swf.iask.com/*
  30. // @match https://*.down.sina.com.cn/*
  31. // @match https://wenku.baidu.com/*
  32. // @match https://wkbjcloudbos.bdimg.com/*
  33. // @match https://wkretype.bdimg.com/*
  34. // @match https://*.chochina.com/*
  35. // @match https://*.weizhuannet.com/*
  36. // @match https://www.taodocs.com/*
  37. // @match https://wenku.so.com/*
  38. // @match https://*.360tres.com/*
  39. // @match https://www.wenkub.com/*
  40. // @match http://c.gb688.cn/*
  41. // @match http://www.nrsis.org.cn/mnr_kfs/file/read/*
  42. // @match https://*.feishu.cn/space/*
  43. // @match http://www.jtysbz.cn:8009/pdf/viewer/*
  44. // @require https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/jspdf/2.4.0/jspdf.umd.min.js
  45. // @require https://unpkg.com/@zip.js/zip.js@2.7.34/dist/zip.min.js
  46. // @require https://unpkg.com/html2canvas@1.4.1/dist/html2canvas.js
  47. // @icon https://dtking.cn/favicon.ico
  48. // @run-at document-idle
  49. // @grant GM_getValue
  50. // @grant GM_deleteValue
  51. // @grant GM_setValue
  52. // @grant GM_download
  53. // @grant GM_notification
  54. // @grant unsafeWindow
  55. // @license Apache-2.0
  56. // ==/UserScript==
  57. (function() {
  58. 'use strict';
  59. let MF =
  60. '#MF_fixed{position:fixed;top:50%;transform:translateY(-50%);right:20px;gap:20px;flex-direction:column;z-index:2147483647;display:flex}';
  61. MF +=
  62. '.MF_box{padding:10px;cursor:pointer;border-color:rgb(0,102,255);border-radius:5px;background-color:white;color:rgb(0,102,255);margin-right:10px;box-shadow:rgb(207,207,207) 1px 1px 9px 3px}.MF_active{color: green}#MF_speed{color: red;}';
  63. MF +=
  64. '@media print{html{height:auto !important}body{display:block !important}#app-left{display:none !important}#app-right{display:none !important}#MF_fixed{display:none !important}.menubar{display:none !important}.top-bar-right{display:none !important}.user-guide{display:none !important}#app-reader-editor-below{display:none !important}.no-full-screen{display:none !important}.comp-vip-pop{display:none !important}.center-wrapper{width:auto !important}.reader-thumb,.related-doc-list,.fold-page-content,.try-end-fold-page,.lazy-load,#MF_textarea,#nav-menu-wrap{display:none !important}}'
  65. const prefix = "MF_";
  66. // canvas 禁止重写 drawImage
  67. const canvasRenderingContext2DPrototype = CanvasRenderingContext2D.prototype;
  68. const originalDrawImage = canvasRenderingContext2DPrototype.drawImage;
  69. Object.defineProperty(canvasRenderingContext2DPrototype, 'drawImage', {
  70. value: originalDrawImage,
  71. writable: false,
  72. configurable: false
  73. });
  74. /**
  75. * @description 添加 URL 到本地缓存
  76. * @author Mr.Fang
  77. * @time 2024年2月4日
  78. * @param {Array} urls 数据
  79. * @param key
  80. */
  81. const MF_addURL = (urls, key = 'listData') => {
  82. let listData = JSON.parse(localStorage.getItem(key)) || [];
  83. let index = 0;
  84. let length = listData.length;
  85. urls.forEach((url) => {
  86. if (!listData.some(item => item.src === url)) {
  87. // 添加新的URL对象
  88. listData.push({
  89. src: url,
  90. page: length + index
  91. });
  92. index++;
  93. }
  94. })
  95. // 将更新后的URL数组存储回localStorage
  96. localStorage.setItem(key, JSON.stringify(listData));
  97. GM_setValue(key, JSON.stringify(listData))
  98. console.log('URL已添加:');
  99. }
  100. /**
  101. * Url 地址拼接,无需预览直接从 HTML 中读取相应的参数即可
  102. */
  103. const loadingUrls = (params) => {
  104. const _pageCount = Viewer._pageCount;
  105. console.log(_pageCount);
  106. let dp;
  107. if (params) {
  108. dp = u.query('#dp').value.replace('www', 'ww'); // 读根网特殊情况
  109. } else {
  110. dp = u.query('#dp').value;
  111. }
  112. const urls = [];
  113. for (var i = 1; i < _pageCount + 1; i++) {
  114. let u = dp + i + ".gif";
  115. urls.push(u);
  116. }
  117. MF_addURL(urls);
  118. }
  119. /**
  120. * Url 地址拼接,无需预览直接从 HTML 中读取相应的参数即可
  121. */
  122. const joinDownloadURL = (baseUrl) => {
  123. const size = Page.size;
  124. const urls = [];
  125. for (var i = 0; i < size; i++) {
  126. urls.push(baseUrl + '/' + i + '.png');
  127. }
  128. MF_addURL(urls);
  129. }
  130. class Box {
  131. id = ""; // id
  132. label = ""; // 按钮文本
  133. fun = ""; // 执行方法
  134. constructor(id, label, fun) {
  135. this.id = id;
  136. this.label = label;
  137. this.fun = fun;
  138. }
  139. }
  140. class Utility {
  141. debug = true;
  142. /**
  143. * 添加 css 样式
  144. * @param e 节点
  145. * @param data JSON 格式样式
  146. */
  147. style(e, data) {
  148. Object.keys(data).forEach(key => {
  149. e.style[key] = data[key]
  150. })
  151. }
  152. attr(e, key, val) {
  153. if (!val) {
  154. return e.getAttribute(key);
  155. } else {
  156. e.setAttribute(key, val);
  157. }
  158. }
  159. /**
  160. * 追加样式
  161. * @param css 格式样式
  162. */
  163. appendStyle(css) {
  164. let style = this.createEl('', 'style');
  165. style.textContent = css;
  166. style.type = 'text/css';
  167. let dom = document.head || document.documentElement;
  168. dom.appendChild(style);
  169. }
  170. /**
  171. * @description 创建 dom
  172. * @param id 必填
  173. * @param elType
  174. * @param data
  175. */
  176. createEl(id, elType, data) {
  177. const el = document.createElement(elType);
  178. el.id = id || '';
  179. if (data) {
  180. this.style(el, data);
  181. }
  182. return el;
  183. }
  184. query(el) {
  185. return document.querySelector(el);
  186. }
  187. queryAll(el) {
  188. return document.querySelectorAll(el);
  189. }
  190. update(el, text) {
  191. const elNode = this.query(el);
  192. if (!elNode) {
  193. console.log('节点不存在');
  194. } else {
  195. elNode.innerHTML = text;
  196. }
  197. }
  198. /**
  199. * 进度
  200. * @param current 当前数量 -1预览结束
  201. * @param total 总数量
  202. * @param content 内容
  203. */
  204. preview(current, total, content) {
  205. return new Promise(async (resolve, reject) => {
  206. if (current === -1) {
  207. this.update('#' + prefix + 'text', content ? content : "已完成");
  208. } else {
  209. let p = (current / total) * 100;
  210. let ps = p.toFixed(0) > 100 ? 100 : p.toFixed(0);
  211. console.log('当前进度', ps)
  212. this.update('#' + prefix + 'text', '进度' + ps + '%');
  213. await this.sleep(500);
  214. resolve();
  215. }
  216. })
  217. }
  218. preText(content) {
  219. this.update('#' + prefix + 'text', content);
  220. }
  221. gui(boxs) {
  222. const box = this.createEl(prefix + "fixed", 'div');
  223. for (let x in boxs) {
  224. let item = boxs[x];
  225. if (!item.id) continue;
  226. let el = this.createEl(prefix + item.id, 'button');
  227. el.append(new Text(item.label));
  228. if (x === '0') {
  229. el.classList = prefix + 'box ' + prefix + "active";
  230. } else {
  231. el.className = prefix + "box";
  232. }
  233. if (item.fun) {
  234. el.onclick = function() {
  235. eval(item.fun);
  236. }
  237. }
  238. if (item.id === 'speed') {
  239. this.attr(el, 'contenteditable', true)
  240. }
  241. box.append(el);
  242. }
  243. document.body.append(box);
  244. }
  245. sleep(ms) {
  246. return new Promise(resolve => setTimeout(resolve, ms));
  247. }
  248. log(msg) {
  249. if (this.debug) {
  250. console.log(msg);
  251. }
  252. }
  253. logt(msg) {
  254. if (this.debug) {
  255. console.table(msg);
  256. }
  257. }
  258. }
  259. const u = new Utility();
  260. u.appendStyle(MF);
  261. const btns = [
  262. new Box('text', '下载进度 0 %'),
  263. new Box('start', '自动翻页', 'autoPreview()'),
  264. new Box('stop', '停止翻页', 'stopPreview()'),
  265. new Box('down', '下载原图', 'executeDownload(2)'),
  266. new Box('pdf', '下载PDF格式', 'executeDownload(1)')
  267. ]
  268. const domain = {
  269. renrendoc: "renrendoc.com",
  270. book118: 'book118.com',
  271. docin: 'docin.com',
  272. wenku: 'wenku.baidu.com',
  273. so: 'wenku.so.com',
  274. doc88: 'doc88.com',
  275. mbalib: 'doc.mbalib.com',
  276. deliwenku: 'deliwenku.com',
  277. cxk: '7cxk.com',
  278. jinchutou: 'jinchutou.com',
  279. mayiwenku: 'mayiwenku.com',
  280. dugen: 'ww.dugen.com',
  281. iask: 'ishare.iask.com',
  282. chochina: 'chochina.com',
  283. weizhuan: 'weizhuannet.com',
  284. taodocs: 'taodocs.com',
  285. wenkub: 'wenkub.com',
  286. gb688: 'gb688.cn',
  287. jjg: 'jjg.spc.org.cn',
  288. shengtongedu: 'pro-img-brtm.baijiayun.com',
  289. sacinfo: 'hbba.sacinfo.org.cn',
  290. qzoffice: 'www.qzoffice.com',
  291. nrsis: 'www.nrsis.org.cn',
  292. nea: '114.251.111.103:18080',
  293. nssi: 'www.nssi.org.cn',
  294. feishu: 'feishu.cn',
  295. jtysbz: 'jtysbz.cn',
  296. jsjlw: 'online.71nc.cn',
  297. mwr: '121.36.94.83:9008',
  298. cebpubservice: 'bulletin.cebpubservice.com',
  299. rbtest: 'rbtest.cnca.cn',
  300. };
  301. const {
  302. host,
  303. href,
  304. origin
  305. } = window.location;
  306. const jsPDF = jspdf.jsPDF;
  307. let zipWriter; // 声明全局变量
  308. zipWriter = new zip.ZipWriter(new zip.BlobWriter("application/zip"), {
  309. bufferedWrite: true,
  310. useCompressionStream: false
  311. });
  312. const doc = new jsPDF({
  313. orientation: 'p',
  314. unit: 'px',
  315. compress: true
  316. });
  317. let pdf_w = 446,
  318. pdf_h = 631,
  319. loading = 500, // 毫秒
  320. pdf_ratio = 0.56,
  321. title = document.title,
  322. fileType = '',
  323. downType = 1, // 下载文件类型
  324. select = null,
  325. selectBox = null,
  326. dom = null,
  327. beforeFun = null,
  328. interval = null,
  329. startPageNo = 0,
  330. BASE_URL = 'https://wkretype.bdimg.com/retype',
  331. readerInfoBai = null, // 百度文档参数
  332. intervalBai = null; // 百度定时任务
  333. if (host.includes(domain.taodocs)) {
  334. iscopy = 'TRUE'; // taodocs copy flag
  335. }
  336. const params = new URLSearchParams(document.location.search.substring(1));
  337. if (params.size && params.get('custom')) {
  338. window.parent.postMessage({
  339. type: "onload",
  340. value: 'success'
  341. }, "*")
  342. u.log('子页面加载完成!');
  343. }
  344. // 百度拷贝文本
  345. const baiduCopy = () => {
  346. const observerOptions = {
  347. characterData: true,
  348. subtree: true
  349. };
  350. // dom 监听器
  351. const observer = new MutationObserver(function(mutationList, observer) {
  352. const mutation = mutationList[0];
  353. let data = mutation.target.data;
  354. let result = data.substring(data.indexOf('“') + 1, data.lastIndexOf('”'));
  355. let textarea = u.query('#MF_textarea');
  356. if (textarea) {
  357. textarea.innerText = result;
  358. } else {
  359. textarea = u.createEl('MF_textarea', 'textarea');
  360. let style = {
  361. width: "100%",
  362. height: "200px",
  363. outline: "none",
  364. padding: "10px",
  365. boxSizing: "border-box",
  366. fontSize: "16px",
  367. border: "1px solid rgb(204, 204, 204)"
  368. }
  369. u.style(textarea, style)
  370. textarea.innerText = result;
  371. let box = u.query('#catalog-main') || u.query('.catalog-main') || u.query(
  372. '.related-doc-list')
  373. box.before(textarea);
  374. }
  375. });
  376. const targetNode2 = document.querySelector('.link')
  377. // 触发监听
  378. observer.observe(targetNode2, observerOptions);
  379. }
  380. // 监听页面卸载,移除百度定时删除广告等 DOM 定时器
  381. window.onunload = function() {
  382. if (intervalBai) {
  383. clearInterval(intervalBai);
  384. intervalBai = null;
  385. }
  386. }
  387. // 百度 xhr 数据监听
  388. if (host.includes(domain.wenku)) {
  389. const _r_text = window.Response.prototype.text;
  390. window.Response.prototype.text = function() {
  391. return new Promise((resolve, reject) => {
  392. _r_text.call(this).then((text) => {
  393. resolve(text);
  394. }).catch(reject);
  395. });
  396. }
  397. const _open = window.XMLHttpRequest.prototype.open;
  398. window.XMLHttpRequest.prototype.open = function(...args) {
  399. this.addEventListener("load", () => {
  400. try {
  401. let content = this.responseText;
  402. const url = args[1];
  403. if (url.includes('ndocview/readerinfo')) {
  404. const {
  405. data
  406. } = JSON.parse(content);
  407. const htmlUrls = data.htmlUrls;
  408. let list = htmlUrls.png;
  409. let images = [];
  410. if (list) {
  411. images = htmlUrls.png.map(item => {
  412. return item.pageLoadUrl
  413. });
  414. } else {
  415. images = htmlUrls;
  416. }
  417. // 文本内容地址保存
  418. if (htmlUrls.json) {
  419. let pageLoadUrl = htmlUrls.json.map(item => {
  420. return item.pageLoadUrl
  421. })
  422. MF_addURL(pageLoadUrl, 'pageData');
  423. }
  424. // 纯文本类型文件
  425. if (fileType === "txt") { // 纯文本类型
  426. let urls = [];
  427. const {
  428. docId,
  429. freePage,
  430. rsign,
  431. md5sum
  432. } = data;
  433. for (var i = readerInfoBai.showPage + 1; i < freePage + 1; i++) {
  434. let x = md5sum.substring(1);
  435. let n = ["pn=" + i, "rn=1", "type=txt", "spr=0", "rsign=" + rsign,
  436. "callback=wenku_" + i
  437. ].join("&");
  438. let url = BASE_URL + "/text/" + docId + "?" + x + "&" + n;
  439. urls.push(url)
  440. }
  441. MF_addURL(urls, 'pageData');
  442. }
  443. MF_addURL(images);
  444. }
  445. } catch {}
  446. });
  447. return _open.apply(this, args);
  448. }
  449. }
  450. const childMessage = (message) => {
  451. window.parent.postMessage({
  452. type: "child",
  453. value: message ? message : ''
  454. }, "*")
  455. }
  456. const parentMessage = (message, attr) => {
  457. const ifarme = document.getElementById(attr);
  458. let _window = ifarme.contentWindow;
  459. _window.postMessage({
  460. type: 'parent',
  461. value: message ? message : ''
  462. }, "*")
  463. }
  464. // 监听页面消息事件
  465. window.addEventListener("message", (e) => {
  466. // console.log(e)
  467. const {
  468. type,
  469. value
  470. } = e.data;
  471. if (type === 'parent') { // 父级-子页面消息
  472. if (value.includes(origin)) {
  473. MF_ImageToBase64(value).then(data => {
  474. childMessage(data);
  475. })
  476. }
  477. } else if (type === 'child') { // 子页面-到父页面消息
  478. let index = Number(localStorage.getItem("current") || "0");
  479. let length = Number(localStorage.getItem("length") || "0");
  480. const {
  481. blob,
  482. uint8,
  483. width,
  484. height
  485. } = value;
  486. if (fileType.includes('ppt') || width > height) {
  487. doc.addPage([width * pdf_ratio, height * pdf_ratio], 'l');
  488. doc.addImage(uint8, 'JPEG', 0, 0, width * pdf_ratio, height * pdf_ratio, index, 'FAST')
  489. } else {
  490. doc.addPage();
  491. doc.addImage(uint8, 'JPEG', 0, 0, pdf_w, pdf_h, index, 'FAST')
  492. }
  493. if (index === 1) {
  494. doc.deletePage(1);
  495. }
  496. zipWriter.add(index + ".png", new zip.BlobReader(blob));
  497. localStorage.setItem('current', index + 1 + "");
  498. downimg();
  499. } else if (type === 'onload') {
  500. const url = new URL(e.origin);
  501. const attrId = url.host.replaceAll(".", "");
  502. const query = document.getElementById('#' + attrId);
  503. if (query) {
  504. downimg();
  505. }
  506. }
  507. })
  508. /**
  509. * @description 前置方法
  510. * @author Mr.Fang
  511. * @time 2024年2月2日
  512. */
  513. const before = () => {
  514. if (beforeFun) {
  515. u.log('---------->beforeFun');
  516. eval(beforeFun)
  517. }
  518. // 画布添加监听事件,当数据加载完成删除 id,防止数据被清空
  519. if (host.includes(domain.wenku)) {
  520. const els = u.queryAll('canvas');
  521. for (var i = 0; i < els.length; i++) {
  522. let eNode = els[i];
  523. const intersectionObserver = new IntersectionObserver((entries) => {
  524. let isIntersecting = entries[0].isIntersecting
  525. if (isIntersecting && eNode.width && eNode.height) {
  526. eNode.id = '';
  527. }
  528. });
  529. // 开始监听
  530. intersectionObserver.observe(eNode);
  531. }
  532. }
  533. }
  534. /**
  535. * @description 初始化方法
  536. * @author Mr.Fang
  537. * @time 2024年2月2日
  538. */
  539. const init = () => {
  540. console.table({
  541. host,
  542. href,
  543. origin
  544. })
  545. dom = document.documentElement || document.body;
  546. if (host.includes(domain.renrendoc)) {
  547. if (!/.*renrendoc\.com\/.+$/.test(href)) {
  548. u.log('结束');
  549. return;
  550. }
  551. const node = u.query('h1');
  552. title = node.innerText.replaceAll(" ", "");
  553. node.nextElementSibling.children
  554. const innerText = node.nextElementSibling.children[6].innerText;
  555. fileType = innerText.split(":")[1].toLowerCase();
  556. dom = u.query('.main-content');
  557. beforeFun =
  558. "let er = u.query('#load_preview_btn');if (er && er.style.display !== 'none') {er.click()}";
  559. select = "#page img";
  560. btns.push(new Box('PPT', '获取地址', 'downtxt()'))
  561. } else if (host.includes(domain.book118)) {
  562. if (!/.+book118\.com\/.+$/.test(href)) {
  563. u.log('结束');
  564. return;
  565. }
  566. if (!href.includes('pptView.html') && !params.get("readpage")) {
  567. let node = u.query('h1')
  568. node = node ? node : u.query('h2');
  569. title = node.innerText.replaceAll(" ", "").replaceAll("VIP", "");
  570. const number = title.lastIndexOf(".");
  571. fileType = title.substring(number + 1).toLowerCase();
  572. GM_setValue('title', title);
  573. if (fileType.includes('ppt')) {
  574. beforeFun = "let eb = u.query('#btn_ppt_front_pc');if (eb) {eb.click();}";
  575. } else {
  576. beforeFun = "let eb = u.query('#btn_preview_remain');if (eb) {eb.click();}";
  577. }
  578. } else {
  579. fileType = 'ppt';
  580. title = GM_getValue('title');
  581. }
  582. select = ".webpreview-item img";
  583. btns.push(new Box('PPT', '获取地址', 'downtxt()'))
  584. } else if (host.includes(domain.docin)) {
  585. if (!/.+docin\.com\/.+$/.test(href)) {
  586. u.log('结束');
  587. return;
  588. }
  589. select = "#contentcontainer canvas";
  590. const toImg = params.get('toImg');
  591. console.log('toImg', toImg);
  592. title = u.query('meta[property="og:title"]').content;
  593. fileType = u.attr(u.query('h1').children[0], 'title').toLowerCase();
  594. if (toImg && toImg === '1') {
  595. select = "#contentcontainer img"
  596. }
  597. console.log('toImg', select);
  598. if (isUserLogin === '1') { // 登录
  599. beforeFun = "let eb = u.query('.model-fold-show');if (eb) {eb.click();}";
  600. }
  601. if (fileType.includes('ppt') || (toImg && toImg === '1')) {
  602. btns.push(new Box('PPT', '获取地址', 'downtxt()'))
  603. }
  604. } else if (host.includes(domain.wenku)) {
  605. if (!/.+wenku\.baidu\.com\/(tfview|view).+$/.test(href)) {
  606. u.log('结束');
  607. return;
  608. }
  609. dom = u.query('.reader-wrap');
  610. beforeFun =
  611. "let eb = u.query('.unfold')?u.query('.unfold'):u.query('.read-all');if (eb) {eb.click();}";
  612. select = "#original-creader-root canvas";
  613. btns.push(new Box('print-pdf', '打印PDF', 'window.print()'))
  614. if (fileType.includes('ppt') || fileType.includes('pdf')) {
  615. btns.push(new Box('PPT', '获取地址', 'downtxt()'))
  616. } else {
  617. btns.push(new Box('get-text', '获取文本', 'fullText()'))
  618. }
  619. } else if (host.includes(domain.so)) {
  620. if (!/.+wenku\.so\.com\/.+$/.test(href)) {
  621. u.log('结束');
  622. return;
  623. }
  624. const {
  625. Title,
  626. DocType,
  627. Field03
  628. } = asyncData.DocInfo;
  629. title = Title;
  630. fileType = DocType.toLowerCase();;
  631. btns.splice(1, 2);
  632. btns.push(new Box('PPT', '获取地址', 'downtxt()'))
  633. MF_addURL(Field03);
  634. } else if (host.includes(domain.doc88)) {
  635. if (!/.+doc88\.com\/.+$/.test(href)) {
  636. u.log('结束');
  637. return;
  638. }
  639. title = u.query('meta[property="og:title"]').content;
  640. fileType = u.query("#box1 .attribute").innerText.split(" ")[0].split(":")[1].toLowerCase();
  641. beforeFun = "let eb = u.query('#continueButton');if (eb) {eb.click();}";
  642. select = "#pageContainer .inner_page";
  643. btns.push(new Box('get-text', '获取文本', 'fullText()'))
  644. } else if (host.includes(domain.mbalib)) {
  645. if (!/doc\.mbalib\.com\/.+$/.test(href)) {
  646. u.log('结束');
  647. return;
  648. }
  649. dom = u.query('#scroll-m-box');
  650. title = u.query('h1 p').innerText;
  651. fileType = title.substring(title.indexOf('.') + 1).toLowerCase();
  652. select = "#viewer .page"
  653. btns.splice(1, 0, new Box('speed', '500'));
  654. btns.push(new Box('get-text', '获取文本', 'fullText()'))
  655. } else if (host.includes(domain.deliwenku) ||
  656. host.includes(domain.cxk) ||
  657. host.includes(domain.jinchutou) ||
  658. host.includes(domain.mayiwenku) ||
  659. host.includes(domain.dugen) ||
  660. host.includes(domain.chochina) ||
  661. host.includes(domain.weizhuan)
  662. ) {
  663. if ((!/.+deliwenku\.com\/.+$/.test(href)) &&
  664. (!/.+7cxk\.com\/.+$/.test(href)) &&
  665. (!/.+jinchutou\.com\/.+$/.test(href)) &&
  666. (!/.+mayiwenku\.com\/.+$/.test(href)) &&
  667. (!/ww\.dugen\.com\/.+$/.test(href)) &&
  668. (!/.+chochina\.com\/.+$/.test(href)) &&
  669. (!/.+weizhuannet\.com\/.+$/.test(href))
  670. ) {
  671. return;
  672. }
  673. // 蚂蚁需手动点击全文
  674. if (host.includes(domain.mayiwenku) || host.includes(domain.dugen)) {
  675. preview();
  676. loadingUrls(host.includes(domain.dugen));
  677. } else {
  678. loadingUrls();
  679. }
  680. if (host.includes(domain.chochina)) {
  681. title = u.query('h1').innerText;
  682. fileType = title.substring(title.indexOf('.') + 1).toLowerCase();
  683. } else {
  684. title = u.query('meta[property="og:title"]').content;
  685. fileType = u.query('meta[property="og:document:type"]').content.toLowerCase();
  686. }
  687. btns.splice(1, 2);
  688. btns.push(new Box('PPT', '获取地址', 'downtxt()'))
  689. } else if (host.includes(domain.iask)) {
  690. if (!/ishare\.iask\.com\/.+$/.test(href)) return;
  691. title = pageConfig.access.title;
  692. fileType = pageConfig.access.format.toLowerCase();;
  693. btns.splice(1, 2);
  694. btns.push(new Box('PPT', '获取地址', 'downtxt()'))
  695. MF_addURL(pageConfig.imgUrl);
  696. } else if (host.includes(domain.taodocs)) {
  697. if (!/www\.taodocs\.com\/.+$/.test(href)) return;
  698. title = u.query('h1').innerText;
  699. fileType = title.substring(title.indexOf('.') + 1).toLowerCase();
  700. beforeFun = "let eb = u.query('.fc2e');if (eb) {eb.click();}";
  701. select = "#canvas canvas";
  702. btns.push(new Box('get-text', '获取文本', 'fullText()'))
  703. } else if (host.includes(domain.wenkub)) {
  704. if (!/www\.wenkub\.com\/.+$/.test(href)) return;
  705. title = u.query('h1').innerText;
  706. fileType = title.substring(title.indexOf('.') + 1).toLowerCase();
  707. beforeFun = "let eb = u.query('.fc2e');if (eb) {eb.click();}";
  708. select = "#pageContainer img";
  709. } else if (host.includes(domain.gb688)) {
  710. if (u.query('#verifyCode')) return;
  711. fileType = 'pdf';
  712. select = "#viewer .page";
  713. btns.splice(1, 0, new Box('speed', '500'));
  714. btns.push(new Box('get-text', '获取文本', 'fullText()'))
  715. } else if (host.includes(domain.jjg)) {
  716. fileType = ".pdf";
  717. select = "#docViewer_ViewContainer .fwr-page-invisible";
  718. // select = "#docViewer_ViewContainer .fwr-page-image img";
  719. } else if (host.includes(domain.shengtongedu)) {
  720. fileType = "ppt";
  721. } else if (host.includes(domain.sacinfo)) {
  722. fileType = "pdf";
  723. const md5 = href.split('/').pop(); // 秘钥
  724. joinDownloadURL('https://hbba.sacinfo.org.cn/hbba_onlineRead_page/' + md5)
  725. btns.splice(1, 2);
  726. btns.push(new Box('PPT', '获取地址', 'downtxt()'))
  727. } else if (host.includes(domain.qzoffice)) {
  728. fileType = "pdf";
  729. title = params.get('content') || 'AI-PPT';
  730. btns.splice(1, 2);
  731. btns.splice(2, 1);
  732. } else if (host.includes(domain.nrsis)) {
  733. fileType = "pdf";
  734. select = ".page canvas";
  735. } else if (host.includes(domain.nea)) {
  736. fileType = "pdf";
  737. select = ".page canvas";
  738. } else if (host.includes(domain.nssi)) {
  739. title = document.title,
  740. fileType = "pdf";
  741. select = "#viewer .page";
  742. dom = u.query('#viewerContainer')
  743. btns.splice(1, 0, new Box('speed', '500'));
  744. } else if (host.includes(domain.feishu)) {
  745. fileType = "pdf";
  746. dom = u.query('#viewerContainer')
  747. fileType = 'pdf';
  748. select = "#viewer .page";
  749. if (title.includes('PDF')) {
  750. btns.splice(1, 0, new Box('speed', '500'));
  751. btns.push(new Box('get-text', '获取文本', 'fullText()'))
  752. } else {
  753. btns.splice(1, 5);
  754. btns.push(new Box('get-build', '打包下载', 'buildDown()'))
  755. }
  756. } else if (host.includes(domain.jtysbz) || host.includes(domain.cebpubservice)) {
  757. fileType = "pdf";
  758. select = "#viewer .page";
  759. btns.splice(1, 0, new Box('speed', '500'));
  760. btns.push(new Box('get-text', '获取文本', 'fullText()'))
  761. } else if (host.includes(domain.jsjlw)) {
  762. fileType = "pdf";
  763. select = "#ctn img";
  764. dom = u.query('#ctn');
  765. } else if (host.includes(domain.mwr)) {
  766. fileType = "pdf";
  767. select = "#imgdiv img";
  768. title = u.query('.left_titile').innerText;
  769. } else if (host.includes(domain.rbtest)) {
  770. fileType = "pdf";
  771. select = ".page canvas";
  772. }
  773. const query = u.query("#btn_ppt_front_pc"); // 原创
  774. if (!query) {
  775. u.gui(btns);
  776. } else {
  777. query.click();
  778. }
  779. console.log('文件名称:', title);
  780. console.log('文件类型:', fileType);
  781. }
  782. (function() {
  783. // 移除多余 iframe
  784. document.querySelectorAll('iframe').forEach(item => {
  785. item.remove()
  786. })
  787. // 清空系统缓存数据
  788. localStorage.removeItem('listData')
  789. localStorage.removeItem('length')
  790. localStorage.removeItem('current')
  791. localStorage.removeItem('pageData')
  792. localStorage.removeItem('down')
  793. localStorage.removeItem('SP_text')
  794. // 百度服务端渲染
  795. if (host.includes(domain.wenku)) {
  796. const {
  797. readerInfo,
  798. viewBiz
  799. } = pageData;
  800. fileType = viewBiz.docInfo.fileType;
  801. title = viewBiz.docInfo.aiQueryTitle;
  802. readerInfoBai = readerInfo;
  803. const htmlUrls = readerInfo.htmlUrls;
  804. if (htmlUrls) {
  805. if (fileType.includes('ppt')) {
  806. MF_addURL(htmlUrls);
  807. } else if (fileType.includes('pdf')) {
  808. let images = [];
  809. if (htmlUrls.png) {
  810. images = htmlUrls.png.map(item => {
  811. return item.pageLoadUrl
  812. })
  813. } else {
  814. images = htmlUrls;
  815. }
  816. MF_addURL(images);
  817. }
  818. // 文本内容地址保存
  819. if (htmlUrls.json) {
  820. let pageLoadUrl = htmlUrls.json.map(item => {
  821. return item.pageLoadUrl
  822. })
  823. MF_addURL(pageLoadUrl, 'pageData');
  824. }
  825. }
  826. // 纯文本类型文件
  827. if (fileType === "txt") { // 纯文本类型
  828. let urls = [];
  829. const {
  830. docId,
  831. freePage,
  832. rsign,
  833. showPage,
  834. md5sum
  835. } = readerInfoBai;
  836. for (var i = 1; i < showPage + 1; i++) {
  837. let x = md5sum.substring(1);
  838. let n = ["pn=" + i, "rn=1", "type=txt", "spr=0", "rsign=" + rsign,
  839. "callback=wenku_" + i
  840. ].join("&");
  841. let url = BASE_URL + "/text/" + docId + "?" + x + "&" + n;
  842. urls.push(url)
  843. }
  844. MF_addURL(urls, 'pageData');
  845. }
  846. setTimeout(() => {
  847. baiduCopy()
  848. }, 500)
  849. intervalBai = setInterval(() => {
  850. // 右侧侧边栏
  851. const vip = u.query('#app-right');
  852. if (vip) {
  853. vip.remove()
  854. }
  855. const chat = u.query('.wk-chat-modal');
  856. if (chat) {
  857. chat.remove()
  858. }
  859. // 左侧广告轮播
  860. const banner = u.query('.banner-wrapper');
  861. if (banner) {
  862. banner.remove()
  863. }
  864. }, 1000);
  865. }
  866. })();
  867. // load 事件
  868. (() => {
  869. // 在这里执行渲染完成后的操作
  870. console.log('HTML 渲染完成!');
  871. // 监听子页面加载完成,发送消息
  872. if (!params.size || !params.get('custom')) {
  873. init()
  874. }
  875. })();
  876. /**
  877. * @description 开始方法,自动预览
  878. * @author Mr.Fang
  879. * @time 2024年2月2日
  880. */
  881. const autoPreview = async () => {
  882. if (host.includes(domain.book118) && fileType.includes('ppt')) {
  883. localStorage.setItem('start', '1');
  884. await autoParsingPPT();
  885. return false;
  886. }
  887. if (host.includes(domain.shengtongedu) && fileType.includes('ppt')) {
  888. localStorage.setItem('start', '1');
  889. await autoShengTongParsingPPT();
  890. return false;
  891. }
  892. if (host.includes(domain.mbalib) ||
  893. host.includes(domain.nssi) ||
  894. host.includes(domain.feishu) ||
  895. host.includes(domain.cebpubservice) ||
  896. host.includes(domain.jtysbz) || (host.includes(domain.gb688) && !u.query('#viewer').style
  897. .transform)) {
  898. localStorage.setItem('start', '1');
  899. localStorage.removeItem('SP_index')
  900. dom.scrollTop = 0;
  901. await scrollPreview()
  902. return false;
  903. }
  904. if (interval) return false;
  905. if (host.includes(domain.docin)) {
  906. // 起始页码
  907. startPageNo = document.querySelector("#page_cur").value - 1 || 0;
  908. } else {
  909. dom.scrollTop = 0;
  910. }
  911. interval = setInterval(() => {
  912. if (host.includes(domain.book118)) {
  913. scrollPageArea()
  914. } else if (host.includes(domain.renrendoc)) {
  915. scrollPageArea()
  916. } else if (host.includes(domain.docin)) {
  917. scrollWinArea()
  918. } else if (host.includes(domain.wenku)) {
  919. scrollWinArea()
  920. } else if (host.includes(domain.doc88)) {
  921. scrollPageAreaDoc88()
  922. } else if (host.includes(domain.taodocs)) {
  923. scrollWinAreaTao()
  924. } else if (host.includes(domain.gb688)) {
  925. scrollPageAreaDocGB()
  926. } else if (host.includes(domain.jjg)) {
  927. scrollPageAreaJJG()
  928. } else if (host.includes(domain.nrsis) ||
  929. host.includes(domain.nea) ||
  930. host.includes(domain.mwr) ||
  931. host.includes(domain.jsjlw) ||
  932. host.includes(domain.rbtest)
  933. ) {
  934. scrollWinArea()
  935. }
  936. }, 500);
  937. }
  938. /**
  939. * @description 结束方法,停止预览
  940. * @author Mr.Fang
  941. * @time 2024年2月2日
  942. */
  943. const stopPreview = async () => {
  944. console.log('---------->stopPreview');
  945. if (interval) {
  946. clearInterval(interval);
  947. interval = null;
  948. }
  949. localStorage.removeItem('start')
  950. }
  951. /**
  952. * @description 结束方法,停止预览,前置方法
  953. * @author Mr.Fang
  954. * @time 2024年7月22日
  955. */
  956. const stopBeforePreview = async () => {
  957. if (host.includes(domain.mwr)) {
  958. const page_index = u.query('.page_index').innerText;
  959. const page_total = u.query('.page_total').innerText;
  960. if (page_index === page_total) {
  961. stopPreview();
  962. u.preview(-1);
  963. } else { // 向上滚动一次
  964. dom.scrollTo({
  965. top: dom.scrollTop - 100,
  966. left: 0,
  967. behavior: "smooth",
  968. });
  969. }
  970. } else {
  971. stopPreview();
  972. u.preview(-1);
  973. }
  974. }
  975. /**
  976. * @description 执行文件下载
  977. * @author Mr.Fang
  978. * @time 2024年2月20日
  979. * @param type 文件类型
  980. */
  981. const executeDownload = async (type) => {
  982. downType = type;
  983. const down = localStorage.getItem('down');
  984. console.log('down', down)
  985. console.log('host', host)
  986. console.log('downType', downType)
  987. if (!down) {
  988. // 结束后续执行的方法
  989. if (host.includes(domain.book118) || host.includes(domain.shengtongedu)) {
  990. if (fileType.includes('ppt')) {
  991. conditionDownload();
  992. } else {
  993. await parseImage()
  994. }
  995. } else if (host.includes(domain.renrendoc)) {
  996. await parseImage()
  997. } else if (host.includes(domain.wenku)) {
  998. const display = u.query('#app-top-right-tool')?.style.display;
  999. if (!display || display === 'none') {
  1000. await downimg()
  1001. }
  1002. } else if (host.includes(domain.docin)) {
  1003. if (params.get('toImg')) {
  1004. await parseImage()
  1005. } else {
  1006. await imageToBase64()
  1007. conditionDownload();
  1008. }
  1009. } else if (host.includes(domain.mbalib) ||
  1010. host.includes(domain.feishu) ||
  1011. host.includes(domain.nssi) ||
  1012. host.includes(domain.cebpubservice) ||
  1013. host.includes(domain.jtysbz)
  1014. ) {
  1015. conditionDownload();
  1016. } else if (
  1017. host.includes(domain.doc88) ||
  1018. host.includes(domain.taodocs) ||
  1019. host.includes(domain.nrsis) ||
  1020. host.includes(domain.nea) ||
  1021. host.includes(domain.rbtest)
  1022. ) {
  1023. await imageToBase64()
  1024. conditionDownload();
  1025. } else if (host.includes(domain.deliwenku) ||
  1026. host.includes(domain.cxk) ||
  1027. host.includes(domain.jinchutou) ||
  1028. host.includes(domain.mayiwenku) ||
  1029. host.includes(domain.dugen) ||
  1030. host.includes(domain.iask) ||
  1031. host.includes(domain.chochina) ||
  1032. host.includes(domain.weizhuan) ||
  1033. host.includes(domain.so) ||
  1034. host.includes(domain.sacinfo)
  1035. ) {
  1036. await downimg()
  1037. } else if (host.includes(domain.gb688)) {
  1038. if (u.query('#viewer').style.transform) { // bg
  1039. await downloadGBImage();
  1040. } else {
  1041. conditionDownload();
  1042. }
  1043. } else if (host.includes(domain.jsjlw)) {
  1044. await parseImage()
  1045. } else if (host.includes(domain.jjg)) {
  1046. await downloadElement()
  1047. conditionDownload();
  1048. } else if (host.includes(domain.qzoffice)) {
  1049. await handleQzoffice();
  1050. conditionDownload();
  1051. } else if (host.includes(domain.mwr)) {
  1052. await downloadImage();
  1053. conditionDownload();
  1054. }
  1055. } else {
  1056. conditionDownload();
  1057. }
  1058. }
  1059. // 飞书打包下载
  1060. const buildDown = async () => {
  1061. const styles = [...u.queryAll('style')].map(div => div.outerHTML).join('\n');
  1062. if (title.includes('excel')) {
  1063. const container = u.query('.container').innerHTML;
  1064. const content =
  1065. `<!DOCTYPE html><html><head><meta charset="utf-8">${styles}</head><body style="overflow: auto;">${container}</body></html>`
  1066. const htmlBlob = new Blob([content], {
  1067. type: "text/html;charset=utf-8"
  1068. });
  1069. zipWriter.add('index.html', new zip.BlobReader(htmlBlob))
  1070. zipWriter.add('index.txt', new zip.TextReader(u.query('.container').innerText))
  1071. } else if (title.includes('txt')) {
  1072. const container = u.query('#scroll-container').innerHTML;
  1073. const content =
  1074. `<!DOCTYPE html><html><head><meta charset="utf-8">${styles}</head><body>${container}</body></html>`
  1075. const htmlBlob = new Blob([content], {
  1076. type: "text/html;charset=utf-8"
  1077. });
  1078. zipWriter.add('index.html', new zip.BlobReader(htmlBlob))
  1079. zipWriter.add('index.txt', new zip.TextReader(u.query('#scroll-container').innerText))
  1080. }
  1081. await u.sleep(500)
  1082. downzip();
  1083. u.preText('下载完成')
  1084. }
  1085. /**
  1086. * 根据指定条件下载文件
  1087. */
  1088. const conditionDownload = () => {
  1089. if (downType === 1) {
  1090. downpdf()
  1091. localStorage.setItem('down', '1')
  1092. } else if (downType === 2) {
  1093. downzip()
  1094. if (!host.includes(domain.qzoffice)) // 排除 qz
  1095. localStorage.setItem('down', '1')
  1096. }
  1097. u.preText('下载完成')
  1098. }
  1099. // 滚动指定 Window
  1100. const scrollWinArea = () => {
  1101. before();
  1102. const scrollTop = dom.scrollTop;
  1103. const height = dom.scrollHeight - dom.clientHeight;
  1104. if (height <= scrollTop) {
  1105. stopBeforePreview();
  1106. } else {
  1107. let top = scrollTop + 500;
  1108. dom.scrollTo({
  1109. top: top,
  1110. left: 0,
  1111. behavior: "smooth",
  1112. });
  1113. u.preview(top, height);
  1114. }
  1115. }
  1116. /**
  1117. * @description 判断 dom 是否在可视范围内
  1118. * @author Mr.Fang
  1119. * @time 2024-6-25
  1120. * @param {HTMLElement} el
  1121. */
  1122. const isElementInViewport = (el) => {
  1123. const rect = el.getBoundingClientRect();
  1124. return (
  1125. rect.top >= 0 && rect.top <= (window.innerHeight || document.documentElement.clientHeight)
  1126. );
  1127. }
  1128. /**
  1129. * @description 图片添加到 zip 或 pdf
  1130. * @author Mr.Fang
  1131. * @time 2024-6-25
  1132. * @see http://raw.githack.com/MrRio/jsPDF/master/docs/module-addImage.html#~addImage
  1133. * @param {HTMLImageElement | HTMLCanvasElement | Uint8Array | RGBAData} imageData
  1134. * @param {Blob} blob
  1135. * @param {Number} i 下标
  1136. * @param {Number} width 宽
  1137. * @param {Number} height 高
  1138. * @param {Boolean} natural 原始高度宽度 true 原始尺寸 false A4
  1139. */
  1140. const saveImageAndPDF = (imageData, blob, i, width, height, natural = false) => {
  1141. let dir = 'p';
  1142. let target_w = pdf_w;
  1143. let target_h = pdf_h;
  1144. if (width > height) {
  1145. dir = 'l';
  1146. target_h = pdf_w;
  1147. target_w = pdf_h;
  1148. }
  1149. if (natural) {
  1150. target_h = height * pdf_ratio;
  1151. target_w = width * pdf_ratio;
  1152. } else {
  1153. target_h = target_h;
  1154. target_w = target_w;
  1155. }
  1156. zipWriter.add(`${i}.png`, new zip.BlobReader(blob));
  1157. doc.addPage([target_w, target_h], dir);
  1158. doc.addImage(imageData, 'JPEG', 0, 0, target_w, target_h, i, 'FAST')
  1159. if (doc.internal.pages[1].length === 2) {
  1160. doc.deletePage(1); // 删除空白页
  1161. }
  1162. }
  1163. /**
  1164. * @description 保存数据
  1165. * @author Mr.Fang
  1166. * @time 2024-6-25
  1167. * @param {Number} i 下标
  1168. * @param {HTMLElement} imageData 图片对象
  1169. * @param {HTMLElement} textLayer 文本对象
  1170. */
  1171. const previewSave = async (i, imageData, textLayer) => {
  1172. const {
  1173. blob,
  1174. width,
  1175. height
  1176. } = await MF_CanvasToBase64(imageData);
  1177. saveImageAndPDF(imageData, blob, i, width, height, false)
  1178. //获取文本内容
  1179. let texts = JSON.parse(localStorage.getItem('SP_text')) || [];
  1180. texts.push(fileType.includes('doc') ? textLayer.innerText : textLayer.textContent);
  1181. localStorage.setItem('SP_text', JSON.stringify(texts))
  1182. // 更新下标
  1183. localStorage.setItem('SP_index', i + 1);
  1184. }
  1185. /**
  1186. * @description 预览&下载
  1187. * @author Mr.Fang
  1188. * @time 2024-6-25
  1189. */
  1190. const scrollPreview = async () => {
  1191. if (!localStorage.getItem("start")) {
  1192. u.preview(-1, null, "已终止");
  1193. return;
  1194. }
  1195. before();
  1196. const i = Number(localStorage.getItem('SP_index')) || 0;
  1197. const childrens = u.queryAll(select);
  1198. const current = childrens[i];
  1199. const length = childrens.length;
  1200. // 如果当前对象在可视范围内,进行保存添加
  1201. const imageData = current.querySelector('canvas');
  1202. const textLayer = current.querySelector('.textLayer');
  1203. if (isElementInViewport(current) && imageData && textLayer) {
  1204. await previewSave(i, imageData, textLayer)
  1205. if (i !== length - 1)
  1206. childrens[i + 1].scrollIntoView({
  1207. behavior: "smooth"
  1208. });
  1209. } else {
  1210. current.scrollIntoView({
  1211. behavior: "smooth"
  1212. });
  1213. }
  1214. u.preview(i, length);
  1215. if (i !== length - 1) {
  1216. let speed = 500,
  1217. MF_speed = Number(u.query('#MF_speed').innerText);
  1218. if (MF_speed > 0) {
  1219. speed = MF_speed
  1220. } else {
  1221. u.query('#MF_speed').innerText = 500
  1222. }
  1223. setTimeout(() => {
  1224. console.log(speed, 'ms 后执行');
  1225. scrollPreview()
  1226. }, speed)
  1227. } else {
  1228. console.log('执行结束');
  1229. u.preview(-1);
  1230. localStorage.removeItem('SP_index')
  1231. localStorage.removeItem('start')
  1232. }
  1233. }
  1234. // 滚动指定 Window
  1235. const scrollWinAreaTao = () => {
  1236. const scrollTop = dom.scrollTop;
  1237. const height = dom.scrollHeight - dom.clientHeight;
  1238. const fc2e = u.query('.fc2e');
  1239. let end = 0;
  1240. const images = u.queryAll(select);
  1241. const length = images.length;
  1242. for (let i = 0; i < length; i++) {
  1243. let item = images[i];
  1244. const {
  1245. top
  1246. } = item.getBoundingClientRect();
  1247. if (item.width === 300 || item.height == 150) {
  1248. end = 1;
  1249. dom.scrollTo({
  1250. top: dom.scrollTop + top,
  1251. left: 0,
  1252. behavior: "smooth",
  1253. });
  1254. u.preview(dom.scrollTop + top, height);
  1255. break;
  1256. }
  1257. }
  1258. if (end === 0) {
  1259. if (!fc2e) {
  1260. stopPreview();
  1261. u.preview(-1);
  1262. } else {
  1263. before()
  1264. }
  1265. }
  1266. }
  1267. // 滚动指定区域
  1268. const scrollPageArea = () => {
  1269. before();
  1270. const clientHeight = dom.clientHeight;
  1271. let end = 0;
  1272. const images = u.queryAll(select);
  1273. const length = images.length;
  1274. for (let i = 0; i < length; i++) {
  1275. let item = images[i];
  1276. const {
  1277. top
  1278. } = item.getBoundingClientRect();
  1279. if (item instanceof HTMLImageElement) {
  1280. if (!item.src && !item.getAttribute('data-src')) {
  1281. end = 1;
  1282. dom.scrollTo({
  1283. top: dom.scrollTop + top,
  1284. left: 0,
  1285. behavior: "smooth",
  1286. });
  1287. u.preview(i + 1, length);
  1288. break;
  1289. }
  1290. } else if (item instanceof HTMLDivElement) {
  1291. end = 1;
  1292. dom.scrollTo({
  1293. top: dom.scrollTop + top,
  1294. left: 0,
  1295. behavior: "smooth",
  1296. });
  1297. u.preview(i + 1, length);
  1298. break;
  1299. }
  1300. }
  1301. if (end === 0) {
  1302. u.preview(-1);
  1303. stopPreview();
  1304. }
  1305. }
  1306. // 道客滚动函数
  1307. const scrollPageAreaDoc88 = () => {
  1308. before();
  1309. const clientHeight = dom.clientHeight;
  1310. let end = 0;
  1311. const images = u.queryAll(select);
  1312. const length = images.length;
  1313. const startNum = document.querySelector("#pageNumInput").value - 1 || 0;
  1314. for (let i = startNum; i < length; i++) {
  1315. let item = images[i];
  1316. const {
  1317. top
  1318. } = item.getBoundingClientRect();
  1319. let previousElementSibling = item.previousElementSibling.previousElementSibling;
  1320. let fs = u.attr(item, 'fs');
  1321. let t = previousElementSibling.innerText;
  1322. if (t.length !== 0) {
  1323. end = 1;
  1324. item.scrollIntoView({
  1325. behavior: "smooth"
  1326. });
  1327. u.preview(i + 1, length);
  1328. break;
  1329. }
  1330. }
  1331. if (end === 0) {
  1332. u.preview(-1);
  1333. stopPreview();
  1334. }
  1335. }
  1336. const scrollPageAreaDocGB = () => {
  1337. // 100% 预览
  1338. if (u.query('#scaleSelect').selectedIndex < 9) {
  1339. u.query('#zoomIn').click()
  1340. }
  1341. const clientHeight = dom.clientHeight;
  1342. let end = 0;
  1343. const els = u.queryAll(select);
  1344. const length = els.length;
  1345. for (let i = 0; i < length; i++) {
  1346. let item = els[i];
  1347. if (u.attr(item, 'bg')) {
  1348. end = 1;
  1349. item.scrollIntoView({
  1350. behavior: "smooth"
  1351. });
  1352. u.preview(i + 1, length);
  1353. break;
  1354. }
  1355. }
  1356. if (end === 0) {
  1357. u.preview(-1);
  1358. stopPreview();
  1359. }
  1360. }
  1361. const scrollPageAreaJJG = () => {
  1362. let end = 0;
  1363. // 放大
  1364. if (u.query('.fwr-rb-zoom-box input').value === '100%') {
  1365. u.query('.fwr-rb-bottom-zoomin').click();
  1366. return;
  1367. }
  1368. const pages = u.query(".fwr-rb-bottom-tabs input").value.split('/');
  1369. const els = u.queryAll(select);
  1370. const length = els.length;
  1371. for (let i = Number(pages[0].trim()) - 1; i < length; i++) {
  1372. const item = els[i];
  1373. const page = item.querySelector('.fwr-page-tile')
  1374. if (!page) {
  1375. end = 1;
  1376. u.query('.fwr-rb-bottom-page-next').click();
  1377. u.preview(i + 1, length);
  1378. break;
  1379. }
  1380. }
  1381. if (end === 0) {
  1382. u.preview(-1);
  1383. stopPreview();
  1384. }
  1385. }
  1386. /**
  1387. * canvas 转 blob 对象
  1388. * 导出全部按 A4 格式导出,方便兼容大部分文档,支持横竖格式
  1389. */
  1390. const imageToBase64 = async () => {
  1391. const images = u.queryAll(select);
  1392. const length = images.length;
  1393. for (let i = 0; i < length; i++) {
  1394. const item = images[i];
  1395. if (host.includes(domain.doc88)) {
  1396. let previousElementSibling = item.previousElementSibling.previousElementSibling;
  1397. let t = previousElementSibling.innerText;
  1398. if (t.length !== 0) {
  1399. continue;
  1400. }
  1401. }
  1402. let {
  1403. blob,
  1404. width,
  1405. height
  1406. } = await MF_CanvasToBase64(item);
  1407. saveImageAndPDF(item, blob, i, width, height, host.includes(domain.doc88) || host.includes(
  1408. domain.rbtest))
  1409. await u.preview(i + 1, length);
  1410. }
  1411. console.log('处理完成', length);
  1412. }
  1413. /**
  1414. * @description 原创力 PPT 解析
  1415. * @author Mr.Fang
  1416. * @time 2024年2月21日
  1417. */
  1418. const autoParsingPPT = async () => {
  1419. if (!localStorage.getItem("start")) {
  1420. u.preview(-1, null, "已终止");
  1421. return;
  1422. }
  1423. const page = Number(u.query('#PageIndex').innerText);
  1424. const total = Number(u.query('#PageCount').innerText);
  1425. const childNodes = u.query("#view").childNodes;
  1426. const count = childNodes.length;
  1427. const max_index = page - 1;
  1428. const current = u.query("#view" + max_index);
  1429. // 动作数量
  1430. const a_len = u.queryAll(`#view${max_index} #animt${max_index}>div`).length;
  1431. if (a_len !== 0) {
  1432. await u.sleep(1000);
  1433. }
  1434. const bgs = MF_RecursiveParsingImages(current);
  1435. await new Promise((resolve) => {
  1436. html2canvas(current, {
  1437. useCORS: true,
  1438. logging: false,
  1439. }).then(function(canvas) {
  1440. let fileName = max_index + "_" + a_len + ".png";
  1441. // 将canvas转换为图片并下载.
  1442. canvas.toBlob(blob => {
  1443. zipWriter.add(fileName, new zip.BlobReader(blob));
  1444. },
  1445. "image/png",
  1446. 1);
  1447. // 添加PDF
  1448. // 794px*1123px ;
  1449. doc.addPage([canvas.width * pdf_ratio, canvas.height * pdf_ratio], 'l');
  1450. doc.addImage(canvas, 'JPEG', 0, 0, canvas.width * pdf_ratio, canvas
  1451. .height *
  1452. pdf_ratio, max_index + "_" + a_len, 'FAST')
  1453. if (max_index === 1) {
  1454. doc.deletePage(1);
  1455. }
  1456. resolve();
  1457. });
  1458. })
  1459. if (a_len === 0) {
  1460. try {
  1461. const detail = bgs.map((item, i) => {
  1462. return zipWriter.add(max_index + "/" + i + ".png", new zip.HttpReader(
  1463. item));
  1464. });
  1465. await Promise.all(detail);
  1466. zipWriter.add(max_index + "/" + "文本描述.txt", new zip.TextReader(current.innerText));
  1467. } catch (e) {
  1468. console.error(e);
  1469. }
  1470. }
  1471. u.preview(page, total);
  1472. const pageNext = u.query('#pageNext');
  1473. const btmRight = u.query('.btmRight');
  1474. if (page !== total) {
  1475. btmRight.click();
  1476. await autoParsingPPT();
  1477. }
  1478. }
  1479. /**
  1480. * 键盘事件 ←左 右→
  1481. */
  1482. const triggerKeyEvent = (element, key = 'right', type) => {
  1483. var event = new KeyboardEvent(type, {
  1484. bubbles: true,
  1485. cancelable: true,
  1486. key: key,
  1487. keyCode: key === 'letf' ? 37 : 39, // 37是左箭头,39是右箭头
  1488. which: key === 'letf' ? 37 : 39
  1489. });
  1490. element.dispatchEvent(event);
  1491. }
  1492. /**
  1493. * @description 盛通教育 PPT 解析
  1494. * @author Mr.Fang
  1495. * @time 2024年5月10日
  1496. */
  1497. const autoShengTongParsingPPT = async () => {
  1498. if (!localStorage.getItem("start")) {
  1499. u.preview(-1, null, "已终止");
  1500. return;
  1501. }
  1502. const current = u.query('#playerView > div:nth-child(2)');
  1503. current.style.transform = 'none'
  1504. const {
  1505. total,
  1506. page
  1507. } = await new Promise((resolve) => {
  1508. const childNodes = document.querySelector(
  1509. "#playerView > div:nth-child(2) > div:nth-child(1) > div").childNodes;
  1510. const total = childNodes.length - 1;
  1511. let page = 1;
  1512. childNodes.forEach((item, index) => {
  1513. if (item.childNodes.length > 0) {
  1514. page = index;
  1515. }
  1516. })
  1517. resolve({
  1518. total,
  1519. page
  1520. })
  1521. })
  1522. const max_index = page - 1;
  1523. // 动作数量
  1524. let a_len = 0;
  1525. if (max_index === Number(localStorage.getItem('currentPage'))) {
  1526. a_len = Number(localStorage.getItem('currentPageIndex')) + 1;
  1527. }
  1528. if (a_len !== 0) {
  1529. await u.sleep(1000);
  1530. }
  1531. const bgs = MF_RecursiveParsingImages(current);
  1532. await new Promise((resolve) => {
  1533. html2canvas(current, {
  1534. useCORS: true,
  1535. logging: false,
  1536. }).then(function(canvas) {
  1537. // 将canvas转换为图片并下载.
  1538. let data = canvas.toDataURL();
  1539. let fileName = `${max_index}_${a_len}.png`;
  1540. zipWriter.add(fileName, new zip.Data64URIReader(data));
  1541. // 添加PDF
  1542. // 794px*1123px ;
  1543. doc.addPage([canvas.width * pdf_ratio, canvas.height * pdf_ratio], 'l');
  1544. doc.addImage(data, 'JPEG', 0, 0, canvas.width * pdf_ratio, canvas
  1545. .height *
  1546. pdf_ratio, max_index + "_" + a_len, 'FAST')
  1547. if (max_index === 1) {
  1548. doc.deletePage(1);
  1549. }
  1550. localStorage.setItem('currentPage', max_index);
  1551. localStorage.setItem('currentPageIndex', a_len);
  1552. resolve();
  1553. });
  1554. })
  1555. if (a_len === 0) {
  1556. try {
  1557. const detail = bgs.map((item, i) => {
  1558. return zipWriter.add(max_index + "/" + i + ".png", new zip.HttpReader(
  1559. item));
  1560. });
  1561. await Promise.all(detail);
  1562. zipWriter.add(max_index + "/" + "文本描述.txt", new zip.TextReader(current.innerText));
  1563. } catch (e) {
  1564. console.error(e);
  1565. }
  1566. }
  1567. u.preview(page, total);
  1568. if (page !== total) {
  1569. triggerKeyEvent(document.body, 'right', 'keydown');
  1570. triggerKeyEvent(document.body, 'right', 'keyup');
  1571. await autoShengTongParsingPPT();
  1572. }
  1573. }
  1574. /**
  1575. * @description 轻竹办公
  1576. * @author Mr.Fang
  1577. * @time 2024年5月17日
  1578. */
  1579. const handleQzoffice = async () => {
  1580. localStorage.removeItem('down')
  1581. // 递归遍历 DOM 节点
  1582. function traverseDOM(node, callback) {
  1583. if (node.nodeType === Node.ELEMENT_NODE) {
  1584. callback(node); // 调用回调函数处理当前节点
  1585. node = node.firstChild; // 获取第一个子节点
  1586. while (node) {
  1587. traverseDOM(node, callback); // 递归遍历子节点
  1588. node = node.nextSibling; // 获取下一个兄弟节点
  1589. }
  1590. }
  1591. }
  1592. // 查找具有指定属性的 <image> 元素
  1593. function findImagesWithAttribute(node) {
  1594. var images = [];
  1595. traverseDOM(node, function(element) {
  1596. if (element.tagName === 'image') {
  1597. images.push(element);
  1598. }
  1599. });
  1600. return images;
  1601. }
  1602. const template = document.getElementById("templateCanvas").cloneNode(true);
  1603. template.style.display = 'block';
  1604. template.style.height = '0px';
  1605. template.style.position = 'relative';
  1606. template.style.display = 'block';
  1607. // 在整个文档中查找具有指定属性的 <image> 元素
  1608. const images = findImagesWithAttribute(template);
  1609. const imageArray = [];
  1610. // 打印找到的元素
  1611. const blobs = [];
  1612. try {
  1613. images.forEach(async (image, i) => {
  1614. const animVal = image.href.animVal;
  1615. let is = imageArray.filter(item => item.href === animVal);
  1616. if (animVal && is.length === 0) {
  1617. image.setAttribute('xlink:href', `./images/${i}.png`)
  1618. imageArray.push({
  1619. name: `./images/${i}.png`,
  1620. href: animVal
  1621. })
  1622. const {
  1623. blob,
  1624. width,
  1625. height
  1626. } = await MF_ImageToBase64(animVal);
  1627. zipWriter.add(`images/${i}.png`, new zip.BlobReader(blob));
  1628. } else {
  1629. image.setAttribute('xlink:href', is[0].name)
  1630. }
  1631. });
  1632. } catch (e) {
  1633. console.log(e);
  1634. }
  1635. const avgArray = document.querySelectorAll(".child-element svg");
  1636. let content = [];
  1637. const outerHTML = template.outerHTML;
  1638. content.push(outerHTML);
  1639. for (let i = 0; i < avgArray.length; i++) {
  1640. const avgArrayElement = avgArray[i];
  1641. const cloneNode = avgArrayElement.cloneNode(true);
  1642. cloneNode.style.position = "static";
  1643. cloneNode.style.width = "100%";
  1644. cloneNode.style.height = "100%";
  1645. cloneNode.style.transform = "none";
  1646. const html = cloneNode.outerHTML;
  1647. content.push(
  1648. "<div classname=\"page-view\" style=\"width: 1200px; height: 820px;\">" +
  1649. html + "</div>");
  1650. }
  1651. // 添加 html
  1652. const htmlBlob = new Blob(['<!DOCTYPE html>' + content.join('\n\n')], {
  1653. type: "text/html;charset=utf-8"
  1654. });
  1655. zipWriter.add('index.html', new zip.BlobReader(htmlBlob))
  1656. zipWriter.add('index.txt', new zip.TextReader(document.querySelector('.texts').innerText))
  1657. }
  1658. /**
  1659. * @description 解析图片 [src]
  1660. * @author Mr.Fang
  1661. * @time 2024年2月2日
  1662. */
  1663. const parseImage = async () => {
  1664. const images = u.queryAll(select);
  1665. if (!images.length) {
  1666. u.log('------>parseImage 暂无数据');
  1667. return;
  1668. }
  1669. const listData = [];
  1670. images.forEach((item) => {
  1671. let src = u.attr(item, 'data-src') || item.src;
  1672. if (src.includes('http:') && location.protocol === 'https') {
  1673. src = src.replace("http:", "https:")
  1674. } else if (src.startsWith("//")) {
  1675. src = "https:" + src;
  1676. }
  1677. if (src) {
  1678. const page = u.attr(item, 'data-page') || u.attr(item.parentElement, 'data-id');
  1679. if (host.includes(domain.docin)) {
  1680. const curr = Number(item.parentElement.id.split('_').pop());
  1681. if (curr >= startPageNo + 1) {
  1682. listData.push({
  1683. page,
  1684. src
  1685. })
  1686. }
  1687. } else {
  1688. listData.push({
  1689. page,
  1690. src
  1691. })
  1692. }
  1693. }
  1694. })
  1695. const store = JSON.stringify(listData);
  1696. u.logt(listData)
  1697. u.log('size:' + images.length);
  1698. GM_setValue('listData', store);
  1699. localStorage.setItem('listData', store)
  1700. u.log('--------->downimg');
  1701. localStorage.removeItem('current')
  1702. downimg()
  1703. }
  1704. /**
  1705. * @description 下载图片
  1706. * @author Mr.Fang
  1707. * @time 2024年2月2日
  1708. */
  1709. const downimg = async () => {
  1710. const images = JSON.parse(GM_getValue('listData'));
  1711. const length = images.length;
  1712. localStorage.setItem('length', length);
  1713. let current = Number(localStorage.getItem("current")) || 0;
  1714. u.log('downimg----------->current:' + current)
  1715. for (let index = current; index < length; index++) {
  1716. const image = images[index];
  1717. const src = image.src;
  1718. if (src.includes(host)) { // 当前域
  1719. const {
  1720. uint8,
  1721. blob,
  1722. width,
  1723. height
  1724. } = await MF_ImageToBase64(src);
  1725. if (fileType.includes('ppt') || width > height) {
  1726. doc.addPage([width * pdf_ratio, height * pdf_ratio], 'l');
  1727. doc.addImage(uint8, 'JPEG', 0, 0, width * pdf_ratio, height * pdf_ratio, index,
  1728. 'FAST')
  1729. } else {
  1730. doc.addPage();
  1731. doc.addImage(uint8, 'JPEG', 0, 0, pdf_w, pdf_h, index, 'FAST')
  1732. }
  1733. if (index === 1) {
  1734. doc.deletePage(1);
  1735. }
  1736. zipWriter.add(index + ".png", new zip.BlobReader(blob));
  1737. current = index;
  1738. await u.preview(current, length);
  1739. } else {
  1740. const url = new URL(src);
  1741. const attrId = url.host.replaceAll(".", "")
  1742. const query = document.getElementById('#' + attrId);
  1743. if (query) { // 框架是否存在
  1744. parentMessage(src, "#" + attrId);
  1745. } else {
  1746. const el = u.createEl("#" + attrId, 'iframe');
  1747. el.src = url.origin + '?custom=true';
  1748. el.style.visibility = "hidden";
  1749. document.body.append(el);
  1750. }
  1751. localStorage.setItem('current', index + "");
  1752. u.preview(current, length);
  1753. break;
  1754. }
  1755. }
  1756. // 非当前域下载文件下标会多加一个数值
  1757. if (localStorage.getItem("current")) {
  1758. current -= 1;
  1759. }
  1760. console.log('current', current);
  1761. if (current === length - 1) {
  1762. conditionDownload();
  1763. }
  1764. }
  1765. /**
  1766. * 图片下载
  1767. */
  1768. const downloadImage = async () => {
  1769. const images = [...u.queryAll(select)];
  1770. const len = images.length;
  1771. for (let i = 0; i < len; i++) {
  1772. const image = images[i]
  1773. const canvas = await MF_ImageToCanvas(image);
  1774. const {
  1775. blob,
  1776. width,
  1777. height
  1778. } = await MF_CanvasToBase64(canvas);
  1779. saveImageAndPDF(canvas, blob, i, width, height, false);
  1780. u.preview(i, len);
  1781. }
  1782. }
  1783. const downloadElement = async () => {
  1784. const nodes = u.queryAll(select + ' .fwr-page-tile');
  1785. const len = nodes.length;
  1786. for (let i = 0; i < len; i++) {
  1787. const node = nodes[i]
  1788. const {
  1789. blob,
  1790. canvas
  1791. } = await MF_ImageStitchingToCanvas(node);
  1792. saveImageAndPDF(canvas, blob, i, canvas.width, canvas.height, true);
  1793. u.preview(i, len);
  1794. }
  1795. }
  1796. const MF_ImageToCanvas = (image) => {
  1797. return new Promise((resolve, reject) => {
  1798. const canvas = u.createEl('', 'canvas');
  1799. const {
  1800. naturalWidth: width,
  1801. naturalHeight: height
  1802. } = image;
  1803. canvas.width = width;
  1804. canvas.height = height;
  1805. let ctx = canvas.getContext('2d');
  1806. ctx.fillStyle = '#FFFFFF';
  1807. ctx.fillRect(0, 0, width, height);
  1808. ctx.drawImage(image, 0, 0, width, height);
  1809. resolve(canvas);
  1810. })
  1811. }
  1812. /**
  1813. * bg pdf 下载
  1814. */
  1815. const downloadGBImage = async () => {
  1816. const els = u.queryAll(select);
  1817. const length = els.length;
  1818. for (let i = 0; i < length; i++) {
  1819. let item = els[i];
  1820. const {
  1821. blob,
  1822. canvas
  1823. } = await MF_ImagePositionToBase64(item);
  1824. if (!blob) {
  1825. continue;
  1826. }
  1827. saveImageAndPDF(canvas, blob, i, canvas.width, canvas.height, true)
  1828. await u.preview(i + 1, length);
  1829. }
  1830. // 非当前域下载文件下标会多加一个数值
  1831. conditionDownload();
  1832. }
  1833. /**
  1834. * @param {String} url 请求地址
  1835. */
  1836. const requestGet = (url) => {
  1837. return new Promise((resolve, reject) => {
  1838. var xhr = new XMLHttpRequest();
  1839. xhr.open("GET", url, true);
  1840. // xhr.setRequestHeader("Content-Type", "application/json");
  1841. xhr.onreadystatechange = function() {
  1842. if (xhr.readyState === 4) {
  1843. if (xhr.status === 206 || xhr.status === 200) {
  1844. try {
  1845. let responseText = xhr.responseText;
  1846. let result = responseText.substring(responseText.indexOf('\(') + 1,
  1847. responseText.length - 1);
  1848. u.log(result)
  1849. resolve(JSON.parse(result));
  1850. } catch (e) {
  1851. reject(e);
  1852. }
  1853. } else {
  1854. reject(new Error(`HTTP status code ${xhr.status}`));
  1855. }
  1856. }
  1857. };
  1858. xhr.onerror = function() {
  1859. reject(new Error("Network error"));
  1860. };
  1861. xhr.send();
  1862. });
  1863. }
  1864. /**
  1865. * 复制到剪切板
  1866. * @param text
  1867. */
  1868. const copyToClipboard = (text) => {
  1869. var input = document.createElement("textarea");
  1870. input.value = text;
  1871. document.body.appendChild(input);
  1872. input.select();
  1873. document.execCommand("copy");
  1874. document.body.removeChild(input);
  1875. }
  1876. /**
  1877. * @description 通过接口获取文本内容
  1878. * @author Mr.Fang
  1879. * @time 2024年2月20日
  1880. */
  1881. const fullText = async () => {
  1882. let text = '';
  1883. if (host.includes(domain.wenku)) {
  1884. const pageData = JSON.parse(localStorage.getItem('pageData'));
  1885. if (pageData) {
  1886. for (var i = 0; i < pageData.length; i++) {
  1887. let url = pageData[i].src;
  1888. let resultData = await requestGet(url);
  1889. if (resultData instanceof Array) {
  1890. text += resultData[0].parags[0].c;
  1891. } else {
  1892. resultData.body.forEach(item => {
  1893. if (typeof item.c === "string") {
  1894. text += item.c;
  1895. }
  1896. })
  1897. }
  1898. }
  1899. } else {
  1900. text = u.query('.ql-editor').innerText;
  1901. }
  1902. } else if (host.includes(domain.mbalib) ||
  1903. host.includes(domain.feishu) ||
  1904. host.includes(domain.cebpubservice) ||
  1905. host.includes(domain.jtysbz)) {
  1906. const texts = JSON.parse(localStorage.getItem("SP_text")) || []
  1907. for (let i = 0; i < texts.length; i++) {
  1908. let t = texts[i];
  1909. text += `\n\n====第${i+1}页====\n\n` + t;
  1910. }
  1911. localStorage.removeItem('SP_text')
  1912. } else if (host.includes(domain.doc88)) {
  1913. // const texts = Core.api._VM;
  1914. const texts = Core.api._bf;
  1915. if (!texts) {
  1916. alert('没有文本内容')
  1917. return
  1918. }
  1919. for (let i = 0; i < texts.length; i++) {
  1920. text += `\n\n====第${i+1}页====\n\n` + texts[i];
  1921. }
  1922. } else if (host.includes(domain.taodocs)) {
  1923. const texts = u.queryAll('#canvas .textLayer');
  1924. for (let i = 0; i < texts.length; i++) {
  1925. let t = texts[i];
  1926. text += `\n\n====第${i+1}页====\n\n`;
  1927. text += t.innerText;
  1928. }
  1929. }
  1930. MF_ExportTxt(text, `${title}.txt`);
  1931. }
  1932. /**
  1933. * @description 下载压缩包,包含图片
  1934. * @author Mr.Fang
  1935. * @time 2024年2月2日
  1936. */
  1937. const downzip = () => {
  1938. zipWriter.close().then(blob => {
  1939. GM_download(URL.createObjectURL(blob), `${title}.zip`);
  1940. URL.revokeObjectURL(blob);
  1941. }).catch(error => {
  1942. console.error(error);
  1943. });
  1944. }
  1945. /**
  1946. * @description 下载 PDF
  1947. * @author Mr.Fang
  1948. * @time 2024年2月2日
  1949. */
  1950. const downpdf = () => {
  1951. // 下载 PDF 文件
  1952. doc.save(`${title}.pdf`, {
  1953. returnPromise: true
  1954. });
  1955. }
  1956. /**
  1957. * @description 下载 txt 文本
  1958. * @author Mr.Fang
  1959. * @time 2024年2月2日
  1960. */
  1961. const downtxt = () => {
  1962. const images = JSON.parse(GM_getValue('listData'));
  1963. const text = images.map(item => {
  1964. return item.src
  1965. }).join("\n");
  1966. MF_ExportTxt(text, `${title}.txt`);
  1967. }
  1968. /**
  1969. * @description 递归加载子节点,获取子节点背景,img 属性值
  1970. * @author Mr.Fang
  1971. * @time 2024年1月20日18:05:49
  1972. * @param children
  1973. * @returns {*[]}
  1974. */
  1975. const MF_RecursiveParsingImages = (children) => {
  1976. const list = [];
  1977. if (children.childNodes.length) {
  1978. children.childNodes.forEach(item => {
  1979. if (item || item instanceof HTMLImageElement) {
  1980. if (item instanceof HTMLImageElement) { // 图片
  1981. let src = item.src;
  1982. list.push(src);
  1983. } else if (item.style) {
  1984. let bgi = item.style.backgroundImage;
  1985. if (bgi && bgi !== 'initial' && bgi.includes('url')) {
  1986. let src = bgi.substring(bgi.indexOf("\"") + 1, bgi.lastIndexOf(
  1987. "\""));
  1988. src = src.indexOf("/") === 0 ? src : "/" + src;
  1989. list.push(origin + src);
  1990. }
  1991. }
  1992. if (item.childNodes.length) {
  1993. const images = MF_RecursiveParsingImages(item);
  1994. list.push(...images);
  1995. }
  1996. }
  1997. })
  1998. }
  1999. return list;
  2000. }
  2001. /**
  2002. * @description 获取文件后缀名
  2003. * @author Mr.Fang
  2004. * @time 2024年6月17日16:31:05
  2005. * @param {name} data 文件名
  2006. * @returns {String} suffix 后缀 ,默认 pdf
  2007. */
  2008. const getFileNameSuffix = (name) => {
  2009. const last = name.lastIndexOf(".");
  2010. return last > 0 ? name.substring(last + 1).toLocaleLowerCase() : 'pdf';
  2011. };
  2012. /**
  2013. * @description 导出 txt 文件
  2014. * @author Mr.Fang
  2015. * @time 2024年1月20日18:05:49
  2016. * @param {Object} data 数据
  2017. * @param {Object} filename 文件名
  2018. */
  2019. const MF_ExportTxt = (data, filename) => {
  2020. const csvContent = "data:text/txt;charset=utf-8," + data;
  2021. const encodedUri = encodeURI(csvContent);
  2022. const link = document.createElement("a");
  2023. link.setAttribute("href", encodedUri);
  2024. link.setAttribute("download", filename);
  2025. // 点击链接以下载文件
  2026. document.body.appendChild(link);
  2027. link.click();
  2028. document.body.removeChild(link);
  2029. }
  2030. /**
  2031. * @description 加载图片
  2032. * @author Mr.Fang
  2033. * @time 2024年1月20日18:05:49
  2034. * @param src 图片地址
  2035. * @returns {Promise<unknown>}
  2036. */
  2037. const MF_ImageToBase64 = (src) => {
  2038. return new Promise((resolve, reject) => {
  2039. // 1、创建 Image 对象
  2040. const image = new Image();
  2041. // 2、onload 加载成功触发
  2042. image.onload = function() {
  2043. try {
  2044. let canvas = u.createEl('', 'canvas');
  2045. const {
  2046. naturalWidth: width,
  2047. naturalHeight: height
  2048. } = image;
  2049. canvas.width = width;
  2050. canvas.height = height;
  2051. let ctx = canvas.getContext('2d');
  2052. ctx.fillStyle = '#FFFFFF';
  2053. ctx.fillRect(0, 0, width, height);
  2054. ctx.drawImage(image, 0, 0, width, height);
  2055. canvas.toBlob(async blob => {
  2056. // canvas 转 blob 对象
  2057. // blob 转 uint8 、PDF 需要 uint8 对象
  2058. const uint8 = await MF_BlobToUint8Array(blob)
  2059. resolve({
  2060. uint8,
  2061. blob,
  2062. width,
  2063. height
  2064. });
  2065. },
  2066. "image/png",
  2067. 1, );
  2068. } catch (e) {
  2069. reject(e);
  2070. }
  2071. }
  2072. image.onerror = reject;
  2073. image.src = src;
  2074. })
  2075. }
  2076. /**
  2077. * @description 基于背景图片定位,转画布
  2078. * @author Mr.Fang
  2079. * @time 2024年3月13日
  2080. * @param src 图片地址
  2081. * @returns {Promise<unknown>}
  2082. */
  2083. const MF_ImagePositionToBase64 = (el) => {
  2084. const base_gb = "http://c.gb688.cn/bzgk/gb/";
  2085. const style = el.style;
  2086. const cw = Number(style.width.replace('px', ''));
  2087. const ch = Number(style.height.replace('px', ''));
  2088. // 所有子节点
  2089. const childrens = el.children;
  2090. // 背景图片地址处理
  2091. if (childrens.length < 2) {
  2092. return new Promise((resolve, reject) => {
  2093. resolve({
  2094. blob: null
  2095. })
  2096. })
  2097. }
  2098. const imageUrl = childrens[0].style.backgroundImage;
  2099. const fullUrl = base_gb + imageUrl.substring(5, imageUrl.length - 2);
  2100. if (!imageUrl) {
  2101. return new Promise((resolve, reject) => {
  2102. resolve({
  2103. blob: null
  2104. })
  2105. })
  2106. }
  2107. return new Promise((resolve, reject) => {
  2108. // 1、创建 Image 对象
  2109. const image = new Image();
  2110. // 2、onload 加载成功触发
  2111. image.onload = function() {
  2112. try {
  2113. let canvas = u.createEl('', 'canvas');
  2114. canvas.width = cw;
  2115. canvas.height = ch;
  2116. // 获取上下文对象
  2117. const ctx = canvas.getContext('2d');
  2118. ctx.fillStyle = "#fff";
  2119. ctx.fillRect(0, 0, canvas.width, canvas.height);
  2120. for (var i = 0; i < childrens.length; i++) {
  2121. const child = childrens[i];
  2122. const pos = child.style.backgroundPosition.split(' ');
  2123. const coord = child.className.split('-');
  2124. const dx = Number(coord[1]);
  2125. const dy = Number(coord[2]);
  2126. const sx = Math.abs(pos[0].replace('px', ''));
  2127. const sy = Math.abs(pos[1].replace('px', ''));
  2128. const rect = child.getBoundingClientRect();
  2129. const {
  2130. width: sw,
  2131. height: sh
  2132. } = rect;
  2133. ctx.drawImage(image, sx, sy, sw, sh, dx * sw, dy * sh, sw, sh);
  2134. if (i === childrens.length - 1) {
  2135. // 转 base64 输出
  2136. canvas.toBlob(
  2137. (blob) => {
  2138. resolve({
  2139. blob,
  2140. canvas
  2141. });
  2142. },
  2143. "image/png",
  2144. 1,
  2145. );
  2146. }
  2147. }
  2148. } catch (e) {
  2149. reject(e);
  2150. }
  2151. }
  2152. image.onerror = reject;
  2153. image.src = fullUrl;
  2154. })
  2155. }
  2156. const MF_ImageStitchingToCanvas = (node) => {
  2157. return new Promise((resolve, reject) => {
  2158. try {
  2159. // 获取最后一个分辨率 / tiles-layer-125 分辨率/ div/ 行 div [img]
  2160. const children = node.lastElementChild.children;
  2161. const firstNode = children[0];
  2162. // 计算画布宽度
  2163. const cwidth = [...firstNode.querySelectorAll('img')].reduce((start, item) => start +
  2164. item.width, 0);
  2165. const cheight = children.length * firstNode.querySelector('img').height;
  2166. const canvas = u.createEl('', 'canvas');
  2167. canvas.width = cwidth;
  2168. canvas.height = cheight;
  2169. // 获取上下文对象
  2170. const ctx = canvas.getContext('2d');
  2171. ctx.fillStyle = "#fff";
  2172. ctx.fillRect(0, 0, canvas.width, canvas.height);
  2173. // 拼接
  2174. for (let i = 0; i < children.length; i++) {
  2175. const chils = [...children[i].querySelectorAll('img')];
  2176. let iw = 0;
  2177. for (let j = 0; j < chils.length; j++) {
  2178. const {
  2179. width,
  2180. height
  2181. } = chils[j];
  2182. ctx.drawImage(chils[j], iw, i * height, width, height);
  2183. iw += width
  2184. }
  2185. }
  2186. canvas.toBlob(
  2187. (blob) => {
  2188. resolve({
  2189. blob,
  2190. canvas,
  2191. });
  2192. },
  2193. "image/png",
  2194. 1,
  2195. );
  2196. } catch (e) {
  2197. //TODO handle the exception
  2198. reject(e)
  2199. }
  2200. })
  2201. }
  2202. /**
  2203. * @description 图片拼接转 blob
  2204. * @author Mr.Fang
  2205. * @time 2024年6月5日
  2206. * @param el 节点对象
  2207. * @returns {Promise<blob>}
  2208. */
  2209. const MF_ImageJoinToBlob = (el) => {
  2210. return new Promise((resolve, reject) => {
  2211. const children = el.children;
  2212. const {
  2213. naturalWidth,
  2214. naturalHeight
  2215. } = children[0];
  2216. // 1、创建画布
  2217. let canvas = u.createEl('', 'canvas');
  2218. canvas.width = naturalWidth * 6;
  2219. canvas.height = naturalHeight;
  2220. const ctx = canvas.getContext('2d');
  2221. ctx.fillStyle = "#fff";
  2222. ctx.fillRect(0, 0, canvas.width, canvas.height);
  2223. // 2、获取所有图片节点
  2224. const listData = []
  2225. for (var i = 0; i < children.length; i++) {
  2226. const img = children[i];
  2227. const left = img.style.left.replace('px', '')
  2228. listData.push({
  2229. index: i,
  2230. left: Number(left)
  2231. })
  2232. }
  2233. listData.sort((a, b) => a.left - b.left);
  2234. // 3、遍历绘制画布
  2235. for (var i = 0; i < listData.length; i++) {
  2236. const img = children[listData[i].index];
  2237. ctx.drawImage(img, i * naturalWidth, 0, naturalWidth, naturalHeight);
  2238. }
  2239. // 4、导出
  2240. canvas.toBlob(
  2241. (blob) => {
  2242. resolve({
  2243. blob,
  2244. canvas,
  2245. });
  2246. },
  2247. "image/png",
  2248. 1,
  2249. );
  2250. })
  2251. }
  2252. /**
  2253. * @description 将 blob 对象转 uint8Array
  2254. * @author Mr.Fang
  2255. * @time 2024年5月27日
  2256. * @param {Object} blob 图片对象
  2257. * @returns {Promise<Uint8Array>}
  2258. */
  2259. const MF_BlobToUint8Array = (blob) => {
  2260. return new Promise((resolve, reject) => {
  2261. const fileReader = new FileReader();
  2262. fileReader.onload = function() {
  2263. resolve(new Uint8Array(this.result));
  2264. };
  2265. fileReader.onerror = function(error) {
  2266. reject(error);
  2267. };
  2268. fileReader.readAsArrayBuffer(blob);
  2269. });
  2270. }
  2271. /**
  2272. * @description 画布输出 blob 对象
  2273. * @author Mr.Fang
  2274. * @time 2024年1月20日18:05:49
  2275. * @param src 图片地址
  2276. * @returns {Promise<Object>}
  2277. */
  2278. const MF_CanvasToBase64 = (canvas) => {
  2279. return new Promise((resolve, reject) => {
  2280. const {
  2281. width,
  2282. height
  2283. } = canvas;
  2284. canvas.toBlob(
  2285. (blob) => {
  2286. resolve({
  2287. blob,
  2288. width,
  2289. height
  2290. });
  2291. },
  2292. "image/png",
  2293. 1,
  2294. );
  2295. })
  2296. }
  2297. })();