Civitai Text Downloader Kai

Click the Download button to save the JSON and images. Also add a button to download JSON and images under details.

Versión del día 22/7/2024. Echa un vistazo a la versión más reciente.

// ==UserScript==
// @name            Civitai Text Downloader Kai
// @name:ja         Civitai Text Downloader Kai
// @namespace       http://tampermonkey.net/
// @version         5.3
// @description     Click the Download button to save the JSON and images.  Also add a button to download JSON and images under details.
// @description:ja  DownloadボタンをクリックするとJSONと画像が保存されます。また、Detailsの下にJSONと画像をダウンロードするボタンを追加します。
// @author          Takenoko3333
// @match           https://civitai.com/*
// @icon            https://civitai.com/favicon.ico
// @grant           none
// @license         BSD
// ==/UserScript==

(function() {
    'use strict';
    // initial access
    let file_id = null;
    let category = "";
    downloadFiles();

    // Processing at page transitions
    if (typeof MutationObserver !== 'undefined') {
        let lastUrl = location.href;
        const observer = new MutationObserver((mutations) => {
            if (lastUrl !== location.href) {
                lastUrl = location.href;
                const interval = setInterval(function() {
                    downloadFiles();
                    if (file_id || category != "models" ) {
                        clearInterval(interval);
                    }
                }, 200);
            }
        });
        const config = { subtree: true, childList: true };
        observer.observe(document, config);
    } else {
        // MutationObserver is not supported
        setInterval(function(){
            downloadFiles();
        }, 500);
    }

    function createButton() {
        const newElement = document.createElement('a');
        newElement.className = 'mantine-UnstyledButton-root mantine-Button-root mantine-4fe1an';
        newElement.type = 'button';
        newElement.setAttribute('data-button', 'true');
        newElement.style = 'margine-top: 8px;';

        const innerDiv = document.createElement('div');
        innerDiv.className = 'mantine-3xbgk5 mantine-Button-inner';

        const innerSpan = document.createElement('span');
        innerSpan.className = 'mantine-qo1k2 mantine-Button-label';
        innerSpan.textContent = 'JSON and Image Download';

        innerDiv.appendChild(innerSpan);
        newElement.appendChild(innerDiv);

        const tableElement = document.querySelector('table');
        let currentElement = tableElement;
        while (currentElement && !currentElement.classList.contains('mantine-Accordion-item')) {
            currentElement = currentElement.parentElement;
        }
        if (currentElement) {
            currentElement.insertAdjacentElement('afterend', newElement);
        }
    }

    function downloadFiles() {
        file_id = null
        category = location.pathname.split("/")[1];
        if (category != "models") return;

        const codeElements = document.querySelectorAll('table code');
        codeElements.forEach((element, index) => {
            if (element.textContent === '@') {
                if (codeElements[index + 1]) {
                    file_id = codeElements[index + 1].textContent;
                }
            }
        });

        if (file_id) createButton();

        document.querySelectorAll('main a[type^="button"]:not([href])').forEach(button => {
            if(!button.classList.contains("ctd-done")){
                button.addEventListener("click", function(){
                    const modelName = document.querySelector('main h1').textContent;
                    const spanElements = document.querySelectorAll('table span');
                    let strength = null;
                    let _id = location.pathname.split("/")[2];

                    spanElements.forEach((element, index) => {
                        if (/^Strength:/.test(element.textContent)) {
                            strength = element.textContent.split(":")[1].trim();
                        }
                    });

                    fetch("https://civitai.com/api/v1/models/" + _id).then(x => x.json()).then(j => {
                        let file = j.modelVersions.find(x => x.id == file_id);
                        let link = document.createElement('a');
                        let text = {
                            "description": "",
                            "model name": modelName,
                            "model url": document.URL,
                            "base model": file.baseModel,
                            "sd version": "Unknown",
                            "activation text": "",
                            "preferred weight": 0,
                            "notes": document.URL + "\nModel name: " + modelName + "\nBase model: " + file.baseModel
                        };

                        if (/^SD 1/.test(file.baseModel)) {
                            text["sd version"] = "SD1";
                        } else if (/^SD 2/.test(file.baseModel)) {
                            text["sd version"] = "SD2";
                        } else if (/^SDXL/.test(file.baseModel) || /^Pony/.test(file.baseModel)) {
                            text["sd version"] = "SDXL";
                        } else if (/^SD 3/.test(file.baseModel)) {
                            text["sd version"] = "SD3";
                        }

                        if(j.description && j.description.textContent){
                            text.description = j.description.textContent;
                        }
                        if(file.trainedWords){
                            text["activation text"] = file.trainedWords.join(" ");
                        }
                        if(strength){
                            text["preferred weight"] = strength;
                        }
                        text = [JSON.stringify(text)];
                        link.href = window.URL.createObjectURL(new Blob(text));
                        let filename = file.files.find(x => x).name || file_id + ".json";
                        filename = filename.replace(/\.[a-z]*$/, ".json")
                        link.download = filename;
                        link.click();

                        let image = file.images.find(x => x);
                        if(image){
                            let xhr = new XMLHttpRequest();
                            let src = image.url;
                            let suffix = "." + src.slice(src.lastIndexOf('.') + 1);
                            suffix = ".png"; // URLの拡張子がjpegになってても実際にimage.civitai.comが返す画像はpngっぽいのでハードコーディングで決め打ち
                            xhr.open('GET', src, true);
                            xhr.responseType = "blob";
                            xhr.onload = function () {
                                let dlLink = document.createElement("a");
                                const dataUrl = URL.createObjectURL(this.response);
                                dlLink.href = dataUrl;
                                filename = filename.replace(".json", suffix)
                                dlLink.download = filename;
                                document.body.insertAdjacentElement("beforeEnd", dlLink);
                                dlLink.click();
                                dlLink.remove();
                                setTimeout(function () {
                                    window.URL.revokeObjectURL(dataUrl);
                                }, 1000);
                            };
                            xhr.send();
                        }
                    });
                });
                button.style.color = "#ffff00";
                button.classList.add("ctd-done");
            }
        });
    }
})();