edits: bridge Matrix -> TG
Signed-off-by: Sumner Evans <sumner.evans@automattic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
|||||||
up "go.mau.fi/util/configupgrade"
|
up "go.mau.fi/util/configupgrade"
|
||||||
"maunium.net/go/mautrix/bridgev2"
|
"maunium.net/go/mautrix/bridgev2"
|
||||||
"maunium.net/go/mautrix/bridgev2/database"
|
"maunium.net/go/mautrix/bridgev2/database"
|
||||||
|
"maunium.net/go/mautrix/id"
|
||||||
|
|
||||||
"go.mau.fi/mautrix-telegram/pkg/connector/media"
|
"go.mau.fi/mautrix-telegram/pkg/connector/media"
|
||||||
)
|
)
|
||||||
@@ -92,7 +93,8 @@ type GhostMetadata struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MessageMetadata 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 {
|
type UserLoginMetadata struct {
|
||||||
|
|||||||
+133
-3
@@ -13,10 +13,12 @@ import (
|
|||||||
"github.com/gotd/td/telegram/message/styling"
|
"github.com/gotd/td/telegram/message/styling"
|
||||||
"github.com/gotd/td/telegram/uploader"
|
"github.com/gotd/td/telegram/uploader"
|
||||||
"github.com/gotd/td/tg"
|
"github.com/gotd/td/tg"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"maunium.net/go/mautrix/bridgev2"
|
"maunium.net/go/mautrix/bridgev2"
|
||||||
"maunium.net/go/mautrix/bridgev2/database"
|
"maunium.net/go/mautrix/bridgev2/database"
|
||||||
"maunium.net/go/mautrix/bridgev2/networkid"
|
"maunium.net/go/mautrix/bridgev2/networkid"
|
||||||
"maunium.net/go/mautrix/event"
|
"maunium.net/go/mautrix/event"
|
||||||
|
"maunium.net/go/mautrix/id"
|
||||||
|
|
||||||
"go.mau.fi/util/variationselector"
|
"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)
|
builder := message.NewSender(t.client.API()).To(peer)
|
||||||
|
|
||||||
|
var contentURI id.ContentURIString
|
||||||
// TODO handle sticker
|
// TODO handle sticker
|
||||||
|
|
||||||
var updates tg.UpdatesClass
|
var updates tg.UpdatesClass
|
||||||
switch msg.Content.MsgType {
|
switch msg.Content.MsgType {
|
||||||
case event.MsgText:
|
case event.MsgText:
|
||||||
|
// TODO unify with edits?
|
||||||
if msg.Content.BeeperLinkPreviews != nil && len(msg.Content.BeeperLinkPreviews) == 0 {
|
if msg.Content.BeeperLinkPreviews != nil && len(msg.Content.BeeperLinkPreviews) == 0 {
|
||||||
builder.NoWebpage()
|
builder.NoWebpage()
|
||||||
}
|
}
|
||||||
@@ -62,6 +66,11 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to download media from Matrix: %w", err)
|
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())
|
uploader := uploader.NewUploader(t.client.API())
|
||||||
var upload tg.InputFileClass
|
var upload tg.InputFileClass
|
||||||
upload, err = uploader.FromBytes(ctx, filename, fileData)
|
upload, err = uploader.FromBytes(ctx, filename, fileData)
|
||||||
@@ -132,13 +141,13 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
|
|||||||
}
|
}
|
||||||
|
|
||||||
hasher := sha256.New()
|
hasher := sha256.New()
|
||||||
hasher.Write([]byte(msg.Content.Body))
|
|
||||||
|
|
||||||
var tgMessageID, tgDate int
|
var tgMessageID, tgDate int
|
||||||
switch sentMessage := updates.(type) {
|
switch sentMessage := updates.(type) {
|
||||||
case *tg.UpdateShortSentMessage:
|
case *tg.UpdateShortSentMessage:
|
||||||
tgMessageID = sentMessage.ID
|
tgMessageID = sentMessage.ID
|
||||||
tgDate = sentMessage.Date
|
tgDate = sentMessage.Date
|
||||||
|
hasher.Write([]byte(msg.Content.Body))
|
||||||
case *tg.Updates:
|
case *tg.Updates:
|
||||||
tgDate = sentMessage.Date
|
tgDate = sentMessage.Date
|
||||||
for _, u := range sentMessage.Updates {
|
for _, u := range sentMessage.Updates {
|
||||||
@@ -147,6 +156,7 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
|
|||||||
tgMessageID = update.ID
|
tgMessageID = update.ID
|
||||||
case *tg.UpdateNewMessage:
|
case *tg.UpdateNewMessage:
|
||||||
msg := update.Message.(*tg.Message)
|
msg := update.Message.(*tg.Message)
|
||||||
|
hasher.Write([]byte(msg.Message))
|
||||||
hasher.Write(mediaHashID(msg.Media))
|
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},
|
Room: networkid.PortalKey{ID: msg.Portal.ID},
|
||||||
SenderID: t.userID,
|
SenderID: t.userID,
|
||||||
Timestamp: time.Unix(int64(tgDate), 0),
|
Timestamp: time.Unix(int64(tgDate), 0),
|
||||||
Metadata: &MessageMetadata{ContentHash: hasher.Sum(nil)},
|
Metadata: &MessageMetadata{
|
||||||
|
ContentHash: hasher.Sum(nil),
|
||||||
|
ContentURI: contentURI,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TelegramClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.MatrixEdit) error {
|
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 {
|
func (t *TelegramClient) HandleMatrixMessageRemove(ctx context.Context, msg *bridgev2.MatrixMessageRemove) error {
|
||||||
|
|||||||
@@ -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)
|
mediaPart, disappearingSetting, mediaHashID, err := c.mediaToMatrix(ctx, portal, intent, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -138,11 +139,19 @@ func (c *TelegramClient) convertToMatrix(ctx context.Context, portal *bridgev2.P
|
|||||||
cm.Parts = append(cm.Parts, mediaPart)
|
cm.Parts = append(cm.Parts, mediaPart)
|
||||||
cm.MergeCaption()
|
cm.MergeCaption()
|
||||||
|
|
||||||
|
contentURI = mediaPart.Content.URL
|
||||||
|
if contentURI == "" {
|
||||||
|
contentURI = mediaPart.Content.File.URL
|
||||||
|
}
|
||||||
|
|
||||||
if disappearingSetting != nil {
|
if disappearingSetting != nil {
|
||||||
cm.Disappear = *disappearingSetting
|
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
|
return cm, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user