initial commit
This commit is contained in:
@@ -0,0 +1,12 @@
|
|||||||
|
# Reddit Bot Docker Environment Configuration
|
||||||
|
|
||||||
|
# .env file example (for Docker)
|
||||||
|
REDDIT_CLIENT_ID=your_client_id
|
||||||
|
REDDIT_CLIENT_SECRET=your_client_secret
|
||||||
|
REDDIT_USERNAME=your_username
|
||||||
|
REDDIT_PASSWORD=your_password
|
||||||
|
REDDIT_USER_AGENT=modbot by /u/your_username
|
||||||
|
REDDIT_SUBREDDIT=your_subreddit
|
||||||
|
REDDIT_WIKI_PAGE=modbot-config
|
||||||
|
|
||||||
|
# Add this file to .gitignore if you commit your project
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Dockerfile for building modreplybot image
|
||||||
|
FROM python:3.11-slim
|
||||||
|
WORKDIR /app
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
COPY . .
|
||||||
|
CMD ["python", "modbot.py"]
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# ModBot 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.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Watches for moderator reports with triggers
|
||||||
|
- Approves posts and leaves stickied comments
|
||||||
|
- Triggers/comments configured via subreddit wiki
|
||||||
|
- Supports multiple triggers/comments
|
||||||
|
- Docker and baremetal support
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### 1. Subreddit Wiki Page
|
||||||
|
Create a wiki page (e.g. `modbot-config`) in your subreddit using Automoderator YAML format. Example:
|
||||||
|
|
||||||
|
```
|
||||||
|
triggers:
|
||||||
|
- trigger: help
|
||||||
|
comment: |
|
||||||
|
Thank you for your report!
|
||||||
|
This post is now approved.
|
||||||
|
|
||||||
|
- trigger: question
|
||||||
|
comment: |
|
||||||
|
This post has been approved.
|
||||||
|
Your question will be answered soon.
|
||||||
|
```
|
||||||
|
|
||||||
|
Each entry under `triggers` defines a trigger and its associated multi-line comment.
|
||||||
|
|
||||||
|
### 2. Environment Variables
|
||||||
|
Create a `.env` file (or set env variables directly) with:
|
||||||
|
|
||||||
|
```
|
||||||
|
REDDIT_CLIENT_ID=your_client_id
|
||||||
|
REDDIT_CLIENT_SECRET=your_client_secret
|
||||||
|
REDDIT_USERNAME=your_username
|
||||||
|
REDDIT_PASSWORD=your_password
|
||||||
|
REDDIT_USER_AGENT=modbot by /u/your_username
|
||||||
|
REDDIT_SUBREDDIT=your_subreddit
|
||||||
|
REDDIT_WIKI_PAGE=modbot-config
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Docker Compose (Recommended)
|
||||||
|
1. Copy `.env.example` to `.env` and fill in your values.
|
||||||
|
2. Run:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker Run
|
||||||
|
1. Copy `.env.example` to `.env` and fill in your values.
|
||||||
|
2. Run:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run --env-file .env slfhstd.uk/slfhstd/modreplybot:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Baremetal (Direct Python)
|
||||||
|
1. Install Python 3.11+
|
||||||
|
2. Install dependencies:
|
||||||
|
|
||||||
|
```
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Set environment variables or create a `.env` file.
|
||||||
|
4. Run:
|
||||||
|
|
||||||
|
```
|
||||||
|
python modbot.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building the Docker Image
|
||||||
|
If you want to build your own image:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker build -t modreplybot .
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
## License
|
||||||
|
MIT
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import os
|
||||||
|
import praw
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
CLIENT_ID = os.environ.get('REDDIT_CLIENT_ID')
|
||||||
|
CLIENT_SECRET = os.environ.get('REDDIT_CLIENT_SECRET')
|
||||||
|
USERNAME = os.environ.get('REDDIT_USERNAME')
|
||||||
|
PASSWORD = os.environ.get('REDDIT_PASSWORD')
|
||||||
|
USER_AGENT = os.environ.get('REDDIT_USER_AGENT', 'modbot by /u/your_username')
|
||||||
|
SUBREDDIT = os.environ.get('REDDIT_SUBREDDIT')
|
||||||
|
WIKI_PAGE = os.environ.get('REDDIT_WIKI_PAGE', 'modbot-config')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def validate():
|
||||||
|
required = [Config.CLIENT_ID, Config.CLIENT_SECRET, Config.USERNAME, Config.PASSWORD, Config.SUBREDDIT]
|
||||||
|
if not all(required):
|
||||||
|
raise ValueError('Missing required Reddit environment variables.')
|
||||||
|
|
||||||
|
|
||||||
|
def get_reddit():
|
||||||
|
Config.validate()
|
||||||
|
return praw.Reddit(
|
||||||
|
client_id=Config.CLIENT_ID,
|
||||||
|
client_secret=Config.CLIENT_SECRET,
|
||||||
|
username=Config.USERNAME,
|
||||||
|
password=Config.PASSWORD,
|
||||||
|
user_agent=Config.USER_AGENT
|
||||||
|
)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
version: '3.8'
|
||||||
|
services:
|
||||||
|
modbot:
|
||||||
|
image: slfhstd.uk/slfhstd/modreplybot:latest
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
restart: unless-stopped
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
import praw
|
||||||
|
from config import get_reddit, Config
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
class ModBot:
|
||||||
|
def __init__(self):
|
||||||
|
self.reddit = get_reddit()
|
||||||
|
self.subreddit = self.reddit.subreddit(Config.SUBREDDIT)
|
||||||
|
self.wiki_page = Config.WIKI_PAGE
|
||||||
|
self.triggers = []
|
||||||
|
self.comments = []
|
||||||
|
|
||||||
|
def fetch_wiki_config(self):
|
||||||
|
import yaml
|
||||||
|
try:
|
||||||
|
wiki_content = self.subreddit.wiki[self.wiki_page].content_md
|
||||||
|
# Example Automoderator YAML format:
|
||||||
|
# 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.comments = []
|
||||||
|
for entry in config.get('triggers', []):
|
||||||
|
self.triggers.append(entry.get('trigger', '').strip())
|
||||||
|
self.comments.append(entry.get('comment', '').strip())
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error fetching wiki config: {e}")
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
print("ModBot started. Watching for mod reports...")
|
||||||
|
while True:
|
||||||
|
self.fetch_wiki_config()
|
||||||
|
for report in self.subreddit.mod.reports(limit=25):
|
||||||
|
self.handle_report(report)
|
||||||
|
time.sleep(30) # Poll every 30 seconds
|
||||||
|
|
||||||
|
def handle_report(self, report):
|
||||||
|
if not hasattr(report, 'mod_reports') or not report.mod_reports:
|
||||||
|
return
|
||||||
|
for mod_report in report.mod_reports:
|
||||||
|
report_text = mod_report[0].lower()
|
||||||
|
for idx, trigger in enumerate(self.triggers):
|
||||||
|
if trigger.lower() in report_text:
|
||||||
|
self.approve_and_comment(report, self.comments[idx])
|
||||||
|
break
|
||||||
|
|
||||||
|
def approve_and_comment(self, submission, comment_text):
|
||||||
|
try:
|
||||||
|
submission.mod.approve()
|
||||||
|
comment = submission.reply(comment_text)
|
||||||
|
comment.mod.distinguish(sticky=True)
|
||||||
|
print(f"Approved and commented on: {submission.id}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error approving/commenting: {e}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
bot = ModBot()
|
||||||
|
bot.run()
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
praw
|
||||||
|
pyyaml
|
||||||
Reference in New Issue
Block a user