2.2.0
This commit is contained in:
@@ -1,5 +1,26 @@
|
||||
|
||||
# Changelog
|
||||
|
||||
## [2.2.0] - 2026-03-12
|
||||
|
||||
### Added
|
||||
- **Configurable Ignore Tags:**
|
||||
- Added `ignore_tags` section to wiki config. Bot now ignores posts with matching tags in the title or flair (case-insensitive).
|
||||
- Updated README.md and bot logic to support this feature.
|
||||
- **Update Checker Integration:**
|
||||
- Added `update_checker.py` module to check for bot updates and notify moderators via modmail.
|
||||
- Update checker runs in a background thread and checks for updates hourly.
|
||||
- **Bot Version & Name Constants:**
|
||||
- Added `BOT_VERSION` and `BOT_NAME` constants at the top of `modreplybot.py` for easy version/name changes.
|
||||
|
||||
### Changed
|
||||
- Integrated update checker startup in main bot entrypoint.
|
||||
- Improved documentation for ignore_tags and update checker features.
|
||||
|
||||
### Fixed
|
||||
- N/A
|
||||
|
||||
|
||||
## [2.1.2] - 2026-03-10
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -36,3 +36,9 @@ o846f5z
|
||||
5judtbe
|
||||
5jugfpj
|
||||
5jv66nh
|
||||
5jvi6wk
|
||||
5jvji2r
|
||||
o9wezfi
|
||||
o9wf1xl
|
||||
o9x1jh0
|
||||
o9x1lyh
|
||||
|
||||
@@ -68,3 +68,5 @@
|
||||
1rqd9ds
|
||||
1rqd966
|
||||
1rqd9aw
|
||||
1rs5sz0
|
||||
1rs5sxl
|
||||
|
||||
@@ -5,5 +5,6 @@ COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
COPY config.py .
|
||||
COPY modreplybot.py .
|
||||
COPY update_checker.py .
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
CMD ["python", "modreplybot.py"]
|
||||
|
||||
@@ -41,10 +41,17 @@ post_tags:
|
||||
__[Click here if your post says "Sorry, this post was removed by Reddit’s filters"](...)__
|
||||
status: enabled
|
||||
flair_id: 12345678-aaaa-bbbb-cccc-1234567890ab
|
||||
|
||||
# New: Ignore tags
|
||||
ignore_tags:
|
||||
- tag: Off-Topic
|
||||
- tag: Meme
|
||||
```
|
||||
|
||||
- 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.
|
||||
- ignore_tags: Bot will ignore (not comment on) posts with these tags in the title. Tags are case-insensitive and match `[Tag]` in the post title or flair.
|
||||
- Status options: `enabled`, `log-only`, `disabled`.
|
||||
- Optional actions: `flair_id`, `stickied`, `lock_post`, `lock_comment`.
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
modreplybot:
|
||||
image: slfhstd.uk/slfhstd/modreplybot:latest
|
||||
image: slfhstd.uk/slfhstd/modreplybot:dev
|
||||
container_name: modreplybot
|
||||
env_file:
|
||||
- .env
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import os
|
||||
import praw
|
||||
from config import get_reddit, Config
|
||||
from update_checker import start_update_checker
|
||||
|
||||
BOT_VERSION = "2.2.0" # Change this for new releases
|
||||
BOT_NAME = "ModReplyBot" # Change this if bot name changes
|
||||
|
||||
import time
|
||||
|
||||
@@ -151,6 +155,12 @@ class ModReplyBot:
|
||||
self.tag_comments[tag] = comment
|
||||
self.tag_statuses[tag] = status
|
||||
self.tag_flair_ids[tag] = flair_id
|
||||
# Parse ignore_tags
|
||||
self.ignore_tags = set()
|
||||
for entry in config.get('ignore_tags', []):
|
||||
tag_val = entry.get('tag', '').strip().lower() if isinstance(entry, dict) else str(entry).strip().lower()
|
||||
if tag_val:
|
||||
self.ignore_tags.add(tag_val)
|
||||
self._last_config_error_revision = None
|
||||
return True
|
||||
|
||||
@@ -255,6 +265,18 @@ class ModReplyBot:
|
||||
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}")
|
||||
# Ignore if any ignore_tag matches flair or title tag
|
||||
ignore = False
|
||||
if flair in self.ignore_tags:
|
||||
ignore = True
|
||||
else:
|
||||
for tag in title_tags_lower:
|
||||
if tag in self.ignore_tags:
|
||||
ignore = True
|
||||
break
|
||||
if ignore:
|
||||
print(f"[TAG WATCH] Ignoring post {submission.id} due to ignore tag.")
|
||||
continue
|
||||
matched_tag = None
|
||||
if flair in self.tag_comments:
|
||||
matched_tag = flair
|
||||
@@ -484,4 +506,6 @@ class ModReplyBot:
|
||||
|
||||
if __name__ == "__main__":
|
||||
bot = ModReplyBot()
|
||||
# Start update checker thread
|
||||
start_update_checker(bot.reddit, Config.SUBREDDIT, BOT_NAME, BOT_VERSION)
|
||||
bot.run()
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import requests
|
||||
import threading
|
||||
import time
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
UPDATE_CHECK_INTERVAL = 3600 # Check every hour
|
||||
UPDATE_COOLDOWN = 86400 # Don't send mail more than once per 24 hours
|
||||
LAST_UPDATE_FILE = os.path.join(os.path.dirname(__file__), 'DB', '.last_update_check.txt')
|
||||
|
||||
|
||||
def get_latest_version(bot_name):
|
||||
"""Fetch latest version info from update server."""
|
||||
try:
|
||||
response = requests.get(f'https://updts.slfhstd.uk/api/version/{bot_name}', timeout=10)
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
except Exception as e:
|
||||
print(f"[UPDATE_CHECKER] Error fetching version: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def send_update_modmail(reddit, subreddit_name, bot_name, current_version, available_version, changelog_url):
|
||||
"""Send modmail to subreddit modteam about available update."""
|
||||
try:
|
||||
subject = f"🤖 {bot_name} Update Available (v{available_version})"
|
||||
message = f"""Hello,
|
||||
|
||||
An update is available for {bot_name}!
|
||||
|
||||
**Current Version:** {current_version}
|
||||
**Available Version:** {available_version}
|
||||
|
||||
Changelog: {changelog_url}
|
||||
|
||||
Please visit the update server for installation instructions.
|
||||
|
||||
---
|
||||
This is an automated message from the Update Checker."""
|
||||
data = {
|
||||
"subject": subject,
|
||||
"text": message,
|
||||
"to": f"/r/{subreddit_name}",
|
||||
}
|
||||
reddit.post("api/compose/", data=data)
|
||||
print(f"[UPDATE_CHECKER] Sent update notification to r/{subreddit_name}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"[UPDATE_CHECKER] Error sending modmail: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def should_send_update_mail():
|
||||
"""Check if enough time has passed since last update mail."""
|
||||
if not os.path.exists(LAST_UPDATE_FILE):
|
||||
return True
|
||||
try:
|
||||
with open(LAST_UPDATE_FILE, 'r') as f:
|
||||
last_check = float(f.read().strip())
|
||||
return (time.time() - last_check) >= UPDATE_COOLDOWN
|
||||
except:
|
||||
return True
|
||||
|
||||
|
||||
def mark_update_mailed():
|
||||
"""Record when update mail was sent."""
|
||||
os.makedirs(os.path.dirname(LAST_UPDATE_FILE), exist_ok=True)
|
||||
with open(LAST_UPDATE_FILE, 'w') as f:
|
||||
f.write(str(time.time()))
|
||||
|
||||
|
||||
def update_checker_thread(reddit, subreddit_name, bot_name, current_version):
|
||||
"""Background thread that checks for updates periodically."""
|
||||
print(f"[UPDATE_CHECKER] Started for {bot_name} v{current_version}")
|
||||
while True:
|
||||
try:
|
||||
latest = get_latest_version(bot_name)
|
||||
if latest:
|
||||
available_version = latest.get('version')
|
||||
changelog_url = latest.get('changelog_url', '')
|
||||
if available_version and available_version != current_version:
|
||||
if should_send_update_mail():
|
||||
sent = send_update_modmail(
|
||||
reddit, subreddit_name, bot_name, current_version, available_version, changelog_url
|
||||
)
|
||||
if sent:
|
||||
mark_update_mailed()
|
||||
else:
|
||||
print(f"[UPDATE_CHECKER] No version info received.")
|
||||
except Exception as e:
|
||||
print(f"[UPDATE_CHECKER] Error in update checker thread: {e}")
|
||||
time.sleep(UPDATE_CHECK_INTERVAL)
|
||||
|
||||
|
||||
def start_update_checker(reddit, subreddit_name, bot_name, current_version):
|
||||
threading.Thread(
|
||||
target=update_checker_thread,
|
||||
args=(reddit, subreddit_name, bot_name, current_version),
|
||||
daemon=True
|
||||
).start()
|
||||
Reference in New Issue
Block a user