Files
beStream/electron/main.ts
2025-12-14 12:57:37 +01:00

219 lines
5.5 KiB
TypeScript

import { app, BrowserWindow, ipcMain, shell, Menu, Tray, nativeImage } from 'electron';
import * as path from 'path';
import * as url from 'url';
const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged;
let mainWindow: BrowserWindow | null = null;
let tray: Tray | null = null;
function createWindow() {
mainWindow = new BrowserWindow({
width: 1400,
height: 900,
minWidth: 800,
minHeight: 600,
backgroundColor: '#141414',
titleBarStyle: 'hiddenInset',
frame: process.platform === 'darwin' ? true : false,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
webSecurity: !isDev,
},
icon: path.join(__dirname, '../public/icon.png'),
});
// Load the app
if (isDev) {
mainWindow.loadURL('http://localhost:5173');
mainWindow.webContents.openDevTools();
} else {
mainWindow.loadURL(
url.format({
pathname: path.join(__dirname, '../dist/index.html'),
protocol: 'file:',
slashes: true,
})
);
}
// Handle external links
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
shell.openExternal(url);
return { action: 'deny' };
});
mainWindow.on('closed', () => {
mainWindow = null;
});
// Create application menu
createMenu();
}
function createMenu() {
const template: Electron.MenuItemConstructorOptions[] = [
{
label: 'beStream',
submenu: [
{ label: 'About beStream', role: 'about' },
{ type: 'separator' },
{ label: 'Preferences', accelerator: 'CmdOrCtrl+,', click: () => {
mainWindow?.webContents.send('navigate', '/settings');
}},
{ type: 'separator' },
{ label: 'Hide beStream', role: 'hide' },
{ role: 'hideOthers' },
{ role: 'unhide' },
{ type: 'separator' },
{ label: 'Quit beStream', role: 'quit' },
],
},
{
label: 'File',
submenu: [
{ label: 'New Window', accelerator: 'CmdOrCtrl+N', click: createWindow },
{ type: 'separator' },
{ label: 'Close Window', role: 'close' },
],
},
{
label: 'Edit',
submenu: [
{ role: 'undo' },
{ role: 'redo' },
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
{ role: 'selectAll' },
],
},
{
label: 'View',
submenu: [
{ role: 'reload' },
{ role: 'forceReload' },
{ role: 'toggleDevTools' },
{ type: 'separator' },
{ role: 'resetZoom' },
{ role: 'zoomIn' },
{ role: 'zoomOut' },
{ type: 'separator' },
{ role: 'togglefullscreen' },
],
},
{
label: 'Navigate',
submenu: [
{ label: 'Home', accelerator: 'CmdOrCtrl+H', click: () => {
mainWindow?.webContents.send('navigate', '/');
}},
{ label: 'Browse', accelerator: 'CmdOrCtrl+B', click: () => {
mainWindow?.webContents.send('navigate', '/browse');
}},
{ label: 'Watchlist', accelerator: 'CmdOrCtrl+L', click: () => {
mainWindow?.webContents.send('navigate', '/watchlist');
}},
{ label: 'Downloads', accelerator: 'CmdOrCtrl+D', click: () => {
mainWindow?.webContents.send('navigate', '/downloads');
}},
{ type: 'separator' },
{ label: 'Back', accelerator: 'CmdOrCtrl+[', click: () => {
mainWindow?.webContents.goBack();
}},
{ label: 'Forward', accelerator: 'CmdOrCtrl+]', click: () => {
mainWindow?.webContents.goForward();
}},
],
},
{
label: 'Window',
submenu: [
{ role: 'minimize' },
{ role: 'zoom' },
{ type: 'separator' },
{ role: 'front' },
],
},
{
label: 'Help',
submenu: [
{ label: 'Learn More', click: () => shell.openExternal('https://github.com') },
],
},
];
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
}
function createTray() {
const iconPath = path.join(__dirname, '../public/icon.png');
const icon = nativeImage.createFromPath(iconPath);
tray = new Tray(icon.resize({ width: 16, height: 16 }));
const contextMenu = Menu.buildFromTemplate([
{ label: 'Open beStream', click: () => mainWindow?.show() },
{ type: 'separator' },
{ label: 'Downloads', click: () => {
mainWindow?.show();
mainWindow?.webContents.send('navigate', '/downloads');
}},
{ type: 'separator' },
{ label: 'Quit', role: 'quit' },
]);
tray.setToolTip('beStream');
tray.setContextMenu(contextMenu);
tray.on('click', () => {
mainWindow?.show();
});
}
// App event handlers
app.whenReady().then(() => {
createWindow();
createTray();
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
// IPC handlers for renderer communication
ipcMain.handle('get-app-path', () => {
return app.getPath('userData');
});
ipcMain.handle('get-downloads-path', () => {
return app.getPath('downloads');
});
ipcMain.handle('show-item-in-folder', (_event, filePath: string) => {
shell.showItemInFolder(filePath);
});
ipcMain.handle('open-external', (_event, url: string) => {
shell.openExternal(url);
});
// Handle certificate errors for development
if (isDev) {
app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
event.preventDefault();
callback(true);
});
}