const { app, BrowserWindow, ipcMain, dialog } = require('electron'); const fs = require('fs'); const path = require('path'); const AdmZip = require('adm-zip'); // For ZIP extraction const { promisify } = require('util'); const readdir = promisify(fs.readdir); const stat = promisify(fs.stat); const { exec } = require('child_process'); let mainWindow; function createWindow() { mainWindow = new BrowserWindow({ width: 1000, height: 800, webPreferences: { nodeIntegration: true, contextIsolation: false, webviewTag: true, // Make sure webview is enabled } }); mainWindow.loadFile('index.html'); } app.whenReady().then(() => { createWindow(); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); // Function to download and extract ZIP files ipcMain.handle('download-and-extract', async (event, downloadUrl, libraryFolder, fileName) => { try { const downloadPath = path.join(libraryFolder, fileName); // Start downloading the game from the URL const response = await fetch(downloadUrl); if (!response.ok) throw new Error('Download failed'); const buffer = await response.arrayBuffer(); const fileBuffer = Buffer.from(buffer); // Write the downloaded zip file to disk fs.writeFileSync(downloadPath, fileBuffer); // Now extract the downloaded ZIP await extractZip(downloadPath, libraryFolder); // Return the path to the extracted folder return { success: true, folderPath: libraryFolder }; } catch (error) { console.error('Error during download or extraction:', error); return { success: false, error: error.message }; } }); // Function to extract ZIP files async function extractZip(zipPath, extractToFolder) { try { const zip = new AdmZip(zipPath); zip.extractAllTo(extractToFolder, true); console.log(`Extracted ZIP to ${extractToFolder}`); // Clean up the ZIP file after extraction fs.unlinkSync(zipPath); // Delete the ZIP file } catch (error) { console.error('Error extracting ZIP:', error); throw new Error('Error extracting ZIP'); } } // Scan for .exe files in the Library folder (excluding `redist` folders) ipcMain.handle('scan-library', async (event, libraryFolder) => { try { const gameExecutables = await scanForExecutables(libraryFolder); return gameExecutables; } catch (error) { console.error('Error scanning library:', error); return []; } }); async function scanForExecutables(directory) { console.log(directory.exeFiles) return directory.exeFiles; } module.exports = { scanForExecutables }; // Handle the Wine binary selection ipcMain.handle('select-wine-binary', async () => { const result = await dialog.showOpenDialog({ properties: ['openFile'], filters: [{ name: 'Executables', extensions: ['exe'] }], }); if (result.canceled || result.filePaths.length === 0) { return null; } winePath = result.filePaths[0]; // Store the path to the Wine binary return winePath; }); // Handle the selection of a Library folder and get list of `.exe` files ipcMain.handle('select-library-folder', async () => { const result = await dialog.showOpenDialog({ properties: ['openDirectory'], }); if (result.canceled || result.filePaths.length === 0) { return null; } const libraryFolderPath = result.filePaths[0]; const exeFiles = await scanDirectory(libraryFolderPath); // Scan the folder for .exe files return { libraryFolderPath, exeFiles }; }); // Recursive function to scan a directory for `.exe` files async function scanDirectory(dirPath) { const exeFiles = []; const files = await fs.promises.readdir(dirPath, { withFileTypes: true }); for (const file of files) { const fullPath = path.join(dirPath, file.name); if (file.isDirectory()) { // Recursively scan subdirectories const subDirFiles = await scanDirectory(fullPath); exeFiles.push(...subDirFiles); } else if (file.isFile() && file.name.toLowerCase().endsWith('.exe')) { // Add `.exe` files to the list exeFiles.push(fullPath); } } return exeFiles; } // Handle running the game via Wine ipcMain.handle('run-game-with-wine', async (event, gameExePath) => { if (!winePath) { return { success: false, message: 'Wine binary not selected' }; } try { await runWineCommand(winePath, gameExePath); return { success: true }; } catch (error) { return { success: false, message: error.message }; } }); // Helper function to execute Wine command function runWineCommand(wineBinary, gameExePath) { return new Promise((resolve, reject) => { const command = `"${wineBinary}" "${gameExePath}"`; exec(command, (error, stdout, stderr) => { if (error) { reject(new Error(`Error running Wine command: ${stderr || stdout}`)); } else { resolve(stdout); } }); }); }