athlete page first draft
This commit is contained in:
@@ -68,6 +68,7 @@ def write_activity(
|
||||
"bbox": list(metrics.bbox) if metrics.bbox else None,
|
||||
"start_latlng": list(metrics.start_latlng) if metrics.start_latlng else None,
|
||||
"end_latlng": list(metrics.end_latlng) if metrics.end_latlng else None,
|
||||
"mmp": metrics.mmp,
|
||||
"laps": [_serialise_lap(lap) for lap in activity.laps],
|
||||
"timeseries": build_timeseries(activity.points, activity.started_at, privacy),
|
||||
"source": source,
|
||||
@@ -115,6 +116,7 @@ def build_summary(
|
||||
"max_hr_bpm": metrics.max_hr_bpm,
|
||||
"avg_cadence_rpm": metrics.avg_cadence_rpm,
|
||||
"avg_power_w": metrics.avg_power_w,
|
||||
"mmp": metrics.mmp,
|
||||
"source": _infer_source(activity),
|
||||
"privacy": privacy,
|
||||
"detail_url": f"activities/{activity_id}.json",
|
||||
@@ -124,6 +126,56 @@ def build_summary(
|
||||
}
|
||||
|
||||
|
||||
def write_athlete_json(summaries: list[dict], output_dir: Path, athlete_config: dict) -> None:
|
||||
"""Aggregate per-activity MMP curves into athlete.json.
|
||||
|
||||
Computes element-wise max MMP for:
|
||||
- all_time
|
||||
- last_365d
|
||||
- last_90d
|
||||
|
||||
The site reads this single file for the athlete/power-curve page.
|
||||
Per-activity mmp is already in each summary for client-side season filtering.
|
||||
"""
|
||||
from datetime import datetime, timezone
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
def _cutoff_iso(days: int) -> str:
|
||||
from datetime import timedelta
|
||||
return (now - timedelta(days=days)).isoformat()
|
||||
|
||||
cutoff_365 = _cutoff_iso(365)
|
||||
cutoff_90 = _cutoff_iso(90)
|
||||
|
||||
def _merge_mmps(activity_mmps: list[list[list[int]]]) -> list[list[int]]:
|
||||
"""Element-wise max across a list of mmp arrays."""
|
||||
best: dict[int, int] = {}
|
||||
for mmp in activity_mmps:
|
||||
for d, w in mmp:
|
||||
if d not in best or w > best[d]:
|
||||
best[d] = w
|
||||
return [[d, w] for d, w in sorted(best.items())]
|
||||
|
||||
all_mmps = [s["mmp"] for s in summaries if s.get("mmp")]
|
||||
mmps_365 = [s["mmp"] for s in summaries if s.get("mmp") and s["started_at"] >= cutoff_365]
|
||||
mmps_90 = [s["mmp"] for s in summaries if s.get("mmp") and s["started_at"] >= cutoff_90]
|
||||
|
||||
athlete = {
|
||||
"bas_version": "1.0",
|
||||
"generated_at": now.isoformat(),
|
||||
"power_curve": {
|
||||
"all_time": _merge_mmps(all_mmps) if all_mmps else None,
|
||||
"last_365d": _merge_mmps(mmps_365) if mmps_365 else None,
|
||||
"last_90d": _merge_mmps(mmps_90) if mmps_90 else None,
|
||||
},
|
||||
**athlete_config,
|
||||
}
|
||||
(output_dir / "athlete.json").write_text(
|
||||
json.dumps(athlete, indent=2, ensure_ascii=False)
|
||||
)
|
||||
|
||||
|
||||
def write_index(summaries: list[dict], output_dir: Path, owner: dict) -> None:
|
||||
"""Write index.json (sorted newest first)."""
|
||||
sorted_summaries = sorted(
|
||||
|
||||
Reference in New Issue
Block a user