Add scripting (tengo) support for every outgoing message (#806)
Adds a new key OutMessage under [tengo] table, which specifies the location of the script that will be invoked on each message being sent to a bridge and can be used to modify the Username and the Text of that message. The script will have the following global variables: read-only: inAccount, inProtocol, inChannel, inGateway outAccount, outProtocol, outChannel, outGateway read-write: msgText, msgUsername The script is reloaded on every message, so you can modify the script on the fly. The default script in https://github.com/42wim/matterbridge/tree/master/internal/tengo/outmessage.tengo is compiled in and will be executed if no script is specified.
This commit is contained in:
parent
d60468bb05
commit
2d277a15f5
@ -168,8 +168,10 @@ type Gateway struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Tengo struct {
|
type Tengo struct {
|
||||||
|
InMessage string
|
||||||
Message string
|
Message string
|
||||||
RemoteNickFormat string
|
RemoteNickFormat string
|
||||||
|
OutMessage string
|
||||||
}
|
}
|
||||||
|
|
||||||
type SameChannelGateway struct {
|
type SameChannelGateway struct {
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -182,10 +181,6 @@ func (b *Birc) handlePrivMsg(client *girc.Client, event girc.Event) {
|
|||||||
// strip action, we made an event if it was an action
|
// strip action, we made an event if it was an action
|
||||||
rmsg.Text += event.StripAction()
|
rmsg.Text += event.StripAction()
|
||||||
|
|
||||||
// strip IRC colors
|
|
||||||
re := regexp.MustCompile(`\x03(?:\d{1,2}(?:,\d{1,2})?)?|[[:cntrl:]]`)
|
|
||||||
rmsg.Text = re.ReplaceAllString(rmsg.Text, "")
|
|
||||||
|
|
||||||
// start detecting the charset
|
// start detecting the charset
|
||||||
mycharset := b.GetString("Charset")
|
mycharset := b.GetString("Charset")
|
||||||
if mycharset == "" {
|
if mycharset == "" {
|
||||||
|
7
contrib/outmessage-irccolors.tengo
Normal file
7
contrib/outmessage-irccolors.tengo
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// See https://github.com/42wim/matterbridge/issues/798
|
||||||
|
|
||||||
|
// if we're not sending to an irc bridge we strip the IRC colors
|
||||||
|
if outProtocol != "irc" {
|
||||||
|
re := text.re_compile(`\x03(?:\d{1,2}(?:,\d{1,2})?)?|[[:cntrl:]]`)
|
||||||
|
msgText=re.replace(msgText,"")
|
||||||
|
}
|
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/42wim/matterbridge/bridge"
|
"github.com/42wim/matterbridge/bridge"
|
||||||
"github.com/42wim/matterbridge/bridge/config"
|
"github.com/42wim/matterbridge/bridge/config"
|
||||||
|
"github.com/42wim/matterbridge/internal"
|
||||||
"github.com/d5/tengo/script"
|
"github.com/d5/tengo/script"
|
||||||
"github.com/d5/tengo/stdlib"
|
"github.com/d5/tengo/stdlib"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
@ -429,6 +430,11 @@ func (gw *Gateway) SendMessage(
|
|||||||
msg.ParentID = "msg-parent-not-found"
|
msg.ParentID = "msg-parent-not-found"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err := gw.modifySendMessageTengo(rmsg, &msg, dest)
|
||||||
|
if err != nil {
|
||||||
|
gw.logger.Errorf("modifySendMessageTengo: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
// if we are using mattermost plugin account, send messages to MattermostPlugin channel
|
// if we are using mattermost plugin account, send messages to MattermostPlugin channel
|
||||||
// that can be picked up by the mattermost matterbridge plugin
|
// that can be picked up by the mattermost matterbridge plugin
|
||||||
if dest.Account == "mattermost.plugin" {
|
if dest.Account == "mattermost.plugin" {
|
||||||
@ -544,3 +550,42 @@ func (gw *Gateway) modifyUsernameTengo(msg *config.Message, br *bridge.Bridge) (
|
|||||||
}
|
}
|
||||||
return c.Get("result").String(), nil
|
return c.Get("result").String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gw *Gateway) modifySendMessageTengo(origmsg *config.Message, msg *config.Message, br *bridge.Bridge) error {
|
||||||
|
filename := gw.BridgeValues().Tengo.OutMessage
|
||||||
|
var res []byte
|
||||||
|
var err error
|
||||||
|
if filename == "" {
|
||||||
|
res, err = internal.Asset("tengo/outmessage.tengo")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res, err = ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s := script.New(res)
|
||||||
|
s.SetImports(stdlib.GetModuleMap(stdlib.AllModuleNames()...))
|
||||||
|
_ = s.Add("inAccount", origmsg.Account)
|
||||||
|
_ = s.Add("inProtocol", origmsg.Protocol)
|
||||||
|
_ = s.Add("inChannel", origmsg.Channel)
|
||||||
|
_ = s.Add("inGateway", origmsg.Gateway)
|
||||||
|
_ = s.Add("outAccount", br.Account)
|
||||||
|
_ = s.Add("outProtocol", br.Protocol)
|
||||||
|
_ = s.Add("outChannel", msg.Channel)
|
||||||
|
_ = s.Add("outGateway", gw.Name)
|
||||||
|
_ = s.Add("msgText", msg.Text)
|
||||||
|
_ = s.Add("msgUsername", msg.Username)
|
||||||
|
c, err := s.Compile()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.Run(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
msg.Text = c.Get("msgText").String()
|
||||||
|
msg.Username = c.Get("msgUsername").String()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
288
internal/bindata.go
Normal file
288
internal/bindata.go
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
// Code generated by go-bindata. DO NOT EDIT.
|
||||||
|
// sources:
|
||||||
|
// tengo/outmessage.tengo
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func bindataRead(data []byte, name string) ([]byte, error) {
|
||||||
|
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_, err = io.Copy(&buf, gz)
|
||||||
|
clErr := gz.Close()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||||
|
}
|
||||||
|
if clErr != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type asset struct {
|
||||||
|
bytes []byte
|
||||||
|
info fileInfoEx
|
||||||
|
}
|
||||||
|
|
||||||
|
type fileInfoEx interface {
|
||||||
|
os.FileInfo
|
||||||
|
MD5Checksum() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type bindataFileInfo struct {
|
||||||
|
name string
|
||||||
|
size int64
|
||||||
|
mode os.FileMode
|
||||||
|
modTime time.Time
|
||||||
|
md5checksum string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi bindataFileInfo) Name() string {
|
||||||
|
return fi.name
|
||||||
|
}
|
||||||
|
func (fi bindataFileInfo) Size() int64 {
|
||||||
|
return fi.size
|
||||||
|
}
|
||||||
|
func (fi bindataFileInfo) Mode() os.FileMode {
|
||||||
|
return fi.mode
|
||||||
|
}
|
||||||
|
func (fi bindataFileInfo) ModTime() time.Time {
|
||||||
|
return fi.modTime
|
||||||
|
}
|
||||||
|
func (fi bindataFileInfo) MD5Checksum() string {
|
||||||
|
return fi.md5checksum
|
||||||
|
}
|
||||||
|
func (fi bindataFileInfo) IsDir() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func (fi bindataFileInfo) Sys() interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _bindataTengoOutmessagetengo = []byte(
|
||||||
|
"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x91\x3d\x8f\xda\x40\x10\x86\xfb\xfd\x15\x13\x37\xb1\x2d\x07\xe7\xa3" +
|
||||||
|
"\xb3\x64\x59\x11\x45\x94\x2e\x8a\x92\x0a\xd0\xb1\xac\x07\x33\xd2\x7a\xc7\x1a\x8f\x31\x88\xe3\xbf\x9f\xcc\x01\x47" +
|
||||||
|
"\x7f\xc5\x75\xef\xae\x9e\x9d\x77\x1f\x4d\x9e\x9a\xbd\x15\xb2\x1b\x8f\x3d\xd8\xbd\x25\x3f\x45\x30\x82\xb6\xfe\xc2" +
|
||||||
|
"\xc1\x1f\x0b\x43\xe1\xa7\x73\x3c\x04\xcd\x80\xc2\x1f\x61\x65\xc7\x7e\xca\xf3\x9d\x0d\x01\x2f\xf1\x97\x55\x1c\xed" +
|
||||||
|
"\xd1\xf0\xa0\x77\x98\x07\x7d\xa3\x79\xd0\x3b\xce\x83\xde\xf8\xd7\x9e\x51\x48\xb1\x30\x6d\xdf\xfc\xc3\x83\x66\xd0" +
|
||||||
|
"\xf6\xcd\xff\x1e\x25\xd8\x16\x4d\x9a\x1b\xa3\x78\x50\x28\x4a\xa0\xb6\x63\xd1\x38\x9a\xce\x51\x62\x4c\x9e\x43\xaf" +
|
||||||
|
"\x42\x1d\x90\x38\x70\xec\x59\xfa\xe9\x8e\xb6\x30\xe2\x67\x41\x08\xac\xd0\x63\xa8\x29\x34\xa0\x0c\x36\x5c\xc0\x8d" +
|
||||||
|
"\x50\xdd\x20\x8c\x78\x7d\xac\x3b\x84\xdf\x7f\xe7\xb7\x01\xb4\x7d\xd0\x84\xb2\x84\x88\xc4\x45\x70\x32\x00\x00\x82" +
|
||||||
|
"\xd3\x3f\xa6\xfe\x99\xe0\x93\xe3\xb6\x23\x8f\xf1\x7a\x79\xf8\xfa\x23\xae\x8a\x65\x7d\xfa\x96\x7d\x3f\xc7\x55\x91" +
|
||||||
|
"\x5d\x63\x52\x25\xd5\xf3\x62\x51\xb8\xa0\xe2\x8b\xd5\x6a\x9d\x5c\xc6\x5c\x4d\x4b\xc1\x99\x60\xe7\xad\xc3\xf8\x26" +
|
||||||
|
"\x1f\x45\x89\x39\x9b\xf7\x6b\xe4\x29\x6d\x1f\x57\x00\x9f\x3e\xc6\x24\xcd\xcd\x4b\x00\x00\x00\xff\xff\x40\xb8\x54" +
|
||||||
|
"\xb8\x64\x02\x00\x00")
|
||||||
|
|
||||||
|
func bindataTengoOutmessagetengoBytes() ([]byte, error) {
|
||||||
|
return bindataRead(
|
||||||
|
_bindataTengoOutmessagetengo,
|
||||||
|
"tengo/outmessage.tengo",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func bindataTengoOutmessagetengo() (*asset, error) {
|
||||||
|
bytes, err := bindataTengoOutmessagetengoBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
info := bindataFileInfo{
|
||||||
|
name: "tengo/outmessage.tengo",
|
||||||
|
size: 612,
|
||||||
|
md5checksum: "",
|
||||||
|
mode: os.FileMode(420),
|
||||||
|
modTime: time.Unix(1555622139, 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
a := &asset{bytes: bytes, info: info}
|
||||||
|
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Asset loads and returns the asset for the given name.
|
||||||
|
// It returns an error if the asset could not be found or
|
||||||
|
// could not be loaded.
|
||||||
|
//
|
||||||
|
func Asset(name string) ([]byte, error) {
|
||||||
|
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||||
|
if f, ok := _bindata[cannonicalName]; ok {
|
||||||
|
a, err := f()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
|
||||||
|
}
|
||||||
|
return a.bytes, nil
|
||||||
|
}
|
||||||
|
return nil, &os.PathError{Op: "open", Path: name, Err: os.ErrNotExist}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// MustAsset is like Asset but panics when Asset would return an error.
|
||||||
|
// It simplifies safe initialization of global variables.
|
||||||
|
// nolint: deadcode
|
||||||
|
//
|
||||||
|
func MustAsset(name string) []byte {
|
||||||
|
a, err := Asset(name)
|
||||||
|
if err != nil {
|
||||||
|
panic("asset: Asset(" + name + "): " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// AssetInfo loads and returns the asset info for the given name.
|
||||||
|
// It returns an error if the asset could not be found or could not be loaded.
|
||||||
|
//
|
||||||
|
func AssetInfo(name string) (os.FileInfo, error) {
|
||||||
|
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||||
|
if f, ok := _bindata[cannonicalName]; ok {
|
||||||
|
a, err := f()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
|
||||||
|
}
|
||||||
|
return a.info, nil
|
||||||
|
}
|
||||||
|
return nil, &os.PathError{Op: "open", Path: name, Err: os.ErrNotExist}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// AssetNames returns the names of the assets.
|
||||||
|
// nolint: deadcode
|
||||||
|
//
|
||||||
|
func AssetNames() []string {
|
||||||
|
names := make([]string, 0, len(_bindata))
|
||||||
|
for name := range _bindata {
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||||
|
//
|
||||||
|
var _bindata = map[string]func() (*asset, error){
|
||||||
|
"tengo/outmessage.tengo": bindataTengoOutmessagetengo,
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// AssetDir returns the file names below a certain
|
||||||
|
// directory embedded in the file by go-bindata.
|
||||||
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
|
// following hierarchy:
|
||||||
|
// data/
|
||||||
|
// foo.txt
|
||||||
|
// img/
|
||||||
|
// a.png
|
||||||
|
// b.png
|
||||||
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
|
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||||
|
// AssetDir("") will return []string{"data"}.
|
||||||
|
//
|
||||||
|
func AssetDir(name string) ([]string, error) {
|
||||||
|
node := _bintree
|
||||||
|
if len(name) != 0 {
|
||||||
|
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||||
|
pathList := strings.Split(cannonicalName, "/")
|
||||||
|
for _, p := range pathList {
|
||||||
|
node = node.Children[p]
|
||||||
|
if node == nil {
|
||||||
|
return nil, &os.PathError{
|
||||||
|
Op: "open",
|
||||||
|
Path: name,
|
||||||
|
Err: os.ErrNotExist,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if node.Func != nil {
|
||||||
|
return nil, &os.PathError{
|
||||||
|
Op: "open",
|
||||||
|
Path: name,
|
||||||
|
Err: os.ErrNotExist,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rv := make([]string, 0, len(node.Children))
|
||||||
|
for childName := range node.Children {
|
||||||
|
rv = append(rv, childName)
|
||||||
|
}
|
||||||
|
return rv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type bintree struct {
|
||||||
|
Func func() (*asset, error)
|
||||||
|
Children map[string]*bintree
|
||||||
|
}
|
||||||
|
|
||||||
|
var _bintree = &bintree{Func: nil, Children: map[string]*bintree{
|
||||||
|
"tengo": {Func: nil, Children: map[string]*bintree{
|
||||||
|
"outmessage.tengo": {Func: bindataTengoOutmessagetengo, Children: map[string]*bintree{}},
|
||||||
|
}},
|
||||||
|
}}
|
||||||
|
|
||||||
|
// RestoreAsset restores an asset under the given directory
|
||||||
|
func RestoreAsset(dir, name string) error {
|
||||||
|
data, err := Asset(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
info, err := AssetInfo(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestoreAssets restores an asset under the given directory recursively
|
||||||
|
func RestoreAssets(dir, name string) error {
|
||||||
|
children, err := AssetDir(name)
|
||||||
|
// File
|
||||||
|
if err != nil {
|
||||||
|
return RestoreAsset(dir, name)
|
||||||
|
}
|
||||||
|
// Dir
|
||||||
|
for _, child := range children {
|
||||||
|
err = RestoreAssets(dir, filepath.Join(name, child))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func _filePath(dir, name string) string {
|
||||||
|
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||||
|
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
|
||||||
|
}
|
19
internal/tengo/outmessage.tengo
Normal file
19
internal/tengo/outmessage.tengo
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
variables available
|
||||||
|
read-only:
|
||||||
|
inAccount, inProtocol, inChannel, inGateway
|
||||||
|
outAccount, outProtocol, outChannel, outGateway
|
||||||
|
|
||||||
|
read-write:
|
||||||
|
msgText, msgUsername
|
||||||
|
*/
|
||||||
|
|
||||||
|
text := import("text")
|
||||||
|
|
||||||
|
// start - strip irc colors
|
||||||
|
// if we're not sending to an irc bridge we strip the IRC colors
|
||||||
|
if inProtocol == "irc" {
|
||||||
|
re := text.re_compile(`\x03(?:\d{1,2}(?:,\d{1,2})?)?|[[:cntrl:]]`)
|
||||||
|
msgText=re.replace(msgText,"")
|
||||||
|
}
|
||||||
|
// end - strip irc colors
|
@ -1452,7 +1452,7 @@ IgnoreFailureOnStart=false
|
|||||||
#https://github.com/d5/tengo/blob/master/docs/stdlib.md
|
#https://github.com/d5/tengo/blob/master/docs/stdlib.md
|
||||||
|
|
||||||
[tengo]
|
[tengo]
|
||||||
#Message allows you to specify the location of a tengo (https://github.com/d5/tengo/) script.
|
#InMessage allows you to specify the location of a tengo (https://github.com/d5/tengo/) script.
|
||||||
#This script will receive every incoming message and can be used to modify the Username and the Text of that message.
|
#This script will receive every incoming message and can be used to modify the Username and the Text of that message.
|
||||||
#The script will have the following global variables:
|
#The script will have the following global variables:
|
||||||
#to modify: msgUsername and msgText
|
#to modify: msgUsername and msgText
|
||||||
@ -1470,7 +1470,27 @@ IgnoreFailureOnStart=false
|
|||||||
# msgUsername="fakeuser"
|
# msgUsername="fakeuser"
|
||||||
#}
|
#}
|
||||||
#OPTIONAL (default empty)
|
#OPTIONAL (default empty)
|
||||||
Message="example.tengo"
|
InMessage="example.tengo"
|
||||||
|
|
||||||
|
#OutMessage allows you to specify the location of the script that
|
||||||
|
#will be invoked on each message being sent to a bridge and can be used to modify the Username
|
||||||
|
#and the Text of that message.
|
||||||
|
#
|
||||||
|
#The script will have the following global variables:
|
||||||
|
#read-only:
|
||||||
|
#inAccount, inProtocol, inChannel, inGateway
|
||||||
|
#outAccount, outProtocol, outChannel, outGateway
|
||||||
|
#
|
||||||
|
#read-write:
|
||||||
|
#msgText, msgUsername
|
||||||
|
#
|
||||||
|
#The script is reloaded on every message, so you can modify the script on the fly.
|
||||||
|
#
|
||||||
|
#The default script in https://github.com/42wim/matterbridge/tree/master/internal/tengo/outmessage.tengo
|
||||||
|
#is compiled in and will be executed if no script is specified.
|
||||||
|
#OPTIONAL (default empty)
|
||||||
|
OutMessage="example.tengo"
|
||||||
|
|
||||||
|
|
||||||
#RemoteNickFormat allows you to specify the location of a tengo (https://github.com/d5/tengo/) script.
|
#RemoteNickFormat allows you to specify the location of a tengo (https://github.com/d5/tengo/) script.
|
||||||
#The script will have the following global variables:
|
#The script will have the following global variables:
|
||||||
|
Loading…
Reference in New Issue
Block a user