From 56acc187a9ed465f65774f046b22df97a58f92a5 Mon Sep 17 00:00:00 2001 From: Slfhstd Date: Tue, 10 Mar 2026 22:29:35 +0000 Subject: [PATCH] V2 release --- DB/chat_wiki_requests.txt | 37 ++++++ DB/commented_posts.txt | 78 ++++++++---- ModGuide.md | 31 ++++- README.md | 164 ++++++++++++++---------- modreplybot.py | 261 +++++++++++++++++++++++++++++--------- 5 files changed, 414 insertions(+), 157 deletions(-) create mode 100644 DB/chat_wiki_requests.txt diff --git a/DB/chat_wiki_requests.txt b/DB/chat_wiki_requests.txt new file mode 100644 index 0000000..a78da6e --- /dev/null +++ b/DB/chat_wiki_requests.txt @@ -0,0 +1,37 @@ +3cmp3o4 +3fx1qfn +3g7v9uc +3jeabq9 +3wskhjw +3x39w4t +3yuu0aa +3zzls88 +3zzlt5d +3zzlvdb +3zzm08q +402nk2v +4abxjnc +4abxt0q +4abxurh +4dl3vu7 +4lq8osg +4n5ukvi +4n5ullm +4uvaecx +4v59c9t +4z0edd4 +51digym +52yjb3r +52yjj84 +o8428zh +o844qn1 +o844sou +o846cxy +o846f5z +5hmwzis +5ju7six +5ju8grz +5ju8ve3 +5jubgcs +5judtbe +5jugfpj diff --git a/DB/commented_posts.txt b/DB/commented_posts.txt index 1741e0f..0c7467f 100644 --- a/DB/commented_posts.txt +++ b/DB/commented_posts.txt @@ -1,27 +1,51 @@ -1roi8zs -1roi5cl -1roi245 -1roi088 -1rlvzus -1rlvufz -1rlvqyo -1rlvfof -1rlpiwm -1rlpivb -1rpysqt -1rpyvk2 -1rpz5j5 -1rpzgxq -1rq014r -1rpyv9d -1rpxb6z -1rpsp6z -1rpsgbi -1rps6ab -1rprg5y -1rpqfb7 -1rpju64 -1rpir3o -1rq2nve -1rq2nwm -1rq2nwm +1rq7d74 +1rq7d8m +1rq7jgx +1rq7jif +1rq7t4b +1rq7t2q +1rq7yfy +1rq7yes +1rq857k +1rq856a +1rq7p24 +1rq8h7x +1rq8h62 +1rq8h62 +1rq856a +1rq8q3r +1rq8q2l +1rq8q2l +1rq8q2l +1rq8xxd +1rq8xwd +1rq94gj +1rq94ex +1rq97u4 +1rq97st +1rq9dmi +1rq9dlb +1rq9lze +1rq9lxo +1rq9pgz +1rq9pfg +1rq9ubo +1rq9uaq +1rq9z7v +1rq9z6p +1rqa30g +1rqa2yy +1rqa6th +1rqa6rz +1rqaawn +1rqaerv +1rqaeq6 +1rqaeq6 +1rqaeq6 +1rqaerv +1rqb476 +1rqbf64 +1rqb45z +1rqbf4n +1rqbf4n +1rqbf4n diff --git a/ModGuide.md b/ModGuide.md index 94871f3..dae2d23 100644 --- a/ModGuide.md +++ b/ModGuide.md @@ -1,3 +1,4 @@ + # ModReplyBot Moderator Guide ## Wiki Configuration Page @@ -12,7 +13,7 @@ https://old.reddit.com/r//wiki/ ## Triggers -Triggers allow moderators to perform bot actions by commenting with a trigger phrase or by reporting a post with a trigger phrase in the report reason. Triggers must start with a `!` (ex: `!help`). +Triggers allow moderators to perform bot actions by commenting with a trigger phrase or by reporting a post with a trigger phrase in the report reason. Triggers must start with a `!` (ex: `!test`). ### Example Trigger Configuration ``` @@ -22,6 +23,10 @@ triggers: Thank you for your report! This post is now approved. status: enabled + flair_id: 12345678-aaaa-bbbb-cccc-1234567890ab + stickied: true + lock_post: false + lock_comment: false - trigger: wc comment: | Welcome to the community! @@ -31,9 +36,13 @@ triggers: - **trigger**: The phrase (without the `!`) that mods use in comments or report reasons. - **comment**: The text the bot will post as a stickied comment. - **status**: - - `enabled`: Bot will approve the post and comment. - - `log-only`: Bot will approve the post but not comment. + - `enabled`: Bot will comment and perform actions. + - `log-only`: Bot will log but not comment. - `disabled`: Bot will not act on this trigger. +- **flair_id**: Optional. Set post flair by ID. +- **stickied**: Optional. Sticky the bot's comment. +- **lock_post**: Optional. Lock the post. +- **lock_comment**: Optional. Lock the bot's comment. ## Auto-Post Tags @@ -46,6 +55,7 @@ post_tags: comment: | __[Click here if your post says "Sorry, this post was removed by Reddit’s filters"](...)__ status: enabled + flair_id: 12345678-aaaa-bbbb-cccc-1234567890ab ``` - **tag**: Comma-separated list of tags. The bot matches tags in post titles (case-insensitive). @@ -54,17 +64,23 @@ post_tags: - `enabled`: Bot will comment automatically. - `log-only`: Bot will log but not comment. - `disabled`: Bot will not act on this tag. +- **flair_id**: Optional. Set post flair by ID. + +## Chat-Based Config Reload +- To reload the wiki config, send a chat message containing `reload-config` to the bot account from a moderator account. +- The bot will reply to the chat message indicating whether the config is valid or not. +- Chat message IDs are tracked in `/DB/chat_wiki_requests.txt` to prevent duplicate reloads after restarts. ## Additional Notes - The bot only comments once per trigger per post (even if triggered multiple times). - The bot only auto-comments once per post for each tag. - All bot actions are logged for transparency. -- If the wiki config is invalid, the bot will notify mods via modmail and pause until fixed. +- If the wiki config is invalid, the bot will reply to the chat message with an error. ## Troubleshooting - Make sure your wiki config is valid YAML and includes both `triggers` and `post_tags` sections. - Use old.reddit.com for wiki editing to avoid formatting issues. -- Check bot logs for errors and modmail for config issues. +- Check bot logs for errors and chat replies for config issues. ## Example Wiki Config Excerpt ``` @@ -74,9 +90,14 @@ triggers: Thank you for your report! This post is now approved. status: enabled + flair_id: 12345678-aaaa-bbbb-cccc-1234567890ab + stickied: true + lock_post: false + lock_comment: false post_tags: - tag: Bedrock, Java comment: | __[Click here if your post says "Sorry, this post was removed by Reddit’s filters"](...)__ status: enabled + flair_id: 12345678-aaaa-bbbb-cccc-1234567890ab ``` diff --git a/README.md b/README.md index f22913f..c965780 100644 --- a/README.md +++ b/README.md @@ -21,91 +21,119 @@ Edit your subreddit wiki page (name set by `REDDIT_WIKI_PAGE` env variable) with ``` triggers: - trigger: help - comment: | - Thank you for your report! - This post is now approved. - status: enabled - - trigger: wc - comment: | - Welcome to the community! - status: log-only -post_tags: - - tag: Bedrock, Java - comment: | - __[Click here if your post says "Sorry, this post was removed by Reddit’s filters"](...)__ - status: enabled -``` + # ModReplyBot -- Triggers: Bot responds to mod comments and mod reports containing `!trigger` (e.g., `!help`) with the configured comment. -- post_tags: Bot posts the comment automatically on new posts with matching tags in the title. -- Status options: `enabled`, `log-only`, `disabled`. + ModReplyBot is a Reddit bot for moderators that automates post actions and stickied comments based on subreddit wiki configuration. It responds to mod comments and mod reports containing trigger phrases, auto-comments on posts with configured tags, and now supports chat-based config reloads. All configuration is managed via a subreddit wiki page and environment variables. -### 2. Environment Variables -Create a `.env` file (or set env variables directly) with: + ## Features + - Responds to moderator comments containing trigger phrases (starting with `!`) + - Responds to moderator reports containing trigger phrases (starting with `!`) + - Sets post flair, locks posts/comments, and posts stickied comments + - Posts automatic comments based on tags in post titles (e.g., `[Bedrock]`, `[Java]`) + - Triggers, tag comments, and bot config are managed via a subreddit wiki page + - Chat-based config reload: send a chat message containing `reload-config` to the bot from a moderator account to reload the wiki config + - Persistent database for auto-commented posts and processed chat requests (survives restarts and container recreations) + - Docker and baremetal support + ## Configuration -``` -REDDIT_CLIENT_ID=your_client_id -REDDIT_CLIENT_SECRET=your_client_secret -REDDIT_USERNAME=your_username -REDDIT_PASSWORD=your_password -REDDIT_USER_AGENT=modreplybot by /u/your_username -REDDIT_SUBREDDIT=your_subreddit -REDDIT_WIKI_PAGE=modreplybot-config -LOG_LEVEL=Default -``` + ### 1. Wiki Page Configuration + Edit your subreddit wiki page (name set by `REDDIT_WIKI_PAGE` env variable) with YAML like: -docker compose up -d -docker run --env-file .env -v $(pwd)/DB:/app/DB slfhstd.uk/slfhstd/modreplybot:latest -pip install -r requirements.txt + ``` + triggers: + - trigger: help + comment: | + Thank you for your report! + This post is now approved. + status: enabled + flair_id: 12345678-aaaa-bbbb-cccc-1234567890ab + stickied: true + lock_post: false + lock_comment: false + - trigger: wc + comment: | + Welcome to the community! + status: log-only -## Installation + post_tags: + - tag: Bedrock, Java + comment: | + __[Click here if your post says "Sorry, this post was removed by Reddit’s filters"](...)__ + status: enabled + flair_id: 12345678-aaaa-bbbb-cccc-1234567890ab + ``` -### Docker Compose (Recommended) -1. Copy `.env.example` to `.env` and fill in your values. -2. Run: + - Triggers: Bot responds to mod comments and mod reports containing `!trigger` (e.g., `!help`) with the configured comment and actions. + - post_tags: Bot posts the comment automatically on new posts with matching tags in the title and can set flair. + - Status options: `enabled`, `log-only`, `disabled`. + - Optional actions: `flair_id`, `stickied`, `lock_post`, `lock_comment`. -``` -docker compose up -d -``` + ### 2. Environment Variables + Create a `.env` file (or set env variables directly) with: -* The DB folder is mounted for persistent database storage. + ``` + REDDIT_CLIENT_ID=your_client_id + REDDIT_CLIENT_SECRET=your_client_secret + REDDIT_USERNAME=your_username + REDDIT_PASSWORD=your_password + REDDIT_USER_AGENT=modreplybot by /u/your_username + REDDIT_SUBREDDIT=your_subreddit + REDDIT_WIKI_PAGE=modreplybot-config + LOG_LEVEL=Default + ``` -### Docker Run -1. Copy `.env.example` to `.env` and fill in your values. -2. Run: + ## Installation -``` -docker run --env-file .env -v $(pwd)/DB:/app/DB slfhstd.uk/slfhstd/modreplybot:latest -``` + ### Docker Compose (Recommended) + 1. Copy `.env.example` to `.env` and fill in your values. + 2. Run: -### Baremetal (Direct Python) -1. Install Python 3.11+ -2. Install dependencies: + ``` + docker compose up -d + ``` -``` -pip install -r requirements.txt -``` + * The DB folder is mounted for persistent database storage. -3. Set environment variables or create a `.env` file. -4. Run: + ### Docker Run + 1. Copy `.env.example` to `.env` and fill in your values. + 2. Run: -``` -python modreplybot.py -``` + ``` + docker run --env-file .env -v $(pwd)/DB:/app/DB slfhstd.uk/slfhstd/modreplybot:latest + ``` + ### Baremetal (Direct Python) + 1. Install Python 3.11+ + 2. Install dependencies: -## Troubleshooting -- Ensure your Reddit credentials are correct and have moderator permissions. -- The bot must be able to read the wiki page and approve posts. -- Check logs for errors. -- The bot only responds to mod comments and mod reports for triggers. -- Database is stored in DB/commented_posts.txt and survives container restarts. -- If the wiki config is invalid, the bot will notify mods via modmail and pause until fixed. + ``` + pip install -r requirements.txt + ``` -## Moderator Guide -See `ModGuide.md` for a detailed guide to configuring triggers, auto-post tags, and wiki options. + 3. Set environment variables or create a `.env` file. + 4. Run: -## License -MIT + ``` + python modreplybot.py + ``` + + ## Chat-Based Config Reload + - To reload the wiki config, send a chat message containing `reload-config` to the bot account from a moderator account. + - The bot will reply to the chat message indicating whether the config is valid or not. + - Chat message IDs are tracked in `/DB/chat_wiki_requests.txt` to prevent duplicate reloads after restarts. + + ## Troubleshooting + - Ensure your Reddit credentials are correct and have moderator permissions. + - The bot must be able to read the wiki page and approve posts. + - Check logs for errors. + - The bot only responds to mod comments and mod reports for triggers. + - Database is stored in `/DB/commented_posts.txt` and `/DB/chat_wiki_requests.txt` and survives container restarts. + - If the wiki config is invalid, the bot will reply to the chat message with an error. + + ## Moderator Guide + See `ModGuide.md` for a detailed guide to configuring triggers, auto-post tags, and wiki options. + + ## License + MIT diff --git a/modreplybot.py b/modreplybot.py index cc44a4e..12b7cfc 100644 --- a/modreplybot.py +++ b/modreplybot.py @@ -5,6 +5,52 @@ from config import get_reddit, Config import time class ModReplyBot: + def chat_message_watcher(self): + chat_requests_file = os.path.join(os.path.dirname(__file__), 'DB', 'chat_wiki_requests.txt') + processed_message_ids = set() + # Load processed IDs from file + if os.path.exists(chat_requests_file): + with open(chat_requests_file, 'r', encoding='utf-8') as f: + for line in f: + processed_message_ids.add(line.strip()) + while True: + try: + for message in self.reddit.inbox.stream(): + if not hasattr(message, 'id') or message.id in processed_message_ids: + continue + processed_message_ids.add(message.id) + # Save processed ID to file + with open(chat_requests_file, 'a', encoding='utf-8') as f: + f.write(message.id + '\n') + if hasattr(message, 'body') and 'reload-config' in message.body.lower(): + # Check if sender is a moderator + author = getattr(message, 'author', None) + if author and author in self.subreddit.moderator(): + print(f"[CHAT WATCH] Moderator '{author}' requested config reload.") + result = self.fetch_yaml_config() + if result: + print("[CHAT WATCH] Wiki config reloaded successfully.") + reply_text = "Config reloaded successfully. Config is valid." + else: + print("[CHAT WATCH] Wiki config reload failed.") + reply_text = "Config reload failed. Config is invalid." + try: + message.reply(reply_text) + print(f"[CHAT WATCH] Replied to chat message {message.id}.") + except Exception as e: + print(f"[CHAT WATCH] Error replying to chat message {message.id}: {e}") + except Exception as e: + print(f"Chat message watcher error: {e}") + import time + time.sleep(30) + def comment_only(self, submission, comment_text): + try: + comment = submission.reply(comment_text) + comment.mod.distinguish(sticky=True) + print(f"Commented (no approval) on: {submission.id}") + self.save_commented_post(submission.id) + except Exception as e: + print(f"Error commenting (no approval): {e}") def __init__(self): import os self.reddit = get_reddit() @@ -14,6 +60,11 @@ class ModReplyBot: self.comments = [] self.commented_posts = set() self.commented_posts_file = os.path.join(os.path.dirname(__file__), 'DB', 'commented_posts.txt') + self.tagged_commented_posts_file = os.path.join(os.path.dirname(__file__), 'DB', 'tagged_commented_posts.txt') + self.tagged_commented_posts = set() + self._wiki_config_cache = None + self._wiki_config_cache_time = 0 + self._wiki_config_cache_ttl = 300 # seconds (5 minutes) self.ensure_config_file() self.load_commented_posts() self.log_level = Config.LOG_LEVEL @@ -44,43 +95,64 @@ class ModReplyBot: # Track last error revision to prevent modmail spam if not hasattr(self, '_last_config_error_revision'): self._last_config_error_revision = None - import yaml - try: - wiki_page = Config.WIKI_PAGE - wiki = self.subreddit.wiki[wiki_page] - wiki_content = wiki.content_md - self._wiki_revision_id = getattr(wiki, 'revision_id', None) - config = yaml.safe_load(wiki_content) - if not isinstance(config, dict) or 'triggers' not in config: - raise ValueError("Wiki config missing required 'triggers' key or is not a dict.") - self.triggers = [] - self.comments = [] - self.statuses = [] - self.tag_comments = {} - self.tag_statuses = {} - for entry in config.get('triggers', []): - self.triggers.append(entry.get('trigger', '').strip()) - self.comments.append(entry.get('comment', '').strip()) - self.statuses.append(entry.get('status', 'enabled').strip().lower()) - for entry in config.get('post_tags', []): - tags_str = entry.get('tag', '').strip() - comment = entry.get('comment', '').strip() - status = entry.get('status', 'enabled').strip().lower() - tags = [t.strip().lower() for t in tags_str.split(',') if t.strip()] - for tag in tags: - self.tag_comments[tag] = comment - self.tag_statuses[tag] = status - # Reset error revision tracker on successful config - self._last_config_error_revision = None - return True - except Exception as e: - self.log(f"Error fetching YAML config from wiki: {e}") - # Only send modmail if revision is new - revision = getattr(self, '_wiki_revision_id', None) - if revision != self._last_config_error_revision: - self.notify_mods_config_error(str(e)) - self._last_config_error_revision = revision + import yaml, time + now = time.time() + # Use cache if not expired + if self._wiki_config_cache and (now - self._wiki_config_cache_time < self._wiki_config_cache_ttl): + config = self._wiki_config_cache + self._wiki_revision_id = getattr(self, '_wiki_revision_id', None) + else: + try: + wiki_page = Config.WIKI_PAGE + wiki = self.subreddit.wiki[wiki_page] + wiki_content = wiki.content_md + self._wiki_revision_id = getattr(wiki, 'revision_id', None) + config = yaml.safe_load(wiki_content) + self._wiki_config_cache = config + self._wiki_config_cache_time = now + except Exception as e: + self.log(f"Error fetching YAML config from wiki: {e}") + revision = getattr(self, '_wiki_revision_id', None) + if revision != self._last_config_error_revision: + self._last_config_error_revision = revision + return False + if not isinstance(config, dict) or 'triggers' not in config: + self.log("Wiki config missing required 'triggers' key or is not a dict.") return False + self.triggers = [] + self.comments = [] + self.statuses = [] + self.flair_ids = [] + self.stickied = [] + self.lock_post = [] + self.lock_comment = [] + self.tag_comments = {} + self.tag_statuses = {} + self.tag_flair_ids = {} + for entry in config.get('triggers', []): + self.triggers.append(entry.get('trigger', '').strip()) + self.comments.append(entry.get('comment', '').strip()) + self.statuses.append(entry.get('status', 'enabled').strip().lower()) + self.flair_ids.append(entry.get('flair_id', '').strip()) + self.stickied.append(bool(entry.get('stickied', False))) + # Parse lock_post as a proper boolean + lock_post_val = entry.get('lock_post', False) + if isinstance(lock_post_val, str): + lock_post_val = lock_post_val.lower() in ['true', '1', 'yes'] + self.lock_post.append(bool(lock_post_val)) + self.lock_comment.append(bool(entry.get('lock_comment', False))) + for entry in config.get('post_tags', []): + tags_str = entry.get('tag', '').strip() + comment = entry.get('comment', '').strip() + status = entry.get('status', 'enabled').strip().lower() + flair_id = entry.get('flair_id', '').strip() + tags = [t.strip().lower() for t in tags_str.split(',') if t.strip()] + for tag in tags: + self.tag_comments[tag] = comment + self.tag_statuses[tag] = status + self.tag_flair_ids[tag] = flair_id + self._last_config_error_revision = None + return True def notify_mods_config_error(self, error_message): try: @@ -133,11 +205,10 @@ class ModReplyBot: config_ok = self.fetch_yaml_config() new_revision = getattr(self, '_wiki_revision_id', None) if old_revision and new_revision and old_revision != new_revision: - if config_ok: - self.log("Wiki config changed, reloading triggers and tag comments.") - self.notify_mods_config_change(new_revision) - else: - self.log("Wiki config error detected, not reloading bot.") + if config_ok: + self.log("Wiki config changed, reloading triggers and tag comments.") + else: + self.log("Wiki config error detected, not reloading bot.") self.log_level = Config.LOG_LEVEL last_revision = new_revision for comment in self.subreddit.stream.comments(skip_existing=True): @@ -145,6 +216,8 @@ class ModReplyBot: self.handle_comment(comment) except Exception as e: print(f"Mod comment watcher error: {e}") + import time + time.sleep(5) def mod_report_watcher(): last_revision = None @@ -169,6 +242,49 @@ class ModReplyBot: threading.Thread(target=mod_comment_watcher, daemon=True).start() threading.Thread(target=mod_report_watcher, daemon=True).start() + threading.Thread(target=self.chat_message_watcher, daemon=True).start() + + def tag_post_watcher(): + while True: + try: + for submission in self.subreddit.stream.submissions(skip_existing=True): + flair = (submission.link_flair_text or '').strip().lower() + title = submission.title.strip() + # Extract tags from title in square brackets + import re + title_tags = re.findall(r'\[(.*?)\]', title) + title_tags_lower = [t.strip().lower() for t in title_tags] + print(f"[TAG WATCH] Post {submission.id}: title='{title}', flair='{flair}', title_tags={title_tags_lower}") + matched_tag = None + # Check flair first + if flair in self.tag_comments: + matched_tag = flair + else: + # Check each tag in title + for tag in title_tags_lower: + if tag in self.tag_comments: + matched_tag = tag + break + if matched_tag: + # Only comment if not already actioned + if submission.id not in self.commented_posts: + status = self.tag_statuses.get(matched_tag, 'enabled') + comment_text = self.tag_comments[matched_tag] + flair_id = self.tag_flair_ids.get(matched_tag, '') + if flair_id: + try: + submission.flair.select(flair_id) + print(f"[TAG WATCH] Set flair '{flair_id}' for post {submission.id}") + except Exception as e: + print(f"[TAG WATCH] Error setting flair '{flair_id}' for post {submission.id}: {e}") + print(f"Auto-commenting on post {submission.id} with tag '{matched_tag}'") + self.comment_only(submission, comment_text) + except Exception as e: + print(f"Tag post watcher error: {e}") + import time + time.sleep(30) + + threading.Thread(target=tag_post_watcher, daemon=True).start() # Keep main thread alive while True: @@ -180,6 +296,7 @@ class ModReplyBot: matched_trigger = None matched_comment = None matched_status = None + matched_idx = None # Check report reasons for triggers if hasattr(submission, 'mod_reports') and submission.mod_reports: for report_tuple in submission.mod_reports: @@ -190,6 +307,7 @@ class ModReplyBot: matched_trigger = trigger matched_comment = self.comments[idx] matched_status = self.statuses[idx] if idx < len(self.statuses) else 'enabled' + matched_idx = idx break if matched_trigger: break @@ -205,18 +323,8 @@ class ModReplyBot: try: footer = "^I ^am ^a ^bot ^and ^this ^comment ^was ^made ^automatically. ^Message ^the ^Mod ^team ^if ^I'm ^not ^working ^correctly." comment_text = matched_comment.replace("{{author}}", submission.author.name if submission.author else "unknown") + "\n\n" + footer - if matched_status == 'enabled': - comment = submission.reply(comment_text) - comment.mod.distinguish(sticky=True) - print(f"Commented on mod report {submission.id} for trigger [{matched_trigger}] (auto)") - self.triggered_posts.add(trigger_key) - elif matched_status == 'log-only': - print(f"Log-only: Did not comment on mod report {submission.id} for trigger [{matched_trigger}] (auto)") - self.triggered_posts.add(trigger_key) - elif matched_status == 'disabled': - print(f"Disabled: Did not comment/log for mod report {submission.id} for trigger [{matched_trigger}] (auto)") - else: - print(f"Unknown status '{matched_status}' for mod report {submission.id} for trigger [{matched_trigger}] (auto)") + self.approve_and_comment(submission, comment_text, matched_status, matched_idx) + self.triggered_posts.add(trigger_key) except Exception as e: print(f"Error commenting on mod report: {e}") else: @@ -240,15 +348,54 @@ class ModReplyBot: print(f"Error removing comment: {e}") submission = comment.submission self.fetch_yaml_config() - self.approve_and_comment(submission, self.comments[idx], status) + self.approve_and_comment(submission, self.comments[idx], status, idx) break - def approve_and_comment(self, submission, comment_text, status='enabled'): + def approve_and_comment(self, submission, comment_text, status='enabled', trigger_idx=None): try: - submission.mod.approve() + print(f"[DEBUG] approve_and_comment called with trigger_idx={trigger_idx}") + if trigger_idx is not None: + print(f"[DEBUG] Config for trigger_idx={trigger_idx}: lock_post={self.lock_post[trigger_idx]}, stickied={self.stickied[trigger_idx]}, lock_comment={self.lock_comment[trigger_idx]}, flair_id={self.flair_ids[trigger_idx]}") + # Approve post if configured for this trigger + # Set flair, stickied, lock_post, lock_comment if configured for this trigger + if trigger_idx is not None: + flair_id = self.flair_ids[trigger_idx] + if flair_id: + try: + submission.flair.select(flair_id) + print(f"[DEBUG] Set flair '{flair_id}' for post {submission.id}") + except Exception as e: + print(f"[DEBUG] Error setting flair '{flair_id}' for post {submission.id}: {e}") + print(f"[DEBUG] lock_post[{trigger_idx}] = {self.lock_post[trigger_idx]}") + if self.lock_post[trigger_idx]: + try: + submission.mod.lock() + print(f"[DEBUG] Locked post {submission.id}") + except Exception as e: + print(f"[DEBUG] Error locking post {submission.id}: {e}") if status == 'enabled': + print(f"[DEBUG] Submission object: {submission}, ID: {submission.id}, Type: {type(submission)}") comment = submission.reply(comment_text) - comment.mod.distinguish(sticky=True) + print(f"[DEBUG] Comment object: {comment}, ID: {comment.id}, Type: {type(comment)}") + # Always sticky if stickied is True, match tag logic + if trigger_idx is not None and self.stickied[trigger_idx]: + try: + result = comment.mod.distinguish(sticky=True) + print(f"[DEBUG] Stickied bot comment {comment.id} on post {submission.id}, result: {result}") + except Exception as e: + print(f"[DEBUG] Error stickying comment {comment.id} on post {submission.id}: {e}") + else: + try: + result = comment.mod.distinguish() + print(f"[DEBUG] Distinguished bot comment {comment.id} on post {submission.id}, result: {result}") + except Exception as e: + print(f"[DEBUG] Error distinguishing comment {comment.id} on post {submission.id}: {e}") + if trigger_idx is not None and self.lock_comment[trigger_idx]: + try: + comment.mod.lock() + print(f"[DEBUG] Locked bot comment {comment.id} on post {submission.id}") + except Exception as e: + print(f"[DEBUG] Error locking comment {comment.id} on post {submission.id}: {e}") print(f"Approved and commented on: {submission.id}") self.save_commented_post(submission.id) elif status == 'log-only':