4
0
mirror of https://github.com/cwinfo/matterbridge.git synced 2025-06-26 00:39:24 +00:00

Add support for Telegram topics (telegram) (#1942)

Topics are surfaced by appending /<topic-id> to the channel setting for the gateway. 
An example for the topic with ID of 16 would be:

```
[[gateway.inout]]
account="telegram.mytelegram"
channel="-100xxxxxxxxxx/16"
```
This commit is contained in:
Thom Dickson
2023-03-14 18:03:04 -04:00
committed by GitHub
parent c2b8e298d8
commit 601f48a50e
16 changed files with 1266 additions and 121 deletions

View File

@ -11,7 +11,7 @@ import (
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper"
"github.com/davecgh/go-spew/spew"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
tgbotapi "github.com/matterbridge/telegram-bot-api/v6"
)
func (b *Btelegram) handleUpdate(rmsg *config.Message, message, posted, edited *tgbotapi.Message) *tgbotapi.Message {
@ -20,6 +20,11 @@ func (b *Btelegram) handleUpdate(rmsg *config.Message, message, posted, edited *
if posted.Text == "/chatId" {
chatID := strconv.FormatInt(posted.Chat.ID, 10)
// Handle chat topics
if posted.IsTopicMessage {
chatID = chatID + "/" + strconv.Itoa(posted.MessageThreadID)
}
_, err := b.Send(config.Message{
Channel: chatID,
Text: fmt.Sprintf("ID of this chat: %s", chatID),
@ -91,7 +96,8 @@ func (b *Btelegram) handleForwarded(rmsg *config.Message, message *tgbotapi.Mess
// handleQuoting handles quoting of previous messages
func (b *Btelegram) handleQuoting(rmsg *config.Message, message *tgbotapi.Message) {
if message.ReplyToMessage != nil {
// Used to check if the message was a reply to the root topic
if message.ReplyToMessage != nil && !(message.ReplyToMessage.MessageID == message.MessageThreadID) { //nolint:nestif
usernameReply := ""
if message.ReplyToMessage.From != nil {
if b.GetBool("UseFirstName") {
@ -211,9 +217,14 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
// set the ID's from the channel or group message
rmsg.ID = strconv.Itoa(message.MessageID)
rmsg.Channel = strconv.FormatInt(message.Chat.ID, 10)
if message.MessageThreadID != 0 {
rmsg.Channel += "/" + strconv.Itoa(message.MessageThreadID)
}
// preserve threading from telegram reply
if message.ReplyToMessage != nil {
if message.ReplyToMessage != nil &&
// Used to check if the message was a reply to the root topic
!(message.ReplyToMessage.MessageID == message.MessageThreadID) {
rmsg.ParentID = strconv.Itoa(message.ReplyToMessage.MessageID)
}
@ -326,12 +337,12 @@ func (b *Btelegram) maybeConvertWebp(name *string, data *[]byte) {
// handleDownloadFile handles file download
func (b *Btelegram) handleDownload(rmsg *config.Message, message *tgbotapi.Message) error {
size := 0
size := int64(0)
var url, name, text string
switch {
case message.Sticker != nil:
text, name, url = b.getDownloadInfo(message.Sticker.FileID, ".webp", true)
size = message.Sticker.FileSize
size = int64(message.Sticker.FileSize)
case message.Voice != nil:
text, name, url = b.getDownloadInfo(message.Voice.FileID, ".ogg", true)
size = message.Voice.FileSize
@ -348,7 +359,7 @@ func (b *Btelegram) handleDownload(rmsg *config.Message, message *tgbotapi.Messa
text = " " + message.Document.FileName + " : " + url
case message.Photo != nil:
photos := message.Photo
size = photos[len(photos)-1].FileSize
size = int64(photos[len(photos)-1].FileSize)
text, name, url = b.getDownloadInfo(photos[len(photos)-1].FileID, "", true)
}
@ -452,7 +463,7 @@ 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, parentID int) (string, error) {
func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64, threadid int, parentID int) (string, error) {
var media []interface{}
for _, f := range msg.Extra["file"] {
fi := f.(config.FileInfo)
@ -502,7 +513,7 @@ func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64, parentID
}
}
return b.sendMediaFiles(msg, chatid, parentID, media)
return b.sendMediaFiles(msg, chatid, threadid, parentID, media)
}
func (b *Btelegram) handleQuote(message, quoteNick, quoteMessage string) string {

View File

@ -10,7 +10,7 @@ import (
"github.com/42wim/matterbridge/bridge"
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/helper"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
tgbotapi "github.com/matterbridge/telegram-bot-api/v6"
)
const (
@ -86,11 +86,41 @@ func TGGetParseMode(b *Btelegram, username string, text string) (textout string,
return textout, parsemode
}
func (b *Btelegram) getIds(channel string) (int64, int, error) {
var chatid int64
topicid := 0
// get the chatid
if strings.Contains(channel, "/") { //nolint:nestif
s := strings.Split(channel, "/")
if len(s) < 2 {
b.Log.Errorf("Invalid channel format: %#v\n", channel)
return 0, 0, nil
}
id, err := strconv.ParseInt(s[0], 10, 64)
if err != nil {
return 0, 0, err
}
chatid = id
tid, err := strconv.Atoi(s[1])
if err != nil {
return 0, 0, err
}
topicid = tid
} else {
id, err := strconv.ParseInt(channel, 10, 64)
if err != nil {
return 0, 0, err
}
chatid = id
}
return chatid, topicid, nil
}
func (b *Btelegram) Send(msg config.Message) (string, error) {
b.Log.Debugf("=> Receiving %#v", msg)
// get the chatid
chatid, err := strconv.ParseInt(msg.Channel, 10, 64)
chatid, topicid, err := b.getIds(msg.Channel)
if err != nil {
return "", err
}
@ -123,13 +153,13 @@ func (b *Btelegram) Send(msg config.Message) (string, error) {
// 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, parentID); msgErr != nil {
if _, msgErr := b.sendMessage(chatid, topicid, 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 {
return b.handleUploadFile(&msg, chatid, parentID)
return b.handleUploadFile(&msg, chatid, topicid, parentID)
}
}
@ -143,7 +173,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, parentID)
return b.sendMessage(chatid, topicid, msg.Username, msg.Text, parentID)
}
return "", nil
@ -157,9 +187,12 @@ func (b *Btelegram) getFileDirectURL(id string) string {
return res
}
func (b *Btelegram) sendMessage(chatid int64, username, text string, parentID int) (string, error) {
func (b *Btelegram) sendMessage(chatid int64, topicid int, username, text string, parentID int) (string, error) {
m := tgbotapi.NewMessage(chatid, "")
m.Text, m.ParseMode = TGGetParseMode(b, username, text)
if topicid != 0 {
m.BaseChat.MessageThreadID = topicid
}
m.ReplyToMessageID = parentID
m.DisableWebPagePreview = b.GetBool("DisableWebPagePreview")
@ -171,11 +204,19 @@ func (b *Btelegram) sendMessage(chatid int64, username, text string, parentID in
}
// sendMediaFiles native upload media files via media group
func (b *Btelegram) sendMediaFiles(msg *config.Message, chatid int64, parentID int, media []interface{}) (string, error) {
func (b *Btelegram) sendMediaFiles(msg *config.Message, chatid int64, threadid int, parentID int, media []interface{}) (string, error) {
if len(media) == 0 {
return "", nil
}
mg := tgbotapi.MediaGroupConfig{ChatID: chatid, ChannelUsername: msg.Username, Media: media, ReplyToMessageID: parentID}
mg := tgbotapi.MediaGroupConfig{
BaseChat: tgbotapi.BaseChat{
ChatID: chatid,
MessageThreadID: threadid,
ChannelUsername: msg.Username,
ReplyToMessageID: parentID,
},
Media: media,
}
messages, err := b.c.SendMediaGroup(mg)
if err != nil {
return "", err