🏠 Home 

Civitai Tool

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


安装此脚本?
// ==UserScript==
// @name         Civitai Tool
// @namespace    http://tampermonkey.net/
// @version      1.3
// @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: #b3ffe7;
width: 100px;
height: 35px;
padding: 5px 15px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
cursor: pointer;
border: none;
margin-left: 5px;
border-radius: 7px;
}
.image-count-selector {
width: 85px; /* 边框宽度 */
height: 35px;
padding: 5px;
border: 1px solid #23caff; /* 输入框描边色 */
border-radius: 7px;
margin-left: 5px;
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, callback) {
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]}.preview.png`;
GM_download(highResSrc, filename);
}
// 图例下载完成后执行回调函数
if (typeof callback === 'function') {
callback();
}
}
// 下载说明
function downloadDescription(modelFileName, modelId) {
// 使用Model ID构造API URL
const apiUrl = `https://civitai.com/api/v1/models/${modelId}`;
fetch(apiUrl)
.then(response => response.json())
.then(data => {
if (data.description) {
let descriptionHtml = data.description; // API返回的HTML格式文本
// 将<p>和<br>标签替换为换行符,保留段落间的空行
descriptionHtml = descriptionHtml.replace(/<p>/gi, "");
descriptionHtml = descriptionHtml.replace(/<\/p>/gi, "\n\n");
descriptionHtml = descriptionHtml.replace(/<br\s*[\/]?>/gi, "\n");
// 创建一个DOM元素来解析HTML文本,并提取文本内容
const tempDiv = document.createElement('div');
tempDiv.innerHTML = descriptionHtml;
// 获取纯文本内容,去除所有HTML标签
let plainTextDescription = tempDiv.textContent || tempDiv.innerText || "";
// 确保纯文本中的连续换行被保留
plainTextDescription = plainTextDescription.replace(/\n\s*\n/g, "\n\n");
// 获取触发词
const triggerWordElements = document.querySelectorAll('.mantine-Group-root.mantine-i72d0e');
let triggerWords = [];
triggerWordElements.forEach(element => {
const word = element.textContent.trim();
if (word) {
triggerWords.push(word);
}
});
const triggerWordsText = triggerWords.length > 0 ? triggerWords.join(', ') : '未发现';
// 组合下载内容
const modelName = data.name || '模型名称未知';
const currentUrl = window.location.href;
const combinedText = `##触发词: ${triggerWordsText}\n\n${plainTextDescription.trim()}\n\n##本模型地址:${currentUrl}\n\n`;
// 触发下载
const blob = new Blob([combinedText], { type: 'text/plain;charset=utf-8' });
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 {
console.error('获取不到模型说明文本。');
}
}).catch(error => {
console.error('Error fetching model description:', error);
});
}
// 模拟原生下载按钮点击
function simulateNativeButtonClick() {
const nativeDownloadButton = document.querySelector('.mantine-UnstyledButton-root.mantine-Button-root.mantine-4fe1an');
nativeDownloadButton && nativeDownloadButton.click();
}
// 下载全部内容
function downloadAll(modelFileName, modelId) {
downloadImages(modelFileName, () => {
downloadDescription(modelFileName, modelId);
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, modelId)); // 更新这一行
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, 50);
})();