NGA Auto Refresh

Refresh NGA post automatically.

当前为 2019-11-30 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name NGA Auto Refresh
  3. // @version 0.1.2
  4. // @description Refresh NGA post automatically.
  5. // @license MIT
  6. // @author eight04 <eight04@gmail.com> (https://github.com/eight04)
  7. // @homepageURL https://github.com/eight04/nga-auto-refresh
  8. // @supportURL https://github.com/eight04/nga-auto-refresh/issues
  9. // @namespace https://github.com/eight04
  10. // @match *://bbs.nga.cn/read.php*
  11. // @grant none
  12. // ==/UserScript==
  13.  
  14. /* eslint-env browser */
  15. (async () => {
  16. const updateInterval = 60 * 1000;
  17. const statusText = createStatusText();
  18. let lastUpdate = Date.now();
  19. // https://github.com/Tampermonkey/tampermonkey/issues/705
  20. const setTimeout = window.setTimeout.bind(window);
  21. const fetch = window.fetch.bind(window);
  22.  
  23. while (!document.querySelector("[title=加载下一页]")) {
  24. while (Date.now() - lastUpdate < updateInterval) {
  25. updateStatus();
  26. await delay(1000);
  27. }
  28. updateStatus("loading");
  29. const r = await fetch(location.href);
  30. if (!r.ok) {
  31. console.error("connection error", r);
  32. continue;
  33. }
  34. const buffer = await r.arrayBuffer();
  35. const parser = new DOMParser;
  36. const root = parser.parseFromString(await decodeGBK(buffer), "text/html");
  37. const loadedIds = getLoadedIds();
  38.  
  39. const nodes = root.querySelector("#m_posts_c").children;
  40. const posts = [];
  41. for (let i = 0; i < nodes.length; i += 2) {
  42. const id = nodes[i].firstElementChild.firstElementChild.id;
  43. if (loadedIds.has(id)) {
  44. continue;
  45. }
  46. posts.push({
  47. table: nodes[i],
  48. js: createScript(nodes[i + 1])
  49. });
  50. }
  51. if (posts.length) {
  52. // update userinfo
  53. for (const script of root.querySelectorAll("script")) {
  54. if (script.textContent.includes("userinfostart")) {
  55. document.head.appendChild(createScript(script));
  56. break;
  57. }
  58. }
  59. // update post
  60. const container = document.querySelector("#m_posts_c");
  61. for (const post of posts) {
  62. container.append(post.table, post.js);
  63. }
  64.  
  65. }
  66. // update pagination
  67. const buttonBar = document.querySelector("#pagebbtm");
  68. const newButtonBar = root.querySelector("#pagebbtm");
  69. buttonBar.parentNode.replaceChild(newButtonBar, buttonBar);
  70. refreshScripts(newButtonBar);
  71. lastUpdate = Date.now();
  72. }
  73.  
  74. updateStatus("current page completed");
  75.  
  76. function getLoadedIds() {
  77. const s = new Set;
  78. const rows = document.querySelectorAll(".postrow");
  79. for (const row of rows) {
  80. s.add(row.id);
  81. }
  82. return s;
  83. }
  84.  
  85. function createStatusText() {
  86. const posts = document.querySelector("#m_posts");
  87. const el = document.createElement("div");
  88. el.style.margin = "10px";
  89. el.style.textAlign = "center";
  90. posts.parentNode.insertBefore(el, posts.nextSibling);
  91. return el;
  92. }
  93.  
  94. function updateStatus(text) {
  95. if (!text) {
  96. text = Math.round((updateInterval - (Date.now() - lastUpdate)) / 1000);
  97. }
  98. statusText.textContent = text;
  99. }
  100.  
  101. function delay(s) {
  102. return new Promise(resolve => setTimeout(resolve, s));
  103. }
  104. function decodeGBK(buffer) {
  105. const decoder = new TextDecoder("gbk");
  106. return decoder.decode(buffer);
  107. }
  108. function createScript(script) {
  109. const newScript = document.createElement("script");
  110. newScript.textContent = script.textContent;
  111. return newScript;
  112. }
  113. function refreshScripts(el) {
  114. const scripts = el.querySelectorAll("script");
  115. for (const script of scripts) {
  116. const newScript = createScript(script);
  117. script.parentNode.replaceChild(newScript, script);
  118. }
  119. }
  120. })();