Beispiel #1
0
    def __init__(self,
                 paths,
                 username=None,
                 password=None,
                 activity_type=None,
                 activity_name=None,
                 verbose=3):
        self.last_request = None
        logger.setLevel(level=verbose * 10)

        self.activity_type = activity_type
        self.activity_name = activity_name

        # Load activities
        self.activities = self.load_activities(paths)

        # Load user
        self.user = User(username, password)
def main(action, filename):
    assert os.path.exists(filename)

    if action != "DOWNLOAD":
        return 0

    # Auth with ~/.guploadrc credentials
    user = User()
    if not user.authenticate():
        logger.error("Invalid Garmin Connect credentials")
        return -1

    # Upload the activity
    activity = Activity(filename)
    if not activity.upload(user):
        logger.error("Failed to send activity to Garmin")
        return -1

    return 0
def main(action, filename):
    assert os.path.exists(filename)

    if action != "DOWNLOAD":
        return 0

    # Auth with ~/.guploadrc credentials
    user = User()
    if not user.authenticate():
        logger.error('Invalid Garmin Connect credentials')
        return -1

    # Upload the activity
    activity = Activity(filename)
    if not activity.upload(user):
        logger.error('Failed to send activity to Garmin')
        return -1

    return 0
Beispiel #4
0
def user():
    """
    Garmin Connect test user
    """
    from garmin_uploader.user import User

    # please do not abuse this account...
    login = '******'
    password = '******'[::-1]
    return User(login, password)
Beispiel #5
0
    def _import(self, workouts: list):
        if not workouts:
            return []
        titles = []
        user = User(username=settings.GARMIN_USER,
                    password=settings.GARMIN_PASS)
        if not user.authenticate():
            logging.error('could not authenticate with garmin')
            raise Exception('could not authenticate with garmin')
        namespaces = {
            'ns': 'http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2'
        }
        # save logs for imported workouts
        for workout in workouts:
            # TODO - set <Activity Sport="">  Other|Running|Biking
            tree = etree.parse(workout['path'])
            notes = tree.xpath('//ns:Activity/ns:Notes/text()',
                               namespaces=namespaces)
            date = tree.xpath('//ns:Activity/ns:Id/text()',
                              namespaces=namespaces)
            title = notes[0] if notes else 'Unknown Upload: {}'.format(
                datetime.now().isoformat())
            activity = Activity(path=workout['path'], name=title)
            activity.upload(user)
            titles.append(title)
            try:
                Workout.objects.create(
                    ifit_id=workout['id'],
                    name=title,
                    date_created=parse_datetime(date[0])
                    if date else datetime.now(),
                )
            except IntegrityError as e:
                logging.exception(
                    'skipping sync that generated an unknown database error')
                logging.error(str(e))
                continue

        logging.info('imported:')
        logging.info(titles)

        return titles
Beispiel #6
0
class Workflow():
    """
    Upload workflow:
     * List activities according to CLI args
     * Load user credentials
     * Authenticate user
     * Upload activities
    """
    def __init__(self,
                 paths,
                 username=None,
                 password=None,
                 activity_type=None,
                 activity_name=None,
                 verbose=3):
        self.last_request = None
        logger.setLevel(level=verbose * 10)

        self.activity_type = activity_type
        self.activity_name = activity_name

        # Load activities
        self.activities = self.load_activities(paths)

        # Load user
        self.user = User(username, password)

    def load_activities(self, paths):
        """
        Load all activities files:
        Sort out file name args given on command line.  Figure out if they are
        fitness file names, directory names containing fitness files, or names
        of csv file lists.
        Also, expand file name wildcards, if necessary.  Check to see if files
        exist and if the file extension is valid.  Build lists of fitnes
        filenames, directories # which will be further searched for files, and
        list files.
        """
        def is_csv(filename):
            '''
            check to see if file exists and that the file
            extension is .csv
            '''
            extension = os.path.splitext(filename)[1].lower()
            return extension == '.csv' and os.path.isfile(filename)

        def is_activity(filename):
            '''
            check to see if file exists and that the extension is a
            valid activity file accepted by GC.
            '''
            if not os.path.isfile(filename):
                logger.warning("File '{}' does not exist. Skipping...".format(
                    filename))  # noqa
                return False

            # Get file extension from name
            extension = os.path.splitext(filename)[1].lower()
            logger.debug("File '{}' has extension '{}'".format(
                filename, extension))  # noqa

            # Valid file extensions are .tcx, .fit, and .gpx
            if extension in VALID_GARMIN_FILE_EXTENSIONS:
                logger.debug("File '{}' extension '{}' is valid.".format(
                    filename, extension))  # noqa
                return True
            else:
                logger.warning(
                    "File '{}' extension '{}' is not valid. Skipping file...".
                    format(filename, extension))  # noqa
                return False

        valid_paths, csv_files = [], []
        for path in paths:
            path = os.path.realpath(path)
            if is_activity(path):
                # Use file directly
                valid_paths.append(path)

            elif is_csv(path):
                # Use file directly
                logger.info("List file '{}' will be processed...".format(path))
                csv_files.append(path)

            elif os.path.isdir(path):
                # Use files in directory
                # - Does not recursively drill into directories.
                # - Does not search for csv files in directories.
                valid_paths += [
                    f for f in glob.glob(os.path.join(path, '*'))
                    if is_activity(f)
                ]

        # Activity name given on command line only applies if a single filename
        # is given.  Otherwise, ignore.
        if len(valid_paths) != 1 and self.activity_name:
            logger.warning(
                '-a option valid only when one fitness file given. Ignoring -a option.'
            )  # noqa
            self.activity_name = None

        # Build activities from valid paths
        activities = [
            Activity(p, self.activity_name, self.activity_type)
            for p in valid_paths
        ]

        # Pull in file info from csv files and apppend activities
        for csv_file in csv_files:
            with open(csv_file, 'r') as csvfile:
                reader = csv.DictReader(csvfile)
                activities += [
                    Activity(row['filename'], row['name'], row['type'])
                    for row in reader if is_activity(row['filename'])
                ]

        if len(activities) == 0:
            raise Exception('No valid files.')

        return activities

    def run(self):
        """
        Authenticated part of the workflow
        Simply login & upload every activity
        """
        if not self.user.authenticate():
            raise Exception('Invalid credentials')

        for activity in self.activities:
            self.rate_limit()
            activity.upload(self.user)

        logger.info('All done.')

    def rate_limit(self):
        min_period = 1
        if not self.last_request:
            self.last_request = 0.0

        wait_time = max(0, min_period - (time.time() - self.last_request))
        if wait_time <= 0:
            return
        time.sleep(wait_time)

        self.last_request = time.time()
        logger.info("Rate limited for %f" % wait_time)