Initial commit
[kiosk.git] / stranger_renderer.py
1 from bs4 import BeautifulSoup
2 import datetime
3 import file_writer
4 import grab_bag
5 import httplib
6 import page_builder
7 import profanity_filter
8 import random
9 import re
10 import renderer
11 import sets
12
13 class stranger_events_renderer(renderer.debuggable_abstaining_renderer):
14     def __init__(self, name_to_timeout_dict):
15         super(stranger_events_renderer, self).__init__(name_to_timeout_dict, True)
16         self.feed_site = "everout.thestranger.com"
17         self.events = grab_bag.grab_bag()
18
19     def debug_prefix(self):
20         return "stranger"
21
22     def periodic_render(self, key):
23         self.debug_print("called for action %s" % key)
24         if key == "Fetch Events":
25             return self.fetch_events()
26         elif key == "Shuffle Events":
27             return self.shuffle_events()
28         else:
29             raise error("Unknown operaiton")
30
31     def get_style(self):
32         return """
33 <STYLE>
34 .calendar-post {
35   line-height: 96%;
36 }
37 .calendar-post-title a {
38   text-decoration: none;
39   color:black;
40   font-size:125%
41   line-height:104%;
42 }
43 .calendar-post-date {
44 }
45 .calendar-post-category {
46 }
47 .calendar-post-location {
48 }
49 .calendar-post-price {
50 }
51 .calendar-touch-link {
52 }
53 .calendar-category {
54   background-color:lightyellow;
55   color:black;
56   border:none;
57   font-size:50%;
58   padding:1px;
59 }
60 .calendar-post-price-mobile {
61   visibility: hidden;
62 }
63 .img-responsive {
64   float: left;
65   margin: 10px 10px 10px 10px;
66 }
67 </STYLE>"""
68
69     def shuffle_events(self):
70         layout = page_builder.page_builder()
71         layout.set_layout(page_builder.page_builder.LAYOUT_FOUR_ITEMS)
72         layout.set_title("Stranger Events")
73         layout.set_style(self.get_style())
74         subset = self.events.subset(4)
75         if subset is None:
76             self.debug_print("Not enough events to build page.")
77             return False
78
79         for msg in subset:
80             layout.add_item(msg)
81         f = file_writer.file_writer('stranger-events_2_none.html')
82         layout.render_html(f)
83         f.close()
84         return True
85
86     def fetch_events(self):
87         self.events.clear()
88         feed_uris = [
89             "/events/?page=1&picks=true",
90             "/events/?page=2&picks=true",
91             "/events/?page=3&picks=true",
92         ]
93         now = datetime.datetime.now()
94         ts = now + datetime.timedelta(1)
95         tomorrow = datetime.datetime.strftime(ts, "%Y-%m-%d")
96         feed_uris.append("/events/?start-date=%s&picks=true" % tomorrow)
97         delta = 5 - now.weekday()
98         if delta <= 0:
99             delta += 7
100         if delta > 1:
101             ts = now + datetime.timedelta(delta)
102             next_sat = datetime.datetime.strftime(ts, "%Y-%m-%d")
103             feed_uris.append("/events/?start-date=%s&page=1&picks=true" % next_sat)
104             feed_uris.append("/events/?start-date=%s&page=2&picks=true" % next_sat)
105         delta += 1
106         if delta > 1:
107             ts = now + datetime.timedelta(delta)
108             next_sun = datetime.datetime.strftime(ts, "%Y-%m-%d")
109             feed_uris.append("/events/?start-date=%s&page=1&picks=true" % next_sun)
110             feed_uris.append("/events/?start-date=%s&page=2&picks=true" % next_sun)
111
112         for uri in feed_uris:
113             self.debug_print("fetching '%s'" % uri)
114             self.conn = httplib.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                 print("stranger: Failed, status %d" % (response.status))
123                 continue
124
125             raw = response.read()
126             soup = BeautifulSoup(raw, "html.parser")
127             filter = profanity_filter.profanity_filter()
128             for x in soup.find_all('div', class_='row event list-item mb-3 py-3'):
129                 text = x.get_text();
130                 if (filter.contains_bad_words(text)):
131                     continue
132
133 #          <div class="row event list-item mb-3 py-3">
134 #          <div class="col-12">
135 #                <a class="category-tag" href="?category=on-demand">On Demand</a>
136 #          </div> // col-12
137 #          <div class="col-md-3 order-1 order-md-3">
138 #              <a href="https://everout.thestranger.com/events/spliff-2020-on-demand/e24125/">
139 #                  <img class="img-responsive" src="https://d2i729k8wyri5w.cloudfront.net/eyJidWNrZXQiOiAiZXZlcm91dC1pbWFnZXMtcHJvZHVjdGlvbiIsICJrZXkiOiAiaW1hZ2UtMTU5MTA2NTQxODU5NzA5My1vcmlnaW5hbC1sb2dvLmpwZWciLCAiZWRpdHMiOiB7InJlc2l6ZSI6IHsiZml0IjogImNvdmVyIiwgIndpZHRoIjogNDAwLCAiaGVpZ2h0IjogMzAwfX19">
140 #              </a>
141 #          </div> // col-md-3 order-1 order-md-3
142 #          <div class="col-md-6 order-2 order-md-1 event-details">
143 #             <h3 class="mb-0 event-title">
144 #                 <a href="https://everout.thestranger.com/events/spliff-2020-on-demand/e24125/"><span class="staff-pick fas fa-star" aria-hidden="true"></span></a>
145 #                 <a href="https://everout.thestranger.com/events/spliff-2020-on-demand/e24125/">
146 #                 <span class="title-link">SPLIFF 2020 - On Demand</span>
147 #                 </a>
148 #             </h3>
149 #             <div class="event-date">
150 #               Every day
151 #             </div> // event-date
152 #             <div class="event-time">
153 #             </div> // event-time
154 #          </div> // col-md-6 order-2 order-md-1 event-details
155 #          <div class="col-md-3 order-3 order-md-2 location-column">
156 #            <div class="location-name">
157 #              <i class="fad fa-map-marker-alt"></i> <a href="https://everout.thestranger.com/locations/the-stranger-online/l27660/">The Stranger (Online)</a>
158 #            </div> // location-name
159 #            <div class="location-region">
160 #            </div> // location-region
161 #            <ul class="event-tags">
162 #              <li>$10 - $20</li>
163 #            </ul>
164 #          </div> // col-md-3 order-3 order-md-2 location-colum
165 #        </div> // row event list-item mb-3 py-3
166
167                 raw = unicode(x)
168                 raw = raw.replace('src="/',
169                                   'align="left" src="https://www.thestranger.com/')
170                 raw = raw.replace('href="/',
171                                   'href="https://www.thestranger.com/')
172                 raw = raw.replace('FREE', 'Free')
173                 raw = raw.replace('Save Event', '')
174                 raw = re.sub('^\s*$', '', raw, 0, re.MULTILINE)
175                 raw = re.sub('\n+', '\n', raw)
176                 raw = re.sub('<span[^<>]*class="calendar-post-ticket"[^<>]*>.*</#span>', '', raw, 0, re.DOTALL | re.IGNORECASE)
177                 self.events.add(raw.encode('utf-8'))
178             self.debug_print("fetched %d events so far." % self.events.size())
179         return self.events.size() > 0
180
181 x = stranger_events_renderer({"Test", 123})
182 x.periodic_render("Fetch Events")
183 x.periodic_render("Shuffle Events")