const { app, BrowserWindow, dialog, ipcMain } = require('electron'); const path = require('path'); const { scanDirectory, extractFileMetadata } = require('./utils/fileUtils'); const dotenv = require('dotenv'); // Load environment variables from .env file dotenv.config(); // Handle creating/removing shortcuts on Windows when installing/uninstalling. try { if (require('electron-squirrel-startup')) { app.quit(); } } catch (error) { // electron-squirrel-startup not available on non-Windows platforms console.log('electron-squirrel-startup not available (expected on non-Windows platforms)'); } let mainWindow; // Create the browser window. function createWindow() { mainWindow = new BrowserWindow({ width: 1200, height: 800, webPreferences: { nodeIntegration: true, contextIsolation: false, enableRemoteModule: true, }, }); // and load the index.html of the app. mainWindow.loadFile('index.html'); // Open the DevTools. // mainWindow.webContents.openDevTools(); } // IPC handler for selecting directory ipcMain.handle('select-directory', async () => { try { const result = await dialog.showOpenDialog({ properties: ['openDirectory'] }); if (result.canceled) { return { success: false, error: 'No directory selected' }; } return { success: true, directory: result.filePaths[0] }; } catch (error) { return { success: false, error: error.message }; } }); // IPC handler for scanning directory ipcMain.handle('scan-directory', async (event, directoryPath) => { try { if (!directoryPath) { return { success: false, error: 'No directory path provided' }; } const files = await scanDirectory(directoryPath); return { success: true, files: files }; } catch (error) { return { success: false, error: error.message }; } }); // Enhanced logging for debugging problematic files ipcMain.handle('log-file-info', async (event, filePath) => { try { const fs = require('fs'); const stats = fs.statSync(filePath); return { success: true, fileInfo: { path: filePath, size: stats.size, modified: stats.mtime, isFile: stats.isFile(), isDirectory: stats.isDirectory() } }; } catch (error) { return { success: false, error: error.message }; } }); // IPC handler for renaming file ipcMain.handle('rename-file', async (event, { oldPath, newName }) => { try { const fs = require('fs'); const newPath = path.join(path.dirname(oldPath), newName); // Check if file exists if (!fs.existsSync(oldPath)) { return { success: false, error: 'Original file does not exist' }; } // Check if new name is different if (oldPath === newPath) { return { success: true, message: 'File name unchanged' }; } // Rename the file fs.renameSync(oldPath, newPath); return { success: true, message: 'File renamed successfully' }; } catch (error) { return { success: false, error: error.message }; } }); // IPC handler for searching TVDB ipcMain.handle('search-tvdb', async (event, query) => { try { // Import required modules const axios = require('axios'); // Get API key from environment const apiKey = process.env.TVDB_API_KEY || process.env.API_KEY; if (!apiKey) { throw new Error('TVDB_API_KEY not found in environment variables'); } // For TVDB v4 API, we need to first get an authentication token // The token is valid for 1 month let token = null; // Try to get token from cache or login try { const loginResponse = await axios.post('https://api4.thetvdb.com/v4/login', { apikey: apiKey }, { headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' } }); token = loginResponse.data.data.token; } catch (loginError) { console.error('TVDB Login Error:', loginError.message); throw new Error('Failed to authenticate with TVDB API: ' + loginError.message); } // Make API request to TheTVDB v4 search endpoint const response = await axios.get('https://api4.thetvdb.com/v4/search', { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', 'Accept': 'application/json' }, params: { query: query } }); // Process the results - v4 API returns different structure const results = response.data.data.map(show => ({ id: show.id, seriesName: show.name, status: show.status?.name, firstAired: show.firstAired, overview: show.overview, image: show.image, slug: show.slug })); return { success: true, results: results }; } catch (error) { console.error('TVDB API Error:', error.message); console.error('Error status:', error.response?.status); console.error('Error data:', error.response?.data); // No more mock data - propagate the actual error return { success: false, error: 'Failed to fetch data from TVDB API: ' + error.message }; } }); // Test function to verify API connectivity ipcMain.handle('test-tvdb-api', async () => { try { // Test actual API connectivity const axios = require('axios'); const apiKey = process.env.TVDB_API_KEY || process.env.API_KEY; if (!apiKey) { return { success: false, error: 'TVDB_API_KEY not found in environment variables' }; } // Test login endpoint const loginResponse = await axios.post('https://api4.thetvdb.com/v4/login', { apikey: apiKey }, { headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' } }); if (loginResponse.data && loginResponse.data.data && loginResponse.data.data.token) { return { success: true, message: 'TVDB API test successful - Token obtained', timestamp: new Date().toISOString() }; } else { return { success: false, error: 'TVDB API test failed - No token received' }; } } catch (error) { return { success: false, error: 'TVDB API test failed: ' + error.message }; } }); // This method will be called when Electron has finished // initialization and is ready to create browser windows. app.whenReady().then(createWindow); // Quit when all windows are closed, except on macOS. There, it's common // for applications and their menu bar to stay active until the user quits // explicitly with Cmd + Q. app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); app.on('activate', () => { // On OS X it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } });