fletchtime 0.2.2__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fletchtime-0.2.2/src/fletchtime.egg-info → fletchtime-0.2.4}/PKG-INFO +20 -8
- {fletchtime-0.2.2 → fletchtime-0.2.4}/README.md +19 -7
- fletchtime-0.2.4/REMERCIEMENTS.md +30 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/docs/architecture.md +47 -1
- {fletchtime-0.2.2 → fletchtime-0.2.4}/docs/dev-guide/index.md +34 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/docs/index.md +3 -1
- fletchtime-0.2.4/docs/premier-club.md +113 -0
- fletchtime-0.2.4/docs/remerciements.md +5 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/docs/roadmap.md +17 -7
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/__main__.py +97 -14
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/_version.py +3 -3
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/engine/models.py +9 -9
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/engine/sequence.py +3 -2
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/logging_setup.py +28 -3
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/runtime.py +3 -1
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/server/http_static.py +22 -4
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/control.html +19 -2
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/display.html +38 -11
- {fletchtime-0.2.2 → fletchtime-0.2.4/src/fletchtime.egg-info}/PKG-INFO +20 -8
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime.egg-info/SOURCES.txt +4 -1
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime.egg-info/scm_file_list.json +4 -1
- fletchtime-0.2.4/src/fletchtime.egg-info/scm_version.json +8 -0
- fletchtime-0.2.4/tests/test_main_cli.py +152 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/tests/test_match_server.py +16 -1
- {fletchtime-0.2.2 → fletchtime-0.2.4}/tests/test_runtime.py +13 -0
- fletchtime-0.2.2/src/fletchtime/web/_defaults/gui/theme.json +0 -64
- fletchtime-0.2.2/src/fletchtime.egg-info/scm_version.json +0 -8
- {fletchtime-0.2.2 → fletchtime-0.2.4}/.github/workflows/build.yml +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/.github/workflows/docs.yml +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/.github/workflows/test.yml +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/.gitignore +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/CONTRIBUTING.md +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/LICENSE +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/config/app.toml +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/config/flint.toml +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/config/indoor.toml +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/demo.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/docs/_static/logo.svg +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/docs/api-reference.md +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/docs/conf.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/docs/requirements.txt +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/docs/specifications.md +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/docs/user-guide/index.md +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/fletchtime.spec +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/pyproject.toml +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/run_server.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/run_tests.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/scripts/generate_classic_sounds.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/setup.cfg +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/__init__.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/engine/__init__.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/engine/engine.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/engine/modes/__init__.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/engine/modes/base.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/engine/modes/flint.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/engine/modes/indoor.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/engine/turn_modes.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/gui.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/server/__init__.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/server/config_store.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/server/match_server.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/server/ws_server.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/__init__.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/_defaults/banners/README.md +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/_defaults/club/README.md +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/_defaults/sounds/packs/README.md +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/_defaults/sounds/packs/classic/countdown_tick.wav +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/_defaults/sounds/packs/classic/emergency_end.wav +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/_defaults/sounds/packs/classic/emergency_start.wav +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/_defaults/sounds/packs/classic/end_of_match.wav +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/_defaults/sounds/packs/classic/end_of_volee.wav +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/_defaults/sounds/packs/classic/pause_end.wav +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/_defaults/sounds/packs/classic/pause_start.wav +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/_defaults/sounds/packs/classic/prep_start.wav +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/_defaults/sounds/packs/classic/shoot_start.wav +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/_defaults/sounds/packs/classic/warning_orange.wav +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/_defaults/targets/flint_20cm_4spot.jpg +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/_defaults/targets/flint_35cm_1spot.jpg +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/_defaults/targets/indoor_compound.jpg +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/_defaults/targets/indoor_recurve.jpg +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/config.html +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/i18n.js +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/index.html +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/logo.svg +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/manual.html +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/screenshots/config.png +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/screenshots/control.png +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/screenshots/display.png +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/screenshots/index.png +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime/web/theme.js +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime.egg-info/dependency_links.txt +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime.egg-info/entry_points.txt +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime.egg-info/requires.txt +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/src/fletchtime.egg-info/top_level.txt +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/tests/test_config_store.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/tests/test_engine.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/tests/test_flint_mode.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/tests/test_indoor_mode.py +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/web/assets/banners/README.md +0 -0
- {fletchtime-0.2.2 → fletchtime-0.2.4}/web/assets/sounds/packs/README.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fletchtime
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: Chronométrage de compétitions d'archerie FFTL (Indoor, Flint) -- serveur + interfaces web incluses
|
|
5
5
|
License: GPL-3.0-or-later
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -21,7 +21,7 @@ Dynamic: license-file
|
|
|
21
21
|
|
|
22
22
|
<img src="https://mrfanghodev.github.io/fletchtime/_static/logo.svg" width="80" height="80" alt="FletchTime logo">
|
|
23
23
|
|
|
24
|
-
[](pyproject.toml)
|
|
25
25
|
[](LICENSE)
|
|
26
26
|
[](https://github.com/MrFanghoDev/fletchtime/actions/workflows/test.yml)
|
|
27
27
|
[](https://pypi.org/project/fletchtime/)
|
|
@@ -38,6 +38,13 @@ compris Pydroid 3. Ajoute `--headless` pour retrouver l'ancien mode
|
|
|
38
38
|
terminal (aussi utilisé automatiquement si la fenêtre ne peut pas se
|
|
39
39
|
charger, ex. `customtkinter` absent).
|
|
40
40
|
|
|
41
|
+
En mode terminal, `fletchtime --headless --help` liste toutes les
|
|
42
|
+
options -- notamment `-v`/`--verbose` et `-d`/`--debug` (plus de détail
|
|
43
|
+
dans le journal), et `--http-port`/`--ws-port` pour remplacer les ports
|
|
44
|
+
configurés le temps d'un seul lancement (ex. plusieurs salles de
|
|
45
|
+
compétition sur un même PC via un script, sans dossier séparé par salle
|
|
46
|
+
-- voir plus bas pour l'approche par copie de dossier).
|
|
47
|
+
|
|
41
48
|
## Installation
|
|
42
49
|
|
|
43
50
|
Trois façons d'obtenir et faire tourner FletchTime, selon ton matériel --
|
|
@@ -105,12 +112,14 @@ Autoriser une application via le pare-feu* -- coche `FletchTime.exe` pour
|
|
|
105
112
|
les réseaux privés.
|
|
106
113
|
|
|
107
114
|
**Ports réseau utilisés** : **8000** en HTTP (pages web) et **8765** en
|
|
108
|
-
WebSocket (synchronisation temps réel) -- deux ports séparés,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
115
|
+
WebSocket (synchronisation temps réel) par défaut -- deux ports séparés,
|
|
116
|
+
tous deux nécessaires, modifiables (fenêtre graphique, `config/gui.toml`,
|
|
117
|
+
ou `--http-port`/`--ws-port` en ligne de commande). Si le serveur tourne
|
|
118
|
+
dans un conteneur/VM (Docker, WSL2...), les deux doivent être redirigés
|
|
119
|
+
vers l'hôte, pas seulement le port HTTP : sans le port WebSocket, les
|
|
120
|
+
pages se chargent normalement mais restent bloquées sur "en attente de
|
|
121
|
+
connexion" indéfiniment (la synchronisation temps réel ne peut jamais
|
|
122
|
+
s'établir).
|
|
114
123
|
|
|
115
124
|
Pour construire ces exécutables toi-même :
|
|
116
125
|
voir `.github/workflows/build.yml` et `fletchtime.spec` (PyInstaller). Un
|
|
@@ -156,6 +165,9 @@ Envie de proposer un correctif, une idée, ou juste signaler un bug ? Voir
|
|
|
156
165
|
[CONTRIBUTING.md](CONTRIBUTING.md) (français/anglais) -- processus
|
|
157
166
|
volontairement simple, flux classique fork/branche/Pull Request.
|
|
158
167
|
|
|
168
|
+
Merci aux membres du club qui ont testé l'outil et proposé des idées au
|
|
169
|
+
fil du développement -- voir [REMERCIEMENTS.md](REMERCIEMENTS.md).
|
|
170
|
+
|
|
159
171
|
## Qualité continue
|
|
160
172
|
|
|
161
173
|
Chaque push et pull request déclenche `.github/workflows/test.yml` :
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<img src="https://mrfanghodev.github.io/fletchtime/_static/logo.svg" width="80" height="80" alt="FletchTime logo">
|
|
2
2
|
|
|
3
|
-
[](pyproject.toml)
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](https://github.com/MrFanghoDev/fletchtime/actions/workflows/test.yml)
|
|
6
6
|
[](https://pypi.org/project/fletchtime/)
|
|
@@ -17,6 +17,13 @@ compris Pydroid 3. Ajoute `--headless` pour retrouver l'ancien mode
|
|
|
17
17
|
terminal (aussi utilisé automatiquement si la fenêtre ne peut pas se
|
|
18
18
|
charger, ex. `customtkinter` absent).
|
|
19
19
|
|
|
20
|
+
En mode terminal, `fletchtime --headless --help` liste toutes les
|
|
21
|
+
options -- notamment `-v`/`--verbose` et `-d`/`--debug` (plus de détail
|
|
22
|
+
dans le journal), et `--http-port`/`--ws-port` pour remplacer les ports
|
|
23
|
+
configurés le temps d'un seul lancement (ex. plusieurs salles de
|
|
24
|
+
compétition sur un même PC via un script, sans dossier séparé par salle
|
|
25
|
+
-- voir plus bas pour l'approche par copie de dossier).
|
|
26
|
+
|
|
20
27
|
## Installation
|
|
21
28
|
|
|
22
29
|
Trois façons d'obtenir et faire tourner FletchTime, selon ton matériel --
|
|
@@ -84,12 +91,14 @@ Autoriser une application via le pare-feu* -- coche `FletchTime.exe` pour
|
|
|
84
91
|
les réseaux privés.
|
|
85
92
|
|
|
86
93
|
**Ports réseau utilisés** : **8000** en HTTP (pages web) et **8765** en
|
|
87
|
-
WebSocket (synchronisation temps réel) -- deux ports séparés,
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
94
|
+
WebSocket (synchronisation temps réel) par défaut -- deux ports séparés,
|
|
95
|
+
tous deux nécessaires, modifiables (fenêtre graphique, `config/gui.toml`,
|
|
96
|
+
ou `--http-port`/`--ws-port` en ligne de commande). Si le serveur tourne
|
|
97
|
+
dans un conteneur/VM (Docker, WSL2...), les deux doivent être redirigés
|
|
98
|
+
vers l'hôte, pas seulement le port HTTP : sans le port WebSocket, les
|
|
99
|
+
pages se chargent normalement mais restent bloquées sur "en attente de
|
|
100
|
+
connexion" indéfiniment (la synchronisation temps réel ne peut jamais
|
|
101
|
+
s'établir).
|
|
93
102
|
|
|
94
103
|
Pour construire ces exécutables toi-même :
|
|
95
104
|
voir `.github/workflows/build.yml` et `fletchtime.spec` (PyInstaller). Un
|
|
@@ -135,6 +144,9 @@ Envie de proposer un correctif, une idée, ou juste signaler un bug ? Voir
|
|
|
135
144
|
[CONTRIBUTING.md](CONTRIBUTING.md) (français/anglais) -- processus
|
|
136
145
|
volontairement simple, flux classique fork/branche/Pull Request.
|
|
137
146
|
|
|
147
|
+
Merci aux membres du club qui ont testé l'outil et proposé des idées au
|
|
148
|
+
fil du développement -- voir [REMERCIEMENTS.md](REMERCIEMENTS.md).
|
|
149
|
+
|
|
138
150
|
## Qualité continue
|
|
139
151
|
|
|
140
152
|
Chaque push et pull request déclenche `.github/workflows/test.yml` :
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Remerciements
|
|
2
|
+
|
|
3
|
+
<!-- sphinx-include-start -->
|
|
4
|
+
|
|
5
|
+
FletchTime doit beaucoup aux membres du club (Les Archers
|
|
6
|
+
Libres de Fontaine le Port) qui ont testé l'outil en conditions réelles,
|
|
7
|
+
remonté des bugs, et proposé des idées qui ont façonné le projet au fil
|
|
8
|
+
de son développement.
|
|
9
|
+
|
|
10
|
+
Un grand merci à :
|
|
11
|
+
|
|
12
|
+
- **Fangho** -- Intention initiale
|
|
13
|
+
- **Xavier** -- Primo testeur
|
|
14
|
+
- **Fabrice** -- Concours multi-serveurs
|
|
15
|
+
- **Caro** -- Ne pas oublier les Remerciements!
|
|
16
|
+
|
|
17
|
+
<!--
|
|
18
|
+
Modèle à remplir : une ligne par personne, avec ce qu'elle a apporté si
|
|
19
|
+
tu veux être précis·e (pas obligatoire -- juste le nom suffit aussi).
|
|
20
|
+
Pas d'ordre particulier attendu (alphabétique, chronologique, ou
|
|
21
|
+
simplement dans l'ordre où ça te vient -- comme tu préfères).
|
|
22
|
+
-->
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
*Tu as testé FletchTime ou proposé une idée et tu ne te retrouves pas
|
|
27
|
+
dans cette liste ? Fais-le savoir pour qu'on corrige ça.*
|
|
28
|
+
|
|
29
|
+
*Envie de contribuer plus directement (code, documentation) ? Voir
|
|
30
|
+
[CONTRIBUTING.md](CONTRIBUTING.md).*
|
|
@@ -28,7 +28,7 @@ installation logicielle sur les tablettes d'affichage.
|
|
|
28
28
|
| Composant | Choix | Justification |
|
|
29
29
|
|---|---|---|
|
|
30
30
|
| Backend WebSocket | Paquet `websockets` (asyncio) | Pas de FastAPI/Pydantic (dépendance Rust `pydantic-core` à risque sur Android/Pydroid) ni d'uvicorn `[standard]` (extensions C `uvloop`/`httptools`) ; `websockets` a un fallback pur Python si son extension C optionnelle ne compile pas — installable de façon fiable sur Pydroid 3. |
|
|
31
|
-
| Serveur HTTP statique | `http.server` (stdlib), port **8000** | Sert les pages et assets sur un port séparé du WebSocket (port **8765**) -- évite l'API instable de combinaison HTTP+WS selon les versions de `websockets` ; utilisé aussi pour la découverte de fichiers (bannières, packs de sons) via le listing de répertoire natif. **Les deux ports doivent être accessibles** depuis les écrans/postes clients (pare-feu, redirection de port si le serveur tourne dans un conteneur/VM -- ex. Docker, WSL2) : rediriger seulement le
|
|
31
|
+
| Serveur HTTP statique | `http.server` (stdlib), port **8000** par défaut | Sert les pages et assets sur un port séparé du WebSocket (port **8765** par défaut) -- évite l'API instable de combinaison HTTP+WS selon les versions de `websockets` ; utilisé aussi pour la découverte de fichiers (bannières, packs de sons) via le listing de répertoire natif. Les deux ports sont modifiables (fenêtre graphique, `config/gui.toml`, ou `--http-port`/`--ws-port` en ligne de commande -- voir {doc}`dev-guide/index`), notamment pour plusieurs salles de compétition sur un même PC. **Les deux ports doivent être accessibles** depuis les écrans/postes clients (pare-feu, redirection de port si le serveur tourne dans un conteneur/VM -- ex. Docker, WSL2) : rediriger seulement le port HTTP charge les pages mais laisse la synchronisation temps réel bloquée ("en attente de connexion" indéfiniment). |
|
|
32
32
|
| Communication temps réel | WebSocket | Évite la dérive du polling, tous les écrans restent synchronisés à la seconde près. |
|
|
33
33
|
| Frontend | HTML/CSS/JS vanilla | Pas de build, une tablette ouvre juste une URL. |
|
|
34
34
|
| Config des modes (Indoor/Flint) | Fichiers **TOML** (`config/*.toml`) | Lu via `tomllib`, stdlib depuis Python 3.11 (donc Pydroid) -- zéro dépendance. Écriture via un petit sérialiseur maison (pas de support d'écriture en stdlib). |
|
|
@@ -502,6 +502,52 @@ Le poste de contrôle, à l'inverse, affiche une bannière large et alarmante
|
|
|
502
502
|
(pas discrète) en cas de coupure -- c'est le responsable du chronométrage
|
|
503
503
|
qui doit être alerté clairement, pas les archers.
|
|
504
504
|
|
|
505
|
+
## Synchronisation du diaporama de l'écran neutre
|
|
506
|
+
|
|
507
|
+
L'écran neutre (hors concours, ou après sa fin) alterne logo/horloge et
|
|
508
|
+
bannières sponsors -- voir `display.html`, `showSlideshowStep`. Aucune
|
|
509
|
+
coordination serveur pour ça : chaque écran calcule sa slide actuelle en
|
|
510
|
+
divisant l'horloge murale (`Date.now()`) par la durée d'une slide, plutôt
|
|
511
|
+
que d'incrémenter un compteur local à partir de 0 à son propre démarrage.
|
|
512
|
+
|
|
513
|
+
```{important}
|
|
514
|
+
Une première version utilisait un compteur local (`slideshowStep`,
|
|
515
|
+
incrémenté par `setInterval`) -- deux écrans qui chargeaient ou se
|
|
516
|
+
reconnectaient à des instants différents affichaient alors des slides
|
|
517
|
+
différentes au même moment, chacun étant reparti de 0 à son propre
|
|
518
|
+
démarrage. Corrigé en dérivant la slide actuelle de l'horloge murale
|
|
519
|
+
(`Math.floor(Date.now() / SLIDE_DURATION_MS) % totalSlides`) : deux
|
|
520
|
+
écrans avec des horloges système raisonnablement synchronisées (le cas
|
|
521
|
+
normal sur un même réseau local) calculent alors la même slide,
|
|
522
|
+
indépendamment de quand chacun a démarré. Vérifié avec un vrai navigateur
|
|
523
|
+
(Chromium via Playwright) : deux pages chargées à 3 secondes d'écart
|
|
524
|
+
affichent bien la même slide.
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
## Découverte du port WebSocket côté client
|
|
528
|
+
|
|
529
|
+
`display.html` et `control.html` ne connaissent pas à l'avance le port
|
|
530
|
+
WebSocket à utiliser : depuis que les ports sont devenus modifiables
|
|
531
|
+
(voir la fenêtre graphique et `config/gui.toml`, pensé pour plusieurs
|
|
532
|
+
salles de compétition sur un même PC), le coder en dur côté client
|
|
533
|
+
casserait silencieusement toute page si le port avait été changé.
|
|
534
|
+
|
|
535
|
+
Chaque page interroge `/api/version` (servi par le même serveur HTTP qui
|
|
536
|
+
vient de la servir, donc forcément sur le bon port) avant d'ouvrir sa
|
|
537
|
+
connexion WebSocket -- la réponse inclut `ws_port`, le port réellement
|
|
538
|
+
configuré (`ServerRuntime.ws_port`, plombé jusqu'à
|
|
539
|
+
`http_static.start_http_server`). Un échec de cette requête (réseau,
|
|
540
|
+
serveur non démarré) se rabat silencieusement sur `8765` -- l'ancien
|
|
541
|
+
port fixe, qui reste une valeur par défaut raisonnable, jamais une
|
|
542
|
+
erreur bloquante pour l'utilisateur.
|
|
543
|
+
|
|
544
|
+
```{note}
|
|
545
|
+
Vérifié avec un vrai navigateur (Chromium via Playwright), pas seulement
|
|
546
|
+
en théorie : les deux pages utilisent bien le port récupéré
|
|
547
|
+
dynamiquement, et se rabattent proprement sur 8765 sans planter quand
|
|
548
|
+
`/api/version` échoue.
|
|
549
|
+
```
|
|
550
|
+
|
|
505
551
|
## Multi-écrans et ciblage
|
|
506
552
|
|
|
507
553
|
Chaque écran se connecte au WebSocket et s'enregistre avec son numéro de lane
|
|
@@ -133,6 +133,40 @@ dernier commit de `main`, seulement la dernière version taguée -- voir
|
|
|
133
133
|
la note correspondante sur {doc}`../index`.
|
|
134
134
|
```
|
|
135
135
|
|
|
136
|
+
## Options de la ligne de commande (mode terminal)
|
|
137
|
+
|
|
138
|
+
`fletchtime --headless --help` (ou `python -m fletchtime --headless
|
|
139
|
+
--help`) affiche la liste complète, mais résumé ici pour référence
|
|
140
|
+
rapide -- voir `fletchtime/__main__.py`, `_build_arg_parser`.
|
|
141
|
+
|
|
142
|
+
| Option | Effet |
|
|
143
|
+
|---|---|
|
|
144
|
+
| `-h`, `--help` | Affiche l'aide et quitte. |
|
|
145
|
+
| `-V`, `--version` | Affiche la version et quitte. |
|
|
146
|
+
| `--headless`, `--no-gui` | Mode terminal, sans fenêtre graphique. |
|
|
147
|
+
| `-v`, `--verbose` | Affiche les journaux applicatifs (commandes reçues, (dé)connexions...) dans le terminal, pas seulement dans le fichier. |
|
|
148
|
+
| `-d`, `--debug` | Journalisation la plus détaillée possible, fichier compris -- implique `--verbose`. |
|
|
149
|
+
| `--http-port PORT` | Remplace le port HTTP configuré, pour cette exécution seulement. |
|
|
150
|
+
| `--ws-port PORT` | Remplace le port WebSocket configuré, pour cette exécution seulement. |
|
|
151
|
+
|
|
152
|
+
```{note}
|
|
153
|
+
`--http-port`/`--ws-port` **ne modifient jamais** `config/gui.toml` --
|
|
154
|
+
un remplacement ponctuel (utile pour un lancement scripté/CI, ou
|
|
155
|
+
plusieurs salles de compétition sur un même PC sans dossier séparé par
|
|
156
|
+
salle), pas un changement persistant. Pour un réglage durable, voir la
|
|
157
|
+
fenêtre graphique (section Ports) ou éditer `config/gui.toml`
|
|
158
|
+
directement.
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Niveaux de journalisation, fichier et terminal indépendants l'un de
|
|
162
|
+
l'autre** (voir `fletchtime.logging_setup.configure_logging`) : le
|
|
163
|
+
fichier de journal (`logs/fletchtime.log`) reste toujours à INFO par
|
|
164
|
+
défaut, quelle que soit la commande utilisée pour lancer FletchTime --
|
|
165
|
+
le diagnostic après-coup d'un concours ne doit pas dépendre de si
|
|
166
|
+
quelqu'un a pensé à ajouter `-v`. Seul le terminal respecte
|
|
167
|
+
`-v`/`--verbose` (silencieux par défaut, WARNING). `--debug` élève les
|
|
168
|
+
deux au niveau DEBUG.
|
|
169
|
+
|
|
136
170
|
## Architecture générale
|
|
137
171
|
|
|
138
172
|
Voir {doc}`../architecture` pour le détail complet. En résumé :
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
:align: center
|
|
5
5
|
```
|
|
6
6
|
|
|
7
|
-
[](https://github.com/MrFanghoDev/fletchtime/blob/master/pyproject.toml)
|
|
8
8
|
[](https://github.com/MrFanghoDev/fletchtime/blob/master/LICENSE)
|
|
9
9
|
[](https://github.com/MrFanghoDev/fletchtime/actions/workflows/test.yml)
|
|
10
10
|
[](https://pypi.org/project/fletchtime/)
|
|
@@ -27,9 +27,11 @@ page d'accueil, pas ici) -- voir {doc}`user-guide/index`.
|
|
|
27
27
|
:maxdepth: 2
|
|
28
28
|
:caption: Contenu
|
|
29
29
|
|
|
30
|
+
premier-club
|
|
30
31
|
specifications
|
|
31
32
|
architecture
|
|
32
33
|
roadmap
|
|
34
|
+
remerciements
|
|
33
35
|
user-guide/index
|
|
34
36
|
dev-guide/index
|
|
35
37
|
api-reference
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Découvrir FletchTime pour son club
|
|
2
|
+
|
|
3
|
+
Cette page s'adresse à quelqu'un qui découvre FletchTime pour la première
|
|
4
|
+
fois -- un⋅e archer⋅ère, un⋅e responsable de club. Pas besoin de
|
|
5
|
+
connaître quoi que ce soit du projet au préalable.
|
|
6
|
+
|
|
7
|
+
## C'est quoi
|
|
8
|
+
|
|
9
|
+
FletchTime est un logiciel de chronométrage pour les compétitions
|
|
10
|
+
d'archerie FFTL (Indoor et Flint) : il gère le décompte du temps de tir,
|
|
11
|
+
les phases de préparation et de repos, les sons qui rythment le
|
|
12
|
+
concours, sur autant d'écrans que nécessaire. Gratuit, open source, né
|
|
13
|
+
de l'usage réel d'un club.
|
|
14
|
+
|
|
15
|
+
## Pourquoi s'en servir
|
|
16
|
+
|
|
17
|
+
::::{grid} 2
|
|
18
|
+
:gutter: 3
|
|
19
|
+
|
|
20
|
+
:::{grid-item-card} 📺 Un écran par pas de tir
|
|
21
|
+
Pas juste un chrono près du starter -- chaque archer voit le temps
|
|
22
|
+
restant sans avoir à se retourner.
|
|
23
|
+
:::
|
|
24
|
+
|
|
25
|
+
:::{grid-item-card} 🔊 Les sons rythment le concours tout seuls
|
|
26
|
+
Début de préparation, passage à l'orange, fin de volée... plus besoin
|
|
27
|
+
qu'une personne déclenche chaque signal à la main.
|
|
28
|
+
:::
|
|
29
|
+
|
|
30
|
+
:::{grid-item-card} 💻 Du matériel qu'un club a probablement déjà
|
|
31
|
+
Un vieux PC, des tablettes ou téléphones pour les écrans -- pas de
|
|
32
|
+
matériel spécialisé à acheter.
|
|
33
|
+
:::
|
|
34
|
+
|
|
35
|
+
:::{grid-item-card} 🔌 Résiste aux coupures et aux plantages
|
|
36
|
+
Le chrono ne perd pas le fil, la reprise se fait sans intervention
|
|
37
|
+
manuelle -- voir {doc}`architecture` pour le détail technique.
|
|
38
|
+
:::
|
|
39
|
+
|
|
40
|
+
::::
|
|
41
|
+
|
|
42
|
+
## Ce qu'il faut avant de commencer
|
|
43
|
+
|
|
44
|
+
- Un appareil pour héberger le serveur (PC ou téléphone selon la méthode
|
|
45
|
+
d'installation choisie) -- pas besoin d'être puissant.
|
|
46
|
+
- Un réseau WiFi local reliant cet appareil et les écrans.
|
|
47
|
+
- Des écrans pour l'affichage : tablettes, téléphones, ou même un vieux
|
|
48
|
+
moniteur relié à un PC secondaire.
|
|
49
|
+
- Aucune compétence technique nécessaire pour l'usage courant -- voir
|
|
50
|
+
plus bas si l'installation elle-même te semble intimidante.
|
|
51
|
+
|
|
52
|
+
## Premiers pas
|
|
53
|
+
|
|
54
|
+
1. **Installer** : plusieurs façons possibles selon le matériel -- voir le
|
|
55
|
+
[README](https://github.com/MrFanghoDev/fletchtime#installation)
|
|
56
|
+
pour le détail de chacune.
|
|
57
|
+
2. **Premier lancement** : une fenêtre s'ouvre avec les adresses à
|
|
58
|
+
utiliser depuis les autres appareils du réseau.
|
|
59
|
+
3. **Ouvrir la page de contrôle** depuis l'appareil hôte ou n'importe
|
|
60
|
+
quel appareil du réseau, choisir le mode (Indoor ou Flint), ajuster
|
|
61
|
+
les réglages si besoin (temps de tir, nombre de volées...).
|
|
62
|
+
4. **Ouvrir la page d'affichage** sur chaque écran destiné aux archers.
|
|
63
|
+
5. **Faire un match d'essai** avant le premier vrai concours -- le
|
|
64
|
+
temps de se familiariser avec les boutons (démarrer, pause, urgence)
|
|
65
|
+
sans pression.
|
|
66
|
+
|
|
67
|
+
Une fois ces cinq étapes passées une fois, le pilotage d'un vrai
|
|
68
|
+
concours se résume à quelques clics : voir le manuel utilisateur
|
|
69
|
+
intégré à l'application (accessible depuis sa page d'accueil) pour le
|
|
70
|
+
détail de chaque réglage et bouton.
|
|
71
|
+
|
|
72
|
+
## Peut-on lui faire confiance
|
|
73
|
+
|
|
74
|
+
Question légitime avant de l'utiliser en compétition officielle :
|
|
75
|
+
|
|
76
|
+
- **Open source** : le code est public, inspectable par qui veut --
|
|
77
|
+
rien de caché.
|
|
78
|
+
- **Testé en conditions réelles de concours**, pas seulement "ça
|
|
79
|
+
compile" -- voir {doc}`roadmap` pour l'historique des versions et ce
|
|
80
|
+
qui a été vérifié en pratique.
|
|
81
|
+
- **Récupère après un plantage ou un redémarrage du serveur** sans
|
|
82
|
+
perdre la progression du match en cours.
|
|
83
|
+
- Reste un projet de club, sans obligation de résultat ni support
|
|
84
|
+
garanti -- voir la
|
|
85
|
+
[licence](https://github.com/MrFanghoDev/fletchtime/blob/master/LICENSE)
|
|
86
|
+
et le ton du
|
|
87
|
+
[guide de contribution](https://github.com/MrFanghoDev/fletchtime/blob/master/CONTRIBUTING.md)
|
|
88
|
+
pour ce que ça implique concrètement.
|
|
89
|
+
|
|
90
|
+
## Où chercher de l'aide
|
|
91
|
+
|
|
92
|
+
::::{grid} 2
|
|
93
|
+
:gutter: 3
|
|
94
|
+
|
|
95
|
+
:::{grid-item-card} 📖 Usage au quotidien
|
|
96
|
+
Réglages, pilotage d'un match : le manuel utilisateur intégré à
|
|
97
|
+
l'application, accessible depuis sa page d'accueil une fois installée.
|
|
98
|
+
:::
|
|
99
|
+
|
|
100
|
+
:::{grid-item-card} 🐛 Un bug, une question
|
|
101
|
+
Les [Issues GitHub](https://github.com/MrFanghoDev/fletchtime/issues).
|
|
102
|
+
:::
|
|
103
|
+
|
|
104
|
+
:::{grid-item-card} 🤝 Envie de contribuer
|
|
105
|
+
Code, documentation, idée -- voir
|
|
106
|
+
[CONTRIBUTING.md](https://github.com/MrFanghoDev/fletchtime/blob/master/CONTRIBUTING.md).
|
|
107
|
+
:::
|
|
108
|
+
|
|
109
|
+
:::{grid-item-card} 🔧 Fonctionnement technique
|
|
110
|
+
Le reste de cette documentation : {doc}`specifications`, {doc}`architecture`.
|
|
111
|
+
:::
|
|
112
|
+
|
|
113
|
+
::::
|
|
@@ -56,23 +56,33 @@ dépendent d'extensions compilées (Rust/C) peu fiables sur Pydroid 3, voir
|
|
|
56
56
|
(`pip install fletchtime` + commande `fletchtime`), exécutables
|
|
57
57
|
autoporteurs Windows/Linux, CI (lint + tests à chaque push).
|
|
58
58
|
|
|
59
|
-
##
|
|
59
|
+
## ✅ Étape 7 — Partage FFTL (hors contact fédération, démarche humaine)
|
|
60
60
|
|
|
61
61
|
- ~~Licence open source claire~~ -- déjà en place : `LICENSE`
|
|
62
62
|
(GPL-3.0-or-later), cohérent avec `pyproject.toml`.
|
|
63
63
|
- ~~Guide de contribution~~ -- fait : `CONTRIBUTING.md` (français/anglais),
|
|
64
64
|
flux classique fork/branche/Pull Request, volontairement simple.
|
|
65
|
-
- Nettoyage
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
65
|
+
- ~~Nettoyage~~ -- fait : balayage complet du dépôt, aucun contenu
|
|
66
|
+
spécifique au club trouvé en dehors de `web/assets/` (normal et
|
|
67
|
+
attendu là). Un vrai souci trouvé au passage, mais côté livraison
|
|
68
|
+
plutôt que dans le dépôt lui-même : un logo de club réel se
|
|
69
|
+
retrouvait dans les archives livrées malgré son exclusion de git --
|
|
70
|
+
corrigé.
|
|
71
|
+
- ~~Guide "premier club"~~ -- fait : {doc}`premier-club`, point d'entrée
|
|
72
|
+
pour quelqu'un qui découvre l'outil sans contexte préalable (c'est
|
|
73
|
+
quoi, pourquoi s'en servir, prérequis, premiers pas, peut-on lui faire
|
|
74
|
+
confiance, où chercher de l'aide).
|
|
71
75
|
- Contact fédération pour retour d'expérience / adoption éventuelle par
|
|
72
76
|
d'autres clubs -- démarche humaine, hors du champ du dépôt lui-même.
|
|
73
77
|
|
|
74
78
|
## Backlog — à discuter / non encore programmé dans une étape précise
|
|
75
79
|
|
|
80
|
+
- ~~**Remerciements**~~ -- structure prête, à compléter : `REMERCIEMENTS.md`
|
|
81
|
+
(modèle à remplir avec les noms), lié depuis le README et intégré à la
|
|
82
|
+
doc Sphinx ({doc}`remerciements` -- même contenu, pas dupliqué, via une
|
|
83
|
+
inclusion). Les membres du club ont aidé à tester et proposé des idées
|
|
84
|
+
au fil du développement -- reste à toi d'ajouter les noms.
|
|
85
|
+
|
|
76
86
|
- ~~**Journal applicatif persistant**~~ -- fait : `MatchServer` journalise
|
|
77
87
|
désormais chaque commande reçue, (dé)connexion, perte de connexion
|
|
78
88
|
réseau et message malformé dans un fichier avec rotation
|
|
@@ -19,6 +19,8 @@ Deux notions de dossier bien distinctes ici, à ne pas confondre :
|
|
|
19
19
|
|
|
20
20
|
from __future__ import annotations
|
|
21
21
|
|
|
22
|
+
import argparse
|
|
23
|
+
import logging
|
|
22
24
|
import shutil
|
|
23
25
|
import signal
|
|
24
26
|
import socket
|
|
@@ -150,7 +152,85 @@ def _print_banner(ip: str, data_root: Path, http_port: int) -> None:
|
|
|
150
152
|
print("=" * 60)
|
|
151
153
|
|
|
152
154
|
|
|
153
|
-
def
|
|
155
|
+
def _build_arg_parser() -> argparse.ArgumentParser:
|
|
156
|
+
parser = argparse.ArgumentParser(
|
|
157
|
+
prog="fletchtime",
|
|
158
|
+
description=(
|
|
159
|
+
"Serveur de chronométrage pour compétitions d'archerie FFTL " "(Indoor et Flint)."
|
|
160
|
+
),
|
|
161
|
+
)
|
|
162
|
+
parser.add_argument(
|
|
163
|
+
"-V",
|
|
164
|
+
"--version",
|
|
165
|
+
action="version",
|
|
166
|
+
version=f"FletchTime {__version__}",
|
|
167
|
+
)
|
|
168
|
+
parser.add_argument(
|
|
169
|
+
"--headless",
|
|
170
|
+
"--no-gui",
|
|
171
|
+
dest="headless",
|
|
172
|
+
action="store_true",
|
|
173
|
+
help="Mode terminal, sans fenêtre graphique.",
|
|
174
|
+
)
|
|
175
|
+
parser.add_argument(
|
|
176
|
+
"-v",
|
|
177
|
+
"--verbose",
|
|
178
|
+
action="store_true",
|
|
179
|
+
help="Affiche les journaux applicatifs (commandes reçues, "
|
|
180
|
+
"(dé)connexions...) dans le terminal, pas seulement dans le "
|
|
181
|
+
"fichier de journal.",
|
|
182
|
+
)
|
|
183
|
+
parser.add_argument(
|
|
184
|
+
"-d",
|
|
185
|
+
"--debug",
|
|
186
|
+
action="store_true",
|
|
187
|
+
help="Journalisation la plus détaillée possible, fichier compris " "-- implique --verbose.",
|
|
188
|
+
)
|
|
189
|
+
parser.add_argument(
|
|
190
|
+
"--http-port",
|
|
191
|
+
type=int,
|
|
192
|
+
metavar="PORT",
|
|
193
|
+
help="Port HTTP -- remplace la valeur de config/gui.toml pour "
|
|
194
|
+
"cette exécution seulement, sans la modifier (voir aussi la "
|
|
195
|
+
"fenêtre graphique pour un réglage persistant).",
|
|
196
|
+
)
|
|
197
|
+
parser.add_argument(
|
|
198
|
+
"--ws-port",
|
|
199
|
+
type=int,
|
|
200
|
+
metavar="PORT",
|
|
201
|
+
help="Port WebSocket -- remplace la valeur de config/gui.toml "
|
|
202
|
+
"pour cette exécution seulement, sans la modifier.",
|
|
203
|
+
)
|
|
204
|
+
return parser
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _resolve_console_log_level(args: argparse.Namespace) -> int:
|
|
208
|
+
if args.debug:
|
|
209
|
+
return logging.DEBUG
|
|
210
|
+
if args.verbose:
|
|
211
|
+
return logging.INFO
|
|
212
|
+
return logging.WARNING
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _resolve_ports(args: argparse.Namespace, parser: argparse.ArgumentParser) -> tuple[int, int]:
|
|
216
|
+
"""Priorité aux options de la ligne de commande sur config/gui.toml,
|
|
217
|
+
sans jamais modifier ce fichier -- une exécution scriptée/CI ne doit
|
|
218
|
+
pas laisser de trace persistante par accident. Revalide les deux
|
|
219
|
+
ports ensemble (même règle que config_store.save_gui_config) même
|
|
220
|
+
si un seul des deux vient de la ligne de commande, pour ne jamais se
|
|
221
|
+
retrouver avec une combinaison invalide (identiques, hors bornes)."""
|
|
222
|
+
gui_config = config_store.load_gui_config()
|
|
223
|
+
http_port = args.http_port if args.http_port is not None else gui_config["http_port"]
|
|
224
|
+
ws_port = args.ws_port if args.ws_port is not None else gui_config["ws_port"]
|
|
225
|
+
for name, port in (("--http-port", http_port), ("--ws-port", ws_port)):
|
|
226
|
+
if not (1 <= port <= 65535):
|
|
227
|
+
parser.error(f"{name} : le port doit être entre 1 et 65535 (reçu {port}).")
|
|
228
|
+
if http_port == ws_port:
|
|
229
|
+
parser.error("--http-port et --ws-port doivent être différents.")
|
|
230
|
+
return http_port, ws_port
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def _run_headless(args: argparse.Namespace, parser: argparse.ArgumentParser) -> None:
|
|
154
234
|
"""Mode terminal classique -- utilisé si l'interface graphique n'a pas
|
|
155
235
|
pu être chargée (ex. `customtkinter` absent), ou explicitement demandé
|
|
156
236
|
via `--headless`/`--no-gui`."""
|
|
@@ -159,18 +239,18 @@ def _run_headless() -> None:
|
|
|
159
239
|
ensure_directories(data_root, app_web_dir)
|
|
160
240
|
assets_dir = data_root / "web" / "assets"
|
|
161
241
|
|
|
162
|
-
|
|
242
|
+
console_level = _resolve_console_log_level(args)
|
|
243
|
+
file_level = logging.DEBUG if args.debug else logging.INFO
|
|
244
|
+
log_file = configure_logging(data_root / "logs", console_level, file_level)
|
|
163
245
|
print(f"Journal détaillé / Detailed log: {log_file}")
|
|
164
246
|
|
|
165
|
-
# Ports lus depuis config/gui.toml (mêmes préférences que
|
|
166
|
-
# graphique, voir config_store.load_gui_config)
|
|
167
|
-
#
|
|
168
|
-
#
|
|
169
|
-
#
|
|
170
|
-
#
|
|
171
|
-
|
|
172
|
-
http_port = gui_config["http_port"]
|
|
173
|
-
ws_port = gui_config["ws_port"]
|
|
247
|
+
# Ports lus depuis config/gui.toml par défaut (mêmes préférences que
|
|
248
|
+
# la fenêtre graphique, voir config_store.load_gui_config), sauf
|
|
249
|
+
# remplacement explicite via --http-port/--ws-port pour cette seule
|
|
250
|
+
# exécution -- permet de faire tourner plusieurs salles de
|
|
251
|
+
# compétition sur un même PC sans dossier séparé par salle, utile
|
|
252
|
+
# pour un lancement scripté/CI par exemple.
|
|
253
|
+
http_port, ws_port = _resolve_ports(args, parser)
|
|
174
254
|
|
|
175
255
|
_print_banner(local_ip(), data_root, http_port)
|
|
176
256
|
|
|
@@ -193,8 +273,11 @@ def _run_headless() -> None:
|
|
|
193
273
|
|
|
194
274
|
|
|
195
275
|
def main() -> None:
|
|
196
|
-
|
|
197
|
-
|
|
276
|
+
parser = _build_arg_parser()
|
|
277
|
+
args = parser.parse_args()
|
|
278
|
+
|
|
279
|
+
if args.headless:
|
|
280
|
+
_run_headless(args, parser)
|
|
198
281
|
return
|
|
199
282
|
|
|
200
283
|
try:
|
|
@@ -212,7 +295,7 @@ def main() -> None:
|
|
|
212
295
|
# repli ne risque pas un conflit de port avec _run_headless().
|
|
213
296
|
print(f"Interface graphique indisponible ({exc}) -- mode terminal.")
|
|
214
297
|
print(f"Graphical interface unavailable ({exc}) -- terminal mode.")
|
|
215
|
-
_run_headless()
|
|
298
|
+
_run_headless(args, parser)
|
|
216
299
|
|
|
217
300
|
|
|
218
301
|
if __name__ == "__main__":
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.2.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 2,
|
|
21
|
+
__version__ = version = '0.2.4'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 2, 4)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g5efc3a10b'
|
|
@@ -14,15 +14,15 @@ from enum import StrEnum
|
|
|
14
14
|
class Phase(StrEnum):
|
|
15
15
|
"""Visual/safety phase of the current step.
|
|
16
16
|
|
|
17
|
-
WAIT
|
|
18
|
-
RED
|
|
19
|
-
GREEN
|
|
20
|
-
ORANGE
|
|
21
|
-
PAUSE
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
EMERGENCY -- danger signal, clock frozen, must be explicitly resumed.
|
|
25
|
-
FINISHED
|
|
17
|
+
- ``WAIT`` -- before the match starts, or between matches. No countdown.
|
|
18
|
+
- ``RED`` -- preparation time (archers approach / take position).
|
|
19
|
+
- ``GREEN`` -- main shooting time.
|
|
20
|
+
- ``ORANGE`` -- warning period near the end of shooting time.
|
|
21
|
+
- ``PAUSE`` -- end of a volée: archers retrieve arrows, no countdown.
|
|
22
|
+
The engine waits here indefinitely until the DOS manually starts
|
|
23
|
+
the next volée (``MatchEngine.next()``).
|
|
24
|
+
- ``EMERGENCY`` -- danger signal, clock frozen, must be explicitly resumed.
|
|
25
|
+
- ``FINISHED`` -- sequence exhausted, nothing left to shoot.
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
28
|
WAIT = "wait"
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""A ``Step`` is one timed segment of a competition (e.g. "red light, 10s,
|
|
2
2
|
end 3 of 12, turn A-B, distance 18m"). A shooting mode's job is only to
|
|
3
|
-
produce an ordered list of ``Step``
|
|
4
|
-
list back, handling ticking, manual advance and emergency
|
|
3
|
+
produce an ordered list of ``Step`` objects up front; the engine then
|
|
4
|
+
plays that list back, handling ticking, manual advance and emergency
|
|
5
|
+
stop.
|
|
5
6
|
|
|
6
7
|
This keeps modes simple, declarative, and trivial to unit test: you can
|
|
7
8
|
assert on the exact list of steps a config produces without running any
|