PanelControll Twitter | X com |Hide Posts by Keywords | (c) tapeavion

Скрытие постов по ключевым словам с панелью управления и скрытие постов от подтвержденных аккаунтов

当前为 2025-01-24 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         PanelControll 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: #4CAF50; color: white; border: none; border-radius: 5px;">Add it</button>
            <button id="clearKeywords" style="width: 100%; padding: 8px; margin-bottom: 5px; background: #f44336; color: white; border: none; border-radius: 5px;">Clear all</button>
            <button id="exportKeywords" style="width: 100%; padding: 8px; margin-bottom: 5px; background: #2196F3; color: white; border: none; border-radius: 5px;">Export</button>
            <button id="importKeywords" style="width: 100%; padding: 8px; background: #ff9800; color: white; border: none; border-radius: 5px;">Import</button>
            <button id="toggleVerifiedPosts" style="width: 100%; padding: 8px; margin-bottom: 5px; background: #007BFF; 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 });
})();