Tenor Multi-User Blocker - Enhanced

Blocks GIFs from multiple users in Tenor search results with debug mode

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Tenor Multi-User Blocker - Enhanced
// @namespace    http://tampermonkey.net/
// @version      3.0
// @description  Blocks GIFs from multiple users in Tenor search results with debug mode
// @author       Ruben Van den Broeck
// @match        https://tenor.com/*
// @license MIT
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    // Configuration
    const DEBUG_MODE = true; // Set to false for production

    // Add usernames separated by commas
    const BLOCKED_USERNAMES = "Blazzord, Lastfridayart, TobiasDavidson";

    // Parse blocked usernames into an array and trim whitespace
    const blockedUsersArray = BLOCKED_USERNAMES.split(',').map(name => name.trim()).filter(name => name.length > 0);

    const API_PATTERNS = [
        /\/gifapi\//,
        /\/v1\//,
        /\/v2\//,
        /\/search\//,
        /\/trending\//,
        /\/categories\//,
        /\/suggestions\//
    ];

    // Logging function
    function debugLog(...args) {
        if (DEBUG_MODE) {
            console.log('[Tenor Blocker]', ...args);
        }
    }

    // Initialize
    debugLog('Blocked users:', blockedUsersArray);

    // Filter function to remove unwanted GIFs
    function filterTenorResponse(data) {
        if (!data || !data.results || !Array.isArray(data.results)) {
            debugLog('Invalid API response structure');
            return data;
        }

        const originalCount = data.results.length;
        const blockedCounts = {};

        data.results = data.results.filter(item => {
            const hasUser = item.user && item.user.username;
            if (!hasUser) return true;

            const isBlocked = blockedUsersArray.includes(item.user.username);

            if (isBlocked) {
                blockedCounts[item.user.username] = (blockedCounts[item.user.username] || 0) + 1;
                debugLog(`Blocked GIF from ${item.user.username}:`, item.id, item.title);
            }

            return !isBlocked;
        });

        const totalBlocked = originalCount - data.results.length;
        if (totalBlocked > 0) {
            debugLog(`Filtered ${totalBlocked} total items:`, blockedCounts);
        }

        return data;
    }

    // Main blocking function
    function startBlocking() {
        debugLog('Starting multi-user blocker...');

        // Intercept Fetch API
        if (window.fetch) {
            const originalFetch = window.fetch;
            window.fetch = async function(...args) {
                const requestUrl = args[0] instanceof Request ? args[0].url : args[0];

                if (API_PATTERNS.some(pattern => pattern.test(requestUrl))) {
                    debugLog('Intercepted fetch request:', requestUrl);

                    const response = await originalFetch.apply(this, args);
                    try {
                        const clonedResponse = response.clone();
                        const json = await clonedResponse.json();
                        const filtered = filterTenorResponse(json);

                        return new Response(JSON.stringify(filtered), {
                            status: response.status,
                            statusText: response.statusText,
                            headers: response.headers
                        });
                    } catch (e) {
                        debugLog('Error processing fetch response:', e);
                        return response;
                    }
                }
                return originalFetch.apply(this, args);
            };
        }

        // Intercept XHR requests
        if (window.XMLHttpRequest) {
            const originalOpen = XMLHttpRequest.prototype.open;
            XMLHttpRequest.prototype.open = function(method, url) {
                this._requestUrl = url;
                return originalOpen.apply(this, arguments);
            };

            const originalSend = XMLHttpRequest.prototype.send;
            XMLHttpRequest.prototype.send = function(body) {
                if (this._requestUrl && API_PATTERNS.some(pattern => pattern.test(this._requestUrl))) {
                    debugLog('Intercepted XHR request:', this._requestUrl);

                    const originalOnload = this.onload;
                    this.onload = function(e) {
                        if (this.responseText) {
                            try {
                                const json = JSON.parse(this.responseText);
                                const filtered = filterTenorResponse(json);
                                Object.defineProperty(this, 'responseText', {
                                    value: JSON.stringify(filtered)
                                });
                            } catch (error) {
                                debugLog('Error processing XHR response:', error);
                            }
                        }
                        if (originalOnload) return originalOnload.call(this, e);
                    };
                }
                return originalSend.apply(this, arguments);
            };
        }

        // Fallback: Clean DOM periodically
        setInterval(() => {
            const gifElements = document.querySelectorAll('div[data-username], div.gif');
            gifElements.forEach(el => {
                const username = el.getAttribute('data-username') ||
                                el.querySelector('.gif-user')?.textContent;

                if (username && blockedUsersArray.some(blocked => username.includes(blocked))) {
                    debugLog('Removing DOM element:', el);
                    el.remove();
                }
            });
        }, 3000);
    }

    // Start the blocking process
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', startBlocking);
    } else {
        startBlocking();
    }
})();