Upload files to "/"

This commit is contained in:
Arma-Damna-Dillo 2024-12-29 16:49:41 -06:00
parent 6e14ef7465
commit e61e7ef89d
5 changed files with 1523 additions and 0 deletions

42
index.html Normal file
View file

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ElectricGames</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="app">
<div id="sidebar">
<button class="sidebar-button" id="downloadsTab">Downloads</button>
<button class="sidebar-button" id="libraryTab">Library</button>
</div>
<main>
<h1>ElectricGames</h1>
<!-- Downloads Section -->
<div id="downloadsSection" class="section active">
<div class="browser-navigation">
<button id="backButton">Back</button>
<button id="forwardButton">Forward</button>
</div>
<webview id="gameBrowser" src="https://steamunlocked.net"></webview>
</div>
<!-- Library Section -->
<div id="librarySection" class="section">
<h2>Library</h2>
<button id="selectLibraryFolder">Select Library Folder</button>
<div id="gameList"></div>
<h3>Wine Setup</h3>
<button id="selectWineButton">Select Wine Binary</button>
<button id="runGameButton">Run Game with Wine</button>
<p id="wineStatus"></p>
</div>
</main>
</div>
<script src="renderer.js"></script>
</body>
</html>

182
main.js Normal file
View file

@ -0,0 +1,182 @@
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);
}
});
});
}

1114
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

21
package.json Normal file
View file

@ -0,0 +1,21 @@
{
"name": "electricgames",
"version": "1.0.0",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"electron": "^33.2.1"
},
"dependencies": {
"adm-zip": "^0.5.16",
"axios": "^1.7.9",
"fs-extra": "^11.2.0",
"unzipper": "^0.12.3"
}
}

164
renderer.js Normal file
View file

@ -0,0 +1,164 @@
const { ipcRenderer } = require('electron');
const path = require('path');
// Declare variables for selected Wine binary and game executable
let winePath = null;
let selectedGameExe = null;
// Tab switching logic
document.getElementById('downloadsTab').addEventListener('click', () => {
switchTab('downloads');
});
document.getElementById('libraryTab').addEventListener('click', () => {
switchTab('library');
});
function switchTab(tabName) {
const tabs = document.querySelectorAll('.sidebar-button');
const sections = document.querySelectorAll('.section');
// Reset all tabs and sections
tabs.forEach(tab => tab.classList.remove('active'));
sections.forEach(section => section.classList.remove('active'));
// Activate the selected tab and section
if (tabName === 'downloads') {
document.getElementById('downloadsTab').classList.add('active');
document.getElementById('downloadsSection').classList.add('active');
} else if (tabName === 'library') {
document.getElementById('libraryTab').classList.add('active');
document.getElementById('librarySection').classList.add('active');
loadLibrary(); // Load the library when switching to this tab
}
}
// Default to Downloads tab active
switchTab('downloads');
// Back and Forward buttons for webview navigation
const gameBrowser = document.getElementById('gameBrowser');
document.getElementById('backButton').addEventListener('click', () => {
gameBrowser.goBack();
});
document.getElementById('forwardButton').addEventListener('click', () => {
gameBrowser.goForward();
});
// Listen for a "download" request from the webview
gameBrowser.addEventListener('did-start-navigation', (event) => {
const downloadUrl = event.url;
if (downloadUrl && downloadUrl.endsWith('.zip')) {
// Trigger download automatically when a .zip file is detected
handleDownload(downloadUrl);
}
});
async function handleDownload(downloadUrl) {
try {
// Prompt the user to choose a library folder
const libraryFolder = await ipcRenderer.invoke('select-library-folder');
if (!libraryFolder) return;
const fileName = path.basename(downloadUrl); // Use the URL to get the file name
// Download and extract the ZIP file
const result = await ipcRenderer.invoke('download-and-extract', downloadUrl, libraryFolder, fileName);
if (result.success) {
console.log('Game downloaded and extracted successfully!');
} else {
console.error('Error downloading or extracting the game:', result.error);
}
} catch (error) {
console.error('Error handling download:', error);
}
}
// Load the Library content (list of .exe files)
async function loadLibrary() {
const libraryFolder = await ipcRenderer.invoke('select-library-folder');
if (libraryFolder) {
const gameList = await ipcRenderer.invoke('scan-library', libraryFolder);
// Show the list of executables in the library
const gameListDiv = document.getElementById('gameList');
gameListDiv.innerHTML = ''; // Clear previous content
if (gameList.length === 0) {
gameListDiv.innerHTML = 'No games found in the library.';
} else {
gameList.forEach(game => {
const gameItem = document.createElement('div');
gameItem.className = 'game-item';
gameItem.textContent = game; // Show the game path or name
gameListDiv.appendChild(gameItem);
});
}
}
}
// Select Wine binary
document.getElementById('selectWineButton').addEventListener('click', async () => {
winePath = await ipcRenderer.invoke('select-wine-binary');
if (winePath) {
document.getElementById('wineStatus').textContent = `Wine Binary Selected: ${winePath}`;
} else {
document.getElementById('wineStatus').textContent = 'No Wine Binary Selected';
}
});
// Select Library Folder and list `.exe` files
document.getElementById('selectLibraryFolder').addEventListener('click', async () => {
const result = await ipcRenderer.invoke('select-library-folder');
if (result && result.libraryFolderPath) {
document.getElementById('wineStatus').textContent = `Library Folder Selected: ${result.libraryFolderPath}`;
displayGameList(result.exeFiles);
} else {
document.getElementById('wineStatus').textContent = 'No Library Folder Selected';
}
});
// Display the list of `.exe` files
function displayGameList(gameList) {
const gameListContainer = document.getElementById('gameList');
gameListContainer.innerHTML = ''; // Clear the existing list
if (gameList.length === 0) {
gameListContainer.innerHTML = 'No games found in the selected library.';
return;
}
gameList.forEach((gameExe) => {
const gameButton = document.createElement('button');
gameButton.textContent = path.basename(gameExe);
gameButton.addEventListener('click', () => {
selectedGameExe = gameExe;
document.getElementById('wineStatus').textContent = `Selected Game: ${path.basename(gameExe)}`;
});
gameListContainer.appendChild(gameButton);
});
}
// Run game using Wine
document.getElementById('runGameButton').addEventListener('click', async () => {
if (!winePath) {
document.getElementById('wineStatus').textContent = 'Please select a Wine binary first.';
return;
}
if (!selectedGameExe) {
document.getElementById('wineStatus').textContent = 'Please select a game to run.';
return;
}
// Run the game via Wine
const result = await ipcRenderer.invoke('run-game-with-wine', selectedGameExe);
if (result.success) {
document.getElementById('wineStatus').textContent = 'Game is running!';
} else {
document.getElementById('wineStatus').textContent = `Error: ${result.message}`;
}
});