diff --git a/README.md b/README.md index fef4f88..57e097e 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,8 @@ Rules have five fields. Only `matches` and `template` are required. * `rooms` - The list of rooms where the rule should apply. If empty, the rule will apply to all rooms the bot is in. * `matches` - The regex or list of regexes to match. +* `probability` - The probability the rule will be executed expressed as a float + between 0 and 1.0. Defaults to 1.0. * `template` - The name of the template to use. * `variables` - A key-value map of variables to extend or override template variables. Like with template variables, the values are parsed as Jinja2 templates. diff --git a/reactbot/config.py b/reactbot/config.py index efbf9ae..77cbb45 100644 --- a/reactbot/config.py +++ b/reactbot/config.py @@ -59,6 +59,7 @@ class Config(BaseProxyConfig): not_rooms=set(rule.get("not_rooms", [])), matches=self._compile_all(rule["matches"]), not_matches=self._compile_all(rule.get("not_matches", [])), + probability=rule.get("probability", 1.0), type=EventType.find(rule["type"]) if "type" in rule else None, template=self.templates[rule["template"]], variables=self._parse_variables(rule)) diff --git a/reactbot/rule.py b/reactbot/rule.py index b97b350..4e338f4 100644 --- a/reactbot/rule.py +++ b/reactbot/rule.py @@ -18,6 +18,8 @@ from typing import Optional, Match, Dict, List, Set, Union, Pattern, Any from attr import dataclass from jinja2 import Template as JinjaTemplate +from random import random + from mautrix.types import RoomID, EventType from maubot import MessageEvent @@ -34,6 +36,7 @@ class Rule: not_rooms: Set[RoomID] matches: List[RPattern] not_matches: List[RPattern] + probability: float template: Template type: Optional[EventType] variables: Dict[str, Any] @@ -49,6 +52,8 @@ class Rule: return None elif evt.room_id in self.not_rooms: return None + elif self.probability < random(): + return None for pattern in self.matches: match = pattern.search(evt.content.body) if match: