怠惰小说下载器

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

当前为 2023-10-22 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name DownloadAllContent
  3. // @name:zh-CN 怠惰小说下载器
  4. // @name:zh-TW 怠惰小説下載器
  5. // @name:ja 怠惰者小説ダウンロードツール
  6. // @namespace hoothin
  7. // @version 2.7.4.2
  8. // @description Fetch and download main content on current page, provide special support for novel
  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 unsafeWindow
  23. // @license MIT License
  24. // @compatible chrome
  25. // @compatible firefox
  26. // @compatible opera 未测试
  27. // @compatible safari 未测试
  28. // @contributionURL https://ko-fi.com/hoothin
  29. // @contributionAmount 1
  30. // ==/UserScript==
  31. (function (global, factory) {
  32. if (typeof define === "function" && define.amd) {
  33. define([], factory);
  34. } else if (typeof exports !== "undefined") {
  35. factory();
  36. } else {
  37. var mod = {
  38. exports: {}
  39. };
  40. factory();
  41. global.FileSaver = mod.exports;
  42. }
  43. })(this, function () {
  44. "use strict";
  45.  
  46. /*
  47. * FileSaver.js
  48. * A saveAs() FileSaver implementation.
  49. *
  50. * By Eli Grey, http://eligrey.com
  51. *
  52. * License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)
  53. * source : http://purl.eligrey.com/github/FileSaver.js
  54. */
  55. 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;
  56.  
  57. function bom(blob, opts) {
  58. if (typeof opts === 'undefined') opts = {
  59. autoBom: false
  60. };else if (typeof opts !== 'object') {
  61. console.warn('Deprecated: Expected third argument to be a object');
  62. opts = {
  63. autoBom: !opts
  64. };
  65. }
  66.  
  67. if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
  68. return new Blob([String.fromCharCode(0xFEFF), blob], {
  69. type: blob.type
  70. });
  71. }
  72.  
  73. return blob;
  74. }
  75.  
  76. function download(url, name, opts) {
  77. var xhr = new XMLHttpRequest();
  78. xhr.open('GET', url);
  79. xhr.responseType = 'blob';
  80.  
  81. xhr.onload = function () {
  82. saveAs(xhr.response, name, opts);
  83. };
  84.  
  85. xhr.onerror = function () {
  86. console.error('could not download file');
  87. };
  88.  
  89. xhr.send();
  90. }
  91.  
  92. function corsEnabled(url) {
  93. var xhr = new XMLHttpRequest();
  94.  
  95. xhr.open('HEAD', url, false);
  96.  
  97. try {
  98. xhr.send();
  99. } catch (e) {}
  100.  
  101. return xhr.status >= 200 && xhr.status <= 299;
  102. }
  103.  
  104.  
  105. function click(node) {
  106. try {
  107. node.dispatchEvent(new MouseEvent('click'));
  108. } catch (e) {
  109. var evt = document.createEvent('MouseEvents');
  110. evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null);
  111. node.dispatchEvent(evt);
  112. }
  113. }
  114.  
  115.  
  116. var isMacOSWebView = _global.navigator && /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent);
  117. var saveAs = _global.saveAs || (
  118. typeof window !== 'object' || window !== _global ? function saveAs() {}
  119.  
  120. : 'download' in HTMLAnchorElement.prototype && !isMacOSWebView ? function saveAs(blob, name, opts) {
  121. var URL = _global.URL || _global.webkitURL;
  122. var a = document.createElement('a');
  123. name = name || blob.name || 'download';
  124. a.download = name;
  125. a.rel = 'noopener';
  126.  
  127. if (typeof blob === 'string') {
  128. a.href = blob;
  129.  
  130. if (a.origin !== location.origin) {
  131. corsEnabled(a.href) ? download(blob, name, opts) : click(a, a.target = '_blank');
  132. } else {
  133. click(a);
  134. }
  135. } else {
  136. a.href = URL.createObjectURL(blob);
  137. setTimeout(function () {
  138. URL.revokeObjectURL(a.href);
  139. }, 4E4);
  140.  
  141. setTimeout(function () {
  142. click(a);
  143. }, 0);
  144. }
  145. }
  146. : 'msSaveOrOpenBlob' in navigator ? function saveAs(blob, name, opts) {
  147. name = name || blob.name || 'download';
  148.  
  149. if (typeof blob === 'string') {
  150. if (corsEnabled(blob)) {
  151. download(blob, name, opts);
  152. } else {
  153. var a = document.createElement('a');
  154. a.href = blob;
  155. a.target = '_blank';
  156. setTimeout(function () {
  157. click(a);
  158. });
  159. }
  160. } else {
  161. navigator.msSaveOrOpenBlob(bom(blob, opts), name);
  162. }
  163. }
  164. : function saveAs(blob, name, opts, popup) {
  165. popup = popup || open('', '_blank');
  166.  
  167. if (popup) {
  168. popup.document.title = popup.document.body.innerText = 'downloading...';
  169. }
  170.  
  171. if (typeof blob === 'string') return download(blob, name, opts);
  172. var force = blob.type === 'application/octet-stream';
  173.  
  174. var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari;
  175.  
  176. var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent);
  177.  
  178. if ((isChromeIOS || force && isSafari || isMacOSWebView) && typeof FileReader !== 'undefined') {
  179. var reader = new FileReader();
  180.  
  181. reader.onloadend = function () {
  182. var url = reader.result;
  183. url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;');
  184. if (popup) popup.location.href = url;else location = url;
  185. popup = null;
  186. };
  187.  
  188. reader.readAsDataURL(blob);
  189. } else {
  190. var URL = _global.URL || _global.webkitURL;
  191. var url = URL.createObjectURL(blob);
  192. if (popup) popup.location = url;else location.href = url;
  193. popup = null;
  194.  
  195. setTimeout(function () {
  196. URL.revokeObjectURL(url);
  197. }, 4E4);
  198. }
  199. });
  200. _global.saveAs = saveAs.saveAs = saveAs;
  201.  
  202. if (typeof module !== 'undefined') {
  203. module.exports = saveAs;
  204. }
  205. });
  206.  
  207. (function() {
  208. 'use strict';
  209. 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*[、)章节節回卷折篇幕集话話]/i;
  210. var innerNextPage=/^\s*(下一[页頁张張]|next\s*page|次のページ)/i;
  211. var lang = navigator.appName=="Netscape"?navigator.language:navigator.userLanguage;
  212. var i18n={};
  213. var rCats=[];
  214. var processFunc;
  215. var win=(typeof unsafeWindow=='undefined'? window : unsafeWindow);
  216. switch (lang){
  217. case "zh-CN":
  218. case "zh-SG":
  219. i18n={
  220. fetch:"开始下载小说【Ctrl+F9】",
  221. info:"本文是使用怠惰小说下载器(DownloadAllContent)下载的",
  222. error:"该段内容获取失败",
  223. downloading:"已下载完成 %s 段,剩余 %s 段<br>正在下载 %s",
  224. complete:"已全部下载完成,共 %s 段",
  225. del:"设置文本干扰码的CSS选择器",
  226. custom:"自定规则下载",
  227. customInfo:"输入网址或者章节CSS选择器",
  228. reSort:"按标题名重新排序章节",
  229. reSortUrl:"按网址重新排序章节",
  230. setting:"选项参数设置",
  231. searchRule:"搜索网站规则",
  232. abort:"跳过此章",
  233. save:"保存当前",
  234. saveAsMd:"存为 Markdown",
  235. downThreadNum:"设置同时下载的线程数",
  236. customTitle:"自定义章节标题,输入内页文字对应选择器",
  237. reSortDefault:"默认按页面中位置排序章节",
  238. reverse:"反转章节排序",
  239. saveBtn:"保存设置",
  240. saveOk:"保存成功",
  241. nextPage:"嗅探章节内分页",
  242. nextPageReg:"自定义分页正则"
  243. };
  244. break;
  245. case "zh-TW":
  246. case "zh-HK":
  247. i18n={
  248. fetch:"開始下載小說【Ctrl+F9】",
  249. info:"本文是使用怠惰小說下載器(DownloadAllContent)下載的",
  250. error:"該段內容獲取失敗",
  251. downloading:"已下載完成 %s 段,剩餘 %s 段<br>正在下載 %s",
  252. complete:"已全部下載完成,共 %s 段",
  253. del:"設置文本干擾碼的CSS選擇器",
  254. custom:"自訂規則下載",
  255. customInfo:"輸入網址或者章節CSS選擇器",
  256. reSort:"按標題名重新排序章節",
  257. reSortUrl:"按網址重新排序章節",
  258. setting:"選項參數設定",
  259. searchRule:"搜尋網站規則",
  260. abort:"跳過此章",
  261. save:"保存當前",
  262. saveAsMd:"存爲 Markdown",
  263. downThreadNum:"設置同時下載的綫程數",
  264. customTitle:"自訂章節標題,輸入內頁文字對應選擇器",
  265. reSortDefault:"預設依頁面中位置排序章節",
  266. reverse:"反轉章節排序",
  267. saveBtn:"儲存設定",
  268. saveOk:"儲存成功",
  269. nextPage:"嗅探章節內分頁",
  270. nextPageReg:"自訂分頁正規"
  271. };
  272. break;
  273. default:
  274. i18n={
  275. fetch:"Download [Ctrl+F9]",
  276. info:"The TXT is downloaded by 'DownloadAllContent'",
  277. error:"Failed in downloading current chapter",
  278. downloading:"%s pages are downloaded, there are still %s pages left<br>Downloading %s ......",
  279. complete:"Completed! Get %s pages in total",
  280. del:"Set css selectors for ignore",
  281. custom:"Custom to download",
  282. customInfo:"Input urls OR sss selectors for chapter links",
  283. reSort:"ReSort by title",
  284. reSortUrl:"Resort by URLs",
  285. setting:"Open Setting",
  286. searchRule:"Search rule",
  287. abort:"Abort",
  288. save:"Save",
  289. saveAsMd:"Save as Markdown",
  290. downThreadNum:"Set threadNum for download",
  291. customTitle: "Customize the chapter title, enter the selector on inner page",
  292. reSortDefault: "Default sort by position in the page",
  293. reverse:"Reverse chapter ordering",
  294. saveBtn:"Save Setting",
  295. saveOk:"Save Over",
  296. nextPage:"Check next page in chapter",
  297. nextPageReg:"Custom RegExp of next page"
  298. };
  299. break;
  300. }
  301. var firefox=navigator.userAgent.toLowerCase().indexOf('firefox')!=-1,curRequests=[];
  302. var rocketContent,txtDownContent,txtDownWords,txtDownQuit,txtDownDivInited=false;
  303.  
  304. function initTxtDownDiv(){
  305. if(txtDownDivInited)return;
  306. txtDownDivInited=true;
  307. rocketContent=document.createElement("div");
  308. document.body.appendChild(rocketContent);
  309. rocketContent.outerHTML=`
  310. <div id="txtDownContent">
  311. <div style="font-size:16px;color:#333333;width:362px;height:110px;position:fixed;left:50%;top:50%;margin-top:-25px;margin-left:-150px;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;">
  312. <div id="txtDownWords" style="position:absolute;width:275px;height: 90px;max-height: 90%;border: 1px solid #f3f1f1;padding: 8px;border-radius: 10px;overflow: auto;">
  313. Analysing......
  314. </div>
  315. <div id="txtDownQuit" style="width: 30px;height: 30px;border-radius: 30px;position:absolute;right:2px;top:2px;cursor: pointer;background-color:#ff5a5a;">
  316. <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>
  317. </div>
  318. <div style="position:absolute;right:0px;bottom:2px;cursor: pointer;max-width:85px">
  319. <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>
  320. <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>
  321. <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>
  322. </div>
  323. </div>
  324. </div>`;
  325. txtDownContent=document.querySelector("#txtDownContent");
  326. txtDownWords=document.querySelector("#txtDownWords");
  327. txtDownQuit=document.querySelector("#txtDownQuit");
  328. txtDownQuit.onclick=function(){
  329. txtDownContent.style.display="none";
  330. txtDownContent.parentNode.removeChild(txtDownContent);
  331. };
  332. initTempSave();
  333. }
  334.  
  335. function saveContent() {
  336. if (win.downloadAllContentSaveAsZip) {
  337. win.downloadAllContentSaveAsZip(rCats, i18n.info, content => {
  338. saveAs(content, document.title + ".zip");
  339. });
  340. } else {
  341. 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"});
  342. saveAs(blob, document.title + ".txt");
  343. }
  344. }
  345.  
  346. function initTempSave(){
  347. var tempSavebtn = document.getElementById('tempSaveTxt');
  348. var abortbtn = document.getElementById('abortRequest');
  349. var saveAsMd = document.getElementById('saveAsMd');
  350. tempSavebtn.onclick = function(){
  351. saveContent();
  352. console.log(curRequests);
  353. }
  354. abortbtn.onclick = function(){
  355. let curRequest = curRequests.pop();
  356. if(curRequest)curRequest[1].abort();
  357. }
  358. saveAsMd.onclick = function(){
  359. let txt = i18n.info+"\n\n---\n"+document.title+"\n===\n";
  360. rCats.forEach(cat => {
  361. cat = cat.replace("\r\n", "\n---").replace(/(\r\n|\n\r)+/g, "\n\n").replace(/[\n\r]\t+/g, "\n");
  362. txt += '\n\n'+cat;
  363. });
  364. var blob = new Blob([txt], {type: "text/plain;charset=utf-8"});
  365. saveAs(blob, document.title+".md");
  366. }
  367. }
  368.  
  369. function indexDownload(aEles){
  370. if(aEles.length<1)return;
  371. initTxtDownDiv();
  372. if(GM_getValue("contentSort")){
  373. aEles.sort(function(a,b){
  374. return parseInt(a.innerText.replace(/[^0-9]/ig,"")) - parseInt(b.innerText.replace(/[^0-9]/ig,""));
  375. });
  376. }
  377. if(GM_getValue("contentSortUrl")){
  378. aEles.sort(function(a,b){
  379. return parseInt(a.href.replace(/[^0-9]/ig,"")) - parseInt(b.href.replace(/[^0-9]/ig,""));
  380. });
  381. }
  382. if(GM_getValue("reverse")){
  383. aEles=aEles.reverse();
  384. }
  385. rCats=[];
  386. var customTitle=GM_getValue("customTitle");
  387. var disableNextPage=!!GM_getValue("disableNextPage");
  388. var customNextPageReg=GM_getValue("nextPageReg");
  389. if (customNextPageReg) {
  390. try {
  391. innerNextPage = new RegExp(customNextPageReg, "i");
  392. } catch(e) {
  393. console.warn(e);
  394. }
  395. }
  396. var insertSigns=[];
  397. // var j=0,rCats=[];
  398. var downIndex=0,downNum=0,downOnce=function(wait){
  399. if(downNum>=aEles.length)return;
  400. let curIndex=downIndex;
  401. let aTag=aEles[curIndex];
  402. let request=(aTag, curIndex)=>{
  403. let tryTimes=0;
  404. let requestBody={
  405. method: 'GET',
  406. url: aTag.href,
  407. headers:{
  408. referer:aTag.href,
  409. "Content-Type":"text/html;charset="+document.charset
  410. },
  411. timeout:15000,
  412. overrideMimeType:"text/html;charset="+document.charset,
  413. onload: function(result) {
  414. downIndex++;
  415. downNum++;
  416. let doc = getDocEle(result.responseText);
  417. let base = doc.querySelector("base");
  418. let nextPage = !disableNextPage && checkNextPage(doc, base ? base.href : aTag.href);
  419. if(nextPage){
  420. var inArr=false;
  421. for(var ai=0;ai<aEles.length;ai++){
  422. if(aEles[ai].href==nextPage.href){
  423. inArr=true;
  424. break;
  425. }
  426. }
  427. if(!inArr){
  428. nextPage.innerText=aTag.innerText+"\t>>";
  429. aEles.push(nextPage);
  430. let targetIndex = curIndex;
  431. for(let a=0;a<insertSigns.length;a++){
  432. let signs=insertSigns[a],breakSign=false;
  433. if(signs){
  434. for(let b=0;b<signs.length;b++){
  435. let sign=signs[b];
  436. if(sign==curIndex){
  437. targetIndex=a;
  438. breakSign=true;
  439. break;
  440. }
  441. }
  442. }
  443. if(breakSign)break;
  444. }
  445. let insertSign = insertSigns[targetIndex];
  446. if(!insertSign)insertSigns[targetIndex] = [];
  447. insertSigns[targetIndex].push(aEles.length-1);
  448. }
  449. }
  450. if (result.status >= 400) {
  451. console.warn("error:", `status: ${result.status} from: ${aTag.href}`);
  452. }
  453. if (customTitle) {
  454. try {
  455. let title = doc.querySelector(customTitle);
  456. if (title && title.innerText) {
  457. aTag.innerText = title.innerText;
  458. }
  459. } catch(e) {
  460. console.warn(e);
  461. }
  462. }
  463. processDoc(curIndex, aTag, doc, (result.status>=400?` status: ${result.status} from: ${aTag.href} `:""));
  464. if (wait) {
  465. setTimeout(() => {
  466. downOnce(wait);
  467. }, wait);
  468. } else downOnce();
  469. },
  470. onerror: function(e) {
  471. console.warn("error:", e);
  472. if(++tryTimes<3){
  473. return GM_xmlhttpRequest(requestBody);
  474. }
  475. downIndex++;
  476. downNum++;
  477. processDoc(curIndex, aTag, null, ` NETWORK ERROR: '+${(e.response||e.responseText)} from: ${aTag.href} `);
  478. if (wait) {
  479. setTimeout(() => {
  480. downOnce(wait);
  481. }, wait);
  482. } else downOnce();
  483. },
  484. ontimeout: function(e) {
  485. console.warn("timeout: times="+tryTimes+" url="+aTag.href);
  486. //console.log(e);
  487. if(++tryTimes<3){
  488. return GM_xmlhttpRequest(requestBody);
  489. }
  490. downIndex++;
  491. downNum++;
  492. processDoc(curIndex, aTag, null, ` TIMEOUT: '+${aTag.href} `);
  493. if (wait) {
  494. setTimeout(() => {
  495. downOnce(wait);
  496. }, wait);
  497. } else downOnce();
  498. }
  499. };
  500. return [curIndex, GM_xmlhttpRequest(requestBody), aTag.href];
  501. }
  502. if(!aTag){
  503. let waitAtagReadyInterval=setInterval(function(){
  504. if(downNum>=aEles.length)clearInterval(waitAtagReadyInterval);
  505. aTag=aEles[curIndex];
  506. if(aTag){
  507. clearInterval(waitAtagReadyInterval);
  508. request(aTag, curIndex);
  509. }
  510. },1000);
  511. return null;
  512. }
  513. let result = request(aTag, curIndex);
  514. if (result) curRequests.push(result);
  515. return result;
  516. };
  517. function getDocEle(str){
  518. var doc = null;
  519. try {
  520. doc = document.implementation.createHTMLDocument('');
  521. doc.documentElement.innerHTML = str;
  522. }
  523. catch (e) {
  524. console.log('parse error');
  525. }
  526. return doc;
  527. }
  528. function sortInnerPage(){
  529. var pageArrs=[],maxIndex=0,i,j;
  530. for(i=0;i<insertSigns.length;i++){
  531. var signs=insertSigns[i];
  532. if(signs){
  533. for(j=0;j<signs.length;j++){
  534. var sign=signs[j];
  535. var cat=rCats[sign];
  536. rCats[sign]=null;
  537. if(!pageArrs[i])pageArrs[i]=[];
  538. pageArrs[i].push(cat);
  539. }
  540. }
  541. }
  542. for(i=pageArrs.length-1;i>=0;i--){
  543. let pageArr=pageArrs[i];
  544. if(pageArr){
  545. for(j=pageArr.length-1;j>=0;j--){
  546. rCats.splice(i+1, 0, pageArr[j]);
  547. }
  548. }
  549. }
  550. rCats = rCats.filter(function(e){return e!=null});
  551. }
  552. var waitForComplete;
  553. function processDoc(i, aTag, doc, cause){
  554. let cbFunc=content=>{
  555. rCats[i]=(aTag.innerText.replace(/[\r\n\t]/g, "") + "\r\n" + (cause || '') + content.replace(/\s*$/, ""));
  556. curRequests = curRequests.filter(function(e){return e[0]!=i});
  557. txtDownContent.style.display="block";
  558. txtDownWords.innerHTML=getI18n("downloading",[downNum,(aEles.length-downNum),aTag.innerText]);
  559. if(downNum==aEles.length){
  560. if(waitForComplete) clearTimeout(waitForComplete);
  561. waitForComplete=setTimeout(()=>{
  562. if(downNum==aEles.length){
  563. txtDownWords.innerHTML=getI18n("complete",[downNum]);
  564. sortInnerPage();
  565. saveContent();
  566. }
  567. },3000);
  568. }
  569. };
  570. let contentResult=getPageContent(doc, content=>{
  571. cbFunc(content);
  572. });
  573. if(contentResult!==false){
  574. cbFunc(contentResult);
  575. }
  576. }
  577. var downThreadNum = parseInt(GM_getValue("downThreadNum"));
  578. downThreadNum = downThreadNum || 20;
  579. if (downThreadNum > 0) {
  580. for (var i = 0; i < downThreadNum; i++) {
  581. downOnce();
  582. if (downIndex >= aEles.length - 1 || downIndex >= downThreadNum - 1) break;
  583. else downIndex++;
  584. }
  585. } else {
  586. downOnce(-downThreadNum * 1000);
  587. if (downIndex < aEles.length - 1 && downIndex < downThreadNum - 1) downIndex++;
  588. }
  589.  
  590. /*for(let i=0;i<aEles.length;i++){
  591. let aTag=aEles[i];
  592. GM_xmlhttpRequest({
  593. method: 'GET',
  594. url: aTag.href,
  595. overrideMimeType:"text/html;charset="+document.charset,
  596. onload: function(result) {
  597. var doc = getDocEle(result.responseText);
  598. processDoc(i, aTag, doc);
  599. }
  600. });
  601. }*/
  602. }
  603.  
  604. function canonicalUri(src, baseUrl) {
  605. if (!src) {
  606. return "";
  607. }
  608. if (src.charAt(0) == "#") return baseUrl + src;
  609. if (src.charAt(0) == "?") return baseUrl.replace(/^([^\?#]+).*/, "$1" + src);
  610. let origin = location.protocol + '//' + location.host;
  611. let url = baseUrl || origin;
  612. url = url.replace(/(\?|#).*/, "");
  613. if (/https?:\/\/[^\/]+$/.test(url)) url = url + '/';
  614. if (url.indexOf("http") !== 0) url = origin + url;
  615. var root_page = /^[^\?#]*\//.exec(url)[0],
  616. root_domain = /^\w+\:\/\/\/?[^\/]+/.exec(root_page)[0],
  617. absolute_regex = /^\w+\:\/\//;
  618. while (src.indexOf("../") === 0) {
  619. src = src.substr(3);
  620. root_page = root_page.replace(/\/[^\/]+\/$/, "/");
  621. }
  622. src = src.replace(/\.\//, "");
  623. if (/^\/\/\/?/.test(src)) {
  624. src = location.protocol + src;
  625. }
  626. return (absolute_regex.test(src) ? src : ((src.charAt(0) == "/" ? root_domain : root_page) + src));
  627. }
  628.  
  629. function checkNextPage(doc, baseUrl) {
  630. let aTags = doc.querySelectorAll("a"), nextPage = null;
  631. for (var i = 0; i < aTags.length; i++) {
  632. let aTag = aTags[i];
  633. if (innerNextPage.test(aTag.innerText) && aTag.href && !/javascript:|#/.test(aTag.href)) {
  634. let nextPageHref = canonicalUri(aTag.getAttribute("href"), baseUrl || location.href);
  635. if (nextPageHref != location.href) {
  636. nextPage = aTag;
  637. nextPage.href = nextPageHref;
  638. break;
  639. }
  640. }
  641. }
  642. return nextPage;
  643. }
  644.  
  645. function textNodesUnder(el){
  646. var n, a=[], walk=document.createTreeWalker(el,NodeFilter.SHOW_TEXT,null,false);
  647. while(n=walk.nextNode()) a.push(n);
  648. return a;
  649. }
  650.  
  651. function getPageContent(doc, cb){
  652. if(!doc)return i18n.error;
  653. if(processFunc){
  654. return processFunc(doc, cb);
  655. }
  656. [].forEach.call(doc.querySelectorAll("span,div,ul"),function(item){
  657. var thisStyle=doc.defaultView?doc.defaultView.getComputedStyle(item):item.style;
  658. if(thisStyle && (thisStyle.display=="none" || (item.nodeName=="SPAN" && thisStyle.fontSize=="0px"))){
  659. item.innerHTML="";
  660. }
  661. });
  662. var i,j,k,rStr="",pageData=(doc.body?doc.body:doc).cloneNode(true),delList=[];
  663. pageData.innerHTML=pageData.innerHTML.replace(/\<\!\-\-((.|[\n|\r|\r\n])*?)\-\-\>/g,"");
  664. [].forEach.call(pageData.querySelectorAll("font.jammer"),function(item){
  665. item.innerHTML="";
  666. });
  667. var selectors=GM_getValue("selectors");
  668. if(selectors){
  669. [].forEach.call(pageData.querySelectorAll(selectors),function(item){
  670. item.innerHTML="";
  671. });
  672. }
  673. [].forEach.call(pageData.querySelectorAll("script,style,link,img,noscript,iframe"),function(item){delList.push(item);});
  674. [].forEach.call(delList,function(item){item.innerHTML="";});
  675. var endEle = ele => {
  676. return /^(I|STRONG|B|FONT|P|DL|DD|H\d)$/.test(ele.nodeName) && ele.children.length == 0;
  677. };
  678. var largestContent,contents=pageData.querySelectorAll("span,div,article,p,td"),largestNum=0;
  679. for(i=0;i<contents.length;i++){
  680. let content=contents[i],hasText=false,allSingle=true,item,curNum=0;
  681. for(j=content.childNodes.length-1;j>=0;j--){
  682. item=content.childNodes[j];
  683. if(item.nodeType==3){
  684. if(/^\s*$/.test(item.data))
  685. item.innerHTML="";
  686. else hasText=true;
  687. }else if(/^(I|A|STRONG|B|FONT|P|DL|DD|H\d)$/.test(item.nodeName)){
  688. hasText=true;
  689. }else if(item.nodeType==1&&item.children.length==1&&/^(I|A|STRONG|B|FONT|P|DL|DD|H\d)$/.test(item.children[0].nodeName)){
  690. hasText=true;
  691. }
  692. }
  693. for(j=content.childNodes.length-1;j>=0;j--){
  694. item=content.childNodes[j];
  695. if(item.nodeType==1 && !/^(I|A|STRONG|B|FONT|BR)$/.test(item.nodeName) && /^[\s\-\_\?\>\|]*$/.test(item.innerHTML))
  696. item.innerHTML="";
  697. }
  698. if(content.childNodes.length>1){
  699. let indexItem=0;
  700. for(j=0;j<content.childNodes.length;j++){
  701. item=content.childNodes[j];
  702. if(item.nodeType==1){
  703. if(item.innerText && item.innerText.length<50 && indexReg.test(item.innerText))indexItem++;
  704. for(k=0;k<item.childNodes.length;k++){
  705. var childNode=item.childNodes[k];
  706. if(childNode.nodeType!=3 && !/^(I|A|STRONG|B|FONT|BR)$/.test(childNode.nodeName)){
  707. allSingle=false;
  708. break;
  709. }
  710. }
  711. if(!allSingle)break;
  712. }
  713. }
  714. if(indexItem>=5)continue;
  715. }else{
  716. allSingle=false;
  717. }
  718. if(!allSingle && !hasText){
  719. continue;
  720. }else {
  721. if(pageData==document && content.offsetWidth<=0 && content.offsetHeight<=0)
  722. continue;
  723. [].forEach.call(content.childNodes,function(item){
  724. if(item.nodeType==3)curNum+=item.data.trim().length;
  725. 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);
  726. });
  727. }
  728. if(curNum>largestNum){
  729. largestNum=curNum;
  730. largestContent=content;
  731. }
  732. }
  733. if(!largestContent)return i18n.error+" : NO TEXT CONTENT";
  734. var childlist=pageData.querySelectorAll(largestContent.nodeName);//+(largestContent.className?"."+largestContent.className.replace(/(^\s*)|(\s*$)/g, '').replace(/\s+/g, '.'):""));
  735. function getRightStr(ele, noTextEnable){
  736. let childNodes=ele.childNodes,cStr="\r\n",hasText=false;
  737. [].forEach.call(ele.querySelectorAll("a[href]"), a => {
  738. a.parentNode && a.parentNode.removeChild(a);
  739. });
  740. for(let j=0;j<childNodes.length;j++){
  741. let childNode=childNodes[j];
  742. if(childNode.nodeType==3 && childNode.data && !/^[\s\-\_\?\>\|]*$/.test(childNode.data))hasText=true;
  743. if(childNode.innerHTML){
  744. childNode.innerHTML=childNode.innerHTML.replace(/\<\s*br\s*\>/gi,"\r\n").replace(/\n+/gi,"\n").replace(/\r+/gi,"\r");
  745. }
  746. if(childNode.textContent){
  747. cStr+=childNode.textContent.replace(/ +/g," ").replace(/([^\r]|^)\n([^\r]|$)/gi,"$1\r\n$2");
  748. }
  749. if(childNode.nodeType!=3 && !/^(I|A|STRONG|B|FONT)$/.test(childNode.nodeName))cStr+="\r\n";
  750. }
  751. if(hasText || noTextEnable || ele==largestContent)rStr+=cStr+"\r\n";
  752. }
  753. for(i=0;i<childlist.length;i++){
  754. var child=childlist[i];
  755. if(getDepth(child)==getDepth(largestContent)){
  756. if(largestContent.className != child.className)continue;
  757. if((largestContent.className && largestContent.className == child.className) || largestContent.parentNode == child.parentNode){
  758. getRightStr(child, true);
  759. }else {
  760. getRightStr(child, false);
  761. }
  762. }
  763. }
  764. return rStr.replace(/[\n\r]+/g,"\n\r");
  765. }
  766.  
  767. function getI18n(key, args){
  768. var resultStr=i18n[key];
  769. if(args && args.length>0){
  770. args.forEach(function(item){
  771. resultStr=resultStr.replace(/%s/,item);
  772. });
  773. }
  774. return resultStr;
  775. }
  776.  
  777. function getDepth(dom){
  778. var pa=dom,i=0;
  779. while(pa.parentNode){
  780. pa=pa.parentNode;
  781. i++;
  782. }
  783. return i;
  784. }
  785.  
  786. function fetch(forceSingle){
  787. forceSingle=forceSingle===true;
  788. processFunc=null;
  789. var aEles=document.body.querySelectorAll("a"),list=[];
  790. for(var i=0;i<aEles.length;i++){
  791. var aEle=aEles[i],has=false;
  792. if((!aEle.href || aEle.href.indexOf("javascript")!=-1) && aEle.dataset.href){
  793. aEle.href=aEle.dataset.href;
  794. }
  795. if(aEle.href==location.href)continue;
  796. for(var j=0;j<list.length;j++){
  797. if(list[j].href==aEle.href){
  798. aEle=list[j];
  799. list.splice(j,1);
  800. list.push(aEle);
  801. has=true;
  802. break;
  803. }
  804. }
  805. if(!has && aEle.href && /^http/i.test(aEle.href) && ((aEle.innerText.trim()!="" && indexReg.test(aEle.innerText.trim())) || /chapter[\-_]?\d/.test(aEle.href))){
  806. list.push(aEle);
  807. }
  808. }
  809. if(list.length>2 && !forceSingle){
  810. indexDownload(list);
  811. }else{
  812. var blob = new Blob([i18n.info+"\r\n\r\n"+document.title+"\r\n\r\n"+getPageContent(document)], {type: "text/plain;charset=utf-8"});
  813. saveAs(blob, document.title+".txt");
  814. }
  815. }
  816.  
  817. function customDown(){
  818. processFunc=null;
  819. var customRules=GM_getValue("DACrules_"+document.domain);
  820. var urls=window.prompt(i18n.customInfo,customRules?customRules:"https://xxx.xxx/book-[20-99].html, https://xxx.xxx/book-[01-10].html");
  821. if(urls){
  822. urls=decodeURIComponent(urls.replace(/%/g,'%25'));
  823. GM_setValue("DACrules_"+document.domain, urls);
  824. var processEles=[];
  825. let urlsArr=urls.split("@@"),eles=[];
  826. if(/^http|^ftp/.test(urlsArr[0])){
  827. [].forEach.call(urlsArr[0].split(","),function(i){
  828. var curEle;
  829. var varNum=/\[\d+\-\d+\]/.exec(i);
  830. if(varNum){
  831. varNum=varNum[0].trim();
  832. }else{
  833. curEle=document.createElement("a");
  834. curEle.href=i;
  835. processEles.push(curEle);
  836. return;
  837. }
  838. var num1=/\[(\d+)/.exec(varNum)[1].trim();
  839. var num2=/(\d+)\]/.exec(varNum)[1].trim();
  840. var num1Int=parseInt(num1);
  841. var num2Int=parseInt(num2);
  842. var numLen=num1.length;
  843. var needAdd=num1.charAt(0)=="0";
  844. if(num1Int>=num2Int)return;
  845. for(var j=num1Int;j<=num2Int;j++){
  846. var urlIndex=j.toString();
  847. if(needAdd){
  848. while(urlIndex.length<numLen)urlIndex="0"+urlIndex;
  849. }
  850. var curUrl=i.replace(/\[\d+\-\d+\]/,urlIndex).trim();
  851. curEle=document.createElement("a");
  852. curEle.href=curUrl;
  853. curEle.innerText=processEles.length.toString();
  854. processEles.push(curEle);
  855. }
  856. });
  857. }else{
  858. let urlSel=urlsArr[0].split(">>");
  859. try{
  860. eles=document.querySelectorAll(urlSel[0]);
  861. eles=[].filter.call(eles, ele=>{
  862. return ele.nodeName=='BODY'||(!!ele.offsetParent&&getComputedStyle(ele).display!=='none');
  863. })
  864. }catch(e){}
  865. if(eles.length==0){
  866. eles=[];
  867. var eleTxts=urlsArr[0].split(/(?<=[^\\])[,,]/),exmpEles=[],excludeTxts={};
  868. [].forEach.call(document.querySelectorAll("a"),function(item){
  869. eleTxts.forEach(txt=>{
  870. var txtArr=txt.split("!");
  871. if(item.innerText.indexOf(txtArr[0])!=-1){
  872. exmpEles.push(item);
  873. excludeTxts[item]=txtArr.splice(1);
  874. }
  875. });
  876. })
  877. exmpEles.forEach(e=>{
  878. var cssSelStr="a",pa=e.parentNode,excludeTxt=excludeTxts[e];
  879. if(e.className)cssSelStr+="."+CSS.escape(e.className);
  880. while(pa && pa.nodeName!="BODY"){
  881. cssSelStr=pa.nodeName+">"+cssSelStr;
  882. pa=pa.parentNode;
  883. }
  884. [].forEach.call(document.querySelectorAll(cssSelStr),function(item){
  885. var isExclude=false;
  886. for(var t in excludeTxt){
  887. if(item.innerText.indexOf(excludeTxt[t])!=-1){
  888. isExclude=true;
  889. break;
  890. }
  891. }
  892. if(!isExclude && eles.indexOf(item)==-1){
  893. eles.push(item);
  894. }
  895. });
  896. });
  897. }
  898. function addItem(item) {
  899. let has=false;
  900. for(var j=0;j<processEles.length;j++){
  901. if(processEles[j].href==item.href){
  902. processEles.splice(j,1);
  903. processEles.push(item);
  904. has=true;
  905. break;
  906. }
  907. }
  908. if((!item.href || item.href.indexOf("javascript")!=-1) && item.dataset.href){
  909. item.href=item.dataset.href;
  910. }
  911. if(!has && item.href && /^http/i.test(item.href)){
  912. processEles.push(item.cloneNode(1));
  913. }
  914. }
  915. [].forEach.call(eles,function(item){
  916. if(urlSel[1]){
  917. item=Function("item",urlSel[1])(item);
  918. let items;
  919. if (Array.isArray(item)) {
  920. items = item;
  921. } else items = [item];
  922. items.forEach(item => {
  923. if(!item || !item.href)return;
  924. if(!item.nodeName || item.nodeName!="A"){
  925. let href=item.href;
  926. let innerText=item.innerText;
  927. item=document.createElement("a");
  928. item.href=href;
  929. item.innerText=innerText;
  930. }
  931. addItem(item);
  932. });
  933. } else {
  934. addItem(item);
  935. }
  936. });
  937. }
  938. if(urlsArr[1]){
  939. processEles.forEach(ele=>{
  940. ele.href=ele.href.replace(new RegExp(urlsArr[1]), urlsArr[2]);
  941. });
  942. }
  943. if(urlsArr[3]){
  944. processFunc=(data, cb)=>{
  945. let doc=data;
  946. if(urlsArr[3].indexOf("return ")==-1){
  947. if(urlsArr[3].indexOf("@")==0){
  948. let content="";
  949. [].forEach.call(data.querySelectorAll(urlsArr[3].slice(1)), ele=>{
  950. [].forEach.call(ele.childNodes, child=>{
  951. if(child.innerHTML){
  952. child.innerHTML=child.innerHTML.replace(/\<\s*br\s*\>/gi,"\r\n").replace(/\n+/gi,"\n").replace(/\r+/gi,"\r");
  953. }
  954. if(child.textContent){
  955. content+=(child.textContent.replace(/ +/g," ").replace(/([^\r]|^)\n([^\r]|$)/gi,"$1\r\n$2")+"\r\n");
  956. }
  957. });
  958. content+="\r\n";
  959. });
  960. return content;
  961. }else return eval(urlsArr[3]);
  962. }else{
  963. return Function("data", "doc", "cb",urlsArr[3])(data, doc, cb);
  964. }
  965. };
  966. }else{
  967. if(win.dacProcess){
  968. processFunc=win.dacProcess;
  969. }
  970. }
  971. indexDownload(processEles);
  972. }
  973. }
  974. const configPage = "https://hoothin.github.io/UserScripts/DownloadAllContent/";
  975. 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>';
  976. function searchRule(){
  977. GM_openInTab(configPage + "#@" + location.hostname, {active: true});
  978. }
  979. if (location.origin + location.pathname == configPage) {
  980. let exampleNode = document.getElementById("example");
  981. if (!exampleNode) return;
  982.  
  983. exampleNode = exampleNode.parentNode;
  984. let ruleList = exampleNode.nextElementSibling.nextElementSibling;
  985. let searchInput = document.createElement("input");
  986. let inputTimer;
  987. function searchByInput() {
  988. clearTimeout(inputTimer);
  989. inputTimer = setTimeout(() => {
  990. let curValue = searchInput.value;
  991. let matchRules = [];
  992. let dontMatchRules = [];
  993. if (curValue) {
  994. for (let i = 0; i < ruleList.children.length; i++) {
  995. let curRule = ruleList.children[i];
  996. let aHref = curRule.firstChild.href;
  997. if (aHref.indexOf(curValue) == -1) {
  998. dontMatchRules.push(curRule);
  999. } else {
  1000. matchRules.push(curRule);
  1001. }
  1002. }
  1003. } else {
  1004. dontMatchRules = ruleList.children;
  1005. }
  1006. if (matchRules.length) {
  1007. for (let i = 0; i < dontMatchRules.length; i++) {
  1008. let curRule = dontMatchRules[i];
  1009. curRule.style.display = "none";
  1010. }
  1011. for (let i = 0; i < matchRules.length; i++) {
  1012. let curRule = matchRules[i];
  1013. curRule.style.display = "";
  1014. }
  1015. } else {
  1016. for (let i = 0; i < dontMatchRules.length; i++) {
  1017. let curRule = dontMatchRules[i];
  1018. curRule.style.display = "";
  1019. }
  1020. }
  1021. }, 500);
  1022. }
  1023. searchInput.style.margin = "10px";
  1024. searchInput.style.width = "100%";
  1025. searchInput.placeholder = i18n.searchRule;
  1026. searchInput.addEventListener("input", function(e) {
  1027. searchByInput();
  1028. });
  1029. if (location.hash) {
  1030. let hash = location.hash.slice(1);
  1031. if (hash.indexOf("@") == 0) {
  1032. setTimeout(() => {
  1033. exampleNode.scrollIntoView();
  1034. }, 500);
  1035. searchInput.value = hash.slice(1);
  1036. searchByInput();
  1037. }
  1038. }
  1039. [].forEach.call(ruleList.querySelectorAll("div.highlight"), highlight => {
  1040. highlight.style.position = "relative";
  1041. highlight.innerHTML = highlight.innerHTML + copySvg;
  1042. let svg = highlight.children[1];
  1043. svg.addEventListener("click", function(e) {
  1044. GM_setClipboard(highlight.children[0].innerText);
  1045. svg.style.opacity = 0;
  1046. setTimeout(() => {
  1047. svg.style.opacity = 1;
  1048. }, 1000);
  1049. });
  1050. });
  1051. exampleNode.parentNode.insertBefore(searchInput, ruleList);
  1052.  
  1053.  
  1054. let donateNode = document.querySelector("[alt='donate']");
  1055. if (!donateNode) return;
  1056. let insertPos = donateNode.parentNode.nextElementSibling;
  1057. let radioIndex = 0;
  1058. function createOption(_name, _value, _type) {
  1059. if (!_type) _type = "input";
  1060. let con = document.createElement("div");
  1061. let option = document.createElement("input");
  1062. let cap = document.createElement("b");
  1063. option.type = _type;
  1064. option.value = _value;
  1065. option.checked = _value;
  1066. cap.style.margin = "0px 10px 0px 0px";
  1067. if (_type == "radio") {
  1068. let label = document.createElement("label");
  1069. label.innerText = _name;
  1070. radioIndex++;
  1071. option.id = "radio" + radioIndex;
  1072. label.setAttribute("for", option.id);
  1073. cap.appendChild(label);
  1074. } else {
  1075. if (_type == "input") {
  1076. option.style.flexGrow = "1";
  1077. }
  1078. cap.innerText = _name;
  1079. }
  1080. con.style.margin = "10px 0";
  1081. con.style.display = "flex";
  1082. con.style.alignItems = "center";
  1083. con.appendChild(cap);
  1084. con.appendChild(option);
  1085. insertPos.parentNode.insertBefore(con, insertPos);
  1086. return option;
  1087. }
  1088. let delSelector = createOption(i18n.del, GM_getValue("selectors") || "");
  1089. delSelector.setAttribute("placeHolder", ".mask,.ksam");
  1090. let downThreadNum = createOption(i18n.downThreadNum, GM_getValue("downThreadNum") || "20", "number");
  1091. let customTitle = createOption(i18n.customTitle, GM_getValue("customTitle") || "");
  1092. customTitle.setAttribute("placeHolder", "title");
  1093. let contentSortUrlValue = GM_getValue("contentSortUrl") || false;
  1094. let contentSortValue = GM_getValue("contentSort") || false;
  1095. let reSortDefault = createOption(i18n.reSortDefault, !contentSortUrlValue && !contentSortValue, "radio");
  1096. let reSortUrl = createOption(i18n.reSortUrl, contentSortUrlValue || false, "radio");
  1097. let contentSort = createOption(i18n.reSort, contentSortValue || false, "radio");
  1098. reSortDefault.name = "sort";
  1099. reSortUrl.name = "sort";
  1100. contentSort.name = "sort";
  1101. let reverse = createOption(i18n.reverse, !!GM_getValue("reverse"), "checkbox");
  1102. let disableNextPage = !!GM_getValue("disableNextPage");
  1103. let nextPage = createOption(i18n.nextPage, !disableNextPage, "checkbox");
  1104. let nextPageReg = createOption(i18n.nextPageReg, GM_getValue("nextPageReg") || "");
  1105. nextPageReg.setAttribute("placeHolder", "^\\s*(下一[页頁张張]|next\\s*page|次のページ)");
  1106. if (disableNextPage) {
  1107. nextPageReg.parentNode.style.display = "none";
  1108. }
  1109. nextPage.onclick = e => {
  1110. nextPageReg.parentNode.style.display = nextPage.checked ? "flex" : "none";
  1111. }
  1112. let saveBtn = document.createElement("button");
  1113. saveBtn.innerText = i18n.saveBtn;
  1114. saveBtn.style.margin = "0 0 20px 0";
  1115. insertPos.parentNode.insertBefore(saveBtn, insertPos);
  1116. saveBtn.onclick = e => {
  1117. GM_setValue("selectors", delSelector.value || "");
  1118. GM_setValue("downThreadNum", downThreadNum.value || 20);
  1119. GM_setValue("customTitle", customTitle.value || "");
  1120. if (reSortUrl.checked) {
  1121. GM_setValue("contentSortUrl", true);
  1122. GM_setValue("contentSort", false);
  1123. } else if (contentSort.checked) {
  1124. GM_setValue("contentSortUrl", false);
  1125. GM_setValue("contentSort", true);
  1126. } else {
  1127. GM_setValue("contentSortUrl", false);
  1128. GM_setValue("contentSort", false);
  1129. }
  1130. GM_setValue("reverse", reverse.checked);
  1131. GM_setValue("disableNextPage", !nextPage.checked);
  1132. GM_setValue("nextPageReg", nextPageReg.value || "");
  1133. alert(i18n.saveOk);
  1134. };
  1135. return;
  1136. }
  1137.  
  1138. function setDel(){
  1139. GM_openInTab(configPage + "#操作說明", {active: true});
  1140. return;
  1141. /*var selValue=GM_getValue("selectors");
  1142. var selectors=prompt(i18n.del,selValue?selValue:"");
  1143. GM_setValue("selectors",selectors);
  1144. selValue=GM_getValue("downThreadNum");
  1145. var downThreadNum=prompt(i18n.downThreadNum,selValue?selValue:"20");
  1146. GM_setValue("downThreadNum",downThreadNum);
  1147. var sortByUrl=window.confirm(i18n.reSortUrl);
  1148. GM_setValue("contentSortUrl",sortByUrl);
  1149. if(!sortByUrl)GM_setValue("contentSort",window.confirm(i18n.reSort));*/
  1150. }
  1151.  
  1152. document.addEventListener("keydown", function(e) {
  1153. if(e.keyCode == 120 && e.ctrlKey) {
  1154. fetch(e.shiftKey);
  1155. }
  1156. });
  1157. GM_registerMenuCommand(i18n.fetch, fetch);
  1158. GM_registerMenuCommand(i18n.custom, customDown);
  1159. GM_registerMenuCommand(i18n.setting, setDel);
  1160. GM_registerMenuCommand(i18n.searchRule, searchRule);
  1161. })();