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.

À partir de 2024-07-22. Voir la dernière version.

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

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce 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            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");
            }
        });
    }
})();