| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- /**
- * @fileoverview IPC Methods Patch for GrabZilla App
- * @author GrabZilla Development Team
- * @version 2.1.0
- * @since 2024-01-01
- */
- /**
- * This file contains the enhanced IPC methods that should replace
- * the placeholder implementations in the main app.js file.
- *
- * To apply these patches:
- * 1. Replace the placeholder methods in app.js with these implementations
- * 2. Add the missing utility methods to the GrabZilla class
- * 3. Include the IPC integration module
- */
- // Enhanced handleSelectSavePath method
- const handleSelectSavePath = async function() {
- 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 handleSelectCookieFile method
- const handleSelectCookieFile = async function() {
- 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 handleDownloadVideos method
- const handleDownloadVideos = async function() {
- 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();
- 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();
- }
- // 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 fetchVideoMetadata method
- const fetchVideoMetadata = async function(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();
- }
- };
- // Utility methods to add to the GrabZilla class
- const updateSavePathUI = function(directoryPath) {
- const savePath = document.getElementById('savePath');
- if (savePath) {
- savePath.textContent = directoryPath;
- savePath.title = directoryPath;
- }
- };
- const updateCookieFileUI = function(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');
- }
- };
- const updateBinaryStatus = function(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';
- }
- };
- const handleDownloadProgress = function(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 manual integration
- if (typeof module !== 'undefined' && module.exports) {
- module.exports = {
- handleSelectSavePath,
- handleSelectCookieFile,
- handleDownloadVideos,
- fetchVideoMetadata,
- updateSavePathUI,
- updateCookieFileUI,
- updateBinaryStatus,
- handleDownloadProgress
- };
- }
- // Instructions for manual integration:
- console.log(`
- IPC Methods Patch Ready!
- To integrate these methods into your GrabZilla app:
- 1. Replace the placeholder methods in app.js:
- - handleSelectSavePath()
- - handleSelectCookieFile()
- - handleDownloadVideos()
- - fetchVideoMetadata()
- 2. Add the utility methods to the GrabZilla class:
- - updateSavePathUI()
- - updateCookieFileUI()
- - updateBinaryStatus()
- - handleDownloadProgress()
- 3. Include the IPC integration module in your HTML:
- <script src="scripts/utils/ipc-integration.js"></script>
- 4. The Electron IPC infrastructure is already set up in:
- - src/main.js (IPC handlers)
- - src/preload.js (secure API exposure)
- All methods include proper error handling, user feedback, and security validation.
- `);
|