Twitter User Blocker

Hide tweets from multiple users on Twitter

  1. // ==UserScript==
  2. // @name Twitter User Blocker
  3. // @name:ja Twitter ユーザーをミュートするやつ
  4. // @namespace http://tampermonkey.net/
  5. // @version 1.0.3
  6. // @description Hide tweets from multiple users on Twitter
  7. // @description:ja IDを入力することですぐミュートできる。表示したり非表示にしたりの切り替えも可能
  8. // @author Nogaccho
  9. // @match https://twitter.com/*
  10. // @match https://x.com/*
  11. // @grant none
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. (function () {
  16. 'use strict';
  17.  
  18. let isBlockingEnabled = false;// ブロッキングが有効かどうかのフラグ
  19. let initialLoad = true;// 初回読み込みかどうかのフラグ
  20. let ids = [];// ブロックするユーザーIDのリスト
  21.  
  22. function saveUserIds(userIds) {
  23. localStorage.setItem("blockedUserIds", JSON.stringify(userIds));// 非表示するユーザーIDをlocalStorageに保存
  24. }
  25.  
  26. function loadUserIds() {
  27. return JSON.parse(localStorage.getItem("blockedUserIds") || "[]");// ローカルストレージから非表示するユーザーIDを読み込み
  28. }
  29.  
  30. function hideTweets() {
  31. if (!isBlockingEnabled) return;// ブロッキングが無効なら処理を中断
  32. let blockedUserIds = loadUserIds();// ブロックするユーザーIDを取得
  33. let tweets = document.querySelectorAll(`[data-testid="tweet"]`); // ツイートの要素を取得
  34. let count = 0;
  35. tweets.forEach(tweet => {
  36. if (initialLoad && count >= 50) return; // 初回読み込み時は50ツイートのみ処理
  37. let authorLink = blockedUserIds.some(id => tweet.querySelector(`a[href*="/${id}"]`));
  38. if (authorLink) {
  39. tweet.style.display = 'none';
  40. count++;
  41. }
  42. });
  43. initialLoad = false;
  44. }
  45.  
  46. function handleScroll() {
  47. // スクロールイベントの処理。新しいツイートが表示されるたびにhideTweetsを呼び出す
  48. let lastTweet = document.querySelectorAll(`[data-testid="tweet"]`).item(document.querySelectorAll(`[data-testid="tweet"]`).length - 1);
  49. let observer = new IntersectionObserver((entries, observer) => {
  50. entries.forEach(entry => {
  51. if (entry.isIntersecting) {
  52. hideTweets();
  53. observer.unobserve(lastTweet);
  54. }
  55. });
  56. }, { threshold: 1.0 });
  57. observer.observe(lastTweet);
  58. }
  59.  
  60. function toggleBlocking() {
  61. // 非表示のON/OFFを切り替える
  62. isBlockingEnabled = !isBlockingEnabled;
  63. if (isBlockingEnabled) {
  64. hideTweets();
  65. } else {
  66. document.querySelectorAll(`[data-testid="tweet"]`).forEach(tweet => {
  67. tweet.style.display = '';
  68. });
  69. }
  70. }
  71.  
  72. function editBlockList() {
  73. // 非表示リストの編集画面
  74. let ids = loadUserIds();
  75. let editContainer = document.createElement("div");
  76. editContainer.style.position = "fixed";
  77. editContainer.style.top = "100px";
  78. editContainer.style.right = "10px";
  79. editContainer.style.backgroundColor = "#273340";
  80. editContainer.style.padding = "10px";
  81. editContainer.style.border = "0.5px solid gray";
  82. editContainer.style.zIndex = "1000";
  83. editContainer.style.color = "white";
  84. editContainer.style.borderRadius = "10px";
  85. editContainer.style.display = "flex";
  86. editContainer.style.flexDirection = "column";
  87.  
  88. let idListContainer = document.createElement("div");
  89. idListContainer.style.maxHeight = "260px";
  90. idListContainer.style.overflowY = "auto";
  91. idListContainer.style.marginBottom = "10px";
  92.  
  93. let idList = document.createElement("ul");
  94. ids.forEach(id => {
  95. let listItem = document.createElement("li");
  96. listItem.style.display = "flex";
  97. listItem.style.justifyContent = "space-between";
  98. listItem.style.alignItems = "center";
  99.  
  100. let idText = document.createElement("span");
  101. idText.textContent = id;
  102. listItem.appendChild(idText);
  103.  
  104. let removeButton = document.createElement("button");
  105. removeButton.textContent = "削除";
  106. removeButton.style.marginLeft = "10px";
  107. styleButton(removeButton);
  108. removeButton.onclick = function () {
  109. ids = ids.filter(userId => userId !== id);
  110. saveUserIds(ids);
  111. listItem.remove()
  112. };
  113.  
  114. listItem.appendChild(removeButton);
  115. idList.appendChild(listItem);
  116. });
  117.  
  118. idListContainer.appendChild(idList);
  119. editContainer.appendChild(idListContainer);
  120.  
  121. let closeButton = document.createElement("button");
  122. closeButton.textContent = "閉じる";
  123. closeButton.style.alignSelf = "flex-start";
  124. styleButton(closeButton);
  125. closeButton.onclick = function () {
  126. document.body.removeChild(editContainer);
  127. };
  128. editContainer.appendChild(closeButton);
  129. document.body.appendChild(editContainer);
  130. }
  131.  
  132. // Create interface for blocking user IDs
  133. let inputBox = document.createElement("input");
  134. inputBox.type = "text";
  135. inputBox.placeholder = ' IDを入力';
  136. inputBox.style.backgroundColor = "#273340";
  137. inputBox.style.color = "#757575";
  138. inputBox.style.border = "none";
  139. inputBox.style.borderRadius = "2px";
  140.  
  141. let saveButton = document.createElement("button");
  142. saveButton.textContent = "追加";
  143. styleButton(saveButton);
  144. saveButton.onclick = function () {
  145. let newUserIds = inputBox.value.split(',').map(id => id.trim().replace(/"/g, '')).filter(id => id !== "");
  146. if (newUserIds.length > 0) {
  147. let currentIds = loadUserIds();
  148. let updatedIds = currentIds.concat(newUserIds.filter(id => !currentIds.includes(id)));
  149. saveUserIds(updatedIds);
  150. hideTweets();
  151. }
  152. inputBox.value = "";
  153. };
  154.  
  155. let toggleCheckbox = document.createElement("input");
  156. toggleCheckbox.type = "checkbox";
  157. toggleCheckbox.checked = isBlockingEnabled;
  158. toggleCheckbox.onchange = toggleBlocking;
  159. let toggleLabel = document.createElement("label");
  160. toggleLabel.style.marginLeft = "5px";
  161. toggleLabel.insertBefore(toggleCheckbox, toggleLabel.firstChild);
  162.  
  163. let editButton = document.createElement("button");
  164. editButton.textContent = "IDリスト";
  165. editButton.style.marginLeft = "10px";
  166. styleButton(editButton);
  167. editButton.onclick = function () {
  168. ids = loadUserIds();
  169. editBlockList();
  170. };
  171.  
  172. let container = document.createElement("div");
  173. container.style.position = "fixed";
  174. container.style.top = "55px";
  175. container.style.right = "10px";
  176. container.appendChild(inputBox);
  177. container.appendChild(saveButton);
  178. container.appendChild(editButton);
  179. container.appendChild(toggleLabel);
  180. document.body.appendChild(container);
  181.  
  182. function styleButton(button) {
  183. button.style.backgroundColor = "#1A8CD8";
  184. button.style.color = "#FFFFFF";
  185. button.style.borderRadius = "10px";
  186. button.style.border = "none";
  187.  
  188. button.onmouseover = function () {
  189. button.style.backgroundColor = "#1576b6";
  190. };
  191.  
  192. button.onmousedown = function () {
  193. button.style.backgroundColor = "#0f5a94";
  194. };
  195. button.onmouseup = function () {
  196. button.style.backgroundColor = "#1A8CD8";
  197. };
  198. button.onmouseleave = function () {
  199. button.style.backgroundColor = "#1A8CD8";
  200. };
  201. }
  202.  
  203. window.addEventListener('scroll', handleScroll);// スクロールイベントリスナーを追加
  204. let observer = new MutationObserver(hideTweets);// DOMの変更を監視するオブザーバーを追加
  205. observer.observe(document.body, { childList: true, subtree: true });
  206. })();