#!/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")