import argparse import getpass from garminexport.garminclient import GarminClient import json import logging import sys logging.basicConfig(level=logging.INFO, format="%(asctime)-15s [%(levelname)s] %(message)s") log = logging.getLogger(__name__) if __name__ == "__main__": parser = argparse.ArgumentParser() # positional args parser.add_argument( "username", metavar="<username>", type=str, help="Account user name.") # optional args parser.add_argument( "--password", type=str, help="Account password.") args = parser.parse_args() print(args) if not args.password: args.password = getpass.getpass("Enter password: "******"client object ready for use.")
def incremental_backup(username: str, password: str = None, user_agent_fn: Callable[[],str] = None, backup_dir: str = os.path.join(".", "activities"), export_formats: List[str] = None, ignore_errors: bool = False, max_retries: int = 7): """Performs (incremental) backups of activities for a given Garmin Connect account. :param username: Garmin Connect user name :param password: Garmin Connect user password. Default: None. If not provided, would be asked interactively. :keyword user_agent_fn: A function that, when called, produces a `User-Agent` string to be used as `User-Agent` for the remainder of the session. If set to None, the default user agent of the http request library is used. :type user_agent_fn: Callable[[], str] :param backup_dir: Destination directory for downloaded activities. Default: ./activities/". :param export_formats: List of desired output formats (json_summary, json_details, gpx, tcx, fit). Default: `None` which means all supported formats will be backed up. :param ignore_errors: Ignore errors and keep going. Default: False. :param max_retries: The maximum number of retries to make on failed attempts to fetch an activity. Exponential backoff will be used, meaning that the delay between successive attempts will double with every retry, starting at one second. Default: 7. The activities are stored in a local directory on the user's computer. The backups are incremental, meaning that only activities that aren't already stored in the backup directory will be downloaded. """ # if no --format was specified, all formats are to be backed up export_formats = export_formats if export_formats else supported_export_formats log.info("backing up formats: %s", ", ".join(export_formats)) if not os.path.isdir(backup_dir): os.makedirs(backup_dir) if not password: password = getpass.getpass("Enter password: "******"scanning activities for %s ...", username) activities = set(retryer.call(client.list_activities)) log.info("account has a total of %d activities", len(activities)) missing_activities = garminexport.backup.need_backup(activities, backup_dir, export_formats) backed_up = activities - missing_activities log.info("%s contains %d backed up activities", backup_dir, len(backed_up)) log.info("activities that aren't backed up: %d", len(missing_activities)) for index, activity in enumerate(missing_activities): id, start = activity if id not in [578518094]: log.info("backing up activity %s from %s (%d out of %d) ...", id, start, index + 1, len(missing_activities)) try: garminexport.backup.download(client, activity, retryer, backup_dir, export_formats) except Exception as e: log.error("failed with exception: %s", e) if not ignore_errors: raise # gewicht herunterladen import urllib.request, json import datetime import time WeightURL = "https://connect.garmin.com/modern/proxy/userprofile-service/userprofile/personal-information/weightWithOutbound/filterByDay?from="+str(int(datetime.datetime(2008,1,1,0,0).timestamp()))+"999"+"&until="+str(int(time.time()))+"999" response = client.session.get(WeightURL) if response.status_code in (404, 204): log.info("failed to download weight 404,204") if response.status_code != 200: log.info("failed to download weight ungleich 200") else: data = json.loads(response.text) heute = datetime.date.today() with open(os.path.join(backup_dir,'weight_'+str(heute.year)+'-'+str(heute.month)+'-'+str(heute.day)+'.json'), 'w') as outfile: json.dump(data,outfile)
def incremental_backup(username: str, password: str = None, backup_dir: str = os.path.join(".", "activities"), export_formats: List[str] = None, ignore_errors: bool = False, max_retries: int = 7): """Performs (incremental) backups of activities for a given Garmin Connect account. :param username: Garmin Connect user name :param password: Garmin Connect user password. Default: None. If not provided, would be asked interactively. :param backup_dir: Destination directory for downloaded activities. Default: ./activities/". :param export_formats: List of desired output formats (json_summary, json_details, gpx, tcx, fit). Default: `None` which means all supported formats will be backed up. :param ignore_errors: Ignore errors and keep going. Default: False. :param max_retries: The maximum number of retries to make on failed attempts to fetch an activity. Exponential backoff will be used, meaning that the delay between successive attempts will double with every retry, starting at one second. Default: 7. The activities are stored in a local directory on the user's computer. The backups are incremental, meaning that only activities that aren't already stored in the backup directory will be downloaded. """ # if no --format was specified, all formats are to be backed up export_formats = export_formats if export_formats else supported_export_formats log.info("backing up formats: %s", ", ".join(export_formats)) if not os.path.isdir(backup_dir): os.makedirs(backup_dir) if not password: password = getpass.getpass("Enter password: "******"scanning activities for %s ...", username) activities = set(retryer.call(client.list_activities)) log.info("account has a total of %d activities", len(activities)) missing_activities = garminexport.backup.need_backup( activities, backup_dir, export_formats) backed_up = activities - missing_activities log.info("%s contains %d backed up activities", backup_dir, len(backed_up)) log.info("activities that aren't backed up: %d", len(missing_activities)) for index, activity in enumerate(missing_activities): id, start = activity log.info("backing up activity %s from %s (%d out of %d) ...", id, start, index + 1, len(missing_activities)) try: garminexport.backup.download(client, activity, retryer, backup_dir, export_formats) except Exception as e: log.error("failed with exception: %s", e) if not ignore_errors: raise
parser.add_argument( "--log-level", metavar="LEVEL", type=str, help=("Desired log output level (DEBUG, INFO, WARNING, ERROR). " "Default: INFO."), default="INFO") args = parser.parse_args() if len(args.activity)>1 and (args.description is not None or args.name is not None): parser.error("When uploading multiple activities, --name or --description cannot be used.") if not args.log_level in LOG_LEVELS: raise ValueError("Illegal log-level argument: {}".format( args.log_level)) logging.root.setLevel(LOG_LEVELS[args.log_level]) try: if not args.password: args.password = getpass.getpass("Enter password: "******"uploading activity file {} ...".format(activity.name)) try: id = client.upload_activity(activity, name=args.name, description=args.description, private=args.private, activity_type=args.type) except Exception as e: log.error("upload failed: {!r}".format(e)) else: log.info("upload successful: https://connect.garmin.com/modern/activity/{}".format(id)) except Exception as e: exc_type, exc_value, exc_traceback = sys.exc_info() log.error(u"failed with exception: %s", e) raise