Updates to use wiki page as config and auto-detec these changes. Bot can also auto-comment on new posts if s pecific [Tag] is detected.
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
1roi8zs
|
||||||
|
1roi5cl
|
||||||
|
1roi245
|
||||||
|
1roi088
|
||||||
|
1rlvzus
|
||||||
|
1rlvufz
|
||||||
|
1rlvqyo
|
||||||
|
1rlvfof
|
||||||
|
1rlpiwm
|
||||||
|
1rlpivb
|
||||||
+2
-1
@@ -5,5 +5,6 @@ services:
|
|||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
volumes:
|
volumes:
|
||||||
- ./config:/app/config
|
- ./config:/app/config
|
||||||
|
- ./DB:/app/DB
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|||||||
+128
-12
@@ -1,3 +1,4 @@
|
|||||||
|
import os
|
||||||
import praw
|
import praw
|
||||||
from config import get_reddit, Config
|
from config import get_reddit, Config
|
||||||
|
|
||||||
@@ -11,7 +12,10 @@ class ModBot:
|
|||||||
self.config_path = os.path.join(os.path.dirname(__file__), 'config', 'config.yaml')
|
self.config_path = os.path.join(os.path.dirname(__file__), 'config', 'config.yaml')
|
||||||
self.triggers = []
|
self.triggers = []
|
||||||
self.comments = []
|
self.comments = []
|
||||||
|
self.commented_posts = set()
|
||||||
|
self.commented_posts_file = os.path.join(os.path.dirname(__file__), 'DB', 'commented_posts.txt')
|
||||||
self.ensure_config_file()
|
self.ensure_config_file()
|
||||||
|
self.load_commented_posts()
|
||||||
|
|
||||||
def ensure_config_file(self):
|
def ensure_config_file(self):
|
||||||
import os
|
import os
|
||||||
@@ -34,47 +38,145 @@ class ModBot:
|
|||||||
def fetch_yaml_config(self):
|
def fetch_yaml_config(self):
|
||||||
import yaml
|
import yaml
|
||||||
try:
|
try:
|
||||||
with open(self.config_path, 'r', encoding='utf-8') as f:
|
wiki_page = Config.WIKI_PAGE
|
||||||
config = yaml.safe_load(f)
|
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.triggers = []
|
self.triggers = []
|
||||||
self.comments = []
|
self.comments = []
|
||||||
|
self.tag_comments = {}
|
||||||
for entry in config.get('triggers', []):
|
for entry in config.get('triggers', []):
|
||||||
self.triggers.append(entry.get('trigger', '').strip())
|
self.triggers.append(entry.get('trigger', '').strip())
|
||||||
self.comments.append(entry.get('comment', '').strip())
|
self.comments.append(entry.get('comment', '').strip())
|
||||||
|
for entry in config.get('post_tags', []):
|
||||||
|
tags_str = entry.get('tag', '').strip()
|
||||||
|
comment = entry.get('comment', '').strip()
|
||||||
|
tags = [t.strip().lower() for t in tags_str.split(',') if t.strip()]
|
||||||
|
for tag in tags:
|
||||||
|
self.tag_comments[tag] = comment
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error fetching YAML config: {e}")
|
print(f"Error fetching YAML config from wiki: {e}")
|
||||||
|
|
||||||
|
def load_commented_posts(self):
|
||||||
|
try:
|
||||||
|
with open(self.commented_posts_file, 'r', encoding='utf-8') as f:
|
||||||
|
for line in f:
|
||||||
|
self.commented_posts.add(line.strip())
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def save_commented_post(self, post_id):
|
||||||
|
self.commented_posts.add(post_id)
|
||||||
|
with open(self.commented_posts_file, 'a', encoding='utf-8') as f:
|
||||||
|
f.write(post_id + '\n')
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
print("ModReplyBot started. Watching for comments...")
|
import threading
|
||||||
|
print("ModReplyBot started. Watching for comments and new posts...")
|
||||||
try:
|
try:
|
||||||
self.fetch_yaml_config()
|
self.fetch_yaml_config()
|
||||||
print(f"Triggers loaded: {self.triggers}")
|
print(f"Triggers loaded: {self.triggers}")
|
||||||
|
print(f"Tag comments loaded: {self.tag_comments}")
|
||||||
print(f"Reddit user: {self.reddit.user.me()}")
|
print(f"Reddit user: {self.reddit.user.me()}")
|
||||||
print(f"Subreddit: {self.subreddit.display_name}")
|
print(f"Subreddit: {self.subreddit.display_name}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Startup error: {e}")
|
print(f"Startup error: {e}")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def comment_watcher():
|
||||||
|
last_revision = None
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
old_revision = last_revision
|
||||||
|
self.fetch_yaml_config()
|
||||||
|
new_revision = getattr(self, '_wiki_revision_id', None)
|
||||||
|
if old_revision and new_revision and old_revision != new_revision:
|
||||||
|
print("Wiki config changed, reloading triggers and tag comments.")
|
||||||
|
self.notify_mods_config_change(new_revision)
|
||||||
|
last_revision = new_revision
|
||||||
|
for comment in self.subreddit.stream.comments(skip_existing=True):
|
||||||
|
self.handle_comment(comment)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Comment watcher error: {e}")
|
||||||
|
# No sleep needed, stream blocks
|
||||||
|
|
||||||
|
def submission_watcher():
|
||||||
|
seen_submissions = set()
|
||||||
|
last_revision = None
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
old_revision = last_revision
|
||||||
|
self.fetch_yaml_config()
|
||||||
|
new_revision = getattr(self, '_wiki_revision_id', None)
|
||||||
|
if old_revision and new_revision and old_revision != new_revision:
|
||||||
|
print("Wiki config changed, reloading triggers and tag comments.")
|
||||||
|
self.notify_mods_config_change(new_revision)
|
||||||
|
last_revision = new_revision
|
||||||
|
new_submissions = list(self.subreddit.new(limit=10))
|
||||||
|
found_submission = False
|
||||||
|
for submission in new_submissions:
|
||||||
|
if submission.id not in seen_submissions:
|
||||||
|
found_submission = True
|
||||||
|
seen_submissions.add(submission.id)
|
||||||
|
self.handle_submission(submission)
|
||||||
|
if not found_submission:
|
||||||
|
print("No submissions detected in new() this cycle.")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Submission watcher error: {e}")
|
||||||
|
import time
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
threading.Thread(target=comment_watcher, daemon=True).start()
|
||||||
|
threading.Thread(target=submission_watcher, daemon=True).start()
|
||||||
|
|
||||||
|
# Keep main thread alive
|
||||||
while True:
|
while True:
|
||||||
|
import time
|
||||||
|
time.sleep(60)
|
||||||
|
def handle_submission(self, submission):
|
||||||
|
# Respond to new posts based on tag(s) in title
|
||||||
|
import re
|
||||||
|
title = submission.title
|
||||||
|
print(f"New post detected: {submission.id} | Title: {title}")
|
||||||
|
tag_matches = re.findall(r"\[(.+?)\]", title)
|
||||||
|
print(f"Tags found in title: {tag_matches}")
|
||||||
|
matched_comment = None
|
||||||
|
matched_tag = None
|
||||||
|
for tag in tag_matches:
|
||||||
|
tag_lower = tag.strip().lower()
|
||||||
|
if tag_lower in self.tag_comments:
|
||||||
|
matched_comment = self.tag_comments[tag_lower]
|
||||||
|
matched_tag = tag_lower
|
||||||
|
break
|
||||||
|
if matched_comment:
|
||||||
|
if submission.id in self.commented_posts:
|
||||||
|
print(f"Already auto-commented on post {submission.id}, skipping.")
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
self.fetch_yaml_config()
|
footer = "^I ^am ^a ^bot ^and ^this ^comment ^was ^made ^automatically. ^Message ^the ^Mod ^team ^if ^I'm ^not ^working ^correctly."
|
||||||
for comment in self.subreddit.stream.comments(skip_existing=True):
|
comment_text = matched_comment.replace("{{author}}", submission.author.name if submission.author else "unknown") + "\n\n" + footer
|
||||||
self.handle_comment(comment)
|
comment = submission.reply(comment_text)
|
||||||
|
comment.mod.distinguish(sticky=True)
|
||||||
|
print(f"Commented on new post {submission.id} with tag [{matched_tag}] (auto)")
|
||||||
|
self.save_commented_post(submission.id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Main loop error: {e}")
|
print(f"Error commenting on new post: {e}")
|
||||||
time.sleep(5) # Poll every 5 seconds
|
else:
|
||||||
|
print(f"No matching tag found for post {submission.id}")
|
||||||
|
|
||||||
def handle_comment(self, comment):
|
def handle_comment(self, comment):
|
||||||
comment_body = comment.body.lower()
|
comment_body = comment.body.lower()
|
||||||
for idx, trigger in enumerate(self.triggers):
|
for idx, trigger in enumerate(self.triggers):
|
||||||
expected = f"!{trigger.lower()}"
|
expected = f"!{trigger.lower()}"
|
||||||
if expected in comment_body:
|
words = [w.strip() for w in comment_body.split()]
|
||||||
# Remove the triggering comment
|
# Only respond if author is a moderator
|
||||||
|
if expected in words and comment.author and comment.author in self.subreddit.moderator():
|
||||||
try:
|
try:
|
||||||
comment.mod.remove()
|
comment.mod.remove()
|
||||||
print(f"Removed triggering comment: {comment.id}")
|
print(f"Removed triggering comment: {comment.id}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error removing comment: {e}")
|
print(f"Error removing comment: {e}")
|
||||||
# Approve the submission and post bot's comment
|
|
||||||
submission = comment.submission
|
submission = comment.submission
|
||||||
self.fetch_yaml_config()
|
self.fetch_yaml_config()
|
||||||
self.approve_and_comment(submission, self.comments[idx])
|
self.approve_and_comment(submission, self.comments[idx])
|
||||||
@@ -89,6 +191,20 @@ class ModBot:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error approving/commenting: {e}")
|
print(f"Error approving/commenting: {e}")
|
||||||
|
|
||||||
|
def notify_mods_config_change(self, revision_id):
|
||||||
|
try:
|
||||||
|
subject = "ModReplyBot config wiki changed"
|
||||||
|
body = f"The config wiki page was updated (revision: {revision_id}).\n\nBot restarted and is running successfully."
|
||||||
|
data = {
|
||||||
|
"subject": subject,
|
||||||
|
"text": body,
|
||||||
|
"to": f"/r/{Config.SUBREDDIT}",
|
||||||
|
}
|
||||||
|
self.reddit.post("api/compose/", data=data)
|
||||||
|
print("Sent modmail notification about config change.")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error sending modmail notification: {e}")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
bot = ModBot()
|
bot = ModBot()
|
||||||
bot.run()
|
bot.run()
|
||||||
|
|||||||
Reference in New Issue
Block a user