6 from threading import Thread
8 from datetime import datetime
12 import renderer_catalog
15 import trigger_catalog
18 def filter_news_during_dinnertime(page):
20 is_dinnertime = now.hour >= 17 and now.hour <= 20
21 return (not is_dinnertime or
24 "mynorthwest" in page or
30 def thread_change_current():
31 page_chooser = chooser.weighted_random_chooser_with_triggers(
32 trigger_catalog.get_triggers(),
33 [ filter_news_during_dinnertime ])
38 (page, triggered) = page_chooser.choose_next_page()
41 print('chooser[%s] - WE ARE TRIGGERED.' % utils.timestamp())
43 print('chooser[%s] - EMERGENCY PAGE %s LOAD NEEDED' % (
44 utils.timestamp(), page))
46 f = open(os.path.join(constants.pages_dir,
47 'current.shtml'), 'w')
51 print('chooser[%s] - page does not exist?!' % (
55 swap_page_target = now + constants.refresh_period_sec
57 # Also notify XMLHTTP clients that they need to refresh now.
58 path = os.path.join(constants.pages_dir,
59 'reload_immediately.html')
61 f.write('Reload, suckers!')
64 # Fix this hack... maybe read the webserver logs and see if it
65 # actually was picked up?
69 elif now >= swap_page_target:
70 if (page == last_page):
71 print(('chooser[%s] - nominal choice got the same page...' % (
74 print('chooser[%s] - nominal choice of %s' % (utils.timestamp(), page))
76 f = open(os.path.join(constants.pages_dir,
77 'current.shtml'), 'w')
81 print('chooser[%s] - page does not exist?!' % (utils.timestamp()))
84 swap_page_target = now + constants.refresh_period_sec
87 def pick_background_color():
89 if now.hour <= 6 or now.hour >= 21:
91 elif now.hour == 7 or now.hour == 20:
96 def emit_wrapped(f, filename):
97 age = utils.describe_age_of_file_briefly("pages/%s" % filename)
98 bgcolor = pick_background_color()
101 <TITLE>Kitchen Kiosk</TITLE>
102 <LINK rel="stylesheet" type="text/css" href="style.css">
103 <SCRIPT TYPE="text/javascript">
105 // Zoom the 'contents' div to fit without scrollbars and then make
107 function zoomScreen() {
110 document.getElementById("content").style.zoom = z+"%%";
111 var body = document.body;
112 var html = document.documentElement;
113 var height = Math.max(body.scrollHeight,
118 var windowHeight = window.innerHeight;
119 var width = Math.max(body.scrollWidth,
124 var windowWidth = window.innerWidth;
125 var heightRatio = height / windowHeight;
126 var widthRatio = width / windowWidth;
128 if (heightRatio <= 1.0 && widthRatio <= 1.0) {
133 document.getElementById("content").style.visibility = "visible";
136 // Load IMG tags with DATA-SRC attributes late.
137 function lateLoadImages() {
138 var image = document.getElementsByTagName('img');
139 for (var i = 0; i < image.length; i++) {
140 if (image[i].getAttribute('DATA-SRC')) {
141 image[i].setAttribute('SRC', image[i].getAttribute('DATA-SRC'));
146 // Operate the clock at the top of the page.
147 function runClock() {
148 var today = new Date();
149 var h = today.getHours();
150 var ampm = h >= 12 ? 'pm' : 'am';
152 h = h ? h : 12; // the hour '0' should be '12'
153 var m = maybeAddZero(today.getMinutes());
155 if (today.getSeconds() %% 2 == 0) {
156 colon = "<FONT STYLE='color: #%s; font-size: 4vmin; font-weight: bold'>:</FONT>";
158 document.getElementById("time").innerHTML = h + colon + m + ampm;
159 document.getElementById("date").innerHTML = today.toDateString();
160 var t = setTimeout(function(){runClock()}, 1000);
163 // Helper method for running the clock.
164 function maybeAddZero(x) {
165 return (x < 10) ? "0" + x : x;
168 // Do something on page load.
169 function addLoadEvent(func) {
170 var oldonload = window.onload;
171 if (typeof window.onload != 'function') {
172 window.onload = func;
174 window.onload = function() {
183 // Sleep thread helper.
184 const sleep = (milliseconds) => {
185 return new Promise(resolve => setTimeout(resolve, milliseconds))
188 var loadedDate = new Date();
190 addLoadEvent(zoomScreen);
191 addLoadEvent(runClock);
192 addLoadEvent(lateLoadImages);
194 // Runs the countdown line at the bottom and is responsible for
195 // normal page reloads caused by the expiration of a timer.
196 (function countdown() {
199 var now = new Date();
200 var deltaMs = now.getTime() - loadedDate.getTime();
202 var remainingMs = (totalMs - deltaMs);
204 if (remainingMs > 0) {
205 var hr = document.getElementById("countdown");
206 var width = (remainingMs / (totalMs - 5000)) * 100.0;
208 hr.style.visibility = "visible";
209 hr.style.width = " ".concat(width, "%%");
210 hr.style.backgroundColor = "maroon";
213 // Reload unconditionally after 22 sec.
214 window.location.reload();
217 // Brief sleep before doing it all over again.
218 sleep(50).then(() => {
224 // Periodically checks for emergency reload events.
228 var xhr = new XMLHttpRequest();
230 'http://wannabe.house/kiosk/pages/reload_immediately.html');
233 if (xhr.status === 200) {
234 window.location.reload();
236 sleep(500).then(() => {
247 <TABLE style="height:100%%; width:100%%" BORDER=0>
250 <DIV id="date"> </DIV>
252 <TD ALIGN="center"><FONT COLOR=#bbbbbb>
253 <DIV id="info"></DIV></FONT>
256 <DIV id="time"> </DIV>
259 <TR STYLE="vertical-align:top">
261 <DIV ID="content" STYLE="zoom: 1; visibility: hidden;">
262 <!-- BEGIN main page contents. -->
263 <!--#include virtual=\"%s\"-->
264 <!-- END main page contents. -->
267 <DIV STYLE="position: absolute; top:1030px; width:99%%">
269 <FONT SIZE=2 COLOR=#bbbbbb>%s @ %s ago.</FONT>
271 <HR id="countdown" STYLE="width:0px;
278 background-color:#ffffff;">
283 </BODY>""" % (bgcolor,
284 constants.refresh_period_sec * 1000,
290 def thread_invoke_renderers():
292 print("renderer[%s]: invoking all renderers in catalog..." % (
294 for r in renderer_catalog.get_renderers():
298 except Exception as e:
299 traceback.print_exc()
300 print("renderer[%s] unknown exception in %s, swallowing it." % (
301 utils.timestamp(), r.get_name()))
303 traceback.print_exc()
304 print("renderer[%s] unknown error in %s, swallowing it." % (
305 utils.timestamp(), r.get_name()))
306 delta = time.time() - now
308 print("renderer[%s]: Warning: %s's rendering took %5.2fs." % (
309 utils.timestamp(), r.get_name(), delta))
310 print("renderer[%s]: thread having a little break for %ds..." % (
311 utils.timestamp(), constants.render_period_sec))
312 time.sleep(constants.render_period_sec)
314 if __name__ == "__main__":
315 logging.basicConfig()
316 changer_thread = None
317 renderer_thread = None
319 if (changer_thread == None or
320 not changer_thread.is_alive()):
321 print("MAIN[%s] - (Re?)initializing chooser thread..." % (
323 changer_thread = Thread(target = thread_change_current, args=())
324 changer_thread.start()
325 if (renderer_thread == None or
326 not renderer_thread.is_alive()):
327 print("MAIN[%s] - (Re?)initializing render thread..." % (
329 renderer_thread = Thread(target = thread_invoke_renderers, args=())
330 renderer_thread.start()
332 print("Should never get here.")