[editor] Add shoutout_created to frontend-known events

Signed-off-by: Knut Ahlers <knut@ahlers.me>
Knut Ahlers 2023-08-14 01:18:45 +02:00
commit 7de61cec28
5 changed files with 1513 additions and 0 deletions

486
Actors.md Normal file

@ -0,0 +1,486 @@
# Available Actions
## Add Fields to Event
Add custom fields to the event to be used as template variables later on
```yaml
- type: eventmod
attributes:
# Fields to set in the event (must produce valid JSON: `map[string]any`)
# Optional: false
# Type: string (Supports Templating)
fields: ""
```
## Add VIP
Add VIP for the given channel
```yaml
- type: vip
attributes:
# Channel to add the VIP to
# Optional: false
# Type: string (Supports Templating)
channel: ""
# User to add as VIP
# Optional: false
# Type: string (Supports Templating)
user: ""
```
## Ban User
Ban user from chat
```yaml
- type: ban
attributes:
# Reason why the user was banned
# Optional: false
# Type: string (Supports Templating)
reason: ""
```
## Commercial
Start Commercial
```yaml
- type: commercial
attributes:
# Duration of the commercial (must not be longer than 180s and must yield an integer)
# Optional: false
# Type: string (Supports Templating)
duration: ""
```
## Custom Event
Create a custom event
```yaml
- type: customevent
attributes:
# JSON representation of fields in the event (`map[string]any`)
# Optional: false
# Type: string (Supports Templating)
fields: "{}"
# Time until the event is triggered (must be valid duration like 1h, 1h1m, 10s, ...)
# Optional: true
# Type: string (Supports Templating)
schedule_in: ""
```
## Delay
Delay next action
```yaml
- type: delay
attributes:
# Static delay to wait
# Optional: true
# Type: duration
delay: 0s
# Dynamic jitter to add to the static delay (the added extra delay will be between 0 and this value)
# Optional: true
# Type: duration
jitter: 0s
```
## Delete Message
Delete message which caused the rule to be executed
```yaml
- type: delete
# Does not have configuration attributes
```
## Enforce Link-Protection
Uses link- and clip-scanner to detect links / clips and applies link protection as defined
```yaml
- type: linkprotect
attributes:
# Allowed links (if any is specified all non matching links will cause enforcement action, link must contain any of these strings)
# Optional: true
# Type: array of strings
allowed_links: []
# Disallowed links (if any is specified all non matching links will not cause enforcement action, link must contain any of these strings)
# Optional: true
# Type: array of strings
disallowed_links: []
# Allowed clip channels (if any is specified clips of all other channels will cause enforcement action, clip-links will be ignored in link-protection when this is used)
# Optional: true
# Type: array of strings
allowed_clip_channels: []
# Disallowed clip channels (if any is specified clips of all other channels will not cause enforcement action, clip-links will be ignored in link-protection when this is used)
# Optional: true
# Type: array of strings
disallowed_clip_channels: []
# Enforcement action to take when disallowed link / clip is detected (ban, delete, duration-value i.e. 1m)
# Optional: false
# Type: string
action: ""
# Reason why the enforcement action was taken
# Optional: false
# Type: string
reason: ""
# Stop rule execution when action is applied (i.e. not to post a message after a ban for spam links)
# Optional: true
# Type: bool
stop_on_action: false
# Stop rule execution when no action is applied (i.e. not to post a message when no enforcement action is taken)
# Optional: true
# Type: bool
stop_on_no_action: false
```
## Execute Script / Command
Execute external script / command
```yaml
- type: script
attributes:
# Command to execute
# Optional: false
# Type: array of strings (Supports Templating in each string)
command: []
# Do not activate cooldown for route when command exits non-zero
# Optional: true
# Type: bool
skip_cooldown_on_error: false
```
## FileSay
Takes the content of an URL and pastes it to the current channel
```yaml
- type: filesay
attributes:
# Source of the content to post
# Optional: false
# Type: string (Supports Templating)
source: ""
```
## Log output
Print info log-line to bot log
```yaml
- type: log
attributes:
# Messsage to log into bot-log
# Optional: false
# Type: string (Supports Templating)
message: ""
```
## Modify Counter
Update counter values
```yaml
- type: counter
attributes:
# Name of the counter to update
# Optional: false
# Type: string (Supports Templating)
counter: ""
# Value to add to the counter
# Optional: true
# Type: string (Supports Templating)
counter_step: "1"
# Value to set the counter to
# Optional: true
# Type: string (Supports Templating)
counter_set: ""
```
## Modify Stream
Update stream information
```yaml
- type: modchannel
attributes:
# Channel to update
# Optional: false
# Type: string (Supports Templating)
channel: ""
# Category / Game to set (use `@1234` format to pass an explicit ID)
# Optional: true
# Type: string (Supports Templating)
game: ""
# Stream title to set
# Optional: true
# Type: string (Supports Templating)
title: ""
```
## Modify Variable
Modify variable contents
```yaml
- type: setvariable
attributes:
# Name of the variable to update
# Optional: false
# Type: string (Supports Templating)
variable: ""
# Clear variable content and unset the variable
# Optional: true
# Type: bool
clear: false
# Value to set the variable to
# Optional: true
# Type: string (Supports Templating)
set: ""
```
## Nuke Chat
Mass ban, delete, or timeout messages based on regex. Be sure you REALLY know what you do before using this! Used wrongly this will cause a lot of damage!
```yaml
- type: nuke
attributes:
# How long to scan into the past, template must yield a duration (max 10m)
# Optional: true
# Type: string (Supports Templating)
scan: "10m"
# What action to take when message matches (delete / ban / <timeout duration>)
# Optional: true
# Type: string (Supports Templating)
action: "delete"
# Regular expression (RE2) to select matching messages
# Optional: false
# Type: string (Supports Templating)
match: ""
```
## Punish User
Apply increasing punishments to user
```yaml
- type: punish
attributes:
# When to lower the punishment level after the last punishment
# Optional: true
# Type: duration
cooldown: 168h
# Actions for each punishment level (ban, delete, duration-value i.e. 1m)
# Optional: false
# Type: array of strings
levels: []
# Reason why the user was banned / timeouted
# Optional: true
# Type: string
reason: ""
# User to apply the action to
# Optional: false
# Type: string (Supports Templating)
user: ""
# Unique identifier for this punishment to differentiate between punishments in the same channel
# Optional: true
# Type: string
uuid: ""
```
## Quote Database
Manage a database of quotes in your channel
```yaml
- type: quotedb
attributes:
# Action to execute (one of: add, del, get)
# Optional: false
# Type: string
action: ""
# Index of the quote to work with, must yield a number (required on 'del', optional on 'get')
# Optional: true
# Type: string (Supports Templating)
index: "0"
# Quote to add: Format like you like your quote, nothing is added (required on: add)
# Optional: true
# Type: string (Supports Templating)
quote: ""
# Format to use when posting a quote (required on: get)
# Optional: true
# Type: string (Supports Templating)
format: "Quote #{{ .index }}: {{ .quote }}"
```
## Remove VIP
Remove VIP for the given channel
```yaml
- type: unvip
attributes:
# Channel to remove the VIP from
# Optional: false
# Type: string (Supports Templating)
channel: ""
# User to remove as VIP
# Optional: false
# Type: string (Supports Templating)
user: ""
```
## Reset User Punishment
Reset punishment level for user
```yaml
- type: reset-punish
attributes:
# User to reset the level for
# Optional: false
# Type: string (Supports Templating)
user: ""
# Unique identifier for this punishment to differentiate between punishments in the same channel
# Optional: true
# Type: string
uuid: ""
```
## Respond to Message
Respond to message with a new message
```yaml
- type: respond
attributes:
# Message text to send
# Optional: false
# Type: string (Supports Templating)
message: ""
# Fallback message text to send if message cannot be generated
# Optional: true
# Type: string (Supports Templating)
fallback: ""
# Send message as a native Twitch-reply to the original message
# Optional: true
# Type: bool
as_reply: false
# Send message to a different channel than the original message
# Optional: true
# Type: string
to_channel: ""
```
## Scan for Clips
Scans for clip-links in the message and adds the "clips" field to the event data
```yaml
- type: clipdetector
# Does not have configuration attributes
```
## Scan for Links
Scans for links in the message and adds the "links" field to the event data
```yaml
- type: linkdetector
# Does not have configuration attributes
```
## Send RAW Message
Send raw IRC message
```yaml
- type: raw
attributes:
# Raw message to send (must be a valid IRC protocol message)
# Optional: false
# Type: string (Supports Templating)
message: ""
```
## Send Whisper
Send a whisper (requires a verified bot!)
```yaml
- type: whisper
attributes:
# Message to whisper to the user
# Optional: false
# Type: string (Supports Templating)
message: ""
# User to send the message to
# Optional: false
# Type: string (Supports Templating)
to: ""
```
## Shoutout
Perform a Twitch-native shoutout
```yaml
- type: shoutout
attributes:
# User to give the shoutout to
# Optional: false
# Type: string (Supports Templating)
user: ""
```
## Stop Execution
Stop Rule Execution on Condition
```yaml
- type: stopexec
attributes:
# Condition when to stop execution (must evaluate to "true" to stop execution)
# Optional: false
# Type: string (Supports Templating)
when: ""
```
## Timeout User
Timeout user from chat
```yaml
- type: timeout
attributes:
# Duration of the timeout
# Optional: false
# Type: duration
duration: 0s
# Reason why the user was timed out
# Optional: false
# Type: string (Supports Templating)
reason: ""
```
## Update Shield Mode
Update shield mode for the given channel
```yaml
- type: shield
attributes:
# Whether the shield-mode should be enabled or disabled
# Optional: false
# Type: bool
enable: false
```

281
Events.md Normal file

@ -0,0 +1,281 @@
# Available Events
## `ban`
Moderator action caused a user to be banned from chat.
Note: This event does **not** contain the acting user! You cannot use the `{{.user}}` variable.
Fields:
- `channel` - The channel the event occurred in
- `target_id` - The ID of the user being banned
- `target_name` - The login-name of the user being banned
## `bits`
User spent bits in the channel. The full message is available like in a normal chat message, additionally the `{{ .bits }}` field is added with the total amount of bits spent.
Fields:
- `bits` - Total amount of bits spent in the message
- `channel` - The channel the event occurred in
- `username` - The login-name of the user who spent the bits
## `category_update`
The current category for the channel was changed. (This event has some delay to the real category change!)
Fields:
- `category` - The name of the new game / category
- `channel` - The channel the event occurred in
## `channelpoint_redeem`
A custom channel-point reward was redeemed in the given channel. (Only available when EventSub support is available and streamer granted required permissions!)
Fields:
- `channel` - The channel the event occurred in
- `reward_cost` - Number of points the user paid for the reward
- `reward_id` - ID of the reward the user redeemed
- `reward_title` - Title of the reward the user redeemed
- `status` - Status of the reward (one of `unknown`, `unfulfilled`, `fulfilled`, and `canceled`)
- `user_id` - The ID of the user who redeemed the reward
- `user_input` - The text the user entered into the input for the reward
- `user` - The login-name of the user who redeemed the reward
## `clearchat`
Moderator action caused chat to be cleared.
Note: This event does **not** contain the acting user! You cannot use the `{{.user}}` variable.
Fields:
- `channel` - The channel the event occurred in
## `delete`
Moderator action caused a chat message to be deleted.
Note: This event does **not** contain the acting user! You cannot use the `{{.user}}` variable.
Fields:
- `channel` - The channel the event occurred in
- `message_id` - The UUID of the message being deleted
- `target_name` - Login name of the author of the deleted message
## `follow`
User followed the channel. This event is not de-duplicated and therefore might be used to spam! (Only available when EventSub support is available!)
Fields:
- `channel` - The channel the event occurred in
- `followed_at` - Time object of the follow date
- `user_id` - ID of the newly following user
- `user` - The login-name of the user who followed
## `giftpaidupgrade`
User upgraded their gifted subscription into a paid one. This event does not contain any details about the tier of the paid subscription.
Fields:
- `channel` - The channel the event occurred in
- `gifter` - The login-name of the user who gifted the subscription
- `username` - The login-name of the user who upgraded their subscription
## `hype_chat`
User used the Twitch "Hype Chat" to pin a message to the chat.
Fields:
- `amount` - Amount of money the user spent (float64, i.e. `1.2` when they used 1.20 EUR)
- `channel` - The channel the event occurred in
- `currency` - [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217#List_of_ISO_4217_currency_codes) alphabetic currency code
- `is_system_message` - Set to `true` if the user left no message and the message was system-generated
- `level` - `ONE` to `TEN`, uppercase number-words
- `messge` - The message the user sent (or the system generated)
- `user_id` - ID of the user
- `user` - The login-name of the user who sent the message
## `join`
User joined the channel-chat. This is **NOT** an indicator they are viewing, the event is **NOT** reliably sent when the user really joined the chat. The event will be sent with some delay after they join the chat and is sometimes repeated multiple times during their stay. So **DO NOT** use this to greet users!
Fields:
- `channel` - The channel the event occurred in
- `user` - The login-name of the user who joined
## `outbound_raid`
The channel has raided another channel. (The event is issued in the moment the raid is executed, not when the raid timer starts!)
Fields:
- `channel` - The channel the raid originated at
- `to` - The login-name of the channel the viewers are sent to
- `to_id` - The ID of the channel the viewers are sent to
- `viewers` - The number of viewers included in the raid
## `part`
User left the channel-chat. This is **NOT** an indicator they are no longer viewing, the event is **NOT** reliably sent when the user really leaves the chat. The event will be sent with some delay after they leave the chat and is sometimes repeated multiple times during their stay. So this does **NOT** mean they do no longer read the chat!
Fields:
- `channel` - The channel the event occurred in
- `user` - The login-name of the user who left
## `permit`
User received a permit, which means they are no longer affected by rules which are disabled on permit.
Fields:
- `channel` - The channel the event occurred in
- `user` - The login-name of the user who **gave** the permit
- `to` - The username who got the permit
## `poll_begin` / `poll_end` / `poll_progress`
A poll was started / was ended / had changes in the given channel.
Fields:
- `channel` - The channel the event occurred in
- `poll` - The poll object describing the poll, see schema in [`pkg/twitch/eventsub.go#L92`](https://github.com/Luzifer/twitch-bot/blob/master/pkg/twitch/eventsub.go#L92)
- `status` - The status of the poll (one of `completed`, `terminated` or `archived`) - only available in `poll_end`
- `title` - The title of the poll the event was generated for
## `raid`
The channel was raided by another user.
Fields:
- `channel` - The channel the event occurred in
- `username` - The login-name of the user who raided the channel
- `viewercount` - The amount of users who have been raided (this number is not fully accurate)
## `resub`
The user shared their resubscription. (This event is triggered manually by the user using the "Share my Resub" button and does not occur when the user does not actively share their sub!)
Fields:
- `channel` - The channel the event occurred in
- `plan` - The sub-plan they are using (`1000` = T1, `2000` = T2, `3000` = T3, `Prime`)
- `subscribed_months` - How long have they been subscribed
- `username` - The login-name of the user who resubscribed
## `shoutout_created`
The channel gave another streamer a (Twitch native) shoutout
Fields:
- `channel` - The channel the event occurred in
- `to_id` - The ID of the channel who received the shoutout
- `to` - The login-name of the channel who received the shoutout
- `viewers` - The amount of viewers the shoutout was shown to
## `shoutout_received`
The channel received a (Twitch native) shoutout by another channel.
Fields:
- `channel` - The channel the event occurred in
- `from_id` - The ID of the channel who issued the shoutout
- `from` - The login-name of the channel who issued the shoutout
- `viewers` - The amount of viewers the shoutout was shown to
## `stream_offline`
The channels stream went offline. (This event has some delay to the real category change!)
Fields:
- `channel` - The channel the event occurred in
## `stream_online`
The channels stream went offline. (This event has some delay to the real category change!)
Fields:
- `channel` - The channel the event occurred in
## `sub`
The user newly subscribed on their own. (This event is triggered automatically and does not need to be shared actively!)
Fields:
- `channel` - The channel the event occurred in
- `plan` - The sub-plan they are using (`1000` = T1, `2000` = T2, `3000` = T3, `Prime`)
- `username` - The login-name of the user who subscribed
## `subgift`
The user gifted the subscription to a specific user. (This event **DOES** occur multiple times after `submysterygift` events!)
Fields:
- `channel` - The channel the event occurred in
- `gifted_months` - Number of months the user gifted
- `origin_id` - ID unique to the gift-event (can be used to match `subgift` events to corresponding `submysterygift` event)
- `plan` - The sub-plan they are using (`1000` = T1, `2000` = T2, `3000` = T3, `Prime`)
- `subscribed_months` - How long the recipient has been subscribed
- `to` - The user who received the sub
- `username` - The login-name of the user who gifted the subscription
## `submysterygift`
The user gifted multiple subs to the community. (This event is followed by `number x subgift` events.)
Fields:
- `channel` - The channel the event occurred in
- `number` - The amount of gifted subs
- `origin_id` - ID unique to the gift-event (can be used to match `subgift` events to corresponding `submysterygift` event)
- `plan` - The sub-plan they are using (`1000` = T1, `2000` = T2, `3000` = T3, `Prime`)
- `username` - The login-name of the user who gifted the subscription
## `timeout`
Moderator action caused a user to be timed out from chat.
Note: This event does **not** contain the acting user! You cannot use the `{{.user}}` variable.
Fields:
- `channel` - The channel the event occurred in
- `duration` - The timeout duration (`time.Duration`, nanoseconds)
- `seconds` - The timeout duration (`int`, seconds)
- `target_id` - The ID of the user being timed out
- `target_name` - The login-name of the user being timed out
## `title_update`
The current title for the channel was changed. (This event has some delay to the real category change!)
Fields:
- `channel` - The channel the event occurred in
- `title` - The title of the stream
## `whisper`
The bot received a whisper message. (You can use `(.*)` as message match and `{{ group 1 }}` as template to get the content of the whisper.)
Fields:
- `username` - The login-name of the user who sent the message

132
Examples.md Normal file

@ -0,0 +1,132 @@
# Rule examples
## Chat-addable generic text-respond-commands
```yaml
# Respond with variable content if set
- actions:
- type: respond
attributes:
message: '{{ variable (list "genericcmd" .channel (group 1) | join ":") }}'
disable_on_template: '{{ eq (variable (list "genericcmd" .channel (group 1) | joih ":")) "" }}'
match_channels: ['#mychannel']
match_message: '^!([^\s]+)(?: |$)'
# Set variable content to content of chat command
- actions:
- type: setvariable
attributes:
variable: '{{ list "genericcmd" .channel (group 1) | join ":" }}'
set: '{{ group 2 }}'
- type: respond
attributes:
message: '[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:
- type: setvariable
attributes:
variable: '{{ list "genericcmd" .channel (group 1) | join ":" }}'
clear: true
- type: respond
attributes:
message: '[Admin] Deleted command !{{ group 1 }}'
enable_on: [broadcaster, moderator]
match_channels: ['#mychannel']
match_message: '^!clearcmd ([^\s]+)'
```
## Game death counter with dynamic name
```yaml
- actions:
- type: counter
attributes:
counter: '{{ channelCounter (recentGame .channel) }}'
- type: respond
attributes:
message: >-
I already died {{ counterValue (channelCounter (recentGame .channel)) }}
times in {{ recentGame .channel }}'
cooldown: 60s
enable_on: [broadcaster, moderator]
match_channels: ['#mychannel']
match_message: '^!death'
```
## Link-protection while allowing Twitch clips
```yaml
- actions:
- type: timeout
attributes:
duration: 1s
- type: respond
attributes:
message: '@{{ .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
```yaml
- actions:
- type: respond
attributes:
message: 'You followed on {{ ( followDate .username ( fixUsername .channel ) ).Format "2006-01-02" }}'
match_channels: ['#mychannel']
match_message: '^!followage'
```
## Respond to a message after random delay
```yaml
- actions:
# Respond after 30-40s
- type: delay
attributes:
delay: 30s
jitter: 10s
- type: respond
attributes:
message: 'Hey {{ .username }}'
match_channels: ['#mychannel']
match_message: '^Hi'
```
## Send a notification on successful permit
```yaml
- actions:
- type: respond
attributes:
message: >-
@{{ 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
```yaml
- actions:
- type: respond
attributes:
message: >-
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]+)'
```

187
Home.md Normal file

@ -0,0 +1,187 @@
## Configuration
```yaml
---
# This must be the config version you've used below. Current version
# is version 2 so probably keep it at 2 until the bot tells you to
# upgrade.
config_version: 2
# List of tokens allowed to access the HTTP API with write access.
# You can generate a token using the web-based config-editor or the
# `api-token` sub-command:
# $ twitch-bot api-token 'mytoken' '*'
# The token will only be printed ONCE and cannot be retrieved afterards.
auth_tokens:
89196495-68eb-4f50-94f0-5c5d99f26be5:
hash: '243261[...]36532e'
modules:
- '*'
name: mytoken
# List of strings: Either Twitch user-ids or nicknames (best to stick
# with IDs as they can't change while nicknames can be changed every
# 60 days). Those users are able to use the config editor web-interface.
bot_editors: []
# List of channels to join. Channels not listed here will not be
# joined and therefore cannot be actioned on.
channels:
- mychannel
# The bot is able to track config changes made through the config-editor
# web-interface using Git (https://git-scm.com/). To use this feature
# create a Git repository in the folder the config is placed: `git init`
#
# Afterwards switch this option to `true` and you're good to go: Each
# change made by the editor causes a Git commit with the logged in user
# as author of the commit.
git_track_config: false
# Enable HTTP server to control plugins / core functionality
# if unset the server is not started, to change the bot must be restarted
http_listen: "127.0.0.1:3000"
# 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"
# List of auto-messages. See documentation for details or use
# web-interface to configure.
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
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 }}'
# List of rules. See documentation for details or use web-interface
# to configure.
rules: # See below for examples
- actions: # Array of actions to take when this rule matches
# See the Actors page in the Wiki for available actors:
# https://github.com/Luzifer/twitch-bot/wiki/Actors
- type: "<actor type>"
attributes:
key: value
# 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
# See the Events page in the Wiki for available events and field documentation
# https://github.com/Luzifer/twitch-bot/wiki/Events
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: []
...
```
## 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`:
```json
{
"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:
```yaml
- actions:
- type: script
attributes:
command: [/usr/bin/bash, -c, "jq . >&2"]
match_channels: ['#tezrian']
match_message: '^!test'
```

427
Templating.md Normal file

@ -0,0 +1,427 @@
## Templating
Generally speaking the templating uses [Golang `text/template`](https://pkg.go.dev/text/template) template syntax. All fields with templating enabled do support the full synax from the `text/template` package.
### Variables
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
### Functions
Within templates following functions can be used:
- built-in functions in `text/template` engine
- functions from [sprig](https://masterminds.github.io/sprig/) function collection
- functions mentioned below
Examples below are using this syntax in the code block:
```
! Message matcher used for the input message
> Input message if used in the example
# Template used in the fields
< Output from the template
```
#### `arg`
Takes the message sent to the channel, splits by space and returns the Nth element
Syntax: `arg <index>`
Example:
```
> !bsg @tester
# {{ arg 1 }} please refrain from BSG
< @tester please refrain from BSG
```
#### `botHasBadge`
Checks whether bot has the given badge in the current channel
Syntax: `botHasBadge <badge>`
Example:
```
# {{ botHasBadge "moderator" }}
< true
```
#### `channelCounter`
Wraps the counter name into a channel specific counter name including the channel name
Syntax: `channelCounter <counter name>`
Example:
```
# {{ channelCounter "test" }}
< 5
```
#### `counterValue`
Returns the current value of the counter which identifier was supplied
Syntax: `counterValue <counter name>`
Example:
```
# {{ counterValue (list .channel "test" | join ":") }}
< 5
```
#### `counterValueAdd`
Adds the given value (or 1 if no value) to the counter and returns its new value
Syntax: `counterValueAdd <counter name> [increase=1]`
Example:
```
# {{ counterValueAdd "myCounter" }} {{ counterValueAdd "myCounter" 5 }}
< 1 6
```
#### `displayName`
Returns the display name the specified user set for themselves
Syntax: `displayName <username> [fallback]`
Example:
```
# {{ displayName "luziferus" }} - {{ displayName "notexistinguser" "foobar" }}
< Luziferus - foobar
```
#### `doesFollow`
Returns whether `from` follows `to`
Syntax: `doesFollow <from> <to>`
Example:
```
# {{ doesFollow "tezrian" "luziferus" }}
< true
```
#### `doesFollowLongerThan`
Returns whether `from` follows `to` for more than `duration`
Syntax: `doesFollowLongerThan <from> <to> <duration>`
Example:
```
# {{ doesFollowLongerThan "tezrian" "luziferus" "168h" }}
< true
```
#### `fixUsername`
Ensures the username no longer contains the `@` or `#` prefix
Syntax: `fixUsername <username>`
Example:
```
# {{ fixUsername .channel }} - {{ fixUsername "@luziferus" }}
< luziferus - luziferus
```
#### `formatDuration`
Returns a formated duration. Pass empty strings to leave out the specific duration part.
Syntax: `formatDuration <duration> <hours> <minutes> <seconds>`
Example:
```
# {{ formatDuration (streamUptime .channel) "hours" "minutes" "seconds" }} - {{ formatDuration (streamUptime .channel) "hours" "minutes" "" }}
< 5 hours, 33 minutes, 12 seconds - 5 hours, 33 minutes
```
#### `followAge`
Looks up when `from` followed `to` and returns the duration between then and now
Syntax: `followAge <from> <to>`
Example:
```
# {{ followAge "tezrian" "luziferus" }}
< 15004h14m59.116620989s
```
#### `followDate`
Looks up when `from` followed `to`
Syntax: `followDate <from> <to>`
Example:
```
# {{ followDate "tezrian" "luziferus" }}
< 2021-04-10 16:07:07 +0000 UTC
```
#### `group`
Gets matching group specified by index from `match_message` regular expression, when `fallback` is defined, it is used when group has an empty match
Syntax: `group <idx> [fallback]`
Example:
```
! !command ([0-9]+) ([a-z]+) ([a-z]*)
> !command 12 test
# {{ group 2 "oops" }} - {{ group 3 "oops" }}
< test - oops
```
#### `inList`
Tests whether a string is in a given list of strings (for conditional templates).
Syntax: `inList "search" "item1" "item2" [...]`
Example:
```
! !command (.*)
> !command foo
# {{ inList (group 1) "foo" "bar" }}
< true
```
#### `jsonAPI`
Fetches remote URL and applies jq-like query to it returning the result as string. (Remote API needs to return status 200 within 5 seconds.)
Syntax: `jsonAPI "https://example.com/doc.json" ".data.exampleString" ["fallback"]`
Example:
```
! !mycmd
> !mycmd
# {{ jsonAPI "https://example.com/doc.json" ".data.exampleString" }}
< example string
```
#### `lastPoll`
Gets the last (currently running or archived) poll for the given channel (the channel must have given extended permission for poll access!)
Syntax: `lastPoll <channel>`
Example:
```
# Last Poll: {{ (lastPoll .channel).Title }}
< Last Poll: Und wie siehts im Template aus?
```
See schema of returned object in [`pkg/twitch/polls.go#L13`](https://github.com/Luzifer/twitch-bot/blob/master/pkg/twitch/polls.go#L13)
#### `lastQuoteIndex`
Gets the last quote index in the quote database for the current channel
Syntax: `lastQuoteIndex`
Example:
```
# Last Quote: #{{ lastQuoteIndex }}
< Last Quote: #32
```
#### `mention`
Strips username and converts into a mention
Syntax: `mention <username>`
Example:
```
# {{ mention "@user" }} {{ mention "user" }} {{ mention "#user" }}
< @user @user @user
```
#### `pow`
Returns float from calculation: `float1 ** float2`
Syntax: `pow <float1> <float2>`
Example:
```
# {{ printf "%.0f" (pow 10 4) }}%
< 10000
```
#### `randomString`
Randomly picks a string from a list of strings
Syntax: `randomString "a" [...]`
Example:
```
# {{ randomString "a" "b" "c" "d" }}
< a
```
#### `recentGame`
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.
Syntax: `recentGame <username> [fallback]`
Example:
```
# {{ recentGame "luziferus" "none" }} - {{ recentGame "thisuserdoesnotexist123" "none" }}
< Metro Exodus - none
```
#### `recentTitle`
Returns the last stream title of the specified user or the `fallback` if the title could not be fetched. If no fallback was supplied the message will fail and not be sent.
Syntax: `recentTitle <username> [fallback]`
Example:
```
# {{ recentGame "luziferus" "none" }} - {{ recentGame "thisuserdoesnotexist123" "none" }}
< Die Oper haben wir überlebt, mal sehen was uns sonst noch alles töten möchte - none
```
#### `seededRandom`
Returns a float value stable for the given seed
Syntax: `seededRandom <string-seed>`
Example:
```
# Your int this hour: {{ printf "%.0f" (mul (seededRandom (list "int" .username (now | date "2006-01-02 15") | join ":")) 100) }}%
< Your int this hour: 17%
```
#### `streamUptime`
Returns the duration the stream is online (causes an error if no current stream is found)
Syntax: `streamUptime <username>`
Example:
```
# {{ formatDuration (streamUptime "luziferus") "hours" "minutes" "" }}
< 3 hours, 56 minutes
```
#### `subCount`
Returns the number of subscribers (accounts) currently subscribed to the given channel
Syntax: `subCount <channel>`
Example:
```
# {{ subCount "luziferus" }}
< 26
```
#### `subPoints`
Returns the number of sub-points currently given through the T1 / T2 / T3 subscriptions to the given channel
Syntax: `subPoints <channel>`
Example:
```
# {{ subPoints "luziferus" }}
< 26
```
#### `tag`
Takes the message sent to the channel, returns the value of the tag specified
Syntax: `tag <tagname>`
Example:
```
# {{ tag "login" }}
< luziferus
```
#### `textAPI`
Fetches remote URL and returns the result as string. (Remote API needs to return status 200 within 5 seconds.)
Syntax: `textAPI "https://example.com/" ["fallback"]`
Example:
```
! !weather (.*)
> !weather Hamburg
# {{ textAPI (printf "https://api.scorpstuff.com/weather.php?units=metric&city=%s" (urlquery (group 1))) }}
< Weather for Hamburg, DE: Few clouds with a temperature of 22 C (71.6 F). [...]
```
#### `variable`
Returns the variable value or default in case it is empty
Syntax: `variable <name> [default]`
Example:
```
# {{ variable "foo" "fallback" }} - {{ variable "unsetvar" "fallback" }}
< test - fallback
```
### Upgrade from `v2.x` to `v3.x`
When adding [sprig](https://masterminds.github.io/sprig/) function collection some functions collided and needed replacement. You need to adapt your templates accordingly:
- Math functions (`add`, `div`, `mod`, `mul`, `multiply`, `sub`) were replaced with their sprig-equivalent and are now working with integers instead of floats. If you need them to continue to work with floats you need to use their [float-variants](https://masterminds.github.io/sprig/mathf.html).
- `now` does no longer format the current date as a string but return the current date. You need to replace this: `now "2006-01-02"` becomes `now | date "2006-01-02"`.
- `concat` is now used to concat arrays. To join strings you will need to modify your code: `concat ":" "string1" "string2"` becomes `lists "string1" "string2" | join ":"`.
- `toLower` / `toUpper` need to be replaced with their sprig equivalent `lower` and `upper`.