Files
2026-07-27 10:05:29 -04:00

94 lines
2.9 KiB
Python

#!/usr/bin/env python3
"""
Download GPX files for your Garmin Connect activities.
Setup:
pip install garminconnect
Usage:
python garmin_gpx_export.py
You'll be prompted for your Garmin Connect email and password
(the same ones you use to log into connect.garmin.com).
Credentials are only used locally to authenticate with Garmin's
servers and are never stored or sent anywhere else.
"""
import getpass
import os
from datetime import datetime
from garminconnect import Garmin, GarminConnectAuthenticationError
def get_mfa_code():
"""Called automatically by garminconnect if Garmin requests an MFA code."""
return input("Enter the MFA code sent to you by Garmin: ").strip()
def main():
# --- Login ---
email = input("Garmin Connect email: ").strip()
password = getpass.getpass("Garmin Connect password: ")
try:
client = Garmin(email=email, password=password, prompt_mfa=get_mfa_code)
client.login()
except GarminConnectAuthenticationError:
print("Login failed. Check your email/password/MFA code.")
return
print(f"Logged in as {client.get_full_name()}")
# --- Config ---
output_dir = "garmin_gpx_exports"
os.makedirs(output_dir, exist_ok=True)
# How many recent activities to check (increase if you want more history)
limit = 50
# Only export activities matching this type, or set to None for all types.
# Common values: "cycling", "running", "walking", "hiking", "swimming"
activity_type_filter = "cycling"
# --- Fetch activity list ---
activities = client.get_activities(0, limit)
print(f"Found {len(activities)} recent activities (checking up to {limit}).")
exported = 0
for act in activities:
act_type = act.get("activityType", {}).get("typeKey", "")
if activity_type_filter and activity_type_filter not in act_type:
continue
activity_id = act["activityId"]
start_time = act.get("startTimeLocal", "unknown_time")
name = act.get("activityName", "activity")
# Sanitize filename
safe_time = start_time.replace(":", "-").replace(" ", "_")
safe_name = "".join(c for c in name if c.isalnum() or c in (" ", "_", "-")).strip()
filename = f"{safe_time}_{safe_name}_{activity_id}.gpx"
filepath = os.path.join(output_dir, filename)
if os.path.exists(filepath):
print(f" Skipping (already downloaded): {filename}")
continue
try:
gpx_data = client.download_activity(
activity_id, dl_fmt=client.ActivityDownloadFormat.GPX
)
with open(filepath, "wb") as f:
f.write(gpx_data)
print(f" Saved: {filename}")
exported += 1
except Exception as e:
print(f" Failed to export activity {activity_id}: {e}")
print(f"\nDone. Exported {exported} new GPX file(s) to ./{output_dir}/")
if __name__ == "__main__":
main()