fix: Game detection improvements
Some checks failed
Queue Release Build / prepare (push) Successful in 27s
Deploy Web Apps / deploy (push) Successful in 10m8s
Queue Release Build / finalize (push) Has been cancelled
Queue Release Build / build-windows (push) Has been cancelled
Queue Release Build / build-linux (push) Has been cancelled

This commit is contained in:
2026-05-17 17:47:40 +02:00
parent 8631290c01
commit a173299ad3
14 changed files with 1942 additions and 34 deletions

View File

@@ -15,7 +15,7 @@ infrastructure adapters and UI.
| **direct-message** | One-to-one WebRTC messages, offline queueing, delivery state, and friends | `DirectMessageService`, `FriendService` |
| **direct-call** | Direct and small-group private calls initiated from people cards and direct messages | `DirectCallService` |
| **experimental-media** | Optional media playback experiments kept isolated from the default attachment path | `ExperimentalMediaSettingsService` |
| **game-activity** | Local game detection, server metadata matching, P2P now-playing sync, and elapsed playtime formatting | `GameActivityService`, `formatGameActivityElapsed()` |
| **game-activity** | Foreground-window-first game detection with confidence scoring (`MIN_GAME_CONFIDENCE`), server metadata matching, P2P now-playing sync, and elapsed playtime formatting | `GameActivityService`, `formatGameActivityElapsed()` |
| **notifications** | Notification preferences, unread tracking, desktop alert orchestration | `NotificationsFacade` |
| **plugins** | Client-only plugin manifests, load ordering, registry state, and signal-server support metadata | `PluginHostService`, `PluginRegistryService` |
| **profile-avatar** | Profile picture upload, crop/zoom editing, processing, local persistence, and P2P avatar sync | `ProfileAvatarFacade` |

View File

@@ -120,7 +120,7 @@ export class GameActivityService implements OnDestroy {
const api = this.electron.getApi();
if (!api?.getRunningProcessNames) {
if (!api?.getRunningProcessNames && !api?.getActiveGameCandidate) {
return;
}
@@ -154,14 +154,33 @@ export class GameActivityService implements OnDestroy {
const api = this.electron.getApi();
if (!api?.getRunningProcessNames) {
if (!api?.getRunningProcessNames && !api?.getActiveGameCandidate) {
return;
}
this.scanInFlight = true;
try {
const processNames = (await api.getRunningProcessNames()).slice(0, MAX_PROCESS_NAMES_PER_REQUEST);
const candidateResult = api.getActiveGameCandidate
? await api.getActiveGameCandidate().catch(() => null)
: null;
let processNames: string[];
let preferredProcessName: string | undefined;
if (candidateResult?.candidate) {
// Main process already scored & filtered this; trust it.
preferredProcessName = candidateResult.candidate.rawProcessName ?? candidateResult.candidate.processName;
processNames = [preferredProcessName];
} else if (candidateResult && candidateResult.fallbackProcessNames.length > 0) {
processNames = candidateResult.fallbackProcessNames.slice(0, MAX_PROCESS_NAMES_PER_REQUEST);
} else if (!candidateResult && api.getRunningProcessNames) {
// Old preload without the new API: fall back to legacy whole-system scan.
processNames = (await api.getRunningProcessNames()).slice(0, MAX_PROCESS_NAMES_PER_REQUEST);
} else {
processNames = [];
}
const processHash = this.buildProcessHash(processNames);
if (processHash === this.lastProcessHash) {
@@ -170,6 +189,12 @@ export class GameActivityService implements OnDestroy {
this.lastProcessHash = processHash;
if (processNames.length === 0) {
this.ngZone.run(() => this.applyMatchedGame(null));
return;
}
const matchedGame = await this.matchRunningGame(processNames);
this.ngZone.run(() => this.applyMatchedGame(matchedGame));