diff options
| author | Fuwn <[email protected]> | 2025-09-16 18:29:44 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2025-09-16 18:29:44 -0700 |
| commit | bc595728306dd977ef631727cb387e82104fed6e (patch) | |
| tree | f595654c4cfd1b073ea89585a51eca662b6afc7b /src | |
| parent | feat(roleplay_limiter): Add time window to minimum post allowance (diff) | |
| download | umabot-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.py | 3 | ||||
| -rw-r--r-- | src/umabot/rules/__init__.py | 3 | ||||
| -rw-r--r-- | src/umabot/rules/media_required.py | 113 |
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 |