Explore: personal GPS heatmap tab under Athlete page

- bincio/explore.py: bake_tracks() simplifies GPS coords (RDP ε=0.0001),
  strips to [lng,lat], groups by sport type, writes per-handle tracks.json
- bake-tracks CLI command; render CLI calls _bake_tracks() after each build;
  strava_zip runs it once at end of batch
- /api/me/tracks endpoint serves the baked file; wipe_user cleans it up
- Explore.svelte: MapLibre full-screen map with sidebar — type pills,
  year/month date filter, Lines / Heatmap (global or by-type) view modes
- AthleteView: Explore tab visible only to profile owner (checks __bincioMe)
- Base.astro: fullscreen prop + Planner nav link
This commit is contained in:
Davide Scaini
2026-05-14 14:31:21 +02:00
parent 2daa66d7b0
commit 5307ae287c
10 changed files with 607 additions and 10 deletions
+12 -2
View File
@@ -7,7 +7,7 @@ from pathlib import Path
from typing import Any
from fastapi import APIRouter, Cookie, HTTPException, Request
from fastapi.responses import JSONResponse
from fastapi.responses import JSONResponse, Response
from bincio.serve import deps, tasks
from bincio.serve.db import (
@@ -43,7 +43,7 @@ def _wipe_user_activities(user_dir: Path) -> int:
if d.exists():
shutil.rmtree(d)
for name in ("index.json", "athlete.json", ".bincio_cache.json"):
for name in ("index.json", "athlete.json", ".bincio_cache.json", "tracks.json"):
f = user_dir / name
if f.exists():
f.unlink()
@@ -52,6 +52,16 @@ def _wipe_user_activities(user_dir: Path) -> int:
return deleted
@router.get("/api/me/tracks")
async def me_tracks(bincio_session: str | None = Cookie(default=None)) -> Response:
"""Return the pre-baked tracks.json for the logged-in user (Explore page)."""
user = deps._require_user(bincio_session)
tracks_path = deps._get_data_dir() / user.handle / "tracks.json"
if not tracks_path.exists():
raise HTTPException(404, "Tracks not yet baked — upload an activity first")
return Response(content=tracks_path.read_bytes(), media_type="application/json")
@router.get("/api/me/storage")
async def me_storage(bincio_session: str | None = Cookie(default=None)) -> JSONResponse:
"""Return per-category disk usage for the logged-in user."""
+5
View File
@@ -487,6 +487,11 @@ async def upload_strava_zip(
user.handle, imported_count, error_count)
if any_imported:
merge_all(dd)
try:
from bincio.explore import bake_tracks
bake_tracks(user.handle, deps._get_data_dir())
except Exception as exc:
log.warning("strava-zip[%s]: bake_tracks failed (non-fatal): %s", user.handle, exc)
tasks._trigger_rebuild(user.handle)
except Exception as exc:
log.error("strava-zip[%s]: fatal error: %s", user.handle, exc, exc_info=True)