summaryrefslogtreecommitdiff
path: root/teleirc/matterbridge/bridge/telegram/telegram.go
diff options
context:
space:
mode:
authorMistivia <i@mistivia.com>2025-11-02 15:27:18 +0800
committerMistivia <i@mistivia.com>2025-11-02 15:27:18 +0800
commite9c24f4af7ed56760f6db7941827d09f6db9020b (patch)
tree62128c43b883ce5e3148113350978755779bb5de /teleirc/matterbridge/bridge/telegram/telegram.go
parent58d5e7cfda4781d8a57ec52aefd02983835c301a (diff)
add matterbridge
Diffstat (limited to 'teleirc/matterbridge/bridge/telegram/telegram.go')
-rw-r--r--teleirc/matterbridge/bridge/telegram/telegram.go205
1 files changed, 205 insertions, 0 deletions
diff --git a/teleirc/matterbridge/bridge/telegram/telegram.go b/teleirc/matterbridge/bridge/telegram/telegram.go
new file mode 100644
index 0000000..43cb818
--- /dev/null
+++ b/teleirc/matterbridge/bridge/telegram/telegram.go
@@ -0,0 +1,205 @@
+package btelegram
+
+import (
+ "fmt"
+ "html"
+ "log"
+ "strconv"
+ "strings"
+
+ "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"
+)
+
+const (
+ unknownUser = "unknown"
+ HTMLFormat = "HTML"
+ HTMLNick = "htmlnick"
+ MarkdownV2 = "MarkdownV2"
+)
+
+type Btelegram struct {
+ c *tgbotapi.BotAPI
+ *bridge.Config
+ avatarMap map[string]string // keep cache of userid and avatar sha
+}
+
+func New(cfg *bridge.Config) bridge.Bridger {
+ tgsConvertFormat := cfg.GetString("MediaConvertTgs")
+ if tgsConvertFormat != "" {
+ err := helper.CanConvertTgsToX()
+ if err != nil {
+ log.Fatalf("Telegram bridge configured to convert .tgs files to '%s', but %s does not appear to work:\n%#v", tgsConvertFormat, helper.LottieBackend(), err)
+ }
+ if !helper.SupportsFormat(tgsConvertFormat) {
+ log.Fatalf("Telegram bridge configured to convert .tgs files to '%s', but %s doesn't support it.", tgsConvertFormat, helper.LottieBackend())
+ }
+ }
+ return &Btelegram{Config: cfg, avatarMap: make(map[string]string)}
+}
+
+func (b *Btelegram) Connect() error {
+ var err error
+ b.Log.Info("Connecting")
+ b.c, err = tgbotapi.NewBotAPI(b.GetString("Token"))
+ if err != nil {
+ b.Log.Debugf("%#v", err)
+ return err
+ }
+ u := tgbotapi.NewUpdate(0)
+ u.Timeout = 60
+ updates := b.c.GetUpdatesChan(u)
+ b.Log.Info("Connection succeeded")
+ go b.handleRecv(updates)
+ return nil
+}
+
+func (b *Btelegram) Disconnect() error {
+ return nil
+}
+
+func (b *Btelegram) JoinChannel(channel config.ChannelInfo) error {
+ return nil
+}
+
+func TGGetParseMode(b *Btelegram, username string, text string) (textout string, parsemode string) {
+ textout = username + text
+ if b.GetString("MessageFormat") == HTMLFormat {
+ b.Log.Debug("Using mode HTML")
+ parsemode = tgbotapi.ModeHTML
+ }
+ if b.GetString("MessageFormat") == "Markdown" {
+ b.Log.Debug("Using mode markdown")
+ parsemode = tgbotapi.ModeMarkdown
+ }
+ if b.GetString("MessageFormat") == MarkdownV2 {
+ b.Log.Debug("Using mode MarkdownV2")
+ parsemode = MarkdownV2
+ }
+ if strings.ToLower(b.GetString("MessageFormat")) == HTMLNick {
+ b.Log.Debug("Using mode HTML - nick only")
+ textout = username + html.EscapeString(text)
+ parsemode = tgbotapi.ModeHTML
+ }
+ return textout, parsemode
+}
+
+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)
+ if err != nil {
+ return "", err
+ }
+
+ // map the file SHA to our user (caches the avatar)
+ if msg.Event == config.EventAvatarDownload {
+ return b.cacheAvatar(&msg)
+ }
+
+ if b.GetString("MessageFormat") == HTMLFormat {
+ msg.Text = makeHTML(html.EscapeString(msg.Text))
+ }
+
+ // Delete message
+ if msg.Event == config.EventMsgDelete {
+ return b.handleDelete(&msg, chatid)
+ }
+
+ // Handle prefix hint for unthreaded messages.
+ if msg.ParentNotFound() {
+ msg.ParentID = ""
+ 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, 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)
+ }
+ }
+
+ // edit the message if we have a msg ID
+ if msg.ID != "" {
+ return b.handleEdit(&msg, chatid)
+ }
+
+ // Post normal message
+ // TODO: recheck it.
+ // 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 "", nil
+}
+
+func (b *Btelegram) getFileDirectURL(id string) string {
+ res, err := b.c.GetFileDirectURL(id)
+ if err != nil {
+ return ""
+ }
+ return res
+}
+
+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)
+ m.ReplyToMessageID = parentID
+ m.DisableWebPagePreview = b.GetBool("DisableWebPagePreview")
+
+ res, err := b.c.Send(m)
+ if err != nil {
+ return "", err
+ }
+ 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,
+ so we can now cache the sha */
+ if fi.SHA != "" {
+ b.Log.Debugf("Added %s to %s in avatarMap", fi.SHA, msg.UserID)
+ b.avatarMap[msg.UserID] = fi.SHA
+ }
+ return "", nil
+}