dropped garminexport.py in favor of the incremental_backup.py script, now renamed to garminbackup.py
This commit is contained in:
parent
71c95330ba
commit
012c029c83
75
README.md
75
README.md
@ -1,15 +1,19 @@
|
|||||||
Garmin Connect activity exporter
|
Garmin Connect activity backup tool
|
||||||
================================
|
===================================
|
||||||
``garminexport.py`` is a program that downloads *all*
|
``garminbackup.py`` is a program that downloads activities for a
|
||||||
activities for a given [Garmin Connect](http://connect.garmin.com/)
|
given [Garmin Connect](http://connect.garmin.com/) account and stores
|
||||||
account and stores them in a backup directory locally on the user's
|
them in a backup directory locally on the user's computer. The first time
|
||||||
computer.
|
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
|
The library contains a simple utility program, ``get_activity.py`` for
|
||||||
of your account. This script only downloads
|
downloading a single Garmin Connect activity. Run ``./get_activity.py --help``
|
||||||
activities that haven't already been downloaded to a certain backup directory.
|
for more details.
|
||||||
It is typically a quicker alternative (except for the first time when all
|
|
||||||
activities will need to be downloaded).
|
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
|
Prerequisites
|
||||||
@ -35,46 +39,41 @@ Install the required dependencies in this virtual environment:
|
|||||||
pip install -r requirements.txt
|
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 <username or email>
|
Running
|
||||||
|
=======
|
||||||
|
The backup program is run as follows (use the ``--help`` flag for a full list
|
||||||
|
of available options):
|
||||||
|
|
||||||
|
./garminbackup.py --backup-dir=activities <username or email>
|
||||||
|
|
||||||
Once started, the program will prompt you for your account password and then
|
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
|
log in to your Garmin Connect account to download activities to the specified
|
||||||
destination directory on your machine.
|
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
|
- ``fit``: activity FIT file (binary format).
|
||||||
been entered manually rather than imported from a Garmin device).
|
*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).
|
All files are written to the same directory (``activities/`` by default).
|
||||||
Each activity file is prefixed by its upload timestamp and its
|
Each activity file is prefixed by its upload timestamp and its activity id.
|
||||||
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 <username or email>
|
|
||||||
|
|
||||||
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
|
Library import
|
||||||
==============
|
==============
|
||||||
|
@ -33,9 +33,7 @@ def get_backed_up(activities, backup_dir, formats):
|
|||||||
|
|
||||||
:rtype: list of int
|
:rtype: list of int
|
||||||
"""
|
"""
|
||||||
# backed up activities follow this pattern: <ISO8601>_<id>_summary.json
|
# backed up activities follow this pattern: <ISO8601>_<id>_<suffix>
|
||||||
activity_file_pattern = r'[\d:T\+\-]+_([0-9]+).tcx'
|
|
||||||
|
|
||||||
format_suffix = dict(json_summary="_summary.json", json_details="_details.json", gpx=".gpx", tcx=".tcx", fit=".fit")
|
format_suffix = dict(json_summary="_summary.json", json_details="_details.json", gpx=".gpx", tcx=".tcx", fit=".fit")
|
||||||
|
|
||||||
backed_up = set()
|
backed_up = set()
|
@ -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="<username>", 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
|
|
Loading…
Reference in New Issue
Block a user