X-Git-Url: https://wannabe.guru.org/gitweb/?a=blobdiff_plain;f=gcal_renderer.py;h=c43a1448b2f8c5f256dc03951d586d7e2d758334;hb=5c39d86ebc075ccb7be98b1dfab8040b72ff9134;hp=11f530451e2bd4f58763fcc306176aefff6aaade;hpb=e4dca16bbd329afdb587e8488767d88e17777254;p=kiosk.git diff --git a/gcal_renderer.py b/gcal_renderer.py index 11f5304..c43a144 100644 --- a/gcal_renderer.py +++ b/gcal_renderer.py @@ -4,18 +4,22 @@ contents of several Google calendars.""" import datetime +import functools +import os +import time +from typing import Any, Dict, List, Optional, Tuple + +from dateutil.parser import parse import gdata # type: ignore import gdata_oauth from oauth2client.client import AccessTokenRefreshError # type: ignore -import os -import time -from typing import Dict, List, Optional, Tuple +import pytz import constants import file_writer import globals import renderer -import secrets +import kiosk_secrets as secrets class gcal_renderer(renderer.debuggable_abstaining_renderer): @@ -34,6 +38,7 @@ class gcal_renderer(renderer.debuggable_abstaining_renderer): ] ) + @functools.total_ordering class comparable_event(object): """A helper class to sort events.""" @@ -46,6 +51,10 @@ class gcal_renderer(renderer.debuggable_abstaining_renderer): ) -> None: if start_time is None: assert(end_time is None) + else: + assert(isinstance(start_time, datetime.datetime)) + if end_time is not None: + assert(isinstance(end_time, datetime.datetime)) self.start_time = start_time self.end_time = end_time self.summary = summary @@ -63,7 +72,15 @@ class gcal_renderer(renderer.debuggable_abstaining_renderer): that.calendar, ) - def __str__(self) -> str: + def __eq__(self, that) -> bool: + return ( + self.start_time == that.start_time and + self.end_time == that.end_time and + self.summary == that.summary and + self.calendar == that.calendar + ) + + def __repr__(self) -> str: return "[%s] %s" % (self.timestamp(), self.friendly_name()) def friendly_name(self) -> str: @@ -72,14 +89,36 @@ class gcal_renderer(renderer.debuggable_abstaining_renderer): return "%s" % name def timestamp(self) -> str: + now = datetime.datetime.now(pytz.timezone("US/Pacific")) if self.start_time is None: return "None" - elif self.start_time.hour == 0: - return datetime.datetime.strftime(self.start_time, "%a %b %d %Y") + elif ( + self.start_time.hour == 0 and + self.start_time.minute == 0 and + self.start_time.second == 0 + ): + if self.start_time.year == now.year: + return datetime.datetime.strftime( + self.start_time, + "%a %b %d" + ) + else: + return datetime.datetime.strftime( + self.start_time, + "%a %b %d, %Y" + ) else: - return datetime.datetime.strftime( - self.start_time, "%a %b %d %Y %H:%M%p" - ) + dt = self.start_time + zone = dt.tzinfo + local_dt = dt.replace(tzinfo=zone).astimezone(tz=pytz.timezone('US/Pacific')) + if local_dt.year == now.year: + return datetime.datetime.strftime( + local_dt, "%a %b %d %I:%M%p" + ) + else: + return datetime.datetime.strftime( + local_dt, "%a %b %d, %Y %I:%M%p" + ) def __init__( self, name_to_timeout_dict: Dict[str, int], oauth: gdata_oauth.OAuth @@ -103,9 +142,9 @@ class gcal_renderer(renderer.debuggable_abstaining_renderer): raise Exception("Unexpected operation") def get_min_max_timewindow(self) -> Tuple[str, str]: - now = datetime.datetime.now() - _time_min = now - datetime.timedelta(1) - _time_max = now + datetime.timedelta(95) + now = datetime.datetime.now(pytz.timezone("US/Pacific")) + _time_min = now - datetime.timedelta(hours=6) + _time_max = now + datetime.timedelta(days=95) time_min = datetime.datetime.strftime(_time_min, "%Y-%m-%dT%H:%M:%SZ") time_max = datetime.datetime.strftime(_time_max, "%Y-%m-%dT%H:%M:%SZ") self.debug_print(f"time_min is {time_min}") @@ -113,19 +152,22 @@ class gcal_renderer(renderer.debuggable_abstaining_renderer): return (time_min, time_max) @staticmethod - def parse_date(date_str: str) -> Optional[datetime.datetime]: - retval = None - try: - _ = date_str.get("date") - if _: - retval = datetime.datetime.strptime(_, "%Y-%m-%d") - else: - _ = date_str.get("dateTime") - if _: - retval = datetime.datetime.strptime(_[:-6], "%Y-%m-%dT%H:%M:%S") - return retval - except: - pass + def parse_date(date: Any) -> Optional[datetime.datetime]: + if isinstance(date, datetime.datetime): + return date + elif isinstance(date, dict): + if 'dateTime' in date: + d = date['dateTime'] + dt = parse(d) + if dt.tzinfo is None: + dt = dt.replace(tzinfo=None).astimezone(tz=pytz.timezone('US/Pacific')) + return dt + elif 'date' in date: + d = date['date'] + dt = datetime.datetime.strptime(d, '%Y-%m-%d') + dt = dt.replace(tzinfo=None).astimezone(tz=pytz.timezone('US/Pacific')) + return dt + print(f'Not sure what to do with this {date} ({type(date)}), help?!') return None def get_events_from_interesting_calendars( @@ -156,12 +198,13 @@ class gcal_renderer(renderer.debuggable_abstaining_renderer): ) for event in events["items"]: summary = event["summary"] - self.debug_print( - f" ... event '{summary}' ({event['start']} to {event['end']}" - ) start = gcal_renderer.parse_date(event["start"]) end = gcal_renderer.parse_date(event["end"]) + self.debug_print( + f" ... event '{summary}' ({event['start']} ({start}) to {event['end']} ({end})" + ) if start is not None and end is not None: + self.debug_print(f' ... adding {summary} to sortable_events') sortable_events.append( gcal_renderer.comparable_event( start, end, summary, calendar["summary"] @@ -172,7 +215,7 @@ class gcal_renderer(renderer.debuggable_abstaining_renderer): or "Holidays" in calendar["summary"] or "Countdown" in summary ): - self.debug_print(" ... event is countdown worthy!") + self.debug_print(f" ... adding {summary} to countdown_events") countdown_events.append( gcal_renderer.comparable_event( start, end, summary, calendar["summary"] @@ -193,20 +236,32 @@ class gcal_renderer(renderer.debuggable_abstaining_renderer): ) = self.get_events_from_interesting_calendars(time_min, time_max) self.sortable_events.sort() with file_writer.file_writer("gcal_3_86400.html") as f: - f.write("

Upcoming Calendar Events:


\n") - f.write("
\n") + f.write( +f""" +

Upcoming Calendar Events:

+
+
+
+""" + ) upcoming_sortable_events = self.sortable_events[:12] - for event in upcoming_sortable_events: + for n, event in enumerate(upcoming_sortable_events): + self.debug_print(f'{n}/12: {event.friendly_name()} / {event.calendar}') + if n % 2 == 0: + color = "#c6b0b0" + else: + color = "#eeeeee" f.write( - f""" - - - -\n""" +f""" + + + + +""" ) f.write("
- {event.timestamp()} - - {event.friendly_name()} -
+ {event.timestamp()} + + {event.friendly_name()} +
\n") @@ -214,7 +269,7 @@ class gcal_renderer(renderer.debuggable_abstaining_renderer): self.countdown_events.sort() with file_writer.file_writer("countdown_3_7200.html") as g: g.write("

Countdowns: