Gemini_Userscript_Refactor-Helper

Kombiniert Clean-HTML Export mit einem Profi-Element-Picker (Blockiert Links, findet ähnliche Elemente).

От 20.11.2025. Виж последната версия.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name          Gemini_Userscript_Refactor-Helper
// @namespace     http://tampermonkey.net/
// @version       3.0
// @description   Kombiniert Clean-HTML Export mit einem Profi-Element-Picker (Blockiert Links, findet ähnliche Elemente).
// @author        Dein Vibe Coding Partner
// @match         *://*/*
// @license MIT 
// @run-at        document-end
// @grant         GM_addStyle
// @grant         GM_setClipboard
// @grant         unsafeWindow
// ==/UserScript==

(function() {
    'use strict';

    // Globale Variablen für den Picker
    let isPicking = false;
    let selectedElements = new Set(); // Speichert die tatsächlich geklickten Elemente

    // #############################################################################
    // # TEIL 1: CLEAN HTML GENERATOR (Das Futter für die KI)
    // #############################################################################

    function getCleanHTML() {
        const clone = document.documentElement.cloneNode(true);

        // Müll entfernen
        const tagsToRemove = ['script', 'style', 'noscript', 'iframe', 'svg', 'meta', 'link', 'path', 'symbol', 'img', 'video', 'picture', 'source', 'canvas', 'div[id^="ad-"]'];
        tagsToRemove.forEach(tag => {
            clone.querySelectorAll(tag).forEach(el => el.remove());
        });

        // Kommentare entfernen
        const removeComments = (node) => {
            const children = node.childNodes;
            for (let i = children.length - 1; i >= 0; i--) {
                const child = children[i];
                if (child.nodeType === 8) node.removeChild(child);
                else if (child.nodeType === 1) removeComments(child);
            }
        };
        removeComments(clone);

        // Attribute putzen & Text zu "K"
        const allowedAttrs = ['id', 'class', 'name', 'role', 'type', 'data-test', 'href', 'value'];
        clone.querySelectorAll('*').forEach(el => {
            [...el.attributes].forEach(attr => {
                if (!allowedAttrs.includes(attr.name)) el.removeAttribute(attr.name);
            });
            // Text durch K ersetzen (Skelett-Modus)
            el.childNodes.forEach(node => {
                if (node.nodeType === 3 && node.nodeValue.trim().length > 0) {
                    node.nodeValue = 'K';
                }
            });
        });

        let htmlString = clone.outerHTML.replace(/^\s*[\r\n]/gm, '');
        return `\n${htmlString}\n`;
    }

    function downloadCleanHTML() {
        const htmlContent = getCleanHTML();
        const filename = `${window.location.hostname.replace(/[^a-z0-9]/gi, '_')}_clean.html`;
        
        const blob = new Blob([htmlContent], { type: 'text/html' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = filename;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        showFeedback(`Datei '${filename}' heruntergeladen!`);
    }

    // #############################################################################
    // # TEIL 2: INTELLIGENTER ELEMENT PICKER
    // #############################################################################

    function togglePicker() {
        isPicking = !isPicking;
        const btn = document.getElementById('gemini-pick-btn');
        const body = document.body;

        if (isPicking) {
            btn.textContent = '✅ Fertig & Kopieren';
            btn.style.background = '#ff6b6b'; // Rot zum Stoppen
            
            // Event Listener HINZUFÜGEN (Capture Phase um Links zu blockieren!)
            document.addEventListener('mouseover', onHover, true);
            document.addEventListener('mouseout', onHoverOut, true);
            document.addEventListener('click', onClick, true);
            
            showFeedback("Pick-Modus AKTIV. Links sind deaktiviert.");
        } else {
            // Beenden und Report erstellen
            finishPicking();
            
            btn.textContent = '🎯 Element Picken';
            btn.style.background = '#77dd77'; // Grün zum Starten
            
            // Event Listener ENTFERNEN
            document.removeEventListener('mouseover', onHover, true);
            document.removeEventListener('mouseout', onHoverOut, true);
            document.removeEventListener('click', onClick, true);
            
            // Aufräumen
            document.querySelectorAll('.gemini-selected, .gemini-similar, .gemini-hover').forEach(el => {
                el.classList.remove('gemini-selected', 'gemini-similar', 'gemini-hover');
            });
            selectedElements.clear();
        }
    }

    function onHover(e) {
        if (!isPicking || e.target.closest('#gemini-panel')) return;
        e.stopPropagation();
        e.target.classList.add('gemini-hover');
    }

    function onHoverOut(e) {
        if (!isPicking) return;
        e.target.classList.remove('gemini-hover');
    }

    function onClick(e) {
        if (!isPicking || e.target.closest('#gemini-panel')) return;
        
        // KILLT ALLE KLICKS AUF DER SEITE (Links, Buttons, etc.)
        e.preventDefault();
        e.stopPropagation();
        e.stopImmediatePropagation();

        const el = e.target;

        // Toggle Auswahl
        if (selectedElements.has(el)) {
            el.classList.remove('gemini-selected');
            selectedElements.delete(el);
            // Ähnliche entfernen (einfachheitshalber alle ähnlichen resetten und neu berechnen)
            document.querySelectorAll('.gemini-similar').forEach(sim => sim.classList.remove('gemini-similar'));
        } else {
            el.classList.add('gemini-selected');
            selectedElements.add(el);
            highlightSimilar(el);
        }
    }

    // Findet Elemente, die genauso aussehen (gleiche Klassen)
    function highlightSimilar(el) {
        if (!el.className) return; // Ohne Klassen zu riskant
        
        // Wir bauen einen Selektor aus dem Tag und den Klassen
        const classes = Array.from(el.classList)
            .filter(c => !c.startsWith('gemini-')) // Unsere eigenen Klassen ignorieren
            .join('.');
            
        if (!classes) return;

        const selector = `${el.tagName.toLowerCase()}.${classes}`;
        
        // Alle finden
        try {
            const similar = document.querySelectorAll(selector);
            similar.forEach(sim => {
                if (sim !== el && !selectedElements.has(sim)) {
                    sim.classList.add('gemini-similar');
                }
            });
            showFeedback(`${similar.length} ähnliche Elemente gefunden!`);
        } catch (err) {
            // Manchmal sind Klassen ungültige Selektoren (z.B. mit Doppelpunkt), ignorieren wir.
        }
    }

    function finishPicking() {
        if (selectedElements.size === 0) {
            showFeedback("Nichts ausgewählt.");
            return;
        }

        let report = "### GEMINI ELEMENT REPORT ###\n\n";

        selectedElements.forEach(el => {
            const styles = window.getComputedStyle(el);
            
            // Versuchen, einen eindeutigen Selektor zu bauen
            let selector = el.tagName.toLowerCase();
            if (el.id) selector += `#${el.id}`;
            if (el.className) {
                 const cleanClasses = Array.from(el.classList)
                    .filter(c => !c.startsWith('gemini-'))
                    .join('.');
                 if (cleanClasses) selector += `.${cleanClasses}`;
            }

            report += `ITEM: ${selector}\n`;
            report += `--------------------------------------------------\n`;
            report += `INNER TEXT: "${el.innerText.substring(0, 50)}..."\n`;
            report += `HTML (Outer): \n${el.outerHTML.replace(/gemini-[a-z]+\s?/g, '')}\n`; // Unsere Klassen aus HTML entfernen
            report += `COMPUTED STYLES:\n`;
            report += `- Display: ${styles.display}\n`;
            report += `- Color: ${styles.color}\n`;
            report += `- Background: ${styles.backgroundColor}\n`;
            report += `- Font: ${styles.fontSize} ${styles.fontFamily}\n`;
            report += `- Padding/Margin: ${styles.padding} / ${styles.margin}\n`;
            report += `\n\n`;
        });

        GM_setClipboard(report);
        showFeedback(`${selectedElements.size} Elemente kopiert!`);
    }

    // #############################################################################
    // # UI & CSS
    // #############################################################################

    function showFeedback(text) {
        const fb = document.getElementById('gemini-feedback');
        fb.innerText = text;
        fb.classList.add('visible');
        setTimeout(() => fb.classList.remove('visible'), 3000);
    }

    function createUI() {
        const panel = document.createElement('div');
        panel.id = 'gemini-panel';
        
        const btnClean = document.createElement('button');
        btnClean.innerHTML = '💀 <b>Clean HTML</b> (Skelett)';
        btnClean.onclick = downloadCleanHTML;
        
        const btnPick = document.createElement('button');
        btnPick.id = 'gemini-pick-btn';
        btnPick.innerHTML = '🎯 <b>Element Picken</b>';
        btnPick.onclick = togglePicker;

        const feedback = document.createElement('div');
        feedback.id = 'gemini-feedback';

        panel.appendChild(btnClean);
        panel.appendChild(btnPick);
        document.body.appendChild(panel);
        document.body.appendChild(feedback);
    }

    GM_addStyle(`
        /* GUI Styles */
        #gemini-panel {
            position: fixed; bottom: 20px; right: 20px; z-index: 2147483647;
            display: flex; gap: 10px; background: #222; padding: 10px;
            border-radius: 50px; box-shadow: 0 5px 20px rgba(0,0,0,0.5);
            border: 1px solid #444;
        }
        #gemini-panel button {
            background: #444; color: white; border: none; padding: 10px 20px;
            border-radius: 30px; cursor: pointer; font-family: sans-serif; font-size: 14px;
            transition: all 0.2s;
        }
        #gemini-panel button:hover { transform: scale(1.05); filter: brightness(1.2); }
        
        #gemini-feedback {
            position: fixed; bottom: 80px; right: 20px; z-index: 2147483647;
            background: #333; color: #fff; padding: 10px 20px; border-radius: 5px;
            font-family: sans-serif; opacity: 0; transition: opacity 0.3s; pointer-events: none;
        }
        #gemini-feedback.visible { opacity: 1; }

        /* HIGHLIGHT STYLES */
        .gemini-hover {
            outline: 2px dashed #ff00ff !important;
            cursor: crosshair !important;
        }
        .gemini-selected {
            outline: 3px solid #0044ff !important; /* Dunkelblau für das Gewählte */
            background-color: rgba(0, 68, 255, 0.2) !important;
            box-shadow: 0 0 10px rgba(0, 68, 255, 0.5) !important;
        }
        .gemini-similar {
            outline: 2px dotted #00ccff !important; /* Hellblau für ähnliche */
            background-color: rgba(0, 204, 255, 0.1) !important;
        }
    `);

    createUI();

})();