Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name CivitAI Gallery Downloader
- // @namespace http://tampermonkey.net/
- // @version 1.0
- // @description Download gallery images when downloading CivitAI model
- // @author You
- // @match https://civitai.com/models/*
- // @grant none
- // ==/UserScript==
- (function() {
- 'use strict';
- let downloadStopped = false;
- // Функция для скачивания файла
- async function downloadFile(url, filename) {
- try {
- const response = await fetch(url);
- if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
- const blob = await response.blob();
- const link = document.createElement('a');
- link.href = URL.createObjectURL(blob);
- link.download = filename;
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
- URL.revokeObjectURL(link.href);
- } catch (error) {
- console.error(`Error downloading ${filename}:`, error);
- }
- }
- // Функция для генерации случайного имени файла
- function generateRandomFilename() {
- const timestamp = Date.now();
- const random = Math.floor(Math.random() * 1000);
- return `${timestamp}_${random}.jpg`;
- }
- // Функция для получения текущих изображений из галереи
- function getCurrentGalleryImages() {
- const images = [];
- const galleryContainer = document.querySelector('div.overflow-hidden > div.-ml-3.flex');
- if (!galleryContainer) {
- return images;
- }
- const imageLinks = galleryContainer.querySelectorAll('a[href^="/images/"]');
- imageLinks.forEach((link) => {
- const img = link.querySelector('.EdgeImage_image__iH4_q');
- if (img && img.src && img.src.includes('image.civitai.com')) {
- const imageId = link.href.split('/images/')[1];
- const originalUrl = img.src.replace(/\/anim=false,width=\d+/, '');
- const filename = generateRandomFilename();
- images.push({
- url: originalUrl,
- filename: filename,
- imageId: imageId
- });
- }
- });
- return images;
- }
- // Функция для поиска кнопки "следующий"
- function findNextButton() {
- // Ищем кнопку по классу tabler-icon-chevron-right
- const chevronRight = document.querySelector('svg.tabler-icon-chevron-right');
- if (chevronRight) {
- const button = chevronRight.closest('button');
- if (button && !button.hasAttribute('data-disabled') && button.style.opacity !== '0.25') {
- return button;
- }
- }
- // Альтернативный поиск по структуре
- const buttons = document.querySelectorAll('button[class*="absolute"][class*="right-3"]');
- for (const button of buttons) {
- const svg = button.querySelector('svg.tabler-icon-chevron-right');
- if (svg && !button.hasAttribute('data-disabled') && button.style.opacity !== '0.25') {
- return button;
- }
- }
- return null;
- }
- // Функция для пролистывания галереи и сбора всех изображений
- async function collectAllGalleryImages() {
- const allImages = new Map(); // Используем Map для избежания дубликатов по imageId
- let attempts = 0;
- const maxAttempts = 100; // Максимальное количество попыток
- let noNewImagesCount = 0;
- showProgress('Сканирование галереи...', false);
- while (attempts < maxAttempts && noNewImagesCount < 5 && !downloadStopped) {
- const currentImages = getCurrentGalleryImages();
- let newImagesFound = false;
- // Добавляем новые изображения
- currentImages.forEach(image => {
- if (!allImages.has(image.imageId)) {
- allImages.set(image.imageId, image);
- newImagesFound = true;
- }
- });
- if (newImagesFound) {
- noNewImagesCount = 0;
- showProgress(`Найдено изображений: ${allImages.size}`, false);
- } else {
- noNewImagesCount++;
- }
- // Ищем кнопку "следующий"
- const nextButton = findNextButton();
- if (nextButton) {
- console.log(`Clicking next button, attempt ${attempts + 1}`);
- nextButton.click();
- await new Promise(resolve => setTimeout(resolve, 300)); // Ждем загрузки
- } else {
- console.log('Next button not found or disabled');
- break; // Больше нет кнопки "следующий"
- }
- attempts++;
- }
- console.log(`Collected ${allImages.size} unique images after ${attempts} attempts`);
- return Array.from(allImages.values());
- }
- // Функция для показа прогресса
- function showProgress(message, showStopButton = true) {
- let progressDiv = document.getElementById('civitai-gallery-progress');
- if (!progressDiv) {
- progressDiv = document.createElement('div');
- progressDiv.id = 'civitai-gallery-progress';
- progressDiv.style.cssText = `
- position: fixed;
- top: 80px;
- right: 20px;
- background: #333;
- color: white;
- padding: 15px;
- border-radius: 8px;
- z-index: 10000;
- font-family: Arial, sans-serif;
- font-size: 14px;
- max-width: 320px;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
- `;
- document.body.appendChild(progressDiv);
- }
- if (showStopButton) {
- progressDiv.innerHTML = `
- <div style="margin-bottom: 10px;">${message}</div>
- <button id="stop-download-btn" style="
- background: #dc3545;
- color: white;
- border: none;
- padding: 8px 16px;
- border-radius: 4px;
- cursor: pointer;
- font-size: 12px;
- width: 100%;
- ">Остановить скачивание</button>
- `;
- const stopBtn = document.getElementById('stop-download-btn');
- if (stopBtn) {
- stopBtn.addEventListener('click', () => {
- downloadStopped = true;
- showProgress('❌ Скачивание остановлено', false);
- hideProgress(2000);
- });
- }
- } else {
- progressDiv.innerHTML = `<div>${message}</div>`;
- }
- }
- // Функция для скрытия прогресса
- function hideProgress(delay = 3000) {
- setTimeout(() => {
- const progressDiv = document.getElementById('civitai-gallery-progress');
- if (progressDiv) {
- progressDiv.remove();
- }
- }, delay);
- }
- // Функция для скачивания галереи
- async function downloadGallery() {
- try {
- downloadStopped = false;
- // Сначала собираем все изображения, пролистывая галерею
- const allImages = await collectAllGalleryImages();
- if (downloadStopped) {
- return;
- }
- if (allImages.length === 0) {
- showProgress('Галерея модели не найдена', false);
- hideProgress(2000);
- return;
- }
- showProgress(`Скачивание ${allImages.length} изображений...`, true);
- // Скачиваем все собранные изображения
- for (let i = 0; i < allImages.length && !downloadStopped; i++) {
- const image = allImages[i];
- showProgress(`Скачивание ${i + 1}/${allImages.length}<br>Файл: ${image.filename}`, true);
- await downloadFile(image.url, image.filename);
- // Задержка между скачиваниями
- await new Promise(resolve => setTimeout(resolve, 600));
- }
- if (!downloadStopped) {
- showProgress('✓ Галерея модели скачана!', false);
- hideProgress();
- }
- } catch (error) {
- console.error('Error downloading gallery:', error);
- showProgress('Ошибка при скачивании галереи', false);
- hideProgress(5000);
- }
- }
- // Функция для перехвата кликов по кнопке скачивания
- function interceptDownloadButtons() {
- const selectors = [
- 'a[data-tour="model:download"]',
- 'a[href*="/api/download/models/"]'
- ];
- selectors.forEach(selector => {
- const buttons = document.querySelectorAll(selector);
- buttons.forEach(button => {
- if (!button.hasAttribute('data-gallery-intercepted')) {
- button.setAttribute('data-gallery-intercepted', 'true');
- button.addEventListener('click', () => {
- console.log('Download button clicked, starting gallery download...');
- // Запускаем скачивание галереи через небольшую задержку
- setTimeout(downloadGallery, 1500);
- });
- }
- });
- });
- }
- // Запускаем при загрузке страницы
- setTimeout(interceptDownloadButtons, 2000);
- // Наблюдаем за изменениями DOM
- const observer = new MutationObserver(() => {
- interceptDownloadButtons();
- });
- observer.observe(document.body, {
- childList: true,
- subtree: true
- });
- })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement