Greasy Fork is available in English.

Wörter-Verwischen-Skript

Blurt Wörter auf Webseiten. Features: Mehrere Treffer, IP-Erkennung und Vollbild

// ==UserScript==
// @name         Wörter-Verwischen-Skript
// @namespace    http://tampermonkey.net/
// @version      3.25
// @description  Blurt Wörter auf Webseiten. Features: Mehrere Treffer, IP-Erkennung und Vollbild
// @author       Sky95
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @connect      api.ipify.org
// @run-at       document-start
// @noframes
// ==/UserScript==

(function() {
    'use strict';

    GM_addStyle(`
        .word-blur {
            filter: blur(7.5px);
            transition: filter 1.5s ease;
        }
        .word-blur:hover {
            filter: blur(0px);
            transition-delay: 1s;
        }
        .full-page-blur {
            filter: blur(10px) !important;
        }
        .full-page-unblur {
            filter: blur(0px) !important;
            transition: filter 0.5s ease !important;
        }
        .full-page-blur * {
            pointer-events: none !important;
        }
        body {
            max-width: 100% !important;
            overflow-x: hidden !important;
        }
        #blur-settings-panel {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 500px;
            background: #2b2b2b !important;
            color: #fff !important;
            border-radius: 8px !important;
            box-shadow: 0 4px 20px rgba(0,0,0,0.8) !important;
            z-index: 10000;
            display: none;
            font-family: 'Courier New', monospace !important;
            pointer-events: auto !important;
            opacity: 0;
            transition: opacity 0.3s ease-in-out;
        }
        #blur-settings-panel.visible {
            opacity: 0.98;
        }
		#blur-section-container {
            max-height: 70vh !important;
            overflow-y: auto !important;
            scrollbar-width: thin !important;
            scrollbar-color: #666 #2b2b2b !important;
		}
        #blur-settings-header {
            padding: 15px 20px !important;
            background: #363636 !important;
            border-radius: 8px 8px 0 0;
            cursor: move;
            user-select: none;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        #blur-settings-header h3 {
            color: #fff !important;
            font-size: 18px !important;
            font-weight: normal !important;
            font-family: Arial, sans-serif !important;
            margin: 0 !important;
            padding: 0 !important;
        }
        #blur-text-info {
            padding: 5px 20px !important;
            background: #262626 !important;
            border: 1px solid #406040 !important;
            font-size: 12px !important;
            color: #afa !important;
            line-height: 1.4 !important;
        }
        #blur-ip-info {
            padding: 5px 20px !important;
            background: #262626 !important;
            font-size: 14px !important;
            color: #aaf !important;
            display: flex !important;
            justify-content: space-between !important;
            align-items: center !important;
            pointer-events: auto !important;
            filter: blur(0) !important;
            margin-top: 5px !important;
        }
        #blur-ip-display {
            pointer-events: auto !important;
            filter: blur(0) !important;
        }
        #blur-ip-button {
            background: #4CAF50 !important;
            color: white !important;
            border: none !important;
            border-radius: 4px !important;
            padding: 5px 10px !important;
            cursor: pointer !important;
            font-size: 12px !important;
            pointer-events: auto !important;
            filter: blur(0) !important;
        }
        #blur-ip-button:hover {
            background: #388E3C !important;
        }
        #blur-close-button {
            background: none !important;
            border: none !important;
            color: #fff !important;
            cursor: pointer !important;
            font-family: Arial, sans-serif !important;
            font-size: 24px !important;
            padding: 0 !important;
            width: 24px !important;
            height: 24px !important;
            display: flex !important;
            align-items: center !important;
            justify-content: center !important;
            line-height: 1 !important;
            text-decoration: none !important;
            outline: none !important;
        }
        #blur-close-button:hover {
            background: rgba(255,255,255,0.1) !important;
            border-radius: 4px !important;
        }
        .blur-section-content {
            padding: 15px 20px !important;
            display: none;
            background: #2b2b2b !important;
        }
        .blur-button-container {
            padding: 15px 20px !important;
            background: #363636 !important;
            border-top: 1px solid #404040 !important;
            display: flex !important;
            justify-content: space-between !important;
            border-radius: 0 0 8px 8px !important;
            gap: 10px !important;
        }
        .blur-button {
            padding: 8px 16px !important;
            border: none !important;
            border-radius: 4px !important;
            cursor: pointer !important;
            font-family: 'Courier New', monospace !important;
            font-size: 14px !important;
            outline: none !important;
            width: auto !important;
        }
        .blur-save-button {
            background: #2196F3 !important;
            color: white !important;
        }
        .blur-save-button:hover {
            background: #1976D2 !important;
        }
        .blur-cancel-button {
            background: #666 !important;
            color: white !important;
        }
        .blur-cancel-button:hover {
            background: #555 !important;
        }
        .blur-section {
            margin: 5px 0 !important;
            border-bottom: 1px solid #404040 !important;
            background: #2b2b2b !important;
        }
        .blur-section-header {
            padding: 10px 20px !important;
            background: #363636 !important;
            cursor: pointer !important;
            user-select: none !important;
            display: flex !important;
            justify-content: space-between !important;
            align-items: center !important;
            color: #fff !important;
            font-size: 14px !important;
            font-weight: bold !important;
        }
        .blur-section-content {
            padding: 15px 20px !important;
            display: none;
            background: #2b2b2b !important;
        }
        .blur-section.expanded .blur-section-content {
            display: block;
        }
        .blur-section-arrow {
            transition: transform 0.3s ease;
            color: #fff !important;
            font-size: 12px !important;
        }
        .blur-section.expanded .blur-section-arrow {
            transform: rotate(180deg);
        }
        .blur-slider-container {
            margin-top: 10px !important;
            display: flex !important;
            align-items: center !important;
            gap: 5px !important;
        }
        .blur-slider-label {
            flex: 1 !important;
            color: #fff !important;
            font-size: 14px !important;
        }
        .blur-slider {
            flex: 1 !important;
            height: 4px !important;
			max-width: 125px;
            background: #666 !important;
            outline: none !important;
            -webkit-appearance: none !important;
            appearance: none !important;
            border-radius: 2px !important;
        }
        .blur-slider::-webkit-slider-thumb {
            -webkit-appearance: none !important;
            appearance: none !important;
            width: 16px !important;
            height: 16px !important;
            background: #2196F3 !important;
            border-radius: 50% !important;
            cursor: pointer !important;
        }
        .blur-slider::-moz-range-thumb {
            width: 16px !important;
            height: 16px !important;
            background: #2196F3 !important;
            border-radius: 50% !important;
            cursor: pointer !important;
            border: none !important;
        }
        .blur-slider-value {
            min-width: 45px !important;
            text-align: right !important;
            color: #2196F3 !important;
            font-size: 12px !important;
        }
		#blur-toggle-button {
            position: fixed !important;
            top: 0 !important;
            left: 0 !important;
            width: 14px !important;
            height: 14px !important;
            max-width: 14px !important;
            max-height: 14px !important;
            min-width: 14px !important;
            min-height: 14px !important;
            background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAACY0lEQVQ4jY3VP4gVVxQG8N+dN+tz1dVVWRMwiQkSEkTBSgurpEqXQkwsrSWQKo2NhYE06dJIugRRk0qIovgHBcHEpAmYgCYQ/LO7havo+nZ1n/v23hT3Ljs8H7t+cGcuw3zfnHPu+c6Ek5bFQRzFG+ji38S5IX6Z5b9DdEN+Ly0S6uX1HMaHZT+DscDWBUbX0j5P+plqHXGG3mfElQTfaexXY2Nga+KtyJOnpMTqx7xoM3WVZ639S4Tv8VWJ+gH24MuGYCjpLVTMY1NiJ3ZXvBl52aETSg0/x+kGea5E1ETCAqYxiQ7aGMJ44HLiSl2IP/SR+8XgOVoYCWxPxEAVUTEa6bR4WONY+dJK+Auj2JJYhzoh5DquD7wd+KDC/RWEvsGOwElcTNwJOd0oC86X9B9FntX4Tj6En7CqT+xbHCnEhcD2mOu4AWtKlE/xd+J64GZViGewb0B0Xy9uphnHP7ideIxeYD4whT9rfm9zp2qQ4wDBNODZQPTKfbEPP8UFrzqnxiUY5r0e7wf2BnZhs9wyQb50Mdfazxf4cYAYuQyrMIFPsCfktU2uYStk0bVop2K9d1fI5khZv4VsvbHECCpIWXAksDmyIZxguMon1X/C/ZiVG7sKuWTRUmM/ivwaOFvjBQ7JfbaIrlebfY1ivcRkoJNoB4YiExU3e9yqq/ypUxUfY4dswzOy8a80FUP2+L3EtcRdDMfskoeJP7o8CCcahGYPFdyzNMJ6cv/dwOmKW7GMr6Gc5dRYccpyaArO4Yk8WcYrJtczN9MYsB+9xoA9ji1ldYsrJhLTs3QP8LL/F/A/amq/lc3UweoAAAAASUVORK5CYII=') !important;
            background-size: cover !important;
            background-color: transparent !important;
            background-repeat: no-repeat !important;
            border: none !important;
            cursor: pointer !important;
            z-index: 9999 !important;
            padding: 0 !important;
            margin: 0 !important;
            outline: none !important;
            pointer-events: auto !important;
            filter: blur(0) !important;
        }
        #blur-toggle-button:hover {
            opacity: 0.8 !important;
        }
        #blur-word-list {
            display: flex !important;
            flex-direction: column !important;
            margin: 0 !important;
            padding: 0 !important;
        }
        .blur-word-entry {
            display: flex !important;
            gap: 5px !important;
            margin-top: 5px !important;
            align-items: center !important;
        }
        .blur-word-input {
            flex-grow: 1 !important;
            background: #1e1e1e !important;
            border: 1px solid #404040 !important;
            color: #ffffff !important;
            padding: 8px !important;
            border-radius: 4px !important;
            font-family: 'Courier New', monospace !important;
            font-size: 14px !important;
            line-height: 1.4 !important;
            height: auto !important;
            width: auto !important;
            margin: 0 !important;
            outline: none !important;
            box-shadow: none !important;
            -webkit-appearance: none !important;
            -moz-appearance: none !important;
            appearance: none !important;
            transition: border-color 0.2s ease !important;
            filter: blur(2px) !important;
        }
        .blur-word-input:focus {
            border-color: #2196F3 !important;
            filter: blur(0) !important;
        }
        .blur-delete-button {
            background: #ff4444 !important;
            color: white !important;
            border: none !important;
            border-radius: 4px !important;
            width: 30px !important;
            height: 30px !important;
            cursor: pointer !important;
            display: flex !important;
            align-items: center !important;
            justify-content: center !important;
            font-family: Arial, sans-serif !important;
            font-size: 20px !important;
            line-height: 1 !important;
            padding: 0 !important;
            margin: 0 !important;
            outline: none !important;
            transition: background-color 0.2s ease !important;
        }
        .blur-delete-button:hover {
            background: #cc0000 !important;
        }
        .blur-add-button {
            background: #4CAF50 !important;
            color: white !important;
            border: none !important;
            border-radius: 4px !important;
            padding: 8px !important;
            height: 36px !important;
            cursor: pointer !important;
            width: 100% !important;
            margin-top: 5px !important;
            font-family: 'Courier New', monospace !important;
            font-size: 14px !important;
            text-align: center !important;
            outline: none !important;
            transition: background-color 0.2s ease !important;
        }
        .blur-add-button:hover {
            background: #388E3C !important;
        }
        .blur-option-container {
            padding: 10px !important;
            background: #1e1e1e !important;
            border-radius: 4px !important;
            margin-top: 5px !important;
        }
        .blur-checkbox-label {
            display: flex !important;
            align-items: center !important;
            gap: 10px !important;
            color: #fff !important;
            font-size: 14px !important;
            cursor: pointer !important;
            user-select: none !important;
        }
        .blur-checkbox {
            width: 16px !important;
            height: 16px !important;
            cursor: pointer !important;
            margin: 0 !important;
        }
    `);

    let blurWords = GM_getValue('blurWords', []);
    let userIP = GM_getValue('userIP', '');
    let isFullPageBlurred = GM_getValue('isFullPageBlurred', false);
    let defaultFullPageBlur = GM_getValue('defaultFullPageBlur', false);
    let wordBlurStrength = GM_getValue('wordBlurStrength', 7.5);
	let hoverDelay = GM_getValue('hoverDelay', 1.0);
    let pageBlurStrength = GM_getValue('pageBlurStrength', 10);
    let wordunblurTransitionSpeed = GM_getValue('wordunblurTransitionSpeed', 1.5);
    let isIPBlurEnabled = GM_getValue('isIPBlurEnabled', false);
    let clickTimeout = null;
    const processedNodes = new WeakSet();
    let isProcessingComplete = false;

    function removeFullPageBlur() {
        setTimeout(() => {
        document.documentElement.classList.add('full-page-unblur');
        document.documentElement.classList.remove('full-page-blur');
        }, 100);
    }

    function checkAndRemoveInitialBlur() {
        if (isProcessingComplete && isFullPageBlurred) {
            removeFullPageBlur();
            isFullPageBlurred = false;
        }
    }

    function toggleFullPageBlur() {
        if (isFullPageBlurred) {
            removeFullPageBlur();
            isFullPageBlurred = false;
        } else {
            document.documentElement.classList.remove('full-page-unblur');
            document.documentElement.classList.add('full-page-blur');
            isFullPageBlurred = true;
        }
    }

    function updateBlurStyles() {
        GM_addStyle(`
            .word-blur {
                filter: blur(${wordBlurStrength}px) !important;
                transition: filter ${wordunblurTransitionSpeed}s ease !important;
            }
			.word-blur:hover {
				filter: blur(0px) !important;
				transition-delay: ${hoverDelay}s !important;
			}
            .full-page-blur {
                filter: blur(${pageBlurStrength}px) !important;
            }
        `);
    }

    function fetchIP() {
        const ipDisplay = document.getElementById('blur-ip-display');
        if (ipDisplay) {
            ipDisplay.style.filter = 'blur(0)';
            ipDisplay.style.opacity = '0.5';
        }

        GM_xmlhttpRequest({
            method: 'GET',
            url: 'https://api.ipify.org?format=json',
            onload: function(response) {
                try {
                    const data = JSON.parse(response.responseText);
                    if (data.ip) {
                        userIP = data.ip;
                        GM_setValue('userIP', userIP);
                        if (ipDisplay) {
                            ipDisplay.textContent = `Aktuelle IP: ${userIP}`;
                            ipDisplay.style.opacity = '1';
                        }
                    }
                } catch (e) {
                    if (ipDisplay) {
                        ipDisplay.style.opacity = '1';
                    }
                }
            },
            onerror: function() {
                if (ipDisplay) {
                    ipDisplay.style.opacity = '1';
                }
            }
        });
    }
	function createWordEntry(word = '') {
        const entry = document.createElement('div');
        entry.className = 'blur-word-entry';

        const input = document.createElement('input');
        input.type = 'text';
        input.className = 'blur-word-input';
        input.value = word;

        const deleteBtn = document.createElement('button');
        deleteBtn.className = 'blur-delete-button';
        deleteBtn.innerHTML = '×';
        deleteBtn.onclick = () => entry.remove();

        entry.appendChild(input);
        entry.appendChild(deleteBtn);

        return entry;
    }

	function createSettings() {
		const panel = document.createElement('div');
		panel.id = 'blur-settings-panel';
		const version = GM_info.script.version;
		panel.innerHTML = `
			<div id="blur-settings-header">
				<h3 style="margin:0">Wörter zum Ausblenden (v${version})</h3>
				<button id="blur-close-button">×</button>
			</div>

			<div id="blur-section-container">
				<div id="blur-ip-info">
					Tipp: Mache ein Doppelkick auf das Einstellungs-Symbol um die Seite zu Bluren. Mit Escape kannst du das Bluren der Seite und das UI wieder Schließen.
				</div>

				<div class="blur-section">
					<div class="blur-section-header">
						<span>Allgemeine Einstellungen</span>
						<span class="blur-section-arrow">▼</span>
					</div>
					<div class="blur-section-content">
						<div id="blur-text-info">
							Passe hier deine Blurstärke und Animationszeiten ein.
						</div>
						<div class="blur-slider-container">
							<label class="blur-slider-label">Wort Blur-Stärke (5px - 10px)</label>
							<input type="range" min="5" max="10" step="0.5" value="${wordBlurStrength}"
								   class="blur-slider" id="word-blur-slider">
							<span class="blur-slider-value">${wordBlurStrength}px</span>
						</div>
						<div class="blur-slider-container">
							<label class="blur-slider-label">Hover verzögerung (0.5s - 1.5s)</label>
							<input type="range" min="0.5" max="1.5" step="0.1" value="${hoverDelay}"
								   class="blur-slider" id="hover-delay-slider">
							<span class="blur-slider-value">${hoverDelay}s</span>
						</div>
						<div class="blur-slider-container">
							<label class="blur-slider-label">Wort unblur Übergangszeit (0.5s - 2.5s)</label>
							<input type="range" min="0.5" max="2.5" step="0.1" value="${wordunblurTransitionSpeed}"
								   class="blur-slider" id="transition-slider">
							<span class="blur-slider-value">${wordunblurTransitionSpeed}s</span>
						</div>
						<div class="blur-option-container">
							<label class="blur-checkbox-label">
								<input type="checkbox" class="blur-checkbox" id="blur-default-setting"
									   ${defaultFullPageBlur ? 'checked' : ''}>
								Seite standardmäßig beim Start blurren
							</label>
						</div>
						<div class="blur-slider-container">
							<label class="blur-slider-label">Seiten Blur-Stärke (5px - 15px)</label>
							<input type="range" min="5" max="15" step="0.5" value="${pageBlurStrength}"
								   class="blur-slider" id="page-blur-slider">
							<span class="blur-slider-value">${pageBlurStrength}px</span>
						</div>
					</div>
				</div>

				<div class="blur-section">
					<div class="blur-section-header">
						<span>IP-Einstellungen</span>
						<span class="blur-section-arrow">▼</span>
					</div>
					<div class="blur-section-content">
						<div id="blur-text-info">
							Ermittel erst deine IP und Aktiviere die Option wenn du deine IP Bluren möchtest.<br>Das Ermitteln funktuiniert nicht automatisch!
						</div>
						<div id="blur-ip-info">
							<span id="blur-ip-display">Aktuelle IP: ${userIP || 'Nicht ermittelt'}</span>
							<button id="blur-ip-button">IP ermitteln</button>
						</div>
						<div class="blur-option-container">
							<label class="blur-checkbox-label">
								<input type="checkbox" class="blur-checkbox" id="ip-blur-setting"
									   ${isIPBlurEnabled ? 'checked' : ''}>
								IP-Blur aktivieren
							</label>
						</div>
					</div>
				</div>

				<div class="blur-section">
					<div class="blur-section-header">
						<span>Wortliste</span>
						<span class="blur-section-arrow">▼</span>
					</div>
					<div class="blur-section-content">
						<div id="blur-text-info">
							Füge hier deine Wörter hinzu die du Bluren möchtest.<br>Drücke auf "+ Neues Wort hinzufügen" um ein neues Feld zu erstellen.<br>Nur ein Wort pro Feld!
						</div>
						<div id="blur-word-list"></div>
						<button class="blur-add-button">+ Neues Wort hinzufügen</button>
					</div>
				</div>
			</div>

            <div class="blur-button-container">
                <button class="blur-button blur-cancel-button" id="blur-cancel">Abbrechen</button>
                <button class="blur-button blur-save-button" id="blur-save">Speichern</button>
            </div>
        `;

        document.body.appendChild(panel);

        const wordList = panel.querySelector('#blur-word-list');
        const addButton = panel.querySelector('.blur-add-button');
        const ipButton = panel.querySelector('#blur-ip-button');
        const sections = panel.querySelectorAll('.blur-section');

        sections.forEach(section => {
            const header = section.querySelector('.blur-section-header');
            header.addEventListener('click', () => {
                section.classList.toggle('expanded');
            });
        });

		const sliders = panel.querySelectorAll('.blur-slider');
		sliders.forEach(slider => {
			const valueDisplay = slider.nextElementSibling;
			slider.addEventListener('input', () => {
				const unit = slider.id.includes('delay') || slider.id.includes('transition') ? 's' : 'px';
				valueDisplay.textContent = `${slider.value}${unit}`;
			});
		});

        addButton.onclick = () => {
            wordList.appendChild(createWordEntry());
        };

        ipButton.onclick = fetchIP;

        const toggleBtn = document.createElement('button');
        toggleBtn.id = 'blur-toggle-button';
        document.body.appendChild(toggleBtn);

        let isDragging = false;
        let currentX;
        let currentY;
        let initialX;
        let initialY;
        let xOffset = 0;
        let yOffset = 0;
		const dragStart = (e) => {
            initialX = e.clientX - xOffset;
            initialY = e.clientY - yOffset;
            if (e.target.closest('#blur-settings-header')) {
                isDragging = true;
            }
        };

		function adjustPanelPosition() {
			const panelRect = panel.getBoundingClientRect();
			const viewportWidth = window.innerWidth;
			const viewportHeight = window.innerHeight;
			let needsAdjustment = false;
			let newX = xOffset;
			let newY = yOffset;

			const panelCenterX = (panelRect.left + panelRect.right) / 2;
			const panelCenterY = (panelRect.top + panelRect.bottom) / 2;

			if (panelRect.right > viewportWidth) {
				newX = viewportWidth / 2 - panelRect.width / 2 - 20;
				needsAdjustment = true;
			} else if (panelRect.left < 0) {
				newX = -viewportWidth / 2 + panelRect.width / 2 + 20;
				needsAdjustment = true;
			}

			if (panelRect.bottom > viewportHeight) {
				newY = viewportHeight / 2 - panelRect.height / 2 - 20;
				needsAdjustment = true;
			} else if (panelRect.top < 0) {
				newY = -viewportHeight / 2 + panelRect.height / 2 + 20;
				needsAdjustment = true;
			}

			if (needsAdjustment) {
				panel.style.transition = 'transform 0.3s ease-out';
				xOffset = newX;
				yOffset = newY;
				panel.style.transform = `translate(calc(-50% + ${newX}px), calc(-50% + ${newY}px))`;

				setTimeout(() => {
					panel.style.transition = '';
				}, 300);
			}
		}

		const resizeObserver = new ResizeObserver(() => {
			adjustPanelPosition();
		});

		resizeObserver.observe(panel);

		window.addEventListener('resize', adjustPanelPosition);

		const drag = (e) => {
			if (isDragging) {
				e.preventDefault();
				currentX = e.clientX - initialX;
				currentY = e.clientY - initialY;
				xOffset = currentX;
				yOffset = currentY;
				panel.style.transform = `translate(calc(-50% + ${currentX}px), calc(-50% + ${currentY}px))`;
			}
		};

		const dragEnd = () => {
			isDragging = false;
			adjustPanelPosition();
		};

        document.addEventListener('mousedown', dragStart);
        document.addEventListener('mousemove', drag);
        document.addEventListener('mouseup', dragEnd);

        function showPanel() {
            panel.style.display = 'block';
            setTimeout(() => {
                panel.classList.add('visible');
            }, 10);
            panel.style.transform = 'translate(-50%, -50%)';
            xOffset = 0;
            yOffset = 0;
            wordList.innerHTML = '';
            blurWords.forEach(word => {
                wordList.appendChild(createWordEntry(word));
            });
        }

        function hidePanel() {
            panel.classList.remove('visible');
            setTimeout(() => {
                panel.style.display = 'none';
            }, 300);
        }

        function handleClick() {
            if (clickTimeout !== null) {
                clearTimeout(clickTimeout);
                clickTimeout = null;
                toggleFullPageBlur();
            } else {
                clickTimeout = setTimeout(() => {
                    clickTimeout = null;
                    showPanel();
                }, 250);
            }
        }

        function saveSettings() {
            const inputs = panel.querySelectorAll('.blur-word-input');
            const newWords = [...new Set([...inputs].map(input => input.value.trim()).filter(w => w))];

            const pageBlurSlider = document.getElementById('page-blur-slider');
            const wordBlurSlider = document.getElementById('word-blur-slider');
			const hoverDelaySlider = document.getElementById('hover-delay-slider');
            const transitionSlider = document.getElementById('transition-slider');
            const defaultBlurCheckbox = document.getElementById('blur-default-setting');
            const ipBlurCheckbox = document.getElementById('ip-blur-setting');

            pageBlurStrength = parseFloat(pageBlurSlider.value);
            wordBlurStrength = parseFloat(wordBlurSlider.value);
			hoverDelay = parseFloat(hoverDelaySlider.value);
            wordunblurTransitionSpeed = parseFloat(transitionSlider.value);
            defaultFullPageBlur = defaultBlurCheckbox.checked;
            isIPBlurEnabled = ipBlurCheckbox.checked;

            GM_setValue('blurWords', newWords);
			GM_setValue('hoverDelay', hoverDelay);
            GM_setValue('pageBlurStrength', pageBlurStrength);
            GM_setValue('wordBlurStrength', wordBlurStrength);
            GM_setValue('wordunblurTransitionSpeed', wordunblurTransitionSpeed);
            GM_setValue('defaultFullPageBlur', defaultFullPageBlur);
            GM_setValue('isIPBlurEnabled', isIPBlurEnabled);

            blurWords = newWords;
            updateBlurStyles();
            hidePanel();
            location.reload();
        }

        function handleKeyPress(e) {
            if (e.key === 'Escape') {
                if (panel.style.display === 'block') {
                    hidePanel();
                } else if (isFullPageBlurred) {
                    removeFullPageBlur();
                    isFullPageBlurred = false;
                }
            }
        }

        toggleBtn.addEventListener('click', handleClick);
        document.getElementById('blur-close-button').addEventListener('click', hidePanel);
        document.getElementById('blur-cancel').addEventListener('click', hidePanel);
        document.getElementById('blur-save').addEventListener('click', saveSettings);
        document.addEventListener('keydown', handleKeyPress);
    }

    function findBlurPositions(text) {
        const positions = [];
        blurWords.forEach(word => {
            const escapedWord = word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
            const regex = new RegExp(escapedWord, 'gi');
            let match;
            while ((match = regex.exec(text)) !== null) {
                positions.push({
                    start: match.index,
                    end: match.index + match[0].length,
                    word: match[0]
                });
            }
        });

        if (isIPBlurEnabled && userIP) {
            const ipRegex = new RegExp(userIP.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g');
            let match;
            while ((match = ipRegex.exec(text)) !== null) {
                positions.push({
                    start: match.index,
                    end: match.index + match[0].length,
                    word: match[0]
                });
            }
        }

        positions.sort((a, b) => a.start - b.start);
        const mergedPositions = [];
        let current = null;

        for (const pos of positions) {
            if (!current) {
                current = {...pos};
            } else if (pos.start <= current.end) {
                current.end = Math.max(current.end, pos.end);
                current.word = text.slice(current.start, current.end);
            } else {
                mergedPositions.push(current);
                current = {...pos};
            }
        }
        if (current) {
            mergedPositions.push(current);
        }

        return mergedPositions;
    }
	function isProcessed(node) {
        if (!node || !node.parentElement) return true;

        const isInput = node.parentElement.closest('input, textarea, [contenteditable="true"]');
        if (isInput) return true;

        const isBlurSettings = node.parentElement.closest('#blur-settings-panel, #blur-ip-display');
        if (isBlurSettings) return true;

        return processedNodes.has(node) ||
               node.parentElement.classList.contains('word-blur') ||
               node.parentElement.hasAttribute('data-blurred');
    }

    function blurText(node) {
        if (isProcessed(node)) return;

        const text = node.textContent;
        if (!text.trim()) {
            processedNodes.add(node);
            return;
        }

        const positions = findBlurPositions(text);
        if (positions.length === 0) {
            processedNodes.add(node);
            return;
        }

        const container = document.createElement('span');
        container.setAttribute('data-blurred', 'true');
        let lastIndex = 0;

        positions.forEach(pos => {
            if (pos.start > lastIndex) {
                container.appendChild(document.createTextNode(
                    text.slice(lastIndex, pos.start)
                ));
            }
            const blurSpan = document.createElement('span');
            blurSpan.className = 'word-blur';
            blurSpan.textContent = pos.word;
            container.appendChild(blurSpan);
            lastIndex = pos.end;
        });

        if (lastIndex < text.length) {
            container.appendChild(document.createTextNode(
                text.slice(lastIndex)
            ));
        }

        node.parentNode.replaceChild(container, node);
        processedNodes.add(container);
    }

    function processNodes(root) {
        const walker = document.createTreeWalker(
            root,
            NodeFilter.SHOW_TEXT,
            {
                acceptNode: (node) => {
                    if (node.parentElement.closest('#blur-settings-panel')) return NodeFilter.FILTER_REJECT;
                    if (node.parentElement.closest('script')) return NodeFilter.FILTER_REJECT;
                    if (node.parentElement.closest('style')) return NodeFilter.FILTER_REJECT;
                    if (node.parentElement.closest('input, textarea, [contenteditable="true"]')) return NodeFilter.FILTER_REJECT;
                    if (isProcessed(node)) return NodeFilter.FILTER_REJECT;
                    return NodeFilter.FILTER_ACCEPT;
                }
            }
        );

        const nodes = [];
        while (walker.nextNode()) nodes.push(walker.currentNode);

        let processedCount = 0;
        const totalNodes = nodes.length;

        function processBatch(startIndex) {
            const endIndex = Math.min(startIndex + 100, nodes.length);
            const batch = nodes.slice(startIndex, endIndex);

            batch.forEach(blurText);
            processedCount += batch.length;

            if (endIndex < nodes.length) {
                requestAnimationFrame(() => processBatch(endIndex));
            } else {
                isProcessingComplete = true;
                checkAndRemoveInitialBlur();
            }
        }

        if (nodes.length > 0) {
            processBatch(0);
        } else {
            isProcessingComplete = true;
            checkAndRemoveInitialBlur();
        }
    }

    const observer = new MutationObserver((mutations) => {
        for (const mutation of mutations) {
            if (mutation.type === 'childList') {
                mutation.addedNodes.forEach(node => {
                    if (node.nodeType === 1) processNodes(node);
                    else if (node.nodeType === 3) blurText(node);
                });
            }
        }
    });

    const initScript = document.createElement('script');
    initScript.textContent = `
        if (${defaultFullPageBlur}) {
            document.documentElement.classList.add('full-page-blur');
        }
    `;
    document.documentElement.appendChild(initScript);

    function init() {
        createSettings();
        processNodes(document.body);
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
        updateBlurStyles();
    }

    if (defaultFullPageBlur) {
        document.documentElement.classList.add('full-page-blur');
        isFullPageBlurred = true;
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

    GM_registerMenuCommand('Wortliste bearbeiten', () => {
        document.getElementById('blur-settings-panel').style.display = 'block';
        const wordList = document.getElementById('blur-word-list');
        wordList.innerHTML = '';
        blurWords.forEach(word => {
            wordList.appendChild(createWordEntry(word));
        });
    });
})();