Skip to content

Instantly share code, notes, and snippets.

@fxchen
Created April 23, 2018 21:19
Show Gist options
  • Save fxchen/ebfc39bbaaaadbe29701f1e3f0d5427e to your computer and use it in GitHub Desktop.
Save fxchen/ebfc39bbaaaadbe29701f1e3f0d5427e to your computer and use it in GitHub Desktop.
A legible timezone-friendly parser and foursquare / existio integrator for quantifying myself
# integrations.py
###################################################################################################
# usage: integrations.py [-h] [-s [n]] [-f] [-c] [-e] [-w]
# A legible timezone-friendly parser and foursquare / existio integrator for quantifying myself
# optional arguments:
# -h, --help show this help message and exit
# -s [n], --show [n] Shows formatted <n> days (default: 30 days)
# -f, --foursquare Grab checkins from Foursquare API
# -c, --calendar Shows events from Outlook Calendar
# -e, --exist Parse times from sleep.json and wake.json
# -w, --woke Show when you woke up today
###################################################################################################
# Derived from prior foursquare.py https://gist.github.com/fxchen/f86239b52ddc3488a222e8c634bd8115
# Change log:
# 2017/10/05 updated for python3
# 2017/11/18 add existio integrations
# 2018/04/23 publish to github
###################################################################################################
import requests, json, datetime, operator, argparse, sys, os, subprocess, six, ssl
""" Globals """
DEFAULT_DAYS = 30
NA_STR_CONSTANT = "N/A"
OUTPUT_FILE = "/Users/fchen/Dropbox/notes/notational/integrations/integrations.txt"
EXIST_OAUTH_TOKEN = "<>"
FOURSQUARE_OAUTH_TOKEN = "<>"
parser = argparse.ArgumentParser(description="A legible timezone friendly parser and integrator for my days")
parser.add_argument("-s", "--show", type=int, metavar="n", nargs="?", const=DEFAULT_DAYS,
help="Shows formatted <n> days (default: " + str(DEFAULT_DAYS) +" days)")
parser.add_argument("-f", "--foursquare", action="store_true",
help="Grab checkins from Foursquare API")
parser.add_argument("-c", "--calendar", action="store_true",
help="Shows events from Outlook Calendar")
parser.add_argument("-e", "--exist", action="store_true",
help="Parse times from sleep.json and wake.json")
parser.add_argument("-w", "--woke", action="store_true",
help="Show when you woke up today")
args = parser.parse_args()
if not (args.foursquare or args.show or args.calendar or args.exist or args.woke):
parser.error("No action requested {--help, --show, --calendar, --exist, --foursquare}")
# Adding an insecure warning tag for Foursquare
requests.packages.urllib3.disable_warnings()
# The following sections have more constants and data
""" Calendaring """
OUTLOOK_CALENDAR_COMMAND = "/Users/fchen/Dropbox/notes/notational/integrations/calendar.sh"
data_formatted_dates = {}
""" Exist """
DEFAULT_LIMIT = 100
EXIST_RESULTS_STR_CONSTANT = "results"
EXIST_SLEEP_URL_TEMPLATE = "https://exist.io/api/1/users/$self/attributes/sleep_start/?limit={}&page={}"
EXIST_SLEEP_JSON = "/Users/fchen/Dropbox/notes/notational/integrations/sleep.json" # Sleep start in minutes from midday
EXIST_WAKE_URL_TEMPLATE = "https://exist.io/api/1/users/$self/attributes/sleep_end/?limit={}&page={}"
EXIST_WAKE_JSON = "/Users/fchen/Dropbox/notes/notational/integrations/wake.json" # Wake start in minutes from midnight
EXIST_HEADERS = {"Authorization": "Token " + EXIST_OAUTH_TOKEN}
EXIST_VALUE_STR_CONSTANT = "value"
# 720 is the number of minutes to get to midday from midnight
NUMBER_OF_MINUTES_MIDDAY = 720
# 1440 is the number of minutes in a day
NUMBER_OF_MINUTES_WHOLE_DAY = 1440
data_sleep = {}
data_wake = {}
def get_minutes_to_human_readable(minutes):
# Return formatted time stamps from integer of minutes
modhours, minute = divmod(minutes, 60)
pmam, hour = divmod(modhours, 12)
hour = (hour, 12)[hour == 0]
return "%02d:%02d" % (hour,minute) + (" AM", " PM")[pmam == 1]
def get_wake_time_human_readable(minutes_str):
return get_minutes_to_human_readable(minutes_str)
def get_wake_time_from_str(date_str):
global data_wake
# Data = number of minutes from midnight
if date_str in data_wake and not (data_wake[date_str] is None):
return get_wake_time_human_readable(data_wake[date_str]) + " Wake up"
return ""
def get_sleep_time_from_str(str):
global data_sleep
# Data = number of minutes after midday
if str in data_sleep and not (data_sleep[str] is None):
return get_minutes_to_human_readable(data_sleep[str] + NUMBER_OF_MINUTES_MIDDAY) + " Sleep"
return ""
def exist():
global EXIST_SLEEP_JSON, EXIST_WAKE_JSON
print("Fetching sleep times >> " + EXIST_SLEEP_JSON)
raw_data = {}
page = 1 # Use page 1 to start
with open(EXIST_SLEEP_JSON, "w") as f:
while True:
response = requests.get(EXIST_SLEEP_URL_TEMPLATE.format(DEFAULT_LIMIT, page), headers=EXIST_HEADERS)
results = response.json().get(EXIST_RESULTS_STR_CONSTANT, None)
if results is None or len(results) == 0:
break
for item in results:
raw_data[item["date"]] = item[EXIST_VALUE_STR_CONSTANT]
page += 1
f.write(json.dumps(raw_data))
f.close()
print("Fetching wake times >> " + EXIST_WAKE_JSON)
raw_data = {}
page = 1 # Use page 1 to start
with open(EXIST_WAKE_JSON, "w") as f:
while True:
response = requests.get(EXIST_WAKE_URL_TEMPLATE.format(DEFAULT_LIMIT, page), headers=EXIST_HEADERS)
results = response.json().get(EXIST_RESULTS_STR_CONSTANT, None)
if results is None or len(results) == 0:
break
for item in results:
raw_data[item["date"]] = item[EXIST_VALUE_STR_CONSTANT]
page += 1
f.write(json.dumps(raw_data))
f.close()
def woke():
woke_str_builder = "{0} Woke up. Slept {1:.1f} hours last night"
# Grab the most recent wake time
response = requests.get(EXIST_WAKE_URL_TEMPLATE.format(1, 1), headers=EXIST_HEADERS)
results = response.json().get(EXIST_RESULTS_STR_CONSTANT, None)
if results is None or len(results) == 0 or results[0][EXIST_VALUE_STR_CONSTANT] is None:
print (NA_STR_CONSTANT)
return
wake_time = results[0][EXIST_VALUE_STR_CONSTANT]
# Grab last night's sleep time
response = requests.get(EXIST_SLEEP_URL_TEMPLATE.format(1, 1), headers=EXIST_HEADERS)
results = response.json().get(EXIST_RESULTS_STR_CONSTANT, None)
if results is None or len(results) == 0 or results[0][EXIST_VALUE_STR_CONSTANT] is None:
print( woke_str_builder.format(get_wake_time_human_readable(wake_time), 0), end="")
return
# Adjust then find sleep duration
sleep_time = results[0][EXIST_VALUE_STR_CONSTANT] + NUMBER_OF_MINUTES_MIDDAY
sleep_duration = (wake_time + NUMBER_OF_MINUTES_WHOLE_DAY - sleep_time) / 60
print( woke_str_builder.format(get_wake_time_human_readable(wake_time), sleep_duration), end="")
""" Foursquare """
FOURSQUARE_URL_TEMPLATE = "https://api.foursquare.com/v2/users/self/checkins?limit=250&oauth_token={}&v=20131026&offset={}"
FOURSQURE_JSON = "foursquare.json"
FOURSQUARE_TIMEZONE_STR_CONSTANT = "timeZoneOffset"
def foursquare():
raw_data = {}
# Saves your foursquare to foursquare.json
print("Fetching check ins >> " + FOURSQURE_JSON)
offset = 0 # We set this offset for request size
with open(FOURSQURE_JSON, "w") as f:
while True:
response = requests.get(FOURSQUARE_URL_TEMPLATE.format(FOURSQUARE_OAUTH_TOKEN, offset), verify=False)
results = response.json()["response"]["checkins"].get("items", None)
if len(results) == 0:
break
for item in results:
raw_data[item["createdAt"] + item[FOURSQUARE_TIMEZONE_STR_CONSTANT] * 60] = item
offset += 250
f.write(json.dumps(raw_data, sort_keys=True, indent=4, separators=(",", ": ")))
f.close()
def show(numdays):
global data_wake, data_sleep
raw_data = {}
DAY_FORMAT = "%Y %b %d %a"
CAL_FORMAT = "%Y%m%d"
TIME_FORMAT = "%I:%M %p"
EXIST_DAY_FORMAT = "%Y-%m-%d"
FOURSQUARE_VENUE_STR_CONSTANT = "venue"
FOURSQUARE_NAME_STR_CONSTANT = "name"
# Make Dates
base = datetime.datetime.today()
date_list = [base - datetime.timedelta(days=x) for x in range(0, numdays)]
## Parse Foursquare Data
with open(FOURSQURE_JSON, "r") as f:
raw_data = json.load(f)
for timestamp, dict in six.iteritems(raw_data):
utctimestamp = datetime.datetime.utcfromtimestamp(int(timestamp)) + datetime.timedelta(minutes=int(dict[FOURSQUARE_TIMEZONE_STR_CONSTANT]))
tz_timestamp = int(timestamp) + int(dict[FOURSQUARE_TIMEZONE_STR_CONSTANT])
# E.g. "2017 May 27 Sat"
day_str = datetime.datetime.fromtimestamp(tz_timestamp).strftime(DAY_FORMAT)
# E.g. "12:58 PM"
time = datetime.datetime.fromtimestamp(tz_timestamp).strftime(TIME_FORMAT)
# Construct the object we're inserting. Some check ins no longer have venue names
obj = {}
if FOURSQUARE_VENUE_STR_CONSTANT in dict and FOURSQUARE_NAME_STR_CONSTANT in dict[FOURSQUARE_VENUE_STR_CONSTANT]:
obj[FOURSQUARE_NAME_STR_CONSTANT] = dict[FOURSQUARE_VENUE_STR_CONSTANT][FOURSQUARE_NAME_STR_CONSTANT]
else:
obj[FOURSQUARE_NAME_STR_CONSTANT] = NA_STR_CONSTANT
obj["time"] = time
obj["corrected_time"] = utctimestamp.strftime(TIME_FORMAT)
obj["timestamp"] = tz_timestamp
try:
data_formatted_dates[day_str].append(obj)
except KeyError:
data_formatted_dates[day_str] = []
data_formatted_dates[day_str].append(obj)
f.close()
## Parse Sleep / Wake Data
with open(EXIST_SLEEP_JSON, "r") as f:
data_sleep = json.load(f)
f.close()
with open(EXIST_WAKE_JSON, "r") as f:
data_wake = json.load(f)
f.close()
# Show in reverse order
for timestamp in date_list[::-1]:
day_str = timestamp.strftime(DAY_FORMAT)
cal_str = timestamp.strftime(CAL_FORMAT)
wake_date_str = timestamp.strftime(EXIST_DAY_FORMAT)
sleep_date_str = (timestamp + datetime.timedelta(days=1)).strftime(EXIST_DAY_FORMAT)
cal_str_command = OUTLOOK_CALENDAR_COMMAND + " " + cal_str
print(day_str + ": ")
print (get_wake_time_from_str(wake_date_str))
if day_str in data_formatted_dates:
# For Python2: process = subprocess.Popen(OUTLOOK_CALENDAR_COMMAND.split(), stdout=subprocess.PIPE)
# For Python2: output, error = process.communicate()
for obj in sorted(data_formatted_dates[day_str], key=lambda k: k["timestamp"]):
print(obj["corrected_time"] + " " + obj[FOURSQUARE_NAME_STR_CONSTANT].strip())
print (get_sleep_time_from_str(sleep_date_str))
if args.calendar:
# For Python2: process = subprocess.Popen(cal_str_command.split(), stdout=subprocess.PIPE)
# Fpr Python2: output, error = process.communicate()
output = subprocess.check_output([OUTLOOK_CALENDAR_COMMAND, cal_str])
print("--- calendar ---")
print(output.decode("UTF-8"))
print ("-----------------------------------------------")
print ("")
if args.foursquare:
foursquare()
if args.exist:
exist()
if args.woke:
woke()
if args.show:
print("Showing " + str(args.show) + " days in the current time zone\n")
while True:
print ("Press space or 'f' to write to " + OUTPUT_FILE)
choice = sys.stdin.read(1)[0]
if choice == "f" :
# Redirect std out to the text file
print ("Please wait…")
sys.stdout = open(OUTPUT_FILE, "w")
show(args.show)
os.system("Open "+OUTPUT_FILE)
break
else:
show(args.show)
break
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment