aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFuwn <[email protected]>2025-09-16 18:29:44 -0700
committerFuwn <[email protected]>2025-09-16 18:29:44 -0700
commitbc595728306dd977ef631727cb387e82104fed6e (patch)
treef595654c4cfd1b073ea89585a51eca662b6afc7b /src
parentfeat(roleplay_limiter): Add time window to minimum post allowance (diff)
downloadumabot-bc595728306dd977ef631727cb387e82104fed6e.tar.xz
umabot-bc595728306dd977ef631727cb387e82104fed6e.zip
feat(rules): Add media_required rule for roleplay posts
Diffstat (limited to 'src')
-rw-r--r--src/umabot/bot.py3
-rw-r--r--src/umabot/rules/__init__.py3
-rw-r--r--src/umabot/rules/media_required.py113
3 files changed, 117 insertions, 2 deletions
diff --git a/src/umabot/bot.py b/src/umabot/bot.py
index cb17b9b..e905d86 100644
--- a/src/umabot/bot.py
+++ b/src/umabot/bot.py
@@ -9,7 +9,7 @@ from socketserver import ThreadingMixIn
from loguru import logger
from .config import Config
-from .rules import SpamDetector, RoleplayLimiter
+from .rules import SpamDetector, RoleplayLimiter, MediaRequiredRule
# from .rules import StaticRoleplayLimiter # Disabled by default - uncomment to use static limiting
@@ -76,6 +76,7 @@ class UmaBot:
# Initialize rules
self.rules = [
SpamDetector(config),
+ MediaRequiredRule(config), # Requires media for roleplay posts
RoleplayLimiter(config, self.subreddit) # Surge-based roleplay limiter (default)
# StaticRoleplayLimiter(config) # Uncomment to use static roleplay limiting instead
]
diff --git a/src/umabot/rules/__init__.py b/src/umabot/rules/__init__.py
index 7573843..6122075 100644
--- a/src/umabot/rules/__init__.py
+++ b/src/umabot/rules/__init__.py
@@ -3,5 +3,6 @@
from .base import Rule
from .spam_detector import SpamDetector
from .roleplay_limiter import RoleplayLimiter, StaticRoleplayLimiter
+from .media_required import MediaRequiredRule
-__all__ = ["Rule", "SpamDetector", "RoleplayLimiter", "StaticRoleplayLimiter"]
+__all__ = ["Rule", "SpamDetector", "RoleplayLimiter", "StaticRoleplayLimiter", "MediaRequiredRule"]
diff --git a/src/umabot/rules/media_required.py b/src/umabot/rules/media_required.py
new file mode 100644
index 0000000..8158c5a
--- /dev/null
+++ b/src/umabot/rules/media_required.py
@@ -0,0 +1,113 @@
+"""Media requirement rule for roleplay posts."""
+
+import praw.models
+from .base import Rule
+
+
+class MediaRequiredRule(Rule):
+ """Requires roleplay posts to have media attached."""
+
+ def __init__(self, config):
+ """Initialize the media required rule."""
+ super().__init__(config)
+ self.roleplay_flair = "Roleplay"
+
+ def should_remove(self, submission: praw.models.Submission) -> bool:
+ """Check if a roleplay post lacks required media."""
+ if not submission.author:
+ return False
+
+ # Check if this is a roleplay post
+ if not self._is_roleplay_post(submission):
+ return False
+
+ # Check if the post has media
+ if self._has_media(submission):
+ return False
+
+ # Roleplay post without media - should be removed
+ self.logger.info(
+ f"Roleplay post by {submission.author.name} removed for missing media "
+ f"(post ID: {submission.id})"
+ )
+ return True
+
+ def get_removal_message(self, submission: praw.models.Submission) -> str:
+ """Get the media requirement removal message."""
+ return (
+ f"Your roleplay post has been removed because it doesn't include any media. "
+ f"All roleplay posts in r/{self.config.subreddit_name} must include an image, video, "
+ f"or other media attachment to enhance the roleplay experience."
+ )
+
+ 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
+
+ def _has_media(self, submission: praw.models.Submission) -> bool:
+ """Check if a submission has media attached."""
+ try:
+ # Check for image/video posts
+ if submission.is_video or submission.is_self:
+ # For self posts, check if they contain media links
+ if submission.is_self and submission.selftext:
+ # Look for common media URLs in the text
+ media_indicators = [
+ 'imgur.com', 'i.imgur.com', 'redd.it', 'i.redd.it',
+ 'youtube.com', 'youtu.be', 'vimeo.com', 'gfycat.com',
+ 'streamable.com', 'twitter.com', 'x.com', 'tiktok.com',
+ 'instagram.com', 'facebook.com', 'discord.com', 'discordapp.com'
+ ]
+
+ text_lower = submission.selftext.lower()
+ return any(indicator in text_lower for indicator in media_indicators)
+ return False
+
+ # Check for link posts with media
+ if hasattr(submission, 'url') and submission.url:
+ # Check if URL points to media
+ url_lower = submission.url.lower()
+ media_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.gifv', '.mp4', '.webm', '.webp']
+ media_domains = [
+ 'imgur.com', 'i.imgur.com', 'redd.it', 'i.redd.it',
+ 'youtube.com', 'youtu.be', 'vimeo.com', 'gfycat.com',
+ 'streamable.com', 'twitter.com', 'x.com', 'tiktok.com',
+ 'instagram.com', 'facebook.com'
+ ]
+
+ # Check file extensions
+ if any(url_lower.endswith(ext) for ext in media_extensions):
+ return True
+
+ # Check media domains
+ if any(domain in url_lower for domain in media_domains):
+ return True
+
+ # Check for gallery posts
+ if hasattr(submission, 'is_gallery') and submission.is_gallery:
+ return True
+
+ # Check for crosspost with media
+ if hasattr(submission, 'crosspost_parent') and submission.crosspost_parent:
+ return self._has_media(submission.crosspost_parent)
+
+ return False
+
+ except Exception as e:
+ self.logger.error(f"Error checking media for submission {submission.id}: {e}")
+ return False