| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- /**
- * @fileoverview Enhanced IPC methods for GrabZilla app
- * @author GrabZilla Development Team
- * @version 2.1.0
- * @since 2024-01-01
- */
- /**
- * Enhanced IPC methods to replace placeholder implementations in app.js
- * These methods provide full Electron IPC integration for desktop functionality
- */
- /**
- * Enhanced cookie file selection with IPC integration
- * Replaces the placeholder handleSelectCookieFile method
- */
- async function handleSelectCookieFile() {
- if (!window.electronAPI) {
- this.showStatus('File selection not available in browser mode', 'error');
- return;
- }
- try {
- this.showStatus('Opening file dialog...', 'info');
-
- const cookieFilePath = await window.electronAPI.selectCookieFile();
-
- if (cookieFilePath) {
- // Update configuration with selected cookie file
- this.state.updateConfig({ cookieFile: cookieFilePath });
-
- // Update UI to show selected file
- this.updateCookieFileUI(cookieFilePath);
-
- this.showStatus('Cookie file selected successfully', 'success');
- console.log('Cookie file selected:', cookieFilePath);
- } else {
- this.showStatus('Cookie file selection cancelled', 'info');
- }
-
- } catch (error) {
- console.error('Error selecting cookie file:', error);
- this.showStatus('Failed to select cookie file', 'error');
- }
- }
- /**
- * Enhanced save directory selection with IPC integration
- */
- async function handleSelectSaveDirectory() {
- if (!window.electronAPI) {
- this.showStatus('Directory selection not available in browser mode', 'error');
- return;
- }
- try {
- this.showStatus('Opening directory dialog...', 'info');
-
- const directoryPath = await window.electronAPI.selectSaveDirectory();
-
- if (directoryPath) {
- // Update configuration with selected directory
- this.state.updateConfig({ savePath: directoryPath });
-
- // Update UI to show selected directory
- this.updateSavePathUI(directoryPath);
-
- this.showStatus('Save directory selected successfully', 'success');
- console.log('Save directory selected:', directoryPath);
- } else {
- this.showStatus('Directory selection cancelled', 'info');
- }
-
- } catch (error) {
- console.error('Error selecting save directory:', error);
- this.showStatus('Failed to select save directory', 'error');
- }
- }
- /**
- * Enhanced video download with full IPC integration
- * Replaces the placeholder handleDownloadVideos method
- */
- async function handleDownloadVideos() {
- const readyVideos = this.state.getVideosByStatus('ready');
-
- if (readyVideos.length === 0) {
- this.showStatus('No videos ready for download', 'info');
- return;
- }
- if (!window.electronAPI) {
- this.showStatus('Video download not available in browser mode', 'error');
- return;
- }
- // Check if save path is configured
- if (!this.state.config.savePath) {
- this.showStatus('Please select a save directory first', 'error');
- return;
- }
- try {
- // Set downloading state
- this.state.updateUI({ isDownloading: true });
- this.updateControlPanelState();
- // Set up progress listener for this download session
- const progressListenerId = 'download-session-' + Date.now();
- window.IPCManager.onDownloadProgress(progressListenerId, (progressData) => {
- this.handleDownloadProgress(progressData);
- });
- this.showStatus(`Starting download of ${readyVideos.length} video(s)...`, 'info');
- // Download videos sequentially to avoid overwhelming the system
- for (const video of readyVideos) {
- try {
- // Update video status to downloading
- this.state.updateVideo(video.id, {
- status: 'downloading',
- progress: 0
- });
- this.renderVideoList();
- // Prepare download options
- const downloadOptions = {
- url: video.url,
- quality: video.quality,
- format: video.format,
- savePath: this.state.config.savePath,
- cookieFile: this.state.config.cookieFile
- };
- // Start download
- const result = await window.electronAPI.downloadVideo(downloadOptions);
- if (result.success) {
- // Update video status to completed
- this.state.updateVideo(video.id, {
- status: 'completed',
- progress: 100,
- filename: result.filename || 'Downloaded'
- });
-
- console.log(`Successfully downloaded: ${video.title}`);
- } else {
- throw new Error(result.error || 'Download failed');
- }
- } catch (error) {
- console.error(`Failed to download video ${video.id}:`, error);
-
- // Update video status to error
- this.state.updateVideo(video.id, {
- status: 'error',
- error: error.message,
- progress: 0
- });
- }
- // Update UI after each video
- this.renderVideoList();
- }
- // Clean up progress listener
- window.IPCManager.removeDownloadProgressListener(progressListenerId);
- // Update final state
- this.state.updateUI({ isDownloading: false });
- this.updateControlPanelState();
- const completedCount = this.state.getVideosByStatus('completed').length;
- const errorCount = this.state.getVideosByStatus('error').length;
-
- if (errorCount === 0) {
- this.showStatus(`Successfully downloaded ${completedCount} video(s)`, 'success');
- } else {
- this.showStatus(`Downloaded ${completedCount} video(s), ${errorCount} failed`, 'warning');
- }
- } catch (error) {
- console.error('Error in download process:', error);
- this.showStatus(`Download process failed: ${error.message}`, 'error');
-
- // Reset state on error
- this.state.updateUI({ isDownloading: false });
- this.updateControlPanelState();
- }
- }
- /**
- * Enhanced metadata fetching with IPC integration
- * Replaces the placeholder fetchVideoMetadata method
- */
- async function fetchVideoMetadata(videoId, url) {
- try {
- // Update video status to indicate metadata loading
- this.state.updateVideo(videoId, {
- title: 'Loading metadata...',
- status: 'ready'
- });
- // Extract thumbnail immediately (this is fast)
- const thumbnail = await URLValidator.extractThumbnail(url);
- // Update video with thumbnail first
- if (thumbnail) {
- this.state.updateVideo(videoId, { thumbnail });
- this.renderVideoList();
- }
- // Fetch real metadata using Electron IPC if available
- let metadata;
- if (window.electronAPI) {
- try {
- metadata = await window.electronAPI.getVideoMetadata(url);
- } catch (error) {
- console.warn('Failed to fetch real metadata, using fallback:', error);
- metadata = await this.simulateMetadataFetch(url);
- }
- } else {
- // Fallback to simulation in browser mode
- metadata = await this.simulateMetadataFetch(url);
- }
- // Update video with fetched metadata
- if (metadata) {
- const updateData = {
- title: metadata.title || 'Unknown Title',
- duration: metadata.duration || '00:00',
- status: 'ready'
- };
- // Use fetched thumbnail if available, otherwise keep the one we extracted
- if (metadata.thumbnail) {
- updateData.thumbnail = metadata.thumbnail;
- }
- this.state.updateVideo(videoId, updateData);
- this.renderVideoList();
- console.log(`Metadata fetched for video ${videoId}:`, metadata);
- }
- } catch (error) {
- console.error(`Failed to fetch metadata for video ${videoId}:`, error);
-
- // Update video with error state but keep it downloadable
- this.state.updateVideo(videoId, {
- title: 'Metadata unavailable',
- status: 'ready',
- error: null // Clear any previous errors since this is just metadata
- });
-
- this.renderVideoList();
- }
- }
- /**
- * Enhanced binary checking with detailed status reporting
- * Replaces the placeholder checkBinaries method
- */
- async function checkBinaries() {
- if (!window.electronAPI) {
- console.warn('Electron API not available - running in browser mode');
- return;
- }
- try {
- console.log('Checking yt-dlp and ffmpeg binaries...');
- const binaryVersions = await window.electronAPI.checkBinaryVersions();
-
- // Update UI based on binary availability
- this.updateBinaryStatus(binaryVersions);
-
- if (binaryVersions.ytDlp.available && binaryVersions.ffmpeg.available) {
- console.log('All required binaries are available');
- console.log('yt-dlp version:', binaryVersions.ytDlp.version);
- console.log('ffmpeg version:', binaryVersions.ffmpeg.version);
- this.showStatus('All dependencies ready', 'success');
- } else {
- const missing = [];
- if (!binaryVersions.ytDlp.available) missing.push('yt-dlp');
- if (!binaryVersions.ffmpeg.available) missing.push('ffmpeg');
-
- console.warn('Missing binaries:', missing);
- this.showStatus(`Missing dependencies: ${missing.join(', ')}`, 'error');
- }
-
- } catch (error) {
- console.error('Error checking binaries:', error);
- this.showStatus('Failed to check dependencies', 'error');
- }
- }
- /**
- * Update cookie file UI to show selected file
- */
- function updateCookieFileUI(cookieFilePath) {
- const cookieFileBtn = document.getElementById('cookieFileBtn');
- if (cookieFileBtn) {
- // Update button text to show file is selected
- const fileName = cookieFilePath.split('/').pop() || cookieFilePath.split('\\').pop();
- cookieFileBtn.textContent = `Cookie File: ${fileName}`;
- cookieFileBtn.title = cookieFilePath;
- cookieFileBtn.classList.add('selected');
- }
- }
- /**
- * Update save path UI to show selected directory
- */
- function updateSavePathUI(directoryPath) {
- const savePath = document.getElementById('savePath');
- if (savePath) {
- savePath.textContent = directoryPath;
- savePath.title = directoryPath;
- }
- }
- /**
- * Update binary status UI based on version check results
- */
- function updateBinaryStatus(binaryVersions) {
- // Update UI elements to show binary status
- console.log('Binary status updated:', binaryVersions);
-
- // Store binary status in state for reference
- this.state.binaryStatus = binaryVersions;
-
- // Update dependency status indicators if they exist
- const ytDlpStatus = document.getElementById('ytdlp-status');
- if (ytDlpStatus) {
- ytDlpStatus.textContent = binaryVersions.ytDlp.available
- ? `yt-dlp ${binaryVersions.ytDlp.version}`
- : 'yt-dlp missing';
- ytDlpStatus.className = binaryVersions.ytDlp.available ? 'status-ok' : 'status-error';
- }
-
- const ffmpegStatus = document.getElementById('ffmpeg-status');
- if (ffmpegStatus) {
- ffmpegStatus.textContent = binaryVersions.ffmpeg.available
- ? `ffmpeg ${binaryVersions.ffmpeg.version}`
- : 'ffmpeg missing';
- ffmpegStatus.className = binaryVersions.ffmpeg.available ? 'status-ok' : 'status-error';
- }
- }
- /**
- * Handle download progress updates from IPC
- */
- function handleDownloadProgress(progressData) {
- const { url, progress } = progressData;
-
- // Find video by URL and update progress
- const video = this.state.videos.find(v => v.url === url);
- if (video) {
- this.state.updateVideo(video.id, { progress });
- this.renderVideoList();
- }
- }
- // Export methods for integration into main app
- if (typeof module !== 'undefined' && module.exports) {
- module.exports = {
- handleSelectCookieFile,
- handleSelectSaveDirectory,
- handleDownloadVideos,
- fetchVideoMetadata,
- checkBinaries,
- updateCookieFileUI,
- updateSavePathUI,
- updateBinaryStatus,
- handleDownloadProgress
- };
- } else if (typeof window !== 'undefined') {
- // Make methods available globally for integration
- window.EnhancedIPCMethods = {
- handleSelectCookieFile,
- handleSelectSaveDirectory,
- handleDownloadVideos,
- fetchVideoMetadata,
- checkBinaries,
- updateCookieFileUI,
- updateSavePathUI,
- updateBinaryStatus,
- handleDownloadProgress
- };
- }
|