import praw import os import os.path import json import time # 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: f.write( f'username = "{env_or_default("USERNAME", "")}"\n' 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' '\n' f'subreddit = "{env_or_default("SUBREDDIT", "")}"\n' f'interval = {env_or_default("INTERVAL", "30")}\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 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() return len(content) == 0 except Exception: return True if config_needs_populating(): write_config_from_env() # 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(' "comment_message": "This post has had the \'Waiting for OP\' flair for 48 hours.",\n') f.write(' "lock_post": False,\n') f.write(' "distinguish_sticky": False\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())) return reddit def main(reddit, all_posts: dict): # all_posts structure: {flair_text: {submission_id: timestamp}} while True: for flair_cfg in flair_times: flair_text = flair_cfg["flair_text"] hours = flair_cfg["hours"] comment_message = flair_cfg["comment_message"] lock_post = flair_cfg.get("lock_post", False) distinguish_sticky = flair_cfg.get("distinguish_sticky", False) # 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() if lock_post: try: subm.mod.lock() except Exception as e: print(f"Could not lock submission: {e}") comment = subm.reply(body=comment_message) try: if distinguish_sticky: comment.mod.distinguish(how="yes", sticky=True) else: comment.mod.distinguish(how="yes") print(f"Distinguished comment (sticky={distinguish_sticky})") except Exception as e: print(f"Could not distinguish comment: {e}") print(f"Post {submission_id} has been flaired {flair_text} for {hours} hours, posted comment") save_posts(all_posts) time.sleep(config.interval) def load_posts(): if not os.path.exists("config/posts.json"): with open("config/posts.json", "w+") as file: 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(), all_posts=posts) except Exception as e: print(e)