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

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

目前為 2025-01-24 提交的版本,檢視 最新版本

// ==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 });
})();