Skip to content

Instantly share code, notes, and snippets.

@smjonas
Created November 14, 2024 23:25
Show Gist options
  • Save smjonas/356b0c60610ab13a3145b010af2075f0 to your computer and use it in GitHub Desktop.
Save smjonas/356b0c60610ab13a3145b010af2075f0 to your computer and use it in GitHub Desktop.
TimeTree calendar data export via unofficial API
import datetime
import json
import os
import uuid
import pytz
import requests
from dotenv import load_dotenv
load_dotenv()
if "TIMETREE_USER" not in os.environ or "TIMETREE_PASSWORD" not in os.environ:
print("TIMETREE_USER and TIMETREE_PASSWORD not set in .env file")
exit(1)
USER = os.getenv("TIMETREE_USER")
PASSWORD = os.getenv("TIMETREE_PASSWORD")
SESSION_ID = None
def sign_in(id=USER, pw=PASSWORD):
url = "https://timetreeapp.com/api/v1/auth/email/signin"
headers = {
"Content-Type": "application/json",
"X-TimeTreeA": "web/2.1.0/en",
}
data = {
"uid": id,
"password": pw,
"uuid": uuid.uuid4().hex,
}
req = requests.put(url, headers=headers, data=json.dumps(data))
session_id = req.cookies.get("_session_id", None)
if session_id is None:
raise Exception(f"Failed to sign in: {req.status_code}: {req.text}")
return session_id
def ensure_signed_in():
global SESSION_ID
if SESSION_ID is None:
SESSION_ID = sign_in()
return SESSION_ID
def get_calendar_list():
ensure_signed_in()
url = "https://timetreeapp.com/api/batch"
data = {
"ops": [{"method": "get", "url": "/v1/calendars", "params": {"since": 0}}],
"sequential": True,
}
headers = {
"Content-Type": "application/json",
"X-TimeTreeA": "web/2.1.0/en",
}
cookies = {
"_session_id": SESSION_ID,
}
req = requests.post(url, headers=headers, cookies=cookies, data=json.dumps(data))
if req.status_code == 200:
response_body = req.json()["results"][0]["body"]
calendar_list = []
if "calendars" in response_body:
for calendar in response_body["calendars"]:
calendar_list.append(
{
"alias_code": calendar["alias_code"],
"id": calendar["id"],
"name": calendar["name"],
}
)
else:
print(response_body)
return calendar_list
else:
return get_calendar_list()
def get_calendar_data(calendar_id):
ensure_signed_in()
url = f"https://timetreeapp.com/api/v1/calendar/{calendar_id}/events/sync"
headers = {
"X-TimeTreeA": "web/2.1.0/en",
}
cookies = {
"_session_id": SESSION_ID,
}
req = requests.get(url, headers=headers, cookies=cookies)
if req.status_code == 200:
return json.loads(req.text)
else:
return get_calendar_data(calendar_id, sign_in())
def main():
global SESSION_ID
SESSION_ID = sign_in()
calendars = get_calendar_list()
calendars_count = len(calendars)
if calendars_count == 0:
print("No calendars found")
return
print(
f"Found {calendars_count} calendars, selecting first one: {calendars[0]['name']}"
)
calendar_data = get_calendar_data(calendars[0]["id"])
print("calendar data: ", calendar_data)
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment