- Nouveau modèle SaintDuJour (mois+jour+saints_json, indépendant de l'année) - Router /api/saints et /api/saints/jour (mois+jour → liste de prénoms) - Script standalone import_webapp_db.py : saints_du_jour.json → saint_du_jour, dictons_du_jour.json → dicton ; modes replace/append, --dry-run, --region - Données JSON 366 jours : saints_du_jour.json + dictons_du_jour.json - Scripts scraping/export calendrier_lunaire/saints_dictons/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
114 lines
3.5 KiB
Python
114 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
|
|
|
|
def _parse_mmdd(mmdd: str) -> tuple[int, int]:
|
|
if len(mmdd) != 4 or not mmdd.isdigit():
|
|
raise ValueError(f"MMDD invalide: {mmdd}")
|
|
month = int(mmdd[:2])
|
|
day = int(mmdd[2:])
|
|
if not (1 <= month <= 12 and 1 <= day <= 31):
|
|
raise ValueError(f"MMDD hors plage: {mmdd}")
|
|
return month, day
|
|
|
|
|
|
def _as_list(value: object) -> list[str]:
|
|
if not value:
|
|
return []
|
|
if isinstance(value, list):
|
|
out: list[str] = []
|
|
for item in value:
|
|
txt = str(item).strip()
|
|
if txt and txt not in out:
|
|
out.append(txt)
|
|
return out
|
|
txt = str(value).strip()
|
|
return [txt] if txt else []
|
|
|
|
|
|
def export_files(source_file: Path, saints_out: Path, dictons_out: Path) -> tuple[int, int]:
|
|
source = json.loads(source_file.read_text(encoding="utf-8"))
|
|
rows = source.get("data", [])
|
|
saints_rows: list[dict] = []
|
|
dictons_rows: list[dict] = []
|
|
|
|
for row in rows:
|
|
mmdd = str(row.get("mmdd", "")).strip()
|
|
if not mmdd:
|
|
continue
|
|
try:
|
|
month, day = _parse_mmdd(mmdd)
|
|
except ValueError:
|
|
continue
|
|
|
|
saints = _as_list(row.get("saints"))
|
|
dictons = _as_list(row.get("dictons"))
|
|
source_url = row.get("source_url")
|
|
|
|
if saints:
|
|
saints_rows.append(
|
|
{
|
|
"mois": month,
|
|
"jour": day,
|
|
"saints": saints,
|
|
"source_url": source_url,
|
|
}
|
|
)
|
|
|
|
if dictons:
|
|
dictons_rows.append(
|
|
{
|
|
"mois": month,
|
|
"jour": day,
|
|
"dictons": dictons,
|
|
"source_url": source_url,
|
|
}
|
|
)
|
|
|
|
saints_rows.sort(key=lambda r: (r["mois"], r["jour"]))
|
|
dictons_rows.sort(key=lambda r: (r["mois"], r["jour"]))
|
|
|
|
saints_out.parent.mkdir(parents=True, exist_ok=True)
|
|
dictons_out.parent.mkdir(parents=True, exist_ok=True)
|
|
saints_out.write_text(json.dumps(saints_rows, ensure_ascii=False, indent=2), encoding="utf-8")
|
|
dictons_out.write_text(json.dumps(dictons_rows, ensure_ascii=False, indent=2), encoding="utf-8")
|
|
return len(saints_rows), len(dictons_rows)
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(
|
|
description="Génère saints_du_jour.json et dictons_du_jour.json depuis saints_YYYY.json."
|
|
)
|
|
parser.add_argument(
|
|
"--source",
|
|
default="calendrier_lunaire/saints_dictons/saints_2026.json",
|
|
help="Source JSON issue du scraper annuel",
|
|
)
|
|
parser.add_argument(
|
|
"--saints-out",
|
|
default="calendrier_lunaire/saints_dictons/saints_du_jour.json",
|
|
help="Fichier JSON de sortie pour les saints",
|
|
)
|
|
parser.add_argument(
|
|
"--dictons-out",
|
|
default="calendrier_lunaire/saints_dictons/dictons_du_jour.json",
|
|
help="Fichier JSON de sortie pour les dictons",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
source_file = Path(args.source)
|
|
saints_out = Path(args.saints_out)
|
|
dictons_out = Path(args.dictons_out)
|
|
saints_count, dictons_count = export_files(source_file, saints_out, dictons_out)
|
|
print(f"Saints exportés : {saints_count} jours -> {saints_out}")
|
|
print(f"Dictons exportés : {dictons_count} jours -> {dictons_out}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|