VK Feed Filter - No Images/Video

Removes posts containing images/videos from VK feed using periodic checks.

// ==UserScript==
// @name         VK Feed Filter - No Images/Video
// @namespace    http://tampermonkey.net/
// @version      1.5
// @description  Removes posts containing images/videos from VK feed using periodic checks.
// @author       AL
// @match        *://vk.com/feed*
// @grant        GM_addStyle
// @run-at       document-idle
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    const SCRIPT_NAME = "VK Feed Filter v1.5 (Interval)";
    const CHECK_INTERVAL_MS = 1500; // Как часто проверять новые посты (в миллисекундах)
    const DEBUG = true; // Включить подробное логирование

    function log(...args) {
        if (DEBUG) {
            console.log(`${SCRIPT_NAME}:`, ...args);
        }
    }
    function error(...args) {
        console.error(`${SCRIPT_NAME}:`, ...args);
    }

    log("Script activated.");

    // --- Inject CSS for hiding ---
    const styleId = 'vk-feed-filter-style-v15';
    const hideCssClass = 'vk-feed-filter-hide-v15';
    const oldStyle = document.getElementById(styleId);
    if(oldStyle) oldStyle.remove();
    // Делаем скрытие максимально надежным
    GM_addStyle(`
        .${hideCssClass} {
            display: none !important;
            visibility: hidden !important;
            height: 0 !important;
            overflow: hidden !important;
            margin: 0 !important;
            padding: 0 !important;
            border: none !important;
            content-visibility: hidden !important; /* Экспериментальное свойство, может помочь */
        }
    `);
    log("Injected CSS for hiding.");

    // --- Selectors (можно оставить из v1.4, они вроде работали для поиска) ---
    const mediaSelectors = [
        // Images & Grids
        '.MediaGrid__thumb', '.MediaGrid__image', 'img.MediaGrid__image',
        '.page_post_sized_thumbs', '.page_post_thumb_wrap img', '.page_preview_photo_image',
        '.thumb_map img', '.thumb_photo', '.PhotoPrimaryAttachment__image',
        'a[aria-label*="фотография"]', 'a[aria-label*="photo"]',
        '.article_snippet--photo_preview',
        '.page_cover',

        // Videos
        '.thumb_video', '.Video', '.page_video_thumb_wrap', '.page_video_inline_wrap',
        '.VideoInlinePlayer', '.VideoThumbnail__thumb', '.page_video_wrap', 'video',
        'iframe[src*="youtube.com"]', 'iframe[src*="vk.com/video_ext.php"]',
        '.videoplayer_media', '.VideoCard__thumb',

        // Clips
        '.ShortVideoFeedItem__playerContainer', '.short_video_feed_item', '.VerticalVideoLayer',
        '.tiktok_video_inline', '.tiktok_video_player',

        // Carousels
        '.ui_gallery__item', '.wall_carousel_item--photo', '.wall_carousel_item--video',
        '.CarouselBasic__item', '.ui_gallery_inner',

        // Others
        '.media_preview', '.ArticleSnippet__imageContainer', '.LinkSnippet__image',
        '.StorySnippet', '.PodcastSnippet__cover', '.poll_graph',
        '.audio_stack_cover',

        // Nested
        '.wall_text img', '.copy_quote img',

        // Specific post types with inherent media
        '.post_type_report',
        '.post_type_map',
        '.post_type_graffiti'
    ].join(', ');

    const postContainerSelector = '.feed_row'; // Контейнер, который обычно виден
    const actualPostSelector = '._post, .article'; // Где искать контент
    const adContainerSelectors = '._ads_block_data_w, .ads_ad_box_legacy, div[data-ad-view]';
    const allContentSelectors = `${postContainerSelector}, ${adContainerSelectors}`; // Объединяем для сканирования

    let checkIntervalId = null;
    let isChecking = false; // Флаг, чтобы предотвратить одновременный запуск проверки

    // --- Function to hide an element ---
    function hideElement(element, reason = 'Media found') {
        if (!element || element.classList.contains(hideCssClass)) {
            return false;
        }
        log(`Hiding element (ID: ${element.id || 'N/A'}, Class: ${element.classList[0] || ''}): ${reason}`);
        element.classList.add(hideCssClass);
        return true;
    }

    // --- Function to scan and hide posts ---
    function scanAndHide() {
        if (isChecking) {
            // log("Scan already in progress, skipping.");
            return;
        }
        isChecking = true;
        // log("Scanning for media posts...");

        let hiddenNow = 0;
        const elementsToCheck = document.querySelectorAll(allContentSelectors);

        if (elementsToCheck.length === 0) {
             // log("No potential post/ad containers found in this scan.");
             isChecking = false;
             return;
        }

        elementsToCheck.forEach(element => {
            if (element.classList.contains(hideCssClass)) {
                return; // Already hidden by us
            }

            // Определяем, где искать медиа
            let contentElement = element;
            if (element.matches(postContainerSelector)) {
                contentElement = element.querySelector(actualPostSelector) || element.querySelector(adContainerSelectors);
                 if (!contentElement) {
                     contentElement = element; // Проверяем саму строку, если внутри ничего нет
                 }
            }

            if (!contentElement) return; // Не удалось найти элемент для проверки

            // Проверяем наличие медиа
            try {
                const containsMedia = contentElement.querySelector(mediaSelectors);
                if (containsMedia) {
                    if (hideElement(element, `Found media: ${containsMedia.tagName}.${containsMedia.classList[0] || ''}`)) {
                        hiddenNow++;
                    }
                }
            } catch (e) {
                error("Error during querySelector:", e, "on element:", contentElement);
            }
        });

        // if (hiddenNow > 0) {
        //    log(`Hid ${hiddenNow} new elements in this scan.`);
        // }
        isChecking = false;
    }

    // --- Start the periodic check ---
    function startIntervalCheck() {
        log(`Starting periodic check every ${CHECK_INTERVAL_MS}ms.`);
        // Perform an initial scan almost immediately
        setTimeout(scanAndHide, 100); // Небольшая задержка после старта
        // Then start the interval
        if (checkIntervalId) {
            clearInterval(checkIntervalId);
        }
        checkIntervalId = setInterval(scanAndHide, CHECK_INTERVAL_MS);

        // Optional: Clear interval on page unload
        window.addEventListener('unload', () => {
            if (checkIntervalId) {
                clearInterval(checkIntervalId);
                log("Stopped periodic check.");
            }
        });
         // Pause checking when tab is hidden
         document.addEventListener('visibilitychange', () => {
             if (document.visibilityState === 'hidden') {
                 if (checkIntervalId) {
                    // clearInterval(checkIntervalId);
                    // checkIntervalId = null;
                     log("Tab hidden, pausing checks (optional - currently checks continue).");
                     // Если раскомментировать clearInterval, то проверки остановятся при неактивной вкладке
                 }
             } else {
                 if (!checkIntervalId) {
                     log("Tab visible, restarting checks.");
                     checkIntervalId = setInterval(scanAndHide, CHECK_INTERVAL_MS);
                      // Run scan immediately on becoming visible
                      setTimeout(scanAndHide, 100);
                 }
             }
         });
    }

    // --- Initialization ---
    log("Waiting for DOM Content Loaded...");
    if (document.readyState === 'interactive' || document.readyState === 'complete') {
        log("DOM already ready.");
        startIntervalCheck();
    } else {
        window.addEventListener('DOMContentLoaded', () => {
            log("DOMContentLoaded event fired.");
            startIntervalCheck();
        }, { once: true });
    }
     // Fallback just in case
     window.addEventListener('load', () => {
         if (!checkIntervalId) {
             log("Window load event fired. Ensuring checks are running.");
             startIntervalCheck();
         }
     }, { once: true });

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址