怠惰小说下载器

通用网站内容抓取工具,可批量抓取任意站点的小说、论坛内容等并保存为TXT文档

当前为 2023-11-03 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name DownloadAllContent
  3. // @name:zh-CN 怠惰小说下载器
  4. // @name:zh-TW 怠惰小説下載器
  5. // @name:ja 怠惰者小説ダウンロードツール
  6. // @namespace hoothin
  7. // @version 2.7.5.5
  8. // @description Fetch and download main textual content from the current page, provide special support for novels
  9. // @description:zh-CN 通用网站内容抓取工具,可批量抓取任意站点的小说、论坛内容等并保存为TXT文档
  10. // @description:zh-TW 通用網站內容抓取工具,可批量抓取任意站點的小說、論壇內容等並保存為TXT文檔
  11. // @description:ja ユニバーサルサイトコンテンツクロールツール、クロール、フォーラム内容など
  12. // @author hoothin
  13. // @match http://*/*
  14. // @match https://*/*
  15. // @match ftp://*/*
  16. // @grant GM_xmlhttpRequest
  17. // @grant GM_registerMenuCommand
  18. // @grant GM_setValue
  19. // @grant GM_getValue
  20. // @grant GM_openInTab
  21. // @grant GM_setClipboard
  22. // @grant GM_addStyle
  23. // @grant unsafeWindow
  24. // @license MIT License
  25. // @compatible chrome
  26. // @compatible firefox
  27. // @compatible opera 未测试
  28. // @compatible safari 未测试
  29. // @contributionURL https://ko-fi.com/hoothin
  30. // @contributionAmount 1
  31. // ==/UserScript==
  32.  
  33. if (window.top != window.self) {
  34. try {
  35. if (window.self.innerWidth < 250 || window.self.innerHeight < 250) {
  36. return;
  37. }
  38. } catch(e) {
  39. return;
  40. }
  41. }
  42.  
  43. (function (global, factory) {
  44. if (typeof define === "function" && define.amd) {
  45. define([], factory);
  46. } else if (typeof exports !== "undefined") {
  47. factory();
  48. } else {
  49. var mod = {
  50. exports: {}
  51. };
  52. factory();
  53. global.FileSaver = mod.exports;
  54. }
  55. })(this, function () {
  56. "use strict";
  57.  
  58. /*
  59. * FileSaver.js
  60. * A saveAs() FileSaver implementation.
  61. *
  62. * By Eli Grey, http://eligrey.com
  63. *
  64. * License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)
  65. * source : http://purl.eligrey.com/github/FileSaver.js
  66. */
  67. var _global = typeof window === 'object' && window.window === window ? window : typeof self === 'object' && self.self === self ? self : typeof global === 'object' && global.global === global ? global : void 0;
  68.  
  69. function bom(blob, opts) {
  70. if (typeof opts === 'undefined') opts = {
  71. autoBom: false
  72. };else if (typeof opts !== 'object') {
  73. console.warn('Deprecated: Expected third argument to be a object');
  74. opts = {
  75. autoBom: !opts
  76. };
  77. }
  78.  
  79. if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
  80. return new Blob([String.fromCharCode(0xFEFF), blob], {
  81. type: blob.type
  82. });
  83. }
  84.  
  85. return blob;
  86. }
  87.  
  88. function download(url, name, opts) {
  89. var xhr = new XMLHttpRequest();
  90. xhr.open('GET', url);
  91. xhr.responseType = 'blob';
  92.  
  93. xhr.onload = function () {
  94. saveAs(xhr.response, name, opts);
  95. };
  96.  
  97. xhr.onerror = function () {
  98. console.error('could not download file');
  99. };
  100.  
  101. xhr.send();
  102. }
  103.  
  104. function corsEnabled(url) {
  105. var xhr = new XMLHttpRequest();
  106.  
  107. xhr.open('HEAD', url, false);
  108.  
  109. try {
  110. xhr.send();
  111. } catch (e) {}
  112.  
  113. return xhr.status >= 200 && xhr.status <= 299;
  114. }
  115.  
  116.  
  117. function click(node) {
  118. try {
  119. node.dispatchEvent(new MouseEvent('click'));
  120. } catch (e) {
  121. var evt = document.createEvent('MouseEvents');
  122. evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null);
  123. node.dispatchEvent(evt);
  124. }
  125. }
  126.  
  127.  
  128. var isMacOSWebView = _global.navigator && /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent);
  129. var saveAs = _global.saveAs || (
  130. typeof window !== 'object' || window !== _global ? function saveAs() {}
  131.  
  132. : 'download' in HTMLAnchorElement.prototype && !isMacOSWebView ? function saveAs(blob, name, opts) {
  133. var URL = _global.URL || _global.webkitURL;
  134. var a = document.createElement('a');
  135. name = name || blob.name || 'download';
  136. a.download = name;
  137. a.rel = 'noopener';
  138.  
  139. if (typeof blob === 'string') {
  140. a.href = blob;
  141.  
  142. if (a.origin !== location.origin) {
  143. corsEnabled(a.href) ? download(blob, name, opts) : click(a, a.target = '_blank');
  144. } else {
  145. click(a);
  146. }
  147. } else {
  148. a.href = URL.createObjectURL(blob);
  149. setTimeout(function () {
  150. URL.revokeObjectURL(a.href);
  151. }, 4E4);
  152.  
  153. setTimeout(function () {
  154. click(a);
  155. }, 0);
  156. }
  157. }
  158. : 'msSaveOrOpenBlob' in navigator ? function saveAs(blob, name, opts) {
  159. name = name || blob.name || 'download';
  160.  
  161. if (typeof blob === 'string') {
  162. if (corsEnabled(blob)) {
  163. download(blob, name, opts);
  164. } else {
  165. var a = document.createElement('a');
  166. a.href = blob;
  167. a.target = '_blank';
  168. setTimeout(function () {
  169. click(a);
  170. });
  171. }
  172. } else {
  173. navigator.msSaveOrOpenBlob(bom(blob, opts), name);
  174. }
  175. }
  176. : function saveAs(blob, name, opts, popup) {
  177. popup = popup || open('', '_blank');
  178.  
  179. if (popup) {
  180. popup.document.title = popup.document.body.innerText = 'downloading...';
  181. }
  182.  
  183. if (typeof blob === 'string') return download(blob, name, opts);
  184. var force = blob.type === 'application/octet-stream';
  185.  
  186. var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari;
  187.  
  188. var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent);
  189.  
  190. if ((isChromeIOS || force && isSafari || isMacOSWebView) && typeof FileReader !== 'undefined') {
  191. var reader = new FileReader();
  192.  
  193. reader.onloadend = function () {
  194. var url = reader.result;
  195. url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;');
  196. if (popup) popup.location.href = url;else location = url;
  197. popup = null;
  198. };
  199.  
  200. reader.readAsDataURL(blob);
  201. } else {
  202. var URL = _global.URL || _global.webkitURL;
  203. var url = URL.createObjectURL(blob);
  204. if (popup) popup.location = url;else location.href = url;
  205. popup = null;
  206.  
  207. setTimeout(function () {
  208. URL.revokeObjectURL(url);
  209. }, 4E4);
  210. }
  211. });
  212. _global.saveAs = saveAs.saveAs = saveAs;
  213.  
  214. if (typeof module !== 'undefined') {
  215. module.exports = saveAs;
  216. }
  217. });
  218.  
  219. (function() {
  220. 'use strict';
  221. var indexReg=/PART\b|^Prologue|Chapter\s*[\-_]?\d+|分卷|^序$|^序\s*言|^序\s*章|^前\s*言|^附\s*[录錄]|^引\s*[言子]|^摘\s*要|^[楔契]\s*子|^后\s*记|^後\s*記|^附\s*言|^结\s*语|^結\s*語|^尾\s*[声聲]|^最終話|^最终话|^番\s*外|^\d+[\s\.、,,)\-_::][^\d#\.]+$|^(\d|\s)*[第(]?\s*[\d〇零一二三四五六七八九十百千万萬-]+\s*[、)章节節回卷折篇幕集话話]/i;
  222. var innerNextPage=/^\s*(下一[页頁张張]|next\s*page|次のページ)/i;
  223. var lang = navigator.appName=="Netscape"?navigator.language:navigator.userLanguage;
  224. var i18n={};
  225. var rCats=[];
  226. var processFunc;
  227. var win=(typeof unsafeWindow=='undefined'? window : unsafeWindow);
  228. switch (lang){
  229. case "zh-CN":
  230. case "zh-SG":
  231. i18n={
  232. fetch:"开始下载小说【Ctrl+F9】",
  233. info:"本文是使用怠惰小说下载器(DownloadAllContent)下载的",
  234. error:"该段内容获取失败",
  235. downloading:"已下载完成 %s 段,剩余 %s 段<br>正在下载 %s",
  236. complete:"已全部下载完成,共 %s 段",
  237. del:"设置文本干扰码的CSS选择器",
  238. custom:"自定规则下载",
  239. customInfo:"输入网址或者章节CSS选择器",
  240. reSort:"按标题名重新排序章节",
  241. reSortUrl:"按网址重新排序章节",
  242. setting:"选项参数设置",
  243. searchRule:"搜索网站规则",
  244. abort:"跳过此章",
  245. save:"保存当前",
  246. saveAsMd:"存为 Markdown",
  247. downThreadNum:"设置同时下载的线程数",
  248. customTitle:"自定义章节标题,输入内页文字对应选择器",
  249. reSortDefault:"默认按页面中位置排序章节",
  250. reverse:"反转章节排序",
  251. saveBtn:"保存设置",
  252. saveOk:"保存成功",
  253. nextPage:"嗅探章节内分页",
  254. nextPageReg:"自定义分页正则",
  255. retainImage:"保留正文中图片的网址",
  256. minTxtLength:"当检测到的正文字数小于此数,则尝试重新抓取",
  257. showFilterList:"下载前显示章节筛选排序窗口",
  258. ok:"确定",
  259. close:"关闭",
  260. dacSortByPos:"按页内位置排序",
  261. dacSortByUrl:"按网址排序",
  262. dacSortByName:"按章节名排序",
  263. dacUseIframe:"使用 iframe 后台加载内容(慢速)",
  264. dacSetCustomRule:"修改规则",
  265. dacAddUrl:"添加章节",
  266. dacStartDownload:"下载选中"
  267. };
  268. break;
  269. case "zh-TW":
  270. case "zh-HK":
  271. i18n={
  272. fetch:"開始下載小說【Ctrl+F9】",
  273. info:"本文是使用怠惰小說下載器(DownloadAllContent)下載的",
  274. error:"該段內容獲取失敗",
  275. downloading:"已下載完成 %s 段,剩餘 %s 段<br>正在下載 %s",
  276. complete:"已全部下載完成,共 %s 段",
  277. del:"設置文本干擾碼的CSS選擇器",
  278. custom:"自訂規則下載",
  279. customInfo:"輸入網址或者章節CSS選擇器",
  280. reSort:"按標題名重新排序章節",
  281. reSortUrl:"按網址重新排序章節",
  282. setting:"選項參數設定",
  283. searchRule:"搜尋網站規則",
  284. abort:"跳過此章",
  285. save:"保存當前",
  286. saveAsMd:"存爲 Markdown",
  287. downThreadNum:"設置同時下載的綫程數",
  288. customTitle:"自訂章節標題,輸入內頁文字對應選擇器",
  289. reSortDefault:"預設依頁面中位置排序章節",
  290. reverse:"反轉章節排序",
  291. saveBtn:"儲存設定",
  292. saveOk:"儲存成功",
  293. nextPage:"嗅探章節內分頁",
  294. nextPageReg:"自訂分頁正規",
  295. retainImage:"保留內文圖片的網址",
  296. minTxtLength:"當偵測到的正文字數小於此數,則嘗試重新抓取",
  297. showFilterList:"下載前顯示章節篩選排序視窗",
  298. ok:"確定",
  299. close:"關閉",
  300. dacSortByPos:"依頁內位置排序",
  301. dacSortByUrl:"依網址排序",
  302. dacSortByName:"依章節名排序",
  303. dacUseIframe:"使用 iframe 背景載入內容(慢速)",
  304. dacSetCustomRule:"修改規則",
  305. dacAddUrl:"新增章節",
  306. dacStartDownload:"下載選取"
  307. };
  308. break;
  309. default:
  310. i18n={
  311. fetch:"Download [Ctrl+F9]",
  312. info:"The TXT is downloaded by 'DownloadAllContent'",
  313. error:"Failed in downloading current chapter",
  314. downloading:"%s pages are downloaded, there are still %s pages left<br>Downloading %s ......",
  315. complete:"Completed! Get %s pages in total",
  316. del:"Set css selectors for ignore",
  317. custom:"Custom to download",
  318. customInfo:"Input urls OR sss selectors for chapter links",
  319. reSort:"ReSort by title",
  320. reSortUrl:"Resort by URLs",
  321. setting:"Open Setting",
  322. searchRule:"Search rule",
  323. abort:"Abort",
  324. save:"Save",
  325. saveAsMd:"Save as Markdown",
  326. downThreadNum:"Set threadNum for download",
  327. customTitle: "Customize the chapter title, enter the selector on inner page",
  328. reSortDefault: "Default sort by position in the page",
  329. reverse:"Reverse chapter ordering",
  330. saveBtn:"Save Setting",
  331. saveOk:"Save Over",
  332. nextPage:"Check next page in chapter",
  333. nextPageReg:"Custom RegExp of next page",
  334. retainImage:"Keep the URL of image if there are images in the text",
  335. minTxtLength:"Try to crawl again when the length of content is less than this",
  336. showFilterList: "Show chapter filtering and sorting window before downloading",
  337. ok:"OK",
  338. close:"Close",
  339. dacSortByPos:"Sort by position",
  340. dacSortByUrl:"Sort by URL",
  341. dacSortByName:"Sort by name",
  342. dacUseIframe: "Use iframe to load content in the background (slow)",
  343. dacSetCustomRule:"Modify rules",
  344. dacAddUrl:"Add Chapter",
  345. dacStartDownload:"Download selected"
  346. };
  347. break;
  348. }
  349. var firefox=navigator.userAgent.toLowerCase().indexOf('firefox')!=-1,curRequests=[],useIframe=false,iframeSandbox=false,iframeInit=false;
  350. var filterListContainer,txtDownContent,txtDownWords,txtDownQuit,dacLinksCon,dacUseIframe;
  351.  
  352. const escapeHTMLPolicy = (win.trustedTypes && win.trustedTypes.createPolicy) ? win.trustedTypes.createPolicy('dac_default', {
  353. createHTML: (string, sink) => string
  354. }) : null;
  355.  
  356. function createHTML(html) {
  357. return escapeHTMLPolicy ? escapeHTMLPolicy.createHTML(html) : html;
  358. }
  359.  
  360. function str2Num(str) {
  361. str = str.replace(/^番\s*外/, "99999+").replace(/[一①Ⅰ壹]/g, "1").replace(/[二②Ⅱ贰]/g, "2").replace(/[三③Ⅲ叁]/g, "3").replace(/[四④Ⅳ肆]/g, "4").replace(/[五⑤Ⅴ伍]/g, "5").replace(/[六⑥Ⅵ陆]/g, "6").replace(/[七⑦Ⅶ柒]/g, "7").replace(/[八⑧Ⅷ捌]/g, "8").replace(/[九⑨Ⅸ玖]/g, "9").replace(/[十⑩Ⅹ拾]/g, "*10+").replace(/[百佰]/g, "*100+").replace(/[千仟]/g, "*1000+").replace(/[万萬]/g, "*10000+").replace(/\s/g, "").match(/[\d\*\+]+/);
  362. if (!str) return 0;
  363. str = str[0];
  364. let mul = str.match(/(\d*)\*(\d+)/);
  365. while(mul) {
  366. let result = parseInt(mul[1] || 1) * parseInt(mul[2]);
  367. str = str.replace(mul[0], result);
  368. mul = str.match(/(\d+)\*(\d+)/);
  369. }
  370. let plus = str.match(/(\d+)\+(\d+)/);
  371. while(plus) {
  372. let result = parseInt(plus[1]) + parseInt(plus[2]);
  373. str = str.replace(plus[0], result);
  374. plus = str.match(/(\d+)\+(\d+)/);
  375. }
  376. return parseInt(str);
  377. }
  378.  
  379. var dragOverItem, dragFrom;
  380. function createLinkItem(aEle) {
  381. let item = document.createElement("div");
  382. item.innerHTML = createHTML(`
  383. <input type="checkbox" checked>
  384. <a class="dacLink" draggable="false" target="_blank" href="${aEle.href}">${aEle.innerText || "📄"}</a>
  385. <span>🖱️</span>
  386. `);
  387. item.title = aEle.innerText;
  388. item.setAttribute("draggable", "true");
  389. item.addEventListener("dragover", e => {
  390. e.preventDefault();
  391. });
  392. item.addEventListener("dragenter", e => {
  393. if (dragOverItem) dragOverItem.style.opacity = "";
  394. item.style.opacity = 0.3;
  395. dragOverItem = item;
  396. });
  397. item.addEventListener('dragstart', e => {
  398. dragFrom = item;
  399. });
  400. item.addEventListener('drop', e => {
  401. if (!dragFrom) return;
  402. if (e.clientX < item.getBoundingClientRect().left + 142) {
  403. dacLinksCon.insertBefore(dragFrom, item);
  404. } else {
  405. if (item.nextElementSibling) {
  406. dacLinksCon.insertBefore(dragFrom, item.nextElementSibling);
  407. } else {
  408. dacLinksCon.appendChild(dragFrom);
  409. }
  410. }
  411. e.preventDefault();
  412. });
  413. dacLinksCon.appendChild(item);
  414. }
  415.  
  416. function filterList(list) {
  417. if (!GM_getValue("showFilterList")) {
  418. indexDownload(list);
  419. return;
  420. }
  421. if (filterListContainer) {
  422. filterListContainer.style.display = "";
  423. filterListContainer.classList.remove("customRule");
  424. dacLinksCon.innerHTML = createHTML("");
  425. } else {
  426. document.addEventListener('dragend', e => {
  427. if (dragOverItem) dragOverItem.style.opacity = "";
  428. }, true);
  429. filterListContainer = document.createElement("div");
  430. filterListContainer.id = "filterListContainer";
  431. filterListContainer.innerHTML = createHTML(`
  432. <div id="dacFilterBg" style="height: 100%; width: 100%; position: fixed; top: 0; z-index: 99998; opacity: 0.3; filter: alpha(opacity=30); background-color: #000;"></div>
  433. <div style="padding: 5px; box-sizing: border-box; overflow: hidden; width: 600px; height: auto; max-height: 80vh; min-height: 200px; position: fixed; left: 50%; top: 10%; margin-left: -300px; z-index: 99998; background-color: #ffffff; border: 1px solid #afb3b6; border-radius: 10px; opacity: 0.95; filter: alpha(opacity=95); box-shadow: 5px 5px 20px 0px #000;">
  434. <div class="dacCustomRule">
  435. ${i18n.custom}
  436. <textarea id="dacCustomInput"></textarea>
  437. <div class="fun">
  438. <input id="dacConfirmRule" value="${i18n.ok}" type="button"/>
  439. <input id="dacCustomClose" value="${i18n.close}" type="button"/>
  440. </div>
  441. </div>
  442. <div class="sort">
  443. <input id="dacSortByPos" value="${i18n.dacSortByPos}" type="button"/>
  444. <input id="dacSortByUrl" value="${i18n.dacSortByUrl}" type="button"/>
  445. <input id="dacSortByName" value="${i18n.dacSortByName}" type="button"/>
  446. </div>
  447. <div id="dacLinksCon" style="max-height: calc(80vh - 100px); min-height: 100px; display: grid; grid-template-columns: auto auto; width: 100%; overflow: auto; white-space: nowrap;"></div>
  448. <p style="margin: 5px; text-align: center; font-size: 14px; height: 20px;"><input id="dacUseIframe" type="checkbox"/><label for="dacUseIframe"> ${i18n.dacUseIframe}</label></p>
  449. <div class="fun">
  450. <input id="dacSetCustomRule" value="${i18n.dacSetCustomRule}" type="button"/>
  451. <input id="dacAddUrl" value="${i18n.dacAddUrl}" type="button"/>
  452. <input id="dacStartDownload" value="${i18n.dacStartDownload}" type="button"/>
  453. <input id="dacLinksClose" value="${i18n.close}" type="button"/>
  454. </div>
  455. </div>`);
  456. let dacSortByPos = filterListContainer.querySelector("#dacSortByPos");
  457. let dacSortByUrl = filterListContainer.querySelector("#dacSortByUrl");
  458. let dacSortByName = filterListContainer.querySelector("#dacSortByName");
  459. let dacSetCustomRule = filterListContainer.querySelector("#dacSetCustomRule");
  460. let dacCustomInput = filterListContainer.querySelector("#dacCustomInput");
  461. let dacConfirmRule = filterListContainer.querySelector("#dacConfirmRule");
  462. let dacCustomClose = filterListContainer.querySelector("#dacCustomClose");
  463. let dacAddUrl = filterListContainer.querySelector("#dacAddUrl");
  464. let dacStartDownload = filterListContainer.querySelector("#dacStartDownload");
  465. let dacLinksClose = filterListContainer.querySelector("#dacLinksClose");
  466. let dacFilterBg = filterListContainer.querySelector("#dacFilterBg");
  467. dacUseIframe = filterListContainer.querySelector("#dacUseIframe");
  468. dacSortByPos.onclick = e => {
  469. let linkList = [].slice.call(dacLinksCon.children);
  470. if (linkList[0].children[1].href != list[0].href) {
  471. list.reverse().forEach(a => {
  472. for (let i = 0; i < linkList.length; i++) {
  473. let link = linkList[i];
  474. if (link.children[1].href == a.href) {
  475. dacLinksCon.insertBefore(link, dacLinksCon.children[0]);
  476. }
  477. }
  478. });
  479. } else {
  480. list.forEach(a => {
  481. for (let i = 0; i < linkList.length; i++) {
  482. let link = linkList[i];
  483. if (link.children[1].href == a.href) {
  484. dacLinksCon.insertBefore(link, dacLinksCon.children[0]);
  485. }
  486. }
  487. });
  488. }
  489. };
  490. dacSortByUrl.onclick = e => {
  491. let linkList = [].slice.call(dacLinksCon.children);
  492. linkList.sort((a, b) => {
  493. const nameA = a.children[1].href.toUpperCase();
  494. const nameB = b.children[1].href.toUpperCase();
  495. if (nameA < nameB) {
  496. return -1;
  497. }
  498. if (nameA > nameB) {
  499. return 1;
  500. }
  501. return 0;
  502. });
  503. if (linkList[0] == dacLinksCon.children[0]) {
  504. linkList = linkList.reverse();
  505. }
  506. linkList.forEach(link => {
  507. dacLinksCon.appendChild(link);
  508. });
  509. };
  510. dacSortByName.onclick = e => {
  511. let linkList = [].slice.call(dacLinksCon.children);
  512. linkList.sort((a, b) => {
  513. return str2Num(a.innerText) - str2Num(b.innerText);
  514. });
  515. if (linkList[0] == dacLinksCon.children[0]) {
  516. linkList = linkList.reverse();
  517. }
  518. linkList.forEach(link => {
  519. dacLinksCon.appendChild(link);
  520. });
  521. };
  522. dacSetCustomRule.onclick = e => {
  523. filterListContainer.classList.add("customRule");
  524. dacCustomInput.value = GM_getValue("DACrules_" + document.domain) || "";
  525. };
  526. dacConfirmRule.onclick = e => {
  527. if (dacCustomInput.value) {
  528. customDown(dacCustomInput.value);
  529. }
  530. };
  531. dacCustomClose.onclick = e => {
  532. filterListContainer.classList.remove("customRule");
  533. };
  534. dacAddUrl.onclick = e => {
  535. let addUrls = window.prompt(i18n.customInfo, "https://xxx.xxx/book-[20-99].html, https://xxx.xxx/book-[01-10].html");
  536. if (!addUrls || !/^http|^ftp/.test(addUrls)) return;
  537. let index = 1;
  538. [].forEach.call(addUrls.split(","), function(i) {
  539. var curEle;
  540. var varNum = /\[\d+\-\d+\]/.exec(i);
  541. if (varNum) {
  542. varNum = varNum[0].trim();
  543. } else {
  544. curEle = document.createElement("a");
  545. curEle.href = i;
  546. curEle.innerText = "Added Url";
  547. createLinkItem(curEle);
  548. return;
  549. }
  550. var num1 = /\[(\d+)/.exec(varNum)[1].trim();
  551. var num2 = /(\d+)\]/.exec(varNum)[1].trim();
  552. var num1Int = parseInt(num1);
  553. var num2Int = parseInt(num2);
  554. var numLen = num1.length;
  555. var needAdd = num1.charAt(0) == "0";
  556. if (num1Int >= num2Int) return;
  557. for (var j = num1Int; j <= num2Int; j++) {
  558. var urlIndex = j.toString();
  559. if (needAdd) {
  560. while(urlIndex.length < numLen) urlIndex = "0" + urlIndex;
  561. }
  562. var curUrl = i.replace(/\[\d+\-\d+\]/, urlIndex).trim();
  563. curEle = document.createElement("a");
  564. curEle.href = curUrl;
  565. curEle.innerText = "Added Url " + index++;
  566. createLinkItem(curEle);
  567. }
  568. });
  569. };
  570. dacStartDownload.onclick = e => {
  571. let linkList = [].slice.call(dacLinksCon.querySelectorAll("input:checked+.dacLink"));
  572. useIframe = !!dacUseIframe.checked;
  573. indexDownload(linkList, true);
  574. filterListContainer.style.display = "none";
  575. };
  576. dacLinksClose.onclick = e => {
  577. filterListContainer.style.display = "none";
  578. };
  579. dacFilterBg.onclick = e => {
  580. filterListContainer.style.display = "none";
  581. };
  582. let listStyle = GM_addStyle(`
  583. #filterListContainer * {
  584. font-size: 13px;
  585. float: initial;
  586. background-image: initial;
  587. }
  588. #filterListContainer.customRule .dacCustomRule {
  589. display: flex;
  590. }
  591. #filterListContainer .dacCustomRule>textarea {
  592. height: 300px;
  593. width: 100%;
  594. border: 1px #DADADA solid;
  595. background: #ededed70;
  596. margin: 5px;
  597. }
  598. #filterListContainer.customRule .dacCustomRule~* {
  599. display: none!important;
  600. }
  601. #dacLinksCon>div {
  602. padding: 5px 0;
  603. display: flex;
  604. }
  605. #dacLinksCon>div>a {
  606. max-width: 245px;
  607. display: inline-block;
  608. text-overflow: ellipsis;
  609. overflow: hidden;
  610. }
  611. #dacLinksCon>div>input {
  612. margin-right: 5px;
  613. }
  614. #filterListContainer .dacCustomRule {
  615. border-radius: 8px;
  616. font-weight: bold;
  617. font-size: 16px;
  618. outline: none;
  619. align-items: center;
  620. flex-wrap: nowrap;
  621. white-space: nowrap;
  622. flex-direction: column;
  623. display: none;
  624. }
  625. #filterListContainer input {
  626. border-width: 2px;
  627. border-style: outset;
  628. border-color: buttonface;
  629. border-image: initial;
  630. border: 1px #DADADA solid;
  631. padding: 5px;
  632. border-radius: 8px;
  633. font-weight: bold;
  634. font-size: 9pt;
  635. outline: none;
  636. cursor: pointer;
  637. line-height: initial;
  638. width: initial;
  639. min-width: initial;
  640. max-width: initial;
  641. height: initial;
  642. min-height: initial;
  643. max-height: initial;
  644. }
  645. #dacLinksCon>div:nth-of-type(4n),
  646. #dacLinksCon>div:nth-of-type(4n+1) {
  647. background: #ffffff;
  648. }
  649. #dacLinksCon>div:nth-of-type(4n+2),
  650. #dacLinksCon>div:nth-of-type(4n+3) {
  651. background: #f5f5f5;
  652. }
  653. #filterListContainer .fun,#filterListContainer .sort {
  654. display: flex;
  655. justify-content: space-around;
  656. flex-wrap: nowrap;
  657. width: 100%;
  658. height: 28px;
  659. }
  660. #filterListContainer input[type=button]:hover {
  661. border: 1px #C6C6C6 solid;
  662. box-shadow: 1px 1px 1px #EAEAEA;
  663. color: #333333;
  664. background: #F7F7F7;
  665. }
  666. #filterListContainer input[type=button]:active {
  667. box-shadow: inset 1px 1px 1px #DFDFDF;
  668. }
  669. `);
  670. dacLinksCon = filterListContainer.querySelector("#dacLinksCon");
  671. let shadowContainer = document.createElement("div");
  672. document.body.appendChild(shadowContainer);
  673. let shadow = shadowContainer.attachShadow({ mode: "open" });
  674. shadow.appendChild(listStyle);
  675. shadow.appendChild(filterListContainer);
  676. }
  677. list.forEach(a => {
  678. createLinkItem(a);
  679. });
  680. dacUseIframe.checked = useIframe;
  681. }
  682.  
  683. function initTxtDownDiv(){
  684. if(txtDownContent){
  685. txtDownContent.style.display="";
  686. return;
  687. }
  688. txtDownContent=document.createElement("div");
  689. txtDownContent.id="txtDownContent";
  690. let shadowContainer = document.createElement("div");
  691. document.body.appendChild(shadowContainer);
  692. let shadow = shadowContainer.attachShadow({ mode: "open" });
  693. shadow.appendChild(txtDownContent);
  694. txtDownContent.innerHTML=createHTML(`
  695. <div style="font-size:16px;color:#333333;width:362px;height:110px;position:fixed;left:50%;top:50%;margin-top:-25px;margin-left:-191px;z-index:100000;background-color:#ffffff;border:1px solid #afb3b6;border-radius:10px;opacity:0.95;filter:alpha(opacity=95);box-shadow:5px 5px 20px 0px #000;">
  696. <div id="txtDownWords" style="position:absolute;width:275px;height: 90px;max-height: 90%;border: 1px solid #f3f1f1;padding: 8px;border-radius: 10px;overflow: auto;">
  697. Analysing......
  698. </div>
  699. <div id="txtDownQuit" style="width: 30px;height: 30px;border-radius: 30px;position:absolute;right:2px;top:2px;cursor: pointer;background-color:#ff5a5a;">
  700. <span style="height: 30px;line-height: 30px;display:block;color:#FFF;text-align:center;font-size: 12px;font-weight: bold;font-family: arial;background: initial; float: initial;">╳</span>
  701. </div>
  702. <div style="position:absolute;right:0px;bottom:2px;cursor: pointer;max-width:85px">
  703. <button id="abortRequest" style="background: #008aff;border: 0;padding: 5px;border-radius: 6px;color: white;float: right;margin: 1px;height: 25px;display:none;line-height: 16px;">${getI18n('abort')}</button>
  704. <button id="tempSaveTxt" style="background: #008aff;border: 0;padding: 5px;border-radius: 6px;color: white;float: right;margin: 1px;height: 25px;line-height: 16px;cursor: pointer;">${getI18n('save')}</button>
  705. <button id="saveAsMd" style="background: #008aff;border: 0;padding: 5px;border-radius: 6px;color: white;float: right;margin: 1px;height: 25px;line-height: 16px;cursor: pointer;overflow: hidden;" title="${getI18n('saveAsMd')}">Markdown</button>
  706. </div>
  707. </div>`);
  708. txtDownWords=txtDownContent.querySelector("#txtDownWords");
  709. txtDownQuit=txtDownContent.querySelector("#txtDownQuit");
  710. txtDownQuit.onclick=function(){
  711. txtDownContent.style.display="none";
  712. };
  713. initTempSave(txtDownContent);
  714. }
  715.  
  716. function saveContent() {
  717. if (win.downloadAllContentSaveAsZip) {
  718. win.downloadAllContentSaveAsZip(rCats, i18n.info, content => {
  719. saveAs(content, document.title + ".zip");
  720. });
  721. } else {
  722. var blob = new Blob([i18n.info + "\r\n\r\n" + document.title + "\r\n\r\n" + rCats.join("\r\n\r\n")], {type: "text/plain;charset=utf-8"});
  723. saveAs(blob, document.title + ".txt");
  724. }
  725. }
  726.  
  727. function initTempSave(txtDownContent){
  728. var tempSavebtn = txtDownContent.querySelector('#tempSaveTxt');
  729. var abortbtn = txtDownContent.querySelector('#abortRequest');
  730. var saveAsMd = txtDownContent.querySelector('#saveAsMd');
  731. tempSavebtn.onclick = function(){
  732. saveContent();
  733. console.log(curRequests);
  734. }
  735. abortbtn.onclick = function(){
  736. let curRequest = curRequests.pop();
  737. if(curRequest)curRequest[1].abort();
  738. }
  739. saveAsMd.onclick = function(){
  740. let txt = i18n.info+"\n\n---\n"+document.title+"\n===\n";
  741. rCats.forEach(cat => {
  742. cat = cat.replace("\r\n", "\n---").replace(/(\r\n|\n\r)+/g, "\n\n").replace(/[\n\r]\t+/g, "\n");
  743. txt += '\n\n'+cat;
  744. });
  745. var blob = new Blob([txt], {type: "text/plain;charset=utf-8"});
  746. saveAs(blob, document.title+".md");
  747. }
  748. }
  749.  
  750. function indexDownload(aEles, noSort){
  751. if(aEles.length<1)return;
  752. initTxtDownDiv();
  753. if(!noSort) {
  754. if(GM_getValue("contentSort")){
  755. aEles.sort((a, b) => {
  756. return str2Num(a.innerText) - str2Num(b.innerText);
  757. });
  758. }
  759. if(GM_getValue("contentSortUrl")){
  760. aEles.sort((a, b) => {
  761. const nameA = a.href.toUpperCase();
  762. const nameB = b.href.toUpperCase();
  763. if (nameA < nameB) {
  764. return -1;
  765. }
  766. if (nameA > nameB) {
  767. return 1;
  768. }
  769. return 0;
  770. });
  771. }
  772. if(GM_getValue("reverse")){
  773. aEles=aEles.reverse();
  774. }
  775. }
  776. rCats=[];
  777. var minTxtLength=GM_getValue("minTxtLength") || 100;
  778. var customTitle=GM_getValue("customTitle");
  779. var disableNextPage=!!GM_getValue("disableNextPage");
  780. var customNextPageReg=GM_getValue("nextPageReg");
  781. if (customNextPageReg) {
  782. try {
  783. innerNextPage = new RegExp(customNextPageReg);
  784. } catch(e) {
  785. console.warn(e);
  786. }
  787. }
  788. var insertSigns=[];
  789. // var j=0,rCats=[];
  790. var downIndex=0,downNum=0,downOnce=function(wait){
  791. if(downNum>=aEles.length)return;
  792. let curIndex=downIndex;
  793. let aTag=aEles[curIndex];
  794. let request=(aTag, curIndex)=>{
  795. let tryTimes=0;
  796. let validTimes=0;
  797. let requestBody={
  798. method: 'GET',
  799. url: aTag.href,
  800. headers:{
  801. referer:aTag.href,
  802. "Content-Type":"text/html;charset="+document.charset
  803. },
  804. timeout:10000,
  805. overrideMimeType:"text/html;charset="+document.charset,
  806. onload: function(result) {
  807. downIndex++;
  808. downNum++;
  809. let doc = getDocEle(result.responseText);
  810. let base = doc.querySelector("base");
  811. let nextPage = !disableNextPage && !processFunc && checkNextPage(doc, base ? base.href : aTag.href);
  812. if(nextPage){
  813. var inArr=false;
  814. for(var ai=0;ai<aEles.length;ai++){
  815. if(aEles[ai].href==nextPage.href){
  816. inArr=true;
  817. break;
  818. }
  819. }
  820. if(!inArr){
  821. nextPage.innerText=aTag.innerText+"\t>>";
  822. aEles.push(nextPage);
  823. let targetIndex = curIndex;
  824. for(let a=0;a<insertSigns.length;a++){
  825. let signs=insertSigns[a],breakSign=false;
  826. if(signs){
  827. for(let b=0;b<signs.length;b++){
  828. let sign=signs[b];
  829. if(sign==curIndex){
  830. targetIndex=a;
  831. breakSign=true;
  832. break;
  833. }
  834. }
  835. }
  836. if(breakSign)break;
  837. }
  838. let insertSign = insertSigns[targetIndex];
  839. if(!insertSign)insertSigns[targetIndex] = [];
  840. insertSigns[targetIndex].push(aEles.length-1);
  841. }
  842. }
  843. if (result.status >= 400) {
  844. console.warn("error:", `status: ${result.status} from: ${aTag.href}`);
  845. } else {
  846. console.log(result.status);
  847. }
  848. if (customTitle) {
  849. try {
  850. let title = doc.querySelector(customTitle);
  851. if (title && title.innerText) {
  852. aTag.innerText = title.innerText;
  853. }
  854. } catch(e) {
  855. console.warn(e);
  856. }
  857. }
  858. let validData = processDoc(curIndex, aTag, doc, (result.status>=400?` status: ${result.status} from: ${aTag.href} `:""), validTimes < 5);
  859. if (!validData && validTimes++ < 5) {
  860. downIndex--;
  861. downNum--;
  862. setTimeout(() => {
  863. GM_xmlhttpRequest(requestBody);
  864. }, 500);
  865. return;
  866. }
  867. if (wait) {
  868. setTimeout(() => {
  869. downOnce(wait);
  870. }, wait);
  871. } else downOnce();
  872. },
  873. onerror: function(e) {
  874. console.warn("error:", e);
  875. if(tryTimes++ < 5){
  876. setTimeout(() => {
  877. GM_xmlhttpRequest(requestBody);
  878. }, 500);
  879. return;
  880. }
  881. downIndex++;
  882. downNum++;
  883. processDoc(curIndex, aTag, null, ` NETWORK ERROR: '+${(e.response||e.responseText)} from: ${aTag.href} `);
  884. if (wait) {
  885. setTimeout(() => {
  886. downOnce(wait);
  887. }, wait);
  888. } else downOnce();
  889. },
  890. ontimeout: function(e) {
  891. console.warn("timeout: times="+tryTimes+" url="+aTag.href);
  892. //console.log(e);
  893. if(tryTimes++ < 5){
  894. setTimeout(() => {
  895. GM_xmlhttpRequest(requestBody);
  896. }, 500);
  897. return;
  898. }
  899. downIndex++;
  900. downNum++;
  901. processDoc(curIndex, aTag, null, ` TIMEOUT: '+${aTag.href} `);
  902. if (wait) {
  903. setTimeout(() => {
  904. downOnce(wait);
  905. }, wait);
  906. } else downOnce();
  907. }
  908. };
  909. if (useIframe) {
  910. let iframe = document.createElement('iframe'), inited = false;
  911. iframe.name = 'pagetual-iframe';
  912. iframe.width = '100%';
  913. iframe.height = '1000';
  914. iframe.frameBorder = '0';
  915. iframe.sandbox = iframeSandbox || "allow-same-origin allow-scripts allow-popups allow-forms";
  916. iframe.style.cssText = 'margin:0!important;padding:0!important;visibility:hidden!important;flex:0;opacity:0!important;pointer-events:none!important;position:fixed;top:0px;left:0px;z-index:-2147483647;';
  917. iframe.addEventListener('load', e => {
  918. if (e.data != 'pagetual-iframe:DOMLoaded' && e.type != 'load') return;
  919. if (inited) return;
  920. inited = true;
  921. function checkIframe() {
  922. try {
  923. let doc = iframe.contentDocument || iframe.contentWindow.document;
  924. if (!doc || !doc.body) {
  925. setTimeout(() => {
  926. checkIframe();
  927. }, 1000);
  928. return;
  929. }
  930. doc.body.scrollTop = 9999999;
  931. doc.documentElement.scrollTop = 9999999;
  932. if (validTimes++ > 10) {
  933. iframe.src = iframe.src;
  934. validTimes = 0;
  935. return;
  936. }
  937. if (customTitle) {
  938. try {
  939. let title = doc.querySelector(customTitle);
  940. if (title && title.innerText) {
  941. aTag.innerText = title.innerText;
  942. }
  943. } catch(e) {
  944. console.warn(e);
  945. }
  946. }
  947. downIndex++;
  948. downNum++;
  949. let validData = processDoc(curIndex, aTag, doc, "", true);
  950. if (!validData) {
  951. downIndex--;
  952. downNum--;
  953. setTimeout(() => {
  954. checkIframe();
  955. }, 500);
  956. return;
  957. }
  958. if (wait) {
  959. setTimeout(() => {
  960. downOnce(wait);
  961. }, wait);
  962. } else downOnce();
  963. } catch(e) {
  964. console.debug("Stop as cors");
  965. }
  966. if (iframe && iframe.parentNode) iframe.parentNode.removeChild(iframe);
  967. }
  968. setTimeout(() => {
  969. checkIframe();
  970. }, 500);
  971. }, false);
  972. let checkReady = setInterval(() => {
  973. let doc;
  974. try {
  975. doc = iframe.contentDocument || (iframe.contentWindow && iframe.contentWindow.document);
  976. } catch(e) {
  977. clearInterval(checkReady);
  978. return;
  979. }
  980. if (doc) {
  981. try {
  982. Function('win', 'iframe', '"use strict";' + (iframeInit || "win.self=win.top;"))(iframe.contentWindow, iframe);
  983. clearInterval(checkReady);
  984. } catch(e) {
  985. console.debug(e);
  986. }
  987. }
  988. }, 50);
  989. iframe.src = aTag.href;
  990. document.body.appendChild(iframe);
  991. return [curIndex, null, aTag.href];
  992. } else {
  993. return [curIndex, GM_xmlhttpRequest(requestBody), aTag.href];
  994. }
  995. }
  996. if(!aTag){
  997. let waitAtagReadyInterval=setInterval(function(){
  998. if(downNum>=aEles.length)clearInterval(waitAtagReadyInterval);
  999. aTag=aEles[curIndex];
  1000. if(aTag){
  1001. clearInterval(waitAtagReadyInterval);
  1002. request(aTag, curIndex);
  1003. }
  1004. },1000);
  1005. return null;
  1006. }
  1007. let result = request(aTag, curIndex);
  1008. if (result) curRequests.push(result);
  1009. return result;
  1010. };
  1011. function getDocEle(str){
  1012. var doc = null;
  1013. try {
  1014. doc = document.implementation.createHTMLDocument('');
  1015. doc.documentElement.innerHTML = str;
  1016. }
  1017. catch (e) {
  1018. console.log('parse error');
  1019. }
  1020. return doc;
  1021. }
  1022. function sortInnerPage(){
  1023. var pageArrs=[],maxIndex=0,i,j;
  1024. for(i=0;i<insertSigns.length;i++){
  1025. var signs=insertSigns[i];
  1026. if(signs){
  1027. for(j=0;j<signs.length;j++){
  1028. var sign=signs[j];
  1029. var cat=rCats[sign];
  1030. rCats[sign]=null;
  1031. if(!pageArrs[i])pageArrs[i]=[];
  1032. pageArrs[i].push(cat);
  1033. }
  1034. }
  1035. }
  1036. for(i=pageArrs.length-1;i>=0;i--){
  1037. let pageArr=pageArrs[i];
  1038. if(pageArr){
  1039. for(j=pageArr.length-1;j>=0;j--){
  1040. rCats.splice(i+1, 0, pageArr[j]);
  1041. }
  1042. }
  1043. }
  1044. rCats = rCats.filter(function(e){return e!=null});
  1045. }
  1046. var waitForComplete;
  1047. function processDoc(i, aTag, doc, cause, check){
  1048. let cbFunc=content=>{
  1049. rCats[i]=(aTag.innerText.replace(/[\r\n\t]/g, "") + "\r\n" + (cause || '') + content.replace(/\s*$/, ""));
  1050. curRequests = curRequests.filter(function(e){return e[0]!=i});
  1051. txtDownContent.style.display="block";
  1052. txtDownWords.innerHTML=getI18n("downloading",[downNum,(aEles.length-downNum),aTag.innerText]);
  1053. if(downNum==aEles.length){
  1054. if(waitForComplete) clearTimeout(waitForComplete);
  1055. waitForComplete=setTimeout(()=>{
  1056. if(downNum==aEles.length){
  1057. txtDownWords.innerHTML=getI18n("complete",[downNum]);
  1058. sortInnerPage();
  1059. saveContent();
  1060. }
  1061. },3000);
  1062. }
  1063. };
  1064. let contentResult=getPageContent(doc, content=>{
  1065. cbFunc(content);
  1066. }, aTag.href);
  1067. if(contentResult!==false){
  1068. if(check && contentResult && contentResult.replace(/\s/g, "").length<minTxtLength){
  1069. return false;
  1070. }
  1071. cbFunc(contentResult);
  1072. }
  1073. return true;
  1074. }
  1075. var downThreadNum = parseInt(GM_getValue("downThreadNum"));
  1076. downThreadNum = downThreadNum || 20;
  1077. if (useIframe && downThreadNum > 5) {
  1078. downThreadNum = 5;
  1079. }
  1080. if (downThreadNum > 0) {
  1081. for (var i = 0; i < downThreadNum; i++) {
  1082. downOnce();
  1083. if (downIndex >= aEles.length - 1 || downIndex >= downThreadNum - 1) break;
  1084. else downIndex++;
  1085. }
  1086. } else {
  1087. downOnce(-downThreadNum * 1000);
  1088. if (downIndex < aEles.length - 1 && downIndex < downThreadNum - 1) downIndex++;
  1089. }
  1090.  
  1091. /*for(let i=0;i<aEles.length;i++){
  1092. let aTag=aEles[i];
  1093. GM_xmlhttpRequest({
  1094. method: 'GET',
  1095. url: aTag.href,
  1096. overrideMimeType:"text/html;charset="+document.charset,
  1097. onload: function(result) {
  1098. var doc = getDocEle(result.responseText);
  1099. processDoc(i, aTag, doc);
  1100. }
  1101. });
  1102. }*/
  1103. }
  1104.  
  1105. function canonicalUri(src, baseUrl) {
  1106. if (!src) {
  1107. return "";
  1108. }
  1109. if (src.charAt(0) == "#") return baseUrl + src;
  1110. if (src.charAt(0) == "?") return baseUrl.replace(/^([^\?#]+).*/, "$1" + src);
  1111. let origin = location.protocol + '//' + location.host;
  1112. let url = baseUrl || origin;
  1113. url = url.replace(/(\?|#).*/, "");
  1114. if (/https?:\/\/[^\/]+$/.test(url)) url = url + '/';
  1115. if (url.indexOf("http") !== 0) url = origin + url;
  1116. var root_page = /^[^\?#]*\//.exec(url)[0],
  1117. root_domain = /^\w+\:\/\/\/?[^\/]+/.exec(root_page)[0],
  1118. absolute_regex = /^\w+\:\/\//;
  1119. while (src.indexOf("../") === 0) {
  1120. src = src.substr(3);
  1121. root_page = root_page.replace(/\/[^\/]+\/$/, "/");
  1122. }
  1123. src = src.replace(/\.\//, "");
  1124. if (/^\/\/\/?/.test(src)) {
  1125. src = location.protocol + src;
  1126. }
  1127. return (absolute_regex.test(src) ? src : ((src.charAt(0) == "/" ? root_domain : root_page) + src));
  1128. }
  1129.  
  1130. function checkNextPage(doc, baseUrl) {
  1131. let aTags = doc.querySelectorAll("a"), nextPage = null;
  1132. for (var i = 0; i < aTags.length; i++) {
  1133. let aTag = aTags[i];
  1134. if (innerNextPage.test(aTag.innerText) && aTag.href && !/javascript:|#/.test(aTag.href)) {
  1135. let nextPageHref = canonicalUri(aTag.getAttribute("href"), baseUrl || location.href);
  1136. if (nextPageHref != location.href) {
  1137. nextPage = aTag;
  1138. nextPage.href = nextPageHref;
  1139. break;
  1140. }
  1141. }
  1142. }
  1143. return nextPage;
  1144. }
  1145.  
  1146. function textNodesUnder(el){
  1147. var n, a=[], walk=document.createTreeWalker(el,NodeFilter.SHOW_TEXT,null,false);
  1148. while(n=walk.nextNode()) a.push(n);
  1149. return a;
  1150. }
  1151.  
  1152. function getPageContent(doc, cb, url){
  1153. if(!doc)return i18n.error;
  1154. if(processFunc){
  1155. return processFunc(doc, cb, url);
  1156. }
  1157. [].forEach.call(doc.querySelectorAll("span,div,ul"),function(item){
  1158. var thisStyle=doc.defaultView?doc.defaultView.getComputedStyle(item):item.style;
  1159. if(thisStyle && (thisStyle.display=="none" || (item.nodeName=="SPAN" && thisStyle.fontSize=="0px"))){
  1160. item.innerHTML="";
  1161. }
  1162. });
  1163. var i,j,k,rStr="",pageData=(doc.body?doc.body:doc).cloneNode(true),delList=[];
  1164. pageData.innerHTML=pageData.innerHTML.replace(/\<\!\-\-((.|[\n|\r|\r\n])*?)\-\-\>/g,"");
  1165. [].forEach.call(pageData.querySelectorAll("font.jammer"),function(item){
  1166. item.innerHTML="";
  1167. });
  1168. var selectors=GM_getValue("selectors");
  1169. if(selectors){
  1170. [].forEach.call(pageData.querySelectorAll(selectors),function(item){
  1171. item.innerHTML="";
  1172. });
  1173. }
  1174. [].forEach.call(pageData.querySelectorAll("script,style,link,img,noscript,iframe"),function(item){delList.push(item);});
  1175. [].forEach.call(delList,function(item){item.innerHTML="";});
  1176. var endEle = ele => {
  1177. return /^(I|STRONG|B|FONT|P|DL|DD|H\d)$/.test(ele.nodeName) && ele.children.length <= 1;
  1178. };
  1179. var largestContent,contents=pageData.querySelectorAll("span,div,article,p,td"),largestNum=0;
  1180. for(i=0;i<contents.length;i++){
  1181. let content=contents[i],hasText=false,allSingle=true,item,curNum=0;
  1182. if(/footer/.test(content.className))continue;
  1183. for(j=content.childNodes.length-1;j>=0;j--){
  1184. item=content.childNodes[j];
  1185. if(item.nodeType==3){
  1186. if(/^\s*$/.test(item.data)){
  1187. item.innerHTML="";
  1188. }else hasText=true;
  1189. }else if(/^(I|A|STRONG|B|FONT|P|DL|DD|H\d)$/.test(item.nodeName)){
  1190. hasText=true;
  1191. }else if(item.nodeType==1&&item.children.length==1&&/^(I|A|STRONG|B|FONT|P|DL|DD|H\d)$/.test(item.children[0].nodeName)){
  1192. hasText=true;
  1193. }
  1194. }
  1195. for(j=content.childNodes.length-1;j>=0;j--){
  1196. item=content.childNodes[j];
  1197. if(item.nodeType==1 && !/^(I|A|STRONG|B|FONT|BR)$/.test(item.nodeName) && /^[\s\-\_\?\>\|]*$/.test(item.innerHTML)){
  1198. item.innerHTML="";
  1199. }
  1200. }
  1201. if(content.childNodes.length>1){
  1202. let indexItem=0;
  1203. for(j=0;j<content.childNodes.length;j++){
  1204. item=content.childNodes[j];
  1205. if(item.nodeType==1){
  1206. if(item.innerText && item.innerText.length<50 && indexReg.test(item.innerText))indexItem++;
  1207. for(k=0;k<item.childNodes.length;k++){
  1208. var childNode=item.childNodes[k];
  1209. if(childNode.nodeType!=3 && !/^(I|A|STRONG|B|FONT|BR)$/.test(childNode.nodeName)){
  1210. allSingle=false;
  1211. break;
  1212. }
  1213. }
  1214. if(!allSingle)break;
  1215. }
  1216. }
  1217. if(indexItem>=5)continue;
  1218. }else{
  1219. allSingle=false;
  1220. }
  1221. if(!allSingle && !hasText){
  1222. continue;
  1223. }else {
  1224. if(pageData==document && content.offsetWidth<=0 && content.offsetHeight<=0){
  1225. continue;
  1226. }
  1227. [].forEach.call(content.childNodes,function(item){
  1228. if(item.nodeType==3)curNum+=item.data.trim().length;
  1229. else if(endEle(item) || (item.nodeType == 1 && item.children.length == 1 && endEle(item.children[0]))) curNum += (firefox ? item.textContent.trim().length : item.innerText.trim().length);
  1230. });
  1231. }
  1232. if(curNum>largestNum){
  1233. largestNum=curNum;
  1234. largestContent=content;
  1235. }
  1236. }
  1237. if(!largestContent)return i18n.error+" : NO TEXT CONTENT";
  1238. var retainImage=!!GM_getValue("retainImage");
  1239. var childlist=pageData.querySelectorAll(largestContent.nodeName);//+(largestContent.className?"."+largestContent.className.replace(/(^\s*)|(\s*$)/g, '').replace(/\s+/g, '.'):""));
  1240. function getRightStr(ele, noTextEnable){
  1241. if(retainImage){
  1242. [].forEach.call(ele.querySelectorAll("img[src]"), img => {
  1243. let imgTxtNode=document.createTextNode(`![img](${canonicalUri(img.getAttribute("src"), url || location.href)})`);
  1244. img.parentNode.replaceChild(imgTxtNode, img);
  1245. });
  1246. }
  1247. let childNodes=ele.childNodes,cStr="\r\n",hasText=false;
  1248. [].forEach.call(ele.querySelectorAll("a[href]"), a => {
  1249. a.parentNode && a.parentNode.removeChild(a);
  1250. });
  1251. for(let j=0;j<childNodes.length;j++){
  1252. let childNode=childNodes[j];
  1253. if(childNode.nodeType==3 && childNode.data && !/^[\s\-\_\?\>\|]*$/.test(childNode.data))hasText=true;
  1254. if(childNode.innerHTML){
  1255. childNode.innerHTML=childNode.innerHTML.replace(/\<\s*br\s*\>/gi,"\r\n").replace(/\n+/gi,"\n").replace(/\r+/gi,"\r");
  1256. }
  1257. let content=childNode.textContent;
  1258. if(content){
  1259. if(!content.trim())continue;
  1260. cStr+=content.replace(/ +/g," ").replace(/([^\r]|^)\n([^\r]|$)/gi,"$1\r\n$2");
  1261. }
  1262. if(childNode.nodeType!=3 && !/^(I|A|STRONG|B|FONT|IMG)$/.test(childNode.nodeName))cStr+="\r\n";
  1263. }
  1264. if(hasText || noTextEnable || ele==largestContent)rStr+=cStr+"\r\n";
  1265. }
  1266. for(i=0;i<childlist.length;i++){
  1267. var child=childlist[i];
  1268. if(getDepth(child)==getDepth(largestContent)){
  1269. if(largestContent.className != child.className)continue;
  1270. if((largestContent.className && largestContent.className == child.className) || largestContent.parentNode == child.parentNode){
  1271. getRightStr(child, true);
  1272. }else {
  1273. getRightStr(child, false);
  1274. }
  1275. }
  1276. }
  1277. return rStr.replace(/[\n\r]+/g,"\n\r");
  1278. }
  1279.  
  1280. function getI18n(key, args){
  1281. var resultStr=i18n[key];
  1282. if(args && args.length>0){
  1283. args.forEach(function(item){
  1284. resultStr=resultStr.replace(/%s/,item);
  1285. });
  1286. }
  1287. return resultStr;
  1288. }
  1289.  
  1290. function getDepth(dom){
  1291. var pa=dom,i=0;
  1292. while(pa.parentNode){
  1293. pa=pa.parentNode;
  1294. i++;
  1295. }
  1296. return i;
  1297. }
  1298.  
  1299. function fetch(forceSingle){
  1300. forceSingle=forceSingle===true;
  1301. processFunc=null;
  1302. var aEles=document.body.querySelectorAll("a"),list=[];
  1303. for(var i=0;i<aEles.length;i++){
  1304. var aEle=aEles[i],has=false;
  1305. if((!aEle.href || aEle.href.indexOf("javascript")!=-1) && aEle.dataset.href){
  1306. aEle.href=aEle.dataset.href;
  1307. }
  1308. if(aEle.href==location.href)continue;
  1309. for(var j=0;j<list.length;j++){
  1310. if(list[j].href==aEle.href){
  1311. aEle=list[j];
  1312. list.splice(j,1);
  1313. list.push(aEle);
  1314. has=true;
  1315. break;
  1316. }
  1317. }
  1318. if(!has && aEle.href && /^http/i.test(aEle.href) && ((aEle.innerText.trim()!="" && indexReg.test(aEle.innerText.trim())) || /chapter[\-_]?\d/.test(aEle.href))){
  1319. list.push(aEle);
  1320. }
  1321. }
  1322. if(list.length>2 && !forceSingle){
  1323. useIframe = false;
  1324. filterList(list);
  1325. }else{
  1326. var blob = new Blob([i18n.info+"\r\n\r\n"+document.title+"\r\n\r\n"+getPageContent(document)], {type: "text/plain;charset=utf-8"});
  1327. saveAs(blob, document.title+".txt");
  1328. }
  1329. }
  1330.  
  1331. function customDown(urls){
  1332. processFunc = null;
  1333. useIframe = false;
  1334. if(urls){
  1335. urls=decodeURIComponent(urls.replace(/%/g,'%25'));
  1336. GM_setValue("DACrules_"+document.domain, urls);
  1337. var processEles=[];
  1338. let urlsArr=urls.split("@@"),eles=[];
  1339. if(/^http|^ftp/.test(urlsArr[0])){
  1340. [].forEach.call(urlsArr[0].split(","),function(i){
  1341. var curEle;
  1342. var varNum=/\[\d+\-\d+\]/.exec(i);
  1343. if(varNum){
  1344. varNum=varNum[0].trim();
  1345. }else{
  1346. curEle=document.createElement("a");
  1347. curEle.href=i;
  1348. curEle.innerText="Added Url";
  1349. processEles.push(curEle);
  1350. return;
  1351. }
  1352. var num1=/\[(\d+)/.exec(varNum)[1].trim();
  1353. var num2=/(\d+)\]/.exec(varNum)[1].trim();
  1354. var num1Int=parseInt(num1);
  1355. var num2Int=parseInt(num2);
  1356. var numLen=num1.length;
  1357. var needAdd=num1.charAt(0)=="0";
  1358. if(num1Int>=num2Int)return;
  1359. for(var j=num1Int;j<=num2Int;j++){
  1360. var urlIndex=j.toString();
  1361. if(needAdd){
  1362. while(urlIndex.length<numLen)urlIndex="0"+urlIndex;
  1363. }
  1364. var curUrl=i.replace(/\[\d+\-\d+\]/,urlIndex).trim();
  1365. curEle=document.createElement("a");
  1366. curEle.href=curUrl;
  1367. curEle.innerText="Added Url " + processEles.length.toString();
  1368. processEles.push(curEle);
  1369. }
  1370. });
  1371. }else{
  1372. let urlSel=urlsArr[0].split(">>");
  1373. try{
  1374. eles=document.querySelectorAll(urlSel[0]);
  1375. eles=[].filter.call(eles, ele=>{
  1376. return ele.nodeName=='BODY'||(!!ele.offsetParent&&getComputedStyle(ele).display!=='none');
  1377. })
  1378. }catch(e){}
  1379. if(eles.length==0){
  1380. eles=[];
  1381. var eleTxts=urlsArr[0].split(/(?<=[^\\])[,,]/),exmpEles=[],excludeTxts={};
  1382. [].forEach.call(document.querySelectorAll("a"),function(item){
  1383. if(!item.offsetParent)return;
  1384. eleTxts.forEach(txt=>{
  1385. var txtArr=txt.split("!");
  1386. if(item.innerText.indexOf(txtArr[0])!=-1){
  1387. exmpEles.push(item);
  1388. excludeTxts[item]=txtArr.splice(1);
  1389. }
  1390. });
  1391. })
  1392. exmpEles.forEach(e=>{
  1393. var cssSelStr="a",pa=e.parentNode,excludeTxt=excludeTxts[e];
  1394. if(e.className)cssSelStr+="."+CSS.escape(e.className);
  1395. while(pa && pa.nodeName!="BODY"){
  1396. cssSelStr=pa.nodeName+">"+cssSelStr;
  1397. pa=pa.parentNode;
  1398. }
  1399. cssSelStr="body>"+cssSelStr;;
  1400. [].forEach.call(document.querySelectorAll(cssSelStr),function(item){
  1401. if(!item.offsetParent)return;
  1402. var isExclude=false;
  1403. for(var t in excludeTxt){
  1404. if(item.innerText.indexOf(excludeTxt[t])!=-1){
  1405. isExclude=true;
  1406. break;
  1407. }
  1408. }
  1409. if(!isExclude && eles.indexOf(item)==-1){
  1410. eles.push(item);
  1411. }
  1412. });
  1413. });
  1414. }
  1415. function addItem(item) {
  1416. let has=false;
  1417. for(var j=0;j<processEles.length;j++){
  1418. if(processEles[j].href==item.href){
  1419. processEles.splice(j,1);
  1420. processEles.push(item);
  1421. has=true;
  1422. break;
  1423. }
  1424. }
  1425. if((!item.href || item.href.indexOf("javascript")!=-1) && item.dataset.href){
  1426. item.href=item.dataset.href;
  1427. }
  1428. if(!has && item.href && /^http/i.test(item.href)){
  1429. processEles.push(item.cloneNode(1));
  1430. }
  1431. }
  1432. [].forEach.call(eles,function(item){
  1433. if(urlSel[1]){
  1434. item=Function("item",urlSel[1])(item);
  1435. let items;
  1436. if (Array.isArray(item)) {
  1437. items = item;
  1438. } else items = [item];
  1439. items.forEach(item => {
  1440. if(!item || !item.href)return;
  1441. if(!item.nodeName || item.nodeName!="A"){
  1442. let href=item.href;
  1443. let innerText=item.innerText;
  1444. item=document.createElement("a");
  1445. item.href=href;
  1446. item.innerText=innerText;
  1447. }
  1448. addItem(item);
  1449. });
  1450. } else {
  1451. addItem(item);
  1452. }
  1453. });
  1454. }
  1455. if(urlsArr[1]){
  1456. processEles.forEach(ele=>{
  1457. ele.href=ele.href.replace(new RegExp(urlsArr[1]), urlsArr[2]);
  1458. });
  1459. }
  1460. var retainImage=!!GM_getValue("retainImage");
  1461. var evalCode = urlsArr[3];
  1462. if (evalCode && /^iframe:/.test(evalCode.trim())) {
  1463. evalCode = evalCode.trim().replace("iframe:", "");
  1464. useIframe = true;
  1465. iframeSandbox = false;
  1466. iframeInit = false;
  1467. while (/^(sandbox|init):/.test(evalCode)) {
  1468. iframeSandbox = evalCode.match(/^sandbox:{(.*?)}/);
  1469. if (iframeSandbox) {
  1470. iframeSandbox = iframeSandbox[1];
  1471. evalCode = evalCode.replace(/^sandbox:{(.*?)}/, "");
  1472. }
  1473. iframeInit = evalCode.match(/^init:{(.*?)}/);
  1474. if (iframeInit) {
  1475. iframeInit = iframeInit[1];
  1476. evalCode = evalCode.replace(/^init:{(.*?)}/, "");
  1477. }
  1478. }
  1479. }
  1480. if(evalCode){
  1481. processFunc=(data, cb, url)=>{
  1482. let doc=data;
  1483. if(evalCode.indexOf("return ")==-1){
  1484. if(evalCode.indexOf("@")==0){
  1485. let content="";
  1486. if(retainImage){
  1487. [].forEach.call(data.querySelectorAll("img[src]"), img => {
  1488. let imgTxt=`![img](${canonicalUri(img.getAttribute("src"), location.href)})`;
  1489. let imgTxtNode=document.createTextNode(imgTxt);
  1490. img.parentNode.replaceChild(imgTxtNode, img);
  1491. });
  1492. }
  1493. [].forEach.call(data.querySelectorAll(evalCode.slice(1)), ele=>{
  1494. [].forEach.call(ele.childNodes, child=>{
  1495. if(child.innerHTML){
  1496. child.innerHTML=child.innerHTML.replace(/\<\s*br\s*\>/gi,"\r\n").replace(/\n+/gi,"\n").replace(/\r+/gi,"\r");
  1497. }
  1498. if(child.textContent){
  1499. content+=(child.textContent.replace(/ +/g," ").replace(/([^\r]|^)\n([^\r]|$)/gi,"$1\r\n$2")+"\r\n");
  1500. }
  1501. });
  1502. content+="\r\n";
  1503. });
  1504. return content;
  1505. }else return eval(evalCode);
  1506. }else{
  1507. return Function("data", "doc", "cb", "url", evalCode)(data, doc, cb, url);
  1508. }
  1509. };
  1510. }else{
  1511. if(win.dacProcess){
  1512. processFunc=win.dacProcess;
  1513. }
  1514. }
  1515. filterList(processEles);
  1516. }
  1517. }
  1518. const configPage = "https://hoothin.github.io/UserScripts/DownloadAllContent/";
  1519. const copySvg = '<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" style="transition: all ease 0.5s;top: 5px;right: 5px;position: absolute;cursor: pointer;"><title>Copy</title><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg>';
  1520. function searchRule(){
  1521. GM_openInTab(configPage + "#@" + location.hostname, {active: true});
  1522. }
  1523. if (location.origin + location.pathname == configPage) {
  1524. let exampleNode = document.getElementById("example");
  1525. if (!exampleNode) return;
  1526.  
  1527. exampleNode = exampleNode.parentNode;
  1528. let ruleList = exampleNode.nextElementSibling.nextElementSibling;
  1529. let searchInput = document.createElement("input");
  1530. let inputTimer;
  1531. function searchByInput() {
  1532. clearTimeout(inputTimer);
  1533. inputTimer = setTimeout(() => {
  1534. let curValue = searchInput.value;
  1535. let matchRules = [];
  1536. let dontMatchRules = [];
  1537. if (curValue) {
  1538. for (let i = 0; i < ruleList.children.length; i++) {
  1539. let curRule = ruleList.children[i];
  1540. let aHref = curRule.firstChild.href;
  1541. if (aHref.indexOf(curValue) == -1) {
  1542. dontMatchRules.push(curRule);
  1543. } else {
  1544. matchRules.push(curRule);
  1545. }
  1546. }
  1547. } else {
  1548. dontMatchRules = ruleList.children;
  1549. }
  1550. if (matchRules.length) {
  1551. for (let i = 0; i < dontMatchRules.length; i++) {
  1552. let curRule = dontMatchRules[i];
  1553. curRule.style.display = "none";
  1554. }
  1555. for (let i = 0; i < matchRules.length; i++) {
  1556. let curRule = matchRules[i];
  1557. curRule.style.display = "";
  1558. }
  1559. } else {
  1560. for (let i = 0; i < dontMatchRules.length; i++) {
  1561. let curRule = dontMatchRules[i];
  1562. curRule.style.display = "";
  1563. }
  1564. }
  1565. }, 500);
  1566. }
  1567. searchInput.style.margin = "10px";
  1568. searchInput.style.width = "100%";
  1569. searchInput.placeholder = i18n.searchRule;
  1570. searchInput.addEventListener("input", function(e) {
  1571. searchByInput();
  1572. });
  1573. if (location.hash) {
  1574. let hash = location.hash.slice(1);
  1575. if (hash.indexOf("@") == 0) {
  1576. setTimeout(() => {
  1577. exampleNode.scrollIntoView();
  1578. }, 500);
  1579. searchInput.value = hash.slice(1);
  1580. searchByInput();
  1581. }
  1582. }
  1583. [].forEach.call(ruleList.querySelectorAll("div.highlight"), highlight => {
  1584. highlight.style.position = "relative";
  1585. highlight.innerHTML = highlight.innerHTML + copySvg;
  1586. let svg = highlight.children[1];
  1587. svg.addEventListener("click", function(e) {
  1588. GM_setClipboard(highlight.children[0].innerText);
  1589. svg.style.opacity = 0;
  1590. setTimeout(() => {
  1591. svg.style.opacity = 1;
  1592. }, 1000);
  1593. });
  1594. });
  1595. exampleNode.parentNode.insertBefore(searchInput, ruleList);
  1596.  
  1597.  
  1598. let donateNode = document.querySelector("[alt='donate']");
  1599. if (!donateNode) return;
  1600. let insertPos = donateNode.parentNode.nextElementSibling;
  1601. let radioIndex = 0;
  1602. function createOption(_name, _value, _type) {
  1603. if (!_type) _type = "input";
  1604. let con = document.createElement("div");
  1605. let option = document.createElement("input");
  1606. let cap = document.createElement("b");
  1607. option.type = _type;
  1608. option.value = _value;
  1609. option.checked = _value;
  1610. cap.style.margin = "0px 10px 0px 0px";
  1611. if (_type == "radio") {
  1612. let label = document.createElement("label");
  1613. label.innerText = _name;
  1614. radioIndex++;
  1615. option.id = "radio" + radioIndex;
  1616. label.setAttribute("for", option.id);
  1617. cap.appendChild(label);
  1618. } else {
  1619. if (_type == "input") {
  1620. option.style.flexGrow = "1";
  1621. }
  1622. cap.innerText = _name;
  1623. }
  1624. con.style.margin = "10px 0";
  1625. con.style.display = "flex";
  1626. con.style.alignItems = "center";
  1627. con.appendChild(cap);
  1628. con.appendChild(option);
  1629. insertPos.parentNode.insertBefore(con, insertPos);
  1630. return option;
  1631. }
  1632. let delSelector = createOption(i18n.del, GM_getValue("selectors") || "");
  1633. delSelector.setAttribute("placeHolder", ".mask,.ksam");
  1634. let downThreadNum = createOption(i18n.downThreadNum, GM_getValue("downThreadNum") || "20", "number");
  1635. let customTitle = createOption(i18n.customTitle, GM_getValue("customTitle") || "");
  1636. customTitle.setAttribute("placeHolder", "title");
  1637. let minTxtLength = createOption(i18n.minTxtLength, GM_getValue("minTxtLength") || "100", "number");
  1638. let contentSortUrlValue = GM_getValue("contentSortUrl") || false;
  1639. let contentSortValue = GM_getValue("contentSort") || false;
  1640. let reSortDefault = createOption(i18n.reSortDefault, !contentSortUrlValue && !contentSortValue, "radio");
  1641. let reSortUrl = createOption(i18n.reSortUrl, contentSortUrlValue || false, "radio");
  1642. let contentSort = createOption(i18n.reSort, contentSortValue || false, "radio");
  1643. reSortDefault.name = "sort";
  1644. reSortUrl.name = "sort";
  1645. contentSort.name = "sort";
  1646. let reverse = createOption(i18n.reverse, !!GM_getValue("reverse"), "checkbox");
  1647. let retainImage = createOption(i18n.retainImage, !!GM_getValue("retainImage"), "checkbox");
  1648. let showFilterList = createOption(i18n.showFilterList, !!GM_getValue("showFilterList"), "checkbox");
  1649. let disableNextPage = !!GM_getValue("disableNextPage");
  1650. let nextPage = createOption(i18n.nextPage, !disableNextPage, "checkbox");
  1651. let nextPageReg = createOption(i18n.nextPageReg, GM_getValue("nextPageReg") || "");
  1652. nextPageReg.setAttribute("placeHolder", "^\\s*(下一[页頁张張]|next\\s*page|次のページ)");
  1653. if (disableNextPage) {
  1654. nextPageReg.parentNode.style.display = "none";
  1655. }
  1656. nextPage.onclick = e => {
  1657. nextPageReg.parentNode.style.display = nextPage.checked ? "flex" : "none";
  1658. }
  1659. let saveBtn = document.createElement("button");
  1660. saveBtn.innerText = i18n.saveBtn;
  1661. saveBtn.style.margin = "0 0 20px 0";
  1662. insertPos.parentNode.insertBefore(saveBtn, insertPos);
  1663. saveBtn.onclick = e => {
  1664. GM_setValue("selectors", delSelector.value || "");
  1665. GM_setValue("downThreadNum", downThreadNum.value || 20);
  1666. GM_setValue("minTxtLength", minTxtLength.value || 100);
  1667. GM_setValue("customTitle", customTitle.value || "");
  1668. if (reSortUrl.checked) {
  1669. GM_setValue("contentSortUrl", true);
  1670. GM_setValue("contentSort", false);
  1671. } else if (contentSort.checked) {
  1672. GM_setValue("contentSortUrl", false);
  1673. GM_setValue("contentSort", true);
  1674. } else {
  1675. GM_setValue("contentSortUrl", false);
  1676. GM_setValue("contentSort", false);
  1677. }
  1678. GM_setValue("reverse", reverse.checked);
  1679. GM_setValue("retainImage", retainImage.checked);
  1680. GM_setValue("showFilterList", showFilterList.checked);
  1681. GM_setValue("disableNextPage", !nextPage.checked);
  1682. GM_setValue("nextPageReg", nextPageReg.value || "");
  1683. alert(i18n.saveOk);
  1684. };
  1685. return;
  1686. }
  1687.  
  1688. function setDel(){
  1689. GM_openInTab(configPage + "#操作說明", {active: true});
  1690. /*var selValue=GM_getValue("selectors");
  1691. var selectors=prompt(i18n.del,selValue?selValue:"");
  1692. GM_setValue("selectors",selectors);
  1693. selValue=GM_getValue("downThreadNum");
  1694. var downThreadNum=prompt(i18n.downThreadNum,selValue?selValue:"20");
  1695. GM_setValue("downThreadNum",downThreadNum);
  1696. var sortByUrl=window.confirm(i18n.reSortUrl);
  1697. GM_setValue("contentSortUrl",sortByUrl);
  1698. if(!sortByUrl)GM_setValue("contentSort",window.confirm(i18n.reSort));*/
  1699. }
  1700.  
  1701. document.addEventListener("keydown", function(e) {
  1702. if(e.keyCode == 120 && e.ctrlKey) {
  1703. fetch(e.shiftKey);
  1704. }
  1705. });
  1706. GM_registerMenuCommand(i18n.fetch, fetch);
  1707. GM_registerMenuCommand(i18n.custom, () => {
  1708. var customRules = GM_getValue("DACrules_" + document.domain);
  1709. var urls = window.prompt(i18n.customInfo, customRules ? customRules : "https://xxx.xxx/book-[20-99].html, https://xxx.xxx/book-[01-10].html");
  1710. if (urls) {
  1711. customDown(urls);
  1712. }
  1713. });
  1714. GM_registerMenuCommand(i18n.setting, setDel);
  1715. GM_registerMenuCommand(i18n.searchRule, searchRule);
  1716. })();