-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgupload.py
242 lines (202 loc) · 9.09 KB
/
gupload.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#!/usr/bin/python
###
# Modified by p-roman 09/2013
# --Added ability to upload all files in a default directory (read from config file).
# Copyright (c) David Lotton 01/2012 <[email protected]>
#
# Name: gupload.py
#
# Brief: gupload.py is a utility to upload Garmin fitness
# GPS files to the connect.garmin.com web site.
# It requires that you have a user account on that
# site. See help (-h option) for more information.
###
# Make sure you have MultipartPostHandler.py in your path as well
import UploadGarmin
import argparse
import os.path
import ConfigParser
import logging
import platform
import string
import glob
parser= argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description='A script to upload .TCX, .GPX, and .FIT files to the Garmin Connect web site.',
epilog="""
Status Output:
The script will output a status for each upload file; Success, FAIL, or
EXISTS. Definitions are as follows:
SUCCESS = Garmin Connect indicated that the upload was successful.
FAIL = Garmin Connect indicated there was a problem with the upload.
EXISTS = Garmin Connect indicated that the workout already exists in
your account.
Credentials:
Username and password credentials may be placed in a configuration file
located either in the current working directory, or in the user's home
directory. WARNING, THIS IS NOT SECURE. USE THIS OPTION AT YOUR OWN
RISK. Username and password are stored as clear text in a file
format that is consistent with Microsoft (r) INI files.
The configuration file must contain a [Credentials] section containing
'username' and 'password' entries.
The name of the config file for non-windows platforms is '.guploadrc'
for windows platforms the config file is named 'gupload.ini'.
Example \'.guploadrc\' (or \'gupload.ini\' for windows):
[Credentials]
username=<myusername>
password=<mypassword>
[DefaultGarminDataDir]
defaultDir=<full_path_to_dir>\*
Replace <myusername> and <mypassword> above with your own login
credentials. If you don't want to keep typing in your garmin file directory,
add the last 2 OPTIONAL lines to the config file, replacing <full_path_to_dir>
with the full path to the directory containing the Garmin files you would like
to upload.
Priority of credentials:
Command line credentials take priority over config files, current
directory config file takes priority over a config file in the user's
home directory.
Examples:
Upload file and set activty name:
gupload.py -l myusername mypassword -a 'Run at park - 12/23' myfile.tcx
Upload multiple files:
gupload.py -l myusername mypassword myfile1.tcx myfile2.tcx myfile3.fit
Upload file using config file for credentials, name file, verbose
output:
gupload.py -v 1 -a 'Run at park - 12/23' myfile.tcx
Upload all FIT, GPX or TCX files in a directory specified in config file:
gupload.py *
""")
parser.add_argument('filename', type=str, nargs='+', help='Path and name of file(s) to upload.')
parser.add_argument('-a', type=str, nargs=1, help='Sets the activity name for the upload file. This option is ignored if multiple upload files are given.')
parser.add_argument('-l', type=str, nargs=2, help='Garmin Connect login credentials \'-l username password\'')
parser.add_argument('-v', type=int, nargs=1, default=[3], choices=[1, 2, 3, 4, 5] , help='Verbose - select level of verbosity. 1=DEBUG(most verbose), 2=INFO, 3=WARNING, 4=ERROR, 5= CRITICAL(least verbose). [default=3]')
myargs = parser.parse_args()
logging.basicConfig(level=(myargs.v[0]*10))
if platform.system() == 'Windows':
configFile='gupload.ini'
else:
configFile='.guploadrc'
# ----Login Credentials for Garmin Connect----
# If credentials are given on command line, use them.
# If no credentials are given on command line, look in
# current directory for a .guploadrc file (or gupload.ini
# for windows). If no .guploadrc/gupload.ini file exists
# in the current directory look in the user's home directory.
configCurrentDir=os.path.abspath(os.path.normpath('./' + configFile))
configHomeDir=os.path.expanduser(os.path.normpath('~/' + configFile))
if myargs.l:
logging.debug('Using credentials from command line.')
username=myargs.l[0]
password=myargs.l[1]
elif os.path.isfile(configCurrentDir):
logging.debug('Using credentials from \'' + configCurrentDir + '\'.')
config=ConfigParser.RawConfigParser()
config.read(configCurrentDir)
username=config.get('Credentials', 'username')
password=config.get('Credentials', 'password')
try:
defaultGarminDataDir=config.get('DefaultGarminDataDir', 'defaultDir')
except:
logging.debug('No default location specified. Ignoring.')
pass
elif os.path.isfile(configHomeDir):
logging.debug('Using credentials from \'' + configHomeDir + '\'.')
config=ConfigParser.RawConfigParser()
config.read(configHomeDir)
username=config.get('Credentials', 'username')
password=config.get('Credentials', 'password')
try:
defaultGarminDataDir=config.get('DefaultGarminDataDir', 'defaultDir')
except:
logging.debug('No default location specified. Ignoring.')
pass
else:
cwd = os.path.abspath(os.path.normpath('./'))
homepath = os.path.expanduser(os.path.normpath('~/'))
logging.critical('\'' + configFile + '\' file does not exist in current directory (' + cwd + ') or home directory (' + homepath + '). Use -l option.')
exit(1)
def obscurePassword(password):
length=len(password)
if length==1:
return('*')
elif length == 2:
return(password[1] + '*')
else:
obscured=password[0]
for letter in range(1, length-1):
obscured=obscured+'*'
obscured=obscured+password[length-1]
return(obscured)
logging.debug('Username: ' + username)
logging.debug('Password: ' + obscurePassword(password))
filenames=myargs.filename
try:
defaultGarminDataDir
except NameError:
#If using the '*' argument, must specify default location in config file
if len(filenames) == 1 and filenames[0] == '*':
raise Exception('Default file path not specified in config file!!')
else:
logging.debug('Default file dir is set to: ' + defaultGarminDataDir)
def checkFile(filename, fileList):
# checkFile - check to see if file exists, append to file list if exsists
logging.debug('Filename: ' + filename)
if os.path.isfile(filename):
logging.debug('File exists.')
# Get file extension from name
extension = os.path.splitext(filename)[1].lower()
logging.debug('File Extension: ' + extension)
# Valid file extensions are .tcx, .fit, and .gpx
if extension in ['.tcx', '.fit', '.gpx']:
logging.debug('File \'' + filename + '\' extension \'' + extension + '\' is valid.')
fileList.append([filename])
else:
logging.warning('File \'' + filename + '\' extension \'' + extension + '\' is not valid. Skipping file...')
else:
logging.warning('File \'' + filename + '\' does not exist. Skipping...')
# Check to see if files exist and if the file type is valid
# Build a list of 'workouts' that includes the valid files
# workout=[str filename, int workoutId, str status]
workouts=[]
for filename in filenames:
if string.find(filename, '*') < 0:
checkFile(filename, workouts)
else:
#If only argument is '*', will use default Garmin file dir (defined in config file)
if filename == "*":
filename = defaultGarminDataDir
logging.debug("Using default garmin data location from config file")
# For Windows we have to expand wildcards ourself
# Ubuntu Linux appears to do the expansion
wildcards=glob.glob(filename)
for wildcard in wildcards:
checkFile(wildcard, workouts)
if len(workouts) == 0:
logging.critical('No valid Files.')
exit(1)
if myargs.a and len(workouts)==1:
activityName=myargs.a[0]
logging.debug('Activity Name: ' + activityName)
# Create object
g = UploadGarmin.UploadGarmin()
# LOGIN
if not g.login(username, password):
logging.critical('LOGIN FAILED - please verify your login credentials')
exit(1)
else:
logging.info('Login Successful.')
# UPLOAD files and append results (workout ID and status)
# to each workout in 'workouts'
for workout in workouts:
workout += g.upload_file(workout[0])
print 'File: ' + workout[0] + ' ID: ' + str(workout[2]) + ' Status: ' + workout[1]
# Name workout if name given. Only for single file. Easier
# to name multiple files from the Garmin Connect site.
if 'activityName' in locals() and len(workouts) == 1:
if workouts[0][1] == 'SUCCESS':
g.name_workout(workouts[0][2], activityName)
logging.info('Acivity name \'' + activityName + '\' written.')
else:
logging.error('Acivity name not written')
exit()