hnbot/discord.go

171 lines
3.9 KiB
Go
Raw Normal View History

2023-04-19 20:48:24 +00:00
package main
import (
"bytes"
"encoding/json"
2023-04-24 22:42:11 +00:00
"errors"
"fmt"
2023-04-19 20:48:24 +00:00
"log"
"net/http"
"github.com/bwmarrin/discordgo"
2023-04-24 22:42:11 +00:00
"github.com/dustin/go-humanize"
2023-04-19 20:48:24 +00:00
"github.com/joho/godotenv"
"github.com/namsral/flag"
)
var (
DiscordWebhook string
DiscordToken string
DiscordClient *discordgo.Session
2023-04-19 20:48:24 +00:00
)
type DiscordEmbedFooter struct {
Text string `json:"text"`
IconUrl string `json:"icon_url"`
}
2023-04-24 22:42:11 +00:00
type DiscordEmbedField struct {
Name string `json:"name"`
Value string `json:"value"`
Inline bool `json:"inline"`
}
2023-04-19 20:48:24 +00:00
type DiscordEmbed struct {
2023-04-24 22:42:11 +00:00
Title string `json:"title"`
Url string `json:"url"`
Color int `json:"color"`
Footer DiscordEmbedFooter `json:"footer"`
Timestamp string `json:"timestamp"`
Fields []DiscordEmbedField `json:"fields"`
2023-04-19 20:48:24 +00:00
}
type DiscordWebhookPayload struct {
Embeds []DiscordEmbed `json:"embeds"`
}
func init() {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
flag.StringVar(&DiscordWebhook, "DISCORD_WEBHOOK", "", "Webhook to send logs to discord")
flag.StringVar(&DiscordToken, "DISCORD_TOKEN", "", "Discord bot token")
2023-04-19 20:48:24 +00:00
flag.Parse()
if DiscordWebhook == "" {
log.Fatal("DISCORD_WEBHOOK not set")
}
if DiscordToken == "" {
log.Fatal("DISCORD_TOKEN not set")
}
initBot()
}
func initBot() {
var err error
DiscordClient, err = discordgo.New(DiscordToken)
if err != nil {
log.Fatal("error creating discord session:", err)
}
DiscordClient.AddHandler(func(s *discordgo.Session, event *discordgo.Ready) {
log.Println("Logged in as", event.User.Username)
})
DiscordClient.AddHandler(onMessage)
DiscordClient.Identify.Intents = discordgo.IntentsGuildMessages | discordgo.IntentsMessageContent
err = DiscordClient.Open()
if err != nil {
log.Fatal("error opening connection to discord: ", err, " -- Is your token correct?")
}
}
func onMessage(s *discordgo.Session, m *discordgo.MessageCreate) {
// Ignore all messages created by the bot itself
if m.Author.ID == s.State.User.ID {
return
}
id, err := ParseHackerNewsLink(m.Content)
if err != nil {
return
}
story := FetchStoryById(id)
2023-04-24 22:42:11 +00:00
id, err = PostStoryToStackerNews(&story)
if err != nil {
var dupesErr *DupesError
if errors.As(err, &dupesErr) {
SendDupesErrorToDiscord(dupesErr)
} else {
log.Fatal("unexpected error returned")
}
}
}
func SendDupesErrorToDiscord(dupesErr *DupesError) {
title := fmt.Sprintf("%d dupe(s) found for %s:", len(dupesErr.Dupes), dupesErr.Url)
color := 0xffc107
var fields []DiscordEmbedField
for _, dupe := range dupesErr.Dupes {
fields = append(fields,
DiscordEmbedField{
Name: "Title",
Value: dupe.Title,
Inline: false,
},
DiscordEmbedField{
Name: "Id",
Value: StackerNewsItemLink(dupe.Id),
Inline: true,
},
DiscordEmbedField{
Name: "Url",
Value: dupe.Url,
Inline: true,
},
DiscordEmbedField{
Name: "User",
Value: dupe.User.Name,
Inline: true,
},
DiscordEmbedField{
Name: "Created",
Value: humanize.Time(dupe.CreatedAt),
Inline: true,
},
DiscordEmbedField{
Name: "Sats",
Value: fmt.Sprint(dupe.Sats),
Inline: true,
},
DiscordEmbedField{
Name: "Comments",
Value: fmt.Sprint(dupe.NComments),
Inline: true,
},
)
}
embed := DiscordEmbed{
Title: title,
Color: color,
Fields: fields,
}
SendEmbedToDiscord(embed)
2023-04-19 20:48:24 +00:00
}
func SendEmbedToDiscord(embed DiscordEmbed) {
bodyJSON, err := json.Marshal(
DiscordWebhookPayload{
Embeds: []DiscordEmbed{embed},
},
)
if err != nil {
log.Fatal("Error during json.Marshal:", err)
}
req, err := http.NewRequest("POST", DiscordWebhook, bytes.NewBuffer(bodyJSON))
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Println("Discord webhook error:", err)
}
defer resp.Body.Close()
}