API HelloFresh réelle câblée + filtrage coco validé en local

- Endpoints découverts: menu (menus-service) + détails batch (recipes/recipes)
- get_menu en 2 temps: menu (ids) -> batch détails (ingrédients/allergènes)
- Fix faux positifs: exclusion sur ingrédients/allergènes/nom, plus sur les tags
  (HelloFresh pose un tag interne 'coconut' sur ~la moitié des recettes)
- Token mis en cache (pas de navigateur si frais)
- endpoints.json versionné (sans secret), semaine optionnelle (défaut = courante)
- Testé: 4 recettes coco/85 détectées, shortlist classée, tous les outils MCP OK
- set_selection (écriture) reste à découvrir sur un compte avec box active
This commit is contained in:
2026-06-15 22:28:40 +02:00
parent b881111504
commit ef6bf9813a
9 changed files with 170 additions and 96 deletions

View File

@@ -27,7 +27,7 @@ TOKEN_CACHE = SESSION_DIR / "token.json"
BASE_URL = "https://www.hellofresh.fr"
# Page qui déclenche des appels gateway authentifiés (menu de la semaine).
MENU_PAGE = f"{BASE_URL}/my-menu"
MENU_PAGE = f"{BASE_URL}/my-account/deliveries/menu"
ACCOUNT_PAGE = f"{BASE_URL}/my-account"
ATTENTE_LOGIN_S = 180 # temps laissé pour un login manuel (captcha / 2FA)
@@ -186,7 +186,15 @@ def _read_token_cache() -> dict | None:
def get_token(force: bool = False) -> str:
"""Renvoie un bearer token valide, en s'assurant d'être connecté au préalable."""
"""Renvoie un bearer token valide.
Si un token en cache est encore frais, on l'utilise sans ouvrir de navigateur.
Sinon on s'assure d'être connecté puis on en capture un neuf.
"""
if not force:
cached = _read_token_cache()
if cached and (time.time() - cached.get("captured_at", 0)) < TOKEN_TTL_S:
return cached["token"]
ensure_logged_in()
return capture_token(force=force)["token"]