diff --git a/config/config.py b/config/config.py index 9562e05..4413dc6 100644 --- a/config/config.py +++ b/config/config.py @@ -6,12 +6,8 @@ user_agent = "Flair Timer Mod Mail Bot" #Subreddits subreddit = "" # "INEEEEDIT" "Ofcoursethatsathing" "All" - -flair_text = "" # Case Sensitive - + interval = 30 # How often should the bot scan the subreddit for these posts, in seconds. Higher = slower/less accurate/save resources, lower = faster/more accurate/use more resources. - -hours = 0.17 # How many hours must the flair been on the post to send the notification - -messagetitle = "" # Title of the modmail -searchlimit = 900 # Max: 1000, this should only be limited to save on resources. The bot sorts by new and if it isn't catching posts that are being changed to the flair simply because they are too old (say the 301st post on the subreddit is changed to the flair) then increase this limit.his limit. + +searchlimit = 900 # Max: 1000, this should only be limited to save on resources. The bot sorts by new and if it isn't catching posts that are being changed to the flair simply because they are too old (say the 301st post on the subreddit is changed to the flair) then increase this limit. + diff --git a/config/flairconfig.py b/config/flairconfig.py new file mode 100644 index 0000000..cbfb754 --- /dev/null +++ b/config/flairconfig.py @@ -0,0 +1,12 @@ +# flairconfig.py +# This file defines the list of flair time configs for the bot. +# Edit this file to customize flair behaviors. + +flair_times = [ + { + "flair_text": "Waiting for OP", + "hours": 48, + "messagetitle": "Modmail Notification", + }, + # Add more configs as needed +] diff --git a/example.env b/example.env index 912fc56..f15ddee 100644 --- a/example.env +++ b/example.env @@ -5,8 +5,5 @@ CLIENT_ID=your_reddit_client_id CLIENT_SECRET=your_reddit_client_secret USER_AGENT=Flair Timer Mod Mail Bot SUBREDDIT=your_subreddit -FLAIR_TEXT=Waiting for OP INTERVAL=30 -HOURS=48 -MESSAGETITLE=Modmail Notification SEARCHLIMIT=600 diff --git a/flairtimermodmail.py b/flairtimermodmail.py index 966c975..4aa1357 100644 --- a/flairtimermodmail.py +++ b/flairtimermodmail.py @@ -1,15 +1,19 @@ import praw +import os import os.path import json import time -# Create default config/config.py if it doesn't exist and exit to prompt manual editing -import sys -default_config_path = os.path.join('config', 'config.py') +# Helper to get env var or default def env_or_default(var, default): return os.environ.get(var, default) + +# Create config/config.py from environment if missing or empty +default_config_path = os.path.join('config', 'config.py') + + def write_config_from_env(): os.makedirs('config', exist_ok=True) with open(default_config_path, 'w') as f: @@ -18,73 +22,116 @@ def write_config_from_env(): f'password = "{env_or_default("PASSWORD", "")}"\n' f'client_id = "{env_or_default("CLIENT_ID", "")}"\n' f'client_secret = "{env_or_default("CLIENT_SECRET", "")}"\n' - f'user_agent = "{env_or_default("USER_AGENT", "Flair Timer Comment Bot" )}"\n' + f'user_agent = "{env_or_default("USER_AGENT", "Flair Timer ModMail Bot")}"\n' '\n' f'subreddit = "{env_or_default("SUBREDDIT", "")}"\n' - f'flair_text = "{env_or_default("FLAIR_TEXT", "Waiting for OP")}"\n' f'interval = {env_or_default("INTERVAL", "30")}\n' - f'hours = {env_or_default("HOURS", "48")}\n' - f'messagetitle = "{env_or_default("MESSAGETITLE", "Modmail Notification")}"\n' f'searchlimit = {env_or_default("SEARCHLIMIT", "600")}\n' ) print(f"Configuration file auto-populated from environment variables at {default_config_path}.") -# Check if config file is missing or empty -populate_config = False -if not os.path.exists(default_config_path): - populate_config = True -else: + +# Check if config file exists and is non-empty, else generate from env +def config_needs_populating(): + if not os.path.exists(default_config_path): + return True try: with open(default_config_path, 'r') as f: content = f.read().strip() - if not content: - populate_config = True + return len(content) == 0 except Exception: - populate_config = True + return True -if populate_config: + +if config_needs_populating(): write_config_from_env() - sys.exit(0) -if not os.path.exists(default_config_path): - sys.exit(0) + +# Import main config import config + + +# Create default flairconfig.py if missing +flair_config_path = os.path.join('config', 'flairconfig.py') + + +def write_default_flairconfig(): + if not os.path.exists(flair_config_path): + os.makedirs(os.path.dirname(flair_config_path), exist_ok=True) + with open(flair_config_path, 'w') as f: + f.write('# flairconfig.py\n') + f.write('# This file defines the list of flair time configs for the bot.\n') + f.write('flair_times = [\n') + f.write(' {\n') + f.write(' "flair_text": "Waiting for OP",\n') + f.write(' "hours": 48,\n') + f.write(' "messagetitle": "Modmail Notification",\n') + f.write(' },\n') + f.write(']\n') + print(f"Default flairconfig.py created at {flair_config_path}.") + + +write_default_flairconfig() + + +# Load flair_times from flairconfig.py +import importlib.util +spec = importlib.util.spec_from_file_location("flairconfig", flair_config_path) +flairconfig = importlib.util.module_from_spec(spec) +spec.loader.exec_module(flairconfig) +flair_times = getattr(flairconfig, "flair_times", []) def authentication(): - print ("Authenticating...") - reddit = praw.Reddit(username = config.username, - password = config.password, - client_id = config.client_id, - client_secret = config.client_secret, - user_agent = config.user_agent) - print ("Authenticated as {}.".format(reddit.user.me())) + print("Authenticating...") + reddit = praw.Reddit( + username=config.username, + password=config.password, + client_id=config.client_id, + client_secret=config.client_secret, + user_agent=config.user_agent + ) + print("Authenticated as {}.".format(reddit.user.me())) return reddit - -def main(reddit, posts: dict): + + +def main(reddit, all_posts: dict): + # all_posts structure: {flair_text: {submission_id: timestamp}} while True: - for submission in reddit.subreddit(config.subreddit).new(limit=config.searchlimit): - if not submission.saved: - if submission.id not in posts.keys() and submission.link_flair_text == config.flair_text: - posts[submission.id] = time.time() - print(f"Post {submission} has been flaired {config.flair_text}") - if submission.id in posts.keys() and submission.link_flair_text != config.flair_text: - posts.pop(submission.id) - print(f"Post {submission} has been unflaired {config.flair_text}") - - for submission in posts: - if time.time() > posts[submission] + (config.hours * 60 * 60): - posts.pop(submission) - reddit.submission(submission).save() - data = { - "subject": config.messagetitle, - "text": f"It has been {config.hours/24} day/s since this was flaired [{config.flair_text}](https://old.reddit.com{reddit.submission(submission).permalink})", - "to": "/r/{}".format(config.subreddit), - } - reddit.post("api/compose/", data=data) - print(f"Post {submission} has been flaired {config.flair_text} for {config.hours * 60} minutes, sent modmail") - break - - save_posts(posts) + for flair_cfg in flair_times: + flair_text = flair_cfg["flair_text"] + hours = flair_cfg["hours"] + messagetitle = flair_cfg.get("messagetitle", "Modmail Notification") + + # Ensure posts dict for this flair + posts = all_posts.setdefault(flair_text, {}) + + for submission in reddit.subreddit(config.subreddit).new(limit=config.searchlimit): + if not submission.saved: + if submission.id not in posts and submission.link_flair_text == flair_text: + posts[submission.id] = time.time() + print(f"Post {submission} has been flaired {flair_text}") + if submission.id in posts and submission.link_flair_text != flair_text: + posts.pop(submission.id) + print(f"Post {submission} has been unflaired {flair_text}") + + expired = [] + for submission_id, flair_time in posts.items(): + if time.time() > flair_time + (hours * 60 * 60): + expired.append(submission_id) + + for submission_id in expired: + posts.pop(submission_id) + subm = reddit.submission(submission_id) + subm.save() + data = { + "subject": messagetitle, + "text": f"It has been {hours/24} day/s since this was flaired [{flair_text}](https://old.reddit.com{subm.permalink})", + "to": "/r/{}".format(config.subreddit), + } + reddit.post("api/compose/", data=data) + print(f"Post {submission_id} has been flaired {flair_text} for {hours} hours, sent modmail") + + save_posts(all_posts) time.sleep(config.interval) def load_posts(): @@ -93,16 +140,20 @@ def load_posts(): json.dump({}, file) with open("config/posts.json", "r+") as file: data = json.load(file) + # Ensure structure: {flair_text: {submission_id: timestamp}} + if not isinstance(data, dict): + return {} return data - + + def save_posts(data): with open('config/posts.json', 'w+') as file: json.dump(data, file) - - + + while True: try: posts = load_posts() - main(reddit = authentication(), posts = posts) + main(reddit=authentication(), all_posts=posts) except Exception as e: print(e)