Hide posts by keywords with the dashboard and hide posts from verified accounts
目前為
// ==UserScript==
// @name Twitter PanelControl | X com |Hide Posts by Keywords | (c) tapeavion
// @namespace http://tampermonkey.net/
// @version 1.3
// @description Hide posts by keywords with the dashboard and hide posts from verified accounts
// @author gullampis810
// @match https://x.com/*
// @grant none
// @license MIT
// @icon https://img.freepik.com/premium-vector/kiev-ukraine-march-19-2021-set-of-twitter-icons-social-media-icons-realistic-set-neumorphic-ui-ux-white-user-interface-neumorphism-style_399089-1207.jpg?size=626&ext=jpg
// ==/UserScript==
(function () {
'use strict';
// ===== Настройки и инициализация ===== //
const STORAGE_KEY = 'hiddenKeywords';
let hiddenKeywords = JSON.parse(localStorage.getItem(STORAGE_KEY)) || [];
let hideVerifiedAccounts = false; // Скрывать подтвержденные аккаунты
let hideUA = true;
let hideUSA = 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()));
// Проверка на наличие эмодзи через <img alt="">
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"]');
// Проверка местоположения пользователя
const userLocationElement = article.querySelector('[data-testid="User-Name"]').nextElementSibling;
const userLocation = userLocationElement ? userLocationElement.textContent.toLowerCase() : '';
const hideByLocation = (hideUA && userLocation.includes('ua')) || (hideUSA && userLocation.includes('usa'));
// Скрываем пост, если найдено совпадение
if (hiddenKeywords.some(keyword => textContent.includes(keyword.toLowerCase())) ||
hasEmojiInUsername ||
isVerifiedAccount ||
hideByLocation) {
article.style.display = 'none';
}
});
}
// ===== Создание панели управления ===== //
function createControlPanel() {
// Создание панели
const panel = document.createElement('div');
panel.style.position = 'fixed';
panel.style.bottom = '0';
panel.style.right = '455px';
panel.style.width = '300px';
panel.style.maxHeight = '502px';
panel.style.overflowY = 'auto';
panel.style.padding = '10px';
panel.style.fontFamily = 'Arial, sans-serif';
panel.style.backgroundColor = '#34506c';
panel.style.color = '#fff';
panel.style.borderRadius = '8px 8px 0 0';
panel.style.boxShadow = '0 0 10px rgba(0,0,0,0.5)';
panel.style.zIndex = '9999';
panel.style.transition = 'transform 0.3s ease-in-out';
panel.style.transform = 'translateY(100%)';
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% - 20px); padding: 5px; margin: 10px 0; border-radius: 5px; border: none;">
<button id="addKeyword" style="width: 100%; padding: 8px; margin-bottom: 5px; background: #203142; color: white; border: none; border-radius: 5px;">Add it</button>
<button id="clearKeywords" style="width: 100%; padding: 8px; margin-bottom: 5px; background: #203142; color: white; border: none; border-radius: 5px;">Clear all</button>
<button id="exportKeywords" style="width: 100%; padding: 8px; margin-bottom: 5px; background: #203142; color: white; border: none; border-radius: 5px;">Export</button>
<button id="importKeywords" style="width: 100%; padding: 8px; background: #203142; color: white; border: none; border-radius: 5px; margin-bottom: 10px;">Import</button>
<button id="toggleVerifiedPosts" style="width: 100%; padding: 8px; margin-bottom: 5px; background: #203142; color: white; border: none; border-radius: 5px;">
Hide verified accounts: Disabled
</button>
<label style="display: block; margin: 10px 0;">
</label>
<ul id="keywordList" style="list-style: none; padding: 0; margin-top: 10px; font-size: 14px; color: #fff;"></ul>
`;
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-переключатель
const toggleContainer = document.createElement('div');
toggleContainer.style.position = 'fixed';
toggleContainer.style.bottom = '8px';
toggleContainer.style.right = '225px';
toggleContainer.style.display = 'flex';
toggleContainer.style.alignItems = 'center';
toggleContainer.style.gap = '10px';
toggleContainer.style.zIndex = '999';
toggleContainer.style.background = '#15202b'; // Фон переключателя
toggleContainer.style.border = '4px solid #6c7e8e'; // Рамка
toggleContainer.style.borderRadius = '18px'; // Радиус для закругления углов
const toggleLabel = document.createElement('label');
toggleLabel.style.display = 'inline-block';
toggleLabel.style.width = '50px';
toggleLabel.style.height = '25px';
toggleLabel.style.borderRadius = '25px'; // label переключателя рамка для кружка
toggleLabel.style.backgroundColor = '#0d1319';
toggleLabel.style.position = 'relative';
toggleLabel.style.cursor = 'pointer';
toggleLabel.style.transition = 'background-color 0.3s';
toggleLabel.style.boxShadow = 'rgb(15 20 25 / 87%) 0px 0px 4px 1px inset'; // Добавлена тень
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 = 'transform 0.3s';
toggleSwitch.style.boxShadow = 'rgb(21, 32, 43) -1px 1px 4px 1px'; // Добавлена тень
toggleLabel.appendChild(toggleSwitch);
toggleContainer.appendChild(toggleLabel);
document.body.appendChild(toggleContainer);
let isPanelVisible = false;
// Добавляем текст к переключателю
const toggleText = document.createElement('span');
toggleText.style.position = 'relative';
toggleText.style.right = '5px';
toggleText.textContent = 'Open Filter Twitter';
toggleText.style.color = '#6c7e8e';
toggleText.style.fontFamily = 'Arial, sans-serif';
toggleText.style.fontSize = '16px';
toggleText.style.marginLeft = '10px';
toggleText.style.fontWeight = 'bold'; // Добавлено жирное начертание
toggleContainer.appendChild(toggleText);
document.body.appendChild(toggleContainer);
// ===== Обработчик переключателя ===== //
toggleLabel.addEventListener('click', () => {
isPanelVisible = !isPanelVisible;
if (isPanelVisible) {
panel.style.transform = 'translateY(0)';
toggleLabel.style.backgroundColor = '#34506c';
toggleSwitch.style.transform = 'translateX(25px)';
} else {
panel.style.transform = 'translateY(100%)';
toggleLabel.style.backgroundColor = '#0e151b';
toggleSwitch.style.transform = 'translateX(0)';
}
});
// ===== Обработчики событий ===== //
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 ? 'Enabled' : 'Disabled'}`;
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 });
})();