edits: bridge Matrix -> TG

Signed-off-by: Sumner Evans <sumner.evans@automattic.com>
This commit is contained in:
Sumner Evans
2024-07-19 14:22:02 -06:00
parent 314b2da99f
commit 5ea342e788
3 changed files with 146 additions and 5 deletions
+3 -1
View File
@@ -8,6 +8,7 @@ import (
up "go.mau.fi/util/configupgrade"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/database"
"maunium.net/go/mautrix/id"
"go.mau.fi/mautrix-telegram/pkg/connector/media"
)
@@ -92,7 +93,8 @@ type GhostMetadata struct {
}
type MessageMetadata struct {
ContentHash []byte `json:"content_hash,omitempty"`
ContentHash []byte `json:"content_hash,omitempty"`
ContentURI id.ContentURIString `json:"content_uri,omitempty"`
}
type UserLoginMetadata struct {
+133 -3
View File
@@ -13,10 +13,12 @@ import (
"github.com/gotd/td/telegram/message/styling"
"github.com/gotd/td/telegram/uploader"
"github.com/gotd/td/tg"
"github.com/rs/zerolog"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/database"
"maunium.net/go/mautrix/bridgev2/networkid"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
"go.mau.fi/util/variationselector"
@@ -45,11 +47,13 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
}
builder := message.NewSender(t.client.API()).To(peer)
var contentURI id.ContentURIString
// TODO handle sticker
var updates tg.UpdatesClass
switch msg.Content.MsgType {
case event.MsgText:
// TODO unify with edits?
if msg.Content.BeeperLinkPreviews != nil && len(msg.Content.BeeperLinkPreviews) == 0 {
builder.NoWebpage()
}
@@ -62,6 +66,11 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
if err != nil {
return nil, fmt.Errorf("failed to download media from Matrix: %w", err)
}
contentURI = msg.Content.URL
if contentURI == "" {
contentURI = msg.Content.File.URL
}
uploader := uploader.NewUploader(t.client.API())
var upload tg.InputFileClass
upload, err = uploader.FromBytes(ctx, filename, fileData)
@@ -132,13 +141,13 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
}
hasher := sha256.New()
hasher.Write([]byte(msg.Content.Body))
var tgMessageID, tgDate int
switch sentMessage := updates.(type) {
case *tg.UpdateShortSentMessage:
tgMessageID = sentMessage.ID
tgDate = sentMessage.Date
hasher.Write([]byte(msg.Content.Body))
case *tg.Updates:
tgDate = sentMessage.Date
for _, u := range sentMessage.Updates {
@@ -147,6 +156,7 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
tgMessageID = update.ID
case *tg.UpdateNewMessage:
msg := update.Message.(*tg.Message)
hasher.Write([]byte(msg.Message))
hasher.Write(mediaHashID(msg.Media))
}
}
@@ -164,14 +174,134 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
Room: networkid.PortalKey{ID: msg.Portal.ID},
SenderID: t.userID,
Timestamp: time.Unix(int64(tgDate), 0),
Metadata: &MessageMetadata{ContentHash: hasher.Sum(nil)},
Metadata: &MessageMetadata{
ContentHash: hasher.Sum(nil),
ContentURI: contentURI,
},
},
}
return
}
func (t *TelegramClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.MatrixEdit) error {
panic("unimplemented edit")
log := zerolog.Ctx(ctx).With().
Str("conversion_direction", "to_telegram").
Str("handler", "matrix_edit").
Logger()
peer, err := t.inputPeerForPortalID(ctx, msg.Portal.ID)
if err != nil {
return err
}
b := message.NewSender(t.client.API()).To(peer)
if msg.Content.MsgType == event.MsgText && msg.Content.BeeperLinkPreviews != nil && len(msg.Content.BeeperLinkPreviews) == 0 {
b.NoWebpage()
}
targetID, err := ids.ParseMessageID(msg.EditTarget.ID)
if err != nil {
return err
}
builder := b.Edit(targetID)
var newContentURI id.ContentURIString
var updates tg.UpdatesClass
switch msg.Content.MsgType {
case event.MsgText:
updates, err = builder.Text(ctx, msg.Content.Body)
case event.MsgImage, event.MsgFile, event.MsgAudio, event.MsgVideo:
filename, caption := getMediaFilenameAndCaption(msg.Content)
var styling []styling.StyledTextOption
if caption != "" {
// TODO resolver?
// TODO HTML
styling = append(styling, html.String(nil, caption))
}
newContentURI = msg.Content.URL
if newContentURI == "" {
newContentURI = msg.Content.File.URL
}
if msg.EditTarget.Metadata.(*MessageMetadata).ContentURI == newContentURI {
log.Info().Msg("media URI unchanged, skipping re-upload, just editing text")
updates, err = builder.StyledText(ctx, styling...)
break
}
log.Info().Msg("media URI changed, re-uploading media")
var fileData []byte
fileData, err = t.main.Bridge.Bot.DownloadMedia(ctx, msg.Content.URL, msg.Content.File)
if err != nil {
return fmt.Errorf("failed to download media from Matrix: %w", err)
}
uploader := uploader.NewUploader(t.client.API())
var upload tg.InputFileClass
upload, err = uploader.FromBytes(ctx, filename, fileData)
if err != nil {
return fmt.Errorf("failed to upload media to Telegram: %w", err)
}
if msg.Content.MsgType == event.MsgImage {
updates, err = builder.Media(ctx, message.UploadedPhoto(upload, styling...))
break
} else {
document := message.UploadedDocument(upload, styling...).Filename(filename)
if msg.Content.Info != nil {
document.MIME(msg.Content.Info.MimeType)
}
var media message.MediaOption
switch msg.Content.MsgType {
case event.MsgAudio:
audioBuilder := document.Audio()
if msg.Content.MSC1767Audio != nil {
audioBuilder.Duration(time.Duration(msg.Content.MSC1767Audio.Duration) * time.Millisecond)
if len(msg.Content.MSC1767Audio.Waveform) > 0 {
audioBuilder.Waveform(waveform.Encode(msg.Content.MSC1767Audio.Waveform))
}
}
if msg.Content.MSC3245Voice != nil {
audioBuilder.Voice()
}
media = audioBuilder
default:
media = document
}
updates, err = builder.Media(ctx, media)
}
default:
return fmt.Errorf("unsupported message type %s", msg.Content.MsgType)
}
if err != nil {
return err
}
hasher := sha256.New()
switch sentMessage := updates.(type) {
case *tg.UpdateShortSentMessage:
hasher.Write([]byte(msg.Content.Body))
case *tg.Updates:
for _, u := range sentMessage.Updates {
switch update := u.(type) {
case *tg.UpdateNewMessage:
msg := update.Message.(*tg.Message)
hasher.Write([]byte(msg.Message))
hasher.Write(mediaHashID(msg.Media))
}
}
default:
return fmt.Errorf("unknown update from message response %T", updates)
}
metadata := msg.EditTarget.Metadata.(*MessageMetadata)
metadata.ContentHash = hasher.Sum(nil)
metadata.ContentURI = newContentURI
return nil
}
func (t *TelegramClient) HandleMatrixMessageRemove(ctx context.Context, msg *bridgev2.MatrixMessageRemove) error {
+10 -1
View File
@@ -130,6 +130,7 @@ func (c *TelegramClient) convertToMatrix(ctx context.Context, portal *bridgev2.P
}
}
var contentURI id.ContentURIString
mediaPart, disappearingSetting, mediaHashID, err := c.mediaToMatrix(ctx, portal, intent, msg)
if err != nil {
return nil, err
@@ -138,11 +139,19 @@ func (c *TelegramClient) convertToMatrix(ctx context.Context, portal *bridgev2.P
cm.Parts = append(cm.Parts, mediaPart)
cm.MergeCaption()
contentURI = mediaPart.Content.URL
if contentURI == "" {
contentURI = mediaPart.Content.File.URL
}
if disappearingSetting != nil {
cm.Disappear = *disappearingSetting
}
}
cm.Parts[0].DBMetadata = &MessageMetadata{ContentHash: hasher.Sum(nil)}
cm.Parts[0].DBMetadata = &MessageMetadata{
ContentHash: hasher.Sum(nil),
ContentURI: contentURI,
}
return cm, nil
}