feat(stt): fenêtre app autonome (profil + WM class dédiés, hors session Brave)

Le mode app s'attachait à la session Brave de l'utilisateur (même profil/icône) →
« ça sent le Brave ». On lance désormais une instance séparée : --class=STT-Funk
+ --user-data-dir dédié (~/.local/share/stt/app-profile), et le .desktop déclare
StartupWMClass=STT-Funk → fenêtre autonome avec sa propre icône de barre des tâches.
(Flatpak : --class seul, sandbox.) Une vraie fenêtre native (pywebview) reste une
option ultérieure. Bump 0.4.1 → 0.4.2.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qjq5jHiqNepnobJpHYpCa
This commit is contained in:
Claude 2026-06-18 21:59:03 +00:00
parent c6de9aef72
commit ceaadbca36
No known key found for this signature in database
4 changed files with 25 additions and 8 deletions

View file

@ -194,6 +194,10 @@ stt --uninstall-desktop # la retirer
Le lanceur exécute `stt --window app` : le HUD s'ouvre en fenêtre *chromeless* (`--app=` de
Chromium/Brave). Modes via `--window` ou `[ui].window_mode` : `app` (fenêtre), `kiosk` (plein
écran, défaut du service), `none` (n'ouvre rien). L'icône est `stt/hud/icon.svg` (aussi favicon).
La fenêtre tourne dans un **profil + une WM class dédiés** (`--class=STT-Funk`, `--user-data-dir`
sous `~/.local/share/stt/app-profile`) → **instance autonome** avec sa propre icône/entrée de barre
des tâches (associée au `.desktop` via `StartupWMClass`), séparée de ta session Brave. (Une vraie
fenêtre native sans navigateur — via `pywebview` — reste possible plus tard si besoin.)
> ⚠️ Le lanceur de bureau et le service systemd (kiosk) utilisent les **mêmes ports** (9300/9301) :
> n'en faire tourner qu'un à la fois. Borne dédiée → service kiosk ; usage à la demande → lanceur

View file

@ -1,6 +1,6 @@
[project]
name = "stt"
version = "0.4.1"
version = "0.4.2"
description = "STT — client vocal Jarvis du homelab Funk (voix + HUD, parle au STT-server)"
requires-python = ">=3.11"
readme = "README.md"

View file

@ -122,6 +122,7 @@ Terminal=false
Categories=Utility;AudioVideo;
Keywords=jarvis;assistant;voix;hermes;
StartupNotify=true
StartupWMClass=STT-Funk
"""

View file

@ -114,17 +114,29 @@ def _run_engine(engine, emit) -> None:
def _open_browser(url: str, mode: str) -> None:
"""Ouvre le HUD. mode : 'app' (fenêtre chromeless, type Discord) | 'kiosk' (plein écran).
"""Ouvre le HUD comme une fenêtre d'application dédiée (pas la session Brave courante).
Cross-distro AlmaLinux/Fedora (RHEL) et Debian/Ubuntu : on tente les binaires natifs
(noms rpm + deb), puis Flatpak (courant sur Fedora/AlmaLinux), sinon repli sur le
navigateur par défaut. Chromium-like : `--app=<url>` = fenêtre sans onglets, `--kiosk` = plein écran.
On force un profil + une WM class propres (`--class=STT-Funk`, `--user-data-dir`) la
fenêtre est une instance séparée, avec sa propre icône / entrée de barre des tâches
(associée au lanceur .desktop via `StartupWMClass`), au lieu de se fondre dans Brave.
mode : 'app' (fenêtre chromeless type Discord) | 'kiosk' (plein écran).
Cross-distro : binaire natif (rpm/deb) Flatpak repli navigateur par défaut.
"""
import shutil
import subprocess
import webbrowser
from pathlib import Path
flags = ["--kiosk", url] if mode == "kiosk" else [f"--app={url}"]
profile = Path.home() / ".local" / "share" / "stt" / "app-profile"
profile.mkdir(parents=True, exist_ok=True)
win = ["--kiosk", url] if mode == "kiosk" else [f"--app={url}"]
# Instance autonome (profil + classe dédiés) — pour les navigateurs natifs.
native = [
"--class=STT-Funk", f"--user-data-dir={profile}",
"--no-first-run", "--no-default-browser-check", *win,
]
# Flatpak est déjà sandboxé : pas de --user-data-dir (chemin hôte inaccessible).
flatpak = ["--class=STT-Funk", *win]
# 1) Binaire natif (rpm/deb)
for browser in (
@ -134,7 +146,7 @@ def _open_browser(url: str, mode: str) -> None:
"microsoft-edge", "vivaldi",
):
if shutil.which(browser):
subprocess.Popen([browser, *flags])
subprocess.Popen([browser, *native])
return
# 2) Flatpak (universel — souvent la voie sur Fedora/AlmaLinux)
@ -145,7 +157,7 @@ def _open_browser(url: str, mode: str) -> None:
["flatpak", "info", appid], capture_output=True
).returncode == 0
if installed:
subprocess.Popen(["flatpak", "run", appid, *flags])
subprocess.Popen(["flatpak", "run", appid, *flatpak])
return
# 3) Repli : onglet dans le navigateur par défaut