Example #1
0
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
Example #3
0
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
Example #4
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
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
Example #6
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))
Example #7
0
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.")
Example #8
0
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.")
Example #9
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))
Example #10
0
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)
Example #11
0
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)
Example #12
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)
Example #13
0
            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)