Universal Link Extractor

Estrae link con filtri di inclusione specifici per ogni sito, con GUI e toggle.

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

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo 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!)

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!)

// ==UserScript==
// @name         Universal Link Extractor
// @namespace    http://tampermonkey.net/
// @version      3.0
// @description  Estrae link con filtri di inclusione specifici per ogni sito, con GUI e toggle.
// @author       ChatGPT (modificato)
// @match        *://*/*
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @license MIT 
// ==/UserScript==

(function() {
    'use strict';

    const currentHost = location.host;
    const enabledSites = JSON.parse(GM_getValue('enabledSites', '[]'));

    // Struttura per salvare i filtri specifici per ogni sito
    // { "example.com": ["pattern1", "pattern2"], "another.com": ["pattern3"] }
    const siteFilters = JSON.parse(GM_getValue('siteFilters', '{}'));

    // Menu per abilitare/disabilitare lo script su questo sito
    GM_registerMenuCommand(
        enabledSites.includes(currentHost)
            ? 'Disabilita Universal Link Extractor su questo sito'
            : 'Abilita Universal Link Extractor su questo sito',
        () => {
            let sites = JSON.parse(GM_getValue('enabledSites', '[]'));
            if (sites.includes(currentHost)) {
                sites = sites.filter(s => s !== currentHost);
                GM_setValue('enabledSites', JSON.stringify(sites));
                alert('Script disabilitato su: ' + currentHost);
            } else {
                sites.push(currentHost);
                GM_setValue('enabledSites', JSON.stringify(sites));

                // Se non esistono filtri per questo sito, crea un default
                if (!siteFilters[currentHost]) {
                    siteFilters[currentHost] = [`^https://${currentHost}/.*`];
                    GM_setValue('siteFilters', JSON.stringify(siteFilters));
                }

                alert('Script abilitato su: ' + currentHost);
            }
        }
    );

    // Se non abilitato, esci
    if (!enabledSites.includes(currentHost)) return;

    // GUI principale
    const panel = document.createElement('div');
    Object.assign(panel.style, {
        position: 'fixed', top: '50px', right: '10px',
        width: '360px', maxHeight: '300px', overflowY: 'auto', overflowX: 'hidden',
        backgroundColor: 'rgba(0,0,0,0.85)', color: '#fff',
        border: '1px solid #444', borderRadius: '4px',
        boxShadow: '0 2px 8px rgba(0,0,0,0.6)', zIndex: '999999',
        fontFamily: 'Arial, sans-serif', fontSize: '14px', lineHeight: '1.4',
        transition: 'max-height 0.3s ease, opacity 0.3s ease', opacity: '1'
    });

    // Ottieni i filtri del sito corrente
    const currentSiteFilters = siteFilters[currentHost] || [`^https://${currentHost}/.*`];

    panel.innerHTML = `
        <div style="padding:12px;">
            <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:8px;">
                <strong>Universal Link Extractor</strong>
                <button id="extractBtn" style="background:#28a745; border:none; color:#fff; padding:4px 8px; border-radius:3px; cursor:pointer;">Estrai link</button>
            </div>
            <div style="font-weight:bold; margin-bottom:8px;">Come usare:</div>
            <ul style="padding-left:20px; margin:0 0 8px 0;">
                <li>Clicca "Estrai link" per copiare quelli che matchano i filtri.</li>
                <li>Configura filtri di <strong>inclusione</strong> specifici per ${currentHost}.</li>
            </ul>
            <div style="font-weight:bold; margin-bottom:4px;">Filtri attivi per ${currentHost}:</div>
            <pre style="background:#f4f4f4; color:#000; padding:10px; border-radius:4px; font-family:monospace; font-size:13px; max-height:80px; overflow-y:auto;">
${currentSiteFilters.join('\n')}
            </pre>
            <div style="font-size:12px; color:#ccc; margin-top:8px;">Apri/chiudi con la freccia blu in alto a destra.</div>
        </div>
    `;
    document.body.appendChild(panel);

    // Listener Estrai
    document.getElementById('extractBtn').addEventListener('click', extractLinks);

    // Toggle sempre visibile
    const toggle = document.createElement('div');
    Object.assign(toggle.style, {
        position: 'fixed', top: '10px', right: '10px',
        width: '32px', height: '32px', cursor: 'pointer',
        backgroundColor: '#007bff', color: '#fff', display: 'flex',
        alignItems: 'center', justifyContent: 'center',
        borderRadius: '4px', fontSize: '18px', fontWeight: 'bold',
        boxShadow: '0 2px 4px rgba(0,0,0,0.5)', zIndex: '1000000',
        userSelect: 'none', transition: 'opacity 0.3s ease', opacity: '1'
    });
    toggle.textContent = '▼';
    document.body.appendChild(toggle);

    let expanded = true;
    toggle.addEventListener('click', () => {
        expanded = !expanded;
        if (expanded) {
            panel.style.maxHeight = '300px'; panel.style.opacity = '1'; toggle.textContent = '▼'; toggle.style.opacity = '1';
        } else {
            panel.style.maxHeight = '0'; panel.style.opacity = '0'; toggle.textContent = '▲'; toggle.style.opacity = '0';
        }
    });

    // Menu comando per configurare i filtri specifici per il sito
    GM_registerMenuCommand(`Configura filtri di inclusione per ${currentHost}`, () => {
        const defaultVal = currentSiteFilters.join(',');
        const inp = prompt(`Regex da includere per ${currentHost} (separa con virgola):`, defaultVal);

        if (inp !== null) {
            const newFilters = inp.split(',').map(s => s.trim()).filter(s => s);

            // Aggiorna i filtri specifici per questo sito
            siteFilters[currentHost] = newFilters;
            GM_setValue('siteFilters', JSON.stringify(siteFilters));

            alert(`Filtri di inclusione aggiornati per ${currentHost}`);
            // Refresh per aggiornare l'interfaccia
            location.reload();
        }
    });

    // Estrai link basandosi solo sui filtri del sito corrente
    function matchesAny(link, patterns) {
        return patterns.some(pat => {
            try {
                return new RegExp(pat).test(link);
            } catch {
                return false;
            }
        });
    }

    function extractLinks() {
        const currentFilters = siteFilters[currentHost] || [`^https://${currentHost}/.*`];

        const links = Array.from(document.querySelectorAll('a[href]'))
            .map(a => a.href)
            .filter(l => matchesAny(l, currentFilters));

        if (!links.length) return alert('Nessun link trovato');

        const count = links.length;
        navigator.clipboard.writeText(links.join('\n')).then(() => {
            console.log('Link estratti:', links);
            alert(`Ho copiato ${count} link negli appunti`);
        });
    }
})();