import { modalManager } from './ModalManager.js'; import { showToast } from '../utils/uiHelpers.js'; import { LoadingManager } from './LoadingManager.js'; import { state } from '../state/index.js'; import { resetAndReload } from '../api/loraApi.js'; export class DownloadManager { constructor() { this.currentVersion = null; this.versions = []; this.modelInfo = null; this.modelVersionId = null; // Add new property for initial version ID // Add initialization check this.initialized = false; this.selectedFolder = ''; // Add LoadingManager instance this.loadingManager = new LoadingManager(); this.folderClickHandler = null; // Add this line this.updateTargetPath = this.updateTargetPath.bind(this); } showDownloadModal() { console.log('Showing download modal...'); // Add debug log if (!this.initialized) { // Check if modal exists const modal = document.getElementById('downloadModal'); if (!modal) { console.error('Download modal element not found'); return; } this.initialized = true; } modalManager.showModal('downloadModal', null, () => { // Cleanup handler when modal closes this.cleanupFolderBrowser(); }); this.resetSteps(); } resetSteps() { document.querySelectorAll('.download-step').forEach(step => step.style.display = 'none'); document.getElementById('urlStep').style.display = 'block'; document.getElementById('loraUrl').value = ''; document.getElementById('urlError').textContent = ''; // Clear new folder input const newFolderInput = document.getElementById('newFolder'); if (newFolderInput) { newFolderInput.value = ''; } this.currentVersion = null; this.versions = []; this.modelInfo = null; this.modelVersionId = null; // Clear selected folder and remove selection from UI this.selectedFolder = ''; const folderBrowser = document.getElementById('folderBrowser'); if (folderBrowser) { folderBrowser.querySelectorAll('.folder-item').forEach(f => f.classList.remove('selected')); } } async validateAndFetchVersions() { const url = document.getElementById('loraUrl').value.trim(); const errorElement = document.getElementById('urlError'); try { this.loadingManager.showSimpleLoading('Fetching model versions...'); const modelId = this.extractModelId(url); if (!modelId) { throw new Error('Invalid Civitai URL format'); } const response = await fetch(`/api/civitai/versions/${modelId}`); if (!response.ok) { throw new Error('Failed to fetch model versions'); } this.versions = await response.json(); if (!this.versions.length) { throw new Error('No versions available for this model'); } // If we have a version ID from URL, pre-select it if (this.modelVersionId) { this.currentVersion = this.versions.find(v => v.id.toString() === this.modelVersionId); } this.showVersionStep(); } catch (error) { errorElement.textContent = error.message; } finally { this.loadingManager.hide(); } } extractModelId(url) { const modelMatch = url.match(/civitai\.com\/models\/(\d+)/); const versionMatch = url.match(/modelVersionId=(\d+)/); if (modelMatch) { this.modelVersionId = versionMatch ? versionMatch[1] : null; return modelMatch[1]; } return null; } showVersionStep() { document.getElementById('urlStep').style.display = 'none'; document.getElementById('versionStep').style.display = 'block'; const versionList = document.getElementById('versionList'); versionList.innerHTML = this.versions.map(version => { const firstImage = version.images?.find(img => !img.url.endsWith('.mp4')); const thumbnailUrl = firstImage ? firstImage.url : '/loras_static/images/no-preview.png'; // Use version-level size or fallback to first file const fileSize = version.modelSizeKB ? (version.modelSizeKB / 1024).toFixed(2) : (version.files[0]?.sizeKB / 1024).toFixed(2); // Use version-level existsLocally flag const existsLocally = version.existsLocally; const localPath = version.localPath; // Check if this is an early access version const isEarlyAccess = version.availability === 'EarlyAccess'; // Create early access badge if needed let earlyAccessBadge = ''; if (isEarlyAccess) { earlyAccessBadge = `