From 012c029c836178ac230f07fd9b3fc16d18718d93 Mon Sep 17 00:00:00 2001 From: petergardfjall Date: Sat, 21 Feb 2015 18:10:43 +0100 Subject: [PATCH] dropped garminexport.py in favor of the incremental_backup.py script, now renamed to garminbackup.py --- README.md | 75 +++++++++++----------- incremental_backup.py => garminbackup.py | 4 +- garminexport.py | 82 ------------------------ 3 files changed, 38 insertions(+), 123 deletions(-) rename incremental_backup.py => garminbackup.py (97%) delete mode 100755 garminexport.py diff --git a/README.md b/README.md index 6cf8fbe..7045b9c 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,19 @@ -Garmin Connect activity exporter -================================ -``garminexport.py`` is a program that downloads *all* -activities for a given [Garmin Connect](http://connect.garmin.com/) -account and stores them in a backup directory locally on the user's -computer. +Garmin Connect activity backup tool +=================================== +``garminbackup.py`` is a program that downloads activities for a +given [Garmin Connect](http://connect.garmin.com/) account and stores +them in a backup directory locally on the user's computer. The first time +the program is run, it will download *all* activities. After that, it will +do incremental backups of your account. That is, the script will only download +activities that haven't already been downloaded to the backup directory. -The ``incremental_backup.py`` program can be used for incremental backups - of your account. This script only downloads -activities that haven't already been downloaded to a certain backup directory. -It is typically a quicker alternative (except for the first time when all -activities will need to be downloaded). +The library contains a simple utility program, ``get_activity.py`` for +downloading a single Garmin Connect activity. Run ``./get_activity.py --help`` +for more details. + +The library also contains a ``garminclient`` module that could be used by third-party +projects that need to communicate over the Garmin Connect API. See the +Library Import section below for more details. Prerequisites @@ -35,46 +39,41 @@ Install the required dependencies in this virtual environment: pip install -r requirements.txt -Running the export program -========================== -The export program is run as follows (use the ``--help`` flag for a list of -available options). - ./garminexport.py +Running +======= +The backup program is run as follows (use the ``--help`` flag for a full list +of available options): + + ./garminbackup.py --backup-dir=activities Once started, the program will prompt you for your account password and then -log in to your Garmin Connect account to download *all* activities to a -destination directory on your machine. +log in to your Garmin Connect account to download activities to the specified +backup directory on your machine. The program will only download activities +that aren't already in the backup directory. -For each activity, these files are stored: +Activities can be exported in any of the formats outlined below. Note that +by default, the program downloads all formats for every activity. Use the +``--format`` option to narrow the selection. - - an activity summary file (JSON) +Supported export formats: + + - ``json_summary``: activity summary file (JSON) - - an activity details file (JSON) + - ``json_details``: activity details file (JSON) - - an activity GPX file (XML) + - ``gpx``: activity GPX file (XML) - - an activity TCX file (XML) + - ``tcx``: an activity TCX file (XML) - - an activity FIT file (binary) (if available -- the activity may have - been entered manually rather than imported from a Garmin device). + - ``fit``: activity FIT file (binary format). + *Note: a ``.fit`` file may not always be possible to export, for example + if an activity was entered manually rather than imported from a Garmin device.* All files are written to the same directory (``activities/`` by default). -Each activity file is prefixed by its upload timestamp and its -activity id. +Each activity file is prefixed by its upload timestamp and its activity id. -Running the incremental backup program -====================================== -The incremental backup program is run in a similar fashion to the export -program (use the ``--help`` flag for a list of available options): - - ./incremental_backup.py --backup-dir=activities - -In this example, it will only download activities that aren't already in -the ``activities/`` directory. Note: The incremental backup program saves -the same files for each activity as the export program (see above). - Library import ============== diff --git a/incremental_backup.py b/garminbackup.py similarity index 97% rename from incremental_backup.py rename to garminbackup.py index b0c7db9..19b865b 100755 --- a/incremental_backup.py +++ b/garminbackup.py @@ -33,9 +33,7 @@ def get_backed_up(activities, backup_dir, formats): :rtype: list of int """ - # backed up activities follow this pattern: __summary.json - activity_file_pattern = r'[\d:T\+\-]+_([0-9]+).tcx' - + # backed up activities follow this pattern: __ format_suffix = dict(json_summary="_summary.json", json_details="_details.json", gpx=".gpx", tcx=".tcx", fit=".fit") backed_up = set() diff --git a/garminexport.py b/garminexport.py deleted file mode 100755 index fe01946..0000000 --- a/garminexport.py +++ /dev/null @@ -1,82 +0,0 @@ -#! /usr/bin/env python -"""A program that downloads all activities for a given Garmin Connect account -and stores them locally on the user's computer. -""" -import argparse -import getpass -from garminexport.garminclient import GarminClient -import garminexport.util -import logging -import os -import sys -import traceback - -logging.basicConfig( - level=logging.INFO, format="%(asctime)-15s [%(levelname)s] %(message)s") -log = logging.getLogger(__name__) - -LOG_LEVELS = { - "DEBUG": logging.DEBUG, - "INFO": logging.INFO, - "WARNING": logging.WARNING, - "ERROR": logging.ERROR -} -"""Command-line (string-based) log-level mapping to logging module levels.""" - - -if __name__ == "__main__": - - parser = argparse.ArgumentParser( - description="Downloads all activities for a given Garmin Connect account.") - # positional args - parser.add_argument( - "username", metavar="", type=str, help="Account user name.") - # optional args - parser.add_argument( - "--password", type=str, help="Account password.") - parser.add_argument( - "--destination", metavar="DIR", type=str, - help=("Destination directory for downloaded activities. Default: " - "./activities/"), default=os.path.join(".", "activities")) - parser.add_argument( - "--log-level", metavar="LEVEL", type=str, - help=("Desired log output level (DEBUG, INFO, WARNING, ERROR). " - "Default: INFO."), default="INFO") - parser.add_argument( - "-f", "--format", choices=garminexport.util.export_formats, - default=None, action='append', - help=("Desired output formats ("+', '.join(garminexport.util.export_formats)+"). " - "Default: ALL.")) - parser.add_argument( - "-E", "--ignore-errors", action='store_true', - help="Ignore errors and keep going. Default: FALSE") - - args = parser.parse_args() - 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 os.path.isdir(args.destination): - os.makedirs(args.destination) - - if not args.password: - args.password = getpass.getpass("Enter password: ") - - with GarminClient(args.username, args.password) as client: - log.info("fetching activities for {} ...".format(args.username)) - all_activities = client.list_activities() - for index, (id, start) in enumerate(activity_ids): - log.info("processing activity {} from {} ({} out of {}) ...".format( - id, start, index+1, len(activity_ids))) - try: - garminexport.util.export_activity( - client, id, args.backup_dir, args.format) - except Exception as e: - log.error(u"failed with exception: %s", e) - if not args.ignore_errors: - raise - except Exception as e: - exc_type, exc_value, exc_traceback = sys.exc_info() - log.error(u"failed with exception: %s", e) - raise