-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
127 lines (107 loc) · 4.64 KB
/
main.py
File metadata and controls
127 lines (107 loc) · 4.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import webbrowser
import datetime
from zoneinfo import ZoneInfo
import os.path
from pathlib import Path
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
class GCalMeet:
"""A class to hold data an functionality for the GCal event fetching and evaluating."""
def __init__(self) -> None:
# If modifying these scopes, delete the file token.json.
self.SCOPES = ["https://www.googleapis.com/auth/calendar.readonly"]
self.PWD = Path(__file__).resolve().parent
def login(self) -> None:
"""Logs into Google API"""
self.creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists(self.PWD / "token.json"):
self.creds = Credentials.from_authorized_user_file(
self.PWD / "token.json", self.SCOPES
)
# If there are no (valid) credentials available, let the user log in.
if not self.creds or not self.creds.valid:
if self.creds and self.creds.expired and self.creds.refresh_token:
self.creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
self.PWD / "credentials.json", self.SCOPES
)
self.creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open(self.PWD / "token.json", "w") as token:
token.write(self.creds.to_json())
def fetch(self) -> None:
try:
service = build("calendar", "v3", credentials=self.creds)
# Call the Calendar API
now = datetime.datetime.now(tz=datetime.timezone.utc).isoformat()
print("Getting the upcoming 10 events")
events_result = (
service.events()
.list(
calendarId="primary",
timeMin=now,
maxResults=10,
singleEvents=True,
orderBy="startTime",
)
.execute()
)
self.events = events_result.get("items", [])
except HttpError as error:
raise ValueError(f"Fetching from GCal API failed. + {error}") from error
def _convert_start_to_datetime_object(self, start: dict) -> datetime.datetime:
naive_dt = datetime.datetime.fromisoformat(start["dateTime"])
aware_dt = naive_dt.astimezone(ZoneInfo(start["timeZone"]))
return aware_dt
def _event_declined(self, event: dict) -> bool:
"""Check in attendees for having declined a meeting."""
if "attendees" not in event:
return False
for attendee in event["attendees"]:
if attendee.get("self"):
if attendee["responseStatus"] == "declined":
return True
return False
def _event_starting_now(
self, aware_now: datetime.datetime, aware_dt: datetime.datetime
) -> bool:
timediff = aware_now - aware_dt
if datetime.timedelta(minutes=4) >= timediff >= datetime.timedelta(minutes=-1):
return True
return False
def evaluate_events(self):
if not self.events:
print("No upcoming events found.")
return
# Prints the start and name of the next 10 events
for event in self.events:
if "dateTime" not in event["start"]:
# full day events dont have `dateTime` but `date` only
print(event["summary"], "skipped (full day event)")
continue
if self._event_declined(event=event):
continue
start_aware_dt = self._convert_start_to_datetime_object(event["start"])
aware_now = datetime.datetime.now(tz=ZoneInfo("Europe/Berlin"))
event_starting_now = self._event_starting_now(
aware_dt=start_aware_dt, aware_now=aware_now
)
print(start_aware_dt, aware_now, event_starting_now, event["summary"])
if event_starting_now:
print("launch in browser")
webbrowser.open(event["hangoutLink"], new=0, autoraise=True)
else:
pass
# print("event not starting now...")
if __name__ == "__main__":
gcalmeet = GCalMeet()
gcalmeet.login()
gcalmeet.fetch()
gcalmeet.evaluate_events()