109 lines
3.1 KiB
Python
109 lines
3.1 KiB
Python
#!/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 += '<span foreground="#323232" background="#CCCCCC">'
|
|
output += f"{print_day.day: >2}"
|
|
if print_day == today:
|
|
output += "</span>"
|
|
print_day += datetime.timedelta(days=1)
|
|
|
|
output += f'\n<span size="small">{timezone_str}</span>'
|
|
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"<tt>{tooltip}</tt>",
|
|
css_class=["foo"],
|
|
percentage="100",
|
|
)
|
|
|
|
print(out.dump(), flush=True)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|