Dynamic Include Sites Script (Protocol-Independent)

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

À partir de 2025-02-13. Voir la dernière version.

Ce script ne devrait pas être installé directement. C'est une librairie créée pour d'autres scripts. Elle doit être inclus avec la commande // @require https://update.greasyfork.org/scripts/526770/1536548/Dynamic%20Include%20Sites%20Script%20%28Protocol-Independent%29.js

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

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

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

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