Nouvelle source de recettes : quitoque.fr #37
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Contexte
Ajouter https://www.quitoque.fr/recettes comme nouvelle source de recettes
importable, au même titre que TheMealDB/Marmiton/750g/Manger Bouger.
Ce n'est pas un cas neuf : le repo a déjà 4 adaptateurs enregistrés
(
apps/api/src/sources/) — TheMealDB (API officielle) et trois sitesfrançais scrapés (Marmiton, 750g, Manger Bouger), tous construits sur un
même bloc générique
jsonLdRecipeAdapter(json-ld-recipe.ts) qui lit lesdonnées structurées
schema.org/Recipeque la plupart des sites de recettesembarquent en JSON-LD pour Google. Le précédent le plus proche pour Quitoque
est Marmiton (
marmiton.ts) — le plus fin des 3 wrappers scrapés :fetchDetail/parsedélégués tels quels au bloc générique, seullist()étant spécifique au site.
(Note en passant, hors sujet de ce ticket :
specs/backend-architecture.md— section "Sources externes", ~lignes 500-600 — est obsolète, elle ne
documente que TheMealDB + le bloc générique et affirme à tort que
registerAllRecipeSources()"n'enregistre aujourd'hui que TheMealDB". Levrai code (
apps/api/src/sources/index.ts) enregistre déjà les 4. Ne pasmélanger ce rattrapage avec ce ticket — seule la section Quitoque doit y
être ajoutée ici.)
Vérifications effectuées sur quitoque.fr
Vérifié en direct (navigateur) plutôt que deviné :
https://www.quitoque.fr/robots.txt) :/recettesn'apparaît dans aucun
disallow— autorisé pouruser-agent: *etexplicitement listé
allow: /pourClaudeBot/GPTBot/PerplexityBot/Google-Extendednommément. Aucun des 3 adaptateurs scrapés existants nedocumente une vérification robots.txt/CGU — celle-ci va donc plus loin
que le précédent du repo, dans le bon sens.
/recettes/<slug>) : contient un bloc<script type="application/ld+json">avec unRecipeschema.org completet propre (vérifié sur "Mijoté de lentilles vertes au lait de coco et
chou romanesco") :
name,description,image,prepTime/totalTime(ISO 8601),
recipeYield: "2",recipeIngredient: ["150 g lentilles vertes (Bio)", "1 gousse d'ail", "0.5 citron jaune (Bio)", "1 à 3 cm gingembre", ...],recipeInstructionsenHowToStep[](name+textpar étape). Le nœud
Recipeest le seul élément d'un tableau JSON-LD depremier niveau (
[{...}]), pas un objet nu.json-ld-recipe.ts:79-92) que ce tableaude premier niveau est déjà géré tel quel par
findRecipeNode(boucle surArray.isArray(node)avant de chercher@type === "Recipe") →jsonLdRecipeAdapter.parsedevrait fonctionner sans aucune retouche surles pages Quitoque, exactement comme Marmiton (délégation intégrale,
zéro patch — contrairement à 750g/Manger Bouger qui corrigent chacun un
vrai bug du JSON-LD de leur site).
extractPortionsgère déjà"2"(regex
\d+) ;flattenInstructionsgère déjàHowToStep[](prend.text, donc le titre "1. Les légumes" de chaque étape serasilencieusement ignoré — comportement identique pour n'importe quel
autre site, pas une régression propre à Quitoque).
/recettes) : 2711 recettes, paginée. Contrairement àMarmiton, pas de
ItemListJSON-LD sur cette page (vérifié : seulOrganizationy est présent) — le pattern Marmiton (lire unItemListembarqué) ne s'applique donc pas tel quel. En revanche :
/recettes?page=2renvoie une pagedifférente (mêmes "2711 produits" annoncés, second lot de cartes) — un
simple paramètre
?page=N, comme le&page=Nde Marmiton.750g (qui doit apparier un
<img>et un<a class="card-link">voisins) : un seul élément
<a class="card__content_header" href="/recettes/<slug>">contient à la fois le lien et un<img alt="<titre réel>" data-src="<url image réelle>">— ⚠️ l'imageréelle est dans
data-src,srcn'est qu'un placeholder lazy-load.DOM, ni d'effet d'un
?q=poulettesté en direct (résultats strictementidentiques à la page non filtrée) — seul un filtre par tags visible
("Filtrer" : Végétarien, Express, Kids friendly...), pas une recherche
libre. Lacune de même nature que celle déjà assumée/documentée pour
750g — pas un blocage, juste à documenter pareillement pour Quitoque.
Marmiton, une page qui ne renvoie aucune carte est le signal de fin
(
nextCursor: null).Conception proposée
Nouveau fichier
apps/api/src/sources/quitoque.ts, calqué surmarmiton.ts:rekeySourceError: dupliquer le petit helper privé demarmiton.ts:73-81(pas exporté du module — 750g et Manger Bouger en ont chacun leur propre
copie aujourd'hui ; pas la peine de le factoriser pour ce ticket).
Ingrédients :
recipeIngredientalimenteParsedRecipeIngredient.rawText/.nametel quel (comme Marmiton/750g/Manger Bouger) — la résolution réellevers le catalogue (
matchIngredientName/matchUnit/extractQuantity,ingredient-matcher.ts, déjà générique et déjà éprouvé en français par les3 adaptateurs existants) se fait plus loin dans le pipeline
(
previewSourceItem,sources.service.ts), pas dans l'adaptateur — rien denouveau à construire là. Deux formulations Quitoque à surveiller (pas à
corriger dans l'adaptateur, juste à vérifier une fois de vraies recettes
importées) : le qualificatif entre parenthèses ("(Bio)") et une quantité en
plage ("1 à 3 cm gingembre") — au pire ces lignes finissent en ingrédient
non résolu, dans le flux de revue manuelle déjà existant
(
RecipeImportForm/tryBuildCompleteImport), pas un blocage.Fichiers à toucher
apps/api/src/sources/quitoque.ts(nouveau) — l'adaptateur ci-dessus.apps/api/src/sources/index.ts— ajouteregisterRecipeSource(quitoqueAdapter)dans
registerAllRecipeSources().apps/api/test/recipe-sources/quitoque.test.ts(nouveau) — mêmeconvention
stubFetchHtml/globalThis.fetchquemarmiton.test.ts/750g.test.ts/manger-bouger.test.ts(Mocha + Chai, pas de lib de mockHTTP). Cas à couvrir :
list()parse bien les cartes d'une page HTMLfixture, gère une page vide (fin de liste), filtre par
query;fetchDetail/parsedélèguent bien et re-labellisentsourceKeyen casd'erreur ;
parsesur une fixture JSON-LD réelle (tableau de premierniveau, forme Quitoque) produit les bons
portions/ingredients/steps.specs/backend-architecture.md— ajoute la section Quitoque au mêmeformat que les autres adaptateurs (sans corriger au passage la
description déjà obsolète des 3 autres — voir la note en Contexte).
Hors scope
(aucune trouvée à ce stade).
si un futur 6e site en a besoin ; pour l'instant chaque adaptateur scrapé
garde sa propre logique de
list(), cohérent avec 750g/Manger Bouger.dans
specs/backend-architecture.md(voir note en Contexte).🤖 Filed by Claude Code