feat(foreground): track topmost process + browser page title
Lint & Test / test (push) Failing after 8s

Adds cross-platform foreground-window tracking and exposes it over REST
(/api/foreground) and the existing WebSocket feed.

- foreground_service.py: Windows probe via ctypes (HANDLE-correct argtypes
  to avoid 64-bit handle truncation); macOS via AppKit; Linux via Xlib
  (Wayland returns unavailable). TTL cache + per-platform fallback.
- browser_url_service.py: when foreground is a recognised browser, extract
  the page title from the window title (browser-name suffix stripped) and
  surface `is_browser` + `browser_page_title`. Optional UIA-based URL
  extraction behind MEDIA_SERVER_BROWSER_UIA env flag (off by default —
  Chromium browsers keep their accessibility tree dormant otherwise).
- websocket_manager: poll foreground every 1s inside the existing status
  loop, broadcast `foreground` on connect and `foreground_update` on
  change. Diff only on user-visible fields to avoid geometry spam.
- WebUI: new editorial card rendered under the monitor list on the
  Display tab — process name, window title, fullscreen/minimized/monitor
  chips, browser block when applicable, exe path, PID, started-ago,
  geometry, platform. 16px inter-section gap matches Settings cadence.
- i18n: 25 new keys added to both en.json and ru.json.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-05-18 03:11:59 +03:00
parent 0cf49deac0
commit 61cdce9b60
15 changed files with 1571 additions and 3 deletions
+3
View File
@@ -12,6 +12,7 @@ import { updateUI, setFrequencyData, stopPositionInterpolation, loadAudioDevices
import { loadScripts, loadScriptsTable, displayQuickAccess } from './scripts.js';
import { loadCallbacksTable } from './callbacks.js';
import { loadHeaderLinks, loadLinksTable } from './links.js';
import { updateForegroundUI } from './foreground.js';
let reconnectTimeout = null;
let wsReconnectAttempts = 0;
@@ -118,6 +119,8 @@ export function connectWebSocket(token) {
if (msg.type === 'status' || msg.type === 'status_update') {
updateUI(msg.data);
} else if (msg.type === 'foreground' || msg.type === 'foreground_update') {
updateForegroundUI(msg.data);
} else if (msg.type === 'scripts_changed') {
console.log('Scripts changed, reloading...');
loadScripts();