974076bd89b65d3bb0798d40a04e04afb82643ca
[kiosk.git] / gkeep_renderer.py
1 #!/usr/bin/env python3
2
3 import logging
4 import os
5 import re
6 from typing import Dict
7
8 import gkeepapi  # type: ignore
9
10 import kiosk_constants
11 import file_writer
12 import renderer
13 import kiosk_secrets as secrets
14
15
16 logger = logging.getLogger(__file__)
17
18
19 class gkeep_renderer(renderer.abstaining_renderer):
20     def __init__(self, name_to_timeout_dict: Dict[str, int]) -> None:
21         super().__init__(name_to_timeout_dict)
22         self.colors_by_name = {
23             "white": "#002222",
24             "green": "#345920",
25             "darkblue": "#1F3A5F",
26             "blue": "#2D545E",
27             "orange": "#604A19",
28             "red": "#5C2B29",
29             "purple": "#42275E",
30             "pink": "#5B2245",
31             "yellow": "#635D19",
32             "brown": "#442F19",
33             "gray": "#3c3f4c",
34             "teal": "#16504B",
35         }
36         self.keep = gkeepapi.Keep()
37         self.token_file = "./google_keep_token.json"
38         if os.path.exists(self.token_file):
39             logger.debug("Attempting to reuse persisted Google Keep login token...")
40             try:
41                 with open(self.token_file, "r") as rf:
42                     token = "".join(rf.readlines()).strip()
43                 self.keep.resume(secrets.google_keep_username, token)
44                 logger.debug("Successfully reused existing login token.")
45             except gkeepapi.exception.LoginException:
46                 logger.warning("Invalid token, attempting to re-login.")
47
48         if not self.keep.login(
49             secrets.google_keep_username,
50             secrets.google_keep_password,
51             secrets.google_keep_mac,
52         ):
53             raise Exception("Error connecting with Google Keep?!")
54         logger.debug("Successfully logged in with Google Keep")
55
56     def debug_prefix(self) -> str:
57         return "gkeep"
58
59     def periodic_render(self, key: str) -> bool:
60         strikethrough = re.compile("(\u2611[^\n]*)\n", re.UNICODE)
61         # linkify = re.compile(r".*(https?:\/\/\S+).*")
62
63         self.keep.sync()
64         result_list = self.keep.find(labels=[self.keep.findLabel("kiosk")])
65         for note in result_list:
66             title = note.title
67             title = title.replace(" ", "-")
68             title = title.replace("/", "")
69
70             filename = f"{title}_2_3600.html"
71             contents = note.text + "\n"
72             logger.debug(f"Note title '{title}'")
73             if contents != "" and not contents.isspace():
74                 contents = strikethrough.sub("", contents)
75                 logger.debug(f"Note contents:\n{contents}")
76                 contents = contents.replace(
77                     "\u2610 ", '<LI><INPUT TYPE="checkbox">&nbsp;'
78                 )
79                 # contents = linkify.sub(r'<a href="\1">\1</a>', contents)
80
81                 individual_lines = contents.split("\n")
82                 num_lines = len(individual_lines)
83                 contents = ""
84                 for x in individual_lines:
85                     leading_spaces = len(x) - len(x.lstrip(" "))
86                     leading_spaces //= 2
87                     leading_spaces = int(leading_spaces)
88                     x = x.lstrip(" ")
89                     # logger.debug(" * (%d) '%s'" % (leading_spaces, x))
90                     for y in range(0, leading_spaces):
91                         x = "<UL>" + x
92                     for y in range(0, leading_spaces):
93                         x = x + "</UL>"
94                     contents = contents + x + "\n"
95
96                 individual_lines = contents.split("\n")
97                 color = note.color.name.lower()
98                 if color in list(self.colors_by_name.keys()):
99                     color = self.colors_by_name[color]
100                 else:
101                     logger.debug(f"Unknown color '{color}'")
102                 print(f"TITLE: {color} {note.title}")
103                 with file_writer.file_writer(filename) as f:
104                     f.write(
105                         """
106 <STYLE type="text/css">
107   a:link { color:#88bfbf; }
108   ul { list-style-type:none; }
109 </STYLE>
110 <DIV STYLE="border-radius:25px; border-style:solid; padding:20px; background-color:%s; color:#eeeeee; font-size:x-large;">
111 """
112                         % color
113                     )
114                     f.write(
115                         f"""
116 <p style="color:#ffffff; font-size:larger"><B>{note.title}</B></p>
117 <HR style="border-top:3px solid white;">
118 """
119                     )
120                     if num_lines >= 10:
121                         logger.debug(f"{num_lines} lines: two column mode")
122                         f.write('<TABLE BORDER=0 WIDTH=100%><TR valign="top">')
123                         f.write(
124                             '<TD WIDTH=50% style="color:#eeeeee; font-size:large">\n'
125                         )
126                         f.write("<FONT><UL STYLE='list-style-type:none'>")
127                         count = 0
128                         for x in individual_lines:
129                             f.write(x + "\n")
130                             count += 1
131                             if count == num_lines / 2:
132                                 f.write("</UL></FONT></TD>\n")
133                                 f.write(
134                                     '<TD WIDTH=50% style="color:#eeeeee; font-size:large">\n'
135                                 )
136                                 f.write("<FONT><UL STYLE='list-style-type:none'>")
137                         f.write("</UL></FONT></TD></TR></TABLE></DIV>")
138                     else:
139                         logger.debug(f"{num_lines} lines: one column mode")
140                         f.write(f"<FONT><UL>{contents}</UL></FONT>")
141                     f.write("</DIV>")
142             else:
143                 logger.debug(f"Note is empty, deleting {filename}.")
144                 _ = os.path.join(kiosk_constants.pages_dir, filename)
145                 try:
146                     os.remove(_)
147                 except:
148                     pass
149
150     if self.token_file:
151         token = self.keep.getMasterToken()
152         os.umask(0)
153         descriptor = os.open(
154             path=self.token_file,
155             flags=(os.O_WRONLY | os.O_CREAT | os.O_TRUNC),
156             mode=0o600,
157         )
158         with open(descriptor, "w") as wf:
159             print(token, file=wf)
160         logger.debug("Saved Google Keep token successfully.")
161     return True
162
163
164 # Test
165 # logger.setLevel(logging.DEBUG)
166 # ch = logging.StreamHandler()
167 # ch.setLevel(logging.DEBUG)
168 # formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
169 # ch.setFormatter(formatter)
170 # logger.addHandler(ch)
171 # x = gkeep_renderer({"Test", 1234})
172 # x.periodic_render("Test")