const { app, BrowserWindow, session, shell, desktopCapturer, autoUpdater, dialog, ipcMain, Notification } = require('electron'); const path = require('path'); const { setupAdBlocker } = require('./ad-blocker'); // Handle Squirrel events (Windows installer) try { if (require('electron-squirrel-startup')) app.quit(); } catch { // electron-squirrel-startup not installed, skip } const HUB_URL = process.env.GAMING_HUB_URL || 'https://hub.daddelolymp.de'; const APP_VERSION = app.getVersion(); // Sync IPC: preload reads app version from package.json ipcMain.on('get-app-version', (event) => { event.returnValue = APP_VERSION; }); function setupAutoUpdater() { if (process.platform !== 'win32') return; // Squirrel.Windows appends /RELEASES to the feed URL, // so point to /downloads where RELEASES + nupkg files live const updateURL = `${HUB_URL}/downloads`; try { autoUpdater.setFeedURL({ url: updateURL }); } catch (e) { console.error('[AutoUpdater] setFeedURL failed:', e.message); return; } autoUpdater.on('update-available', () => { console.log('[AutoUpdater] Update available, downloading...'); if (mainWindow) mainWindow.webContents.send('update-available'); }); autoUpdater.on('update-downloaded', (_event, releaseNotes, releaseName) => { console.log('[AutoUpdater] Update downloaded:', releaseName || 'new version'); if (mainWindow) mainWindow.webContents.send('update-ready'); }); // Handle install-update request from renderer ipcMain.on('install-update', () => { autoUpdater.quitAndInstall(); }); autoUpdater.on('update-not-available', () => { console.log('[AutoUpdater] App is up to date.'); if (mainWindow) mainWindow.webContents.send('update-not-available'); }); // Manual check from renderer ipcMain.on('check-for-updates', () => { try { autoUpdater.checkForUpdates(); } catch (e) { console.error('[AutoUpdater]', e.message); } }); autoUpdater.on('error', (err) => { console.error('[AutoUpdater] Error:', err.message); if (mainWindow) mainWindow.webContents.send('update-error', err.message); }); // Check for updates after 5 seconds, then every 30 minutes setTimeout(() => { try { autoUpdater.checkForUpdates(); } catch (e) { console.error('[AutoUpdater]', e.message); } }, 5000); setInterval(() => { try { autoUpdater.checkForUpdates(); } catch (e) { console.error('[AutoUpdater]', e.message); } }, 30 * 60 * 1000); } let mainWindow; function createWindow() { mainWindow = new BrowserWindow({ width: 1400, height: 900, minWidth: 900, minHeight: 600, title: 'Gaming Hub', icon: path.join(__dirname, 'assets', 'icon.png'), webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, nodeIntegration: false, }, backgroundColor: '#1a1b1e', autoHideMenuBar: true, }); // Setup ad blocker BEFORE loading URL setupAdBlocker(session.defaultSession); // Enable screen capture (getDisplayMedia) in Electron — always show picker session.defaultSession.setDisplayMediaRequestHandler(async (_request, callback) => { const sources = await desktopCapturer.getSources({ types: ['screen', 'window'], thumbnailSize: { width: 320, height: 180 } }); if (sources.length === 0) { callback({}); return; } // Build a picker window so the user always chooses const picker = new BrowserWindow({ width: 680, height: 520, parent: mainWindow, modal: true, resizable: false, minimizable: false, maximizable: false, title: 'Bildschirm / Fenster ausw\u00e4hlen', backgroundColor: '#1a1b1e', autoHideMenuBar: true, webPreferences: { contextIsolation: true, nodeIntegration: false }, }); const sourceData = sources.map(s => ({ id: s.id, name: s.name, thumbnail: s.thumbnail.toDataURL(), })); const html = `

Bildschirm oder Fenster ausw\u00e4hlen

`; picker.loadURL('data:text/html;charset=utf-8,' + encodeURIComponent(html)); let resolved = false; picker.webContents.on('page-title-updated', (_ev, title) => { if (!title.startsWith('PICK:')) return; resolved = true; const selectedId = title.slice(5); picker.close(); if (!selectedId) { callback({}); return; } const chosen = sources.find(s => s.id === selectedId); if (chosen) { callback({ video: chosen, audio: 'loopback' }); } else { callback({}); } }); picker.on('closed', () => { if (!resolved) callback({}); }); }); // Custom User-Agent to identify Electron app const currentUA = mainWindow.webContents.getUserAgent(); mainWindow.webContents.setUserAgent(currentUA + ` GamingHubDesktop/${APP_VERSION}`); mainWindow.loadURL(HUB_URL); // Open external links in default browser mainWindow.webContents.setWindowOpenHandler(({ url }) => { if (!url.startsWith(HUB_URL)) { shell.openExternal(url); return { action: 'deny' }; } return { action: 'allow' }; }); // Handle navigation to external URLs mainWindow.webContents.on('will-navigate', (event, url) => { if (!url.startsWith(HUB_URL)) { event.preventDefault(); shell.openExternal(url); } }); // Track streaming status from renderer (synchronous — no async race) let isStreaming = false; ipcMain.on('streaming-status', (_event, active) => { isStreaming = active; }); // Windows toast notifications from renderer ipcMain.on('show-notification', (_event, title, body) => { if (Notification.isSupported()) { const notif = new Notification({ title, body, icon: path.join(__dirname, 'assets', 'icon.png') }); notif.show(); } }); // Warn before closing if a stream is active mainWindow.on('close', (event) => { if (!isStreaming) return; const result = dialog.showMessageBoxSync(mainWindow, { type: 'warning', buttons: ['Beenden', 'Abbrechen'], defaultId: 1, cancelId: 1, title: 'Stream laeuft noch!', message: 'Ein Stream ist noch aktiv.\nBeim Beenden wird der Stream gestoppt.', }); if (result !== 0) event.preventDefault(); }); } app.whenReady().then(() => { createWindow(); setupAutoUpdater(); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit(); }); app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow(); });