- // ==UserScript==
- // @name Panel Control XFilter 2.4.57 (c) tapeavion
- // @namespace http://tampermonkey.net/
- // @version 2.4.57
- // @description Hide posts by keywords with the dashboard and hide posts from verified accounts
- // @author gullampis810
- // @match https://x.com/*
- // @match https://x.com/i/grok*
- // @match https://blank.org/*
- // @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";
- const FAVORITE_USERS_KEY = "favoriteUsers";
- let hiddenKeywords = JSON.parse(localStorage.getItem(STORAGE_KEY)) || [];
- let favoriteUsers = JSON.parse(localStorage.getItem(FAVORITE_USERS_KEY)) || [];
- let unblockedKeywords = JSON.parse(localStorage.getItem("unblockedKeywords")) || [];
- let hideVerifiedAccounts = false;
- let hideNonVerifiedAccounts = JSON.parse(localStorage.getItem("hideNonVerifiedAccounts")) || false;
- let isShowingFavorites = false;
- 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 = {};
-
- // Получение имени пользователя из профиля
- function getUsernameFromProfile() {
- const profileUrl = window.location.href;
- const match = profileUrl.match(/x\.com\/([^\?\/]+)/);
- if (match && match[1]) {
- return match[1].toLowerCase();
- }
- const usernameElement = document.querySelector('a[href*="/"][role="link"] div[dir="ltr"] span');
- return usernameElement ? usernameElement.textContent.replace('@', '').toLowerCase() : '';
- }
-
- // ===== Сохранение в localStorage ===== //
- function saveKeywords() {
- localStorage.setItem(STORAGE_KEY, JSON.stringify(hiddenKeywords));
- }
-
- function saveFavoriteUsers() {
- localStorage.setItem(FAVORITE_USERS_KEY, JSON.stringify(favoriteUsers));
- }
-
- function saveUnblockedKeywords() {
- localStorage.setItem("unblockedKeywords", JSON.stringify(unblockedKeywords));
- }
-
- // ===== Функция для обновления фильтров по языкам ===== //
- 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;
- }
- }
- return false;
- }
-
- // ===== Функция скрытия постов ===== //
- function hidePosts() {
- document.querySelectorAll("article").forEach((article) => {
- const textContent = article.innerText.toLowerCase();
- const isVerifiedAccount = article.querySelector('[data-testid="icon-verified"]');
- const usernameElement = article.querySelector('a[href*="/"]');
- const username = usernameElement ? usernameElement.getAttribute("href").slice(1).toLowerCase() : "";
-
- const isFavoriteUser = favoriteUsers.includes(username);
-
- if (isFavoriteUser) {
- article.style.display = "";
- return;
- }
-
- const matchesKeyword = hiddenKeywords.some((keyword) => {
- try {
- return new RegExp(keyword, "i").test(textContent);
- } catch (e) {
- return textContent.includes(keyword.toLowerCase());
- }
- });
-
- const shouldHideVerified = hideVerifiedAccounts && isVerifiedAccount;
- const shouldHideNonVerified = hideNonVerifiedAccounts && !isVerifiedAccount;
- const shouldHideByLanguage = isTextInLanguage(textContent);
- const shouldHideByKeyword = matchesKeyword;
-
- if (shouldHideVerified || shouldHideNonVerified || shouldHideByLanguage || shouldHideByKeyword) {
- article.style.display = "none";
- } else {
- article.style.display = "";
- }
- });
- }
-
- // ===== Debounce для оптимизации ===== //
- function debounce(func, wait) {
- let timeout;
- return function (...args) {
- clearTimeout(timeout);
- timeout = setTimeout(() => func.apply(this, args), wait);
- };
- }
-
- const debouncedHidePosts = debounce(hidePosts, 200);
-
- // ===== Создание панели управления ===== //
- const panel = document.createElement("div");
- panel.style.position = "fixed";
- panel.style.bottom = "62px";
- panel.style.right = "180px";
- panel.style.width = "335px";
- panel.style.height = "510px";
- 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>
- <h4 class="version-text">v2.4.57</h4>
- <div style="display: flex; align-items: center; gap: 5px; margin: 10px 0;">
- <input id="keywordInput" type="text" placeholder="Enter the word or @username" style="width: calc(100% - 95px); height: 40px; padding: 5px; border-radius: 5px; border: none; background: #15202b; color: #fff;">
- <button id="addKeyword" style="min-width: 79px; max-width: 80px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px;">Add it</button>
- </div>
- <div style="display: flex; flex-wrap: wrap; gap: 5px; position: relative;">
- <div style="display: flex; align-items: center; gap: 5px;">
- <div id="searchWrapper" style="position: relative;">
- <input id="searchInput" type="text" placeholder="Search keywords or users" style="width: 240px; height: 40px; padding: 5px; border-radius: 5px; border: none; background-color: #15202b; color: #fff;">
- <span id="clearSearch" style="display: none; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); color: #fff; cursor: pointer;">✖</span>
- </div>
- <button id="openLanguagePopup" style="width: 80px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px; font-size: 13px; font-weight: bold;">Language Filtering</button>
- </div>
- <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="toggleBlockKeywords" style="flex: 1; min-width: 80px; max-width: 90px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px; font-size: 13px; font-weight: bold;">Unblock All</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;">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 Enable</button>
- <button id="toggleNonVerifiedPosts" style="width: 242px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px; font-size: 13px; font-weight: bold;">Hide non-verified accounts: Turn ON</button>
- <button id="toggleFavoriteUsers" style="width: 80px; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; height: 40px; font-size: 13px; font-weight: bold;">Favorite Users</button>
- </div>
- <div id="listLabel" style="margin-top: 10px; font-size: 14px; color: #fff;">List of Keywords</div>
- <ul id="keywordList" style="list-style: position: relative; inside; padding: 0; margin-top: 5px; font-size: 14px; color: #fff; max-height: 135px; overflow-y: auto; border: 1px solid #ccc; border-radius: 5px; background-color: #15202b; box-shadow: 0 2px 5px rgba(0,0,0,0.3);"></ul>
- `;
-
- document.body.appendChild(panel);
-
- const searchInput = document.getElementById("searchInput");
- const clearSearch = document.getElementById("clearSearch");
-
- searchInput.addEventListener("input", () => {
- clearSearch.style.display = searchInput.value.trim() ? "block" : "none";
- updateKeywordList();
- });
-
- clearSearch.addEventListener("click", () => {
- searchInput.value = "";
- clearSearch.style.display = "none";
- updateKeywordList();
- });
-
- const lengthFilterInput = document.createElement("input");
- lengthFilterInput.type = "number";
- lengthFilterInput.placeholder = "Min length";
- lengthFilterInput.style.width = "80px";
- lengthFilterInput.style.marginTop = "10px";
- panel.appendChild(lengthFilterInput);
-
- lengthFilterInput.addEventListener("change", () => {
- debouncedHidePosts();
- });
-
- // ===== Предотвращение перетаскивания для поля ввода ===== //
- const keywordInput = document.getElementById("keywordInput");
- keywordInput.addEventListener("mousedown", (event) => {
- event.stopPropagation();
- });
-
- // ===== Перетаскивание панели ===== //
- let isDragging = false;
- let offsetX = 0;
- let offsetY = 0;
-
- panel.addEventListener("mousedown", (event) => {
- isDragging = true;
- offsetX = event.clientX - panel.offsetLeft;
- offsetY = event.clientY - panel.offsetTop;
- panel.style.cursor = "grabbing";
- });
-
- document.addEventListener("mousemove", (event) => {
- if (isDragging) {
- panel.style.left = event.clientX - offsetX + "px";
- panel.style.top = event.clientY - offsetY + "px";
- }
- });
-
- document.addEventListener("mouseup", () => {
- isDragging = false;
- panel.style.cursor = "grab";
- });
-
- // ===== Создание попапа для языков ===== //
- const languagePopup = document.createElement("div");
- languagePopup.style.display = "none";
- languagePopup.style.position = "fixed";
- languagePopup.style.top = "460px";
- languagePopup.style.right = "65px";
- languagePopup.style.transform = "translate(-52%, 7%)";
- languagePopup.style.backgroundColor = "#34506c";
- languagePopup.style.padding = "20px";
- languagePopup.style.borderRadius = "8px";
- languagePopup.style.zIndex = "10000";
- languagePopup.style.width = "8%";
- languagePopup.style.boxShadow = "0 0 10px rgba(0,0,0,0.5)";
- languagePopup.style.fontFamily = "Arial, sans-serif";
-
- for (const language in languageFilters) {
- const checkbox = document.createElement("input");
- checkbox.type = "checkbox";
- checkbox.id = `lang-${language}`;
- checkbox.name = language;
-
- const label = document.createElement("label");
- label.htmlFor = `lang-${language}`;
- label.textContent = language.charAt(0).toUpperCase() + language.slice(1);
-
- const wrapper = document.createElement("div");
- wrapper.appendChild(checkbox);
- wrapper.appendChild(label);
- languagePopup.appendChild(wrapper);
- }
-
- const closeButton = document.createElement("button");
- closeButton.textContent = "X";
- closeButton.style.position = "relative";
- closeButton.style.width = "40px";
- closeButton.style.height = "40px";
- closeButton.style.borderRadius = "50%";
- closeButton.style.backgroundColor = "#203142";
- closeButton.style.color = "#fff";
- 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.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");
- 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";
- warningText.style.position = "relative";
- warningText.style.top = "20px";
- languagePopup.appendChild(warningText);
-
- for (const language in languageFilters) {
- document.getElementById(`lang-${language}`).addEventListener("change", () => {
- updateLanguageFilter(language);
- });
- }
-
- // ===== Стили для подсветки и скроллбара ===== //
- const style = document.createElement("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);
- }
- #keywordList::-webkit-scrollbar {
- width: 25px;
- }
- #keywordList::-webkit-scrollbar-thumb {
- background-color: #C1A5EF;
- border-radius: 8px;
- border: 3px solid #4F3E6A;
- height: 80px;
- }
- #keywordList::-webkit-scrollbar-thumb:hover {
- background-color: #C6AEFF;
- }
- #keywordList::-webkit-scrollbar-thumb:active {
- background-color: #B097C9;
- }
- #keywordList::-webkit-scrollbar-track {
- background: #455565;
- border-radius: 0px 0px 8px 0px;
- }
- .version-text {
- left: 275px;
- position: relative;
- bottom: 18px;
- color: #15202b;
- margin: 0;
- font-size: 14px;
- width: 47px;
- }
- #keywordInput {
- cursor: #ffffff59;
- background: #15202b;
- }
- #favoriteUserButton:hover img {
- filter: brightness(1.2);
- }
- #favoriteUserButton:active img {
- transform: scale(0.9);
- }
- `;
- document.head.appendChild(style);
-
- // ===== Кнопка переключения панели FilterX ===== //
- let isSwitchOn = localStorage.getItem("isSwitchOn") === "true";
- const toggleButton = document.createElement("div");
- toggleButton.style.display = "flex";
- toggleButton.style.alignItems = "center";
- toggleButton.style.gap = "10px";
- toggleButton.style.background = " #15202b";
- toggleButton.style.border = "4px solid #6c7e8e";
- toggleButton.style.borderRadius = "45px";
- toggleButton.style.padding = "8px 12px";
- toggleButton.style.marginTop = "10px";
- toggleButton.style.cursor = "pointer";
- toggleButton.style.width = "auto";
- toggleButton.className = "css-175oi2r r-16y2uox";
-
- function isGrokPage() {
- return window.location.href.startsWith("https://x.com/i/grok");
- }
-
- const toggleLabel = document.createElement("label");
- toggleLabel.style.display = "inline-block";
- toggleLabel.style.width = "50px";
- toggleLabel.style.height = "25px";
- toggleLabel.style.borderRadius = "25px";
- toggleLabel.style.backgroundColor = isSwitchOn ? " #425364" : " #0d1319";
- toggleLabel.style.position = "relative";
- toggleLabel.style.cursor = "pointer";
- toggleLabel.style.transition = "background-color 0.3s";
- toggleLabel.style.top = "0px";
- toggleLabel.style.left = "75px";
-
- const toggleSwitch = document.createElement("div");
- 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";
-
- function toggleSwitchState(event) {
- event.stopPropagation();
- isSwitchOn = !isSwitchOn;
- localStorage.setItem("isSwitchOn", isSwitchOn.toString());
- toggleSwitch.style.left = isSwitchOn ? "calc(100% - 23px)" : "2px";
- toggleLabel.style.backgroundColor = isSwitchOn ? " #425364" : " #0d1319";
-
- if (isSwitchOn) {
- panel.style.display = "block";
- setTimeout(() => {
- panel.style.height = "485px";
- }, 10);
- } else {
- panel.style.height = "0px";
- setTimeout(() => {
- panel.style.display = "none";
- }, 300);
- }
- isPanelVisible = isSwitchOn;
- localStorage.setItem("panelVisible", isPanelVisible.toString());
- }
-
- const debouncedToggleSwitchState = debounce(toggleSwitchState, 300);
-
- toggleButton.addEventListener("click", debouncedToggleSwitchState);
- toggleLabel.appendChild(toggleSwitch);
- toggleButton.appendChild(toggleLabel);
-
- const toggleText = document.createElement("span");
- toggleText.textContent = "FilterX";
- toggleText.style.color = " #6c7e8e";
- toggleText.style.fontFamily = "Arial, sans-serif";
- toggleText.style.fontSize = "16px";
- toggleText.style.fontWeight = "bold";
- toggleText.style.position = "absolute";
- toggleText.style.top = "12px";
- toggleText.style.left = "25px";
- toggleButton.appendChild(toggleText);
-
- function waitForPostButton(callback) {
- const interval = setInterval(() => {
- const postButton = document.querySelector("[data-testid='SideNav_NewTweet_Button']");
- const postButtonContainer = postButton?.parentElement;
- if (postButtonContainer) {
- clearInterval(interval);
- callback(postButtonContainer);
- } else {
- console.warn("Контейнер кнопки 'Опубликовать пост' не найден");
- }
- }, 500);
- }
-
- waitForPostButton((postButtonContainer) => {
- toggleButton.style.display = isGrokPage() ? "none" : "flex";
- postButtonContainer.appendChild(toggleButton);
- });
-
- // ===== Управление высотой панели ===== //
- let isPanelVisible = localStorage.getItem("panelVisible") === "true";
-
- function togglePanel() {
- if (isPanelVisible) {
- panel.style.height = "0px";
- setTimeout(() => {
- panel.style.display = "none";
- }, 300);
- } else {
- panel.style.display = "block";
- setTimeout(() => {
- panel.style.height = "510px";
- }, 10);
- }
- isPanelVisible = !isPanelVisible;
- localStorage.setItem("panelVisible", isPanelVisible.toString());
- }
-
- toggleButton.addEventListener("click", togglePanel);
-
- if (isPanelVisible) {
- panel.style.height = "510px";
- panel.style.display = "block";
- } else {
- panel.style.height = "0px";
- panel.style.display = "none";
- }
-
- // ===== Элементы управления ===== //
- const addKeywordBtn = document.getElementById("addKeyword");
- const clearKeywordsBtn = document.getElementById("clearKeywords");
- const exportKeywordsBtn = document.getElementById("exportKeywords");
- const importKeywordsBtn = document.getElementById("importKeywords");
- const toggleVerifiedBtn = document.getElementById("toggleVerifiedPosts");
- const toggleNonVerifiedBtn = document.getElementById("toggleNonVerifiedPosts");
- const toggleBlockBtn = document.getElementById("toggleBlockKeywords");
- const openLanguagePopupBtn = document.getElementById("openLanguagePopup");
- const toggleFavoriteUsersBtn = document.getElementById("toggleFavoriteUsers");
- const keywordList = document.getElementById("keywordList");
-
- // ===== Обработчики событий ===== //
- addKeywordBtn.addEventListener("click", () => {
- const inputValue = keywordInput.value.trim();
- if (inputValue) {
- if (isShowingFavorites && inputValue.startsWith("@")) {
- const username = inputValue.slice(1).toLowerCase();
- if (!favoriteUsers.includes(username)) {
- favoriteUsers.push(username);
- saveFavoriteUsers();
- updateKeywordList();
- debouncedHidePosts();
- }
- } else if (!isShowingFavorites && !hiddenKeywords.includes(inputValue)) {
- hiddenKeywords.push(inputValue);
- saveKeywords();
- updateKeywordList();
- debouncedHidePosts();
- }
- keywordInput.value = "";
- }
- });
-
- toggleNonVerifiedBtn.textContent = `Hide non-verified accounts: ${hideNonVerifiedAccounts ? "Turn OFF" : "Turn ON"}`;
- toggleNonVerifiedBtn.addEventListener("click", () => {
- hideNonVerifiedAccounts = !hideNonVerifiedAccounts;
- localStorage.setItem("hideNonVerifiedAccounts", JSON.stringify(hideNonVerifiedAccounts));
- toggleNonVerifiedBtn.textContent = `Hide non-verified accounts: ${hideNonVerifiedAccounts ? "Turn OFF" : "Turn ON"}`;
- hidePosts();
- });
-
- clearKeywordsBtn.addEventListener("click", () => {
- if (confirm("Are you sure you want to clear the list?")) {
- if (isShowingFavorites) {
- favoriteUsers = [];
- saveFavoriteUsers();
- } else {
- hiddenKeywords = [];
- unblockedKeywords = [];
- saveKeywords();
- saveUnblockedKeywords();
- }
- updateKeywordList();
- hidePosts();
- }
- });
-
- exportKeywordsBtn.addEventListener("click", () => {
- const data = isShowingFavorites ? favoriteUsers : hiddenKeywords;
- const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent(JSON.stringify(data))}`;
- const downloadAnchor = document.createElement("a");
- downloadAnchor.setAttribute("href", dataStr);
- downloadAnchor.setAttribute("download", isShowingFavorites ? "favorite_users.json" : "hidden_keywords.json");
- document.body.appendChild(downloadAnchor);
- downloadAnchor.click();
- document.body.removeChild(downloadAnchor);
- });
-
- importKeywordsBtn.addEventListener("click", () => {
- const input = document.createElement("input");
- input.type = "file";
- input.accept = "application/json";
- input.addEventListener("change", (event) => {
- const file = event.target.files[0];
- const reader = new FileReader();
- reader.onload = () => {
- try {
- const importedData = JSON.parse(reader.result);
- if (Array.isArray(importedData)) {
- if (isShowingFavorites) {
- favoriteUsers = [...new Set([...favoriteUsers, ...importedData.map(u => u.startsWith("@") ? u.slice(1).toLowerCase() : u.toLowerCase())])];
- saveFavoriteUsers();
- } else {
- hiddenKeywords = [...new Set([...hiddenKeywords, ...importedData])];
- saveKeywords();
- }
- updateKeywordList();
- hidePosts();
- } else {
- alert("Incorrect file format.");
- }
- } catch (e) {
- alert("Error reading the file.");
- }
- };
- reader.readAsText(file);
- });
- input.click();
- });
-
- toggleBlockBtn.addEventListener("click", () => {
- if (!isShowingFavorites) {
- if (hiddenKeywords.length > 0) {
- unblockedKeywords = [...hiddenKeywords];
- hiddenKeywords = [];
- toggleBlockBtn.textContent = "Block All";
- } else {
- hiddenKeywords = [...unblockedKeywords];
- unblockedKeywords = [];
- toggleBlockBtn.textContent = "Unblock All";
- }
- saveKeywords();
- saveUnblockedKeywords();
- updateKeywordList();
- hidePosts();
- }
- });
-
- toggleBlockBtn.textContent = hiddenKeywords.length > 0 ? "Unblock All" : "Block All";
-
- toggleVerifiedBtn.addEventListener("click", () => {
- hideVerifiedAccounts = !hideVerifiedAccounts;
- toggleVerifiedBtn.textContent = `Hide verified accounts: ${hideVerifiedAccounts ? "Turn OFF" : "Turn ON"}`;
- hidePosts();
- });
-
- toggleFavoriteUsersBtn.addEventListener("click", () => {
- isShowingFavorites = !isShowingFavorites;
- toggleFavoriteUsersBtn.textContent = isShowingFavorites ? "Keywords" : "Favorite Users";
- keywordInput.placeholder = isShowingFavorites ? "Enter @username" : "Enter the word";
- updateKeywordList();
- });
-
- openLanguagePopupBtn.addEventListener("click", () => {
- const panelRect = panel.getBoundingClientRect();
- languagePopup.style.top = `${panelRect.top - 320}px`;
- languagePopup.style.left = `${panelRect.right - 10}px`;
- languagePopup.style.display = "block";
- });
-
- // ===== Обновление списка ключевых слов или избранных пользователей ===== //
- function updateKeywordList() {
- const list = document.getElementById("keywordList");
- const label = document.getElementById("listLabel");
- const searchInput = document.getElementById("searchInput");
- const searchQuery = searchInput ? searchInput.value.trim().toLowerCase() : "";
- list.innerHTML = "";
-
- if (isShowingFavorites) {
- label.textContent = "Favorite Users";
- const filteredUsers = favoriteUsers.filter(user => user.toLowerCase().includes(searchQuery));
- if (filteredUsers.length === 0) {
- list.textContent = searchQuery ? "No matches found" : "Нет";
- } else {
- filteredUsers.forEach((user, index) => {
- const listItem = document.createElement("li");
- listItem.textContent = `@${user}`;
- listItem.style.marginBottom = "5px";
-
- const deleteButton = document.createElement("button");
- 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", () => {
- favoriteUsers.splice(favoriteUsers.indexOf(user), 1);
- saveFavoriteUsers();
- updateKeywordList();
- hidePosts();
- });
-
- listItem.appendChild(deleteButton);
- list.appendChild(listItem);
- });
- }
- } else {
- label.textContent = "List of Keywords";
- const filteredKeywords = hiddenKeywords.filter(keyword => keyword.toLowerCase().includes(searchQuery));
- if (filteredKeywords.length === 0) {
- list.textContent = searchQuery ? "No matches found" : "Нет";
- } else {
- filteredKeywords.forEach((keyword, index) => {
- const listItem = document.createElement("li");
- listItem.textContent = keyword;
- listItem.style.marginBottom = "5px";
-
- const deleteButton = document.createElement("button");
- 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(hiddenKeywords.indexOf(keyword), 1);
- saveKeywords();
- updateKeywordList();
- hidePosts();
- });
-
- listItem.appendChild(deleteButton);
- list.appendChild(listItem);
- });
- }
- }
- }
-
- // ===== Создание кнопки избранного в профиле ===== //
- function addFavoriteButtonToProfile() {
- const buttonContainer = document.querySelector('.css-175oi2r.r-obd0qt.r-18u37iz.r-1w6e6rj.r-1h0z5md.r-dnmrzs');
- if (!buttonContainer || buttonContainer.querySelector('#favoriteUserButton')) {
- return;
- }
-
- const username = getUsernameFromProfile();
- if (!username) {
- return;
- }
-
- const isFavorite = favoriteUsers.includes(username);
-
- const favoriteButton = document.createElement('button');
- favoriteButton.id = 'favoriteUserButton';
- favoriteButton.setAttribute('aria-label', isFavorite ? 'Удалить из избранного' : 'Добавить в избранное');
- favoriteButton.setAttribute('role', 'button');
- favoriteButton.type = 'button';
- favoriteButton.className = 'css-175oi2r r-sdzlij r-1phboty r-rs99b7 r-lrvibr r-6gpygo r-1wron08 r-2yi16 r-1qi8awa r-1loqt21 r-o7ynqc r-6416eg r-1ny4l3l css-175oi2r r-18u37iz r-1wtj0ep';
- favoriteButton.style.borderColor = 'rgb(83, 100, 113)';
- favoriteButton.style.backgroundColor = 'rgba(0, 0, 0, 0)';
-
- const buttonContent = document.createElement('div');
- buttonContent.dir = 'ltr';
- buttonContent.className = 'css-146c3p1 r-bcqeeo r-qvutc0 r-1qd0xha r-q4m81j r-a023e6 r-rjixqe r-b88u0q r-1awozwy r-6koalj r-18u37iz r-16y2uox r-1777fci';
- buttonContent.style.color = 'rgb(239, 243, 244)';
-
- const icon = document.createElement('img');
- // PNG из вашего SVG в base64
- icon.src = 'data:image/png;base64,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';
- icon.style.width = '25px';
- icon.style.height = '25px';
- icon.style.filter = isFavorite ? 'hue-rotate(300deg) saturate(2)' : 'none'; // для изменения цвета
- icon.setAttribute('aria-hidden', 'true');
- icon.className = 'r-4qtqp9 r-yyyyoo r-dnmrzs r-bnwqim r-lrvibr r-m6rgpd r-z80fyv r-19wmn03';
-
- buttonContent.appendChild(icon);
- favoriteButton.appendChild(buttonContent);
-
- favoriteButton.addEventListener('click', () => {
- if (isFavorite) {
- favoriteUsers = favoriteUsers.filter(user => user !== username);
- favoriteButton.setAttribute('aria-label', 'Добавить в избранное');
- icon.style.filter = 'none';
- } else if (!favoriteUsers.includes(username)) {
- favoriteUsers.push(username);
- favoriteButton.setAttribute('aria-label', 'Удалить из избранного');
- icon.style.filter = 'hue-rotate(300deg) saturate(2)';
- }
- saveFavoriteUsers();
- updateKeywordList();
- debouncedHidePosts();
- });
-
- buttonContainer.insertBefore(favoriteButton, buttonContainer.firstChild);
- }
-
- // ===== Автоматическое скрытие панели при открытии фото ===== //
- function isPhotoViewerOpen() {
- const currentUrl = window.location.href;
- const isPhotoOpen = /\/photo\/\d+$/.test(currentUrl);
- const photoModal = document.querySelector('div[aria-label="Image"]') || document.querySelector('div[data-testid="imageViewer"]');
- return isPhotoOpen || !!photoModal;
- }
-
- function updateToggleButtonVisibility() {
- toggleButton.style.display = isGrokPage() ? "none" : "flex";
- }
-
- function toggleElementsVisibility() {
- const isPhotoOpen = isPhotoViewerOpen();
- if (isPhotoOpen || isGrokPage()) {
- panel.style.display = "none";
- toggleButton.style.display = "none";
- } else {
- if (isPanelVisible) {
- panel.style.display = "block";
- panel.style.height = "510px";
- }
- toggleButton.style.display = "flex";
- }
- }
-
- // ===== Наблюдение за изменениями DOM ===== //
- const observer = new MutationObserver(() => {
- debouncedHidePosts();
- });
- observer.observe(document.body, { childList: true, subtree: true });
-
- const profileObserver = new MutationObserver(() => {
- if (window.location.href.includes('x.com/') && !window.location.href.includes('/status/')) {
- addFavoriteButtonToProfile();
- }
- });
- profileObserver.observe(document.body, { childList: true, subtree: true });
-
- toggleElementsVisibility();
- window.addEventListener("popstate", () => {
- updateToggleButtonVisibility();
- toggleElementsVisibility();
- });
-
- const urlObserver = new MutationObserver(() => {
- updateToggleButtonVisibility();
- toggleElementsVisibility();
- });
- urlObserver.observe(document.body, { childList: true, subtree: true });
-
- document.addEventListener("click", (event) => {
- if (event.target.closest('div[aria-label="Close"]') || event.target.closest('div[data-testid="imageViewer-close"]')) {
- setTimeout(toggleElementsVisibility, 100);
- }
- });
-
- // ===== Инициализация ===== //
- updateKeywordList();
- hidePosts();
- })();