Dynamic Include Sites Script (Protocol-Independent)

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

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

Този скрипт не може да бъде инсталиран директно. Това е библиотека за други скриптове и може да бъде използвана с мета-директива // @require https://update.greasyfork.org/scripts/526770/1536548/Dynamic%20Include%20Sites%20Script%20%28Protocol-Independent%29.js

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

You will need to install an extension such as Tampermonkey to install this script.

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

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

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

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

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

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

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

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

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

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

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

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

// ==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, '.') + "$");
    }
})();