AI Blur Extension Volker Weber's konstante Versuche KI überall raus zu bekommen brachte mich auf die Idee eine Firefox Extension zu machen, die schlichtweg jeden Absatz der bestimmte Schlagwörter enthält ausblendet... Auch die ist vollkommen Vibe-Coded mit KI - so als kleine Rebellion... Also auf eigene Gefahr. Veröffentlicht ist noch nix, Kinderkrankheiten gibts auch nocht... Der "Versperren" Button ist bei Google Suchtreffern zum Beispiel noch verkehrt herum und eigentlich mag ich Verschwommenheit nicht so richtig. Das müssen irgendwann klare Blockelemente sein die nach Paywall aussehen müssen... VIBE CODED - auf eure eigene Gefahr Dateien in Ordner schreiben, Firefox about:debugging aufrufen und via "Dieser Firefox" eine temporäre Erweiterung laden. So wie sie ist kommt die Erweiterung ohne Icons. Generiert euch ein paar mit irgendeiner, verkleinert die auf 96x96 und 48x48 und legt die als PNG in einen assets-Unterordner, wenn ihr denn ein Icon haben wollt... content.js // Standardwörter laden const DEFAULT_KEYWORDS = ['KI', 'AI', 'künstliche Intelligenz', 'Artificial Intelligence']; let customKeywords = []; let blurredElements = new Set(); // Auf Speicher-Änderungen hören browser.storage.onChanged.addListener((changes) => { if (changes.customKeywords) { customKeywords = changes.customKeywords.newValue || []; // Reset und neu verarbeiten blurredElements.clear(); processPage(); } }); // Gespeicherte benutzerdefinierte Wörter laden async function loadCustomKeywords() { try { const result = await browser.storage.local.get('customKeywords'); customKeywords = result.customKeywords || []; } catch (error) { console.error('Fehler beim Laden der Keywords:', error); } } // Prüfe ob Text ein Keyword enthält (nur als ganzes Wort) function containsKeyword(text, keywords) { for (let keyword of keywords) { // Erstelle Regex mit Word Boundaries // Escape special regex characters const escapedKeyword = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // \b = Word boundary (nur ganze Wörter) const regex = new RegExp(`\\b${escapedKeyword}\\b`, 'gi'); if (regex.test(text)) { return true; } } return false; } // Seite verarbeiten async function processPage() { await loadCustomKeywords(); const allKeywords = [...DEFAULT_KEYWORDS, ...customKeywords]; // Überschriften verarbeiten (zuerst!) ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].forEach(tag => { document.querySelectorAll(tag).forEach(heading => { if (blurredElements.has(heading)) return; const text = heading.textContent; if (containsKeyword(text, allKeywords)) { blurElement(heading, true); blurredElements.add(heading); } }); }); // Paragraphen und Text-Container verarbeiten const walker = document.createTreeWalker( document.body, NodeFilter.SHOW_ELEMENT, { acceptNode: function(node) { // Ignoriere Script, Style, und bereits verarbeitete Elemente if (node.tagName.match(/^(SCRIPT|STYLE|NOSCRIPT)$/i)) { return NodeFilter.FILTER_REJECT; } if (blurredElements.has(node)) { return NodeFilter.FILTER_REJECT; } // Nur p, div, span, article, section verarbeiten (größere Container) if (node.tagName.match(/^(P|DIV|SPAN|ARTICLE|SECTION|BLOCKQUOTE)$/i)) { return NodeFilter.FILTER_ACCEPT; } return NodeFilter.FILTER_SKIP; } }, false ); let node; while (node = walker.nextNode()) { // Prüfe nur direkten Text, nicht Text in Kind-Elementen let hasKeyword = false; for (let child of node.childNodes) { if (child.nodeType === Node.TEXT_NODE) { if (containsKeyword(child.textContent, allKeywords)) { hasKeyword = true; break; } } } if (hasKeyword) { blurElement(node, false); blurredElements.add(node); } } } // Element verschwommen darstellen function blurElement(element, isHeading = false) { // Für Überschriften: stärkerer Blur const blurAmount = isHeading ? '12px' : '8px'; // State für Toggle speichern let isBlurred = true; // Wrapper für den Unlock-Button erstellen let unlockButton = null; let buttonContainer = null; // Styling für das Element element.style.cursor = 'pointer'; element.style.transition = 'filter 0.3s ease'; // Initial verschwommen updateBlur(true); // Click-Handler für Entsperrung element.addEventListener('click', (e) => { // Ignoriere Klicks auf den Button selbst if (unlockButton && e.target === unlockButton) { return; } // Wenn versperrt: Entsperren und Klick blockieren if (isBlurred) { e.preventDefault(); e.stopPropagation(); isBlurred = false; updateBlur(false); } // Wenn entsperrt: Link-Klicks erlauben (kein preventDefault) }); function updateBlur(blur) { if (blur) { element.style.filter = `blur(${blurAmount})`; element.style.opacity = '0.8'; element.style.userSelect = 'none'; element.style.pointerEvents = 'auto'; element.title = 'Klick zum Lesen'; // Button entfernen wenn vorhanden if (buttonContainer) { buttonContainer.remove(); buttonContainer = null; unlockButton = null; } } else { element.style.filter = 'blur(0px)'; element.style.opacity = '1'; element.style.userSelect = 'auto'; element.style.pointerEvents = 'auto'; element.title = ''; // Button-Container neben dem Element erstellen buttonContainer = document.createElement('span'); buttonContainer.style.cssText = ` display: inline-block; margin-left: 8px; white-space: nowrap; `; // Button hinzufügen zum Wieder-Versperren unlockButton = document.createElement('button'); unlockButton.textContent = '🔒 Versperren'; unlockButton.style.cssText = ` padding: 6px 12px; background: #ff6b6b; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 12px; font-weight: bold; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); transition: background 0.2s ease; vertical-align: middle; `; unlockButton.addEventListener('mouseover', () => { unlockButton.style.background = '#ff5252'; }); unlockButton.addEventListener('mouseout', () => { unlockButton.style.background = '#ff6b6b'; }); unlockButton.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); isBlurred = true; updateBlur(true); }); buttonContainer.appendChild(unlockButton); element.parentNode.insertBefore(buttonContainer, element.nextSibling); } } } // Initial verarbeiten processPage(); // Bei dynamischen Inhalten neu prüfen const observer = new MutationObserver((mutations) => { // Nur wenn tatsächlich neue Nodes hinzugefügt werden let shouldProcess = false; for (let mutation of mutations) { if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { shouldProcess = true; break; } } if (shouldProcess) { // Kleine Verzögerung um Flimmern zu vermeiden setTimeout(() => { processPage(); }, 100); } }); observer.observe(document.body, { childList: true, subtree: true }); options.js let customKeywords = []; // Optionen beim Laden laden async function loadOptions() { try { const result = await browser.storage.local.get('customKeywords'); customKeywords = result.customKeywords || []; displayKeywords(); } catch (error) { console.error('Fehler beim Laden der Optionen:', error); } } // Alle Stichwörter anzeigen function displayKeywords() { const list = document.getElementById('keywordsList'); list.innerHTML = ''; if (customKeywords.length === 0) { list.innerHTML = '

Noch keine benutzerdefinierten Wörter hinzugefügt.

'; return; } customKeywords.forEach((keyword, index) => { const div = document.createElement('div'); div.className = 'keyword-item'; div.innerHTML = ` ${escapeHtml(keyword)} `; list.appendChild(div); }); } // Wort hinzufügen async function addKeyword() { const input = document.getElementById('newKeyword'); const keyword = input.value.trim(); if (!keyword) { showStatus('Bitte geben Sie ein Wort ein!', 'error'); return; } if (customKeywords.includes(keyword)) { showStatus('Dieses Wort existiert bereits!', 'error'); return; } if (keyword.length > 50) { showStatus('Das Wort ist zu lang (max. 50 Zeichen)!', 'error'); return; } customKeywords.push(keyword); try { await browser.storage.local.set({ customKeywords }); showStatus(`"${keyword}" hinzugefügt!`, 'success'); input.value = ''; displayKeywords(); } catch (error) { showStatus('Fehler beim Speichern!', 'error'); console.error(error); } } // Wort löschen (Event Delegation) async function removeKeyword(index) { const keyword = customKeywords[index]; customKeywords.splice(index, 1); try { await browser.storage.local.set({ customKeywords }); showStatus(`"${keyword}" gelöscht!`, 'success'); displayKeywords(); } catch (error) { showStatus('Fehler beim Löschen!', 'error'); console.error(error); } } // Status-Meldung anzeigen function showStatus(message, type) { const status = document.getElementById('status'); status.textContent = message; status.style.display = 'block'; status.style.background = type === 'error' ? '#ffebee' : '#d4edda'; status.style.color = type === 'error' ? '#c62828' : '#155724'; status.style.borderColor = type === 'error' ? '#ef5350' : '#28a745'; setTimeout(() => { status.style.display = 'none'; }, 3000); } // XSS-Schutz function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // Beim Seitenaufrufen laden und Event-Listener zuweisen document.addEventListener('DOMContentLoaded', () => { loadOptions(); // Button-Click Listener für Hinzufügen const addButton = document.querySelector('.add-form button'); if (addButton) { addButton.addEventListener('click', addKeyword); } // Enter-Taste zum Hinzufügen const input = document.getElementById('newKeyword'); if (input) { input.addEventListener('keypress', (e) => { if (e.key === 'Enter') { e.preventDefault(); addKeyword(); } }); } // Event Delegation für Löschen-Buttons const keywordsList = document.getElementById('keywordsList'); if (keywordsList) { keywordsList.addEventListener('click', (e) => { if (e.target && e.target.classList.contains('remove-btn')) { const index = parseInt(e.target.dataset.index, 10); removeKeyword(index); } }); } }); popup.js function openOptions() { browser.runtime.openOptionsPage().catch(error => { console.error('Fehler beim Öffnen der Optionsseite:', error); }); } // Alternativ: Button-Click direkt zuweisen document.addEventListener('DOMContentLoaded', () => { const button = document.querySelector('button'); if (button) { button.addEventListener('click', openOptions); } }); options.html AI Blur - Optionen

🔍 AI Blur Extension Einstellungen

Benutzerdefinierte Wörter

Zusätzliche Wörter hinzufügen die automatisch verschwommt werden sollen:

Aktuell konfigurierte Wörter:

Standard-Wörter

Diese Wörter werden immer automatisch erkannt:

popup.html AI Blur Popup

🔍 AI Blur Extension

Funktioniert!
KI-bezogene Texte werden verschwommt.
manifest.json { "manifest_version": 3, "name": "AI Blur Extension", "version": "1.0.0", "description": "Verschwommelt KI-Inhalte automatisch - Klick zum Entsperren", "author": "Dein Name", "permissions": [ "storage" ], "host_permissions": [ "https://*/*", "http://*/*", "file:///*" ], "icons": { "48": "assets/icon-48.png", "96": "assets/icon-96.png" }, "action": { "default_title": "AI Blur Extension Optionen", "default_popup": "popup.html" }, "options_page": "options.html", "content_scripts": [ { "matches": [ "https://*/*", "http://*/*", "file:///*" ], "js": ["content.js"], "run_at": "document_end" } ] }