SpoilerMan

Want to blurr spoilers? Spoiler man to the rescue!

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

You will need to install an extension such as Tampermonkey to install this script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Advertisement:

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

Advertisement:

// ==UserScript==
// @name         SpoilerMan
// @namespace    codesidian.com
// @description  Want to blurr spoilers? Spoiler man to the rescue!
// @version      1.2
// @match        *://*/*
// @grant        GM.setValue
// @grant        GM.getValue
// @grant        GM.registerMenuCommand
// @author       Joshua Latham (codesidian.com) & Gemini 2.5 Pro
// @license      MIT 
// ==/UserScript==

(function() {
    'use strict';

    const CLASS_STORAGE_KEY = 'spoilerManBlurredClasses';
    const MODE_STORAGE_KEY = 'spoilerManMode'; // Stores 'blur' or 'hide'
    const BLUR_STRENGTH_KEY = 'spoilerManBlurStrength'; // Stores the blur strength
    let lastHoveredElement = null;
    const highlightStyle = '2px dashed red';

    function getBlurredClasses() {
        return GM.getValue(CLASS_STORAGE_KEY, []);
    }

    function getDisplayMode() {
        return GM.getValue(MODE_STORAGE_KEY, 'blur');
    }

    function getBlurStrength() {
        return GM.getValue(BLUR_STRENGTH_KEY, 40);
    }

    async function addBlurredClass(className) {
        if (!className || className.trim() === '') return;
        const classes = await getBlurredClasses();
        if (!classes.includes(className)) {
            classes.push(className);
            await GM.setValue(CLASS_STORAGE_KEY, classes);
            window.location.reload();
        } else {
            alert(`'${className}' is already in the blur list.`);
        }
    }

    async function clearBlurredClasses() {
        if (confirm("Are you sure you want to clear all spoiler rules?")) {
            await GM.setValue(CLASS_STORAGE_KEY, []);
            window.location.reload();
        }
    }

    async function toggleDisplayMode() {
        const currentMode = await getDisplayMode();
        const newMode = currentMode === 'blur' ? 'hide' : 'blur';
        await GM.setValue(MODE_STORAGE_KEY, newMode);
        window.location.reload();
    }

    async function setBlurStrength() {
        const currentStrength = await getBlurStrength();
        const newStrengthStr = prompt("Enter new blur strength in pixels (e.g., 20):", currentStrength);
        if (newStrengthStr) {
            const newStrength = parseInt(newStrengthStr, 10);
            if (!isNaN(newStrength) && newStrength >= 0) {
                await GM.setValue(BLUR_STRENGTH_KEY, newStrength);
                window.location.reload();
            } else {
                alert("Invalid input. Please enter a valid non-negative number.");
            }
        }
    }


    function applySpoilerEffect(className, mode, blurStrength) {
        const elementsToModify = document.querySelectorAll('.' + className);
        elementsToModify.forEach(element => {
            if (mode === 'blur') {
                const blurValue = `${blurStrength}px`;
                element.style.display = ''; // Ensure element is visible
                element.style.filter = `blur(${blurValue})`;
                element.style.transition = 'filter 1s ease';
                element.addEventListener('mouseenter', () => element.style.filter = 'blur(0px)');
                element.addEventListener('mouseleave', () => element.style.filter = `blur(${blurValue})`);
            } else {
                element.style.display = 'none';
            }
        });
    }


    function findTargetWithClasses(element) {
        let current = element;
        while (current) {
            if (current.classList && current.classList.length > 0) {
                return current;
            }
            current = current.parentElement;
        }
        return null;
    }

    const clickListener = (event) => {
        event.preventDefault();
        event.stopPropagation();
        const usefulTarget = findTargetWithClasses(event.target);
        deactivateSelectionMode();

        if (usefulTarget) {
            addBlurredClass(usefulTarget.classList[0].trim());
        } else {
            alert("Could not find any usable classes for the clicked element or its parents.");
        }
    };

    const hoverListener = (event) => {
        const target = event.target;
        if (lastHoveredElement) {
            lastHoveredElement.style.outline = '';
        }
        target.style.outline = highlightStyle;
        lastHoveredElement = target;
    };

    function deactivateSelectionMode() {
        if (lastHoveredElement) {
            lastHoveredElement.style.outline = '';
        }
        document.body.style.cursor = 'default';
        document.removeEventListener('mouseover', hoverListener);
        document.removeEventListener('click', clickListener, true);
    }

    function activateSelectionMode() {
        alert("Selection mode activated. Hover over elements to highlight them, then click the one you want to blur/hide.");
        document.body.style.cursor = 'crosshair';
        document.addEventListener('mouseover', hoverListener);
        document.addEventListener('click', clickListener, true);
    }

    async function registerMenuCommands() {
        GM.registerMenuCommand('🎯 Select an element to spoil', activateSelectionMode);
        GM.registerMenuCommand('❌ Clear all spoiler rules', clearBlurredClasses);
        GM.registerMenuCommand('⚙️ Set Blur Strength', setBlurStrength);

        const currentMode = await getDisplayMode();
        const nextModeText = currentMode === 'blur' ? 'Hide' : 'Blur';
        GM.registerMenuCommand(`🔄 Switch to ${nextModeText} Mode`, toggleDisplayMode);
    }


    async function main() {
        await registerMenuCommands();

        const classesToAffect = await getBlurredClasses();
        const mode = await getDisplayMode();
        const blurStrength = await getBlurStrength();

        console.log(`SpoilerMan active in '${mode}' mode with blur strength ${blurStrength}px.`);

        if (classesToAffect.length > 0) {
            classesToAffect.forEach(className => {
                applySpoilerEffect(className, mode, blurStrength);
            });
        }
    }

    main();

})();