Civitai Tool

一键下载模型、图例、模型说明(附触发词)

当前为 2024-01-24 提交的版本,查看 最新版本

// ==UserScript==
// @name         Civitai Tool
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  一键下载模型、图例、模型说明(附触发词)
// @author       宇泽同学
// @match        https://civitai.com/*
// @grant        GM_download
// @license MIT
// ==/UserScript==

(function () {
'use strict';

var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = `
.custom-button {
    background: radial-gradient(circle, #00BFFF,#005ec9); /* 渐变色 */
    color: #F0FFF0;
    width: 95px;
    height: 35px;
    padding: 5px 15px;
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 14px;
    cursor: pointer;
    border: none;
    margin-left: 10px;
    margin-top: 10px;
    border-radius: 7px;
}
.image-count-selector {
    width: 75px; /* 边框宽度 */
    height: 35px;
    padding: 5px;
    border: 1px solid #23caff; /* 输入框描边色 */
    border-radius: 7px;
    margin-left: 10px;
    display: inline-block;
}
`;
document.head.appendChild(style);

// 获取当前页面的URL中的模型ID
function getModelIdFromUrl() {
    const urlRegex = /https:\/\/civitai.com\/models\/(\d+)(?:\/|$|\?modelVersionId=\d+)/;
    const match = window.location.href.match(urlRegex);
    return match ? match[1] : null;
}

// 从API获取模型文件名的函数
function fetchModelFileName(modelId, modelVersionId) {
    let apiUrl = `https://civitai.com/api/v1/models/${modelId}`;
    if (modelVersionId) {
        apiUrl += `?modelVersionId=${modelVersionId}`;
    }

    return fetch(apiUrl)
        .then(response => response.json())
        .then(data => {
            if (modelVersionId) {
                const modelVersion = data.modelVersions.find(version => version.id.toString() === modelVersionId);
                return modelVersion ? modelVersion.files.find(file => file.primary).name : null;
            } else {
                const publishedVersion = data.modelVersions.find(version => version.status === 'Published');
                return publishedVersion ? publishedVersion.files.find(file => file.primary).name : null;
            }
        })
        .catch(error => {
            console.error('Error fetching model file name:', error);
            return null;
        });
}

// 下载图例
function downloadImages(modelFileName) {
    const numberOfImages = document.getElementById('imageCountInput').value;
    const thumbnailElements = document.querySelectorAll('.mantine-7aj0so');
    for (let i = 0; i < Math.min(numberOfImages, thumbnailElements.length); i++) {
        const thumbnailSrc = thumbnailElements[i].src;
        const highResSrc = thumbnailSrc.replace('/width=450/', '/original=true/');
        const filename = `${modelFileName.split('.')[0]}.png`;
        GM_download(highResSrc, filename);
    }
}

// 下载说明
function downloadDescription(modelFileName) {
    const triggerWordElements = document.querySelectorAll('.mantine-Group-root.mantine-i72d0e');
    let triggerWords = [];
    const descriptionElement = document.querySelector('.mantine-150s3z1');
    const modelName = descriptionElement ? descriptionElement.querySelector('strong') ? descriptionElement.querySelector('strong').textContent : '模型名称未知' : '模型名称未知';
    const currentUrl = window.location.href;

    if (triggerWordElements.length > 0) {
        triggerWordElements.forEach(element => {
            const word = element.textContent.trim();
            if (word) {
                triggerWords.push(word);
            }
        });
        const triggerWordsText = triggerWords.length > 0 ? triggerWords.join(', ') : '未发现';
        const combinedText = `触发词: ${triggerWordsText}\n\n${descriptionElement ? descriptionElement.innerText : ''}\n\n本模型地址:${currentUrl}\n\n`;
        const blob = new Blob([combinedText], { type: 'text/plain' });
        const link = document.createElement('a');
        link.href = window.URL.createObjectURL(blob);
        link.download = `${modelFileName.split('.')[0]}.txt`;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    } else {
        const combinedText = `本模型地址:${currentUrl}\n\n`;
        const blob = new Blob([combinedText], { type: 'text/plain' });
        const link = document.createElement('a');
        link.href = window.URL.createObjectURL(blob);
        link.download = `${modelFileName.split('.')[0]}.txt`;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    }
}

// 模拟原生下载按钮点击
function simulateNativeButtonClick() {
    const nativeDownloadButton = document.querySelector('.mantine-UnstyledButton-root.mantine-Button-root.mantine-4fe1an');
    nativeDownloadButton && nativeDownloadButton.click();
}

// 下载全部内容
function downloadAll(modelFileName, modelId) {
    downloadDescription(modelFileName);
    downloadImages(modelFileName);
    setTimeout(() => {
        simulateNativeButtonClick();
    }, 1000);
}

// 创建下载按钮
function createButton(text, onClick) {
    const button = document.createElement('button');
    button.textContent = text;
    button.className = 'custom-button';
    button.addEventListener('click', onClick);
    return button;
}

// 创建数字输入框
function createNumberInput() {
    const input = document.createElement('input');
    input.className = 'image-count-selector';
    input.id = 'imageCountInput';
    input.type = 'number';
    input.value = '1';
    input.min = '1';
    return input;
}

// 主函数
function main() {
    const modelId = getModelIdFromUrl();
    const urlParams = new URLSearchParams(window.location.search);
    const modelVersionId = urlParams.get('modelVersionId');
    if (modelId) {
        fetchModelFileName(modelId, modelVersionId).then(modelFileName => {
            if (modelFileName) {
                const imageCountInput = createNumberInput();
                const downloadImagesButton = createButton('下载图例', () => downloadImages(modelFileName));
                const downloadDescriptionButton = createButton('下载说明', () => downloadDescription(modelFileName));
                const downloadAllButton = createButton('我全都要', () => downloadAll(modelFileName, modelId));

                const buttonContainer = document.createElement('div');
                buttonContainer.className = 'custom-button-container';
                buttonContainer.appendChild(downloadImagesButton);
                buttonContainer.appendChild(imageCountInput);
                buttonContainer.appendChild(downloadDescriptionButton);
                buttonContainer.appendChild(downloadAllButton);

                const targetElement = document.querySelector('.mantine-UnstyledButton-root.mantine-Accordion-control.mantine-17tws88');
                if (targetElement && !targetElement.parentNode.querySelector('.custom-button-container')) {
                    targetElement.parentNode.insertBefore(buttonContainer, targetElement);
                } else {
                    console.error('未找到目标元素,无法插入按钮容器。');
                }
            }
        });
    }
}

function checkAndInsertButtons() {
    setTimeout(() => {
        main();
        checkAndInsertButtons();
    }, 1000);
}

window.addEventListener('load', checkAndInsertButtons);

 // 监听网址变化
    function checkUrlChange() {
        const currentUrl = window.location.href;
        if (currentUrl !== sessionStorage.getItem('previousUrl')) {
            sessionStorage.setItem('previousUrl', currentUrl);
            window.location.reload();
        }
    }

    window.addEventListener('load', main);
    setInterval(checkUrlChange, 800);

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址