Spaces:
Sleeping
Sleeping
| // SHINYY WORKSPACE - Shared Data System | |
| // Connects Face Swapper, Compressor, and Workflow Hub | |
| class ShinyyWorkspace { | |
| constructor() { | |
| this.storageKey = 'shinyy_workspace'; | |
| this.data = this.loadData(); | |
| this.listeners = []; | |
| } | |
| // Load data from localStorage | |
| loadData() { | |
| try { | |
| const stored = localStorage.getItem(this.storageKey); | |
| return stored ? JSON.parse(stored) : this.getDefaultData(); | |
| } catch (e) { | |
| console.warn('Failed to load workspace data:', e); | |
| return this.getDefaultData(); | |
| } | |
| } | |
| // Get default data structure | |
| getDefaultData() { | |
| return { | |
| faceSwapResults: [], | |
| compressedFiles: [], | |
| workflowFiles: [], | |
| activeWorkflow: null, | |
| recentProjects: [], | |
| settings: { | |
| autoTransfer: true, | |
| preserveQuality: true, | |
| defaultCompression: 0.8 | |
| } | |
| }; | |
| } | |
| // Save data to localStorage | |
| saveData() { | |
| try { | |
| localStorage.setItem(this.storageKey, JSON.stringify(this.data)); | |
| this.notifyListeners(); | |
| } catch (e) { | |
| console.error('Failed to save workspace data:', e); | |
| } | |
| } | |
| // Add face swap results | |
| addFaceSwapResults(results) { | |
| console.log('addFaceSwapResults called with:', results); | |
| if (!Array.isArray(results)) results = [results]; | |
| const processedResults = results.map(result => ({ | |
| id: result.id || this.generateId(), | |
| type: 'face_swap', | |
| timestamp: result.timestamp || Date.now(), | |
| originalSize: result.originalSize || 0, | |
| resultImage: result.resultImage || result.image, | |
| preview: result.preview || result.resultImage, | |
| fileName: result.fileName || `face_swap_${Date.now()}.jpg`, | |
| transferredTo: result.transferredTo || [], | |
| metadata: { | |
| sourceImages: result.sourceImages || [], | |
| targetImages: result.targetImages || [], | |
| processingTime: result.processingTime || 0, | |
| model: result.model || 'default' | |
| } | |
| })); | |
| console.log('Processed results:', processedResults); | |
| this.data.faceSwapResults.push(...processedResults); | |
| console.log('Total face swap results after adding:', this.data.faceSwapResults.length); | |
| this.data.recentProjects.unshift({ | |
| type: 'face_swap', | |
| timestamp: Date.now(), | |
| count: processedResults.length, | |
| preview: processedResults[0].preview | |
| }); | |
| this.saveData(); | |
| console.log('Data saved to localStorage'); | |
| return processedResults; | |
| } | |
| // Add compressed files | |
| addCompressedFiles(files) { | |
| if (!Array.isArray(files)) files = [files]; | |
| const processedFiles = files.map(file => ({ | |
| id: this.generateId(), | |
| type: 'compressed', | |
| timestamp: Date.now(), | |
| originalFile: file.originalFile || file.name, | |
| compressedUrl: file.compressedUrl || file.url, | |
| compressedSize: file.compressedSize || file.size, | |
| originalSize: file.originalSize || 0, | |
| fileName: file.fileName || file.name, | |
| format: file.format || 'jpeg', | |
| quality: file.quality || 0.8, | |
| metadata: { | |
| compressionRatio: file.compressionRatio || 0, | |
| processingTime: file.processingTime || 0, | |
| adjustments: file.adjustments || {} | |
| } | |
| })); | |
| this.data.compressedFiles.push(...processedFiles); | |
| this.data.recentProjects.unshift({ | |
| type: 'compression', | |
| timestamp: Date.now(), | |
| count: processedFiles.length, | |
| preview: processedFiles[0].compressedUrl | |
| }); | |
| this.saveData(); | |
| return processedFiles; | |
| } | |
| // Get files for transfer between tools | |
| getFilesForTransfer(fromTool, toTool) { | |
| switch(fromTool) { | |
| case 'face_swapper': | |
| return this.data.faceSwapResults.filter(result => !result.transferredTo?.includes(toTool)); | |
| case 'compressor': | |
| return this.data.compressedFiles.filter(file => !file.transferredTo?.includes(toTool)); | |
| default: | |
| return []; | |
| } | |
| } | |
| // Transfer files between tools | |
| transferFiles(fileIds, fromTool, toTool) { | |
| fileIds.forEach(id => { | |
| let file; | |
| if (fromTool === 'face_swapper') { | |
| file = this.data.faceSwapResults.find(f => f.id === id); | |
| } else if (fromTool === 'compressor') { | |
| file = this.data.compressedFiles.find(f => f.id === id); | |
| } | |
| if (file) { | |
| if (!file.transferredTo) file.transferredTo = []; | |
| file.transferredTo.push(toTool); | |
| // Add to workflow files for the target tool | |
| this.data.workflowFiles.push({ | |
| ...file, | |
| transferredFrom: fromTool, | |
| transferredTo: toTool, | |
| transferTimestamp: Date.now() | |
| }); | |
| } | |
| }); | |
| this.saveData(); | |
| } | |
| // Get workflow files for specific tool | |
| getWorkflowFiles(tool) { | |
| return this.data.workflowFiles.filter(file => file.transferredTo === tool); | |
| } | |
| // Set active workflow | |
| setActiveWorkflow(workflow) { | |
| this.data.activeWorkflow = { | |
| ...workflow, | |
| timestamp: Date.now() | |
| }; | |
| this.saveData(); | |
| } | |
| // Get active workflow | |
| getActiveWorkflow() { | |
| return this.data.activeWorkflow; | |
| } | |
| // Clear old data (cleanup) | |
| clearOldData(daysOld = 7) { | |
| const cutoffTime = Date.now() - (daysOld * 24 * 60 * 60 * 1000); | |
| this.data.faceSwapResults = this.data.faceSwapResults.filter(item => item.timestamp > cutoffTime); | |
| this.data.compressedFiles = this.data.compressedFiles.filter(item => item.timestamp > cutoffTime); | |
| this.data.workflowFiles = this.data.workflowFiles.filter(item => item.transferTimestamp > cutoffTime); | |
| this.data.recentProjects = this.data.recentProjects.filter(item => item.timestamp > cutoffTime); | |
| this.saveData(); | |
| } | |
| // Export data | |
| exportData() { | |
| return JSON.stringify(this.data, null, 2); | |
| } | |
| // Import data | |
| importData(jsonData) { | |
| try { | |
| const imported = JSON.parse(jsonData); | |
| this.data = { ...this.data, ...imported }; | |
| this.saveData(); | |
| return true; | |
| } catch (e) { | |
| console.error('Failed to import data:', e); | |
| return false; | |
| } | |
| } | |
| // Utility functions | |
| generateId() { | |
| return Math.random().toString(36).substr(2, 9) + Date.now().toString(36); | |
| } | |
| formatFileSize(bytes) { | |
| if (bytes === 0) return '0 B'; | |
| const k = 1024; | |
| const sizes = ['B', 'KB', 'MB', 'GB']; | |
| const i = Math.floor(Math.log(bytes) / Math.log(k)); | |
| return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; | |
| } | |
| // Event listeners | |
| addListener(callback) { | |
| this.listeners.push(callback); | |
| } | |
| removeListener(callback) { | |
| this.listeners = this.listeners.filter(l => l !== callback); | |
| } | |
| notifyListeners() { | |
| this.listeners.forEach(callback => callback(this.data)); | |
| } | |
| // Statistics | |
| getStats() { | |
| return { | |
| totalFaceSwaps: this.data.faceSwapResults.length, | |
| totalCompressions: this.data.compressedFiles.length, | |
| totalTransfers: this.data.workflowFiles.length, | |
| recentProjects: this.data.recentProjects.length, | |
| storageUsed: JSON.stringify(this.data).length | |
| }; | |
| } | |
| } | |
| // Global workspace instance | |
| window.shinyyWorkspace = new ShinyyWorkspace(); | |
| // Auto-cleanup old data on load | |
| setTimeout(() => { | |
| window.shinyyWorkspace.clearOldData(); | |
| }, 5000); | |
| // Export for module systems | |
| if (typeof module !== 'undefined' && module.exports) { | |
| module.exports = ShinyyWorkspace; | |
| } | |