aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2025-09-03 21:16:37 -0700
committerFuwn <[email protected]>2025-09-03 21:16:37 -0700
commit8771d932d23fcc6aa36c92d1f7759f965d64a796 (patch)
tree2916cabbbb1c5be1cb13c80a187ec57740d79036
parentfeat(roleplay_limiter): Use surge-based removal model (diff)
downloadumabot-8771d932d23fcc6aa36c92d1f7759f965d64a796.tar.xz
umabot-8771d932d23fcc6aa36c92d1f7759f965d64a796.zip
feat(roleplay_limiter): Add static limiter module back
-rw-r--r--README.md16
-rw-r--r--src/umabot/bot.py4
-rw-r--r--src/umabot/rules/__init__.py4
-rw-r--r--src/umabot/rules/roleplay_limiter.py80
4 files changed, 98 insertions, 6 deletions
diff --git a/README.md b/README.md
index 90621ac..12f8639 100644
--- a/README.md
+++ b/README.md
@@ -11,16 +11,26 @@ A modular Reddit bot for automated post moderation built with Python and PRAW.
- **Dry Run Mode**: Test the bot without actually removing posts
- **Comprehensive Logging**: Detailed logs for monitoring and debugging
-### Surge-Based Roleplay Limiting
+### Roleplay Limiting Options
-The bot uses intelligent surge detection to manage roleplay posts:
+The bot supports two roleplay limiting modes:
+
+#### Surge-Based Limiting (Default)
+Intelligent surge detection that adjusts limits based on subreddit activity:
- **Normal Activity** (< 20 roleplay posts): Users can post up to 5 roleplay posts per time window
- **Moderate Surge** (20+ roleplay posts): Users limited to 3 roleplay posts per time window
- **High Surge** (40+ roleplay posts): Users limited to 1 roleplay post per time window
- **Extreme Surge** (60+ roleplay posts): All roleplay posts temporarily blocked
-The system automatically adjusts limits based on recent roleplay activity and provides dynamic removal messages explaining the current restrictions.
+#### Static Limiting (Optional)
+Fixed limit that doesn't change based on activity:
+
+- **Fixed Limit**: Users can post a configurable number of roleplay posts per time window (default: 1)
+- **Simple**: No surge detection, just enforces the same limit for all users
+- **Predictable**: Consistent behavior regardless of subreddit activity
+
+To switch to static limiting, uncomment the `StaticRoleplayLimiter` line in `src/umabot/bot.py` and comment out the `RoleplayLimiter` line.
## Quick Start
diff --git a/src/umabot/bot.py b/src/umabot/bot.py
index 6c9797c..cb17b9b 100644
--- a/src/umabot/bot.py
+++ b/src/umabot/bot.py
@@ -10,6 +10,7 @@ from loguru import logger
from .config import Config
from .rules import SpamDetector, RoleplayLimiter
+# from .rules import StaticRoleplayLimiter # Disabled by default - uncomment to use static limiting
class HealthCheckHandler(BaseHTTPRequestHandler):
@@ -75,7 +76,8 @@ class UmaBot:
# Initialize rules
self.rules = [
SpamDetector(config),
- RoleplayLimiter(config, self.subreddit)
+ RoleplayLimiter(config, self.subreddit) # Surge-based roleplay limiter (default)
+ # StaticRoleplayLimiter(config) # Uncomment to use static roleplay limiting instead
]
# Track processed submissions to avoid processing old posts
diff --git a/src/umabot/rules/__init__.py b/src/umabot/rules/__init__.py
index e912e70..7573843 100644
--- a/src/umabot/rules/__init__.py
+++ b/src/umabot/rules/__init__.py
@@ -2,6 +2,6 @@
from .base import Rule
from .spam_detector import SpamDetector
-from .roleplay_limiter import RoleplayLimiter
+from .roleplay_limiter import RoleplayLimiter, StaticRoleplayLimiter
-__all__ = ["Rule", "SpamDetector", "RoleplayLimiter"]
+__all__ = ["Rule", "SpamDetector", "RoleplayLimiter", "StaticRoleplayLimiter"]
diff --git a/src/umabot/rules/roleplay_limiter.py b/src/umabot/rules/roleplay_limiter.py
index 60490a9..5aea520 100644
--- a/src/umabot/rules/roleplay_limiter.py
+++ b/src/umabot/rules/roleplay_limiter.py
@@ -138,3 +138,83 @@ class RoleplayLimiter(Rule):
except Exception as e:
self.logger.error(f"Error checking flair for submission {submission.id}: {e}")
return False
+
+
+class StaticRoleplayLimiter(Rule):
+ """Static roleplay limiter that limits users to a fixed number of roleplay posts per time window."""
+
+ def __init__(self, config):
+ """Initialize the static roleplay limiter."""
+ super().__init__(config)
+ self.user_roleplay_posts: Dict[str, List[float]] = {}
+ self.max_roleplay_posts = config.max_roleplay_posts_per_day
+ self.time_window = config.roleplay_limit_window_hours * 60 * 60 # Convert hours to seconds
+ self.roleplay_flair = "Roleplay"
+
+ def should_remove(self, submission: praw.models.Submission) -> bool:
+ """Check if a user has posted too many roleplay posts."""
+ if not submission.author:
+ return False
+
+ # Check if this is a roleplay post
+ if not self._is_roleplay_post(submission):
+ return False
+
+ username = submission.author.name
+ current_time = time.time()
+
+ # Clean old posts from tracking
+ self._clean_old_posts(username, current_time)
+
+ # Count current roleplay posts in the time window
+ if username not in self.user_roleplay_posts:
+ self.user_roleplay_posts[username] = []
+
+ post_count = len(self.user_roleplay_posts[username])
+
+ # Add current post to tracking
+ self.user_roleplay_posts[username].append(current_time)
+
+ # Check if this post exceeds the limit
+ if post_count >= self.max_roleplay_posts:
+ self.logger.info(
+ f"User {username} has posted {post_count + 1} roleplay posts in {self.config.roleplay_limit_window_hours} hours "
+ f"(limit: {self.max_roleplay_posts})"
+ )
+ return True
+
+ return False
+
+ def get_removal_message(self, submission: praw.models.Submission) -> str:
+ """Get the static roleplay removal message."""
+ return self.config.roleplay_message
+
+ def _clean_old_posts(self, username: str, current_time: float) -> None:
+ """Remove roleplay posts older than the time window from tracking."""
+ if username not in self.user_roleplay_posts:
+ return
+
+ cutoff_time = current_time - self.time_window
+ self.user_roleplay_posts[username] = [
+ post_time for post_time in self.user_roleplay_posts[username]
+ if post_time > cutoff_time
+ ]
+
+ def _is_roleplay_post(self, submission: praw.models.Submission) -> bool:
+ """Check if a submission has the roleplay flair."""
+ try:
+ # Check link flair text
+ if hasattr(submission, 'link_flair_text') and submission.link_flair_text:
+ return submission.link_flair_text.lower() == self.roleplay_flair.lower()
+
+ # Check flair template ID (if using new flair system)
+ if hasattr(submission, 'link_flair_template_id') and submission.link_flair_template_id:
+ # You might need to map flair template IDs to names
+ # For now, we'll just check the text
+ pass
+
+ return False
+
+ except Exception as e:
+ self.logger.error(f"Error checking flair for submission {submission.id}: {e}")
+ return False