Skip to content

Commit b4ff0cf

Browse files
committed
feat(api,web): Vinted wardrobe sync, import prefill, and API service renames
Made-with: Cursor
1 parent c63d61f commit b4ff0cf

81 files changed

Lines changed: 4485 additions & 1011 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

api/.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,8 @@ VINTED_BROWSER_DISCREET_X=-2400
2020
VINTED_BROWSER_DISCREET_Y=0
2121
VINTED_BROWSER_DISCREET_MINIMIZE=true
2222
VINTED_CHROME_EXECUTABLE=
23+
# Profil Chromium persistant (session Vinted). Vide = %LOCALAPPDATA%\GoupixDex\vinted-nodriver-profile (Windows).
24+
# VINTED_USER_DATA_DIR=
25+
# true = profil jetable à chaque lancement (comportement ancien).
26+
# VINTED_BROWSER_EPHEMERAL=false
2327
CORS_ORIGINS=*

api/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@ ebayBuilder.ts
66
__pycache__/
77
*.pyc
88
uploads/
9+
# Fichiers générés pour les annonces Vinted (listing_<id>_<hash>.<ext>)
10+
images/listing_*

api/config.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,25 +44,29 @@ class AppSettings(BaseSettings):
4444
supabase_storage_bucket: str | None = None
4545
usd_to_eur: float = 0.92
4646
cors_origins: str = "*"
47-
#: Marge initiale (table ``settings``) à la création d'un compte et pour le margin_seeder.
47+
#: Initial margin (``settings`` table) when creating an account and for ``margin_seeder``.
4848
seed_margin_percent: int = Field(default=60, ge=0, le=500)
49-
#: Base PokéWallet ou URL du proxy (ex. https://goupixdex-proxy.dibodev.fr).
49+
#: PokéWallet base URL or proxy URL (e.g. https://goupixdex-proxy.dibodev.fr).
5050
poke_wallet_base_url: str = "https://api.pokewallet.io"
51-
#: Si défini, envoi de ``X-Proxy-Secret`` ; la clé API peut rester uniquement sur le proxy.
51+
#: When set, sends ``X-Proxy-Secret``; the API key can stay only on the proxy.
5252
poke_wallet_proxy_secret: str | None = None
5353
poke_wallet_user_agent: str = "GoupixDex/1.0 (+https://goupixdex.dibodev.fr)"
54-
#: Sur le VPS : ``true`` (navigateur sans fenêtre). En local : laisser ``false`` ou absent.
54+
#: On the VPS: ``true`` (headless browser). Locally: leave ``false`` or unset.
5555
vinted_browser_headless: bool = False
56-
#: Si ``headless`` est ``false`` : fenêtre hors écran (Chrome réel, moins bloqué par Vinted que le vrai headless).
57-
#: Mettre ``false`` pour retrouver ``--start-maximized`` (ex. Xvfb plein écran).
56+
#: When ``headless`` is ``false``: off-screen window (real Chrome; often less blocked by Vinted than true headless).
57+
#: Set ``false`` to use ``--start-maximized`` (e.g. full-screen Xvfb).
5858
vinted_browser_discreet: bool = True
59-
#: Position initiale (coords écran). Valeurs négatives : souvent hors du moniteur principal (Windows / macOS).
59+
#: Initial window position (screen coords). Negative values: often off the primary monitor (Windows / macOS).
6060
vinted_browser_discreet_x: int = -2400
6161
vinted_browser_discreet_y: int = 0
62-
#: En mode discret, minimise la fenêtre juste après ouverture (peut être désactivé en cas de souci UI).
62+
#: In discreet mode, minimize the window right after open (can be disabled if UI glitches).
6363
vinted_browser_discreet_minimize: bool = True
64-
#: Chemin explicite vers Chromium/Chrome (ex. ``/usr/bin/chromium`` sur Debian après ``apt install chromium``).
64+
#: Explicit path to Chromium/Chrome (e.g. ``/usr/bin/chromium`` on Debian after ``apt install chromium``).
6565
vinted_chrome_executable: str | None = None
66+
#: Persistent nodriver Chrome profile (Vinted session). Empty = default folder under user local data.
67+
vinted_user_data_dir: str | None = None
68+
#: When ``true``: no ``user_data_dir`` (throwaway profile each launch, as before).
69+
vinted_browser_ephemeral: bool = False
6670

6771

6872
@lru_cache

api/core/deps.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818

1919
def get_bearer_or_query_token(
2020
credentials: Annotated[HTTPAuthorizationCredentials | None, Depends(security)],
21-
token: Annotated[str | None, Query(description="JWT pour EventSource (sans header Authorization)")] = None,
21+
token: Annotated[str | None, Query(description="JWT for EventSource (when Authorization header is unavailable)")] = None,
2222
) -> str:
23-
"""JWT depuis ``Authorization: Bearer`` ou ``?token=`` (SSE / EventSource)."""
23+
"""JWT from ``Authorization: Bearer`` or ``?token=`` (SSE / EventSource)."""
2424
if credentials is not None:
2525
return credentials.credentials
2626
if token and token.strip():
@@ -32,7 +32,7 @@ def get_current_user_from_token_str(
3232
raw_token: Annotated[str, Depends(get_bearer_or_query_token)],
3333
db: Annotated[Session, Depends(get_db)],
3434
) -> User:
35-
"""Utilisateur courant à partir du jeton Bearer ou query."""
35+
"""Current user resolved from Bearer token or query string."""
3636
try:
3737
sub = get_sub_from_token(raw_token)
3838
user_id = int(sub)

api/core/nodriver_uvicorn_loop.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
"""Boucle asyncio pour uvicorn + nodriver sous Windows.
1+
"""Asyncio event loop for uvicorn + nodriver on Windows.
22
3-
Avec ``--reload``, uvicorn peut sélectionner ``SelectorEventLoop``, incompatible avec
3+
With ``--reload``, uvicorn may pick ``SelectorEventLoop``, which is incompatible with
44
``create_subprocess_exec`` (Chrome / nodriver).
55
6-
Pour un ``--loop`` **personnalisé**, uvicorn importe **un seul** objet et le passe à
7-
``asyncio.Runner`` : ce doit être la **classe** de boucle (ex. ``ProactorEventLoop``),
8-
appelée sans argument pour créer l'instance — **pas** une fonction du type
9-
``lambda use_subprocess: ProactorEventLoop`` (voir ``uvicorn.config.Config.get_loop_factory``).
6+
For a **custom** ``--loop``, uvicorn imports **one** object and passes it to
7+
``asyncio.Runner``: it must be the **loop class** (e.g. ``ProactorEventLoop``),
8+
instantiated with no arguments — **not** a factory like
9+
``lambda: ProactorEventLoop()`` (see ``uvicorn.config.Config.get_loop_factory``).
1010
11-
Référence à passer à ``uvicorn --loop`` sur Windows :
11+
Value to pass to ``uvicorn --loop`` on Windows:
1212
"""
1313

1414
from __future__ import annotations
1515

16-
# Classe d'event loop du stdlib (importable uniquement sous Windows).
16+
# Stdlib event-loop class (importable only on Windows).
1717
UVICORN_WINDOWS_NODRIVER_LOOP = "asyncio.windows_events:ProactorEventLoop"

api/core/win32_asyncio.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
"""Windows: politique Proactor (utile hors uvicorn). Avec ``uvicorn --reload``, préférer
2-
``python run_dev.py`` ou ``--loop core.nodriver_uvicorn_loop:loop_factory`` (voir README).
1+
"""Windows: Proactor event-loop policy (useful outside uvicorn). With ``uvicorn --reload``, prefer
2+
``python run_dev.py`` or ``--loop core.nodriver_uvicorn_loop:...`` (see README).
33
"""
44

55
from __future__ import annotations

0 commit comments

Comments
 (0)