Add Discord Invite Connector
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
b3cc7e8d9a
commit
8d438c6c01
3 changed files with 203 additions and 0 deletions
29
README.md
29
README.md
|
@ -16,6 +16,35 @@ Pretty-print issues Twitch AutoMod had with the message
|
||||||
match_message: '!autodebug (.+)'
|
match_message: '!autodebug (.+)'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## dc-invite
|
||||||
|
|
||||||
|
Create a Discord invite and send the invite link through a whisper
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- description: Discord-Invite
|
||||||
|
actions:
|
||||||
|
- type: script
|
||||||
|
attributes:
|
||||||
|
command:
|
||||||
|
- /data/bin/dc-invite
|
||||||
|
- --channel-id=1234... # Right-click on channel, copy ID
|
||||||
|
#- --discord-bot-token=... # Can provide through env: DISCORD_BOT_TOKEN
|
||||||
|
- --message-template
|
||||||
|
- 'Hey, hier ist der Invite für meinen Discord: https://discord.gg/%s'
|
||||||
|
- --send-to={{ fixUsername .user }}
|
||||||
|
- type: discordhook
|
||||||
|
attributes:
|
||||||
|
content: |
|
||||||
|
Ein Discord-Invite (`{{ .invite_code }}`) wurde erstellt:
|
||||||
|
`{{ fixUsername .user }}` ({{ .user_id }})
|
||||||
|
hook_url: https://discord.com/api/webhooks/...
|
||||||
|
username: Invite-Bot
|
||||||
|
match_channels:
|
||||||
|
- '#luziferus'
|
||||||
|
match_event: channelpoint_redeem
|
||||||
|
disable_on_template: '{{ ne .reward_id "45d441e9-6a00-4c3e-8bd8-b2cd8b913753" }}'
|
||||||
|
```
|
||||||
|
|
||||||
## dice
|
## dice
|
||||||
|
|
||||||
Throw `N` `M`-sided dices and print the result into the chat
|
Throw `N` `M`-sided dices and print the result into the chat
|
||||||
|
|
81
dc-invite/invite.go
Normal file
81
dc-invite/invite.go
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const discordRequestTimeout = 2 * time.Second
|
||||||
|
|
||||||
|
type (
|
||||||
|
createChannelInviteReq struct {
|
||||||
|
MaxAge int64 `json:"max_age"`
|
||||||
|
MaxUses int64 `json:"max_uses"`
|
||||||
|
Temporary bool `json:"temporary"`
|
||||||
|
Unique bool `json:"unique"`
|
||||||
|
// more unsupported params
|
||||||
|
}
|
||||||
|
|
||||||
|
createChannelInviteResp struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
// more unsupported params
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func createInvite() (string, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), discordRequestTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
var (
|
||||||
|
body = new(bytes.Buffer)
|
||||||
|
err error
|
||||||
|
reqURL = fmt.Sprintf("https://discord.com/api/channels/%s/invites", cfg.ChannelID)
|
||||||
|
)
|
||||||
|
|
||||||
|
if err = json.NewEncoder(body).Encode(createChannelInviteReq{
|
||||||
|
MaxAge: int64(cfg.ExpireIn / time.Second),
|
||||||
|
MaxUses: cfg.Uses,
|
||||||
|
Temporary: false,
|
||||||
|
Unique: true,
|
||||||
|
}); err != nil {
|
||||||
|
return "", errors.Wrap(err, "encoding request body")
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, reqURL, body)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "creating request")
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Authorization", strings.Join([]string{"Bot", cfg.DiscordBotToken}, " "))
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("X-Audit-Log-Reason", fmt.Sprintf("twitch-bot-tools/dc-invite requested for %s", cfg.SendTo))
|
||||||
|
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "executing request")
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := resp.Body.Close(); err != nil {
|
||||||
|
logrus.WithError(err).Error("closing response body (leaked fd)")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return "", errors.Errorf("unexpected status %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
var invite createChannelInviteResp
|
||||||
|
if err = json.NewDecoder(resp.Body).Decode(&invite); err != nil {
|
||||||
|
return "", errors.Wrap(err, "decoding invite response")
|
||||||
|
}
|
||||||
|
|
||||||
|
return invite.Code, nil
|
||||||
|
}
|
93
dc-invite/main.go
Normal file
93
dc-invite/main.go
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/Luzifer/rconfig/v2"
|
||||||
|
"github.com/Luzifer/twitch-bot/v3/plugins"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
cfg = struct {
|
||||||
|
ChannelID string `flag:"channel-id,c" default:"" description:"Snowflake ID of the channel to invite to" validate:"nonzero"`
|
||||||
|
DiscordBotToken string `flag:"discord-bot-token,t" default:"" description:"Token for a Bot with CREATE_INSTANT_INVITE permission" validate:"nonzero"`
|
||||||
|
ExpireIn time.Duration `flag:"expire-in,e" default:"24h" description:"How long should the invite be valid"`
|
||||||
|
LogLevel string `flag:"log-level" default:"info" description:"Log level (debug, info, warn, error, fatal)"`
|
||||||
|
MessageTemplate string `flag:"message-template,m" default:"Your discord invite: https://discord.gg/%s" description:"Message to send in the whisper (use %s at the position of the invite code)"`
|
||||||
|
SendTo string `flag:"send-to,s" default:"" description:"Twitch user to whisper the code to"`
|
||||||
|
VersionAndExit bool `flag:"version" default:"false" description:"Prints current version and exits"`
|
||||||
|
Uses int64 `flag:"uses,u" default:"1" description:"Expire after N uses"`
|
||||||
|
}{}
|
||||||
|
|
||||||
|
version = "dev"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initApp() error {
|
||||||
|
rconfig.AutoEnv(true)
|
||||||
|
if err := rconfig.ParseAndValidate(&cfg); err != nil {
|
||||||
|
return errors.Wrap(err, "parsing cli options")
|
||||||
|
}
|
||||||
|
|
||||||
|
l, err := logrus.ParseLevel(cfg.LogLevel)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "parsing log-level")
|
||||||
|
}
|
||||||
|
logrus.SetLevel(l)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var err error
|
||||||
|
if err = initApp(); err != nil {
|
||||||
|
logrus.WithError(err).Fatal("initializing app")
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.VersionAndExit {
|
||||||
|
logrus.WithField("version", version).Info("twitch-bot-tools/dc-invite")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
invite, err := createInvite()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Fatal("creating invite")
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldsPayload := new(bytes.Buffer)
|
||||||
|
if err = json.NewEncoder(fieldsPayload).Encode(map[string]any{
|
||||||
|
"invite_code": invite,
|
||||||
|
}); err != nil {
|
||||||
|
logrus.WithError(err).Fatal("encoding fields payload")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = json.NewEncoder(os.Stdout).Encode([]plugins.RuleAction{
|
||||||
|
{
|
||||||
|
Type: "eventmod",
|
||||||
|
Attributes: plugins.FieldCollectionFromData(map[string]any{
|
||||||
|
"fields": fieldsPayload.String(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "log",
|
||||||
|
Attributes: plugins.FieldCollectionFromData(map[string]any{
|
||||||
|
"message": fmt.Sprintf("twitch-bot-tools/dc-invite: created invite %s for user %s", invite, cfg.SendTo),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "whisper",
|
||||||
|
Attributes: plugins.FieldCollectionFromData(map[string]any{
|
||||||
|
"message": fmt.Sprintf(cfg.MessageTemplate, invite),
|
||||||
|
"to": cfg.SendTo,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}); err != nil {
|
||||||
|
logrus.WithError(err).Fatal("encoding bot actions")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue