From 8267309a7abefa4903eb2e2c2e6886b3950a45a1 Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Sat, 8 Nov 2025 01:51:55 +0100 Subject: [PATCH] initial commit --- README.md | 38 ++++++++++++ bumble_icon_512.png | Bin 0 -> 3135 bytes package.json | 42 ++++++++++++++ src/main.js | 138 ++++++++++++++++++++++++++++++++++++++++++++ src/preload.js | 19 ++++++ 5 files changed, 237 insertions(+) create mode 100644 README.md create mode 100644 bumble_icon_512.png create mode 100644 package.json create mode 100644 src/main.js create mode 100644 src/preload.js diff --git a/README.md b/README.md new file mode 100644 index 0000000..a6a08f8 --- /dev/null +++ b/README.md @@ -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. diff --git a/bumble_icon_512.png b/bumble_icon_512.png new file mode 100644 index 0000000000000000000000000000000000000000..83b538540f22ca723e778f27c548076ae25b4c34 GIT binary patch literal 3135 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 z z9U684)7cFvrIFOtxg5)p8E}#L+QO73iG>QqOSsIU2`C5eANzwq!{?%l#oB0L`64~C z+7V>35;d_A!q_|>t!Ama8*|PEhQc8aa&_5XHk~2T3M;1OHSHGB%Uj6WZ$De?f)JCt z65mT$d)}K~nh_W8XAH*_Bl0<}>^u>l4!f={sx-QfC7wAlL+!WzY2ssh=z2eL?^2ZiQ*)Dl&2%P!43}S>$cqY(gJpMNG2HjQ~#-lv1$}4{kr?E{|V`i Pv4cb|iVpiyrQZH;gF_uL literal 0 HcmV?d00001 diff --git a/package.json b/package.json new file mode 100644 index 0000000..b4e582a --- /dev/null +++ b/package.json @@ -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" + } +} diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..6922000 --- /dev/null +++ b/src/main.js @@ -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(); +}); diff --git a/src/preload.js b/src/preload.js new file mode 100644 index 0000000..a033378 --- /dev/null +++ b/src/preload.js @@ -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 + } +});