Source code for scratchattach.eventhandlers.filterbot

"""FilterBot class"""
from __future__ import annotations

from .message_events import MessageEvents
import time

[docs] class HardFilter:
[docs] def __init__(self, filter_name="UntitledFilter", *, equals=None, contains=None, author_name=None, project_id=None, profile=None, case_sensitive=False): self.equals=equals self.contains=contains self.author_name=author_name self.project_id=project_id self.profile=profile self.case_sensitive=case_sensitive self.filter_name = filter_name
[docs] def apply(self, content, author_name, source_id): if not self.case_sensitive: content = content.lower() if self.equals is not None: if self.case_sensitive: if self.equals == content: return True else: if self.equals.lower() == content: return True if self.contains is not None: if self.case_sensitive: if self.contains.lower() in content: return True else: if self.contains in content: return True if self.author_name == author_name: return True if self.project_id == source_id or self.profile == source_id: return True return False
[docs] class SoftFilter(HardFilter):
[docs] def __init__(self, score:float, filter_name="UntitledFilter", *, equals=None, contains=None, author_name=None, project_id=None, profile=None, case_sensitive=False): self.score = score super().__init__(filter_name, equals=equals, contains=contains, author_name=author_name, project_id=project_id, profile=profile, case_sensitive=case_sensitive)
[docs] class SpamFilter(HardFilter):
[docs] def __init__(self, filter_name="UntitledFilter", *, equals=None, contains=None, author_name=None, project_id=None, profile=None, case_sensitive=False): self.memory = [] super().__init__(filter_name, equals=equals, contains=contains, author_name=author_name, project_id=project_id, profile=profile, case_sensitive=case_sensitive)
[docs] def apply(self, content, author_name, source_id): applies = super().apply(content, author_name, source_id) if not applies: return False self.memory.insert(0, {"content":content, "time":time.time()}) print(content, self.memory) for comment in list(self.memory)[1:]: if comment["time"] < time.time() -300: self.memory.remove(comment) if comment["content"].lower() == content.lower(): return True return False
[docs] class Filterbot(MessageEvents): # The Filterbot class is built upon MessageEvents, similar to how CloudEvents is built upon CloudEvents
[docs] def __init__(self, user, *, log_deletions=True): super().__init__(user) self.hard_filters = [] self.soft_filters = [] self.spam_filters = [] self.log_deletions = log_deletions self.event(self.on_message, thread=False) self.update_interval = 2
[docs] def add_filter(self, filter_obj): if isinstance(filter_obj, SoftFilter): self.soft_filters.append(filter_obj) elif isinstance(filter_obj, SpamFilter): # careful: SpamFilter is also HardFilter due to inheritence self.spam_filters.append(filter_obj) elif isinstance(filter_obj, HardFilter): self.hard_filters.append(filter_obj)
[docs] def add_f4f_filter(self): self.add_filter(HardFilter("(f4f_filter) 'f4f'", contains="f4f")) self.add_filter(HardFilter("(f4f_filter) 'follow me'", contains="follow me")) self.add_filter(HardFilter("(f4f_filter) 'follow @'", contains="follow @")) self.add_filter(HardFilter("(f4f_filter) f 4 f'", contains="f 4 f")) self.add_filter(HardFilter("(f4f_filter) 'follow for'", contains="follow for"))
[docs] def add_ads_filter(self): self.add_filter(SoftFilter(1, "(ads_filter) links", contains="scratch.mit.edu/projects/")) self.add_filter(SoftFilter(-1, "(ads_filter) feedback", contains="feedback")) self.add_filter(HardFilter("(ads_filter) 'check out my'", contains="check out my")) self.add_filter(HardFilter("(ads_filter) 'play my'", contains="play my")) self.add_filter(SoftFilter(1, "(ads_filter) 'advertis'", contains="advertis"))
[docs] def add_spam_filter(self): self.add_filter(SpamFilter("(spam_filter)", contains=""))
[docs] def add_genalpha_nonsense_filter(self): self.add_filter(HardFilter("(genalpha_nonsene_filter) 'skibidi'", contains="skibidi")) self.add_filter(HardFilter("[genalpha_nonsene_filter) 'rizzler'", contains="rizzler")) self.add_filter(HardFilter("(genalpha_nonsene_filter) 'fanum tax'", contains="fanum tax"))
[docs] def on_message(self, message): if message.type == "addcomment": delete = False content = message.comment_fragment if message.comment_type == 0: # project comment source_id = message.comment_obj_id if self.user._session.connect_project(message.comment_obj_id).author_name != self.user.username: return # no permission to delete if message.comment_type == 1: # profile comment source_id = message.comment_obj_title if message.comment_obj_title != self.user.username: return # no permission to delete if message.comment_type == 2: # studio comment return # studio comments aren't handled # Apply hard filters for hard_filter in self.hard_filters: if hard_filter.apply(content, message.actor_username, source_id): delete=True if self.log_deletions: print(f"DETECTED: #{message.comment_id} violates hard filter: {hard_filter.filter_name}") break # Apply spam filters if delete is False: for spam_filter in self.spam_filters: if spam_filter.apply(content, message.actor_username, source_id): delete=True if self.log_deletions: print(f"DETECTED: #{message.comment_id} violates spam filter: {spam_filter.filter_name}") break # Apply soft filters if delete is False: score = 0 violated_filers = [] for soft_filter in self.soft_filters: if soft_filter.apply(content, message.actor_username, source_id): score += soft_filter.score violated_filers.append(soft_filter.name) if score >= 1: print(f"DETECTED: #{message.comment_id} violates too many soft filters: {violated_filers}") delete = True if delete is True: try: message.target().delete() if self.log_deletions: print(f"DELETED: #{message.comment_id} by f{message.actor_username}: '{content}'") except Exception as e: if self.log_deletions: print(f"DELETION FAILED: #{message.comment_id} by f{message.actor_username}: '{content}'")