# Phase 4 Part 3: Parallel Processing Integration & Performance Benchmarking **Start Date:** October 2, 2025 **Estimated Time:** 9-12 hours (6-8 hours Part A + 3-4 hours Part B) **Status:** Planning → Implementation --- ## Overview Complete the parallel processing system by: 1. **Part A**: Integrating DownloadManager with UI (Tasks 15-17) 2. **Part B**: Benchmarking and optimizing the system (Task 25) --- ## Part A: Parallel Processing Integration (6-8 hours) ### Task 1: Connect DownloadManager to app.js (2 hours) **Goal**: Replace sequential download logic with parallel DownloadManager **Files to Modify:** - `scripts/app.js` - handleDownloadVideos() method **Implementation Steps:** 1. **Import and Initialize DownloadManager** ```javascript // At top of app.js this.downloadManager = null; // Will be set via IPC // In init() if (window.electronAPI) { // DownloadManager is in main process, access via IPC } ``` 2. **Update handleDownloadVideos() Method** ```javascript async handleDownloadVideos() { const videos = this.getDownloadableVideos(); if (videos.length === 0) return; // Use download manager instead of sequential loop for (const video of videos) { try { // Add to download queue via IPC await window.electronAPI.queueDownload({ videoId: video.id, url: video.url, quality: video.quality, format: video.format, savePath: this.state.config.savePath, cookieFile: this.state.config.cookieFile, priority: video.priority || 0 }); // Update UI to show queued status this.state.updateVideo(video.id, { status: 'queued' }); } catch (error) { console.error(`Failed to queue video ${video.id}:`, error); } } } ``` 3. **Set Up Download Event Listeners** ```javascript setupDownloadEventListeners() { // Listen for download started window.electronAPI.onDownloadStarted?.((data) => { this.state.updateVideo(data.videoId, { status: 'downloading', progress: 0 }); }); // Listen for download progress (already exists) window.IPCManager.onDownloadProgress('app', (progressData) => { this.handleDownloadProgress(progressData); }); // Listen for download completed window.electronAPI.onDownloadCompleted?.((data) => { this.state.updateVideo(data.videoId, { status: 'completed', progress: 100, filename: data.filename }); this.showDownloadNotification(data.video, 'success'); }); // Listen for download failed window.electronAPI.onDownloadFailed?.((data) => { this.state.updateVideo(data.videoId, { status: 'error', error: data.error }); this.showDownloadNotification(data.video, 'error', data.error); }); } ``` --- ### Task 2: Add IPC Methods for Download Queue Management (1 hour) **Files to Modify:** - `src/preload.js` - Add new IPC methods - `src/main.js` - Add download manager IPC handlers **preload.js Additions:** ```javascript // Queue management queueDownload: (options) => ipcRenderer.invoke('queue-download', options), cancelDownload: (videoId) => ipcRenderer.invoke('cancel-download', videoId), pauseDownload: (videoId) => ipcRenderer.invoke('pause-download', videoId), resumeDownload: (videoId) => ipcRenderer.invoke('resume-download', videoId), getQueueStatus: () => ipcRenderer.invoke('get-queue-status'), // Event listeners onDownloadStarted: (callback) => { ipcRenderer.on('download-started', (event, data) => callback(data)); return () => ipcRenderer.removeListener('download-started', callback); }, onDownloadCompleted: (callback) => { ipcRenderer.on('download-completed', (event, data) => callback(data)); return () => ipcRenderer.removeListener('download-completed', callback); }, onDownloadFailed: (callback) => { ipcRenderer.on('download-failed', (event, data) => callback(data)); return () => ipcRenderer.removeListener('download-failed', callback); } ``` **main.js Additions:** ```javascript // Queue download handler ipcMain.handle('queue-download', async (event, options) => { try { const downloadId = await downloadManager.addDownload(options); return { success: true, downloadId }; } catch (error) { console.error('Error queuing download:', error); return { success: false, error: error.message }; } }); // Pause download handler ipcMain.handle('pause-download', async (event, videoId) => { try { const paused = downloadManager.pauseDownload(videoId); return { success: paused }; } catch (error) { return { success: false, error: error.message }; } }); // Resume download handler ipcMain.handle('resume-download', async (event, videoId) => { try { const resumed = downloadManager.resumeDownload(videoId); return { success: resumed }; } catch (error) { return { success: false, error: error.message }; } }); // Get queue status handler ipcMain.handle('get-queue-status', async (event) => { try { const status = downloadManager.getQueueStatus(); return { success: true, status }; } catch (error) { return { success: false, error: error.message }; } }); // Set up download manager events downloadManager.on('downloadStarted', (data) => { mainWindow?.webContents.send('download-started', data); }); downloadManager.on('downloadCompleted', (data) => { mainWindow?.webContents.send('download-completed', data); performanceMonitor.recordDownload(data); }); downloadManager.on('downloadFailed', (data) => { mainWindow?.webContents.send('download-failed', data); }); ``` --- ### Task 3: Update Queue Status Panel Integration (1 hour) **Files to Modify:** - `scripts/app.js` - updateQueuePanel() method **Enhanced updateQueuePanel():** ```javascript async updateQueuePanel() { if (!window.electronAPI || !window.electronAPI.getDownloadStats) return; try { // Get download manager stats const result = await window.electronAPI.getDownloadStats(); if (result && result.success && result.stats) { const stats = result.stats; // Update counts document.getElementById('activeCount').textContent = stats.active || 0; document.getElementById('queuedCount').textContent = stats.queued || 0; // Update max concurrent from settings const maxConcurrent = this.state.config.maxConcurrent || stats.maxConcurrent || 4; document.getElementById('maxConcurrentDisplay').textContent = maxConcurrent; } // Get queue status for detailed info const queueResult = await window.electronAPI.getQueueStatus?.(); if (queueResult && queueResult.success) { this.updateActiveDownloadsList(queueResult.status); } } catch (error) { console.error('Failed to update queue panel:', error); } } updateActiveDownloadsList(queueStatus) { // Update individual video progress bars queueStatus.active?.forEach(download => { const video = this.state.getVideo(download.videoId); if (video) { this.state.updateVideo(video.id, { status: 'downloading', progress: download.progress, downloadSpeed: download.speed, eta: download.eta }); } }); } ``` --- ### Task 4: Add Download Speed Indicators (1.5 hours) **Files to Modify:** - `scripts/app.js` - getStatusText() and updateVideoElement() - `index.html` - Update video item template **Update Video Status Display:** ```javascript getStatusText(video) { switch (video.status) { case 'downloading': const speed = video.downloadSpeed ? ` (${this.formatSpeed(video.downloadSpeed)})` : ''; const eta = video.eta ? ` - ${this.formatETA(video.eta)}` : ''; return `Downloading ${video.progress || 0}%${speed}${eta}`; case 'queued': return 'Queued'; case 'converting': return `Converting ${video.progress || 0}%`; case 'completed': return 'Completed'; case 'error': return 'Error'; case 'ready': default: return 'Ready'; } } formatSpeed(bytesPerSecond) { if (bytesPerSecond < 1024) return `${bytesPerSecond} B/s`; if (bytesPerSecond < 1024 * 1024) return `${(bytesPerSecond / 1024).toFixed(1)} KB/s`; return `${(bytesPerSecond / 1024 / 1024).toFixed(1)} MB/s`; } formatETA(seconds) { if (seconds < 60) return `${Math.round(seconds)}s`; if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${Math.round(seconds % 60)}s`; return `${Math.floor(seconds / 3600)}h ${Math.floor((seconds % 3600) / 60)}m`; } ``` --- ### Task 5: Add Queue Management Controls (1.5 hours) **Files to Modify:** - `scripts/app.js` - Add pause/resume/cancel handlers - Update video item template with control buttons **Add Control Buttons to Video Items:** ```javascript // In createVideoElement(), add control buttons const controlsHTML = video.status === 'downloading' || video.status === 'queued' ? `