hnbot/discord.go

189 lines
4.3 KiB
Go
Raw Normal View History

2023-04-19 20:48:24 +00:00
package main
import (
2023-04-24 22:42:11 +00:00
"errors"
"fmt"
2023-04-19 20:48:24 +00:00
"log"
2023-04-25 00:22:27 +00:00
"strings"
2023-04-19 20:48:24 +00:00
"github.com/bwmarrin/discordgo"
2023-04-24 22:42:11 +00:00
"github.com/dustin/go-humanize"
2023-06-01 01:07:02 +00:00
"github.com/ekzyis/sn-goapi"
2023-04-19 20:48:24 +00:00
"github.com/joho/godotenv"
"github.com/namsral/flag"
)
var (
2023-04-24 23:57:37 +00:00
DiscordToken string
2023-04-25 00:01:58 +00:00
dg *discordgo.Session
2023-04-24 23:57:37 +00:00
DiscordChannelId string
2023-04-19 20:48:24 +00:00
)
func init() {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
flag.StringVar(&DiscordToken, "DISCORD_TOKEN", "", "Discord bot token")
2023-04-24 23:57:37 +00:00
flag.StringVar(&DiscordChannelId, "DISCORD_CHANNEL_ID", "", "Discord channel id")
2023-04-19 20:48:24 +00:00
flag.Parse()
if DiscordToken == "" {
log.Fatal("DISCORD_TOKEN not set")
}
2023-04-24 23:57:37 +00:00
if DiscordChannelId == "" {
log.Fatal("DISCORD_CHANNEL_ID not set")
}
initBot()
}
func initBot() {
var err error
2023-04-25 00:01:58 +00:00
dg, err = discordgo.New("Bot " + DiscordToken)
if err != nil {
log.Fatal("error creating discord session:", err)
}
2023-04-25 00:01:58 +00:00
dg.AddHandler(func(s *discordgo.Session, event *discordgo.Ready) {
log.Println("Logged in as", event.User.Username)
})
2023-04-25 00:01:58 +00:00
dg.AddHandler(onMessage)
2023-04-25 00:22:27 +00:00
dg.AddHandler(onMessageReact)
dg.Identify.Intents = discordgo.IntentsGuildMessages | discordgo.IntentsMessageContent | discordgo.IntentGuildMessageReactions
2023-04-25 00:01:58 +00:00
err = dg.Open()
if err != nil {
log.Fatal("error opening connection to discord: ", err, " -- Is your token correct?")
}
}
func onMessage(s *discordgo.Session, m *discordgo.MessageCreate) {
if m.Author.ID == s.State.User.ID {
return
}
2023-04-25 00:22:27 +00:00
hackerNewsId, err := ParseHackerNewsLink(m.Content)
if err != nil {
return
}
2023-04-25 09:51:12 +00:00
story, err := FetchStoryById(hackerNewsId)
2023-04-25 00:22:27 +00:00
_, err = PostStoryToStackerNews(&story, PostStoryOptions{SkipDupes: false})
2023-04-24 22:42:11 +00:00
if err != nil {
2023-06-01 01:07:02 +00:00
var dupesErr *sn.DupesError
2023-04-24 22:42:11 +00:00
if errors.As(err, &dupesErr) {
2023-04-25 00:22:27 +00:00
SendDupesErrorToDiscord(hackerNewsId, dupesErr)
2023-04-25 09:51:12 +00:00
return
2023-04-24 22:42:11 +00:00
}
2023-04-25 09:51:12 +00:00
SendErrorToDiscord(err)
2023-04-24 22:42:11 +00:00
}
}
2023-04-25 00:22:27 +00:00
func onMessageReact(s *discordgo.Session, reaction *discordgo.MessageReactionAdd) {
if reaction.UserID == s.State.User.ID {
return
}
if reaction.Emoji.Name != "⏭️" {
return
}
m, err := s.ChannelMessage(reaction.ChannelID, reaction.MessageID)
if err != nil {
2023-04-25 09:51:12 +00:00
SendErrorToDiscord(err)
2023-04-25 00:22:27 +00:00
return
}
if len(m.Embeds) == 0 {
return
}
embed := m.Embeds[0]
if !strings.Contains(embed.Title, "dupe(s) found for") {
return
}
id, err := ParseHackerNewsLink(embed.Footer.Text)
if err != nil {
return
}
2023-04-25 09:51:12 +00:00
story, err := FetchStoryById(id)
if err != nil {
SendErrorToDiscord(err)
return
}
2023-04-25 00:22:27 +00:00
id, err = PostStoryToStackerNews(&story, PostStoryOptions{SkipDupes: true})
if err != nil {
2023-04-25 09:51:12 +00:00
SendErrorToDiscord(err)
2023-04-25 00:22:27 +00:00
}
}
2023-06-01 01:07:02 +00:00
func SendDupesErrorToDiscord(hackerNewsId int, dupesErr *sn.DupesError) {
2023-04-25 09:51:12 +00:00
msg := fmt.Sprint(dupesErr)
log.Println(msg)
2023-04-24 22:42:11 +00:00
title := fmt.Sprintf("%d dupe(s) found for %s:", len(dupesErr.Dupes), dupesErr.Url)
color := 0xffc107
2023-04-24 23:57:37 +00:00
var fields []*discordgo.MessageEmbedField
2023-04-24 22:42:11 +00:00
for _, dupe := range dupesErr.Dupes {
fields = append(fields,
2023-04-24 23:57:37 +00:00
&discordgo.MessageEmbedField{
2023-04-24 22:42:11 +00:00
Name: "Title",
Value: dupe.Title,
Inline: false,
},
2023-04-24 23:57:37 +00:00
&discordgo.MessageEmbedField{
2023-04-24 22:42:11 +00:00
Name: "Id",
2023-06-01 01:07:02 +00:00
Value: sn.FormatLink(dupe.Id),
2023-04-24 22:42:11 +00:00
Inline: true,
},
2023-04-24 23:57:37 +00:00
&discordgo.MessageEmbedField{
2023-04-24 22:42:11 +00:00
Name: "Url",
Value: dupe.Url,
Inline: true,
},
2023-04-24 23:57:37 +00:00
&discordgo.MessageEmbedField{
2023-04-24 22:42:11 +00:00
Name: "User",
Value: dupe.User.Name,
Inline: true,
},
2023-04-24 23:57:37 +00:00
&discordgo.MessageEmbedField{
2023-04-24 22:42:11 +00:00
Name: "Created",
Value: humanize.Time(dupe.CreatedAt),
Inline: true,
},
2023-04-24 23:57:37 +00:00
&discordgo.MessageEmbedField{
2023-04-24 22:42:11 +00:00
Name: "Sats",
Value: fmt.Sprint(dupe.Sats),
Inline: true,
},
2023-04-24 23:57:37 +00:00
&discordgo.MessageEmbedField{
2023-04-24 22:42:11 +00:00
Name: "Comments",
Value: fmt.Sprint(dupe.NComments),
Inline: true,
},
)
}
2023-04-25 09:51:12 +00:00
2023-04-24 23:57:37 +00:00
embed := discordgo.MessageEmbed{
2023-04-24 22:42:11 +00:00
Title: title,
Color: color,
Fields: fields,
2023-04-25 00:22:27 +00:00
Footer: &discordgo.MessageEmbedFooter{
Text: HackerNewsItemLink(hackerNewsId),
IconURL: "https://news.ycombinator.com/y18.gif",
},
2023-04-24 22:42:11 +00:00
}
2023-04-24 23:57:37 +00:00
SendEmbedToDiscord(&embed)
2023-04-19 20:48:24 +00:00
}
2023-04-24 23:57:37 +00:00
func SendEmbedToDiscord(embed *discordgo.MessageEmbed) {
2023-04-25 00:01:58 +00:00
_, err := dg.ChannelMessageSendEmbed(DiscordChannelId, embed)
2023-04-19 20:48:24 +00:00
if err != nil {
2023-04-25 09:51:12 +00:00
err = fmt.Errorf("error during sending embed: %w", err)
log.Println(err)
2023-04-19 20:48:24 +00:00
}
}
2023-04-25 09:51:12 +00:00
func SendErrorToDiscord(err error) {
msg := fmt.Sprint(err)
log.Println(msg)
embed := discordgo.MessageEmbed{
Title: "Error",
Color: 0xff0000,
Description: msg,
}
SendEmbedToDiscord(&embed)
}