1 #!/usr/local/bin/python3.7
6 from threading import Thread
8 from datetime import datetime
12 import renderer_catalog
15 import trigger_catalog
18 def thread_change_current():
19 page_chooser = chooser.weighted_random_chooser_with_triggers(
20 trigger_catalog.get_triggers())
25 (page, triggered) = page_chooser.choose_next_page()
28 print('chooser[%s] - WE ARE TRIGGERED.' % utils.timestamp())
30 print('chooser[%s] - EMERGENCY PAGE %s LOAD NEEDED' % (
31 utils.timestamp(), page))
33 f = open(os.path.join(constants.pages_dir,
34 'current.shtml'), 'w')
38 print('chooser[%s] - page does not exist?!' % (
42 swap_page_target = now + constants.refresh_period_sec
44 # Also notify XMLHTTP clients that they need to refresh now.
45 path = os.path.join(constants.pages_dir,
46 'reload_immediately.html')
48 f.write('Reload, suckers!')
51 # Fix this hack... maybe read the webserver logs and see if it
52 # actually was picked up?
56 elif now >= swap_page_target:
57 if (page == last_page):
58 print(('chooser[%s] - nominal choice got the same page...' % (
61 print('chooser[%s] - nominal choice of %s' % (utils.timestamp(), page))
63 f = open(os.path.join(constants.pages_dir,
64 'current.shtml'), 'w')
68 print('chooser[%s] - page does not exist?!' % (utils.timestamp()))
71 swap_page_target = now + constants.refresh_period_sec
74 def pick_background_color():
76 if now.hour <= 6 or now.hour >= 21:
78 elif now.hour == 7 or now.hour == 20:
83 def emit_wrapped(f, filename):
84 age = utils.describe_age_of_file_briefly("pages/%s" % filename)
85 bgcolor = pick_background_color()
88 <TITLE>Kitchen Kiosk</TITLE>
89 <LINK rel="stylesheet" type="text/css" href="style.css">
90 <SCRIPT TYPE="text/javascript">
92 // Zoom the 'contents' div to fit without scrollbars and then make
94 function zoomScreen() {
97 document.getElementById("content").style.zoom = z+"%%";
98 var body = document.body;
99 var html = document.documentElement;
100 var height = Math.max(body.scrollHeight,
105 var windowHeight = window.innerHeight;
106 var width = Math.max(body.scrollWidth,
111 var windowWidth = window.innerWidth;
112 var heightRatio = height / windowHeight;
113 var widthRatio = width / windowWidth;
115 if (heightRatio <= 1.0 && widthRatio <= 1.0) {
120 document.getElementById("content").style.visibility = "visible";
123 // Load IMG tags with DATA-SRC attributes late.
124 function lateLoadImages() {
125 var image = document.getElementsByTagName('img');
126 for (var i = 0; i < image.length; i++) {
127 if (image[i].getAttribute('DATA-SRC')) {
128 image[i].setAttribute('SRC', image[i].getAttribute('DATA-SRC'));
133 // Operate the clock at the top of the page.
134 function runClock() {
135 var today = new Date();
136 var h = today.getHours();
137 var ampm = h >= 12 ? 'pm' : 'am';
139 h = h ? h : 12; // the hour '0' should be '12'
140 var m = maybeAddZero(today.getMinutes());
142 if (today.getSeconds() %% 2 == 0) {
143 colon = "<FONT STYLE='color: #%s; font-size: 4vmin; font-weight: bold'>:</FONT>";
145 document.getElementById("time").innerHTML = h + colon + m + ampm;
146 document.getElementById("date").innerHTML = today.toDateString();
147 var t = setTimeout(function(){runClock()}, 1000);
150 // Helper method for running the clock.
151 function maybeAddZero(x) {
152 return (x < 10) ? "0" + x : x;
155 // Do something on page load.
156 function addLoadEvent(func) {
157 var oldonload = window.onload;
158 if (typeof window.onload != 'function') {
159 window.onload = func;
161 window.onload = function() {
170 // Sleep thread helper.
171 const sleep = (milliseconds) => {
172 return new Promise(resolve => setTimeout(resolve, milliseconds))
176 var loadedDate = new Date();
178 addLoadEvent(zoomScreen);
179 addLoadEvent(runClock);
180 addLoadEvent(lateLoadImages);
181 addLoadEvent(function() {
185 // Reload the page after a certain amount of time has passed or
186 // immediately if told to do so.
190 var now = new Date();
191 var deltaMs = now.getTime() - loadedDate.getTime();
193 // Reload unconditionally after 22 sec.
195 window.location.reload();
198 // Reload immediately if told.
199 var xhr = new XMLHttpRequest();
201 'http://wannabe.house/kiosk/pages/reload_immediately.html');
204 if (xhr.status === 200) {
205 window.location.reload();
207 sleep(500).then(() => {
218 <TABLE style="height:100%%; width:100%%" BORDER=0>
221 <DIV id="date"> </DIV>
223 <TD ALIGN="center"><FONT COLOR=#bbbbbb>
224 <DIV id="info"></DIV></FONT>
227 <DIV id="time"> </DIV>
230 <TR STYLE="vertical-align:top">
232 <DIV ID="content" STYLE="zoom: 1; visibility: hidden;">
233 <!-- BEGIN main page contents. -->
234 <!--#include virtual=\"%s\"-->
235 <!-- END main page contents. -->
239 <FONT SIZE=2 COLOR=#bbbbbb>%s @ %s ago.</FONT>
244 </BODY>""" % (bgcolor,
245 constants.refresh_period_sec * 1000,
251 def thread_invoke_renderers():
253 print("renderer[%s]: invoking all renderers in catalog..." % (
255 for r in renderer_catalog.get_renderers():
259 except Exception as e:
260 traceback.print_exc()
261 print("renderer[%s] unknown exception in %s, swallowing it." % (
262 utils.timestamp(), r.get_name()))
264 traceback.print_exc()
265 print("renderer[%s] unknown error in %s, swallowing it." % (
266 utils.timestamp(), r.get_name()))
267 delta = time.time() - now
269 print("renderer[%s]: Warning: %s's rendering took %5.2fs." % (
270 utils.timestamp(), r.get_name(), delta))
271 print("renderer[%s]: thread having a little break for %ds..." % (
272 utils.timestamp(), constants.render_period_sec))
273 time.sleep(constants.render_period_sec)
275 if __name__ == "__main__":
276 logging.basicConfig()
277 changer_thread = None
278 renderer_thread = None
280 if (changer_thread == None or
281 not changer_thread.is_alive()):
282 print("MAIN[%s] - (Re?)initializing chooser thread..." % (
284 changer_thread = Thread(target = thread_change_current, args=())
285 changer_thread.start()
286 if (renderer_thread == None or
287 not renderer_thread.is_alive()):
288 print("MAIN[%s] - (Re?)initializing render thread..." % (
290 renderer_thread = Thread(target = thread_invoke_renderers, args=())
291 renderer_thread.start()
293 print("Should never get here.")