package discord import ( "context" "strings" "github.com/bwmarrin/discordgo" ) // API is the Discord REST surface used by the outbound subscriber. type API interface { SendToChannel(ctx context.Context, channelID string, msg Message) (messageID string, err error) StartThread(ctx context.Context, channelID, name string) (threadID string, err error) SendToThread(ctx context.Context, threadID string, msg Message) (messageID string, err error) Edit(ctx context.Context, channelID, messageID string, msg Message) error Close() error } type sessionAPI struct { session *discordgo.Session } func (s *sessionAPI) SendToChannel(_ context.Context, channelID string, msg Message) (string, error) { sent, err := s.session.ChannelMessageSendComplex(channelID, toMessageSend(msg)) if err != nil { return "", err } return sent.ID, nil } func (s *sessionAPI) StartThread(_ context.Context, channelID, name string) (string, error) { thread, err := s.session.ThreadStartComplex(channelID, &discordgo.ThreadStart{ Name: name, Type: discordgo.ChannelTypeGuildPublicThread, AutoArchiveDuration: 10080, }) if err != nil { return "", err } return thread.ID, nil } func (s *sessionAPI) SendToThread(ctx context.Context, threadID string, msg Message) (string, error) { return s.SendToChannel(ctx, threadID, msg) } func (s *sessionAPI) Edit(_ context.Context, channelID, messageID string, msg Message) error { content := messageContent(msg) embeds := toEmbeds(msg) _, err := s.session.ChannelMessageEditComplex(&discordgo.MessageEdit{ ID: messageID, Channel: channelID, Content: &content, Embeds: &embeds, }) return err } func (s *sessionAPI) Close() error { if s == nil || s.session == nil { return nil } return s.session.Close() } func toMessageSend(msg Message) *discordgo.MessageSend { var files []*discordgo.File for _, f := range msg.Files { files = append(files, &discordgo.File{ Name: f.Name, ContentType: f.ContentType, Reader: f.Reader, }) } return &discordgo.MessageSend{ Content: messageContent(msg), Embeds: toEmbeds(msg), Files: files, AllowedMentions: &discordgo.MessageAllowedMentions{}, } } func toEmbeds(msg Message) []*discordgo.MessageEmbed { imageURLs := embedImageURLs(msg) if msg.Title == "" && msg.Description == "" && msg.City == "" && msg.Author == "" && len(imageURLs) == 0 { return nil } main := &discordgo.MessageEmbed{ Title: msg.Title, URL: publicURL(msg.URL), Description: msg.Description, Color: embedColor, } if msg.City != "" { main.Fields = append(main.Fields, &discordgo.MessageEmbedField{ Name: "City", Value: msg.City, Inline: true, }) } if msg.Author != "" { main.Fields = append(main.Fields, &discordgo.MessageEmbedField{ Name: "Author", Value: msg.Author, Inline: true, }) } embeds := []*discordgo.MessageEmbed{main} for i, url := range imageURLs { if i == 0 { main.Image = &discordgo.MessageEmbedImage{URL: url} continue } embeds = append(embeds, &discordgo.MessageEmbed{ Color: embedColor, Image: &discordgo.MessageEmbedImage{URL: url}, }) } return embeds } func embedImageURLs(msg Message) []string { var attached []string for _, f := range msg.Files { if strings.HasPrefix(f.ContentType, "image/") { attached = append(attached, "attachment://"+f.Name) } } if len(attached) > 0 { return attached } return msg.ImageURLs }