Merge branch 'master' of ssh://wwwjail.house/usr/local/git/base/kiosk
[kiosk.git] / recipe_renderer_and_trigger.py
1 #!/usr/bin/env python3
2
3 import logging
4 import os
5 from typing import Dict, Optional, List, Tuple
6
7 from pyutils.files import file_utils
8
9 import kiosk_constants as constants
10 import file_writer
11 import globals
12 import renderer
13 import trigger
14
15
16 logger = logging.getLogger(__name__)
17
18 RECIPE_PAGE = "recipe-unwrapped_1_82400.html"
19 RECIPE_PATH = os.path.join(constants.pages_dir, RECIPE_PAGE)
20
21
22 class RecipeTrigger(trigger.trigger):
23     def get_triggered_page_list(self) -> Optional[List[Tuple[str, int]]]:
24         if globals.get("recipe_page_triggered"):
25             logger.debug("Recipe page is triggered!")
26             return [(RECIPE_PAGE, trigger.trigger.PRIORITY_HIGH)]
27         return None
28
29
30 class RecipeRenderer(renderer.abstaining_renderer):
31     def __init__(
32         self,
33         url_location: str,
34         name_to_timeout_dict: Dict[str, int],
35     ) -> None:
36         super().__init__(name_to_timeout_dict)
37         self.url_location = url_location
38
39     def periodic_render(self, key: str) -> bool:
40         triggered = False
41         if file_utils.does_path_exist(self.url_location):
42             with open(self.url_location, "r") as rf:
43                 url = rf.read()
44             url.strip()
45             logger.debug(f"Read {url} from {self.url_location}, writing the page")
46
47             if url and len(url) > 0:
48                 with file_writer.file_writer(RECIPE_PATH) as f:
49                     f.write(
50                         """
51 <!DOCTYPE html>
52 <html>
53   <head>
54     <title>Current Recipe</title>
55     <style>
56       #recipe {
57           height: 100%;
58       }
59       html,
60       body {
61           height: 100%;
62           margin: 0;
63           padding: 0;
64       }
65     </style>
66     <script>
67       const sleep = (milliseconds) => {
68           return new Promise(resolve => setTimeout(resolve, milliseconds))
69       }
70
71       function iframeRef( frameRef ) {
72         return frameRef.contentWindow
73           ? frameRef.contentWindow.document
74           : frameRef.contentDocument
75       }
76
77       function countdown() {
78           setTimeout(
79               function() {
80                   var now = new Date();
81                   var deltaMs = now.getTime() - loadedDate.getTime();
82                   var totalMs = 120000;
83                   var remainingMs = (totalMs - deltaMs);
84
85                   if (remainingMs <= 0) {
86                       // Reload unconditionally every two minutes.
87                       window.location.reload(true);
88                   }
89
90                   // Get rid of the recipe title bar, it's too big.
91                   var recipe = iframeRef(document.getElementById('embedded'))
92                   recipe.getElementById('id_main_nav').style.visibility = 'hidden';
93
94                   // Brief sleep before doing it all over again.
95                   sleep(1000).then(() => {
96                       countdown();
97                   });
98               }, 1000)
99       }
100     </script>
101   </head>
102                        """
103                     )
104                     f.write(
105                         f"""
106   <body onload='javascript:loadedDate = new Date(); countdown();'>
107     <span>
108       <div id="recipe">
109         <IFRAME ID='embedded' WIDTH=100% HEIGHT=100% SRC="{url}"></IFRAME>
110       </div>
111     </span>
112   </body>
113 </html>
114                        """
115                     )
116                     triggered = True
117
118         if not triggered:
119             logger.debug("We are no longer triggered.")
120             if file_utils.does_path_exist(RECIPE_PATH):
121                 file_utils.remove(RECIPE_PATH)
122         else:
123             logger.debug("We are triggered.")
124         globals.put("recipe_page_triggered", triggered)
125         return True