#!/usr/bin/env python3 import logging from typing import Callable, Dict, Iterable, List, Set import praw # type: ignore from scottutilz import profanity_filter import file_writer import grab_bag import page_builder import renderer import kiosk_secrets as secrets logger = logging.getLogger(__name__) class reddit_renderer(renderer.abstaining_renderer): """A renderer to pull text content from reddit.""" def __init__( self, name_to_timeout_dict: Dict[str, int], subreddit_list: List[str], *, min_votes: int = 20, font_size: int = 24, additional_filters: Iterable[Callable[[str], bool]] = [], ): super().__init__(name_to_timeout_dict) self.subreddit_list = subreddit_list self.praw = praw.Reddit( client_id=secrets.reddit_client_id, client_secret=secrets.reddit_client_secret, user_agent=secrets.reddit_user_agent, ) self.min_votes = min_votes self.font_size = font_size self.messages = grab_bag.grab_bag() self.filters: List[Callable[..., bool]] = [ profanity_filter.ProfanityFilter().contains_bad_word ] self.filters.extend(additional_filters) self.deduper: Set[str] = set() def periodic_render(self, key: str) -> bool: logger.debug('called for "%s"' % key) if key == "Scrape": return self.scrape_reddit() elif key == "Shuffle": return self.shuffle_messages() else: raise Exception("Unexpected operation") def append_message(self, messages: List[str]) -> None: for msg in messages: title = str(msg.title) if title in self.deduper: continue filtered = "" for filt in self.filters: if filt(title) is True: filtered = filt.__name__ break if filtered != "": logger.info(f'Filter {filtered} struck down "{title}"') continue if msg.ups < self.min_votes: logger.debug( f'"{title}" doesn\'t have enough upvotes to be interesting' ) continue self.deduper.add(title) content = f"{msg.ups}" if ( msg.thumbnail != "self" and msg.thumbnail != "default" and msg.thumbnail != "" ): content = f'' self.messages.add( f"""
{content} {title}
({msg.author})
""" ) def scrape_reddit(self) -> bool: self.deduper.clear() self.messages.clear() for subreddit in self.subreddit_list: try: msg = self.praw.subreddit(subreddit).hot() self.append_message(msg) except: pass try: msg = self.praw.subreddit(subreddit).new() self.append_message(msg) except: pass try: msg = self.praw.subreddit(subreddit).rising() self.append_message(msg) except: pass try: msg = self.praw.subreddit(subreddit).controversial("week") self.append_message(msg) except: pass try: msg = self.praw.subreddit(subreddit).top("day") self.append_message(msg) except: pass logger.debug(f"There are now {self.messages.size()} messages") return True def shuffle_messages(self) -> bool: layout = page_builder.page_builder() layout.set_layout(page_builder.page_builder.LAYOUT_FOUR_ITEMS) x = "" for subreddit in self.subreddit_list: x += f"{subreddit} " if len(x) > 30: if "SeaWA" in x: x = "[local interests]" else: x = "Unknown, fixme" layout.set_title("Reddit /r/%s" % x.strip()) subset = self.messages.subset(4) if subset is None: logger.debug("Not enough messages to pick from.") return False for msg in subset: layout.add_item(msg) with file_writer.file_writer("%s_4_10800.html" % self.subreddit_list[0]) as f: layout.render_html(f) return True class til_reddit_renderer(reddit_renderer): def __init__(self, name_to_timeout_dict: Dict[str, int]): super().__init__( name_to_timeout_dict, ["todayilearned"], min_votes=100, font_size=20 ) class quotes_reddit_renderer(reddit_renderer): def __init__(self, name_to_timeout_dict: Dict[str, int]): super().__init__(name_to_timeout_dict, ["quotes"], min_votes=100, font_size=20) class showerthoughts_reddit_renderer(reddit_renderer): @staticmethod def dont_tell_me_about_gift_cards(msg: str) -> bool: return "gift card" in msg def __init__(self, name_to_timeout_dict: Dict[str, int]): super().__init__( name_to_timeout_dict, ["showerthoughts"], min_votes=150, additional_filters=[ showerthoughts_reddit_renderer.dont_tell_me_about_gift_cards ], ) class seattle_reddit_renderer(reddit_renderer): def __init__(self, name_to_timeout_dict: Dict[str, int]): super().__init__( name_to_timeout_dict, ["seattle", "seattleWA", "SeaWA", "bellevue", "kirkland", "CoronavirusWA"], min_votes=50, ) class lifeprotips_reddit_renderer(reddit_renderer): def __init__(self, name_to_timeout_dict: Dict[str, int]): super().__init__(name_to_timeout_dict, ["lifeprotips"], min_votes=50) # x = reddit_renderer({"Test", 1234}, ["seattle","bellevue"], min_votes=50, font_size=24) # x.periodic_render("Scrape") # x.periodic_render("Shuffle")