add upload_activity client method and upload_activity.py example
This commit is contained in:
parent
c91568d302
commit
c5feaf86c2
@ -12,6 +12,7 @@ from StringIO import StringIO
|
|||||||
import sys
|
import sys
|
||||||
import zipfile
|
import zipfile
|
||||||
import dateutil
|
import dateutil
|
||||||
|
import os.path
|
||||||
|
|
||||||
#
|
#
|
||||||
# Note: For more detailed information about the API services
|
# Note: For more detailed information about the API services
|
||||||
@ -341,3 +342,63 @@ class GarminClient(object):
|
|||||||
# and cannot be exported to fit
|
# and cannot be exported to fit
|
||||||
return orig_file if fmt=='fit' else None
|
return orig_file if fmt=='fit' else None
|
||||||
|
|
||||||
|
@require_session
|
||||||
|
def upload_activity(self, file, format=None, name=None, description=None, activity_type=None, private=None):
|
||||||
|
"""Upload a GPX, TCX, or FIT file for an activity.
|
||||||
|
|
||||||
|
:param file: Path or open file
|
||||||
|
:param format: File format (gpx, tcx, or fit); guessed from filename if None
|
||||||
|
:param name: Optional name for the activity on Garmin Connect
|
||||||
|
:param description: Optional description for the activity on Garmin Connect
|
||||||
|
:param activity_type: Optional activityType key (lowercase: e.g. running, cycling)
|
||||||
|
:param private: If true, then activity will be set as private.
|
||||||
|
:returns: ID of the newly-uploaded activity
|
||||||
|
:rtype: int
|
||||||
|
"""
|
||||||
|
|
||||||
|
if isinstance(file, basestring):
|
||||||
|
file = open(file, "rb")
|
||||||
|
|
||||||
|
# guess file type if unspecified
|
||||||
|
fn = os.path.basename(file.name)
|
||||||
|
_, ext = os.path.splitext(fn)
|
||||||
|
if format is None:
|
||||||
|
if ext.lower() in ('.gpx','.tcx','.fit'):
|
||||||
|
format = ext.lower()[1:]
|
||||||
|
else:
|
||||||
|
raise Exception(u"could not guess file type for {}".format(fn))
|
||||||
|
|
||||||
|
# upload it
|
||||||
|
files = dict(data=(fn, file))
|
||||||
|
response = self.session.post("https://connect.garmin.com/proxy/upload-service-1.1/json/upload/.{}".format(format),
|
||||||
|
files=files)
|
||||||
|
|
||||||
|
# check response and get activity ID
|
||||||
|
if response.status_code != 200:
|
||||||
|
raise Exception(u"failed to upload {} for activity: {}\n{}".format(
|
||||||
|
format, response.status_code, response.text))
|
||||||
|
|
||||||
|
j = response.json()
|
||||||
|
if len(j["detailedImportResult"]["failures"]) or len(j["detailedImportResult"]["successes"])!=1:
|
||||||
|
raise Exception(u"failed to upload {} for activity")
|
||||||
|
activity_id = j["detailedImportResult"]["successes"][0]["internalId"]
|
||||||
|
|
||||||
|
# add optional fields
|
||||||
|
fields = ( ('name',name,("display","value")),
|
||||||
|
('description',description,("display","value")),
|
||||||
|
('type',activity_type,("activityType","key")),
|
||||||
|
('privacy','private' if private else None,("definition","key")) )
|
||||||
|
for endpoint, value, path in fields:
|
||||||
|
if value is not None:
|
||||||
|
response = self.session.post("https://connect.garmin.com/proxy/activity-service-1.2/json/{}/{}".format(endpoint, activity_id),
|
||||||
|
data={'value':value})
|
||||||
|
if response.status_code != 200:
|
||||||
|
raise Exception(u"failed to set {} for activity {}: {}\n{}".format(
|
||||||
|
endpoint, activity_id, response.status_code, response.text))
|
||||||
|
|
||||||
|
j = response.json()
|
||||||
|
p0, p1 = path
|
||||||
|
if p0 not in j or j[p0][p1] != value:
|
||||||
|
raise Exception(u"failed to set {} for activity {}\n".format(endpoint, activity_id))
|
||||||
|
|
||||||
|
return activity_id
|
||||||
|
66
upload_activity.py
Normal file
66
upload_activity.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#! /usr/bin/env python
|
||||||
|
"""A program that uploads an activity file to a Garmin
|
||||||
|
Connect account.
|
||||||
|
"""
|
||||||
|
import argparse
|
||||||
|
import getpass
|
||||||
|
from garminexport.garminclient import GarminClient
|
||||||
|
import logging
|
||||||
|
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=("Uploads an activity file to a Garmin Connect account."))
|
||||||
|
# positional args
|
||||||
|
parser.add_argument(
|
||||||
|
"username", metavar="<username>", type=str, help="Account user name.")
|
||||||
|
parser.add_argument(
|
||||||
|
"activity", metavar="<file>", type=argparse.FileType("rb"),
|
||||||
|
help="Activity file (.gpx, .tcx, or .fit).")
|
||||||
|
|
||||||
|
# optional args
|
||||||
|
parser.add_argument(
|
||||||
|
"--password", type=str, help="Account password.")
|
||||||
|
parser.add_argument(
|
||||||
|
'-N', '--name', help="Activity name on Garmin Connect.")
|
||||||
|
parser.add_argument(
|
||||||
|
'-D', '--description', help="Activity description on Garmin Connect.")
|
||||||
|
parser.add_argument(
|
||||||
|
'-P', '--private', action='store_true', help="Make activity private on Garmin Connect.")
|
||||||
|
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 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: ")
|
||||||
|
with GarminClient(args.username, args.password) as client:
|
||||||
|
log.info("uploading activity file {} ...".format(args.activity.name))
|
||||||
|
id = client.upload_activity(args.activity, name=args.name, description=args.description, private=args.private)
|
||||||
|
log.info("upload successful: https://connect.garmin.com/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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user