Various small changes; fix up the camera trigger, improve logging,
[kiosk.git] / stranger_renderer.py
1 from bs4 import BeautifulSoup
2 import datetime
3 import file_writer
4 import grab_bag
5 import http.client
6 import page_builder
7 import profanity_filter
8 import random
9 import re
10 import renderer
11
12 class stranger_events_renderer(renderer.debuggable_abstaining_renderer):
13     def __init__(self, name_to_timeout_dict):
14         super(stranger_events_renderer, self).__init__(name_to_timeout_dict, True)
15         self.feed_site = "everout.com"
16         self.events = grab_bag.grab_bag()
17
18     def debug_prefix(self):
19         return "stranger"
20
21     def periodic_render(self, key):
22         self.debug_print("called for action %s" % key)
23         if key == "Fetch Events":
24             return self.fetch_events()
25         elif key == "Shuffle Events":
26             return self.shuffle_events()
27         else:
28             raise error("Unknown operaiton")
29
30     def get_style(self):
31         return """
32 <STYLE>
33 .calendar-post {
34   line-height: 96%;
35 }
36 .calendar-post-title a {
37   text-decoration: none;
38   color:black;
39   font-size:125%
40   line-height:104%;
41 }
42 .calendar-post-date {
43 }
44 .calendar-post-category {
45 }
46 .calendar-post-location {
47 }
48 .calendar-post-price {
49 }
50 .calendar-touch-link {
51 }
52 .calendar-category {
53   background-color:lightyellow;
54   color:black;
55   border:none;
56   font-size:50%;
57   padding:1px;
58 }
59 .calendar-post-price-mobile {
60   visibility: hidden;
61 }
62 .img-responsive {
63   float: left;
64   margin: 10px 10px 10px 10px;
65 }
66 </STYLE>"""
67
68     def shuffle_events(self):
69         layout = page_builder.page_builder()
70         layout.set_layout(page_builder.page_builder.LAYOUT_FOUR_ITEMS)
71         layout.set_title("Stranger Events")
72         layout.set_style(self.get_style())
73         subset = self.events.subset(4)
74         if subset is None:
75             self.debug_print("Not enough events to build page.")
76             return False
77
78         for msg in subset:
79             layout.add_item(msg)
80         f = file_writer.file_writer('stranger-events_2_none.html')
81         layout.render_html(f)
82         f.close()
83         return True
84
85     def fetch_events(self):
86         self.events.clear()
87         feed_uris = [
88             "/stranger-seattle/events/?page=1",
89             "/stranger-seattle/events/?page=2",
90             "/stranger-seattle/events/?page=3",
91         ]
92         now = datetime.datetime.now()
93         ts = now + datetime.timedelta(1)
94         tomorrow = datetime.datetime.strftime(ts, "%Y-%m-%d")
95         feed_uris.append("/stranger-seattle/events/?start-date=%s" % tomorrow)
96         delta = 5 - now.weekday()
97         if delta <= 0:
98             delta += 7
99         if delta > 1:
100             ts = now + datetime.timedelta(delta)
101             next_sat = datetime.datetime.strftime(ts, "%Y-%m-%d")
102             feed_uris.append("/stranger-seattle/events/?start-date=%s&page=1" % next_sat)
103             feed_uris.append("/stranger-seattle/events/?start-date=%s&page=2" % next_sat)
104         delta += 1
105         if delta > 1:
106             ts = now + datetime.timedelta(delta)
107             next_sun = datetime.datetime.strftime(ts, "%Y-%m-%d")
108             feed_uris.append("/stranger-seattle/events/?start-date=%s&page=1" % next_sun)
109             feed_uris.append("/stranger-seattle/events/?start-date=%s&page=2" % next_sun)
110
111         for uri in feed_uris:
112             try:
113                 self.debug_print("fetching 'https://%s%s'" % (self.feed_site, uri))
114                 self.conn = http.client.HTTPSConnection(self.feed_site)
115                 self.conn.request(
116                     "GET",
117                     uri,
118                     None,
119                     {"Accept-Charset": "utf-8"})
120                 response = self.conn.getresponse()
121                 if response.status != 200:
122                     self.debug_print("Connection failed, status %d" % (
123                         response.status))
124                     self.debug_print(response.getheaders())
125                     continue
126                 raw = response.read()
127             except:
128                 self.debug_print("Exception talking to the stranger, ignoring.")
129                 continue
130
131             soup = BeautifulSoup(raw, "html.parser")
132             filter = profanity_filter.profanity_filter()
133             for x in soup.find_all('div', class_='row event list-item mb-3 py-3'):
134                 text = x.get_text();
135                 if (filter.contains_bad_words(text)):
136                     continue
137                 raw = str(x)
138                 raw = raw.replace('src="/',
139                                   'align="left" src="https://www.thestranger.com/')
140                 raw = raw.replace('href="/',
141                                   'href="https://www.thestranger.com/')
142                 raw = raw.replace('FREE', 'Free')
143                 raw = raw.replace('Save Event', '')
144                 raw = re.sub('^\s*$', '', raw, 0, re.MULTILINE)
145                 #raw = re.sub('\n+', '\n', raw)
146                 raw = re.sub('<span[^<>]*class="calendar-post-ticket"[^<>]*>.*</#span>', '', raw, 0, re.DOTALL | re.IGNORECASE)
147                 self.events.add(raw)
148             self.debug_print("fetched %d events so far." % self.events.size())
149         return self.events.size() > 0
150
151 # Test
152 #x = stranger_events_renderer({"Test", 123})
153 #x.periodic_render("Fetch Events")
154 #x.periodic_render("Shuffle Events")