// ==UserScript==
// @name PanelControl XFilter Twitter X-com Hide Posts by Keywords (c) tapeavion 1.5
// @namespace http://tampermonkey.net/
// @version 1.5
// @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
// @downloadURL none
// ==/UserScript==
(function () {
'use strict';
// ===== Настройки и инициализация ===== //
const STORAGE_KEY = 'hiddenKeywords';
let hiddenKeywords = JSON.parse(localStorage.getItem(STORAGE_KEY)) || [];
let hideVerifiedAccounts = true; // Скрывать подтвержденные аккаунты
// ===== Сохранение в localStorage ===== //
function saveKeywords() {
localStorage.setItem(STORAGE_KEY, JSON.stringify(hiddenKeywords));
}
//==================== функция скрытия ==================//
function hidePosts() {
document.querySelectorAll('article').forEach((article) => {
// Проверка текста поста на наличие скрытых ключевых слов
const textContent = article.innerText.toLowerCase();
// Проверяем никнейм на наличие эмодзи
const userNameContainer = article.querySelector('[data-testid="User-Name"]');
let hasEmojiInUsername = false;
if (userNameContainer) {
const userNameText = userNameContainer.innerText.toLowerCase();
hasEmojiInUsername = hiddenKeywords.some(keyword => userNameText.includes(keyword.toLowerCase()));
if (!hasEmojiInUsername) {
const emojiImages = userNameContainer.querySelectorAll('img[alt]');
hasEmojiInUsername = Array.from(emojiImages).some(img =>
hiddenKeywords.includes(img.alt.trim())
);
}
}
// Проверка подтвержденного аккаунта
const isVerifiedAccount = hideVerifiedAccounts && article.querySelector('[data-testid="icon-verified"]');
// Скрываем пост, если найдено совпадение
if (hiddenKeywords.some(keyword => textContent.includes(keyword.toLowerCase())) ||
hasEmojiInUsername ||
isVerifiedAccount) {
article.style.display = 'none';
}
});
}
// ===== Создаем панель управления ===== //
function createControlPanel() {
const panel = document.createElement('div');
panel.style.position = 'fixed';
panel.style.bottom = '0px';
panel.style.right = '440px';
panel.style.width = '300px';
panel.style.height = '420px';
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 = 'hidden'; // Скрывать содержимое
panel.style.transition = 'height 0.3s ease'; // Анимация высоты
panel.innerHTML = `
Hiding Control
`;
document.body.appendChild(panel);
// Стили для подсветки
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);
}
`;
document.head.appendChild(style);
// ======== Кнопка iOS-переключатель Panel FilterX ========= //
let isSwitchOff = localStorage.getItem('isSwitchOff') === 'true'; // Начальное состояние переключателя из localStorage
// Создание элементов панели
const toggleButton = document.createElement('div');
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');
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');
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 = '2px';
toggleSwitch.style.transition = 'left 0.3s ease';
toggleSwitch.style.boxShadow = 'rgb(21, 32, 43) -1px 1px 4px 1px';
// Устанавливаем начальное состояние переключателя
toggleSwitch.style.left = isSwitchOff ? 'calc(100% - 23px)' : '2px';
toggleLabel.style.backgroundColor = isSwitchOff ? '#425364' : '#0d1319';
// Функция для изменения состояния переключателя
function toggleSwitchState() {
isSwitchOff = !isSwitchOff;
localStorage.setItem('isSwitchOff', isSwitchOff); // Сохраняем состояние в localStorage
// Обновляем стиль переключателя
toggleSwitch.style.left = isSwitchOff ? 'calc(100% - 23px)' : '2px';
toggleLabel.style.backgroundColor = isSwitchOff ? '#425364' : '#0d1319';
}
// Добавляем обработчик на клик по переключателю
toggleLabel.addEventListener('click', toggleSwitchState);
// Добавляем элементы на страницу
toggleLabel.appendChild(toggleSwitch);
toggleButton.appendChild(toggleLabel);
document.body.appendChild(toggleButton);
// Добавление текста к переключателю
const toggleText = document.createElement('span');
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') === 'true';
function togglePanel() {
if (isPanelVisible) {
panel.style.height = '0px'; // Сворачиваем панель
setTimeout(() => {
panel.style.display = 'none'; // Скрываем панель после анимации
}, 300);
} else {
panel.style.display = 'block'; // Показываем панель
setTimeout(() => {
panel.style.height = '420px'; // Разворачиваем панель
}, 10);
}
isPanelVisible = !isPanelVisible; true// Переключаем состояние
localStorage.setItem('panelVisible', isPanelVisible); // Сохраняем состояние
}
toggleButton.addEventListener('click', togglePanel);
// При загрузке восстанавливаем состояние панели
if (isPanelVisible) {
panel.style.height = '420px'; // Разворачиваем панель
panel.style.display = 'block';
} else {
panel.style.height = '0px'; // Сворачиваем панель
panel.style.display = 'none';
}
// ===== Обработчики событий ===== //
document.getElementById('addKeyword').addEventListener('click', () => {
const input = document.getElementById('keywordInput');
const keyword = input.value.trim();
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;charset=utf-8,${encodeURIComponent(JSON.stringify(hiddenKeywords))}`;
const downloadAnchor = document.createElement('a');
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');
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 importedKeywords = JSON.parse(reader.result);
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();
});
// ===== Кнопка для включения/выключения скрытия подтвержденных аккаунтов ===== //
document.getElementById('toggleVerifiedPosts').addEventListener('click', () => {
hideVerifiedAccounts = !hideVerifiedAccounts;
document.getElementById('toggleVerifiedPosts').textContent = `Hide verified accounts: ${hideVerifiedAccounts ? 'Turn OFF' : 'Turn ON'}`;
hidePosts(); // Перепроверка всех постов с новыми настройками
});
}
// ===== Обновление списка ключевых слов ===== //
function updateKeywordList() {
const list = document.getElementById('keywordList');
list.style.maxHeight = '150px';
list.style.overflowY = 'auto';
list.style.paddingRight = '10px';
list.style.border = '1px solid #ccc';
list.style.borderRadius = '5px';
list.style.backgroundColor = '#15202b';
list.style.boxShadow = '0 2px 5px rgba(0, 0, 0, 0.3)';
list.innerHTML = '';
hiddenKeywords.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(index, 1);
saveKeywords();
updateKeywordList();
hidePosts();
});
listItem.appendChild(deleteButton);
list.appendChild(listItem);
});
if (hiddenKeywords.length === 0) {
list.textContent = 'Нет';
}
}
// ===== Инициализация ===== //
createControlPanel();
updateKeywordList(); // Обновление списка при загрузке страницы
hidePosts();
// ===== Наблюдатель для динамического контента ===== //
const observer = new MutationObserver(hidePosts);
observer.observe(document.body, { childList: true, subtree: true });
})();