Dynamic Include Sites Script (Protocol-Independent)

Run on default & user-defined sites using wildcard patterns (ignores protocols), with full management features.

Versión del día 13/2/2025. Echa un vistazo a la versión más reciente.

Este script no debería instalarse directamente. Es una biblioteca que utilizan otros scripts mediante la meta-directiva de inclusión // @require https://update.greasyfork.org/scripts/526770/1536548/Dynamic%20Include%20Sites%20Script%20%28Protocol-Independent%29.js

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         Dynamic Include Sites Script (Protocol-Independent)
// @namespace    http://tampermonkey.net/
// @version      3.2
// @description  Run on default & user-defined sites using wildcard patterns (ignores protocols), with full management features.
// @author       blvdmd
// @match        *://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @grant        GM_download
// ==/UserScript==

(function () {
    'use strict';

    const STORAGE_KEY = "additionalSites"; // Key for storing additional site patterns

    function getDefaultList() {
        return [
            "https://*example.com*",
            "*example2*"
        ];
    }

    function normalizeUrl(url) {
        return url.replace(/^https?:\/\//, ''); // Remove "http://" or "https://"
    }

    // Load stored additional sites (default is an empty array)
    let additionalSites = GM_getValue(STORAGE_KEY, []);

    // Merge user-defined sites with default sites (protocols ignored)
    let mergedSites = [...new Set([...getDefaultList(), ...additionalSites])].map(normalizeUrl);

    // Add menu commands for user interaction
    GM_registerMenuCommand("➕ Add Current Site to Include List", addCurrentSiteMenu);
    GM_registerMenuCommand("📜 View Included Sites", viewIncludedSites);
    GM_registerMenuCommand("🗑️ Delete Specific Entries", deleteEntries);
    GM_registerMenuCommand("✏️ Edit an Entry", editEntry);
    GM_registerMenuCommand("🚨 Clear All Entries", clearAllEntries);
    GM_registerMenuCommand("📤 Export Site List as JSON", exportAdditionalSites);
    GM_registerMenuCommand("📥 Import Site List from JSON", importAdditionalSites);

    const currentHost = window.location.hostname;
    const currentPath = window.location.pathname;
    const currentFullPath = normalizeUrl(`${window.location.href}`);

    if (shouldRunOnCurrentSite()) {
        console.log(`✅ Running script on: ${currentFullPath}`);
        runScript();
    }

    function runScript() {
        console.log("🚀 Script is running...");
        alert("Included site");

        // Your main logic here
    }

    function shouldRunOnCurrentSite() {
        return mergedSites.some(pattern => wildcardToRegex(normalizeUrl(pattern)).test(currentFullPath));
    }

    function addCurrentSiteMenu() {
        const domainParts = currentHost.split('.');
        const baseDomain = domainParts.length > 2 ? domainParts.slice(-2).join('.') : domainParts.join('.');
        const secondLevelDomain = domainParts.length > 2 ? domainParts.slice(-2, -1)[0] : domainParts[0];

        const baseOptions = [
            { name: `Base Hostname (*.${baseDomain}*)`, pattern: `*.${baseDomain}*` },
            { name: `Base Domain (*.${secondLevelDomain}.*)`, pattern: `*.${secondLevelDomain}.*` },
            { name: `Host Contains (*${secondLevelDomain}*)`, pattern: `*${secondLevelDomain}*` },
            { name: `Exact Path (${currentHost}${currentPath})`, pattern: normalizeUrl(`${window.location.href}`) },
        ];

        const customOption = { name: "Custom Wildcard Pattern", pattern: normalizeUrl(`${window.location.href}`) };

        const options = [...baseOptions, customOption];

        const userChoice = prompt(
            "Select an option to add the site:\n" +
            options.map((opt, index) => `${index + 1}. ${opt.name}`).join("\n") +
            "\nEnter a number or cancel."
        );

        if (!userChoice) return;

        const selectedIndex = parseInt(userChoice, 10) - 1;
        if (selectedIndex >= 0 && selectedIndex < options.length) {
            let pattern = normalizeUrl(options[selectedIndex].pattern);

            if (options[selectedIndex].name === "Custom Wildcard Pattern") {
                pattern = normalizeUrl(prompt("Edit custom wildcard pattern:", pattern));
                if (!pattern.trim()) return alert("Invalid pattern. Operation canceled.");
            }

            if (!additionalSites.includes(pattern)) {
                additionalSites.push(pattern);
                GM_setValue(STORAGE_KEY, additionalSites);
                mergedSites = [...new Set([...getDefaultList(), ...additionalSites])].map(normalizeUrl);
                alert(`✅ Added site with pattern: ${pattern}`);
            } else {
                alert(`⚠️ Pattern "${pattern}" is already in the list.`);
            }
        }
    }

    function viewIncludedSites() {
        //alert(`🔍 Included Sites:\n${mergedSites.join("\n") || "No sites added yet."}`);
        alert(`🔍 Included Sites:\n${additionalSites.join("\n") || "No sites added yet."}`);
    }

    function deleteEntries() {
        if (additionalSites.length === 0) return alert("⚠️ No user-defined entries to delete.");

        const userChoice = prompt(
            "Select entries to delete (comma-separated numbers):\n" +
            additionalSites.map((item, index) => `${index + 1}. ${item}`).join("\n")
        );

        if (!userChoice) return;

        const indicesToRemove = userChoice.split(',').map(num => parseInt(num.trim(), 10) - 1);
        additionalSites = additionalSites.filter((_, index) => !indicesToRemove.includes(index));
        GM_setValue(STORAGE_KEY, additionalSites);
        mergedSites = [...new Set([...getDefaultList(), ...additionalSites])].map(normalizeUrl);
        alert("✅ Selected entries have been deleted.");
    }

    function editEntry() {
        if (additionalSites.length === 0) return alert("⚠️ No user-defined entries to edit.");

        const userChoice = prompt(
            "Select an entry to edit:\n" +
            additionalSites.map((item, index) => `${index + 1}. ${item}`).join("\n")
        );

        if (!userChoice) return;

        const selectedIndex = parseInt(userChoice, 10) - 1;
        if (selectedIndex < 0 || selectedIndex >= additionalSites.length) return alert("❌ Invalid selection.");

        const newPattern = normalizeUrl(prompt("Edit the pattern:", additionalSites[selectedIndex]));
        if (newPattern && newPattern.trim() && newPattern !== additionalSites[selectedIndex]) {
            additionalSites[selectedIndex] = newPattern.trim();
            GM_setValue(STORAGE_KEY, additionalSites);
            mergedSites = [...new Set([...getDefaultList(), ...additionalSites])].map(normalizeUrl);
            alert("✅ Entry updated.");
        }
    }

    function clearAllEntries() {
        if (additionalSites.length === 0) return alert("⚠️ No user-defined entries to clear.");

        if (confirm(`🚨 You have ${additionalSites.length} entries. Clear all?`)) {
            additionalSites = [];
            GM_setValue(STORAGE_KEY, additionalSites);
            mergedSites = [...getDefaultList()].map(normalizeUrl);
            alert("✅ All user-defined entries cleared.");
        }
    }

    function exportAdditionalSites() {
        GM_download("data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(additionalSites, null, 2)), "additionalSites_backup.json");
        alert("📤 Additional sites exported as JSON.");
    }

    function importAdditionalSites() {
        const input = document.createElement("input");
        input.type = "file";
        input.accept = ".json";
        input.onchange = event => {
            const reader = new FileReader();
            reader.onload = e => {
                additionalSites = JSON.parse(e.target.result);
                GM_setValue(STORAGE_KEY, additionalSites);
                mergedSites = [...new Set([...getDefaultList(), ...additionalSites])];
                alert("📥 Sites imported successfully.");
            };
            reader.readAsText(event.target.files[0]);
        };
        input.click();
    }

    function wildcardToRegex(pattern) {
        return new RegExp("^" + pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*').replace(/\?/g, '.') + "$");
    }
})();