From 30aae8e257007adde40a522a0ac29cfdc39b80da Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 30 Mar 2022 23:23:52 +0300 Subject: [PATCH] Multiple media in one message (telegram) (#1779) * Send multiple images/video/documents as media group * Fix media caption quotting * Fix errors handling * Refactor parent id detection * Try to reduce cognitive complexity of code * Remove unused conditional --- bridge/telegram/handlers.go | 56 +++++++++++++++++++++++-------------- bridge/telegram/telegram.go | 44 +++++++++++++++++++++-------- 2 files changed, 68 insertions(+), 32 deletions(-) diff --git a/bridge/telegram/handlers.go b/bridge/telegram/handlers.go index 6267c12b..e4c2a36e 100644 --- a/bridge/telegram/handlers.go +++ b/bridge/telegram/handlers.go @@ -111,7 +111,11 @@ func (b *Btelegram) handleQuoting(rmsg *config.Message, message *tgbotapi.Messag usernameReply = unknownUser } if !b.GetBool("QuoteDisable") { - rmsg.Text = b.handleQuote(rmsg.Text, usernameReply, message.ReplyToMessage.Text) + quote := message.ReplyToMessage.Text + if quote == "" { + quote = message.ReplyToMessage.Caption + } + rmsg.Text = b.handleQuote(rmsg.Text, usernameReply, quote) } } } @@ -439,8 +443,8 @@ func (b *Btelegram) handleEdit(msg *config.Message, chatid int64) (string, error } // handleUploadFile handles native upload of files -func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64) string { - var c tgbotapi.Chattable +func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64, parentID int) (string, error) { + var media []interface{} for _, f := range msg.Extra["file"] { fi := f.(config.FileInfo) file := tgbotapi.FileBytes{ @@ -449,32 +453,42 @@ func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64) string { } switch filepath.Ext(fi.Name) { case ".jpg", ".jpe", ".png": - pc := tgbotapi.NewPhoto(chatid, file) - pc.Caption, pc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) - c = pc + pc := tgbotapi.NewInputMediaPhoto(file) + if fi.Comment != "" { + pc.Caption, pc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) + } + media = append(media, pc) case ".mp4", ".m4v": - vc := tgbotapi.NewVideo(chatid, file) - vc.Caption, vc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) - c = vc + vc := tgbotapi.NewInputMediaVideo(file) + if fi.Comment != "" { + vc.Caption, vc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) + } + media = append(media, vc) case ".mp3", ".oga": - ac := tgbotapi.NewAudio(chatid, file) - ac.Caption, ac.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) - c = ac + ac := tgbotapi.NewInputMediaAudio(file) + if fi.Comment != "" { + ac.Caption, ac.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) + } + media = append(media, ac) case ".ogg": voc := tgbotapi.NewVoice(chatid, file) voc.Caption, voc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) - c = voc + voc.ReplyToMessageID = parentID + res, err := b.c.Send(voc) + if err != nil { + return "", err + } + return strconv.Itoa(res.MessageID), nil default: - dc := tgbotapi.NewDocument(chatid, file) - dc.Caption, dc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) - c = dc - } - _, err := b.c.Send(c) - if err != nil { - b.Log.Errorf("file upload failed: %#v", err) + dc := tgbotapi.NewInputMediaDocument(file) + if fi.Comment != "" { + dc.Caption, dc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) + } + media = append(media, dc) } } - return "" + + return b.sendMediaFiles(msg, chatid, parentID, media) } func (b *Btelegram) handleQuote(message, quoteNick, quoteMessage string) string { diff --git a/bridge/telegram/telegram.go b/bridge/telegram/telegram.go index 1b648309..25225416 100644 --- a/bridge/telegram/telegram.go +++ b/bridge/telegram/telegram.go @@ -115,16 +115,21 @@ func (b *Btelegram) Send(msg config.Message) (string, error) { msg.Text = fmt.Sprintf("[reply]: %s", msg.Text) } + var parentID int + if msg.ParentID != "" { + parentID, _ = b.intParentID(msg.ParentID) + } + // Upload a file if it exists if msg.Extra != nil { for _, rmsg := range helper.HandleExtra(&msg, b.General) { - if _, msgErr := b.sendMessage(chatid, rmsg.Username, rmsg.Text, msg.ParentID); msgErr != nil { + if _, msgErr := b.sendMessage(chatid, rmsg.Username, rmsg.Text, parentID); msgErr != nil { b.Log.Errorf("sendMessage failed: %s", msgErr) } } // check if we have files to upload (from slack, telegram or mattermost) if len(msg.Extra["file"]) > 0 { - b.handleUploadFile(&msg, chatid) + return b.handleUploadFile(&msg, chatid, parentID) } } @@ -138,7 +143,7 @@ func (b *Btelegram) Send(msg config.Message) (string, error) { // Ignore empty text field needs for prevent double messages from whatsapp to telegram // when sending media with text caption if msg.Text != "" { - return b.sendMessage(chatid, msg.Username, msg.Text, msg.ParentID) + return b.sendMessage(chatid, msg.Username, msg.Text, parentID) } return "", nil @@ -152,16 +157,10 @@ func (b *Btelegram) getFileDirectURL(id string) string { return res } -func (b *Btelegram) sendMessage(chatid int64, username, text, parentID string) (string, error) { +func (b *Btelegram) sendMessage(chatid int64, username, text string, parentID int) (string, error) { m := tgbotapi.NewMessage(chatid, "") m.Text, m.ParseMode = TGGetParseMode(b, username, text) - if parentID != "" { - rmid, err := strconv.Atoi(parentID) - if err != nil { - return "", err - } - m.ReplyToMessageID = rmid - } + m.ReplyToMessageID = parentID m.DisableWebPagePreview = b.GetBool("DisableWebPagePreview") res, err := b.c.Send(m) @@ -171,6 +170,29 @@ func (b *Btelegram) sendMessage(chatid int64, username, text, parentID string) ( return strconv.Itoa(res.MessageID), nil } +// sendMediaFiles native upload media files via media group +func (b *Btelegram) sendMediaFiles(msg *config.Message, chatid int64, parentID int, media []interface{}) (string, error) { + if len(media) == 0 { + return "", nil + } + mg := tgbotapi.MediaGroupConfig{ChatID: chatid, ChannelUsername: msg.Username, Media: media, ReplyToMessageID: parentID} + messages, err := b.c.SendMediaGroup(mg) + if err != nil { + return "", err + } + // return first message id + return strconv.Itoa(messages[0].MessageID), nil +} + +// intParentID return integer parent id for telegram message +func (b *Btelegram) intParentID(parentID string) (int, error) { + pid, err := strconv.Atoi(parentID) + if err != nil { + return 0, err + } + return pid, nil +} + func (b *Btelegram) cacheAvatar(msg *config.Message) (string, error) { fi := msg.Extra["file"][0].(config.FileInfo) /* if we have a sha we have successfully uploaded the file to the media server,