ModReplyBot 1.0.0 release
This commit is contained in:
@@ -1 +1,2 @@
|
|||||||
.env
|
.env
|
||||||
|
config/*
|
||||||
@@ -5,4 +5,5 @@ COPY requirements.txt .
|
|||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
COPY config.py .
|
COPY config.py .
|
||||||
COPY modreplybot.py .
|
COPY modreplybot.py .
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
CMD ["python", "modreplybot.py"]
|
CMD ["python", "modreplybot.py"]
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
# ModReplyBot Reddit Bot
|
# ModReplyBot Reddit Bot
|
||||||
|
|
||||||
This bot watches a subreddit for moderator reports containing triggers, approves posts, and leaves stickied comments. Triggers and comments are configured via a subreddit wiki page. All other settings are handled via environment variables.
|
This bot watches a subreddit for moderator reports containing triggers, approves posts, and leaves stickied comments. Triggers and comments are configured via a local YAML file. All other settings are handled via environment variables.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- Watches for moderator reports with triggers
|
- Watches for moderator reports with triggers
|
||||||
- Approves posts and leaves stickied comments
|
- Approves posts and leaves stickied comments
|
||||||
- Triggers/comments configured via subreddit wiki
|
- Triggers/comments configured via config/config.yaml
|
||||||
- Supports multiple triggers/comments
|
- Supports multiple triggers/comments
|
||||||
- Docker and baremetal support
|
- Docker and baremetal support
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
### 1. Subreddit Wiki Page
|
### 1. Trigger and Comment Configuration
|
||||||
Create a wiki page (e.g. `modreplybot-config`) in your subreddit using Automoderator YAML format. Example:
|
Edit the file at `config/config.yaml` in your project directory. Example:
|
||||||
|
|
||||||
```
|
```
|
||||||
triggers:
|
triggers:
|
||||||
@@ -27,7 +27,7 @@ triggers:
|
|||||||
Your question will be answered soon.
|
Your question will be answered soon.
|
||||||
```
|
```
|
||||||
|
|
||||||
Each entry under `triggers` defines a trigger and its associated multi-line comment.
|
Each entry under `triggers` defines a trigger and its associated multi-line comment. The bot will automatically create this file with example content if it does not exist.
|
||||||
|
|
||||||
### 2. Environment Variables
|
### 2. Environment Variables
|
||||||
Create a `.env` file (or set env variables directly) with:
|
Create a `.env` file (or set env variables directly) with:
|
||||||
@@ -39,7 +39,6 @@ REDDIT_USERNAME=your_username
|
|||||||
REDDIT_PASSWORD=your_password
|
REDDIT_PASSWORD=your_password
|
||||||
REDDIT_USER_AGENT=modreplybot by /u/your_username
|
REDDIT_USER_AGENT=modreplybot by /u/your_username
|
||||||
REDDIT_SUBREDDIT=your_subreddit
|
REDDIT_SUBREDDIT=your_subreddit
|
||||||
REDDIT_WIKI_PAGE=modreplybot-config
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|||||||
+2
-1
@@ -1,8 +1,9 @@
|
|||||||
version: '3.8'
|
|
||||||
services:
|
services:
|
||||||
modbot:
|
modbot:
|
||||||
image: slfhstd.uk/slfhstd/modreplybot:latest
|
image: slfhstd.uk/slfhstd/modreplybot:latest
|
||||||
container_name: modreplybot
|
container_name: modreplybot
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
|
volumes:
|
||||||
|
- ./config:/app/config
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|||||||
+58
-29
@@ -5,51 +5,80 @@ import time
|
|||||||
|
|
||||||
class ModBot:
|
class ModBot:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
import os
|
||||||
self.reddit = get_reddit()
|
self.reddit = get_reddit()
|
||||||
self.subreddit = self.reddit.subreddit(Config.SUBREDDIT)
|
self.subreddit = self.reddit.subreddit(Config.SUBREDDIT)
|
||||||
self.wiki_page = Config.WIKI_PAGE
|
self.config_path = os.path.join(os.path.dirname(__file__), 'config', 'config.yaml')
|
||||||
self.triggers = []
|
self.triggers = []
|
||||||
self.comments = []
|
self.comments = []
|
||||||
|
self.ensure_config_file()
|
||||||
|
|
||||||
def fetch_wiki_config(self):
|
def ensure_config_file(self):
|
||||||
|
import os
|
||||||
|
if not os.path.exists(self.config_path):
|
||||||
|
default_yaml = (
|
||||||
|
'triggers:\n'
|
||||||
|
' - trigger: help\n'
|
||||||
|
' comment: |\n'
|
||||||
|
' Thank you for your report!\n'
|
||||||
|
' This post is now approved.\n'
|
||||||
|
' - trigger: question\n'
|
||||||
|
' comment: |\n'
|
||||||
|
' This post has been approved.\n'
|
||||||
|
' Your question will be answered soon.\n'
|
||||||
|
)
|
||||||
|
os.makedirs(os.path.dirname(self.config_path), exist_ok=True)
|
||||||
|
with open(self.config_path, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(default_yaml)
|
||||||
|
|
||||||
|
def fetch_yaml_config(self):
|
||||||
import yaml
|
import yaml
|
||||||
try:
|
try:
|
||||||
wiki_content = self.subreddit.wiki[self.wiki_page].content_md
|
with open(self.config_path, 'r', encoding='utf-8') as f:
|
||||||
# Example Automoderator YAML format:
|
config = yaml.safe_load(f)
|
||||||
# triggers:
|
|
||||||
# - trigger: help
|
|
||||||
# comment: |
|
|
||||||
# Thank you for your report!
|
|
||||||
# This post is now approved.
|
|
||||||
# - trigger: question
|
|
||||||
# comment: |
|
|
||||||
# This post has been approved.
|
|
||||||
config = yaml.safe_load(wiki_content)
|
|
||||||
self.triggers = []
|
self.triggers = []
|
||||||
self.comments = []
|
self.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())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error fetching wiki config: {e}")
|
print(f"Error fetching YAML config: {e}")
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
print("ModBot started. Watching for mod reports...")
|
print("ModReplyBot started. Watching for comments...")
|
||||||
while True:
|
try:
|
||||||
self.fetch_wiki_config()
|
self.fetch_yaml_config()
|
||||||
for report in self.subreddit.mod.reports(limit=25):
|
print(f"Triggers loaded: {self.triggers}")
|
||||||
self.handle_report(report)
|
print(f"Reddit user: {self.reddit.user.me()}")
|
||||||
time.sleep(30) # Poll every 30 seconds
|
print(f"Subreddit: {self.subreddit.display_name}")
|
||||||
|
except Exception as e:
|
||||||
def handle_report(self, report):
|
print(f"Startup error: {e}")
|
||||||
if not hasattr(report, 'mod_reports') or not report.mod_reports:
|
|
||||||
return
|
return
|
||||||
for mod_report in report.mod_reports:
|
while True:
|
||||||
report_text = mod_report[0].lower()
|
try:
|
||||||
for idx, trigger in enumerate(self.triggers):
|
self.fetch_yaml_config()
|
||||||
if trigger.lower() in report_text:
|
for comment in self.subreddit.stream.comments(skip_existing=True):
|
||||||
self.approve_and_comment(report, self.comments[idx])
|
self.handle_comment(comment)
|
||||||
break
|
except Exception as e:
|
||||||
|
print(f"Main loop error: {e}")
|
||||||
|
time.sleep(5) # Poll every 5 seconds
|
||||||
|
|
||||||
|
def handle_comment(self, comment):
|
||||||
|
comment_body = comment.body.lower()
|
||||||
|
for idx, trigger in enumerate(self.triggers):
|
||||||
|
expected = f"!{trigger.lower()}"
|
||||||
|
if expected in comment_body:
|
||||||
|
# Remove the triggering comment
|
||||||
|
try:
|
||||||
|
comment.mod.remove()
|
||||||
|
print(f"Removed triggering comment: {comment.id}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error removing comment: {e}")
|
||||||
|
# Approve the submission and post bot's comment
|
||||||
|
submission = comment.submission
|
||||||
|
self.fetch_yaml_config()
|
||||||
|
self.approve_and_comment(submission, self.comments[idx])
|
||||||
|
break
|
||||||
|
|
||||||
def approve_and_comment(self, submission, comment_text):
|
def approve_and_comment(self, submission, comment_text):
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user