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