您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Hide posts by keywords with the dashboard and hide posts from verified accounts
当前为
// ==UserScript== // @name PanelControl Filtration Posts language popup by Keywords XFilter (c) tapeavion // @namespace http://tampermonkey.net/ // @version 2.1 // @description Hide posts by keywords with the dashboard and hide posts from verified accounts // @author gullampis810 // @match https://x.com/* // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant GM_setValue // @grant GM_getValue // @license MIT // @icon https://www.pinclipart.com/picdir/big/450-4507608_twitter-circle-clipart.png // ==/UserScript== (function () { "use strict"; // ===== Настройки и инициализация ===== // const STORAGE_KEY = "hiddenKeywords"; console.log("STORAGE_KEY =", STORAGE_KEY); let hiddenKeywords = JSON.parse(localStorage.getItem(STORAGE_KEY)) || []; let hideVerifiedAccounts = true; // Скрывать подтвержденные аккаунты const languageFilters = { english: /[a-zA-Z]/, russian: /[А-Яа-яЁё]/, japanese: /[\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Han}]/u, ukrainian: /[А-Яа-яІіЄєЇїҐґ]/, belarusian: /[А-Яа-яЎўЁёІі]/, tatar: /[А-Яа-яӘәӨөҮүҖҗ]/, mongolian: /[\p{Script=Mongolian}]/u, chinese: /[\p{Script=Han}]/u, german: /[a-zA-ZßÄäÖöÜü]/, polish: /[a-zA-ZąćęłńóśźżĄĆĘŁŃÓŚŹŻ]/, french: /[a-zA-Zàâçéèêëîïôûùüÿ]/, swedish: /[a-zA-ZåäöÅÄÖ]/, estonian: /[a-zA-ZäõöüÄÕÖÜ]/, danish: /[a-zA-Z帿ŨÆ]/, turkish: /[a-zA-ZıİçÇğĞöÖşŞüÜ]/, portuguese: /[a-zA-Zàáâãçéêíóôõúü]/, }; let activeLanguageFilters = {}; // Словарь активных языков // ===== Сохранение в localStorage ===== // function saveKeywords() { console.log("saveKeywords called with", ...arguments); localStorage.setItem(STORAGE_KEY, JSON.stringify(hiddenKeywords)); } // ===== Функция для обновления отображения по языкам ===== // function updateLanguageFilter(language) { if (activeLanguageFilters[language]) { delete activeLanguageFilters[language]; } else { activeLanguageFilters[language] = languageFilters[language]; } hidePosts(); // Пересчитываем скрытие постов } // ===== Проверка языка текста ===== // function isTextInLanguage(text) { for (const [language, regex] of Object.entries(activeLanguageFilters)) { if (regex.test(text)) { return true; // Возвращаем true, если текст на этом языке } } return false; } // ===== Функция Скрытия постов ===== // function hidePosts() { document.querySelectorAll("article").forEach((article) => { // Если был клик по кнопке "Перевести пост", пропускаем скрытие для этого поста if (isTranslateButtonClicked && article.contains(document.querySelector('button[aria-expanded="false"]'))) { return; // Пропустить скрытие } const textContent = article.innerText.toLowerCase(); console.log("textContent =", textContent); const isVerifiedAccount = hideVerifiedAccounts && article.querySelector('[data-testid="icon-verified"]'); if ( hiddenKeywords.some((keyword) => textContent.includes(keyword.toLowerCase())) || isTextInLanguage(textContent) || isVerifiedAccount ) { article.style.display = "none"; } }); } // ===== Создание панели управления ===== // const panel = document.createElement("div"); panel.style.position = "fixed"; panel.style.bottom = "62px"; panel.style.right = "180px"; panel.style.width = "335px"; panel.style.height = "310px"; panel.style.padding = "8px"; panel.style.fontFamily = "Arial, sans-serif"; panel.style.backgroundColor = "#34506c"; panel.style.color = "#fff"; panel.style.borderRadius = "8px"; panel.style.boxShadow = "0 0 10px rgba(0,0,0,0.5)"; panel.style.zIndex = "9999"; panel.style.overflow = "auto"; panel.style.transition = "height 0.3s ease"; panel.innerHTML = ` <h3 style="margin: 0; font-size: 16px;">Hiding Control</h3> <input id="keywordInput" type="text" placeholder="Enter the word" style="width: calc(100% - 95px); height: 30px; padding: 5px; margin: 10px 0; border-radius: 5px; border: none;"> <div style="display: flex; flex-wrap: wrap; gap: 5px; position: relative;"> <button id="addKeyword" style="flex: 1; min-width: 70px; max-width: 70px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px;"> Add it </button> <button id="exportKeywords" style="flex: 1; min-width: 60px; max-width: 70px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px;"> Export </button> <button id="importKeywords" style="flex: 1; min-width: 60px; max-width: 70px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px;"> Import </button> <button id="clearKeywords" style="flex: 1; min-width: 60px; max-width: 80px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px; bottom: 0px; position: relative; left: 1px;"> Clear all </button> <button id="toggleVerifiedPosts" style="width: 242px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px; font-size: 13px; font-weight: bold;"> Hide verified accounts: Click to Disable </button> <button id="openLanguagePopup" style="width: 80px; display: flex; align-content: center; flex-wrap: wrap; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px; font-size: 13px; font-weight: bold;"> Language Filtering </button> </div> <ul id="keywordList" style="list-style: position: relative; inside; padding: 0; margin-top: 10px; font-size: 14px; color: #fff;"></ul> `; document.body.appendChild(panel); console.log("panel =", panel); // Создаем попап для выбора языков const languagePopup = document.createElement("div"); console.log("languagePopup =", languagePopup); languagePopup.style.display = "none"; languagePopup.style.position = "fixed"; languagePopup.style.top = "50%"; languagePopup.style.left = "67%"; languagePopup.style.right = "67%"; languagePopup.style.transform = "translate(-60%, -55%)"; languagePopup.style.backgroundColor = "rgb(52, 80, 108)"; languagePopup.style.padding = "20px"; languagePopup.style.borderRadius = "8px"; languagePopup.style.zIndex = "10000"; languagePopup.style.width = "8%"; languagePopup.style.boxShadow = "rgba(0, 0, 0, 0.5) 0px 0px 10px"; languagePopup.style.fontFamily = "Arial, sans-serif"; // Устанавливаем шрифт Arial // Добавляем чекбоксы для каждого языка for (const language in languageFilters) { const checkbox = document.createElement("input"); console.log("checkbox =", checkbox); checkbox.type = "checkbox"; checkbox.id = `lang-${language}`; checkbox.name = language; const label = document.createElement("label"); console.log("label =", label); label.htmlFor = `lang-${language}`; label.textContent = language.charAt(0).toUpperCase() + language.slice(1); const wrapper = document.createElement("div"); console.log("wrapper =", wrapper); wrapper.appendChild(checkbox); wrapper.appendChild(label); languagePopup.appendChild(wrapper); } // Добавляем кнопку закрытия попапа const closeButton = document.createElement("button"); console.log("closeButton =", closeButton); closeButton.textContent = "X"; // Стили для круглой кнопки closeButton.style.position = "relative"; closeButton.style.width = "40px"; closeButton.style.height = "40px"; closeButton.style.borderRadius = "50%"; closeButton.style.backgroundColor = "rgb(32, 49, 66)"; closeButton.style.color = "rgb(255, 255, 255)"; closeButton.style.border = "none"; closeButton.style.display = "flex"; closeButton.style.alignItems = "center"; closeButton.style.justifyContent = "center"; closeButton.style.cursor = "pointer"; closeButton.style.marginTop = "10px"; closeButton.style.boxShadow = "rgba(0, 0, 0, 0.1) 0px 4px 6px"; closeButton.style.transition = "background-color 0.3s"; closeButton.style.fontFamily = "Arial, sans-serif"; closeButton.style.left = "82%"; closeButton.style.top = "56px"; closeButton.addEventListener("click", () => { languagePopup.style.display = "none"; }); languagePopup.appendChild(closeButton); document.body.appendChild(languagePopup); // Обработчик для открытия попапа document.getElementById("openLanguagePopup").addEventListener("click", () => { languagePopup.style.display = "block"; }); // Добавляем текст с предупреждением const warningText = document.createElement("div"); console.log("warningText =", warningText); warningText.textContent = "⚠️it may stops working"; warningText.style.color = "#ffcc00"; // Желтый цвет для предупреждения warningText.style.fontSize = "14px"; warningText.style.marginBottom = "10px"; warningText.style.textAlign = "end"; warningText.style.right = "38px"; // Сдвигаем вправо на 50px warningText.style.position = "relative"; // Устанавливаем позиционирование warningText.style.top = "20px"; // Сдвигаем вниз на 15px languagePopup.appendChild(warningText); // Обработчики для чекбоксов for (const language in languageFilters) { document .getElementById(`lang-${language}`) .addEventListener("change", (event) => { updateLanguageFilter(language); }); } // Стили для подсветки const style = document.createElement("style"); console.log("style =", style); style.textContent = ` button { transition: box-shadow 0.3s, transform 0.3s; } button:hover { box-shadow: 0 0 10px rgba(255, 255, 255, 0.7); } button:active { transform: scale(0.95); box-shadow: 0 0 5px rgba(255, 255, 255, 0.7); } `; document.head.appendChild(style); // ======== Кнопка iOS-переключатель Panel FilterX ========= // // Проверяем сохраненное состояние переключателя в localStorage let isSwitchOn = localStorage.getItem("isSwitchOff") === "true"; // Начальное состояние переключателя из localStorage // Создание элементов панели const toggleButton = document.createElement("div"); console.log("toggleButton =", toggleButton); toggleButton.style.position = "fixed"; toggleButton.style.top = "94%"; toggleButton.style.right = "90px"; toggleButton.style.width = "192px"; toggleButton.style.display = "flex"; toggleButton.style.alignItems = "center"; toggleButton.style.gap = "10px"; toggleButton.style.zIndex = "1"; toggleButton.style.background = "#15202b"; toggleButton.style.border = "4px solid #6c7e8e"; toggleButton.style.borderRadius = "18px"; toggleButton.style.boxSizing = "border-box"; // Создаем label для переключателя const toggleLabel = document.createElement("label"); console.log("toggleLabel =", toggleLabel); toggleLabel.style.display = "inline-block"; toggleLabel.style.width = "50px"; toggleLabel.style.height = "25px"; toggleLabel.style.borderRadius = "25px"; toggleLabel.style.backgroundColor = "#0d1319"; toggleLabel.style.position = "relative"; toggleLabel.style.cursor = "pointer"; toggleLabel.style.transition = "background-color 0.3s"; // Создаем кружок переключателя const toggleSwitch = document.createElement("div"); console.log("toggleSwitch =", toggleSwitch); toggleSwitch.style.position = "absolute"; toggleSwitch.style.width = "21px"; toggleSwitch.style.height = "21px"; toggleSwitch.style.borderRadius = "50%"; toggleSwitch.style.backgroundColor = "#6c7e8e"; toggleSwitch.style.top = "2px"; // Устанавливаем начальное положение кружка в зависимости от состояния toggleSwitch.style.left = isSwitchOn ? "calc(100% - 23px)" : "2px"; // Если выключено, то слева, если включено — справа // Плавная анимация toggleSwitch.style.transition = "left 0.3s ease"; toggleSwitch.style.boxShadow = "rgb(21, 32, 43) -1px 1px 4px 1px"; // Устанавливаем начальное состояние фона toggleLabel.style.backgroundColor = isSwitchOn ? "#425364" : "#0d1319"; // Функция для изменения состояния переключателя function toggleSwitchState() { isSwitchOn = !isSwitchOn; localStorage.setItem("isSwitchOn", isSwitchOn.toString()); // Сохраняем состояние в localStorage (как строку) // Обновляем стиль переключателя toggleSwitch.style.left = isSwitchOn ? "calc(100% - 23px)" : "2px"; toggleLabel.style.backgroundColor = isSwitchOn ? "#425364" : "#0d1319"; } // Добавляем обработчик на клик по переключателю toggleButton.addEventListener("click", toggleSwitchState); // Добавляем элементы на страницу toggleLabel.appendChild(toggleSwitch); toggleButton.appendChild(toggleLabel); document.body.appendChild(toggleButton); // Добавление текста к переключателю const toggleText = document.createElement("span"); console.log("toggleText =", toggleText); toggleText.style.position = "relative"; toggleText.style.right = "5px"; toggleText.textContent = "Panel FilterX"; toggleText.style.color = "#6c7e8e"; toggleText.style.fontFamily = "Arial, sans-serif"; toggleText.style.fontSize = "16px"; toggleText.style.marginLeft = "10px"; toggleText.style.fontWeight = "bold"; toggleButton.appendChild(toggleText); //====================== Управление высотой панели =======================// let isPanelVisible = localStorage.getItem("panelVisible") === "truefalse"; // По умолчанию скрыта, если в localStorage не сохранено другое значение function togglePanel() { if (isPanelVisible) { panel.style.height = "0px"; // Сворачиваем панель setTimeout(() => { panel.style.display = "none"; // Скрываем панель после анимации }, 300); } else { panel.style.display = "block"; // Показываем панель setTimeout(() => { panel.style.height = "310px"; // Разворачиваем панель }, 10); } isPanelVisible = !isPanelVisible; // Переключаем состояние localStorage.setItem("panelVisible", isPanelVisible.toString()); // Сохраняем состояние } toggleButton.addEventListener("click", togglePanel); // При загрузке восстанавливаем состояние панели if (isPanelVisible) { panel.style.height = "310px"; // Разворачиваем панель panel.style.display = "block"; } else { panel.style.height = "0px"; // Сворачиваем панель panel.style.display = "none"; } // ===== Обработчики событий ===== // document.getElementById("addKeyword").addEventListener("click", () => { const input = document.getElementById("keywordInput"); console.log("input =", input); const keyword = input.value.trim(); console.log("keyword =", keyword); if (keyword && !hiddenKeywords.includes(keyword)) { hiddenKeywords.push(keyword); saveKeywords(); updateKeywordList(); hidePosts(); input.value = ""; } }); document.getElementById("clearKeywords").addEventListener("click", () => { if (confirm("Are you sure you want to clear the list?")) { hiddenKeywords = []; saveKeywords(); updateKeywordList(); hidePosts(); } }); document.getElementById("exportKeywords").addEventListener("click", () => { const dataStr = `data:text/json; console.log('dataStr =', dataStr);charset=utf-8,${encodeURIComponent( JSON.stringify(hiddenKeywords), )}`; const downloadAnchor = document.createElement("a"); console.log("downloadAnchor =", downloadAnchor); downloadAnchor.setAttribute("href", dataStr); downloadAnchor.setAttribute("download", "hidden_keywords.json"); document.body.appendChild(downloadAnchor); downloadAnchor.click(); document.body.removeChild(downloadAnchor); }); document.getElementById("importKeywords").addEventListener("click", () => { const input = document.createElement("input"); console.log("input =", input); input.type = "file"; input.accept = "application/json"; input.addEventListener("change", (event) => { const file = event.target.files[0]; console.log("file =", file); const reader = new FileReader(); console.log("reader =", reader); reader.onload = () => { try { const importedKeywords = JSON.parse(reader.result); console.log("importedKeywords =", importedKeywords); if (Array.isArray(importedKeywords)) { hiddenKeywords = [ ...new Set([...hiddenKeywords, ...importedKeywords]), ]; saveKeywords(); updateKeywordList(); hidePosts(); } else { alert("Incorrect file format."); } } catch (e) { alert("Error reading the file."); } }; reader.readAsText(file); }); input.click(); }); // Переменная для отслеживания клика на кнопку "Перевести пост" let isTranslateButtonClicked = false; // Функция для отслеживания клика по кнопке "Перевести пост" function handleTranslateButtonClick(event) { isTranslateButtonClicked = true; setTimeout(() => { isTranslateButtonClicked = false; }, 500); // Сбросить флаг через 500 мс } // ===== Наблюдатель за кнопками "Перевести пост" ===== // function observeTranslateButton() { document.querySelectorAll('button[aria-expanded="false"]').forEach(button => { button.removeEventListener('click', handleTranslateButtonClick); // Убираем старые обработчики button.addEventListener('click', handleTranslateButtonClick); // Добавляем новый обработчик }); } // ===== Кнопка для включения/выключения скрытия подтвержденных аккаунтов ===== // document .getElementById("toggleVerifiedPosts") .addEventListener("click", () => { hideVerifiedAccounts = !hideVerifiedAccounts; document.getElementById("toggleVerifiedPosts").textContent = `Hide verified accounts: ${ hideVerifiedAccounts ? "Turn OFF" : "Turn ON" }`; hidePosts(); // Перепроверка всех постов с новыми настройками }); // ===== Функция для применения кастомного скроллбара ===== // function applyCustomScrollbar() { const style = document.createElement("style"); style.id = "custom-scrollbar-style"; style.innerHTML = ` #keywordList::-webkit-scrollbar { width: 8px; } #keywordList::-webkit-scrollbar-thumb { background:rgb(143, 23, 79); border-radius: 4px; } #keywordList::-webkit-scrollbar-track { background:rgb(44, 173, 55); } `; if (!document.getElementById("custom-scrollbar-style")) { document.head.appendChild(style); } } // ===== Функция для наблюдения за изменениями в списке ===== // function observeKeywordList() { const list = document.getElementById("keywordList"); if (!list) return; const observer = new MutationObserver(() => { console.log( "Обнаружены изменения в списке ключевых слов, обновляем стили...", ); applyCustomScrollbar(); }); observer.observe(list, { childList: true, subtree: true }); } // ===== Обновление списка ключевых слов ===== // function updateKeywordList() { const list = document.getElementById("keywordList"); console.log("list =", list); list.style.listStyle = "inside"; list.style.padding = "0px 10px 0px 0px"; list.style.marginTop = "10px"; list.style.fontSize = "14px"; list.style.color = "rgb(255, 255, 255)"; list.style.maxHeight = "135px"; list.style.overflowY = "auto"; list.style.border = "1px solid rgb(204, 204, 204)"; list.style.borderRadius = "5px"; list.style.backgroundColor = "rgb(21, 32, 43)"; list.style.boxShadow = "rgba(0, 0, 0, 0.3) 0px 2px 5px"; list.style.position = "relative"; list.style.width = "315px"; list.innerHTML = ""; hiddenKeywords.forEach((keyword, index) => { const listItem = document.createElement("li"); console.log("listItem =", listItem); listItem.textContent = keyword; listItem.style.marginBottom = "5px"; const deleteButton = document.createElement("button"); console.log("deleteButton =", deleteButton); deleteButton.textContent = "❌"; deleteButton.style.marginLeft = "10px"; deleteButton.style.backgroundColor = "#f44336"; deleteButton.style.color = "#fff"; deleteButton.style.border = "none"; deleteButton.style.borderRadius = "3px"; deleteButton.style.cursor = "pointer"; deleteButton.addEventListener("click", () => { hiddenKeywords.splice(index, 1); saveKeywords(); updateKeywordList(); hidePosts(); }); listItem.appendChild(deleteButton); list.appendChild(listItem); }); if (hiddenKeywords.length === 0) { list.textContent = "Нет"; } applyCustomScrollbar(); // Применяем кастомный скроллбар observeKeywordList(); // Повторно запускаем наблюдатель } // Запуск кастомного скролла и наблюдателя при загрузке страницы applyCustomScrollbar(); observeKeywordList(); // ===== Инициализация ===== // updateKeywordList(); // Обновление списка при загрузке страницы hidePosts(); // ===== Наблюдатель для динамического контента ===== // const observer = new MutationObserver(() => { hidePosts(); observeTranslateButton(); // Обновляем наблюдатель за кнопками }); observer.observe(document.body, { childList: true, subtree: true }); })();