Skip to content

Instantly share code, notes, and snippets.

@patmigliaccio
Created May 10, 2023 02:49
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Embed
What would you like to do?
A simple script for exporting all FatSecret weight history to CSV.
"""
# Export FatSecret Weight History CSV
A simple script for exporting all FatSecret weight history to CSV.
## Installation
*Install Dependencies*
```sh
pip install fatsecret decouple rauth
```
*Create .env file with OAuth1.0 credentials*
```
CONSUMER_KEY=
CONSUMER_SECRET=
```
## Run
```sh
python export.py
```
### Config
Update the `years_of_data` variable to the maximum number of years
worth of data to retrieve.
"""
import csv
from datetime import date, datetime, timedelta
from decouple import config
from fatsecret import Fatsecret
import os
import pickle
import time
consumer_key = config("CONSUMER_KEY")
consumer_secret = config("CONSUMER_SECRET")
years_of_data = 10
token_file = "token.pickle"
output_file = "output.csv"
def auth() -> Fatsecret:
"""Logins in the user and returns a Fatsecret instance."""
session_token = None
if os.path.exists(token_file):
with open(token_file, "rb") as file:
session_token = pickle.load(file)
if session_token is None:
fs = Fatsecret(consumer_key, consumer_secret)
auth_url = fs.get_authorize_url()
print(
f"Browse to the following URL in your browser to authorize access:\n{1}",
auth_url,
)
pin = input("Enter the PIN provided by FatSecret: ")
session_token = fs.authenticate(pin)
with open(token_file, "wb") as file:
pickle.dump(session_token, file)
else:
fs = Fatsecret(consumer_key, consumer_secret, session_token=session_token)
return fs
def convert_date(date_int: int):
"""Transforms a date_int value to YYYY-MM-DD."""
reference_date = datetime(1970, 1, 1)
date = reference_date + timedelta(days=float(date_int))
return date.strftime("%Y-%m-%d")
def convert_weight(weight_kg: float):
"""Converts kgs to lbs (rounded to nearest decimal)."""
return round(weight_kg * 2.20462, 2)
def transform_weights(response: dict[str, str]):
"""Tranforms the values to output object."""
date_str = convert_date(int(response["date_int"]))
weight_lbs = convert_weight(float(response["weight_kg"]))
return {
"date": date_str,
"weight": weight_lbs,
"comment": response.get("weight_comment"),
}
def get_weights_by_month(fs: Fatsecret, date: datetime):
"""Retrieves all of the weights recorded during a particular month."""
all_weights = []
weights = fs.weights_get_month(date)
if weights is not None:
if not isinstance(weights, list):
weights = [weights]
for weight in weights:
if weight:
result = transform_weights(weight)
all_weights.append(result)
return all_weights
def dump_csv(values):
"""Creates a .csv file with the object data."""
fieldnames = ["date", "weight", "comment"]
with open(output_file, "w", newline="") as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for value in values:
writer.writerow(value)
def main():
"""
Authenticates and iterates over each month for a set number
of years. Uses a retry loop to handle rate limiting.
"""
fs = auth()
start_date = date.today() - timedelta(days=365 * years_of_data)
end_date = date.today()
all_weights = []
retries = 10
try:
current_date = start_date
while current_date <= end_date:
try:
first_day_of_month = datetime(current_date.year, current_date.month, 1)
weights = get_weights_by_month(fs, first_day_of_month)
time.sleep(1)
if len(weights):
all_weights.extend(weights)
# Reset number of revivals
retries = 10
# Move to the next month
current_date = current_date.replace(day=1)
current_date += timedelta(days=32)
current_date = current_date.replace(day=1)
except Exception as e:
print(e)
if retries == 0:
raise Exception("Failed too many times...")
time.sleep(5)
retries -= 1
print("Retrying...")
except:
print("Failed. Saving dump...")
dump_csv(all_weights)
print("Dumped.")
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment