def load_strava_tracks(self, strava_config: str) -> typing.List[Track]: tracks = [] tracks_names = [] if self.cache_dir: self.strava_cache_file = os.path.join(self.cache_dir, strava_config) if os.path.isfile(self.strava_cache_file): with open(self.strava_cache_file) as f: strava_cache_data = json.load(f) tracks = [ self._strava_cache_to_track(i) for i in strava_cache_data ] tracks_names = [track.file_names[0] for track in tracks] with open(strava_config) as f: strava_data = json.load(f) client = Client() response = client.refresh_access_token(**strava_data) client.access_token = response["access_token"] fliter_dict = {"before": datetime.datetime.utcnow()} if tracks: max_time = max(track.start_time for track in tracks) if max_time: fliter_dict = {"after": max_time - datetime.timedelta(days=2)} for activate in client.get_activities(**fliter_dict): # tricky to pass the timezone if str(activate.id) in tracks_names: continue t = Track() t.load_strava(activate) tracks.append(t) self._store_strava_tracks_to_cache(tracks) return self._filter_and_merge_tracks(tracks)
def load_strava_tracks(self, strava_config: str) -> typing.List[Track]: tracks = [] tracks_names = [] if self.cache_dir: self.strava_cache_file = os.path.join(self.cache_dir, strava_config) if os.path.isfile(self.strava_cache_file): with open(self.strava_cache_file) as f: strava_cache_data = json.load(f) tracks = [self._strava_cache_to_track(i) for i in strava_cache_data] tracks_names = [track.file_names[0] for track in tracks] with open(strava_config) as f: strava_data = json.load(f) filter_type = strava_data.pop("activity_type", None) client = Client() response = client.refresh_access_token(**strava_data) client.access_token = response["access_token"] filter_dict = {"before": datetime.datetime.utcnow()} if tracks: max_time = max(track.start_time() for track in tracks) filter_dict = {"after": max_time - datetime.timedelta(days=2)} for activity in client.get_activities(**filter_dict): # tricky to pass the timezone if str(activity.id) in tracks_names: continue if filter_type and activity.type not in ( [filter_type] if isinstance(filter_type, str) else filter_type ): # pylint: disable=superfluous-parens continue t = Track() t.load_strava(activity) tracks.append(t) self._store_strava_tracks_to_cache(tracks) return self._filter_and_merge_tracks(tracks)
def get_strava_client(): token = get_strava_access_token() rate_limiter = RateLimiter() rate_limiter.rules.append( XRateLimitRule({ 'short': { 'usageFieldIndex': 0, 'usage': 0, # 60s * 15 = 15 min 'limit': 100, 'time': (60 * 15), 'lastExceeded': None, }, 'long': { 'usageFieldIndex': 1, 'usage': 0, # 60s * 60m * 24 = 1 day 'limit': 1000, 'time': (60 * 60 * 24), 'lastExceeded': None } })) client = Client(rate_limiter=rate_limiter) client.access_token = token return client
def pull_data(self, members, challenges): client = Client() for m in members: logger.debug("processing member: {}".format(m)) # Check if the access token needs renewing. Should last 6hrs, so only needs doing once regardless of how many calls we make. if time.time() > m.access_token_expiry: logger.info("Renewing token") refresh_response = client.refresh_access_token( client_id=config.strava_client_id, client_secret=config.strava_client_secret, refresh_token=m.refresh_token) m.access_token = refresh_response['access_token'] m.refresh_token = refresh_response['refresh_token'] m.access_token_expiry = refresh_response['expires_at'] m.save() client.access_token = m.access_token client.refresh_token = m.refresh_token client.token_expires_at = m.access_token_expiry for c in challenges: logger.debug("Processing challenge: {}".format(c)) efforts = client.get_segment_efforts( c.segment_id, start_date_local=c.date_from, end_date_local=c.date_to) for e in efforts: logger.debug("Processing effort: {}".format(e)) Attempt.add(e, m, c)
def get_client(): client = Client() token = load_token() client.refresh_token = token["refresh_token"] if token["expires_at"] < time.time(): token = refresh_token(client) client.access_token = token["access_token"] return client
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 = "442a2a9e4db1f7008fc96789e18c16e05875305d" # replace this with your token client.access_token = access_token athlete = client.get_athlete() logger("Now authenticated for " + athlete.firstname + " " + athlete.lastname) # We open the cardioactivities CSV file and start reading through it with open('logarun.csv') as csvfile: activities = csv.reader(csvfile) activity_counter = 0 for row in activities: if row[2] == 'time': continue if activity_counter >= 500: logger("Upload count at 500 - pausing uploads for 15 minutes to avoid rate-limit") time.sleep(900) activity_counter = 0 if row[0] not in log: logger("Manually uploading " + row[0]) duration = int(float(row[2])) # time in seconds dist = float(row[1])*1609.344 # convert miles to meters starttime = row[0] strava_activity_type = "Run" try: upload = client.create_activity( name = "logarun Run", start_date_local = starttime, elapsed_time = duration, distance = dist, description = "Shoe used: " + row[3], 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.")
def add_user(code: str): """ Takes a temporary access code returned from Strava and retrieves the associated user and access token. Then it checks for the user in the database. If they're not found, then the new user is recorded. If they are found, then just the access token is recorded in case it has changed. """ client = Client() if not Config.TESTING: response = client.exchange_code_for_token( client_id=Config.CLIENT_ID, client_secret=Config.CLIENT_SECRET, code=code, ) current_app.logger.debug("Response: " + str(response)) client.access_token = response["access_token"] access_token = response["access_token"] refresh_token = response["refresh_token"] access_expr = datetime.fromtimestamp(response["expires_at"]) athlete = client.get_athlete() user_id = athlete.id first_name = athlete.firstname else: access_token = "access" refresh_token = "refresh" access_expr = datetime.now() - timedelta(hours=5) user_id = 1 first_name = "joe" # noinspection PyArgumentList # Check if the user is already in the db if User.query.get(user_id) is None: u = User( id=user_id, first_name=first_name, access_token=access_token, refresh_token=refresh_token, access_expr=access_expr, ) db.session.add(u) db.session.commit() current_app.logger.info(f"New user added: {user_id}") else: u = User.query.get(user_id) u.access_token = access_token u.refresh_token = refresh_token u.access_expr = access_expr db.session.commit() current_app.logger.info( f"User {user_id} already found; updating token, logging in," " and redirecting to dashboard" ) return u
def check_if_access_token_valid(): print("Checking Access token valid") access_token = get_string_from_file('access_token') strava = Client() try: strava.access_token = access_token strava.get_athlete() except AccessUnauthorized: print("Access Token not valid") return False print("Access Token valid. Exiting...") sys.exit(0)
def main(): assert len(args.athlete_ids) == len(args.access_tokens) logger.info("app id: %i, fetching friends for ids %s" % \ (args.id_strava_app, str(args.athlete_ids))) for i in range( len(args.access_tokens) ): client = Client() client.access_token = args.access_tokens[i] athlete_id = args.athlete_ids[i] time.sleep(TIME_PAUSE) friends = [ friend.id for friend in client.get_athlete_friends() ] time.sleep(TIME_PAUSE) followers = [ follower.id for follower in client.get_athlete_followers() ] add_friends_to_db(conn, athlete_id, friends, type="friend") add_friends_to_db(conn, athlete_id, followers, type="follower") logger.info("Done.")
import os import fnmatch import shutil from requests.exceptions import ConnectionError, HTTPError from datetime import datetime, timedelta # First, load settings from file print("Loading settings...") with open("settings.json", "r") as f: settings = json.load(f) # Then, connect to user Strava account. try: print("Connecting to Strava...") StravaClient = Client() StravaClient.access_token = settings.get('strava_token') # You're logged in ! StravaAthlete = StravaClient.get_athlete() print("Hello, {} {}.\nYou are now connected to Strava.".format( StravaAthlete.firstname, StravaAthlete.lastname)) except HTTPError as err: print("Connecting problem: {}".format(err)) exit(1) # Now we'll try to find activity(ies) to upload. tcxStorageDir = settings.get('archives_dir') # Where TCX files are stored Debug = False # If we need to have some more informations... #Debug = True Year = datetime.now().strftime( "%Y"
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 get_strava_client(): token = get_strava_access_token() client = Client() client.access_token = token return client
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.")
import os import fnmatch import shutil from requests.exceptions import ConnectionError, HTTPError from datetime import datetime, timedelta # First, load settings from file print("Loading settings...") with open("settings.json", "r") as f: settings = json.load(f) # Then, connect to user Strava account. try: print("Connecting to Strava...") StravaClient = Client() StravaClient.access_token = settings.get('strava_token') # You're logged in ! StravaAthlete = StravaClient.get_athlete() print("Hello, {} {}.\nYou are now connected to Strava.".format(StravaAthlete.firstname, StravaAthlete.lastname)) except HTTPError as err: print("Connecting problem: {}".format(err)) exit(1) # Now we'll try to find activity(ies) to upload. tcxStorageDir = settings.get('archives_dir') # Where TCX files are stored Debug = False # If we need to have some more informations... #Debug = True Year = datetime.now().strftime("%Y") # This exists because TCX files are like : 2015-06-06T15-23-01.000Z_Walking.tcx Exclude = ('UploadedToStrava', 'Endomondo', 'runtastic2strava') # List directories we don't want do search into
def main(): assert len(args.athlete_ids) == len(args.access_tokens) logger.info("app id: %i, fetching activities for ids %s" % \ (args.id_strava_app, str(args.athlete_ids))) for i in range( len(args.access_tokens) ): # for each athlete client = Client() client.access_token = args.access_tokens[i] athlete_id = args.athlete_ids[i] # get summary activities first (filterd before detailed activity call) time.sleep(TIME_PAUSE) activity_ids = get_user_activities(client) # now fetch detailed versions, add to db detailed_activites = [] activity_to_segments = {} # { act_id: # { seg_id : # { "distance" : x, "grade" : y }, }, } segment_ranks = {} # { seg_id : { "auth_athlete_rank" : auth_rank, # "other_athletes" : { other_id : other_rank, } } } for act_id in activity_ids: try: activity_to_segments[act_id] = {} time.sleep(TIME_PAUSE) detailed_activity = client.get_activity( act_id ) detailed_activites.append( detailed_activity ) for seg_effort in detailed_activity.segment_efforts: segment = seg_effort.segment seg_id = int(segment.id) seg_dist = float( unithelper.miles(segment.distance) ) seg_grade = segment.average_grade seg_dct = { "distance" : seg_dist, "grade" : seg_grade } activity_to_segments[act_id][seg_id] = seg_dct if segment_ranks.has_key(seg_id): # already have ranks continue # might be overlap between activities else: try: # some = hazardous = error time.sleep(TIME_PAUSE) # now get ranks for this segment leaderboard_entries = \ client.get_segment_leaderboard(seg_id, top_results_limit=1).entries segment_ranks[seg_id] = { "auth_athlete_rank" : -1, "other_athletes" : {} } for entry in leaderboard_entries: if entry.athlete_id == athlete_id: segment_ranks[seg_id]["auth_athlete_rank"] = entry.rank continue other_id = entry.athlete_id other_rank = entry.rank segment_ranks[seg_id]["other_athletes"][other_id] = other_rank except Exception, e: logger.warning("Error with segment_id %i, removing from activity,"\ " trace:\n %s" % (seg_id, traceback.print_exc())) activity_to_segments[act_id].pop(seg_id) continue if len(activity_to_segments[act_id]) > 0: add_activity(conn, athlete_id, detailed_activity) # if made it here, okay else: logger.info("No segments for activity %i, skipping" % act_id) except Exception, e: # occurs with wrong privaleges, eg private activity logger.warning("Error with activity %i for athlete %i, popping. tracebac:\n%s" % \ (act_id, athlete_id, traceback.print_exc())) activity_to_segments.pop(act_id)
def add_challenge(segment_id, year, month): segment = client.get_segment(segment_id) print(segment) Challenge.add(segment, year, month) if __name__ == '__main__': m = Member.objects.filter(refresh_token__gte="").limit(1) print(list(m)) m = list(m)[0] client.access_token = m.access_token client.refresh_token = m.refresh_token client.token_expires_at = m.access_token_expiry # Check if the access token needs renewing. Should last 6hrs, so only needs doing once regardless of how many calls we make. if time.time() > m.access_token_expiry: logger.info("Renewing token") refresh_response = client.refresh_access_token( client_id=config.strava_client_id, client_secret=config.strava_client_secret, refresh_token=m.refresh_token) m.access_token = refresh_response['access_token'] m.refresh_token = refresh_response['refresh_token'] m.access_token_expiry = refresh_response['expires_at'] m.save()
settings = load_config() client = Client() if time.time() > int(settings['expires_at']): print("Renewing tokens") refresh_response = client.refresh_access_token( client_id=settings['client_id'], client_secret=settings['client_secret'], refresh_token=settings['refresh_token']) settings['refresh_token'] = refresh_response['refresh_token'] settings['access_token'] = refresh_response['access_token'] settings['expires_at'] = refresh_response['expires_at'] save_config(settings) else: client.access_token = settings['access_token'] client.refresh_token = settings['refresh_token'] client.expires_at = settings['expires_at'] activities = client.get_activities(limit=10) for activity in activities: if activity.type == 'Run': ms = activity.average_speed km = activity.distance / 1000 mile = km * 0.621371 km_pace = 1000 / (ms * 60) sec_km, min_km = math.modf(km_pace) sec_km = sec_km * 60
from datetime import datetime # 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