Experimental Discord bot written in Python
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

Patterns

The PatternCog offers a way of creating custom message filters of moderate complexity without needing to make code changes in the bot and redeploy it. A guild can have any number of custom patterns. The commands are:

  • /pattern add <name> <statement> - Add a new named pattern
  • /pattern remove <name> - Remove a named pattern
  • /pattern list - List all named patterns

The pattern <name> can be anything. If it contains spaces, enclose it in double quotes, e.g. "my filter".

Statements

A statement consists of one or more actions to take on a message followed by an expression defining the criteria for which messages match. For example:

reply "You can't say that word!", delete if message contains "heck"

This statement has two actions (separated by a comma): replying, then deleting the original message. It will match any message that contains the word “heck”.

The list of actions and the matching expression are separated by the word “if”, which must be present in every statement.

<action>, <action>, ..., <action> if <condition>

Actions

One or more actions can be added to the statement. If there is more than one, they are separated with commas. Example:

delete, kick, modwarn

Available actions:

  • ban - Bans the user. The “reason” in the audit log will reference the pattern name.
  • delete - Deletes the message.
  • kick - Kicks the user. The “reason” in the audit log will reference the pattern name.
  • modinfo - Posts an informative message in the bot warning channel but does not tag the mods. Useful for logging a pattern that is mildly harmful but not worth getting immediate mod attention. Message will have options to delete, kick, or ban.
  • modwarn - Tags the mods in a warning message. The message will offer quick actions to manually delete the message, kick the user, and ban the user (assuming the other actions didn’t already do one or more of these things)
  • reply "message" - Makes Rocketbot automatically reply to their message with the given text.

Expressions

The simplest expression just consists of a message field, a comparison operator, and a value to compare it to. For example:

content.plain contains "forbidden"

The message will match if its content.plain field contains the word "forbidden".

The available operators and type of value depends on the field being accessed.

Fields

  • author - Who sent the message. Available operators: ==, !=. Comparison value must be a user mention (an @ that Discord will tab-complete for you).
  • author.id (alias author) - The numeric ID of the user who sent the message. Available operators: ==, !=. Comparison value must be a numeric user ID.
  • author.joinage - How much time has elapsed from when the author joined and when the message was sent. If the user has joined and left multiple times this is since the most recent join. Available operators: ==, !=, <, >, <=, >=. Comparison value must be a timespan (see below)
  • author.name - The username of the author. Available operators: ==, !=, contains, !contains, containsword, !containsword, matches, !matches. Comparison value must be a quoted string.
  • content.plain - The plain text of the message. All markdown formatting is removed, and mentions look like the @Username text name that gets displayed.
  • content.markdown (alias content) - The raw markdown of the message. This contains all markdown characters, and mentions are of the <@!0000000> form. Available operators: ==, !=, contains, !contains, matches, !matches. Comparison value must be a quoted string.
  • lastmatched - How long ago this pattern matched a message. Used for imposing a cooldown, especially for autoresponses. If the pattern has never matched it will be treated as if it last ran 100 years ago for comparison purposes. Available operators: ==, !=, <, >, <=, >=. Comparison value must be a timespan (see below).

Operators

  • == - The values are equal.
  • != - The values are not equal.
  • < - The field is less than the given value.
  • > - The field is greater than the given value.
  • <= - The field is less than or equal to the given value.
  • >= - The field is greater than or equal to the given value.
  • contains - The value is contained somewhere in the field value. Will match parts of words (e.g. “cat” will match “scatter”).
  • !contains - The value is not contained anywhere in the field value.
  • containsword - The value is contained somewhere in the field value as a whole word (e.g. “cat” will not match “scatter”).
  • !containsword - The value is not contained somewhere in the field value as a whole word.
  • matches - The given regular expression matches part of the field value.
  • !matches - The given regular expression does not match any part of the field value.

Values

Text values must be enclosed in double quote (") characters. To include a literal quote character, escape it with a backslash, e.g. "string with \"quotes\" in it". Literal backslashes can be escaped with two backslashes, e.g. "string with \\ backslash".

Timespans consist of one or more pairs of a number and a unit letter (“d” for days, “h” for hours, “m” for minutes, “s” for seconds). Examples:

  • 30d - 30 days
  • 1h30m - 1 hour, 30 minutes
  • 99d9h9m9s - 99 days, 9 hours, 9 minutes, 9 seconds

Regular expressions are provided in double quotes like a regular string. Backslashed character classes must be escaped, e.g. "foo\\s+bar" for “foo” and “bar” separated by whitespace.

Compound Expressions

Multiple expressions can be combined with “and” or “or”. For example:

content.plain contains "alpha" and content.plain contains "bravo"

This will only match messages that contain both “alpha” and “bravo” somewhere in the text.

More complex expressions can use parentheses to clarify the order of interpretation. For example:

(content.plain contains "foo" and author.joinage < 30m) or (content.plain contains "bar" and author.joinage > 30m)

A message will match if it contains “foo” and the user joined in the last half hour, OR it will match if the message contains “bar” and the author joined more than a half hour ago.

Lastly, expressions can be inverted by prefixing a !. For example:

!(content.plain contains "me" and content.plain contains "you")

This will only match messages that do not contain both “me” and “you”. If it contains just “me” or just “you” or neither word then it will match. If both are present it will not match.

Examples

Here are examples of add commands:

Automatically delete a banned word:

/pattern add "bad word" delete if content.plain contains "darn"

Ban anyone who posts a URL within the first 30 minutes of joining the server.

/pattern add "url spam" ban if author.joinage < 30m and (content.plain contains "http://" or content.plain contains "https://")

Automatically reply to anyone asking when lunch is.

/pattern add "lunch" reply "Lunch is at noon." if content.plain == "When is lunch?"

Grammar

<statement> ::= <actions> <ws> “if” <ws> <expression>

<ws> ::= SPACE | TAB | CR | LF | <ws> <ws>

<actions> ::= <action> | <action> “,” <ws> <actions>

<action> ::= “ban” | “delete” | “kick” | “modinfo” | “modwarn” | “reply” <ws> <quoted_string>

<quoted_string> ::= ‘“’ ANY ‘”’

<expression> ::= <simple_expr> | <not_expr> | <paren_expr> | <compound_expr>

<simple_expr> ::= <field_name> <ws> <op> <ws> <value>

<not_expr> ::= “!” <expression>

<paren_expr> ::= “(” <expression> “)”

<compound_expr> ::= <and_expr> | <or_expr>

<and_expr> ::= <expression> <ws> “and” <ws> <expression>

<or_expr> ::= <expression> <ws> “or” <ws> <expression>

<field_name> ::= “author” | “author.id” | “author.joinage” | “author.name” | “content.markdown” | “content.plain” | “lastmatched”

<op> ::= “==” | “!=” | “<” | “>” | “<=” | “>=” | “contains” | “!contains” | “containsword” | “!containsword” | “matches” | “!matches”

<value> ::= <int> | <float> | <quoted_string> | <timespan> | <mention>

<timespan> ::= <timespan_component> | <timespan_component> <timespan>

<timespan_component> ::= <int> <timespan_unit>

<timespan_unit> ::= “d” | “h” | “m” | “s”

<mention> ::= “<@!” <int> “>”