4chan-auto-watcher

a script to automatically watch 4chan threads matching a pattern

目前为 2023-11-22 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name 4chan-auto-watcher
  3. // @namespace github.com/diegostafa/userscripts
  4. // @match https://boards.4chan.org/*/catalog
  5. // @match https://boards.4channel.org/*/catalog
  6. // @version 2
  7. // @author Diego <dstafa.dev@gmail.com> (github.com/diegostafa)
  8. // @description a script to automatically watch 4chan threads matching a pattern
  9. // @run-at document-end
  10. // ==/UserScript==
  11.  
  12. const currentBoard = window.location.pathname.split("/").filter((s) => s !== "")[0];
  13.  
  14. let boardsAndFilters = [
  15. ["", /^[^a-z]*$/],
  16. ];
  17.  
  18. const buildUi = () => {
  19.  
  20. const createButton = (text) => {
  21. let button = document.createElement("div");
  22. button.innerHTML = text;
  23. button.style.backgroundColor = "#444444";
  24. button.style.color = "white";
  25. button.style.textAlign = "center";
  26. button.style.border = "none";
  27. button.style.padding = "2px";
  28. button.style.cursor = "pointer";
  29. return button;
  30. };
  31.  
  32. const createAutowatchButton = () => {
  33. let button = createButton("autowatch");
  34. button.addEventListener("click", () => { autoWatch(); });
  35. return button;
  36. };
  37.  
  38. const createConfigButton = () => {
  39. let button = createButton("config");
  40.  
  41. button.addEventListener("click", () => {
  42. var win = window.open("", "Autowatch config", "toolbar=no");
  43. win.document.body.innerHTML = `TODO`;
  44.  
  45. });
  46.  
  47. return button;
  48. };
  49.  
  50. let threadWatcher = document.getElementById("threadWatcher");
  51. let btnContainer = document.createElement("div");
  52.  
  53. btnContainer.style.display = "grid";
  54. btnContainer.style.gridTemplateColumns = "repeat(2, 1fr)";
  55. btnContainer.style.gridGap = "2px";
  56. // btnContainer.appendChild(createConfigButton());
  57. btnContainer.appendChild(createAutowatchButton());
  58.  
  59. threadWatcher.appendChild(btnContainer);
  60. };
  61.  
  62. const isThreadMatching = (filters) => (thread) => {
  63. const teaser = thread.querySelector('.teaser');
  64.  
  65. if (!teaser) return false;
  66.  
  67. return filters.reduce(
  68. (acc, [board, filter]) =>
  69. acc = acc || (filter.test(teaser.textContent) && (board === "" || currentBoard === board)), false);
  70. };
  71.  
  72. const autoWatch = () => {
  73. let threads = Array.from(document.querySelectorAll('#threads .thread'));
  74.  
  75. threads
  76. .filter(isThreadMatching(boardsAndFilters))
  77. .map((thread) => thread.querySelector('span.watchIcon'))
  78. .filter((watchIcon) => watchIcon !== null)
  79. .forEach((watchIcon) => watchIcon.click());
  80. };
  81.  
  82. buildUi();