250 lines
6.9 KiB
JavaScript
250 lines
6.9 KiB
JavaScript
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();
|
|
}
|
|
}); |