initial commit

This commit is contained in:
Victor Giers
2025-11-08 01:51:55 +01:00
commit 8267309a7a
5 changed files with 237 additions and 0 deletions

38
README.md Normal file
View File

@@ -0,0 +1,38 @@
# Bumble Electron
A very small Electron shell that wraps the Bumble web app so you can keep it next to the rest of your desktop messengers.
## Features
- Loads the official Bumble web experience at `https://bumble.com/get-started` inside a dedicated window.
- Blocks unexpected navigation (drag-and-drop or pop-out windows open in your default browser).
- Single-instance enforcement so app links/notifications focus the already running window.
- Pre-configured permissions for microphone, camera, geolocation, and notifications to match the needs of voice/video calls.
## Getting Started
1. Install dependencies once:
```bash
npm install
```
2. Launch the desktop app:
```bash
npm start
```
3. Log in with your Bumble account right from the window that appears.
The project uses Electron only; no build step is required. If you want the window back after closing (macOS), use the dock icon or rerun `npm start`.
### Window behavior
- Clicking the close button now just minimizes the window so Bumble keeps running in the background.
- Use `Cmd+Q` (macOS) or `Ctrl+Q` (Windows/Linux) to quit the app completely.
## Build a Desktop Binary
Electron Builder is preconfigured for macOS, Windows, and Linux. To create unsigned binaries for your current platform:
```bash
npm run build
```
Artifacts land in `dist/`. When building on macOS without a valid signing identity (or if you need to skip signing), set `CSC_IDENTITY_AUTO_DISCOVERY=false` before running the build.
## Packaging Notes
The default build outputs (mac `.app`, Windows installer via NSIS, Linux AppImage/Deb) are defined in `package.json#build`. Adjust that section if you need different targets or want to point at alternative icons/resources.

BIN
bumble_icon_512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

42
package.json Normal file
View File

@@ -0,0 +1,42 @@
{
"name": "bumble-electron",
"version": "1.0.0",
"description": "Desktop Electron shell for Bumble Web.",
"main": "src/main.js",
"scripts": {
"start": "electron .",
"dev": "electron .",
"build": "electron-builder"
},
"keywords": [
"electron",
"bumble",
"desktop"
],
"author": "",
"license": "ISC",
"build": {
"appId": "com.victorstools.bumble",
"productName": "Bumble Desktop",
"mac": {
"category": "public.app-category.social-networking",
"icon": "bumble_icon_512.png"
},
"win": {
"target": "nsis",
"icon": "bumble_icon_512.png"
},
"linux": {
"target": [
"AppImage",
"deb"
],
"category": "Network",
"icon": "bumble_icon_512.png"
}
},
"devDependencies": {
"electron": "^39.1.1",
"electron-builder": "^26.0.12"
}
}

138
src/main.js Normal file
View File

@@ -0,0 +1,138 @@
const {
app,
BrowserWindow,
Menu,
shell,
session,
nativeTheme,
globalShortcut
} = require('electron');
const path = require('path');
const BUMBLE_URL = 'https://bumble.com/get-started';
const SINGLE_INSTANCE_LOCK = app.requestSingleInstanceLock();
const ALLOWED_PERMISSIONS = new Set(['media', 'geolocation', 'notifications']);
const ICON_PATH = path.join(__dirname, '..', 'bumble_icon_512.png');
let mainWindow;
let isQuitting = false;
app.setAppUserModelId('com.victorstools.bumble');
if (!SINGLE_INSTANCE_LOCK) {
app.quit();
}
const desktopUserAgent = `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${process.versions.chrome} Safari/537.36`;
const configureSession = () => {
const defaultSession = session.defaultSession;
if (!defaultSession) {
return;
}
defaultSession.setPermissionRequestHandler((_, permission, callback) => {
callback(ALLOWED_PERMISSIONS.has(permission));
});
defaultSession.setUserAgent(desktopUserAgent);
};
const createWindow = () => {
if (mainWindow) {
return mainWindow;
}
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
minWidth: 900,
minHeight: 600,
title: 'Bumble',
backgroundColor: nativeTheme.shouldUseDarkColors ? '#16161a' : '#ffffff',
icon: ICON_PATH,
autoHideMenuBar: true,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false,
spellcheck: true,
sandbox: false
}
});
mainWindow.loadURL(BUMBLE_URL, { userAgent: desktopUserAgent });
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
shell.openExternal(url);
return { action: 'deny' };
});
mainWindow.webContents.on('will-navigate', (event, url) => {
if (!url.startsWith('https://') && !url.startsWith('http://')) {
event.preventDefault();
}
});
mainWindow.on('close', event => {
if (!isQuitting) {
event.preventDefault();
mainWindow.minimize();
}
});
mainWindow.on('closed', () => {
mainWindow = null;
});
return mainWindow;
};
if (SINGLE_INSTANCE_LOCK) {
app.on('second-instance', () => {
if (mainWindow) {
if (mainWindow.isMinimized()) {
mainWindow.restore();
}
mainWindow.show();
mainWindow.focus();
} else {
createWindow();
}
});
}
app.on('before-quit', () => {
isQuitting = true;
});
app.whenReady().then(() => {
Menu.setApplicationMenu(null);
configureSession();
createWindow();
globalShortcut.register('CommandOrControl+Q', () => {
isQuitting = true;
app.quit();
});
app.on('activate', () => {
if (mainWindow) {
if (mainWindow.isMinimized()) {
mainWindow.restore();
}
mainWindow.show();
} else {
createWindow();
}
});
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('will-quit', () => {
globalShortcut.unregisterAll();
});

19
src/preload.js Normal file
View File

@@ -0,0 +1,19 @@
const { contextBridge } = require('electron');
// Prevent files from being dropped into the Bumble webview, which would otherwise
// trigger navigations away from the Bumble UI.
window.addEventListener('dragover', event => {
event.preventDefault();
});
window.addEventListener('drop', event => {
event.preventDefault();
});
contextBridge.exposeInMainWorld('bumbleDesktop', {
platform: process.platform,
versions: {
chrome: process.versions.chrome,
electron: process.versions.electron
}
});