CivitAi Utilities

A script that adds new tools to the civitai image generator

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

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

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

// ==UserScript==
// @name         CivitAi Utilities
// @namespace    http://tampermonkey.net/
// @version      0.11
// @description  A script that adds new tools to the civitai image generator
// @author       Pedro6159
// @match        https://civitai.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=civitai.com
// @run-at document-end
// @license      MIT
// @grant       GM_setValue
// @grant       GM_getValue
// @grant       GM_xmlhttpRequest
// ==/UserScript==

(function () {
    'use strict';
    // Editable variables for users
    var delay = 500 // Milliseconds to wait for the script to start injecting into the website.
    var enable_infolabels = true; // Creates labels that show positive and negative prompt size
    var enable_taglist = true; // Enable tag list box
    var tag_list_url = "https://drive.google.com/uc?id=1uR_hEn_6BQz3gP4gO0nhVfF9TY97JSNP"; // You must have a raw tag list url

    // code

    // Url
    var u = window.document.URL;
    var datalist = undefined;
    var datalist_bkp = undefined;


    function getElementByXpath(path) {
        return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
    }
    // Ele filtra a string para retornar apenas a palavra, remove sintaxes do stable diffusion como "()", "[]", "{}", e os pesos ":x.x"
    String.prototype.sdfilter = function () {
        return this.toString().replace(/[()\[\]{}'"]|\W[:\d+(\.\d+)?]/g, "").trim().toLowerCase();
    };
    function addlabels(element) {
        // Prompt Label Length
        let _pll = document.createElement("span");
        _pll.id = "promptlength"; _pll.innerText = "Prompt Length : 0/1024";
        // Prompt Label Negativo
        let _negpll = document.createElement("span");
        _negpll.id = "negpromptlength"; _negpll.innerText = "Neg Prompt Length : 0/1024";
        // Adiciona os dois na ordem
        element.append(_pll);
        element.insertBefore(_pll, element.childNodes[0]);
        element.append(_negpll);
        element.insertBefore(_negpll, element.childNodes[1]);
    }
    function initialize_gui(gui) {
        const promptarea = getElementByXpath("(//textarea[contains(@class,'input')])[1]")
        const negpromptarea = getElementByXpath("(//textarea[contains(@class,'input')])[2]")
        promptarea.addEventListener('input', () => {
            updatelabel()
        });
        negpromptarea.addEventListener('input', () => {
            updatelabel()
        });
        if (enable_infolabels)
            addlabels(gui.childNodes[0]);
        if (enable_taglist)
            initialize_autocomplete(gui.childNodes[0]);
        console.log("Loaded UI");
    }

    // INICIA A CONSTRUÇÃO DO AUTO COMPLETE
    function initialize_autocomplete(element) {
        let infodiv = document.createElement("div");
        infodiv.id = "infodiv";
        element.append(infodiv);
        element.insertBefore(infodiv, element.childNodes[2]);
        // Infodiv pega o elemento criado pelo script com mesmo ID, então suporta ambas interfaces
        // Começa a adicionar o div na interface
        let ac_div = document.createElement("div");
        ac_div.style = "border: 3px solid rgb(52 52 52); overflow: auto;min-height:100px;height:250px;resize: vertical;";
        ac_div.id = "infoautocomplete";
        ac_div.beforeunload = function () { alert("deletado") };
        infodiv.append(ac_div);
        var order_type = 1;
        var btn_order = document.createElement("span");
        btn_order.style = "font-weight: bold; display: inline-block;border:thin solid;margin: 0 1px;padding:5px;cursor:pointer;"
        btn_order.innerText = "Sort (Normal)";
        btn_order.onclick = () => {
            if (order_type == 1) { // Mudar para ordem alfabetica (A-Z)
                datalist.sort();
                btn_order.innerText = "Sort (A-Z)";
                btn_order.style.color = "#8f9cff";
                order_type = 2;
            }
            else if (order_type == 2) {
                datalist.reverse();
                btn_order.innerText = "Sort (Z-A)";
                btn_order.style.color = "#90ff8f";
                order_type = 3;
            }
            else if (order_type == 3) {
                shuffle(datalist);
                btn_order.innerText = "Sort (Random)";
                btn_order.style.color = "rgb(255 55 219)";
                order_type = 4;
            }
            else if (order_type == 4) {
                datalist = Array.from(datalist_bkp);
                btn_order.innerText = "Sort (Normal)";
                btn_order.style.color = "White";
                order_type = 1;
            }
            autocompletelist.innerHTML = "";
            let results = getResults(selectedword[1].sdfilter());
            showtags(results);
        };
        ac_div.append(btn_order);
        var order_type_2 = 1;
        var btn_order2 = document.createElement("span");
        btn_order2.style = "font-weight: bold; display: inline-block;border:thin solid;margin: 0 1px;padding:5px;cursor:pointer;"
        btn_order2.innerText = "View (Inline)";
        btn_order2.onclick = () => {
            if (order_type_2 == 1) { // Mudar para ordem alfabetica (A-Z)
                btn_order2.innerText = "View (Vertical)";
                btn_order2.style.color = "#8f9cff";
                autocompletelist.style.display = "grid";
                order_type_2 = 2;
            }
            else if (order_type_2 == 2) {
                datalist.reverse();
                btn_order2.innerText = "View (Inline)";
                btn_order2.style.color = "White";
                autocompletelist.style.display = "inline";
                order_type_2 = 1;
            }
        };
        ac_div.append(btn_order2);
        ac_div.append(document.createElement("br"));

        if (datalist == undefined) {
            // Label dizendo que esta carregando a lista
            var labelloading = document.createElement("p");
            labelloading.id = "loadlabel";
            labelloading.style = "font-size:24px;font-weight: bold;color:Cyan"
            labelloading.innerText = "Loading TagList...";
            ac_div.append(labelloading);
        }
        // Elemento de lista de resultados
        var autocompletelist = document.createElement("ul");
        autocompletelist.style = "display:inline;padding-left: 0px;";
        autocompletelist.id = "results";
        ac_div.append(autocompletelist);



        if (datalist == undefined) {
            GM_xmlhttpRequest({
                method: "GET",
                // Url da lista de TAgs
                url: tag_list_url,
                onload: (ev) => {
                    // Foi carregado e atualiza o label
                    datalist = ev.responseText.match(/[^\r\n]+/g);
                    var versioninfo = datalist[0];
                    if (!versioninfo.startsWith("("))
                        versioninfo = "Customized";
                    labelloading.innerText = "Tag list loaded.\r\nCurrent version : " + versioninfo;
                    console.log("AutoComplete Tags Loaded | " + versioninfo);
                    labelloading.style.color = "#66FF99";
                    labelloading.style.cursor = "pointer";
                    datalist.shift();
                    datalist_bkp = Array.from(datalist);
                    // Avisar que foi carregado e fazer animação do label desaparecer lentamente
                    var o = 0;
                    var fade = setInterval(function () {
                        if (o < 100) {
                            labelloading.style.opacity = ((100 - o) + "%"); o = o + 0.11;
                        }
                        else {
                            clearInterval(fade); labelloading.remove();
                        }
                    }, 1);
                    labelloading.onclick = function () {
                        labelloading.remove();
                        clearInterval(fade);
                    }
                },
                onerror: () => {
                    console.error("List not loaded, invalid url.");
                }
            });
        }

        var promptarea = getElementByXpath("(//textarea[contains(@class,'input')])[1]");
        // Pega a caixa de texto do prompt dependendo da interface
        var selectedword;
        promptarea.oninput = function () {
            // Esse limpa tudo.
            autocompletelist.innerHTML = "";
            // Começa a progurar por tags
            selectedword = getWord(promptarea);
            let results = getResults(selectedword[1].sdfilter());
            showtags(results);
        };
        function showtags(results) {
            if (results.length > 0) {
                // Ele exibe a lista de tags em relação aos caractere que tu escreveu
                let i = 0;
                for (i; i < results.length; i++) {
                    const tags = document.createElement("li");
                    tags.style = "display: inline-block;padding: 0.5rem;border-color:white;border:solid;border-width:thin";
                    tags.className = "tags";
                    if (results[i][1] == 1) {
                        tags.style["background-color"] = "#302D00";
                        tags.innerText = results[i][0];
                        autocompletelist.append(tags);
                        autocompletelist.insertBefore(tags, autocompletelist.childNodes[0]);
                    }
                    else {
                        tags.innerText = results[i][0];
                        autocompletelist.append(tags);
                    }

                }
                // Caso chegue até o final, não vai adicionar o botão de "Mostrar Mais"
                if (i > 40) {
                    autocompletelist.innerHTML += "<li id='showmore' style='display: inline-block;padding: 0.5rem;border-color:white;border:solid;border-width:thin;background-color:darkblue'>Show More</li>";
                    // Função de mostrar mais
                    document.getElementById("showmore").onclick = () => {
                        // O texto da ultima tag
                        const lasttagarea = autocompletelist.childNodes[autocompletelist.childNodes.length - 2].innerText;
                        // Começa a procurar mais tags
                        let results = getResults(selectedword[1].sdfilter(), lasttagarea);
                        // Remove o "Show More"
                        autocompletelist.childNodes[autocompletelist.childNodes.length - 1].remove();
                        showtags(results);
                    };
                }
            }
        }
        // Obtem o array a partir da palavra que você escreveu para auto completar, que tem relação a lista de tags
        function getResults(input, last) {
            input = input.replace(/[_+-]+/g, " ");
            const results = [];
            let i = 0;
            // Caso você tiver clicado em "Mostrar Mais", ele pega a ultima tag da lista e continua a procurar por mais
            if (last) {
                i = searchStringInArray(last, datalist) + 1
            }

            // Pega palavras proximas
            const l = datalist.length;
            for (i; i < l; i++) {
                if (input === datalist[i].slice(0, input.length)) {
                    if (input == datalist[i])
                        results.push([datalist[i], 1]); // 1 a palavra é igual a tag
                    else
                        results.push([datalist[i], 0]); // 0 sugestoes de tag

                    if (results.length > 40)
                        break;
                }

            }
            return results;
        }
        // Quando você clicar em umas das tags para completar a palavra
        autocompletelist.onclick = function (event) {
            // Identificador tags, para não pensar que é aquele botão de 'mostrar mais'
            if (event.target.className != "tags")
                return;
            const setValue = event.target.innerText;
            // Separa o prompt em virgulas e remove espaços vazios
            let valuetext = promptarea.value.split(",").map(function (word) {
                return word.trim();
            });
            // Começa a procurar a palavra no array separado em virgula e depois substituir
            for (let i = 0; i < valuetext.length; i++) {
                if (valuetext[i].trim() == selectedword[1]) {
                    // Preserva os parenteses e a sintaxe de peso
                    const word = valuetext[i].sdfilter();
                    valuetext[i] = valuetext[i].replace(word, setValue);
                }
            }
            promptarea.value = valuetext.join(", ");
            this.innerHTML = "";
        };
    }

    // Procura a string no array retornando apenas o index
    function searchStringInArray(str, strArray) {
        const l = strArray.length;
        for (var j = 0; j < l; j++) {
            if (strArray[j].match(str)) return j;
        }
        return -1;
    };
    function getWord(textarea) {
        var cursorPos = textarea.selectionStart;
        var text = textarea.value;

        // Encontrar a palavra na posição do cursor
        var start = text.lastIndexOf(',', cursorPos - 1) + 1;
        var end = text.indexOf(',', cursorPos);
        end = end === -1 ? text.length : end;

        // Extrair a palavra
        var selectedWord = text.substring(start, end).trim();

        // Separar as palavras por vírgula
        var wordsArray = text.split(',').map(function (word) {
            return word.trim();
        });
        var selectedIndex = wordsArray.indexOf(selectedWord);
        //console.log("Posição do cursor:", cursorPos);
        //console.log("Palavra selecionada:", selectedWord);
        //console.log("Array de palavras:", wordsArray);
        return [selectedIndex, selectedWord.trim(), wordsArray];
    };
    // Aleatorizar Array
    function shuffle(array) {
        let currentIndex = array.length, randomIndex;

        // While there remain elements to shuffle.
        while (currentIndex > 0) {

            // Pick a remaining element.
            randomIndex = Math.floor(Math.random() * currentIndex);
            currentIndex--;

            // And swap it with the current element.
            [array[currentIndex], array[randomIndex]] = [
                array[randomIndex], array[currentIndex]];
        }

        return array;
    };
    // Atualiza as informações do tamanho do prompt positivo e negativo
    function updatelabel() {
        document.getElementById("promptlength").innerText = "Prompt Length : " + getElementByXpath("(//textarea[contains(@class,'input')])[1]").value.length;
        document.getElementById("negpromptlength").innerText = "Neg Prompt Length : " + getElementByXpath("(//textarea[contains(@class,'input')])[2]").value.length;
    };
    window.onload = function () {
        if (document.readyState == 'complete') {
            var gui;
            console.log("Trying to find the interface to inject the script...");
            var tempo = setInterval(function () {
                if (!document.getElementById("infodiv")) {
                    gui = getElementByXpath("//form/div[1]/div[1]/div[not(@style)]/div[3]");
                    if (gui) {
                        initialize_gui(gui);
                    }
                }
            }, delay);
            window.onload = null;
        }
    };
})();