YouTube Video Selector and Hider (Language Independent)

Quickly select and hide multiple videos on YouTube, works in any language

// ==UserScript==
// @name         YouTube Video Selector and Hider (Language Independent)
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Quickly select and hide multiple videos on YouTube, works in any language
// @match        https://www.youtube.com/*
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    let isSelecting = false;
    let startX, startY;
    let selectedVideos = new Set();

    // Create hide button
    const hideButton = document.createElement('button');
    hideButton.textContent = 'Hide Selected (0)';
    hideButton.style.position = 'fixed';
    hideButton.style.top = '10px';
    hideButton.style.right = '10px';
    hideButton.style.zIndex = '9999';
    hideButton.style.display = 'none';
    hideButton.style.padding = '10px';
    hideButton.style.backgroundColor = '#ff0000';
    hideButton.style.color = '#ffffff';
    hideButton.style.border = 'none';
    hideButton.style.borderRadius = '5px';
    hideButton.style.cursor = 'pointer';
    document.body.appendChild(hideButton);

    // Event listeners
    document.addEventListener('keydown', handleKeyDown);
    document.addEventListener('keyup', handleKeyUp);
    document.addEventListener('mousedown', handleMouseDown);
    document.addEventListener('mousemove', handleMouseMove);
    document.addEventListener('mouseup', handleMouseUp);
    hideButton.addEventListener('click', hideSelectedVideos);

    function handleKeyDown(e) {
        if (e.key.toLowerCase() === 'x' && !isSelecting) {
            isSelecting = true;
            document.body.style.userSelect = 'none';
        }
    }

    function handleKeyUp(e) {
        if (e.key.toLowerCase() === 'x') {
            isSelecting = false;
            document.body.style.userSelect = '';
            removeSelectionBox();
        }
    }

    function handleMouseDown(e) {
        if (isSelecting) {
            startX = e.clientX;
            startY = e.clientY;
            createSelectionBox(startX, startY);
        }
    }

    function handleMouseMove(e) {
        if (isSelecting) {
            const selectionBox = document.getElementById('selection-box');
            if (selectionBox) {
                const width = e.clientX - startX;
                const height = e.clientY - startY;
                selectionBox.style.width = Math.abs(width) + 'px';
                selectionBox.style.height = Math.abs(height) + 'px';
                selectionBox.style.left = (width < 0 ? e.clientX : startX) + 'px';
                selectionBox.style.top = (height < 0 ? e.clientY : startY) + 'px';
            }
        }
    }

    function handleMouseUp() {
        if (isSelecting) {
            const selectionBox = document.getElementById('selection-box');
            if (selectionBox) {
                selectVideos(selectionBox);
                removeSelectionBox();
            }
        }
    }

    function createSelectionBox(x, y) {
        removeSelectionBox();
        const selectionBox = document.createElement('div');
        selectionBox.id = 'selection-box';
        selectionBox.style.position = 'fixed';
        selectionBox.style.border = '2px solid blue';
        selectionBox.style.backgroundColor = 'rgba(0, 0, 255, 0.1)';
        selectionBox.style.left = x + 'px';
        selectionBox.style.top = y + 'px';
        selectionBox.style.zIndex = '9998';
        document.body.appendChild(selectionBox);
    }

    function removeSelectionBox() {
        const existingBox = document.getElementById('selection-box');
        if (existingBox) {
            existingBox.remove();
        }
    }

    function selectVideos(selectionBox) {
        const videos = document.querySelectorAll('ytd-rich-item-renderer');
        const boxRect = selectionBox.getBoundingClientRect();

        videos.forEach(video => {
            const videoRect = video.getBoundingClientRect();
            if (!(videoRect.right < boxRect.left ||
                  videoRect.left > boxRect.right ||
                  videoRect.bottom < boxRect.top ||
                  videoRect.top > boxRect.bottom)) {
                if (selectedVideos.has(video)) {
                    selectedVideos.delete(video);
                    video.style.outline = '';
                } else {
                    selectedVideos.add(video);
                    video.style.outline = '2px solid red';
                }
            }
        });

        updateHideButton();
    }

    function updateHideButton() {
        hideButton.textContent = `Hide Selected (${selectedVideos.size})`;
        hideButton.style.display = selectedVideos.size > 0 ? 'block' : 'none';
    }

    async function hideSelectedVideos() {
        const totalVideos = selectedVideos.size;
        let hiddenVideos = 0;

        hideButton.disabled = true;
        hideButton.style.backgroundColor = '#888888';

        for (const video of selectedVideos) {
            await hideVideo(video);
            video.style.outline = '';
            hiddenVideos++;
            hideButton.textContent = `Hiding... (${hiddenVideos}/${totalVideos})`;
        }

        selectedVideos.clear();
        hideButton.textContent = `Hidden ${hiddenVideos} videos`;
        hideButton.disabled = false;
        hideButton.style.backgroundColor = '#ff0000';

        setTimeout(() => {
            hideButton.style.display = 'none';
        }, 2000);
    }

    function hideVideo(video) {
        return new Promise((resolve) => {
            // Find and click the menu button (3 dots)
            const menuButton = video.querySelector('ytd-menu-renderer button[aria-label]');
            if (!menuButton || !menuButton.click) {
                resolve();
                return;
            }

            // Click the menu button to open it
            menuButton.click();

            // Wait for the menu to open and then find the hide option
            setTimeout(() => {
                const options = Array.from(document.querySelectorAll('ytd-menu-service-item-renderer'));
                let hideOption = null;

                // Try to find the hide option
                for (const option of options) {
                    // Check button text content (for any language)
                    const text = (option.textContent || '').toLowerCase().trim();
                    if (text.includes('hide') || text.includes('dölj') || text.includes('not interested')) {
                        hideOption = option;
                        break;
                    }

                    // Check for notification/bell icon (to avoid clicking it)
                    const notificationIcon = option.querySelector('svg path[d="M10 20h4c0 1.1-.9 2-2 2s-2-.9-2-2zm10-2.65V19H4v-1.65l2-1.88v-5.15C6 6.4 7.56 3.4 11 3v-.5c0-.83.67-1.5 1.5-1.5s1.5.67 1.5 1.5V3c3.44.4 5 3.4 5 7.32v5.15l2 1.88z"]');
                    if (notificationIcon) {
                        continue;
                    }

                    // Fallback: Check for hide icon
                    const icon = option.querySelector('yt-icon svg');
                    if (icon && icon.innerHTML.includes('M12 2c5.52 0 10 4.48 10 10s-4.48 10-10 10S2 17.52 2 12 6.48 2 12 2zM3 12c0 2.31.87 4.41 2.29 6L18 5.29C16.41 3.87 14.31 3 12 3c-4.97 0-9 4.03-9 9zm15.71-6L6 18.71C7.59 20.13 9.69 21 12 21c4.97 0 9-4.03 9-9 0-2.31-.87-4.41-2.29-6z')) {
                        hideOption = option;
                        break;
                    }
                }

                if (hideOption && hideOption.click) {
                    // Wait a bit and click the hide option
                    setTimeout(() => {
                        hideOption.click();
                        setTimeout(resolve, 100);
                    }, 50);
                } else {
                    // If we can't find the hide option, close the menu and continue
                    document.body.click();
                    setTimeout(resolve, 100);
                }
            }, 100);
        });
    }
})();