Compare commits
3 Commits
b3a2788555
..
V2
| Author | SHA1 | Date | |
|---|---|---|---|
| 4f9243ff59 | |||
| 36fd5430bc | |||
| 95da1522b6 |
@@ -1 +1,2 @@
|
||||
modtestposts_config.yaml
|
||||
.env
|
||||
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
# Changelog - TestPostsBot V2
|
||||
|
||||
## Overview
|
||||
Complete refactor of TestPostsBot to be a continuously running, trigger-based posting bot that responds to moderator commands via chat messages.
|
||||
|
||||
## Major Features Added
|
||||
|
||||
### 1. Trigger-Based Posting System
|
||||
- Bot now runs continuously and listens for chat messages instead of executing once and exiting
|
||||
- Moderators can trigger posts by sending chat messages containing configured trigger keywords
|
||||
- Each trigger can post one or multiple posts in sequence
|
||||
- Posts are made with 2-second delays between submissions to respect rate limiting
|
||||
|
||||
### 2. YAML Configuration Format
|
||||
- **Changed from:** JSON configuration format
|
||||
- **Changed to:** YAML configuration format for better readability and maintainability
|
||||
- New config structure supports nested trigger/post relationships
|
||||
- Example YAML config provided in `example_config.yaml`
|
||||
|
||||
### 3. Chat Message Handler
|
||||
- Added chat message watcher that runs as a background thread
|
||||
- Listens for messages sent to the bot account by moderators
|
||||
- Implements special `reload-config` command for validating wiki config without making posts
|
||||
- Validates that sender is a moderator before processing commands
|
||||
- Tracks processed message IDs to prevent duplicate processing
|
||||
|
||||
### 4. Configuration Validation
|
||||
- New `validate_config_from_wiki()` function validates YAML format and required structure
|
||||
- Validates that config has a `posts` key with proper trigger/post structure
|
||||
- Prevents bot from running with invalid configuration
|
||||
- `reload-config` command provides feedback on config validity
|
||||
|
||||
### 5. Enhanced Logging
|
||||
- Added prefixed logging for different operations: `[STARTUP]`, `[POSTING]`, `[CHAT WATCH]`
|
||||
- Detailed debug output showing:
|
||||
- Messages received and who sent them
|
||||
- Moderator status verification
|
||||
- Trigger matching and posting status
|
||||
- Config validation results
|
||||
- Error messages with full tracebacks
|
||||
|
||||
## File Changes
|
||||
|
||||
### New Files
|
||||
- **example_config.yaml** - Comprehensive example showing trigger and post configuration with multiple scenarios
|
||||
- **.gitignore** - Added to exclude common files
|
||||
- **example.env** - Environment configuration template
|
||||
|
||||
### Modified Files
|
||||
|
||||
#### bot.py
|
||||
**Old Behavior:**
|
||||
- Ran once, fetched posts from hardcoded config, made posts, and exited
|
||||
- No continuous operation
|
||||
- No trigger system
|
||||
|
||||
**New Behavior:**
|
||||
- Runs continuously in infinite loop
|
||||
- Spawns chat message watcher as background daemon thread
|
||||
- Loads triggers from wiki config dynamically
|
||||
- Only posts when a moderator sends a matching trigger
|
||||
- Implements `reload-config` special command
|
||||
- Validates config on startup
|
||||
- Graceful shutdown on KeyboardInterrupt
|
||||
|
||||
**Key Functions:**
|
||||
- `chat_message_watcher()` - Monitors inbox stream for moderator messages
|
||||
- `make_posts()` - Posts to subreddit with rate limit delays
|
||||
- `main()` - Continuous operation loop with thread management
|
||||
|
||||
#### config.py
|
||||
**Old Behavior:**
|
||||
- Fetched JSON config from wiki
|
||||
- Simple error handling with fallback empty dict
|
||||
|
||||
**New Behavior:**
|
||||
- Uses `yaml.safe_load()` instead of `json.loads()`
|
||||
- `fetch_config_from_wiki()` - Fetches and parses YAML config
|
||||
- `validate_config_from_wiki()` - Validates config format and required keys
|
||||
- `get_trigger_posts()` - Retrieves posts associated with specific trigger
|
||||
- Better error messages for YAML parsing failures
|
||||
|
||||
#### requirements.txt
|
||||
**Added:**
|
||||
- `PyYAML` - Required for YAML config parsing
|
||||
|
||||
#### README.md
|
||||
**Complete Rewrite:**
|
||||
- Added comprehensive documentation for trigger-based system
|
||||
- Documented new YAML config format with examples
|
||||
- Explained how moderators trigger posts
|
||||
- Added setup instructions for environment variables
|
||||
- Documented `reload-config` command
|
||||
- Added Docker and standalone running instructions
|
||||
- Clarified that only moderators can trigger posts
|
||||
|
||||
#### docker-compose.yml
|
||||
**Updated:**
|
||||
- Environment variables now leverage .env file
|
||||
- Updated service configuration for continuous operation
|
||||
|
||||
#### Dockerfile
|
||||
**Updated:**
|
||||
- Adjusted for continuous operation mode
|
||||
- Ensures proper signal handling for graceful shutdown
|
||||
|
||||
### Configuration Examples
|
||||
|
||||
**Old Format (JSON):**
|
||||
```json
|
||||
{
|
||||
"posts": [
|
||||
{"title": "Test Post 1", "body": "Body for post 1"},
|
||||
{"title": "Test Post 2", "body": "Body for post 2"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**New Format (YAML):**
|
||||
```yaml
|
||||
posts:
|
||||
- trigger: "test"
|
||||
posts:
|
||||
- title: "Test Post 1"
|
||||
body: "Body for post 1"
|
||||
- title: "Test Post 2"
|
||||
body: "Body for post 2"
|
||||
|
||||
- trigger: "weekly-thread"
|
||||
posts:
|
||||
- title: "Weekly Thread 1"
|
||||
body: "Content"
|
||||
- title: "Weekly Thread 2"
|
||||
body: "Content"
|
||||
```
|
||||
|
||||
## Operational Changes
|
||||
|
||||
### Before (V1)
|
||||
- Bot runs, posts hardcoded posts, exits
|
||||
- Single execution cycle
|
||||
- Config loaded once at startup
|
||||
- No way to trigger posts without restarting bot
|
||||
|
||||
### After (V2)
|
||||
- Bot runs continuously
|
||||
- Moderators send chat messages to trigger posts
|
||||
- Config is fetched fresh for each trigger (allows live updates)
|
||||
- Special `reload-config` command validates configuration
|
||||
- Background thread handles message monitoring
|
||||
- Main thread keeps bot alive indefinitely
|
||||
|
||||
## Chat Commands
|
||||
|
||||
### Trigger Posts
|
||||
Send chat message containing trigger keyword (e.g., "modtestposts", "weekly-thread")
|
||||
- Bot fetches configured posts for that trigger
|
||||
- Posts them to the subreddit in sequence
|
||||
- Replies with confirmation of posts made
|
||||
|
||||
### Reload Config
|
||||
Send chat message containing "reload-config"
|
||||
- Bot validates wiki config YAML format
|
||||
- Replies with success/failure status
|
||||
- Useful for verifying config before using triggers
|
||||
|
||||
## Technical Improvements
|
||||
|
||||
1. **Concurrency:** Uses threading for background message monitoring while keeping main thread alive
|
||||
2. **Deduplication:** Tracks processed message IDs in `DB/chat_wiki_requests.txt` to prevent duplicate processing
|
||||
3. **Recovery:** Graceful error handling with continue on failures in message stream
|
||||
4. **Validation:** Comprehensive config validation before any operations
|
||||
5. **Logging:** Detailed logging for debugging and monitoring
|
||||
|
||||
## Compatibility Notes
|
||||
|
||||
- Requires `praw` and `PyYAML` packages
|
||||
- PRAW version should support `inbox.stream()` method
|
||||
- Reddit bot account must be moderator of target subreddit
|
||||
- Reddit bot account must be added to chat conversations where triggers will be sent
|
||||
|
||||
## Upgrade Path from V1
|
||||
|
||||
1. Update wiki config from JSON to YAML format
|
||||
2. Restructure config to use triggers (see `example_config.yaml`)
|
||||
3. Redeploy bot with updated code
|
||||
4. Send "reload-config" to verify new config works
|
||||
5. Use trigger keywords to post instead of restarting bot
|
||||
|
||||
---
|
||||
|
||||
**Version:** 2.0
|
||||
**Date:** March 11, 2026
|
||||
**Status:** Production Ready
|
||||
@@ -5,4 +5,5 @@ COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
COPY bot.py .
|
||||
COPY config.py .
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
CMD ["python", "bot.py"]
|
||||
|
||||
@@ -66,23 +66,59 @@ def chat_message_watcher(reddit, subreddit_name):
|
||||
with open(chat_requests_file, 'a', encoding='utf-8') as f:
|
||||
f.write(message.id + '\n')
|
||||
|
||||
if hasattr(message, 'body'):
|
||||
message_body = message.body.lower()
|
||||
# Check if sender is a moderator
|
||||
# Check if message has body and author
|
||||
if not hasattr(message, 'body'):
|
||||
continue
|
||||
|
||||
author = getattr(message, 'author', None)
|
||||
if author and author in subreddit.moderator():
|
||||
if not author:
|
||||
continue
|
||||
|
||||
# Check if sender is a moderator
|
||||
try:
|
||||
is_mod = author in subreddit.moderator()
|
||||
except Exception as e:
|
||||
print(f"[CHAT WATCH] Error checking if {author} is mod: {e}")
|
||||
continue
|
||||
|
||||
if not is_mod:
|
||||
continue
|
||||
|
||||
message_body_lower = message.body.lower()
|
||||
print(f"[CHAT WATCH] Moderator '{author}' sent message: {message.body[:100]}")
|
||||
|
||||
# Handle special 'reload-config' command
|
||||
if 'reload-config' in message_body_lower:
|
||||
print(f"[CHAT WATCH] Reload-config command detected.")
|
||||
result = validate_config_from_wiki(reddit, subreddit_name, WIKI_PAGE)
|
||||
if result:
|
||||
print("[CHAT WATCH] Wiki config validated successfully.")
|
||||
reply_text = "Config validated successfully. Config is valid YAML."
|
||||
else:
|
||||
print("[CHAT WATCH] Wiki config validation failed.")
|
||||
reply_text = "Config validation failed. Check the wiki config YAML formatting."
|
||||
try:
|
||||
message.reply(reply_text)
|
||||
print(f"[CHAT WATCH] Replied to message {message.id}.")
|
||||
except Exception as e:
|
||||
print(f"[CHAT WATCH] Error replying to message {message.id}: {e}")
|
||||
continue
|
||||
|
||||
# Load current config to check for triggers
|
||||
config = fetch_config_from_wiki(reddit, subreddit_name, WIKI_PAGE)
|
||||
posts_config = config.get('posts', [])
|
||||
|
||||
trigger_found = False
|
||||
|
||||
# Check if message contains any trigger
|
||||
for post_config in posts_config:
|
||||
if not isinstance(post_config, dict):
|
||||
continue
|
||||
|
||||
trigger = post_config.get('trigger', '').lower()
|
||||
if trigger and trigger in message_body:
|
||||
print(f"[CHAT WATCH] Moderator '{author}' triggered '{trigger}'.")
|
||||
if trigger and trigger in message_body_lower:
|
||||
trigger_found = True
|
||||
print(f"[CHAT WATCH] Matched trigger '{trigger}' in message.")
|
||||
|
||||
# Get posts for this trigger
|
||||
trigger_posts = get_trigger_posts(reddit, subreddit_name, WIKI_PAGE, trigger)
|
||||
@@ -97,14 +133,17 @@ def chat_message_watcher(reddit, subreddit_name):
|
||||
|
||||
try:
|
||||
message.reply(reply_text)
|
||||
print(f"[CHAT WATCH] Replied to chat message {message.id}.")
|
||||
print(f"[CHAT WATCH] Replied to message {message.id}.")
|
||||
except Exception as e:
|
||||
print(f"[CHAT WATCH] Error replying to chat message {message.id}: {e}")
|
||||
print(f"[CHAT WATCH] Error replying to message {message.id}: {e}")
|
||||
|
||||
# Only process the first matching trigger per message
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
print(f"[CHAT WATCH] Chat message watcher error: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
time.sleep(30)
|
||||
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
testpostbot:
|
||||
image: slfhstd.uk/slfhstd/testpostbot:latest
|
||||
testpostsbot:
|
||||
image: slfhstd.uk/slfhstd/testpostsbot:dev
|
||||
env_file:
|
||||
- .env
|
||||
restart: unless-stopped
|
||||
|
||||
Reference in New Issue
Block a user