自动无缝翻页

自动无缝翻页,目前支持:423Down、Apphot、不死鸟、小众软件、异次元软件、FitGirl Repacks、AlphaCoders、PubMed、三国杀论坛、百分浏览器论坛

当前为 2021-04-28 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name 自动无缝翻页
  3. // @version 1.2.0
  4. // @author X.I.U
  5. // @description 自动无缝翻页,目前支持:423Down、Apphot、不死鸟、小众软件、异次元软件、FitGirl Repacks、AlphaCoders、PubMed、三国杀论坛、百分浏览器论坛
  6. // @match *://www.423down.com/*
  7. // @exclude *://www.423down.com/*.html
  8. // @match *://apphot.cc/*
  9. // @exclude *://apphot.cc/*.html
  10. // @match *://iao.su/*
  11. // @match *://www.appinn.com/
  12. // @match *://www.appinn.com/*/*/
  13. // @match *://www.appinn.com/?s=*
  14. // @match *://www.iplaysoft.com/*
  15. // @match *://fitgirl-repacks.site/*
  16. // @match *://*.alphacoders.com/*
  17. // @match *://club.sanguosha.com/*
  18. // @match *://www.centbrowser.net/*
  19. // @match *://pubmed.ncbi.nlm.nih.gov/?term=*
  20. // @icon https://i.loli.net/2021/03/07/rdijeYm83pznxWq.png
  21. // @grant GM_xmlhttpRequest
  22. // @grant GM_registerMenuCommand
  23. // @grant GM_openInTab
  24. // @license GPL-3.0 License
  25. // @run-at document-end
  26. // @namespace https://github.com/XIU2/UserScript
  27. // ==/UserScript==
  28.  
  29. (function() {
  30. // 注册脚本菜单
  31. GM_registerMenuCommand('反馈 & 欢迎申请支持', function () {window.GM_openInTab('https://github.com/XIU2/UserScript#xiu2userscript', {active: true,insert: true,setParent: true});window.GM_openInTab('https://greasyfork.org/zh-CN/scripts/419215/feedback', {active: true,insert: true,setParent: true});});
  32.  
  33. // 默认 ID 为 0
  34. var curSite = {SiteTypeID: 0};
  35.  
  36. // 自动翻页规则
  37. // type:1 = 脚本实现自动无缝翻页,2 = 网站自带了自动无缝翻页功能,只需要点击下一页按钮即可,这时 nextText 为按钮文本,避免一瞬间加载太多次下一页
  38. // HT_insert:1 = 插入该元素本身的前面;2 = 插入该元素当中,第一个子元素前面;3 = 插入该元素当中,最后一个子元素后面;4 = 插入该元素本身的后面;
  39. // scrollDelta:数值越大,滚动条触发点越靠上(越早开始翻页),一般是访问网页速度越慢,该值就需要越大
  40. // function:before = 插入前执行函数;after = 插入后执行函数;parameter = 参数
  41. let DBSite = {
  42. _423down_postslist: {
  43. SiteTypeID: 1,
  44. pager: {
  45. type: 1,
  46. nextLink: '//div[@class="paging"]//a[contains(text(),"下一页")][@href]',
  47. pageElement: 'css;div.content-wrap ul.excerpt > li',
  48. HT_insert: ['css;div.content-wrap ul.excerpt', 3],
  49. replaceE: 'css;div.paging',
  50. scrollDelta: 1500
  51. }
  52. },
  53. apphot_postslist: {
  54. SiteTypeID: 2,
  55. pager: {
  56. type: 1,
  57. nextLink: '//div[@class="pagination"]//a[contains(text(),"下一页")][@href]',
  58. pageElement: 'css;div.content > article.excerpt',
  59. HT_insert: ['css;div.pagination', 1],
  60. replaceE: 'css;div.pagination',
  61. scrollDelta: 1500
  62. }
  63. },
  64. iao_su_postslist: {
  65. SiteTypeID: 3,
  66. pager: {
  67. type: 1,
  68. nextLink: '//li[@class="btn btn-primary next"]//a[@href]',
  69. pageElement: 'css;#index > article, #archive > article',
  70. HT_insert: ['css;ol.page-navigator', 1],
  71. replaceE: 'css;ol.page-navigator',
  72. scrollDelta: 800
  73. },
  74. function: {
  75. before: iao_su_postslist_beforeFunction
  76. }
  77. },
  78. appinn_postslist: {
  79. SiteTypeID: 4,
  80. pager: {
  81. type: 1,
  82. nextLink: '//a[@class="next page-numbers"][@href]',
  83. pageElement: 'css;section#latest-posts > article',
  84. HT_insert: ['css;nav.navigation.pagination', 1],
  85. replaceE: 'css;div.nav-links',
  86. scrollDelta: 1500
  87. }
  88. },
  89. iplaysoft_postslist: {
  90. SiteTypeID: 5,
  91. pager: {
  92. type: 1,
  93. nextLink: '//div[@class="pagenavi"]//a[@title="下一页"][@href]',
  94. pageElement: 'css;#postlist > div.entry',
  95. HT_insert: ['css;#postlist > .pagenavi-button', 1],
  96. replaceE: 'css;.pagenavi-button, .pagenavi',
  97. scrollDelta: 1200
  98. },
  99. function: {
  100. before: iplaysoft_postslist_beforeFunction
  101. }
  102. },
  103. iplaysoft_postcomments: {
  104. SiteTypeID: 6,
  105. pager: {
  106. type: 2,
  107. nextLink: '#loadHistoryComments',
  108. nextText: '展开后面',
  109. scrollDelta: 1200
  110. }
  111. },
  112. discuz_forum: {
  113. SiteTypeID: 7,
  114. pager: {
  115. type: 2,
  116. nextLink: '#autopbn',
  117. nextText: '下一页 »',
  118. scrollDelta: 1000
  119. }
  120. },
  121. discuz_thread: {
  122. SiteTypeID: 8,
  123. pager: {
  124. type: 1,
  125. nextLink: '//a[@class="nxt"][@href]',
  126. pageElement: 'css;div#postlist > div[id^="post_"]',
  127. HT_insert: ['css;div#postlist', 3],
  128. replaceE: 'css;div.pg',
  129. scrollDelta: 1000
  130. }
  131. },
  132. discuz_search: {
  133. SiteTypeID: 9,
  134. pager: {
  135. type: 1,
  136. nextLink: '//a[@class="nxt"][@href]',
  137. pageElement: 'css;div#threadlist > ul',
  138. HT_insert: ['css;div#threadlist', 3],
  139. replaceE: 'css;div.pg',
  140. scrollDelta: 1000
  141. }
  142. },
  143. pubmed_postslist: {
  144. SiteTypeID: 10,
  145. pager: {
  146. type: 2,
  147. nextLink: 'button.load-button.next-page',
  148. nextText: 'Show more',
  149. scrollDelta: 1500
  150. }
  151. },
  152. wall_alphacoders: {
  153. SiteTypeID: 11,
  154. pager: {
  155. type: 1,
  156. nextLink: '//a[@id="next_page"][@href]',
  157. pageElement: 'css;.thumb-container-big, .avatar-thumb, .thumb-element',
  158. HT_insert: ['css;.thumb-container-big:nth-last-child(1), .avatar-thumb:nth-last-child(1), .thumb-element:nth-last-child(1)', 4],
  159. replaceE: '//div[@class="hidden-xs hidden-sm"]/..',
  160. scrollDelta: 1000
  161. }
  162. },
  163. art_alphacoders: {
  164. SiteTypeID: 12,
  165. pager: {
  166. type: 1,
  167. nextLink: '//a[@id="next_page"][@href]',
  168. pageElement: 'css;.container-masonry > div',
  169. HT_insert: ['css;.container-masonry', 3],
  170. replaceE: '//div[@class="hidden-xs hidden-sm"]/..',
  171. scrollDelta: 1000
  172. },
  173. function: {
  174. before: art_alphacoders_beforeFunction
  175. }
  176. },
  177. fitgirl: {
  178. SiteTypeID: 13,
  179. pager: {
  180. type: 1,
  181. nextLink: '//a[@class="next page-numbers"][@href]',
  182. pageElement: 'css;article[id^="post-"]',
  183. HT_insert: ['css;nav.navigation.paging-navigation', 1],
  184. replaceE: 'css;nav.navigation.paging-navigation',
  185. scrollDelta: 2000
  186. }
  187. }
  188. };
  189.  
  190.  
  191. switch (location.host) {
  192. case "www.423down.com":
  193. curSite = DBSite._423down_postslist;
  194. break;
  195. case "apphot.cc":
  196. curSite = DBSite.apphot_postslist;
  197. break;
  198. case "iao.su":
  199. curSite = DBSite.iao_su_postslist;
  200. break;
  201. case "www.appinn.com":
  202. curSite = DBSite.appinn_postslist;
  203. break;
  204. case "www.iplaysoft.com":
  205. if (location.pathname.indexOf(".html") > -1 || location.pathname.indexOf("/p/") > -1) { // 文章内
  206. curSite = DBSite.iplaysoft_postcomments;
  207. } else { // 其他页面
  208. curSite = DBSite.iplaysoft_postslist;
  209. }
  210. break;
  211. case "fitgirl-repacks.site":
  212. curSite = DBSite.fitgirl;
  213. break;
  214. case "art.alphacoders.com":
  215. curSite = DBSite.art_alphacoders;
  216. setTimeout(art_alphacoders_beforeFunction_0, 1000);
  217. break;
  218. case "wall.alphacoders.com":
  219. case "avatars.alphacoders.com":
  220. case "mobile.alphacoders.com":
  221. curSite = DBSite.wall_alphacoders;
  222. break;
  223. case "club.sanguosha.com": // Discuz! 论坛专用
  224. case "www.centbrowser.net":
  225. if (location.pathname.indexOf('.html') > -1) { // 判断是不是静态网页(.html 结尾)
  226. if (location.pathname.indexOf('forum') > -1) { // 各版块帖子列表
  227. curSite = DBSite.discuz_forum;
  228. } else if (location.pathname.indexOf('thread') > -1) { // 帖子内
  229. curSite = DBSite.discuz_thread;
  230. hidePgbtn(); // 隐藏帖子内的 [下一页] 按钮
  231. }else if(location.pathname.indexOf('search') > -1) { // 搜索结果
  232. curSite = DBSite.discuz_search;
  233. }
  234. } else {
  235. if (location.search.indexOf('mod=forumdisplay') > -1) { // 各版块帖子列表
  236. curSite = DBSite.discuz_forum;
  237. } else if (location.search.indexOf('mod=viewthread') > -1) { // 帖子内
  238. curSite = DBSite.discuz_thread;
  239. hidePgbtn(); // 隐藏帖子内的 [下一页] 按钮
  240. } else if (location.pathname.indexOf('search') > -1) { // 搜索结果
  241. curSite = DBSite.discuz_search;
  242. }
  243. }
  244. break;
  245. case "pubmed.ncbi.nlm.nih.gov":
  246. curSite = DBSite.pubmed_postslist;
  247. break;
  248. }
  249. curSite.pageUrl = ""; // 下一页URL
  250. pageLoading(); // 自动无缝翻页
  251.  
  252.  
  253. // 自动无缝翻页
  254. function pageLoading() {
  255. if (curSite.SiteTypeID > 0) {
  256. windowScroll(function (direction, e) {
  257. if (direction === "down") { // 下滑才准备翻页
  258. let scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
  259. let scrollDelta = curSite.pager.scrollDelta;
  260. if (document.documentElement.scrollHeight <= document.documentElement.clientHeight + scrollTop + scrollDelta) {
  261. if (curSite.pager.type === 1) {
  262. ShowPager.loadMorePage();
  263. } else {
  264. let autopbn = document.querySelector(curSite.pager.nextLink);
  265. if (autopbn) { // 如果正在加载,就不再点击
  266. if (!curSite.pager.nextText) { // 如果没有指定 nextText 就直接点击
  267. autopbn.click();
  268. } else if (autopbn.innerText.indexOf(curSite.pager.nextText) > -1){ // 如果指定了 nextText 就需要判断后再点击(避免已经在加载了,还重复点击)
  269. autopbn.click();
  270. }
  271. }
  272. }
  273. }
  274. }
  275. });
  276. }
  277. }
  278.  
  279.  
  280. // 隐藏帖子内的 [下一页] 按钮
  281. function hidePgbtn() {
  282. let style_hidePgbtn = document.createElement('style');
  283. style_hidePgbtn.innerHTML = `.pgbtn {display: none;}`;
  284. document.head.appendChild(style_hidePgbtn);
  285. }
  286.  
  287.  
  288. // iplaysoft 的插入前函数
  289. function iplaysoft_postslist_beforeFunction(pageElems) {
  290. pageElems.forEach(function (one) {
  291. let now = one.querySelector("img.lazyload")
  292. if (now && !now.getAttribute('src')) {
  293. now.setAttribute("src",now.getAttribute('data-src'))
  294. now.setAttribute("srcset",now.getAttribute('data-src'))
  295. now.setAttribute("class","lazyloaded")
  296. }
  297. });
  298. return pageElems
  299. }
  300.  
  301.  
  302. // iao.su 的插入前函数
  303. function iao_su_postslist_beforeFunction(pageElems) {
  304. pageElems.forEach(function (one) {
  305. let now = one.getElementsByClassName("post-card")[0]
  306. if (now) {
  307. now.getElementsByClassName("blog-background")[0].style.backgroundImage = 'url("' + RegExp("(?<=loadBannerDirect\\(').*(?=', '',)").exec(now.getElementsByTagName("script")[0].innerText)[0]; + '")';
  308. }
  309. });
  310. return pageElems
  311. }
  312.  
  313.  
  314. // art_alphacoders
  315. function art_alphacoders_beforeFunction_0() {
  316. let pageElems1 = document.querySelectorAll(".container-masonry > div")
  317. document.querySelector(".container-masonry").style.height = "auto"
  318. pageElems1.forEach(function (one) {
  319. one.setAttribute("style","float: left");
  320. });
  321. }
  322.  
  323.  
  324. // art_alphacoders 的插入前函数
  325. function art_alphacoders_beforeFunction(pageElems) {
  326. pageElems.forEach(function (one) {
  327. one.setAttribute("style","float: left");
  328. });
  329. return pageElems
  330. }
  331.  
  332.  
  333. // 滚动条事件
  334. function windowScroll(fn1) {
  335. var beforeScrollTop = document.documentElement.scrollTop,
  336. fn = fn1 || function () {};
  337. setTimeout(function () { // 延时执行,避免刚载入到页面就触发翻页事件
  338. window.addEventListener("scroll", function (e) {
  339. var afterScrollTop = document.documentElement.scrollTop,
  340. delta = afterScrollTop - beforeScrollTop;
  341. if (delta == 0) return false;
  342. fn(delta > 0 ? "down" : "up", e);
  343. beforeScrollTop = afterScrollTop;
  344. }, false);
  345. }, 1000)
  346. }
  347.  
  348.  
  349. var ShowPager = { // 修改自 https://greasyfork.org/scripts/14178
  350. getFullHref: function (e) {
  351. if(e == null) return '';
  352. "string" != typeof e && (e = e.getAttribute("href"));
  353. var t = this.getFullHref.a;
  354. return t || (this.getFullHref.a = t = document.createElement("a")), t.href = e, t.href;
  355. },
  356. createDocumentByString: function (e) {
  357. if (e) {
  358. if ("HTML" !== document.documentElement.nodeName) return (new DOMParser).parseFromString(e, "application/xhtml+xml");
  359. var t;
  360. try {
  361. t = (new DOMParser).parseFromString(e, "text/html");
  362. } catch (e) {
  363. }
  364. if (t) return t;
  365. if (document.implementation.createHTMLDocument) t = document.implementation.createHTMLDocument("ADocument"); else try {
  366. (t = document.cloneNode(!1)).appendChild(t.importNode(document.documentElement, !1)),
  367. t.documentElement.appendChild(t.createElement("head")), t.documentElement.appendChild(t.createElement("body"));
  368. } catch (e) {
  369. }
  370. if (t) {
  371. var r = document.createRange();
  372. r.selectNodeContents(document.body);
  373. var n = r.createContextualFragment(e);
  374. t.body.appendChild(n);
  375. for (var a, o = {
  376. TITLE: !0,
  377. META: !0,
  378. LINK: !0,
  379. STYLE: !0,
  380. BASE: !0
  381. }, i = t.body, s = i.childNodes, c = s.length - 1; c >= 0; c--) o[(a = s[c]).nodeName] && i.removeChild(a);
  382. return t;
  383. }
  384. } else console.error("没有找到要转成DOM的字符串");
  385. },
  386. loadMorePage: function () {
  387. if (curSite.pager) {
  388. let curPageEle = getElementByXpath(curSite.pager.nextLink);
  389. var url = this.getFullHref(curPageEle);
  390. //console.log(`${url} ${curPageEle} ${curSite.pageUrl}`);
  391. if(url === '') return;
  392. if(curSite.pageUrl === url) return;// 避免重复加载相同的页面
  393. curSite.pageUrl = url;
  394. // 读取下一页的数据
  395. curSite.pager.startFilter && curSite.pager.startFilter();
  396. GM_xmlhttpRequest({
  397. url: url,
  398. method: "GET",
  399. timeout: 5000,
  400. onload: function (response) {
  401. try {
  402. //console.log(`${response.responseText}`)
  403. var newBody = ShowPager.createDocumentByString(response.responseText);
  404. let pageElems = getAllElements(curSite.pager.pageElement, newBody, newBody);
  405. let toElement = getAllElements(curSite.pager.HT_insert[0])[0];
  406. if (pageElems.length >= 0) {
  407. // 如果有插入前函数就执行函数
  408. if (curSite.function && curSite.function.before) {
  409. if (curSite.function.parameter) { // 如果指定了参数
  410. pageElems = curSite.function.before(curSite.function.parameter);
  411. }else{
  412. pageElems = curSite.function.before(pageElems);
  413. }
  414. }
  415. // 插入位置
  416. let addTo;
  417. switch (curSite.pager.HT_insert[1]) {
  418. case 1:
  419. addTo = "beforebegin"
  420. break;
  421. case 2:
  422. addTo = "afterbegin"
  423. break;
  424. case 3:
  425. addTo = "beforeend"
  426. break;
  427. case 4:
  428. addTo = "afterend"
  429. break;
  430. }
  431. // 插入新页面元素
  432. pageElems.forEach(function (one) {
  433. toElement.insertAdjacentElement(addTo, one);
  434. });
  435. // 替换待替换元素
  436. try {
  437. let oriE = getAllElements(curSite.pager.replaceE);
  438. let repE = getAllElements(curSite.pager.replaceE, newBody, newBody);
  439. if (oriE.length === repE.length) {
  440. for (var i = 0; i < oriE.length; i++) {
  441. oriE[i].outerHTML = repE[i].outerHTML;
  442. }
  443. }
  444. } catch (e) {
  445. console.log(e);
  446. }
  447. // 如果有插入后函数就执行函数
  448. if (curSite.function && curSite.function.after) {
  449. if (curSite.function.parameter) { // 如果指定了参数
  450. curSite.function.after(curSite.function.parameter);
  451. }else{
  452. curSite.function.after();
  453. }
  454. }
  455. }
  456. } catch (e) {
  457. console.log(e);
  458. }
  459. }
  460. });
  461. }
  462. },
  463. };
  464.  
  465.  
  466. function getElementByXpath(e, t, r) {
  467. r = r || document, t = t || r;
  468. try {
  469. return r.evaluate(e, t, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  470. } catch (t) {
  471. return void console.error("无效的xpath");
  472. }
  473. }
  474.  
  475.  
  476. function getAllElements(e, t, r, n, o) {
  477. let getAllElementsByXpath = function(e, t, r) {
  478. return r = r || document, t = t || r, r.evaluate(e, t, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  479. }
  480.  
  481. var i, s = [];
  482. if (!e) return s;
  483. if (r = r || document, n = n || window, o = o || void 0, t = t || r, "string" == typeof e) i = 0 === e.search(/^css;/i) ? function getAllElementsByCSS(e, t) {
  484. return (t || document).querySelectorAll(e);
  485. }(e.slice(4), t) : getAllElementsByXpath(e, t, r); else {
  486. if (!(i = e(r, n, o))) return s;
  487. if (i.nodeType) return s[0] = i, s;
  488. }
  489. return function makeArray(e) {
  490. var t, r, n, o = [];
  491. if (e.pop) {
  492. for (t = 0, r = e.length; t < r; t++) (n = e[t]) && (n.nodeType ? o.push(n) : o = o.concat(makeArray(n)));
  493. return a()(o);
  494. }
  495. if (e.item) {
  496. for (t = e.length; t;) o[--t] = e[t];
  497. return o;
  498. }
  499. if (e.iterateNext) {
  500. for (t = e.snapshotLength; t;) o[--t] = e.snapshotItem(t);
  501. return o;
  502. }
  503. }(i);
  504. }
  505. })();