Last active
September 24, 2018 04:35
-
-
Save 0x263b/2d2b7a37a675750cc696aec41f69226a to your computer and use it in GitHub Desktop.
Discord spoiler bot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"encoding/json" | |
"fmt" | |
"io/ioutil" | |
"net/http" | |
"net/url" | |
"os" | |
"os/signal" | |
"regexp" | |
"runtime" | |
"strings" | |
"syscall" | |
"time" | |
"github.com/bwmarrin/discordgo" | |
humanize "github.com/dustin/go-humanize" | |
) | |
// Add your discord token | |
// and your bot Client ID | |
const ( | |
Token string = "" | |
ClientID string = "" | |
BotName string = "Spoiler Bot" | |
EmbedColor int = 0x01ffe1 | |
) | |
type Pasted struct { | |
// Struct for paste json response | |
Paste struct { | |
ID string `json:"id"` | |
Link string `json:"link"` | |
Raw string `json:"raw"` | |
LangCode string `json:"lang_code"` | |
Formatted string `json:"formatted"` | |
ExpirationDate time.Time `json:"expiration_date"` | |
} `json:"paste"` | |
Status string `json:"status"` | |
} | |
func pasteURL(title string, paste string) string { | |
form := url.Values{ | |
"title": {title}, | |
"lang": {"markdown"}, | |
"paste": {paste}, | |
} | |
encoded := bytes.NewBufferString(form.Encode()) | |
client := &http.Client{} | |
request, _ := http.NewRequest("POST", "https://mnn.im/c", encoded) | |
response, _ := client.Do(request) | |
defer response.Body.Close() | |
body, _ := ioutil.ReadAll(response.Body) | |
var pasted Pasted | |
json.Unmarshal(body, &pasted) | |
return pasted.Paste.Formatted | |
} | |
func main() { | |
// Create a new Discord session using the provided bot token. | |
dg, err := discordgo.New("Bot " + Token) | |
if err != nil { | |
fmt.Println("error creating Discord session,", err) | |
return | |
} | |
// Register the messageCreate func as a callback for MessageCreate events. | |
dg.AddHandler(messageCreate) | |
// Open a websocket connection to Discord and begin listening. | |
err = dg.Open() | |
if err != nil { | |
fmt.Println("error opening connection,", err) | |
return | |
} | |
// Wait here until CTRL-C or other term signal is received. | |
fmt.Println("Bot is now running. Press CTRL-C to exit.") | |
sc := make(chan os.Signal, 1) | |
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill) | |
<-sc | |
// Cleanly close down the Discord session. | |
dg.Close() | |
} | |
// This function will be called (due to AddHandler above) every time a new | |
// message is created on any channel that the authenticated bot has access to. | |
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { | |
// Ignore all messages created by the bot itself | |
// This isn't required in this specific example but it's a good practice. | |
if m.Author.ID == s.State.User.ID { | |
return | |
} | |
message := strings.ToLower(m.Content) | |
// Spoiler command | |
cw := regexp.MustCompile(`^!(sp|cw) (.+)\|(.+)`) // has warning | |
nw := regexp.MustCompile(`^!(sp|cw) (.+)`) // no warning | |
if cw.MatchString(message) { | |
cmdSpoiler(s, m, true) | |
} else if nw.MatchString(message) { | |
cmdSpoiler(s, m, false) | |
} | |
if message == "!help" { | |
cmdHelp(s, m) | |
} | |
if message == "!stats" { | |
cmdStats(s, m) | |
} | |
if message == "!ping" { | |
s.ChannelMessageSend(m.ChannelID, "Pong!") | |
} | |
} | |
func cmdSpoiler(s *discordgo.Session, m *discordgo.MessageCreate, hasWarn bool) { | |
s.ChannelMessageDelete(m.ChannelID, m.ID) | |
var spoiler string | |
spoiler = strings.Replace(m.Content, "!sp ", "", 1) | |
spoiler = strings.Replace(spoiler, "!cw ", "", 1) | |
var warning string | |
var content string | |
if hasWarn { | |
split := strings.SplitN(spoiler, "|", 2) | |
warning = split[0] | |
content = strings.TrimSpace(split[1]) | |
} else { | |
warning = "Content Warning" | |
content = spoiler | |
} | |
rotated := rot13(content) | |
if len(rotated) > 240 { | |
rotated = fmt.Sprintf("%s...", rotated[0:240]) | |
} | |
markdown := fmt.Sprintf("### %s \n\nPosted by `%s` \n\n%s", warning, m.Author.Username, content) | |
markdownURL := pasteURL(warning, markdown) | |
s.ChannelMessageSendEmbed(m.ChannelID, &discordgo.MessageEmbed{ | |
Author: &discordgo.MessageEmbedAuthor{ | |
Name: m.Author.Username, | |
IconURL: m.Author.AvatarURL(""), | |
}, | |
Color: EmbedColor, | |
Title: warning, | |
Description: rotated, | |
URL: markdownURL, | |
}) | |
} | |
func cmdHelp(s *discordgo.Session, m *discordgo.MessageCreate) { | |
s.ChannelMessageSendEmbed(m.ChannelID, &discordgo.MessageEmbed{ | |
Author: &discordgo.MessageEmbedAuthor{ | |
Name: BotName, | |
IconURL: s.State.User.AvatarURL("128"), | |
URL: fmt.Sprintf("https://discordapp.com/oauth2/authorize?client_id=%s&scope=bot&permissions=92160", ClientID), | |
}, | |
Color: EmbedColor, | |
Fields: []*discordgo.MessageEmbedField{ | |
{ | |
Name: "Usage", | |
Value: "```!sp your message```", | |
Inline: false, | |
}, | |
{ | |
Name: "Custom warning message", | |
Value: "```!sp spoiler for star warps | your message```", | |
Inline: false, | |
}, | |
}, | |
}) | |
} | |
func cmdStats(s *discordgo.Session, m *discordgo.MessageCreate) { | |
stats := runtime.MemStats{} | |
runtime.ReadMemStats(&stats) | |
users := 0 | |
for _, guild := range s.State.Ready.Guilds { | |
users += len(guild.Members) | |
} | |
channels := 0 | |
for _, guild := range s.State.Ready.Guilds { | |
channels += len(guild.Channels) | |
} | |
s.ChannelMessageSendEmbed(m.ChannelID, &discordgo.MessageEmbed{ | |
Author: &discordgo.MessageEmbedAuthor{ | |
Name: BotName, | |
IconURL: s.State.User.AvatarURL("128"), | |
URL: fmt.Sprintf("https://discordapp.com/oauth2/authorize?client_id=%s&scope=bot&permissions=92160", ClientID), | |
}, | |
Color: EmbedColor, | |
Fields: []*discordgo.MessageEmbedField{ | |
{ | |
Name: "Discordgo", | |
Value: discordgo.VERSION, | |
Inline: true, | |
}, | |
{ | |
Name: "Go", | |
Value: runtime.Version(), | |
Inline: true, | |
}, | |
{ | |
Name: "Memory", | |
Value: fmt.Sprintf("%s / %s", humanize.Bytes(stats.Alloc), humanize.Bytes(stats.Sys)), | |
Inline: true, | |
}, | |
{ | |
Name: "Tasks", | |
Value: fmt.Sprintf("%d", runtime.NumGoroutine()), | |
Inline: true, | |
}, | |
{ | |
Name: "Servers", | |
Value: fmt.Sprintf("%d", len(s.State.Ready.Guilds)), | |
Inline: true, | |
}, | |
{ | |
Name: "Channels", | |
Value: fmt.Sprintf("%d", channels), | |
Inline: true, | |
}, | |
{ | |
Name: "Users", | |
Value: fmt.Sprintf("%d", users), | |
Inline: true, | |
}, | |
}, | |
}) | |
} | |
func rot13char(c rune) rune { | |
if c >= 'a' && c <= 'm' || c >= 'A' && c <= 'M' { | |
return c + 13 | |
} else if c >= 'n' && c <= 'z' || c >= 'N' && c <= 'Z' { | |
return c - 13 | |
} | |
return c | |
} | |
func rot13(s string) string { | |
return strings.Map(rot13char, s) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment