def main(action, filename): if action != "DOWNLOAD": return 0 try: with open(STRAVA_CREDENTIALS_FILE, 'r') as f: access_token = f.read().strip(' \t\n\r') except FileNotFoundError: print('No Strava credentials provided.') print('You first need to run the script to fetch the credentials') print('./40-upload_to_strava.py') return -1 try: client = Client(access_token=access_token) print('Uploading {}: '.format(os.path.basename(filename)), end='') with open(filename, 'rb') as f: upload = client.upload_activity( activity_file=f, data_type='fit', private=STRAVA_UPLOAD_PRIVATE, ) except (ActivityUploadFailed, FileNotFoundError) as err: print('FAILED') print('Reason:', err) return -1 print('SUCCESS') return 0
def upload_files(self, files): """ Upload files to Strava """ # connect to Strava API client = Client(self.config.strava["access_token"]) for fn in files: try: upload = client.upload_activity(open(self.src_path + fn, "r"), "fit") activity = upload.wait(30, 10) # if a file has been uploaded, copy it locally, as this ensures # we don't attempt to re-upload the same activity in future if activity: shutil.copy(self.src_path + fn, self.dest_path + fn) logging.debug("new file uploaded: {0}, {1} ({2})".format( activity.name, activity.distance, fn)) except exc.ActivityUploadFailed as error: print error
def upload_activity(client: Client, activity_type: str, file_path: Path) -> bool: """ Helper method to upload the activity to Strava. This method will handle the different possibilities when uploading an activity. Args: client (Client): configured Strava client. activity_type (str): Strava activity string. file_path (Path): Path to the `*.tcx` activity file. Returns: bool: True if the activity have been uploaded successfully. False otherwise. Raises: RateLimitExceeded: When the API limits have been reached. Generally when more than 1000 petitions have been done during the day. ConnectionError: When it has been impossible to connect the Strava servers. Exception: Unknown exceptions that will be logged in detail. """ try: activity_file = open(file_path, 'r') client.upload_activity(activity_file=activity_file, data_type='tcx', activity_type=activity_type, private=False) except exc.ActivityUploadFailed: logger.exception('Error uploading the activity `{}`.', file_path.stem) return False except exc.RateLimitExceeded: logger.exception('Exceeded the API rate limit.') raise except ConnectionError: logger.exception('No internet connection.') raise except Exception: logger.exception('Unknown exception') raise # If no error return true logger.debug('Activity `{}` uploaded sucessfully.', file_path.stem) return True
def main(action, filename): if action != "DOWNLOAD": return 0 try: with open(STRAVA_CREDENTIALS_FILE, "rb") as f: token_data = pickle.load(f) access_token = token_data["access_token"] if token_data["expires_at"] <= time.time(): client = Client() token_data = client.refresh_access_token( client_id=CLIENT_ID, client_secret=CLIENT_SECRET, refresh_token=token_data["refresh_token"], ) access_token = token_data["access_token"] with open(STRAVA_CREDENTIALS_FILE, "wb") as fw: pickle.dump(token_data, fw, 0) except (FileNotFoundError, KeyError): print("No Strava credentials provided.") print("You first need to run the script to fetch the credentials") print("./40-upload_to_strava.py") return -1 try: client = Client(access_token=access_token) print("Uploading {}: ".format(os.path.basename(filename)), end="") with open(filename, "rb") as f: upload = client.upload_activity( activity_file=f, data_type="fit", private=STRAVA_UPLOAD_PRIVATE, ) except (ActivityUploadFailed, FileNotFoundError) as err: print("FAILED") print("Reason:", err) return -1 print("SUCCESS") return 0
def main(action, filename): if action != "DOWNLOAD": return 0 try: with open(STRAVA_CREDENTIALS_FILE, 'rb') as f: token_data = pickle.load(f) access_token = token_data['access_token'] if token_data['expires_at'] <= time.time(): client = Client() token_data = client.refresh_access_token( client_id=CLIENT_ID, client_secret=CLIENT_SECRET, refresh_token=token_data['refresh_token']) access_token = token_data['access_token'] with open(STRAVA_CREDENTIALS_FILE, 'wb') as fw: pickle.dump(token_data, fw, 0) except (FileNotFoundError, KeyError): print('No Strava credentials provided.') print('You first need to run the script to fetch the credentials') print('./40-upload_to_strava.py') return -1 try: client = Client(access_token=access_token) print('Uploading {}: '.format(os.path.basename(filename)), end='') with open(filename, 'rb') as f: upload = client.upload_activity( activity_file=f, data_type='fit', private=STRAVA_UPLOAD_PRIVATE, ) except (ActivityUploadFailed, FileNotFoundError) as err: print('FAILED') print('Reason:', err) return -1 print('SUCCESS') return 0
# Need to convert sport type into Strava one i = 0 Strava_Sports = model.Activity.TYPES if Debug: print("Try to find activity in Strava Sports...") while i < len(Strava_Sports): if not tcxSportType.find(Strava_Sports[i]) == -1: tcxSportType = Strava_Sports[i] i = i + 1 if Debug: print("At {}/{}".format(i, len(Strava_Sports))) # Next: upload to Strava print("Uploading...") try: upload = StravaClient.upload_activity( activity_file=open(File, 'r'), data_type='tcx', private=True if tcxSportType == 'Swim' else False, activity_type=tcxSportType) except exc.ActivityUploadFailed as err: print("Uploading problem raised: {}".format(err)) errStr = str(err) # deal with duplicate type of error, if duplicate then continue with next file, else stop if errStr.find('duplicate of activity'): print("Remove dulicate activity file {}".format(File)) os.remove(File) isDuplicate = True else: exit(1) except ConnectionError as err: print("No Internet connection: {}".format(err))
def main(): # Creating a log file and a logging function log = open("log.txt", "a+") now = str(datetime.now()) def logger(message): log.write(now + " | " + message + "\n") print(message) # Opening the connection to Strava logger("Connecting to Strava") client = Client() # You need to run the strava_local_client.py script - with your application's ID and secret - to generate the access token. access_token = "your_token" # replace this with your token client.access_token = access_token athlete = client.get_athlete() logger("Now authenticated for " + athlete.firstname + " " + athlete.lastname) # Creating an archive folder to put uploaded .gpx files archive = "../archive" # Function to convert the HH:MM:SS in the Runkeeper CSV to seconds def duration_calc(duration): # Splits the duration on the :, so we wind up with a 3-part array split_duration = str(duration).split(":") # If the array only has 2 elements, we know the activity was less than an hour if len(split_duration) == 2: hours = 0 minutes = int(split_duration[0]) seconds = int(split_duration[1]) else: hours = int(split_duration[0]) minutes = int(split_duration[1]) seconds = int(split_duration[2]) total_seconds = seconds + (minutes * 60) + (hours * 60 * 60) return total_seconds # Translate RunKeeper's activity codes to Strava's, could probably be cleverer def activity_translator(rk_type): if rk_type == "Running": return "Run" elif rk_type == "Cycling": return "Ride" elif rk_type == "Hiking": return "Hike" elif rk_type == "Walking": return "Walk" elif rk_type == "Swimming": return "Swim" elif rk_type == "Elliptical": return "Elliptical" else: return "None" # feel free to extend if you have other activities in your repertoire; Strava activity codes can be found in their API docs # We open the cardioactivities CSV file and start reading through it with open('cardioActivities.csv') as csvfile: activities = csv.DictReader(csvfile) activity_counter = 0 for row in activities: if activity_counter >= 599: logger( "Upload count at 599 - pausing uploads for 15 minutes to avoid rate-limit" ) time.sleep(900) activity_counter = 0 else: # used to have to check if we were trying to process the header row # no longer necessary when we process as a dictionary # if there is a gpx file listed, find it and upload it if ".gpx" in row['GPX File']: gpxfile = row['GPX File'] strava_activity_type = activity_translator(str( row['Type'])) if gpxfile in os.listdir('.'): logger("Uploading " + gpxfile) try: upload = client.upload_activity( activity_file=open(gpxfile, 'r'), data_type='gpx', private=False, description=row['Notes'], activity_type=strava_activity_type) except exc.ActivityUploadFailed as err: logger("Uploading problem raised: {}".format(err)) errStr = str(err) # deal with duplicate type of error, if duplicate then continue with next file, else stop if errStr.find('duplicate of activity'): logger( "Moving duplicate activity file {}".format( gpxfile)) shutil.move(gpxfile, archive) isDuplicate = True logger("Duplicate File " + gpxfile) else: exit(1) except ConnectionError as err: logger("No Internet connection: {}".format(err)) exit(1) logger("Upload succeeded.\nWaiting for response...") try: upResult = upload.wait() except HTTPError as err: logger( "Problem raised: {}\nExiting...".format(err)) exit(1) except: logger("Another problem occured, sorry...") exit(1) logger("Uploaded " + gpxfile + " - Activity id: " + str(upResult.id)) activity_counter += 1 shutil.move(gpxfile, archive) else: logger("No file found for " + gpxfile + "!") #if no gpx file, upload the data from the CSV else: if row['Activity Id'] not in log: logger("Manually uploading " + row['Activity Id']) # convert to total time in seconds dur = duration_calc(row['Duration']) # convert to meters dist = float(row['Distance (mi)']) * 1609.344 starttime = datetime.strptime(str(row['Date']), "%Y-%m-%d %H:%M:%S") strava_activity_type = activity_translator( str(row['Type'])) # designates part of day for name assignment above, matching Strava convention for GPS activities if 3 <= starttime.hour <= 11: part = "Morning " elif 12 <= starttime.hour <= 4: part = "Afternoon " elif 5 <= starttime.hour <= 7: part = "Evening " else: part = "Night " try: upload = client.create_activity( name=part + strava_activity_type + " (Manual)", start_date_local=starttime, elapsed_time=dur, distance=dist, description=row['Notes'], activity_type=strava_activity_type) logger("Manually created " + row['Activity Id']) activity_counter += 1 except ConnectionError as err: logger("No Internet connection: {}".format(err)) exit(1) logger("Complete! Logged " + str(activity_counter) + " activities.")
def main(): # Creating a log file and a logging function log = open("log.txt","a+") now = str(datetime.now()) def logger (message): log.write(now + " | " + message + "\n") print message # Opening the connection to Strava logger("Connecting to Strava") client = Client() # You need to run the strava_local_client.py script - with your application's ID and secret - to generate the access token. access_token = "your_token" # replace this with your token client.access_token = access_token athlete = client.get_athlete() logger("Now authenticated for " + athlete.firstname + " " + athlete.lastname) # Creating an archive folder to put uploaded .gpx files archive = "../archive" # Function to convert the HH:MM:SS in the Runkeeper CSV to seconds def duration_calc(duration): # Splits the duration on the :, so we wind up with a 3-part array split_duration = str(duration).split(":") # If the array only has 2 elements, we know the activity was less than an hour if len(split_duration) == 2: hours = 0 minutes = int(split_duration[0]) seconds = int(split_duration[1]) else: hours = int(split_duration[0]) minutes = int(split_duration[1]) seconds = int(split_duration[2]) total_seconds = seconds + (minutes*60) + (hours*60*60) return total_seconds # Translate RunKeeper's activity codes to Strava's, could probably be cleverer def activity_translator(rk_type): if rk_type == "Running": return "Run" elif rk_type == "Cycling": return "Ride" elif rk_type == "Hiking": return "Hike" elif rk_type == "Walking": return "Walk" elif rk_type == "Swimming": return "Swim" elif rk_type == "Elliptical": return "Elliptical" else: return "None" # feel free to extend if you have other activities in your repertoire; Strava activity codes can be found in their API docs # We open the cardioactivities CSV file and start reading through it with open('cardioActivities.csv', 'rb') as csvfile: activities = csv.reader(csvfile) activity_counter = 0 for row in activities: if activity_counter >= 599: logger("Upload count at 599 - pausing uploads for 15 minutes to avoid rate-limit") time.sleep(900) activity_counter = 0 else: pass if row[0] == "Date": pass else: # if there is a gpx file listed, find it and upload it if ".gpx" in row[11]: gpxfile = row[11] strava_activity_type = activity_translator(str(row[1])) if gpxfile in os.listdir('.'): logger("Uploading " + gpxfile) try: upload = client.upload_activity( activity_file = open(gpxfile,'r'), data_type = 'gpx', private = False, description = row[10], activity_type = strava_activity_type ) except exc.ActivityUploadFailed as err: logger("Uploading problem raised: {}".format(err)) errStr = str(err) # deal with duplicate type of error, if duplicate then continue with next file, else stop if errStr.find('duplicate of activity'): logger("Moving dulicate activity file {}".format(gpxfile)) shutil.move(gpxfile,archive) isDuplicate = True logger("Duplicate File " + gpxfile) else: exit(1) except ConnectionError as err: logger("No Internet connection: {}".format(err)) exit(1) logger("Upload succeeded.\nWaiting for response...") try: upResult = upload.wait() except HTTPError as err: logger("Problem raised: {}\nExiting...".format(err)) exit(1) except: logger("Another problem occured, sorry...") exit(1) logger("Uploaded " + gpxfile + " - Activity id: " + str(upResult.id)) activity_counter += 1 shutil.move(gpxfile, archive) else: logger("No file found for " + gpxfile + "!") #if no gpx file, upload the data from the CSV else: if row[0] not in log: logger("Manually uploading " + row[0]) dur = duration_calc(row[4]) dist = float(row[3])*1609.344 starttime = datetime.strptime(str(row[0]),"%Y-%m-%d %H:%M:%S") strava_activity_type = activity_translator(str(row[1])) # designates part of day for name assignment above, matching Strava convention for GPS activities if 3 <= starttime.hour <= 11: part = "Morning " elif 12 <= starttime.hour <= 4: part = "Afternoon " elif 5 <= starttime.hour <=7: part = "Evening " else: part = "Night " try: upload = client.create_activity( name = part + strava_activity_type + " (Manual)", start_date_local = starttime, elapsed_time = dur, distance = dist, description = row[10], activity_type = strava_activity_type ) logger("Manually created " + row[0]) activity_counter += 1 except ConnectionError as err: logger("No Internet connection: {}".format(err)) exit(1) logger("Complete! Logged " + str(activity_counter) + " activities.")
# Need to convert sport type into Strava one i = 0 Strava_Sports = model.Activity.TYPES if Debug: print("Try to find activity in Strava Sports...") while i < len(Strava_Sports): if not tcxSportType.find(Strava_Sports[i]) == -1: tcxSportType = Strava_Sports[i] i = i + 1 if Debug: print("At {}/{}".format(i,len(Strava_Sports))) # Next: upload to Strava print("Uploading...") try: upload = StravaClient.upload_activity( activity_file = open(File, 'r'), data_type = 'tcx', private = True if tcxSportType == 'Swim' else False, activity_type = tcxSportType ) except exc.ActivityUploadFailed as err: print("Uploading problem raised: {}".format(err)) errStr = str(err) # deal with duplicate type of error, if duplicate then continue with next file, else stop if errStr.find('duplicate of activity'): print("Remove dulicate activity file {}".format(File)) os.remove(File) isDuplicate = True else: exit(1) except ConnectionError as err: print("No Internet connection: {}".format(err))
def main(args=None): allowed_exts = { '.tcx': lambda v: '<TrainingCenterDatabase' in v[:200], '.gpx': lambda v: '<gpx' in v[:200], '.fit': lambda v: v[8:12] == '.FIT' } p = argparse.ArgumentParser( description='''Uploads activities to Strava.''') p.add_argument( 'activities', nargs='*', type=argparse.FileType("rb"), default=(stdin, ), help="Activity files to upload (plain or gzipped {})".format( ', '.join(allowed_exts))) p.add_argument('-P', '--no-popup', action='store_true', help="Don't browse to activities after upload.") p.add_argument( '-E', '--env', help= 'Look for ACCESS_TOKEN in environment variable rather than ~/.stravacli' ) g = p.add_argument_group('Activity file details') g.add_argument('-p', '--private', action='store_true', help='Make activities private') g.add_argument( '-t', '--type', choices=allowed_exts, default=None, help= 'Force files to be interpreted as being of given type (default is to autodetect based on name, or contents for stdin)' ) g.add_argument( '-x', '--xml-desc', action='store_true', help="Parse name/description fields from GPX and TCX files.") g.add_argument('-T', '--title', help='Activity title') g.add_argument('-D', '--desc', dest='description', help='Activity description') g.add_argument( '-A', '--activity-type', default=None, help='''Type of activity. If not specified, the default value is taken from user profile. Supported values: ride, run, swim, workout, hike, walk, nordicski, alpineski, backcountryski, iceskate, inlineskate, kitesurf, rollerski, windsurf, workout, snowboard, snowshoe''' ) args = p.parse_args(args) if args.xml_desc: if args.title: p.error( 'argument -T/--title not allowed with argument -x/--xml-desc') if args.description: p.error( 'argument -D/--desc not allowed with argument -x/--xml-desc') ##### # Authorize Strava cid = 3163 # CLIENT_ID if args.env: cat = os.environ.get('ACCESS_TOKEN') else: cp = ConfigParser.ConfigParser() cp.read(os.path.expanduser('~/.stravacli')) cat = None if cp.has_section('API'): cat = cp.get('API', 'ACCESS_TOKEN' ) if 'access_token' in cp.options('API') else None while True: client = Client(cat) try: athlete = client.get_athlete() except requests.exceptions.ConnectionError: p.error("Could not connect to Strava API") except Exception as e: print("NOT AUTHORIZED", file=stderr) print( "Need Strava API access token. Launching web browser to obtain one.", file=stderr) client = Client() authorize_url = client.authorization_url( client_id=cid, redirect_uri='http://stravacli-dlenski.rhcloud.com/auth', scope='view_private,write') webbrowser.open_new_tab(authorize_url) client.access_token = cat = raw_input("Enter access token: ") else: if not cp.has_section('API'): cp.add_section('API') if not 'ACCESS_TOKEN' in cp.options('API') or cp.get( 'API', 'ACCESS_TOKEN', None) != cat: cp.set('API', 'ACCESS_TOKEN', cat) cp.write(open(os.path.expanduser('~/.stravacli'), "w")) break print(u"Authorized to access account of {} {} (id {:d}).".format( athlete.firstname, athlete.lastname, athlete.id)) ##### for ii, f in enumerate(args.activities): if f is stdin: fn = 'stdin' contents = f.read() f = StringIO(contents) if args.type is None: # autodetect gzip and extension based on content if contents.startswith('\x1f\x8b'): gz, cf, uf = '.gz', f, gzip.GzipFile(fileobj=f, mode='rb') contents = uf.read() else: gz, uf, cf = '', f, NamedTemporaryFile(suffix='.gz') gzip.GzipFile(fileobj=cf, mode='w+b').writelines(f) for ext, checker in allowed_exts.items(): if checker(contents): print( u"Uploading {} activity from stdin...".format(ext + gz)) break else: p.error("Could not determine file type of stdin") else: base, ext = 'activity', args.type else: base, ext = os.path.splitext( f.name if args.type is None else 'activity.' + args.type) # autodetect based on extensions if ext.lower() == '.gz': base, ext = os.path.splitext(base) # un-gzip it in order to parse it gz, cf, uf = '.gz', f, None if args.no_parse else gzip.GzipFile( fileobj=f, mode='rb') else: gz, uf, cf = '', f, NamedTemporaryFile(suffix='.gz') gzip.GzipFile(fileobj=cf, mode='w+b').writelines(f) if ext.lower() not in allowed_exts: p.error( "Don't know how to handle extension {} (allowed are {}).". format(ext, ', '.join(allowed_exts))) print(u"Uploading {} activity from {}...".format(ext + gz, f.name)) # try to parse activity name, description from file if requested if args.xml_desc: uf.seek(0, 0) if ext.lower() == '.gpx': x = etree.parse(uf) nametag, desctag = x.find("{*}name"), x.find("{*}desc") title = nametag and nametag.text desc = desctag and desctag.text elif ext.lower() == '.tcx': x = etree.parse(uf) notestag = x.find("{*}Activities/{*}Activity/{*}Notes") if notestag is not None: title, desc = (notestag.text.split('\n', 1) + [None])[:2] else: title = args.title desc = args.description # upload activity try: cf.seek(0, 0) upstat = client.upload_activity(cf, ext[1:] + '.gz', title, desc, private=args.private, activity_type=args.activity_type) activity = upstat.wait() duplicate = False except exc.ActivityUploadFailed as e: words = e.args[0].split() if words[-4:-1] == ['duplicate', 'of', 'activity']: activity = client.get_activity(words[-1]) duplicate = True else: raise # show results uri = "http://strava.com/activities/{:d}".format(activity.id) print(u" {}{}".format(uri, " (duplicate)" if duplicate else ''), file=stderr) if not args.no_popup: webbrowser.open_new_tab(uri)
def strava_upload(): """ upload to strava, borrowed from https://github.com/dlenski/stravacli """ allowed_exts = { '.tcx': lambda v: '<TrainingCenterDatabase' in v[:200], '.gpx': lambda v: '<gpx' in v[:200], '.fit': lambda v: v[8:12] == '.FIT' } par = argparse.ArgumentParser(description='Uploads activities to Strava.') par.add_argument( 'activities', nargs='*', type=argparse.FileType("rb"), default=(stdin, ), help="Activity files to upload (plain or gzipped {})".format(', '.join(allowed_exts))) par.add_argument( '-P', '--no-popup', action='store_true', help="Don't browse to activities after upload.") par.add_argument( '-E', '--env', help='Look for ACCESS_TOKEN in environment variable ' 'rather than ~/.stravacli') grp = par.add_argument_group('Activity file details') grp.add_argument('-p', '--private', action='store_true', help='Make activities private') grp.add_argument( '-t', '--type', choices=allowed_exts, default=None, help='Force files to be interpreted as being of given ' 'type (default is to autodetect based on name, or ' 'contents for stdin)') grp.add_argument( '-x', '--xml-desc', action='store_true', help='Parse name/description fields from GPX and TCX ' 'files.') grp.add_argument('-T', '--title', help='Activity title') grp.add_argument('-D', '--desc', dest='description', help='Activity description') grp.add_argument( '-A', '--activity-type', default=None, help='Type of activity. If not specified, the default ' 'value is taken from user profile. ' 'Supported values: \n\t ride, run, swim, workout, ' 'hike, walk, nordicski, alpineski, backcountryski, ' 'iceskate, inlineskate, kitesurf, rollerski, ' 'windsurf, workout, snowboard, snowshoe') args = par.parse_args() if args.xml_desc: if args.title: print('argument -T/--title not allowed with argument ' '-x/--xml-desc', file=stderr) if args.description: print('argument -D/--desc not allowed with argument ' '-x/--xml-desc', file=stderr) # Authorize Strava cp_ = ConfigParser() cp_.read(os.path.expanduser('~/.stravacli')) cat = None if cp_.has_section('API'): if 'access_token' in cp_.options('API'): cat = cp_.get('API', 'ACCESS_TOKEN') cs = cp_.get('API', 'CLIENT_SECRET') cat = cp_.get('API', 'ACCESS_TOKEN') while True: client = Client(cat) try: athlete = client.get_athlete() except requests.exceptions.ConnectionError: print("Could not connect to Strava API", file=stderr) except Exception as e: print("NOT AUTHORIZED %s" % e, file=stderr) print( "Need Strava API access token. Launching web browser to " "obtain one.", file=stderr) client = Client() webserver = QueryGrabber(response='<title>Strava auth code received!</title>This window can be closed.') _scope = 'view_private,write' authorize_url = client.authorization_url(client_id=cid, redirect_uri=webserver.root_uri(), scope=_scope) webbrowser.open_new_tab(authorize_url) webserver.handle_request() client.access_token = cat = client.exchange_code_for_token(client_id=cid,client_secret=cs,code=webserver.received['code']) cp_.add_section('API') cp_.set('API','CLIENT_ID', cid) cp_.set('API','CLIENT_SECRET', cs) cp_.set('API','ACCESS_TOKEN', cat) cp_.write(open(os.path.expanduser('~/.stravacli'),"w")) else: if not cp_.has_section('API'): cp_.add_section('API') if 'ACCESS_TOKEN' not in cp_.options('API') or cp_.get('API', 'ACCESS_TOKEN', None) != cat: cp_.set('API', 'ACCESS_TOKEN', cat) cp_.write(open(os.path.expanduser('~/.stravacli'), "w")) break print("Authorized to access account of {} {} (id {:d}).".format(athlete.firstname, athlete.lastname, athlete.id)) for act in args.activities: if act is stdin: contents = act.read() act = StringIO(contents) if args.type is None: # autodetect gzip and extension based on content if contents.startswith('\x1f\x8b'): gz_, cf_, uf_ = '.gz', act, gzip.GzipFile(fileobj=act, mode='rb') contents = uf_.read() else: gz_, uf_, cf_ = '', act, NamedTemporaryFile(suffix='.gz') gzip.GzipFile(fileobj=cf_, mode='w+b').writelines(act) for ext, checker in allowed_exts.items(): if checker(contents): print("Uploading {} activity from stdin...".format(ext + gz_)) break else: print("Could not determine file type of stdin", file=stderr) else: base, ext = 'activity', args.type else: base, ext = os.path.splitext(act.name if args.type is None else 'activity.' + args.type) # autodetect based on extensions if ext.lower() == '.gz': base, ext = os.path.splitext(base) # un-gzip it in order to parse it gz_, cf_, uf_ = '.gz', act, None if args.no_parse else \ gzip.GzipFile(fileobj=act, mode='rb') else: gz_, uf_, cf_ = '', act, NamedTemporaryFile(suffix='.gz') gzip.GzipFile(fileobj=cf_, mode='w+b').writelines(act) if ext.lower() not in allowed_exts: print( "Don't know how to handle extension " "{} (allowed are {}).".format(ext, ', '.join(allowed_exts)), file=stderr) print("Uploading {} activity from {}...".format(ext + gz_, act.name)) # try to parse activity name, description from file if requested if args.xml_desc: uf_.seek(0, 0) if ext.lower() == '.gpx': x = etree.parse(uf_) nametag, desctag = x.find("{*}name"), x.find("{*}desc") title = nametag and nametag.text desc = desctag and desctag.text elif ext.lower() == '.tcx': x = etree.parse(uf_) notestag = x.find("{*}Activities/{*}Activity/{*}Notes") if notestag is not None: title, desc = (notestag.text.split('\n', 1) + [None])[:2] else: title = args.title desc = args.description # upload activity try: cf_.seek(0, 0) upstat = client.upload_activity( cf_, ext[1:] + '.gz', title, desc, private=args.private, activity_type=args.activity_type) activity = upstat.wait() duplicate = False except exc.ActivityUploadFailed as e: words = e.args[0].split() if words[-4:-1] == ['duplicate', 'of', 'activity']: activity = client.get_activity(words[-1]) duplicate = True else: raise # show results uri = "http://strava.com/activities/{:d}".format(activity.id) print(" {}{}".format(uri, " (duplicate)" if duplicate else ''), file=stderr) if not args.no_popup: webbrowser.open_new_tab(uri)
else: pass if row[0] == "Date": pass else: # if there is a gpx file listed, find it and upload it if ".gpx" in row[11]: gpxfile = row[11] strava_activity_type = activity_translator(str(row[1])) if gpxfile in os.listdir('.'): logger("Uploading " + gpxfile) try: upload = client.upload_activity( activity_file = open(gpxfile,'r'), data_type = 'gpx', private = False, description = row[10], activity_type = strava_activity_type ) except exc.ActivityUploadFailed as err: logger("Uploading problem raised: {}".format(err)) errStr = str(err) # deal with duplicate type of error, if duplicate then continue with next file, else stop if errStr.find('duplicate of activity'): logger("Moving dulicate activity file {}".format(gpxfile)) shutil.move(gpxfile,archive) isDuplicate = True logger("Duplicate File " + gpxfile) else: exit(1)
nametag, desctag = x.find("{*}name"), x.find("{*}desc") title = nametag and nametag.text desc = desctag and desctag.text elif ext.lower()=='.tcx': x = etree.parse(uf) notestag = x.find("{*}Activities/{*}Activity/{*}Notes") if notestag is not None: title, desc = (notestag.text.split('\n',1)+[None])[:2] else: title = args.title desc = args.description # upload activity try: cf.seek(0, 0) upstat = client.upload_activity(cf, ext[1:] + '.gz', title, desc, private=args.private, activity_type=args.activity_type) activity = upstat.wait() duplicate = False except exc.ActivityUploadFailed as e: words = e.args[0].split() if words[-4:-1]==['duplicate','of','activity']: activity = client.get_activity(words[-1]) duplicate = True else: raise # show results uri = "http://strava.com/activities/{:d}".format(activity.id) print(" {}{}".format(uri, " (duplicate)" if duplicate else ''), file=stderr) if not args.no_popup: webbrowser.open_new_tab(uri)