twitch-bot/wiki/Home.md
Knut Ahlers 04d415810d
Add example for generic chat-addable commands
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2021-06-30 01:37:41 +02:00

12 KiB

Configuration

---

# Channels to join (only those can be acted on)
channels:
  - mychannel

# Allow moderators to hand out permits (if set to false only broadcaster can do this)
permit_allow_moderator: true
# How long to permit on !permit command
permit_timeout: 60s

# Variables are made available in templating (for example useful to disable several
# rules at once using the `disable_on_template` directive)
# Supported data types: Boolean, Float, Integer, String
variables:
  myvariable: true
  anothervariable: "string"

auto_messages:
  - channel: 'mychannel'          # String, channel to send message to
    message: 'Automated message'  # String, message to send
    use_action: true              # Bool, optional, send message as action (`/me <message>`)

    # Even though all of these are optional, at least one MUST be specified for the entry to be valid
    cron: '*/10 * * * *'  # String, optional, cron syntax when to send the message
    message_interval: 3   # Integer, optional, how many non-bot-messages must be sent in between
    time_interval: 900s   # Duration, optional, how long to wait before repeating the message

    only_on_live: true    # Boolean, optional, only send the message when channel is live

    # Disable message using templating, must yield string `true` to disable the automated message
    disable_on_template: '{{ ne .myvariable true }}'

rules: # See below for examples

  - actions: # Array of actions to take when this rule matches

    # Issue a ban on the user who wrote the chat-line
    - ban: "reason of ban"

    # Command to execute for the chat message, must return an JSON encoded array of actions
    - command: [/bin/bash, -c, "echo '[{\"respond\": \"Text\"}]'"]

    # Modify an internal counter value (does NOT send a chat line)
    - counter: "counterid" # String to identify the counter, applies templating
      counter_set: 25      # String, set counter to value (counter_step is ignored if set),
                           # applies templating but MUST result in a parseable integer
      counter_step: 1      # Integer, can be negative or positive, default: +1

    # Introduce a delay between two actions
    - delay: 1m         # Duration, how long to wait (fixed)
      delay_jitter: 1m  # Duration, add random delay to fixed delay between 0 and this value

    # Issue a delete on the message caught
    - delete_message: true # Bool, set to true to delete

    # Send raw IRC message to Twitch servers
    - raw_message: 'PRIVMSG #{{ .channel }} :Test' # String, applies templating

    # Send responding message to the channel the original message was received in
    - respond: 'Hello chatter'    # String, applies templating
      respond_as_reply: true      # Boolean, optional, use Twitch-Reply feature in respond
      respond_fallback: 'Oh noes' # String, text to send if the template function causes
                                  # an error, applies templating (default: unset)

    # Issue a timeout on the user who wrote the chat-line
    - timeout: 1s # Duration value: 1s / 1m / 1h

    # Set a variable to value defined for later usage
    - variable: myvar       # String, name of the variable to set (applies templating)
      clear: false          # Boolean, clear the variable
      set: '{{ .channel }}' # String, value to set the variable to (applies templating)

    # Send a whisper (ATTENTION: You need to have a known / verified bot for this!)
    # Without being known / verified your whisper will just silently get dropped by Twitch
    # Go here to get that verification: https://dev.twitch.tv/limit-increase
    - whisper_to: '{{ .username }}' # String, username to send to, applies templating
      whisper_message: 'Ohai!'      # String, message to send, applies templating

    # Add a cooldown to the rule in general (not to trigger counters twice, ...)
    # Using this will prevent the rule to be executed in all matching channels
    # as long as the cooldown is active.
    cooldown: 1s # Duration value: 1s / 1m / 1h

    # Add a cooldown to the rule per channel (not to trigger counters twice, ...)
    # Using this will prevent the rule to be executed in the channel it was triggered
    # which means other channels are not affected.
    channel_cooldown: 1s # Duration value: 1s / 1m / 1h

    # Add a cooldown to the rule per user (not to trigger counters twice, ...)
    # Using this will prevent the rule to be executed for the user which triggered it
    # in any of the matching channels, which means other users can trigger the command
    # while that particular user cannot
    user_cooldown: 1s # Duration value: 1s / 1m / 1h

    # Do not apply cooldown for these badges
    skip_cooldown_for: [broadcaster, moderator]

    # Disable the rule by setting to true
    disable: false

    # Disable actions when the matched channel has no active stream
    disable_on_offline: false

    # Disable actions on this rule if the user has an active permit
    disable_on_permit: false

    # Disable actions using templating, must yield string `true` to disable the rule
    disable_on_template: '{{ ne .myvariable true }}'

    # Disable actions on this rule if the user has one of these badges
    disable_on: [broadcaster, moderator]

    # Enable actions on this rule only if the user has one of these badges
    enable_on: [broadcaster, moderator]

    # Require the chat message to be sent in this channel
    match_channels: ['#mychannel']

    # Require the chat message to be sent by one of these users
    match_users: ['mychannel'] # List of users, all names MUST be all lower-case

    # Execute actions when this event occurs
    # Available events: join, host, part, permit, raid, resub, sub, subgift, whisper
    match_event: 'permit'

    # Execute action when the chat message matches this regular expression
    match_message: '' # String, regular expression

    # Disable the actions on this rule if one of these regular expression matches the chat message
    disable_on_match_messages: []

...

Templating

There are certain variables available in the strings with templating enabled:

  • channel - Channel the message was sent to, only available for regular messages not events
  • msg - The message object, used in functions, should not be sent to chat
  • permitTimeout - Value of permit_timeout in seconds
  • username - The username of the message author

Additionally there are some functions available in the templates:

  • arg <idx> - Takes the message sent to the channel, splits by space and returns the Nth element
  • channelCounter <counter name> - Wraps the counter name into a channel specific counter name including the channel name
  • concat <delimiter> <...parts> - Join the given string parts with delimiter
  • counterValue <counter name> - Returns the current value of the counter which identifier was supplied
  • displayName <username> [fallback] - Returns the display name the specified user set for themselves
  • fixUsername <username> - Ensures the username no longer contains the @ or # prefix
  • followDate <from> <to> - Looks up when from followed to
  • group <idx> - Gets matching group specified by index from match_message regular expression
  • recentGame <username> [fallback] - Returns the last played game name of the specified user (see shoutout example) or the fallback if the game could not be fetched. If no fallback was supplied the message will fail and not be sent.
  • tag <tagname> - Takes the message sent to the channel, returns the value of the tag specified
  • toLower <string> - Converts the given string to lower-case
  • toUpper <string> - Converts the given string to upper-case
  • variable <name> [default] - Returns the variable value or default in case it is empty

Command executions

Your command will get a JSON object passed through stdin you can parse to gain details about the message. It is expected to yield an array of actions on stdout and exit with status 0. If it does not the action will be marked failed. In case you need to output debug output you can use stderr which is directly piped to the bots stderr.

This is an example input you might get on stdin:

{
  "badges": {
    "glhf-pledge": 1,
    "moderator": 1
  },
  "channel": "#tezrian",
  "message": "!test",
  "tags": {
    "badge-info": "",
    "badges": "moderator/1,glhf-pledge/1",
    "client-nonce": "6801c82a341f728dbbaad87ef30eae49",
    "color": "#A72920",
    "display-name": "Luziferus",
    "emotes": "",
    "flags": "",
    "id": "dca06466-3741-4b22-8339-4cb5b07a02cc",
    "mod": "1",
    "room-id": "485884564",
    "subscriber": "0",
    "tmi-sent-ts": "1610313040489",
    "turbo": "0",
    "user-id": "69699328",
    "user-type": "mod"
  },
  "username": "luziferus"
}

The example was dumped using this action:

  - actions:
    - command: [/usr/bin/bash, -c, "jq . >&2"]
    match_channels: ['#tezrian']
    match_message: '^!test'

Rule examples

Chat-addable generic text-respond-commands

  # Respond with variable content if set
  - actions:
    - respond: '{{ variable (concat ":" "genericcmd" .channel (group 1)) }}'
    disable_on_template: '{{ eq (variable (concat ":" "genericcmd" .channel (group 1))) "" }}'
    match_channels: ['#mychannel']
    match_message: '^!([^\s]+)(?: |$)'

  # Set variable content to content of chat command
  - actions:
    - variable: '{{ concat ":" "genericcmd" .channel (group 1) }}'
      set: '{{ group 2 }}'
    - respond: '[Admin] Set command !{{ group 1 }} to "{{ group 2 }}"'
    enable_on: [broadcaster, moderator]
    match_channels: ['#mychannel']
    match_message: '^!setcmd ([^\s]+) (.*)'

  # Remove variable and therefore delete command
  - actions:
    - variable: '{{ concat ":" "genericcmd" .channel (group 1) }}'
      clear: true
    - respond: '[Admin] Deleted command !{{ group 1 }}'
    enable_on: [broadcaster, moderator]
    match_channels: ['#mychannel']
    match_message: '^!clearcmd ([^\s]+)'

Game death counter with dynamic name

  - actions:
    - counter: '{{ channelCounter (recentGame .channel) }}'
    - respond: >-
        I already died {{ counterValue (channelCounter (recentGame .channel)) }}
        times in {{ recentGame .channel }}'        
    cooldown: 60s
    enable_on: [broadcaster, moderator]
    match_channels: ['#mychannel']
    match_message: '^!death'
  - actions:
    - timeout: 1s
    - respond: '@{{ .username }}, please ask for permission before posting links.'
    disable_on: [broadcaster, moderator, subscriber, vip]
    disable_on_match_messages:
      - '^(?:https?://)?clips\.twitch\.tv/[a-zA-Z0-9-]+$'
    disable_on_permit: true
    match_channels: ['#mychannel']
    match_message: '(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]'

Post follow date for an user

  - actions:
    - respond: 'You followed on {{ ( followDate .username ( fixUsername .channel ) ).Format "2006-01-02" }}'
    match_channels: ['#mychannel']
    match_message: '^!followage'

Respond to a message after random delay

  - actions:
    # Respond after 30-40s
    - delay: 30s
      delay_jitter: 10s
    - respond: 'Hey {{ .username }}'
    match_channels: ['#mychannel']
    match_message: '^Hi'

Send a notification on successful permit

  - actions:
    - respond: >-
        @{{ fixUsername (arg 1) }}, you will not get timed out
        for the next {{ .permitTimeout }} seconds.        
    match_channels: ['#mychannel']
    match_event: 'permit'

Shoutout command with game query

  - actions:
    - respond: >-
        Check out @{{ fixUsername (group 1) }} and leave a follow,
        they were last playing {{ recentGame (fixUsername (group 1)) "something mysterious" }}
        at https://twitch.tv/{{ fixUsername (group 1) }}        
    enable_on: [broadcaster, moderator]
    match_channels: ['#mychannel']
    match_message: '^!so ([@\w]+)'