Merge pull request #317 from facetoe/google_calendar
Add GoogleCalendar module
This commit is contained in:
commit
bf2e992fc9
@ -35,6 +35,12 @@ MOCK_MODULES = [
|
|||||||
"speedtest_cli",
|
"speedtest_cli",
|
||||||
"pyzabbix",
|
"pyzabbix",
|
||||||
"vk",
|
"vk",
|
||||||
|
"google-api-python-client",
|
||||||
|
"dateutil",
|
||||||
|
"httplib2",
|
||||||
|
"oauth2client",
|
||||||
|
"apiclient"
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
for mod_name in MOCK_MODULES:
|
for mod_name in MOCK_MODULES:
|
||||||
|
120
i3pystatus/google_calendar.py
Normal file
120
i3pystatus/google_calendar.py
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import datetime
|
||||||
|
|
||||||
|
import httplib2
|
||||||
|
import oauth2client
|
||||||
|
import pytz
|
||||||
|
from apiclient import discovery
|
||||||
|
from dateutil import parser
|
||||||
|
|
||||||
|
from i3pystatus import IntervalModule
|
||||||
|
from i3pystatus.core.color import ColorRangeModule
|
||||||
|
from i3pystatus.core.util import internet, require
|
||||||
|
|
||||||
|
|
||||||
|
class GoogleCalendar(IntervalModule, ColorRangeModule):
|
||||||
|
"""
|
||||||
|
Simple module for displaying next Google Calendar event.
|
||||||
|
|
||||||
|
Requires the Google Calendar API package - https://developers.google.com/google-apps/calendar/quickstart/python.
|
||||||
|
Additionally requires the `colour`, `httplib2`, `oauth2client`, `pytz`, `apiclient` and `dateutil` modules.
|
||||||
|
|
||||||
|
All top level keys returned by the Google Calendar API can be used as formatters. Some
|
||||||
|
examples include:
|
||||||
|
|
||||||
|
.. rubric:: Available formatters
|
||||||
|
|
||||||
|
* `{kind}` — type of event
|
||||||
|
* `{status}` — eg, confirmed
|
||||||
|
* `{summary}` — essentially the title
|
||||||
|
* `{htmlLink}` — link to the calendar event
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
settings = (
|
||||||
|
('format', 'format string'),
|
||||||
|
("credential_path", "Path to credentials"),
|
||||||
|
("skip_recurring", "Skip recurring events."),
|
||||||
|
("urgent_seconds", "Add urgent hint when this many seconds until event startTime"),
|
||||||
|
("start_color", "Hex or English name for start of color range, eg '#00FF00' or 'green'"),
|
||||||
|
("end_color", "Hex or English name for end of color range, eg '#FF0000' or 'red'"),
|
||||||
|
)
|
||||||
|
|
||||||
|
required = ('credential_path',)
|
||||||
|
|
||||||
|
format = "{summary} ({remaining_time})"
|
||||||
|
urgent_seconds = 300
|
||||||
|
interval = 30
|
||||||
|
color = '#FFFFFF'
|
||||||
|
skip_recurring = True
|
||||||
|
credential_path = None
|
||||||
|
|
||||||
|
service = None
|
||||||
|
credentials = None
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
self.colors = self.get_hex_color_range(self.end_color, self.start_color, self.urgent_seconds * 2)
|
||||||
|
|
||||||
|
@require(internet)
|
||||||
|
def run(self):
|
||||||
|
if not self.service:
|
||||||
|
self.connect_service()
|
||||||
|
|
||||||
|
display_event = self.get_next_event()
|
||||||
|
if display_event:
|
||||||
|
start_time = parser.parse(display_event['start']['dateTime'])
|
||||||
|
now = datetime.datetime.now(tz=pytz.UTC)
|
||||||
|
|
||||||
|
alert_time = now + datetime.timedelta(seconds=self.urgent_seconds)
|
||||||
|
display_event['remaining_time'] = str((start_time - now)).partition('.')[0]
|
||||||
|
urgent = alert_time > start_time
|
||||||
|
color = self.get_color(now, start_time)
|
||||||
|
|
||||||
|
self.output = {
|
||||||
|
'full_text': self.format.format(**display_event),
|
||||||
|
'color': color,
|
||||||
|
'urgent': urgent
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
self.output = {
|
||||||
|
'full_text': "",
|
||||||
|
}
|
||||||
|
|
||||||
|
def connect_service(self):
|
||||||
|
self.credentials = oauth2client.file.Storage(self.credential_path).get()
|
||||||
|
self.service = discovery.build('calendar', 'v3', http=self.credentials.authorize(httplib2.Http()))
|
||||||
|
|
||||||
|
def get_next_event(self):
|
||||||
|
for event in self.get_events():
|
||||||
|
start_time = parser.parse(event['start']['dateTime'])
|
||||||
|
now = datetime.datetime.now(tz=pytz.UTC)
|
||||||
|
if 'recurringEventId' in event and self.skip_recurring:
|
||||||
|
continue
|
||||||
|
elif start_time < now:
|
||||||
|
continue
|
||||||
|
return event
|
||||||
|
|
||||||
|
def get_events(self):
|
||||||
|
now, later = self.get_timerange()
|
||||||
|
events_result = self.service.events().list(
|
||||||
|
calendarId='primary',
|
||||||
|
timeMin=now,
|
||||||
|
timeMax=later,
|
||||||
|
maxResults=10,
|
||||||
|
singleEvents=True,
|
||||||
|
orderBy='startTime',
|
||||||
|
timeZone='utc'
|
||||||
|
).execute()
|
||||||
|
return events_result.get('items', [])
|
||||||
|
|
||||||
|
def get_timerange(self):
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
later = now + datetime.timedelta(days=1)
|
||||||
|
now = now.isoformat() + 'Z'
|
||||||
|
later = later.isoformat() + 'Z'
|
||||||
|
return now, later
|
||||||
|
|
||||||
|
def get_color(self, now, start_time):
|
||||||
|
seconds_to_event = (start_time - now).seconds
|
||||||
|
v = self.percentage(seconds_to_event, self.urgent_seconds)
|
||||||
|
color = self.get_gradient(v, self.colors)
|
||||||
|
return color
|
Loading…
Reference in New Issue
Block a user