From 7c0afd011404db6b54f0646015e05f6ac2f7f738 Mon Sep 17 00:00:00 2001 From: zman Date: Sun, 3 Mar 2024 14:38:44 -0500 Subject: [PATCH] first commit --- .gitignore | 3 ++ app.py | 49 ++++++++++++++++++++++++++++ config.py | 15 +++++++++ main.py | 33 +++++++++++++++++++ models.py | 79 ++++++++++++++++++++++++++++++++++++++++++++++ reddit_monitor.py | 27 ++++++++++++++++ requirements.txt | Bin 0 -> 470 bytes webhook.py | 21 ++++++++++++ 8 files changed, 227 insertions(+) create mode 100644 .gitignore create mode 100644 app.py create mode 100644 config.py create mode 100644 main.py create mode 100644 models.py create mode 100644 reddit_monitor.py create mode 100644 requirements.txt create mode 100644 webhook.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa421b1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.db +__pycache__ +.venv diff --git a/app.py b/app.py new file mode 100644 index 0000000..48b7172 --- /dev/null +++ b/app.py @@ -0,0 +1,49 @@ +import threading +import time +from datetime import datetime +from models import Submission, session_scope, submission_exists, update_submission, insert_submission + + +class Application: + def __init__(self, reddit_monitor, webhook_notifier): + self.reddit_monitor = reddit_monitor + self.webhook_notifier = webhook_notifier + + def process_submissions(self, submissions): + with session_scope() as session: + for submission in submissions: + if submission_exists(session, submission.id): + update_submission(session, submission) + else: + submission = Submission( + id=submission.id, + title=submission.title, + name=submission.name, + url=submission.url, + score=submission.score, + num_comments=submission.num_comments, + created_utc=submission.created_utc, + selftext=submission.selftext, + permalink=submission.permalink, + upvote_ratio=submission.upvote_ratio + ) + insert_submission(session, submission) + self.webhook_notifier.send_notification(submission) + + def periodic_update(self): + submissions = self.reddit_monitor.update_submissions() + self.process_submissions(submissions) + + def run_periodic_update(self, interval=3600): + while True: + self.periodic_update() + print(f"Existing posts Updated at {datetime.now()}") + time.sleep(interval) + + def run(self): + update_frequency = 3600 # 3600 + update_thread = threading.Thread(target=self.run_periodic_update, args=(update_frequency, )) + update_thread.daemon = True + update_thread.start() + submissions = self.reddit_monitor.stream_submissions() + self.process_submissions(submissions) \ No newline at end of file diff --git a/config.py b/config.py new file mode 100644 index 0000000..def5dd8 --- /dev/null +++ b/config.py @@ -0,0 +1,15 @@ +import os + + +class Config: + POKEMANS_DB_URL = os.getenv("POKEMANS_DB_URL", "sqlite:///pokemans.db") + PRAW_CLIENT_ID = os.getenv("PRAW_CLIENT_ID") + PRAW_CLIENT_SECRET = os.getenv("PRAW_CLIENT_SECRET") + PRAW_USERNAME = os.getenv("PRAW_USERNAME") + PRAW_PASSWORD = os.getenv("PRAW_PASSWORD") + POKEMANS_WEBHOOK_URL = os.getenv("POKEMANS_WEBHOOK_URL") + PKMN_ENV = 'dev' # os.getenv("PKMN_ENV") + SUBREDDIT_NAME = "pkmntcgdeals" + USER_AGENT = "praw:zman.video_repost_bot:v0.1.0 (by u/jzman21)" + DISABLE_WEBHOOK = False + DESTROY_DB = False \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..a918aed --- /dev/null +++ b/main.py @@ -0,0 +1,33 @@ +from models import create_db, reset_db +from reddit_monitor import RedditMonitor +from webhook import WebhookNotifier +from app import Application +from config import Config + + +if __name__ == "__main__": + client_id = Config.PRAW_CLIENT_ID + client_secret = Config.PRAW_CLIENT_SECRET + user_agent = Config.USER_AGENT + username = Config.PRAW_USERNAME + password = Config.PRAW_PASSWORD + subreddit_name = Config.SUBREDDIT_NAME + discord_webhook_url = Config.POKEMANS_WEBHOOK_URL + disable_webhook = Config.DISABLE_WEBHOOK + destroy_db = Config.DESTROY_DB + pkmn_env = Config.PKMN_ENV + + if destroy_db and pkmn_env == 'dev': + reset_db() + else: + create_db() + + reddit_monitor = RedditMonitor(client_id, client_secret, user_agent, username, password, subreddit_name) + webhook_notifier = WebhookNotifier(discord_webhook_url, disable_webhook) + app = Application(reddit_monitor, webhook_notifier) + app.run() + +""" +TODO: +- Filter out canadian/uk deals +""" \ No newline at end of file diff --git a/models.py b/models.py new file mode 100644 index 0000000..c157fb6 --- /dev/null +++ b/models.py @@ -0,0 +1,79 @@ +from sqlalchemy import create_engine, Column, Integer, String, Float +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker +import os +from contextlib import contextmanager + + +Base = declarative_base() +Session = sessionmaker() + +@contextmanager +def session_scope(): + session = get_session() + try: + yield session + session.commit() + except: + session.rollback() + raise + finally: + session.close() + +class Submission(Base): + __tablename__ = 'submissions' + id = Column(String, primary_key=True) + title = Column(String) + name = Column(String) + url = Column(String) + score = Column(Integer) + num_comments = Column(Integer) + created_utc = Column(Float) + selftext = Column(String) + permalink = Column(String) + upvote_ratio = Column(Float) + +def get_engine(database_url=os.getenv("POKEMANS_DB_URL", "sqlite:///pokemans.db")): + engine = create_engine(database_url) + Session.configure(bind=engine) + return engine + +def create_db(): + engine = get_engine() + Base.metadata.create_all(engine) + +def reset_db(): + engine = get_engine() + Base.metadata.drop_all(engine) + Base.metadata.create_all(engine) + +def get_session(): + return Session() + +def insert_submission(session, submission): + session.add(submission) + session.commit() + +def submission_exists(session, submission_id): + return session.query(Submission).filter(Submission.id == submission_id).first() is not None + +def get_all_submissions(session): + return session.query(Submission).all() + +def delete_submission(session, submission_id): + session.query(Submission).filter(Submission.id == submission_id).delete() + session.commit() + +def update_submission(session, submission): + session.query(Submission).filter(Submission.id == submission.id).update({ + 'title': submission.title, + 'name': submission.name, + 'url': submission.url, + 'score': submission.score, + 'num_comments': submission.num_comments, + 'created_utc': submission.created_utc, + 'selftext': submission.selftext, + 'permalink': submission.permalink, + 'upvote_ratio': submission.upvote_ratio + }) + session.commit() \ No newline at end of file diff --git a/reddit_monitor.py b/reddit_monitor.py new file mode 100644 index 0000000..9b02d28 --- /dev/null +++ b/reddit_monitor.py @@ -0,0 +1,27 @@ +import praw +from models import Submission, session_scope +from datetime import datetime, timedelta + + +class RedditMonitor: + def __init__(self, client_id, client_secret, user_agent, username, password, subreddit_name): + self.reddit = praw.Reddit( + client_id=client_id, + client_secret=client_secret, + user_agent=user_agent, + username=username, + password=password + ) + self.subreddit = self.reddit.subreddit(subreddit_name) + + def stream_submissions(self): + for submission in self.subreddit.stream.submissions(): + yield submission + + def update_submissions(self): + with session_scope() as session: + one_week_ago = datetime.utcnow() - timedelta(weeks=1) + submissions_to_update = session.query(Submission).filter(Submission.created_utc >= one_week_ago.timestamp()).all() + for db_submission in submissions_to_update: + praw_submission = self.reddit.submission(id=db_submission.id) + yield praw_submission \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..4d51c22fe47c885c90e855b876c6844d1b1b1c4b GIT binary patch literal 470 zcmY+B!A`?K3`FN#iBBm?+6uUE;LZi{0Vv&uQUOUxQWg04!W(ZBfg&eb@3Uv@{G5_% zbsDtOGjYqaP(iG8$=h+EnUY>q!S&FC=4#Y(dMEcr)pzu8?UD*duG+%XJPnlVMxqGH zeRtY$TTM4tp|+>4(lN5vu#WQIO$z-w2)ne~A_yyf=)k*2v7d+~9Y*F+54zVKt~^)G z9A6V>ZwnOdZXmzMW23E};6BNCnx0%6Ur%K167{kBftn5e&CbsXNw1u`P%&BR<`3WD k#Cu$`yZi_8?(@t?D%WVX^l}&PKLu|ud8?kyTgp551rNbStpET3 literal 0 HcmV?d00001 diff --git a/webhook.py b/webhook.py new file mode 100644 index 0000000..9c40edd --- /dev/null +++ b/webhook.py @@ -0,0 +1,21 @@ +import requests + + +class WebhookNotifier: + def __init__(self, webhook_url, disable_webhook=False): + self.webhook_url = webhook_url + self.disable_webhook = disable_webhook + + def send_notification(self, submission): + title = submission.title + url = submission.url + permalink = submission.permalink + selftext = submission.selftext + content = f""" + **New Deal!** + **Title:** {title} + **URL:** {url} + **Permalink:** https://old.reddit.com{permalink} + **Selftext:** {selftext}""" + if not self.disable_webhook: + requests.post(self.webhook_url, data={"content": content}) \ No newline at end of file