Скрытие постов по ключевым словам с панелью управления и скрытие постов от подтвержденных аккаунтов
目前為
// ==UserScript==
// @name PanelControl Twitter | X com |Hide Posts by Keywords | (c) tapeavion
// @namespace http://tampermonkey.net/
// @version 1.1
// @description Скрытие постов по ключевым словам с панелью управления и скрытие постов от подтвержденных аккаунтов
// @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 = '20px';
panel.style.width = '300px';
panel.style.maxHeight = '502px';
panel.style.overflowY = 'auto';
panel.style.padding = '10px';
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;">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;">
<input type="checkbox" id="hideUA" style="margin-right: 10px;">
doesntwork inprocess Hide posts UA
</label>
<label style="display: block;">
<input type="checkbox" id="hideUSA" style="margin-right: 10px;">
doesntwork inprocess Hide posts USA
</label>
<ul id="keywordList" style="list-style: none; padding: 0; margin-top: 10px; font-size: 14px; color: #fff;"></ul>
`;
document.body.appendChild(panel);
// Создаем iOS-переключатель
const toggleContainer = document.createElement('div');
toggleContainer.style.position = 'fixed';
toggleContainer.style.bottom = '93%';
toggleContainer.style.right = '1%';
toggleContainer.style.display = 'flex';
toggleContainer.style.alignItems = 'center';
toggleContainer.style.gap = '10px';
toggleContainer.style.zIndex = '9999';
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 = '#203142';
toggleSwitch.style.top = '2px';
toggleSwitch.style.left = '2px';
toggleSwitch.style.transition = 'transform 0.3s';
toggleLabel.appendChild(toggleSwitch);
toggleContainer.appendChild(toggleLabel);
document.body.appendChild(toggleContainer);
let isPanelVisible = false;
// ===== Обработчик переключателя ===== //
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(); // Перепроверка всех постов с новыми настройками
});
// ===== Обработчики для новых переключателей ===== //
document.getElementById('hideUA').addEventListener('change', function() {
hideUA = this.checked;
hidePosts();
});
document.getElementById('hideUSA').addEventListener('change', function() {
hideUSA = this.checked;
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 = '#444';
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 });
})();