#!/usr/bin/env python # # Custom waybar module for clocks. Implemented because the official clock module was downloading timezone definitions on every boot. import datetime import json import sys import time from dataclasses import dataclass from functools import lru_cache from typing import Final, List, Optional from zoneinfo import ZoneInfo INTERVAL: Final[int] = 10 LOCAL_TIMEZONE = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo @dataclass class Update: text: Optional[str] alt: Optional[str] tooltip: Optional[str] css_class: Optional[List[str]] percentage: Optional[str] def dump(self) -> str: # Dump a dict because we can't name our member variable "class" return json.dumps( { k: v for k, v in { "text": self.text, "alt": self.alt, "tooltip": self.tooltip, "class": self.css_class, "percentage": self.percentage, }.items() if v is not None } ) @lru_cache(maxsize=1) def make_calendar(today: datetime.date, tz: datetime.tzinfo): width: Final[int] = 20 start_of_month = today.replace(day=1) month_header = today.strftime("%B %Y") padding = width - len(month_header) right_padding = " " * (padding // 2) left_padding = right_padding + (" " if padding % 2 == 1 else "") header = f"{left_padding}{month_header}{right_padding}" days_of_week = "Su Mo Tu We Th Fr Sa" timezone_str = str(tz) # Make the grid first_day_padding = " " * ( 0 if start_of_month.weekday() == 6 else (3 * (1 + start_of_month.weekday())) - 1 ) output = f"{header}\n{days_of_week}\n{first_day_padding}" print_day = start_of_month while print_day.month == today.month: if print_day.weekday() == 6: output += "\n" else: output += " " if print_day == today: output += '' output += f"{print_day.day: >2}" if print_day == today: output += "" print_day += datetime.timedelta(days=1) output += f'\n{timezone_str}' return output def main(): tz: Optional[datetime.tzinfo] = ( ZoneInfo(sys.argv[1]) if len(sys.argv) >= 2 else LOCAL_TIMEZONE ) if tz is None: raise Exception("Failed to detect timezone.") next_update = time.time() while True: time_before_next_update = next_update - time.time() if time_before_next_update > 0: time.sleep(time_before_next_update) next_update = time.time() + INTERVAL now = datetime.datetime.now(tz=tz) text = now.strftime("%Y-%m-%d %H:%M") tooltip = make_calendar(now.date(), tz) out = Update( text=text, alt="foo", tooltip=f"{tooltip}", css_class=["foo"], percentage="100", ) print(out.dump(), flush=True) if __name__ == "__main__": main()