SPB Git forge

spb/fabri-ka

Public

Agrégateur de produits québécois — www.fabri-ka.com

217commits 1branches 0releases
66.1 MBsize
maindefault branch
3 h agolast push
Python 38.4% HTML 30.3% TypeScript 17.2% CSS 11% JavaScript 3.2%

[ka6] fix connecteur magillhats.com: bascule generic→woocommerce + Store API non versionnée + retries 507/508. Cause racine (2026-09-17): l'hébergement du site (CloudLinux) est à bout de ressources — ~1 requête sur 8 passe, le reste en 508 « Resource Limit Is Reached »/507, indépendant de l'IP (vérifié via proxy résidentiel). La fiche était en catalog_endpoint __generic__ (crawl sitemap+JSON-LD): les sitemaps en 507/508 donnaient 0 URL → faux « ok / 0 » silencieux qui a purgé le catalogue (65→59→42→0, 65 produits en base active=0). Or le site EST un WooCommerce fonctionnel… ancien (<6.4, probablement restauré d'une vieille sauvegarde): la Store API y est NON versionnée — /wp-json/wc/store/products répond 200 avec 66 produits, /wc/store/v1/products donne rest_no_route 404. Fix: (1) fiche stores.json basculée sur catalog_endpoint /wp-json/wc/store/products (dispatch plateforme → WooCommerceConnector, valeur truthy sinon run() saute la boutique); (2) woocommerce.py: fallback _api_version='' — sur échec de la page 1 (quel qu'il soit, un 508 peut masquer le 404) retenter la route non versionnée avant ?rest_route=; (3) _get_items: jusqu'à 8 tentatives espacées de 3 s sur 507/508 (limite compte hébergeur, intermittente). Sync réel 2026-09-17 18:22: magillhats.com 66 produits (+66), base 72 actifs (6 doublons ex-clés slug seront désactivés via MISS_GRACE=2). Non-régression: artisandulac.ca 443, multi-eco.com 8, labete.ca 0 sans erreur (_woo_uninstalled intact). Si le site reste en 508 sur un sync complet: erreur explicite ou fallback HTML partiel — produits préservés, réintégration auto.

Simon-Pierre Boucher committed 9 days ago (Sep 17, 2026) parent 729a60d

2 changed files +40 −10

modified data/stores.json +1 −1
@@ -91259,7 +91259,7 @@
91259 91259 "name": "Magill Hats",
91260 91260 "url": "https://magillhats.com",
91261 91261 "platform": "woocommerce",
91262 − "catalog_endpoint": "__generic__",
91262 + "catalog_endpoint": "/wp-json/wc/store/products",
91263 91263 "city": "",
91264 91264 "region": "Montréal",
91265 91265 "postal_prefix": "H2N",
modified fabrika/connectors/woocommerce.py +39 −9
@@ -20,18 +20,38 @@ class WooCommerceConnector(BaseConnector):
20 20 # l'API REST reste servie via la forme ?rest_route= (ex. colorantic.com).
21 21 _use_rest_route = False
22 22
23 + # Vieux WooCommerce (< 6.4) : la Store API n'est pas versionnée —
24 + # /wc/store/products répond mais /wc/store/v1/products donne rest_no_route
25 + # (ex. magillhats.com, restauré sur une vieille sauvegarde). Vide = sans /v1.
26 + _api_version = "v1"
27 +
23 28 def _store_api_url(self, path: str, query: str = "") -> str:
24 29 """URL Store API : /wp-json/wc/store/v1/<path> ou ?rest_route= en secours."""
30 + ver = f"{self._api_version}/" if self._api_version else ""
25 31 if self._use_rest_route:
26 32 sep = "&" if query else ""
27 − return f"{self.base}/?rest_route=/wc/store/v1/{path}{sep}{query}"
33 + return f"{self.base}/?rest_route=/wc/store/{ver}{path}{sep}{query}"
28 34 sep = "?" if query else ""
29 − return f"{self.base}/wp-json/wc/store/v1/{path}{sep}{query}"
35 + return f"{self.base}/wp-json/wc/store/{ver}{path}{sep}{query}"
30 36
31 37 def _get_items(self, url: str):
32 38 """JSON direct, sinon Scrapfly (Cloudflare & cie) en dernier recours."""
39 + import time as _time
33 40 try:
34 − r = self.get(url)
41 + for _attempt in range(8):
42 + try:
43 + r = self.get(url)
44 + break
45 + except Exception as exc508:
46 + code = getattr(getattr(exc508, "response", None), "status_code", None)
47 + # hébergement à bout de ressources (CloudLinux « Resource Limit
48 + # Is Reached » 508 / « Insufficient Storage » 507, ex.
49 + # magillhats.com) : intermittent — ~1 requête sur 7 passe,
50 + # indépendant de l'IP; réessayer brièvement plutôt qu'échouer
51 + if code in (507, 508) and _attempt < 7:
52 + _time.sleep(3)
53 + continue
54 + raise
35 55 try:
36 56 return r.json()
37 57 except ValueError:
@@ -331,18 +351,28 @@ class WooCommerceConnector(BaseConnector):
331 351 try:
332 352 items = self._get_items(self._store_api_url("products", f"per_page=100&page={page}"))
333 353 except Exception as exc:
334 − if page == 1 and not self._use_rest_route:
354 + if page != 1:
355 + break
356 + items = None
357 + if self._api_version:
358 + # vieux WooCommerce (< 6.4) : Store API non versionnée
359 + # /wc/store/products, la route /v1/ donne rest_no_route —
360 + # tenter quel que soit l'échec, un 508 intermittent peut
361 + # masquer le 404 (ex. magillhats.com)
362 + self._api_version = ""
363 + try:
364 + items = self._get_items(self._store_api_url("products", f"per_page=100&page={page}"))
365 + except Exception:
366 + self._api_version = "v1"
367 + if items is None and not self._use_rest_route:
335 368 # chemin /wp-json/ bloqué par l'hébergeur ? retenter via ?rest_route=
336 369 self._use_rest_route = True
337 370 try:
338 371 items = self._get_items(self._store_api_url("products", f"per_page=100&page={page}"))
339 372 except Exception:
340 373 self._use_rest_route = False
341 − first_page_exc = exc
342 − break
343 − else:
344 − if page == 1:
345 − first_page_exc = exc
374 + if items is None:
375 + first_page_exc = exc
346 376 break
347 377 if not isinstance(items, list) or not items:
348 378 break
349 379