自动无缝翻页

自动无缝翻页,目前支持:423Down、Apphot(原烈火汉化)、小众软件、PubMed、三国杀论坛

当前为 2021-03-30 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name 自动无缝翻页
  3. // @version 1.1.5
  4. // @author X.I.U
  5. // @description 自动无缝翻页,目前支持:423Down、Apphot(原烈火汉化)、小众软件、PubMed、三国杀论坛
  6. // @match *://www.423down.com/*
  7. // @exclude *://www.423down.com/*.html
  8. // @match *://apphot.cc/*
  9. // @exclude *://apphot.cc/*.html
  10. // @match *://www.appinn.com/
  11. // @match *://www.appinn.com/*/*/
  12. // @match *://www.appinn.com/?s=*
  13. // @match *://pubmed.ncbi.nlm.nih.gov/?term=*
  14. // @match *://club.sanguosha.com/*
  15. // @icon https://i.loli.net/2021/03/07/rdijeYm83pznxWq.png
  16. // @grant GM_xmlhttpRequest
  17. // @grant GM_registerMenuCommand
  18. // @grant GM_openInTab
  19. // @license GPL-3.0 License
  20. // @run-at document-end
  21. // @namespace https://github.com/XIU2/UserScript
  22. // ==/UserScript==
  23.  
  24. (function() {
  25. // 注册脚本菜单
  26. GM_registerMenuCommand('反馈 & 申请添加支持', function () {window.GM_openInTab('https://github.com/XIU2/UserScript#xiu2userscript', {active: true,insert: true,setParent: true});});
  27.  
  28. // 默认 ID 为 0
  29. var curSite = {SiteTypeID: 0};
  30.  
  31. // 自动翻页规则
  32. // type:1 = 脚本实现自动无缝翻页,2 = 网站自带了自动无缝翻页功能,只需要点击下一页按钮即可,这时 nextText 为按钮文本,避免一瞬间加载太多次下一页
  33. // HT_insert:1 = 插入元素前面;2 = 插入元素中的最后一个子元素后面
  34. // scrollDelta:数值越大,滚动条触发点越靠上(越早开始翻页)
  35. let DBSite = {
  36. _423down_postslist: {
  37. SiteTypeID: 1,
  38. pager: {
  39. type: 1,
  40. nextLink: '//div[@class="paging"]//a[contains(text(),"下一页")][@href]',
  41. pageElement: 'css;div.content-wrap ul.excerpt > li',
  42. HT_insert: ['css;div.content-wrap ul.excerpt', 2],
  43. replaceE: 'css;div.paging',
  44. scrollDelta: 1500
  45. }
  46. },
  47. apphot_postslist: {
  48. SiteTypeID: 2,
  49. pager: {
  50. type: 1,
  51. nextLink: '//div[@class="pagination"]//a[contains(text(),"下一页")][@href]',
  52. pageElement: 'css;div.content > article.excerpt',
  53. HT_insert: ['css;div.pagination', 1],
  54. replaceE: 'css;div.pagination',
  55. scrollDelta: 1500
  56. }
  57. },
  58. appinn_postslist: {
  59. SiteTypeID: 3,
  60. pager: {
  61. type: 1,
  62. nextLink: '//a[@class="next page-numbers"][@href]',
  63. pageElement: 'css;section#latest-posts > article',
  64. HT_insert: ['css;nav.navigation.pagination', 1],
  65. replaceE: 'css;div.nav-links',
  66. scrollDelta: 1500
  67. }
  68. },
  69. pubmed_postslist: {
  70. SiteTypeID: 4,
  71. pager: {
  72. type: 2,
  73. nextLink: 'button.load-button.next-page',
  74. nextText: 'Show more',
  75. scrollDelta: 1500
  76. }
  77. },
  78. sanguosha_forum: {
  79. SiteTypeID: 5,
  80. pager: {
  81. type: 2,
  82. nextLink: '#autopbn',
  83. nextText: '下一页 »',
  84. scrollDelta: 800
  85. }
  86. },
  87. sanguosha_thread: {
  88. SiteTypeID: 6,
  89. pager: {
  90. type: 1,
  91. nextLink: '//a[@class="nxt"][@href]',
  92. pageElement: 'css;div#postlist > div[id^="post_"]',
  93. HT_insert: ['css;div#postlist', 2],
  94. replaceE: 'css;div.pg',
  95. scrollDelta: 800
  96. }
  97. },
  98. sanguosha_search: {
  99. SiteTypeID: 7,
  100. pager: {
  101. type: 1,
  102. nextLink: '//a[@class="nxt"][@href]',
  103. pageElement: 'css;div#threadlist > ul',
  104. HT_insert: ['css;div#threadlist', 2],
  105. replaceE: 'css;div.pg',
  106. scrollDelta: 800
  107. }
  108. }
  109. };
  110.  
  111.  
  112. switch (location.host) {
  113. case "www.423down.com":
  114. curSite = DBSite._423down_postslist;
  115. break;
  116. case "apphot.cc":
  117. curSite = DBSite.apphot_postslist;
  118. break;
  119. case "www.appinn.com":
  120. curSite = DBSite.appinn_postslist;
  121. break;
  122. case "pubmed.ncbi.nlm.nih.gov":
  123. curSite = DBSite.pubmed_postslist;
  124. break;
  125. case "club.sanguosha.com":
  126. if(location.pathname.indexOf("forum") > -1){ // 各版块帖子列表
  127. curSite = DBSite.sanguosha_forum;
  128. }else if(location.pathname.indexOf("thread") > -1){ // 帖子内
  129. curSite = DBSite.sanguosha_thread;
  130. hidePgbtn(); // 隐藏帖子内的 [下一页] 按钮
  131. }else if(location.pathname.indexOf("search") > -1){ // 搜索结果
  132. curSite = DBSite.sanguosha_search;
  133. }
  134. break;
  135. }
  136. curSite.pageUrl = ""; // 下一页URL
  137. pageLoading(); // 自动无缝翻页
  138.  
  139.  
  140. // 自动无缝翻页
  141. function pageLoading() {
  142. if (curSite.SiteTypeID > 0){
  143. windowScroll(function (direction, e) {
  144. if (direction === "down") { // 下滑才准备翻页
  145. let scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
  146. //console.log(document.documentElement.scrollHeight)
  147. let scrollDelta = curSite.pager.scrollDelta;
  148. if (document.documentElement.scrollHeight <= document.documentElement.clientHeight + scrollTop + scrollDelta) {
  149. if (curSite.pager.type === 1) {
  150. ShowPager.loadMorePage();
  151. }else{
  152. let autopbn = document.querySelector(curSite.pager.nextLink);
  153. if (autopbn && autopbn.innerText == curSite.pager.nextText){ // 如果正在加载,就不再点击
  154. autopbn.click();
  155. }
  156. }
  157. }
  158. }
  159. });
  160. }
  161. }
  162.  
  163.  
  164. // 隐藏帖子内的 [下一页] 按钮
  165. function hidePgbtn(){
  166. let style_hidePgbtn = document.createElement('style');
  167. style_hidePgbtn.innerHTML = `.pgbtn {display: none;}`;
  168. document.head.appendChild(style_hidePgbtn);
  169. }
  170.  
  171.  
  172. // 滚动条事件
  173. function windowScroll(fn1) {
  174. var beforeScrollTop = document.documentElement.scrollTop,
  175. fn = fn1 || function () {};
  176. setTimeout(function () { // 延时执行,避免刚载入到页面就触发翻页事件
  177. window.addEventListener("scroll", function (e) {
  178. var afterScrollTop = document.documentElement.scrollTop,
  179. delta = afterScrollTop - beforeScrollTop;
  180. if (delta == 0) return false;
  181. fn(delta > 0 ? "down" : "up", e);
  182. beforeScrollTop = afterScrollTop;
  183. }, false);
  184. }, 1000)
  185. }
  186.  
  187.  
  188. var ShowPager = { // 修改自 https://greasyfork.org/scripts/14178
  189. getFullHref: function (e) {
  190. if(e == null) return '';
  191. "string" != typeof e && (e = e.getAttribute("href"));
  192. var t = this.getFullHref.a;
  193. return t || (this.getFullHref.a = t = document.createElement("a")), t.href = e, t.href;
  194. },
  195. createDocumentByString: function (e) {
  196. if (e) {
  197. if ("HTML" !== document.documentElement.nodeName) return (new DOMParser).parseFromString(e, "application/xhtml+xml");
  198. var t;
  199. try {
  200. t = (new DOMParser).parseFromString(e, "text/html");
  201. } catch (e) {
  202. }
  203. if (t) return t;
  204. if (document.implementation.createHTMLDocument) t = document.implementation.createHTMLDocument("ADocument"); else try {
  205. (t = document.cloneNode(!1)).appendChild(t.importNode(document.documentElement, !1)),
  206. t.documentElement.appendChild(t.createElement("head")), t.documentElement.appendChild(t.createElement("body"));
  207. } catch (e) {
  208. }
  209. if (t) {
  210. var r = document.createRange();
  211. r.selectNodeContents(document.body);
  212. var n = r.createContextualFragment(e);
  213. t.body.appendChild(n);
  214. for (var a, o = {
  215. TITLE: !0,
  216. META: !0,
  217. LINK: !0,
  218. STYLE: !0,
  219. BASE: !0
  220. }, i = t.body, s = i.childNodes, c = s.length - 1; c >= 0; c--) o[(a = s[c]).nodeName] && i.removeChild(a);
  221. return t;
  222. }
  223. } else console.error("没有找到要转成DOM的字符串");
  224. },
  225. loadMorePage: function () {
  226. if (curSite.pager) {
  227. let curPageEle = getElementByXpath(curSite.pager.nextLink);
  228. var url = this.getFullHref(curPageEle);
  229. //console.log(`${url} ${curPageEle} ${curSite.pageUrl}`);
  230. if(url === '') return;
  231. if(curSite.pageUrl === url) return;// 不会重复加载相同的页面
  232. curSite.pageUrl = url;
  233. // 读取下一页的数据
  234. curSite.pager.startFilter && curSite.pager.startFilter();
  235. GM_xmlhttpRequest({
  236. url: url,
  237. method: "GET",
  238. timeout: 5000,
  239. onload: function (response) {
  240. try {
  241. //console.log(`${response.responseText}`)
  242. var newBody = ShowPager.createDocumentByString(response.responseText);
  243. let pageElems = getAllElements(curSite.pager.pageElement, newBody, newBody);
  244. let toElement = getAllElements(curSite.pager.HT_insert[0])[0];
  245. if (pageElems.length >= 0) {
  246. let addTo = "beforeend";
  247. if (curSite.pager.HT_insert[1] == 1) addTo = "beforebegin";
  248. // 插入新页面元素
  249. pageElems.forEach(function (one) {
  250. toElement.insertAdjacentElement(addTo, one);
  251. });
  252. // 替换待替换元素
  253. try {
  254. let oriE = getAllElements(curSite.pager.replaceE);
  255. let repE = getAllElements(curSite.pager.replaceE, newBody, newBody);
  256. if (oriE.length === repE.length) {
  257. for (var i = 0; i < oriE.length; i++) {
  258. oriE[i].outerHTML = repE[i].outerHTML;
  259. }
  260. }
  261. } catch (e) {
  262. console.log(e);
  263. }
  264. }
  265. } catch (e) {
  266. console.log(e);
  267. }
  268. }
  269. });
  270. }
  271. },
  272. };
  273.  
  274.  
  275. function getElementByXpath(e, t, r) {
  276. r = r || document, t = t || r;
  277. try {
  278. return r.evaluate(e, t, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  279. } catch (t) {
  280. return void console.error("无效的xpath");
  281. }
  282. }
  283.  
  284.  
  285. function getAllElements(e, t, r, n, o) {
  286. let getAllElementsByXpath = function(e, t, r) {
  287. return r = r || document, t = t || r, r.evaluate(e, t, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  288. }
  289.  
  290. var i, s = [];
  291. if (!e) return s;
  292. 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) {
  293. return (t || document).querySelectorAll(e);
  294. }(e.slice(4), t) : getAllElementsByXpath(e, t, r); else {
  295. if (!(i = e(r, n, o))) return s;
  296. if (i.nodeType) return s[0] = i, s;
  297. }
  298. return function makeArray(e) {
  299. var t, r, n, o = [];
  300. if (e.pop) {
  301. for (t = 0, r = e.length; t < r; t++) (n = e[t]) && (n.nodeType ? o.push(n) : o = o.concat(makeArray(n)));
  302. return a()(o);
  303. }
  304. if (e.item) {
  305. for (t = e.length; t;) o[--t] = e[t];
  306. return o;
  307. }
  308. if (e.iterateNext) {
  309. for (t = e.snapshotLength; t;) o[--t] = e.snapshotItem(t);
  310. return o;
  311. }
  312. }(i);
  313. }
  314. })();