records: exclude indoor/treadmill/virtual sub_sport; rebuild athlete.json on bake
- fit.py: map FIT sub_sport 'treadmill' and 'virtual' to 'indoor' - writer.py: broaden _is_outdoor to catch all indoor sub_sport variants - render/cli.py: rebuild athlete.json from index.json on every bake so records never go stale when the exclusion logic changes
This commit is contained in:
@@ -147,11 +147,13 @@ def _normalise_sub_sport(value: Any) -> str | None:
|
|||||||
mapping = {
|
mapping = {
|
||||||
"generic": None, # FIT default — unspecified
|
"generic": None, # FIT default — unspecified
|
||||||
"virtual_activity": "indoor",
|
"virtual_activity": "indoor",
|
||||||
|
"virtual": "indoor",
|
||||||
"road": "road",
|
"road": "road",
|
||||||
"mountain": "mountain",
|
"mountain": "mountain",
|
||||||
"gravel_cycling": "gravel",
|
"gravel_cycling": "gravel",
|
||||||
"cyclocross": "gravel",
|
"cyclocross": "gravel",
|
||||||
"indoor_cycling": "indoor",
|
"indoor_cycling": "indoor",
|
||||||
|
"treadmill": "indoor",
|
||||||
"trail": "trail",
|
"trail": "trail",
|
||||||
"track": "track",
|
"track": "track",
|
||||||
"cross_country_skiing": "nordic",
|
"cross_country_skiing": "nordic",
|
||||||
|
|||||||
@@ -277,8 +277,10 @@ def write_athlete_json(summaries: list[dict], output_dir: Path, athlete_config:
|
|||||||
best[d] = w
|
best[d] = w
|
||||||
return [[d, w] for d, w in sorted(best.items())]
|
return [[d, w] for d, w in sorted(best.items())]
|
||||||
|
|
||||||
|
_INDOOR_SUB_SPORTS = {"indoor", "treadmill", "virtual"}
|
||||||
|
|
||||||
def _is_outdoor(s: dict) -> bool:
|
def _is_outdoor(s: dict) -> bool:
|
||||||
return s.get("sub_sport") != "indoor"
|
return s.get("sub_sport") not in _INDOOR_SUB_SPORTS
|
||||||
|
|
||||||
all_mmps = [s["mmp"] for s in summaries if s.get("mmp") and _is_outdoor(s)]
|
all_mmps = [s["mmp"] for s in summaries if s.get("mmp") and _is_outdoor(s)]
|
||||||
mmps_365 = [s["mmp"] for s in summaries if s.get("mmp") and _is_outdoor(s) and s["started_at"] >= cutoff_365]
|
mmps_365 = [s["mmp"] for s in summaries if s.get("mmp") and _is_outdoor(s) and s["started_at"] >= cutoff_365]
|
||||||
|
|||||||
@@ -105,6 +105,35 @@ def _bake_tracks(data: Path, handle: str | None = None) -> None:
|
|||||||
console.print(f" [yellow]{user_dir.name}[/yellow]: bake_tracks failed: {exc}")
|
console.print(f" [yellow]{user_dir.name}[/yellow]: bake_tracks failed: {exc}")
|
||||||
|
|
||||||
|
|
||||||
|
def _rebuild_athlete_json(data: Path, handle: str | None = None) -> None:
|
||||||
|
"""Rebuild athlete.json for one user or all users from their current index.json."""
|
||||||
|
import json
|
||||||
|
from bincio.extract.writer import write_athlete_json
|
||||||
|
|
||||||
|
targets = [data / handle] if handle else _user_dirs(data)
|
||||||
|
_COMPUTED = {"bas_version", "generated_at", "power_curve", "records", "best_climbs"}
|
||||||
|
for user_dir in targets:
|
||||||
|
index_path = user_dir / "index.json"
|
||||||
|
if not index_path.exists():
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
index_data = json.loads(index_path.read_text(encoding="utf-8"))
|
||||||
|
summaries = index_data.get("activities", [])
|
||||||
|
if not summaries:
|
||||||
|
continue
|
||||||
|
athlete_config: dict = {}
|
||||||
|
athlete_path = user_dir / "athlete.json"
|
||||||
|
if athlete_path.exists():
|
||||||
|
try:
|
||||||
|
existing = json.loads(athlete_path.read_text(encoding="utf-8"))
|
||||||
|
athlete_config = {k: v for k, v in existing.items() if k not in _COMPUTED}
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
write_athlete_json(summaries, user_dir, athlete_config)
|
||||||
|
except Exception as exc:
|
||||||
|
console.print(f" [yellow]{user_dir.name}[/yellow]: rebuild_athlete failed: {exc}")
|
||||||
|
|
||||||
|
|
||||||
def _write_root_manifest(data: Path) -> None:
|
def _write_root_manifest(data: Path) -> None:
|
||||||
"""Rewrite the root index.json shard manifest from current user dirs."""
|
"""Rewrite the root index.json shard manifest from current user dirs."""
|
||||||
import json
|
import json
|
||||||
@@ -207,6 +236,7 @@ def render(
|
|||||||
console.print(f"Data: [cyan]{data}[/cyan]")
|
console.print(f"Data: [cyan]{data}[/cyan]")
|
||||||
|
|
||||||
_merge_edits(data, handle=handle)
|
_merge_edits(data, handle=handle)
|
||||||
|
_rebuild_athlete_json(data, handle=handle)
|
||||||
_bake_tracks(data, handle=handle)
|
_bake_tracks(data, handle=handle)
|
||||||
_write_root_manifest(data)
|
_write_root_manifest(data)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user