feat(desktop): add automatic game/app activity detection

Add cross-platform process scanning that detects running games and apps,
then broadcasts them as Rich Presence activities via the existing Phase 1
pipeline (activityStore -> WS -> other users).

- games.json dictionary with 26 entries (games, Spotify, VLC, OBS)
- activityDetector module: polls OS process list every 15s via execFile,
  matches against dictionary, emits IPC on state change only
- IPC bridge in main.ts/preload.ts with cleanup on quit
- Frontend activityBridge subscribes to IPC and feeds activityStore
- Supports Windows (tasklist CSV), macOS (ps -c), Linux (ps)
This commit is contained in:
Jannis Braun
2026-03-21 02:57:30 +01:00
parent 568b049b22
commit 0f4f129337
7 changed files with 321 additions and 0 deletions
@@ -0,0 +1,30 @@
import type { Activity } from '@backspace/shared';
import { useActivityStore } from '../stores/activityStore';
let unsubscribe: (() => void) | null = null;
export function initActivityBridge(): void {
if (unsubscribe) return; // already initialized
if (!window.backspace?.onActivityDetected) return; // not Electron
// Subscribe to future activity changes from main process
unsubscribe = window.backspace.onActivityDetected((activity) => {
if (activity) {
useActivityStore.getState().pushActivities([activity as Activity]);
} else {
useActivityStore.getState().pushActivities([]);
}
});
// Request current state (handles instance-switch: game was already running)
window.backspace.getCurrentActivity?.().then((activity: unknown) => {
if (activity) {
useActivityStore.getState().pushActivities([activity as Activity]);
}
}).catch(() => {});
}
export function teardownActivityBridge(): void {
unsubscribe?.();
unsubscribe = null;
}
+4
View File
@@ -48,6 +48,10 @@ interface BackspaceElectronAPI {
getAutoLaunchSettings: () => Promise<{ openAtLogin: boolean; startMinimized: boolean }>;
setAutoLaunchSettings: (settings: { openAtLogin?: boolean; startMinimized?: boolean }) =>
Promise<{ openAtLogin: boolean; startMinimized: boolean }>;
// Activity detection (game/app process scanning)
onActivityDetected: (callback: (activity: unknown) => void) => (() => void);
getCurrentActivity: () => Promise<unknown>;
}
interface Window {