Created
April 22, 2017 13:19
-
-
Save Cyclenerd/106f2a6245f44690de83a2e27b50d5fc to your computer and use it in GitHub Desktop.
Velo Hero Export Script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# This script downloads training data from Velo Hero | |
import sys, urllib2, urllib, json, logging, time | |
""" | |
Get Single Sign-on ID | |
https://app.velohero.com/sso | |
""" | |
sso_key = '' | |
""" | |
Last ID | |
If no ID is given everything is downloaded | |
If an ID is specified, only workouts with a larger ID are downloaded | |
""" | |
last_workout_id = '' | |
# Configure logging | |
logger = logging.getLogger() | |
handler = logging.StreamHandler() | |
formatter = logging.Formatter( '%(levelname)-8s %(message)s' ) | |
handler.setFormatter(formatter) | |
logger.addHandler(handler) | |
# Set level. | |
logger.setLevel(logging.DEBUG) | |
# Set workouts per page | |
limit = 20 | |
def print_debug(text): | |
""" | |
print_debug() prints DEBUG with text | |
""" | |
logger.debug( str(text) ) | |
def print_info(text): | |
""" | |
print_info() prints INFO with text | |
""" | |
logger.info( str(text) ) | |
def print_critical_and_exit(text): | |
""" | |
print_critical_and_exit() prints CRITICAL with text and exit | |
""" | |
logger.critical( str(text) ) | |
sys.exit(9) | |
def check_http_error(code): | |
""" | |
check_http_error() evaluates HTTP status code and prints a message | |
""" | |
if e.code >= 400: | |
print_critical_and_exit ( 'Login failed! Single Sign-on key not found or expired. Please check your SSO key.' ) | |
elif e.code >= 500: | |
print_critical_and_exit ( 'Server Error' ) | |
else: | |
print_critical_and_exit ( 'Unknown error' ) | |
def get_last_page(total, limit): | |
""" | |
get_last_page() determines the last page | |
""" | |
pages = float(total) / float(limit) | |
last_page = 1 | |
if pages > int(pages): | |
last_page = int(pages + 1) | |
else: | |
last_page = int(pages) | |
print_debug( 'Last page: ' + str(last_page) ) | |
return last_page | |
def get_url(url, parameters): | |
""" | |
get_url() loads data from Velo Hero | |
""" | |
parameters['sso'] = str(sso_key) | |
req = urllib2.Request( url ) | |
req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/3.14159265359 Firefox/42.1') | |
try: | |
resp = urllib2.urlopen( req, urllib.urlencode( parameters ) ) | |
except urllib2.HTTPError as e: | |
check_http_error(e.code) | |
return resp | |
def get_workout(workout): | |
""" | |
get_workout() checks if workout has a recording. Downloads export. | |
""" | |
workout_title = workout['date_ymd'] + ' ' + workout['start_time'] + ' (' + workout['id'] + ')' | |
if workout['file_type']: | |
print_info( 'Download: ' + workout_title) | |
with open(workout['date_ymd'] + '_' + workout['id'] + '.pwx', 'wb') as output: | |
output.write( get_pwx(workout['id']) ) | |
else: | |
print_debug( 'Workout without file: ' + workout_title ) | |
time.sleep(3) | |
def get_pwx(id): | |
""" | |
get_pwx() downloads PWX export | |
""" | |
resp = get_url('http://app.velohero.com/export/activity/pwx/' + str(id), {}) | |
return resp.read() | |
def get_json(url, parameters): | |
""" | |
get_json() loads and outputs the JSON response | |
""" | |
resp = get_url(url, parameters) | |
return json.loads( resp.read(), encoding="ISO-8859-1" ) # with ISO-8859-1 encoding to fix UTF-8 bugs | |
def get_total(): | |
""" | |
get_total() determines the total number of all workouts | |
""" | |
parameters = { | |
'limit': str(limit), | |
'offset': str('999999999999999999'), | |
} | |
workouts = get_json('http://app.velohero.com/export/workouts/json', parameters) | |
if 'total' in workouts: | |
total = workouts['total'] | |
print_debug('Total: ' + str(total) ) | |
return total | |
else: | |
return 0 | |
def get_workouts(page): | |
""" | |
get_workouts() loads all workouts of a page | |
""" | |
page = int(page) | |
offset = ( limit * page ) - limit | |
parameters = { | |
'limit': str(limit), | |
'offset': str(offset), | |
} | |
workouts = get_json('http://app.velohero.com/export/workouts/json', parameters) | |
if 'workouts' in workouts: | |
return workouts['workouts'] | |
else: | |
return {} | |
def get_last_workouts(workout_id): | |
""" | |
get_last_workouts() loads all new workouts since the last run | |
""" | |
parameters = { 'workout_id': str(workout_id) } | |
workouts = get_json('http://app.velohero.com/export/workouts/json', parameters) | |
if 'workouts' in workouts: | |
return workouts['workouts'] | |
else: | |
return {} | |
try: | |
last_workout_id = int(last_workout_id) | |
except ValueError: | |
last_workout_id = 0 | |
if last_workout_id > 0: | |
print_debug('last workout id: ' + str(last_workout_id)) | |
for workout in get_last_workouts(last_workout_id): | |
get_workout(workout) | |
else: | |
total = get_total() | |
if total > 0: | |
last_page = get_last_page(total, limit) | |
for page in range (1, last_page + 1): | |
print_debug( 'Get page: ' + str(page) ) | |
for workout in get_workouts(page): | |
get_workout(workout) | |
else: | |
print_critical_and_exit ( 'No workouts found' ) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment