Skip to content

Instantly share code, notes, and snippets.

@Cyclenerd
Created April 22, 2017 13:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Cyclenerd/106f2a6245f44690de83a2e27b50d5fc to your computer and use it in GitHub Desktop.
Save Cyclenerd/106f2a6245f44690de83a2e27b50d5fc to your computer and use it in GitHub Desktop.
Velo Hero Export Script
#!/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