🏠 Home 

Twitter (X): Скрыть Текстовые Публикации

Сделайте ленту публикаций чище


Install this script?
  1. // ==UserScript==
  2. // @name Twitter (X): Скрыть Текстовые Публикации
  3. // @name:en Twitter (X): Hide Text Posts
  4. // @name:ru Twitter (X): Скрыть Текстовые Публикации
  5. // @name:zh Twitter (X): 隐藏文本出版物
  6. // @namespace http://tampermonkey.net/
  7. // @version 3.3
  8. // @description Сделайте ленту публикаций чище
  9. // @description:en Make your feed cleaner
  10. // @description:ru Сделайте ленту публикаций чище
  11. // @description:zh 使出版物提要更清洁
  12. // @author Grihail
  13. // @match https://twitter.com/*
  14. // @icon https://www.google.com/s2/favicons?sz=64&domain=twitter.com
  15. // @grant GM_setValue
  16. // @grant GM_getValue
  17. // @license CC-BY
  18. // ==/UserScript==
  19. //Локализация
  20. const pageLanguage = document.documentElement.lang.toLowerCase();
  21. const currentLanguage = pageLanguage.startsWith('ru') ? 'ru' : (pageLanguage.startsWith('zh') ? 'zh' : 'en'); // Добавлено определение для китайского языка
  22. const translations = {
  23. en: {title: 'Hide:', textPost: 'Text post', textReply: 'Text reply:', textRepost: 'Text repost', textQuote: 'Text quote', selfRepost: 'Self repost',
  24. },
  25. ru: {title: 'Скрыть:', textPost: 'Текстовый пост', textReply: 'Текстовый ответ:', textRepost: 'Репост текста', textQuote: 'Цитата текста', selfRepost: 'Само-репост',
  26. },
  27. zh: {title: '隐藏:', textPost: '文本帖子', textReply: '文本回复:', textRepost: '文本转发', textQuote: '文本引用', selfRepost: '自我转发',
  28. }
  29. };
  30. // Интеграция интерфейса и функционал
  31. function insertPostSettings() {
  32. const postSettingsHTML = `
  33. <div class="postSettings" style="border-radius: 16px; width: 90%; border-color: rgb(47, 51, 54); overflow: hidden; border-width: 1px; border-style: solid; display: flex; box-sizing: border-box; flex-direction: column; padding: 0 12px 12px 12px; margin-top: 16px;">
  34. <h2 style="margin-block: unset; display: flex; align-items: center; padding-left: 12px;" class="r-1h3ijdo r-1nao33i r-37j5jr r-adyw6z r-b88u0q r-135wba7 r-bcqeeo">
  35. <span>${translations[currentLanguage].title}</span></h2>
  36. <div class="textCheck" style="width: 90%;display: flex;justify-content: space-between;align-items: center;padding: 12px;">
  37. <svg viewBox="0 0 24 24" style="margin-right: 12px;height: 1.25em;flex-shrink: 0;">
  38. <g style="fill: #e7e9ea;">
  39. <path d="M1.751 10c0-4.42 3.584-8 8.005-8h4.366c4.49 0 8.129 3.64 8.129 8.13 0 2.96-1.607 5.68-4.196 7.11l-8.054 4.46v-3.69h-.067c-4.49.1-8.183-3.51-8.183-8.01zm8.005-6c-3.317 0-6.005 2.69-6.005 6 0 3.37 2.77 6.08 6.138 6.01l.351-.01h1.761v2.3l5.087-2.81c1.951-1.08 3.163-3.13 3.163-5.36 0-3.39-2.744-6.13-6.129-6.13H9.756z"></path></g></svg>
  40. <span class="r-1nao33i r-37j5jr r-a023e6 r-rjixqe" style="width: 100%;">${translations[currentLanguage].textPost}</span>
  41. <input type="checkbox" class="textPost" data-target-class="textPostHide" ${getCheckboxValue('textPost')}></input></div>
  42. <div class="replytextCheck" style="width: 90%;display: flex;justify-content: space-between;align-items: center;padding: 12px;">
  43. <svg viewBox="0 0 24 24" style="margin-right: 12px;height: 1.25em;flex-shrink: 0;">
  44. <g style="fill: #e7e9ea;"><path d="M1.751 10c0-4.42 3.584-8 8.005-8h4.366c4.49 0 8.129 3.64 8.129 8.13 0 2.96-1.607 5.68-4.196 7.11l-8.054 4.46v-3.69h-.067c-4.49.1-8.183-3.51-8.183-8.01zm8.005-6c-3.317 0-6.005 2.69-6.005 6 0 3.37 2.77 6.08 6.138 6.01l.351-.01h1.761v2.3l5.087-2.81c1.951-1.08 3.163-3.13 3.163-5.36 0-3.39-2.744-6.13-6.129-6.13H9.756z"></path></g></svg>
  45. <span class="r-1nao33i r-37j5jr r-a023e6 r-rjixqe" style="width: 100%;">${translations[currentLanguage].textReply}</span>
  46. <input type="checkbox" class="textReply" data-target-class="textReplyHide"${getCheckboxValue('textReply')}></input></div>
  47. <div class="repostCheck" style="width: 90%;display: flex;justify-content: space-between;align-items: center;padding: 12px;">
  48. <svg viewBox="0 0 24 24" style="margin-right: 12px;height: 1.25em;flex-shrink: 0;">
  49. <g style="fill: #e7e9ea;">
  50. <path d="M4.5 3.88l4.432 4.14-1.364 1.46L5.5 7.55V16c0 1.1.896 2 2 2H13v2H7.5c-2.209 0-4-1.79-4-4V7.55L1.432 9.48.068 8.02 4.5 3.88zM16.5 6H11V4h5.5c2.209 0 4 1.79 4 4v8.45l2.068-1.93 1.364 1.46-4.432 4.14-4.432-4.14 1.364-1.46 2.068 1.93V8c0-1.1-.896-2-2-2z"></path></g></svg>
  51. <span class="r-1nao33i r-37j5jr r-a023e6 r-rjixqe" style="width: 100%;">${translations[currentLanguage].textRepost}</span>
  52. <input type="checkbox" class="textRepost" data-target-class="textRepostHide"${getCheckboxValue('textRepost')}></input></div>
  53. <div class="selfrepostCheck" style="width: 90%;display: flex;justify-content: space-between;align-items: center;padding: 12px;">
  54. <svg viewBox="0 0 24 24" style="margin-right: 12px;height: 1.25em;flex-shrink: 0;">
  55. <g style="fill: #e7e9ea;">
  56. <path d="M14.23 2.854c.98-.977 2.56-.977 3.54 0l3.38 3.378c.97.977.97 2.559 0 3.536L9.91 21H3v-6.914L14.23 2.854zm2.12 1.414c-.19-.195-.51-.195-.7 0L5 14.914V19h4.09L19.73 8.354c.2-.196.2-.512 0-.708l-3.38-3.378zM14.75 19l-2 2H21v-2h-6.25z"></path></g></svg>
  57. <span class="r-1nao33i r-37j5jr r-a023e6 r-rjixqe" style="width: 100%;">${translations[currentLanguage].textQuote}</span>
  58. <input type="checkbox" class="textQuote" data-target-class="textQuoteHide"${getCheckboxValue('textQuote')}></input></div>
  59. <div class="replyCheck" style="width: 90%;display: flex;justify-content: space-between;align-items: center;padding: 12px;">
  60. <svg viewBox="0 0 24 24" style="margin-right: 12px;height: 1.25em;flex-shrink: 0;">
  61. <g style="fill: #e7e9ea;">
  62. <path d="M4.5 3.88l4.432 4.14-1.364 1.46L5.5 7.55V16c0 1.1.896 2 2 2H13v2H7.5c-2.209 0-4-1.79-4-4V7.55L1.432 9.48.068 8.02 4.5 3.88zM16.5 6H11V4h5.5c2.209 0 4 1.79 4 4v8.45l2.068-1.93 1.364 1.46-4.432 4.14-4.432-4.14 1.364-1.46 2.068 1.93V8c0-1.1-.896-2-2-2z"></path></g></svg>
  63. <span class="r-1nao33i r-37j5jr r-a023e6 r-rjixqe" style="width: 100%;">${translations[currentLanguage].selfRepost}</span>
  64. <input type="checkbox" class="selfRepost" data-target-class="selfRepostHide"${getCheckboxValue('selfRepost')}></input></div></div>
  65. `;
  66. const targetSelector = "body > #react-root > div > div > div[data-at-shortcutkeys] > header > div > div > div > div:nth-child(1)";
  67. const targetElement = document.querySelector(targetSelector);
  68. if (!document.querySelector('.postSettings')) {
  69. targetElement.insertAdjacentHTML('beforeend', postSettingsHTML);
  70. const checkboxes = document.querySelectorAll('.postSettings input[type="checkbox"]');
  71. function updateVisibility() {
  72. if (window.location.href !== 'https://twitter.com/home') {
  73. // Если не на домашней странице Twitter, не обновляем видимость элементов
  74. return;
  75. }
  76. checkboxes.forEach(checkbox => {
  77. const dataAttribute = checkbox.getAttribute('data-target-class');
  78. const elementsToToggle = document.querySelectorAll(`.${dataAttribute}`);
  79. elementsToToggle.forEach(element => {
  80. element.style.display = checkbox.checked ? 'none' : 'block';
  81. });
  82. });
  83. // Сохраняем значения checkbox в localStorage
  84. setCheckboxValue('textPost', checkboxes[0].checked);
  85. setCheckboxValue('textReply', checkboxes[1].checked);
  86. setCheckboxValue('textRepost', checkboxes[2].checked);
  87. setCheckboxValue('textQuote', checkboxes[3].checked);
  88. setCheckboxValue('selfRepost', checkboxes[4].checked);
  89. }
  90. checkboxes.forEach(checkbox => {
  91. checkbox.addEventListener('change', updateVisibility);
  92. });
  93. setInterval(updateVisibility, 100);
  94. // Дополнительный код для управления видимостью интерфейса в зависимости от URL
  95. setInterval(() => {
  96. const currentURL = window.location.href;
  97. const postSettings = document.querySelector('.postSettings');
  98. if (currentURL === "https://twitter.com/home") {
  99. postSettings.style.opacity = '100%';
  100. } else {
  101. postSettings.style.opacity = '0%';
  102. }
  103. }, 700);
  104. }
  105. }
  106. // Функция для получения значения checkbox из localStorage
  107. function getCheckboxValue(key) {
  108. const screenName = getCurrentUserScreenName();
  109. return localStorage.getItem(`${screenName}_${key}`) === 'false' ? '' : 'checked';
  110. }
  111. // Функция для сохранения значения checkbox в localStorage
  112. function setCheckboxValue(key, value) {
  113. const screenName = getCurrentUserScreenName();
  114. localStorage.setItem(`${screenName}_${key}`, value);
  115. }
  116. // Функция для извлечения screenName из HTML кода
  117. function extractScreenName(html) {
  118. var regex = /"screen_name":"([^"]+)"/;
  119. var match = html.match(regex);
  120. if (match && match[1]) {
  121. return match[1];
  122. } else {
  123. return null;
  124. }
  125. }
  126. // Функция для получения screenName текущего пользователя
  127. function getCurrentUserScreenName() {
  128. var htmlCode = document.documentElement.outerHTML;
  129. var screenName = extractScreenName(htmlCode);
  130. return screenName ? screenName : 'unknown';
  131. }
  132. setInterval(function() {
  133. document.querySelectorAll('div:nth-child(1) > section > div:nth-child(2) > div > [data-testid="cellInnerDiv"]').forEach(function(element) {
  134. const media = element.querySelector('article > div > div > div:nth-child(2) > div:nth-child(2) > div[id] > div:not([id])');
  135. const reply = element.querySelector('article > div > div > div:nth-child(2) > div:nth-child(1) > div:nth-child(2)');
  136. const lastReply = element.querySelector('article > div > div > div:nth-child(1) > div > div > div');
  137. const repost = element.querySelector('article > div > div > div:nth-child(1) > div > div > div > div');
  138. const quote = element.querySelector('article > div > div > div:nth-child(2) > div:nth-child(2) > div[id] > div[id]');
  139. const mediaQuote = element.querySelector('article > div > div > div:nth-child(2) > div:nth-child(2) > div[id] > div[id] > div[role] > div > div:nth-child(3)');
  140. const repostAuthor = element.querySelector('article > div > div > div:nth-child(1) > div > div > div > div > div:nth-child(2) > div > div > div > a[href]');
  141. const postAuthor = element.querySelector('article > div > div > div:nth-child(2) > div:nth-child(1) > div > div > div > div:nth-child(2) > div > div:nth-child(2) > div > a[href]');
  142. if (!media && !repost && !lastReply && !quote) {
  143. element.classList.add('textPostHide');
  144. }
  145. if (!media && (reply || lastReply)) {
  146. element.classList.add('textReplyHide');
  147. }
  148. if ((!media && repost) && (!reply || !lastReply)) {
  149. element.classList.add('textRepostHide');
  150. }
  151. if (!media && quote) {
  152. element.classList.add('textQuoteHide');
  153. }
  154. if (postAuthor && repostAuthor && postAuthor.href === repostAuthor.href) {
  155. element.classList.add('selfRepostHide');
  156. }})}, 1000);
  157. // Основной код скрипта
  158. setInterval(() => {
  159. const currentURL = window.location.href;
  160. if (currentURL === 'https://twitter.com/home') {
  161. insertPostSettings();
  162. addClassesToElements();
  163. }
  164. }, 1000);