SpoilerMan

Want to blurr spoilers? Spoiler man to the rescue!

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

Advertisement:

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

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();

})();