commit 7c0afd011404db6b54f0646015e05f6ac2f7f738 Author: zman Date: Sun Mar 3 14:38:44 2024 -0500 first commit 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 0000000..4d51c22 Binary files /dev/null and b/requirements.txt differ 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