Skip to content

Commit

Permalink
3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
cyckl committed May 3, 2021
1 parent 80b62af commit 9860e10
Show file tree
Hide file tree
Showing 3 changed files with 188 additions and 95 deletions.
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module cyckl/tweeter

go 1.16

require github.com/bwmarrin/discordgo v0.23.3-0.20210410202908-577e7dd4f6cc
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
github.com/bwmarrin/discordgo v0.23.2 h1:BzrtTktixGHIu9Tt7dEE6diysEF9HWnXeHuoJEt2fH4=
github.com/bwmarrin/discordgo v0.23.2/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M=
github.com/bwmarrin/discordgo v0.23.3-0.20210410202908-577e7dd4f6cc h1:S3C2Q9BUNkjWFO5S5FVghkIHZ/g+PmYYr/+luZ83FVc=
github.com/bwmarrin/discordgo v0.23.3-0.20210410202908-577e7dd4f6cc/go.mod h1:OMKxbTmkKofBjBi4/yidO3ItxbJ6PUfEUkjchM4En8c=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
268 changes: 173 additions & 95 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,144 +3,222 @@ package main
import (
"flag"
"fmt"
"log"
"math/rand"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"time"
"github.com/bwmarrin/discordgo"
)

// Set global variables / boot information
const version = "3.0.0"
var (
token string
version string
s *discordgo.Session
token = flag.String("t", "", "Bot token")
register = flag.Bool("r", false, "Register (or re-register) bot commands on startup")
unregister = flag.Bool("u", false, "Unregister bot commands on shutdown")
)

func init() {
version = "2.0.3"
flag.StringVar(&token, "t", "", "Bot token")
// Print boot "splash"
fmt.Println("╔═══════════════════════╗")
fmt.Println("║ Tweeter by cyckl ║")
fmt.Println(fmt.Sprintf("║ Running version %s ║", version))
fmt.Println("╚═══════════════════════╝")
log.Println("[Info] Minimum permissions are 75776")

// Seed RNG
rand.Seed(time.Now().UnixNano())
log.Println("[Info] Random number generator seeded")

// Pass args in
flag.Parse()
}

// Establish available commands
var (
commands = []*discordgo.ApplicationCommand{
{
Name: "tweet",
Description: "Generate a fake tweet",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "content",
Description: "Tweet content",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionUser,
Name: "user",
Description: "Select tweet author",
Required: false,
},
},
},
{
Name: "about",
Description: "About Tweeter",
},
}
)

func main() {
// Create new Discord session using bot token
dg, err := discordgo.New("Bot " + token)
// Declare error here so it can be set without :=
var err error

// Create bot client session
log.Println("[Info] Logging in")
s, err = discordgo.New("Bot " + *token)
if err != nil {
fmt.Println("error creating discord session,", err)
return
log.Fatalf("[Fatal] Error creating session: %v", err)
}

// Pass on command events to functions
log.Println("[Info] Registering intents")
s.AddHandler(tweet)
s.AddHandler(about)

// Register the tweet, about func as a callback for MessageCreate events
dg.AddHandler(tweet)
dg.AddHandler(about)

// For this example we only care about recieving message events
dg.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsGuildMessages)
// We only care about integration (command) intents
s.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsGuildIntegrations)

// Open websocket conn to Discord and listen
err = dg.Open()
// Open websocket connection to Discord and listen
err = s.Open()
if err != nil {
fmt.Println("error opening connection,", err)
return
log.Fatalf("[Fatal] Error opening connection: %v", err)
}

// Wait here until EOF
fmt.Println("╔═══════════════════════╗")
fmt.Println("║ Tweeter by cyckl ║")
fmt.Println(fmt.Sprintf("║ Running version %s ║", version))
fmt.Println("╚═══════════════════════╝")
fmt.Println("[Permissions] 75776")

// Seed RNG
rand.Seed(time.Now().UnixNano())
fmt.Println("[Info] Random number generator seeded")
if *register == true {
registerCmd(s)
}

// Close Discord session cleanly
sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
<-sc
dg.Close()
fmt.Println("[Info] Program terminated")
defer s.Close()

stop := make(chan os.Signal)
signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
<-stop

if *unregister == true {
unregisterCmd(s)
}

log.Println("[Info] Shutting down")
}

// Pueudorandom numbers
func randInt(min, max int) int {
return min + rand.Intn(max-min)
}

func tweet(s *discordgo.Session, m *discordgo.MessageCreate) {
// Ignore bot messages, good practice
if m.Author.ID == s.State.User.ID {
return
}

if strings.HasPrefix(m.Content, ".t ") {
// Nickname handling
tweetAuthor := "undefined"
if m.Member.Nick != "" {
tweetAuthorValues := []string{m.Member.Nick, " (@", m.Author.Username, ")"}
tweetAuthor = strings.Join(tweetAuthorValues, "")
func tweet(s *discordgo.Session, i *discordgo.InteractionCreate) {
if i.Data.Name == "tweet" {
// Set default endpoints for data (no selected user and no nickname)
author := fmt.Sprintf("@%s", i.Member.User.Username)
avatar := discordgo.EndpointUserAvatar(i.Member.User.ID, i.Member.User.Avatar)

// Handle user selection and nicknames
if len(i.Data.Options) == 2 {
// If there is a selected user, set the author and avatar to the selected user instead of default
author = fmt.Sprintf("@%s", i.Data.Options[1].UserValue(s).Username)
avatar = discordgo.EndpointUserAvatar(i.Data.Options[1].UserValue(s).ID, i.Data.Options[1].UserValue(s).Avatar)
} else {
tweetAuthor = m.Author.Username
// If there is no selected user, at least check if the command author has a nickname
if i.Member.Nick != "" {
author = fmt.Sprintf("%s (@%s)", i.Member.Nick, i.Member.User.Username)
}
}

// Delete command issuer
s.ChannelMessageDelete(m.ChannelID, m.ID)

// Fill embed and send it
s.ChannelMessageSendEmbed(m.ChannelID, &discordgo.MessageEmbed{
Author: &discordgo.MessageEmbedAuthor{
Name: tweetAuthor,
IconURL: discordgo.EndpointUserAvatar(m.Author.ID, m.Author.Avatar),
},
Color: 1942002,
Description: strings.TrimPrefix(m.Content, ".t "),
Footer: &discordgo.MessageEmbedFooter{
Text: "Twitter",
IconURL: "https://abs.twimg.com/icons/apple-touch-icon-192x192.png",

// Respond to command event with embed
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionApplicationCommandResponseData{
// One entry in the array of embeds... Why did they make this a fucking array?
Embeds: []*discordgo.MessageEmbed{
{
Author: &discordgo.MessageEmbedAuthor{
Name: author,
IconURL: avatar,
},
Color: 1942002,
Description: i.Data.Options[0].StringValue(),
Footer: &discordgo.MessageEmbedFooter{
Text: "Twitter",
IconURL: "https://abs.twimg.com/icons/apple-touch-icon-192x192.png",
},
Fields: []*discordgo.MessageEmbedField{
{Name: "Retweets", Value: strconv.Itoa(randInt(5000, 50000)), Inline: true},
{Name: "Likes", Value: strconv.Itoa(randInt(25000, 150000)), Inline: true},
},
},
},
},
})
}
}

Fields: []*discordgo.MessageEmbedField{
{Name: "Retweets", Value: strconv.Itoa(randInt(5000, 50000)), Inline: true},
{Name: "Likes", Value: strconv.Itoa(randInt(25000, 150000)), Inline: true},
func about(s *discordgo.Session, i *discordgo.InteractionCreate) {
if i.Data.Name == "about" {
// Respond to command event with embed
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionApplicationCommandResponseData{
Embeds: []*discordgo.MessageEmbed{
{
Thumbnail: &discordgo.MessageEmbedThumbnail{
URL: "https://github.com/cyckl/tweeter/raw/master/img/tweeter.png",
},
Title: "Tweeter by cyckl",
Author: &discordgo.MessageEmbedAuthor{
Name: "About",
IconURL: "https://github.com/cyckl/tweeter/raw/master/img/tweeter.png",
},
Color: 16729402,
Description: "Tweeter is a mock Twitter embed generator for Discord.",
Footer: &discordgo.MessageEmbedFooter{
Text: "Why do I still maintain this?",
},

Fields: []*discordgo.MessageEmbedField{
{Name: "Version", Value: version, Inline: true},
{Name: "Build date", Value: "2021-05-02", Inline: true},
{Name: "Github", Value: "https://github.com/cyckl/tweeter", Inline: false},
},
},
},
},
})

// Log to console
fmt.Println(fmt.Sprintf("[Tweet] (%s) %s", m.Author.ID, strings.TrimPrefix(m.Content, ".t ")))
}
}

func about(s *discordgo.Session, m *discordgo.MessageCreate) {
// Ignore bot messages, good practice
if m.Author.ID == s.State.User.ID {
return
func registerCmd(s *discordgo.Session) {
// Register commands
for _, v := range commands {
log.Println("[Info] Registering:", v.Name)
_, err := s.ApplicationCommandCreate(s.State.User.ID, "", v)
if err != nil {
log.Panicf("[Error] Cannot create '%v' command: %v", v.Name, err)
}
}
}

if m.Content == "t.about" {
// Send embed
s.ChannelMessageSendEmbed(m.ChannelID, &discordgo.MessageEmbed{
Thumbnail: &discordgo.MessageEmbedThumbnail{
URL: "https://github.com/cyckl/tweeter/raw/master/img/tweeter.png",
},
Title: "Tweeter by cyckl",
Author: &discordgo.MessageEmbedAuthor{
Name: "About",
IconURL: "https://github.com/cyckl/tweeter/raw/master/img/tweeter.png",
},
Color: 16729402,
Description: "Tweeter is a mock Twitter embed generator for Discord.",
Footer: &discordgo.MessageEmbedFooter{
Text: "This is beta software. Please be patient.",
},

Fields: []*discordgo.MessageEmbedField{
{Name: "Version", Value: version, Inline: true},
{Name: "Build date", Value: "2020-10-09", Inline: true},
{Name: "Github", Value: "https://github.com/cyckl/tweeter", Inline: false},
},
})
func unregisterCmd(s *discordgo.Session) {
// Get command list
pubCommands, err := s.ApplicationCommands(s.State.User.ID, "")
if err != nil {
log.Panicf("[Error] Cannot get application commands: %v", err)
}

// Unregister commands by ID
for _, v := range pubCommands {
log.Println("[Info] Unregistering:", v.Name)
err := s.ApplicationCommandDelete(s.State.User.ID, "", v.ID)
if err != nil {
log.Panicf("[Error] Cannot delete '%v' command: %v", v.Name, err)
}
}
log.Println("[Info] Commands unregistered")
}

0 comments on commit 9860e10

Please sign in to comment.