diff --git a/pkg/connector/client.go b/pkg/connector/client.go
index ef98495..dc785e9 100644
--- a/pkg/connector/client.go
+++ b/pkg/connector/client.go
@@ -2,6 +2,7 @@ package connector
import (
"context"
+ "errors"
"fmt"
"strconv"
"time"
@@ -14,6 +15,8 @@ import (
"go.mau.fi/mautrix-meta/config"
"go.mau.fi/mautrix-meta/messagix"
"go.mau.fi/mautrix-meta/messagix/cookies"
+
+ //"go.mau.fi/mautrix-meta/messagix/socket"
"go.mau.fi/mautrix-meta/messagix/table"
"go.mau.fi/mautrix-meta/messagix/types"
@@ -21,8 +24,12 @@ import (
"maunium.net/go/mautrix/bridge/status"
"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/event"
+ metaTypes "go.mau.fi/mautrix-meta/messagix/types"
)
type metaEvent struct {
@@ -285,9 +292,132 @@ func (m *MetaClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) (*b
panic("unimplemented")
}
+type msgconvContextKey int
+
+const (
+ msgconvContextKeyIntent msgconvContextKey = iota
+ msgconvContextKeyClient
+ msgconvContextKeyE2EEClient
+ msgconvContextKeyBackfill
+)
+
// HandleMatrixMessage implements bridgev2.NetworkAPI.
-func (m *MetaClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.MatrixMessage) (message *bridgev2.MatrixMessageResponse, err error) {
- panic("unimplemented")
+func (m *MetaClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.MatrixMessage) (*bridgev2.MatrixMessageResponse, error) {
+ log := zerolog.Ctx(ctx)
+
+ content, ok := msg.Event.Content.Parsed.(*event.MessageEventContent)
+ if !ok {
+ log.Error().Type("content_type", content).Msg("Unexpected parsed content type")
+ return nil, fmt.Errorf("unexpected parsed content type: %T", content)
+ }
+ if content.MsgType == event.MsgNotice /*&& !portal.bridge.Config.Bridge.BridgeNotices*/ {
+ log.Warn().Msg("Ignoring notice message")
+ return nil, nil
+ }
+
+ ctx = context.WithValue(ctx, msgconvContextKeyClient, m.client)
+
+ thread, err := strconv.Atoi(string(msg.Portal.ID))
+ if err != nil {
+ log.Err(err).Str("thread_id", string(msg.Portal.ID)).Msg("Failed to parse thread ID")
+ return nil, fmt.Errorf("failed to parse thread ID: %w", err)
+ }
+
+ tasks, otid, err := m.messageConverter.ToMeta(ctx, msg.Event, content, false, int64(thread))
+ if errors.Is(err, metaTypes.ErrPleaseReloadPage) {
+ log.Err(err).Msg("Got please reload page error while converting message, reloading page in background")
+ // go m.client.Disconnect()
+ // err = errReloading
+ panic("unimplemented")
+ } else if errors.Is(err, messagix.ErrTokenInvalidated) {
+ panic("unimplemented")
+ // go sender.DisconnectFromError(status.BridgeState{
+ // StateEvent: status.StateBadCredentials,
+ // Error: MetaCookieRemoved,
+ // })
+ // err = errLoggedOut
+ }
+
+ if err != nil {
+ log.Err(err).Msg("Failed to convert message")
+ //go ms.sendMessageMetrics(evt, err, "Error converting", true)
+ return nil, err
+ }
+
+ log.UpdateContext(func(c zerolog.Context) zerolog.Context {
+ return c.Int64("otid", otid)
+ })
+ log.Debug().Msg("Sending Matrix message to Meta")
+
+ //otidStr := strconv.FormatInt(otid, 10)
+ //portal.pendingMessages[otid] = evt.ID
+ //messageTS := time.Now()
+ var resp *table.LSTable
+
+ retries := 0
+ for retries < 5 {
+ if err = m.client.WaitUntilCanSendMessages(15 * time.Second); err != nil {
+ log.Err(err).Msg("Error waiting to be able to send messages, retrying")
+ } else {
+ resp, err = m.client.ExecuteTasks(tasks...)
+ if err == nil {
+ break
+ }
+ log.Err(err).Msg("Failed to send message to Meta, retrying")
+ }
+ retries++
+ }
+
+ log.Trace().Any("response", resp).Msg("Meta send response")
+ // var msgID string
+ // if resp != nil && err == nil {
+ // for _, replace := range resp.LSReplaceOptimsiticMessage {
+ // if replace.OfflineThreadingId == otidStr {
+ // msgID = replace.MessageId
+ // }
+ // }
+ // if len(msgID) == 0 {
+ // for _, failed := range resp.LSMarkOptimisticMessageFailed {
+ // if failed.OTID == otidStr {
+ // log.Warn().Str("message", failed.Message).Msg("Sending message failed")
+ // //go ms.sendMessageMetrics(evt, fmt.Errorf("%w: %s", errServerRejected, failed.Message), "Error sending", true)
+ // return
+ // }
+ // }
+ // for _, failed := range resp.LSHandleFailedTask {
+ // if failed.OTID == otidStr {
+ // log.Warn().Str("message", failed.Message).Msg("Sending message failed")
+ // go ms.sendMessageMetrics(evt, fmt.Errorf("%w: %s", errServerRejected, failed.Message), "Error sending", true)
+ // return
+ // }
+ // }
+ // log.Warn().Msg("Message send response didn't include message ID")
+ // }
+ // }
+ // if msgID != "" {
+ // portal.pendingMessagesLock.Lock()
+ // _, ok = portal.pendingMessages[otid]
+ // if ok {
+ // portal.storeMessageInDB(ctx, evt.ID, msgID, otid, sender.MetaID, messageTS, 0)
+ // delete(portal.pendingMessages, otid)
+ // } else {
+ // log.Debug().Msg("Not storing message send response: pending message was already removed from map")
+ // }
+ // portal.pendingMessagesLock.Unlock()
+ // }
+
+ return &bridgev2.MatrixMessageResponse{
+ DB: &database.Message{
+ //ID: nil,
+ MXID: msg.Event.ID,
+ Room: networkid.PortalKey{ID: msg.Portal.ID},
+ //SenderID: nil,
+ Timestamp: time.Time{},
+ },
+ }, nil
+
+ // timings.totalSend = time.Since(start)
+ // go ms.sendMessageMetrics(evt, err, "Error sending", true)
}
// IsLoggedIn implements bridgev2.NetworkAPI.
diff --git a/pkg/connector/msgconv/from-matrix.go b/pkg/connector/msgconv/from-matrix.go
index fe070fb..b1073cf 100644
--- a/pkg/connector/msgconv/from-matrix.go
+++ b/pkg/connector/msgconv/from-matrix.go
@@ -20,20 +20,21 @@ import (
"context"
"errors"
"fmt"
- "net/http"
+
+ //"net/http"
"time"
- "github.com/rs/zerolog"
- "go.mau.fi/util/exerrors"
- "go.mau.fi/util/exmime"
- "go.mau.fi/util/ffmpeg"
+ //"github.com/rs/zerolog"
+ //"go.mau.fi/util/exerrors"
+ //"go.mau.fi/util/exmime"
+ //"go.mau.fi/util/ffmpeg"
"maunium.net/go/mautrix/event"
- "go.mau.fi/mautrix-meta/messagix"
+ //"go.mau.fi/mautrix-meta/messagix"
"go.mau.fi/mautrix-meta/messagix/methods"
"go.mau.fi/mautrix-meta/messagix/socket"
"go.mau.fi/mautrix-meta/messagix/table"
- "go.mau.fi/mautrix-meta/messagix/types"
+ //"go.mau.fi/mautrix-meta/messagix/types"
)
var (
@@ -46,20 +47,21 @@ var (
ErrURLNotFound = errors.New("url not found")
)
-func (mc *MessageConverter) ToMeta(ctx context.Context, evt *event.Event, content *event.MessageEventContent, relaybotFormatted bool) ([]socket.Task, int64, error) {
+func (mc *MessageConverter) ToMeta(ctx context.Context, evt *event.Event, content *event.MessageEventContent, relaybotFormatted bool, threadID int64) ([]socket.Task, int64, error) {
if evt.Type == event.EventSticker {
content.MsgType = event.MsgImage
}
task := &socket.SendMessageTask{
- ThreadId: mc.GetData(ctx).ThreadID,
+ //ThreadId: mc.GetData(ctx).ThreadID,
+ ThreadId: threadID,
Otid: methods.GenerateEpochId(),
Source: table.MESSENGER_INBOX_IN_THREAD,
InitiatingSource: table.FACEBOOK_INBOX,
SendType: table.TEXT,
SyncGroup: 1,
- ReplyMetaData: mc.GetMetaReply(ctx, content),
+ //ReplyMetaData: mc.GetMetaReply(ctx, content),
}
if content.MsgType == event.MsgEmote && !relaybotFormatted {
content.Body = "/me " + content.Body
@@ -70,22 +72,22 @@ func (mc *MessageConverter) ToMeta(ctx context.Context, evt *event.Event, conten
switch content.MsgType {
case event.MsgText, event.MsgNotice, event.MsgEmote:
task.Text = content.Body
- case event.MsgImage, event.MsgVideo, event.MsgAudio, event.MsgFile:
- resp, err := mc.reuploadFileToMeta(ctx, evt, content)
- if err != nil {
- return nil, 0, err
- }
- attachmentID := resp.Payload.RealMetadata.GetFbId()
- if attachmentID == 0 {
- zerolog.Ctx(ctx).Warn().RawJSON("response", resp.Raw).Msg("No fbid received for upload")
- return nil, 0, fmt.Errorf("failed to upload attachment: fbid not received")
- }
- task.SendType = table.MEDIA
- task.AttachmentFBIds = []int64{attachmentID}
- if content.FileName != "" && content.Body != content.FileName {
- // This might not actually be allowed
- task.Text = content.Body
- }
+ // case event.MsgImage, event.MsgVideo, event.MsgAudio, event.MsgFile:
+ // resp, err := mc.reuploadFileToMeta(ctx, evt, content)
+ // if err != nil {
+ // return nil, 0, err
+ // }
+ // attachmentID := resp.Payload.RealMetadata.GetFbId()
+ // if attachmentID == 0 {
+ // zerolog.Ctx(ctx).Warn().RawJSON("response", resp.Raw).Msg("No fbid received for upload")
+ // return nil, 0, fmt.Errorf("failed to upload attachment: fbid not received")
+ // }
+ // task.SendType = table.MEDIA
+ // task.AttachmentFBIds = []int64{attachmentID}
+ // if content.FileName != "" && content.Body != content.FileName {
+ // // This might not actually be allowed
+ // task.Text = content.Body
+ // }
case event.MsgLocation:
// TODO implement
fallthrough
@@ -101,65 +103,65 @@ func (mc *MessageConverter) ToMeta(ctx context.Context, evt *event.Event, conten
return []socket.Task{task, readTask}, task.Otid, nil
}
-func (mc *MessageConverter) downloadMatrixMedia(ctx context.Context, content *event.MessageEventContent) (data []byte, mimeType, fileName string, err error) {
- mxc := content.URL
- if content.File != nil {
- mxc = content.File.URL
- }
- data, err = mc.DownloadMatrixMedia(ctx, mxc)
- if err != nil {
- err = exerrors.NewDualError(ErrMediaDownloadFailed, err)
- return
- }
- if content.File != nil {
- err = content.File.DecryptInPlace(data)
- if err != nil {
- err = exerrors.NewDualError(ErrMediaDecryptFailed, err)
- return
- }
- }
- mimeType = content.GetInfo().MimeType
- if mimeType == "" {
- mimeType = http.DetectContentType(data)
- }
- fileName = content.FileName
- if fileName == "" {
- fileName = content.Body
- if fileName == "" {
- fileName = string(content.MsgType)[2:] + exmime.ExtensionFromMimetype(mimeType)
- }
- }
- return
-}
+// func (mc *MessageConverter) downloadMatrixMedia(ctx context.Context, content *event.MessageEventContent) (data []byte, mimeType, fileName string, err error) {
+// mxc := content.URL
+// if content.File != nil {
+// mxc = content.File.URL
+// }
+// data, err = mc.DownloadMatrixMedia(ctx, mxc)
+// if err != nil {
+// err = exerrors.NewDualError(ErrMediaDownloadFailed, err)
+// return
+// }
+// if content.File != nil {
+// err = content.File.DecryptInPlace(data)
+// if err != nil {
+// err = exerrors.NewDualError(ErrMediaDecryptFailed, err)
+// return
+// }
+// }
+// mimeType = content.GetInfo().MimeType
+// if mimeType == "" {
+// mimeType = http.DetectContentType(data)
+// }
+// fileName = content.FileName
+// if fileName == "" {
+// fileName = content.Body
+// if fileName == "" {
+// fileName = string(content.MsgType)[2:] + exmime.ExtensionFromMimetype(mimeType)
+// }
+// }
+// return
+// }
-func (mc *MessageConverter) reuploadFileToMeta(ctx context.Context, evt *event.Event, content *event.MessageEventContent) (*types.MercuryUploadResponse, error) {
- threadID := mc.GetData(ctx).ThreadID
- data, mimeType, fileName, err := mc.downloadMatrixMedia(ctx, content)
- if err != nil {
- return nil, err
- }
- _, isVoice := evt.Content.Raw["org.matrix.msc3245.voice"]
- if isVoice {
- data, err = ffmpeg.ConvertBytes(ctx, data, ".m4a", []string{}, []string{"-c:a", "aac"}, mimeType)
- if err != nil {
- return nil, err
- }
- mimeType = "audio/mp4"
- fileName += ".m4a"
- }
- resp, err := mc.GetClient(ctx).SendMercuryUploadRequest(ctx, threadID, &messagix.MercuryUploadMedia{
- Filename: fileName,
- MimeType: mimeType,
- MediaData: data,
- IsVoiceClip: isVoice,
- })
- if err != nil {
- zerolog.Ctx(ctx).Debug().
- Str("file_name", fileName).
- Str("mime_type", mimeType).
- Bool("is_voice_clip", isVoice).
- Msg("Failed upload metadata")
- return nil, fmt.Errorf("%w: %w", ErrMediaUploadFailed, err)
- }
- return resp, nil
-}
+// func (mc *MessageConverter) reuploadFileToMeta(ctx context.Context, evt *event.Event, content *event.MessageEventContent) (*types.MercuryUploadResponse, error) {
+// threadID := mc.GetData(ctx).ThreadID
+// data, mimeType, fileName, err := mc.downloadMatrixMedia(ctx, content)
+// if err != nil {
+// return nil, err
+// }
+// _, isVoice := evt.Content.Raw["org.matrix.msc3245.voice"]
+// if isVoice {
+// data, err = ffmpeg.ConvertBytes(ctx, data, ".m4a", []string{}, []string{"-c:a", "aac"}, mimeType)
+// if err != nil {
+// return nil, err
+// }
+// mimeType = "audio/mp4"
+// fileName += ".m4a"
+// }
+// resp, err := mc.GetClient(ctx).SendMercuryUploadRequest(ctx, threadID, &messagix.MercuryUploadMedia{
+// Filename: fileName,
+// MimeType: mimeType,
+// MediaData: data,
+// IsVoiceClip: isVoice,
+// })
+// if err != nil {
+// zerolog.Ctx(ctx).Debug().
+// Str("file_name", fileName).
+// Str("mime_type", mimeType).
+// Bool("is_voice_clip", isVoice).
+// Msg("Failed upload metadata")
+// return nil, fmt.Errorf("%w: %w", ErrMediaUploadFailed, err)
+// }
+// return resp, nil
+// }
diff --git a/pkg/connector/msgconv/from-meta.go b/pkg/connector/msgconv/from-meta.go
index 7112672..264e075 100644
--- a/pkg/connector/msgconv/from-meta.go
+++ b/pkg/connector/msgconv/from-meta.go
@@ -17,30 +17,34 @@
package msgconv
import (
- "bytes"
+ //"bytes"
"context"
"errors"
"fmt"
"html"
- "image"
+
+ //"image"
_ "image/gif"
_ "image/jpeg"
_ "image/png"
- "net/http"
+
+ //"net/http"
"net/url"
"regexp"
"slices"
- "strconv"
+
+ //"strconv"
"strings"
"github.com/rs/zerolog"
- "go.mau.fi/util/exmime"
- "go.mau.fi/util/ffmpeg"
+ //"go.mau.fi/util/exmime"
+ //"go.mau.fi/util/ffmpeg"
//"golang.org/x/exp/maps"
_ "golang.org/x/image/webp"
"maunium.net/go/mautrix/bridgev2"
- "maunium.net/go/mautrix/crypto/attachment"
+
+ //"maunium.net/go/mautrix/crypto/attachment"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
@@ -187,24 +191,25 @@ func (mc *MessageConverter) ToMatrix(ctx context.Context, msg *table.WrappedMess
_, hasExternalURL := part.Extra["external_url"]
unsupported, _ := part.Extra["fi.mau.unsupported"].(bool)
if unsupported && !hasExternalURL {
- _, threadURL := mc.GetThreadURL(ctx)
- if threadURL != "" {
- part.Extra["external_url"] = threadURL
- part.Content.EnsureHasHTML()
- var protocolName string
- switch {
- case strings.HasPrefix(threadURL, "https://www.instagram.com"):
- protocolName = "Instagram"
- case strings.HasPrefix(threadURL, "https://www.facebook.com"):
- protocolName = "Facebook"
- case strings.HasPrefix(threadURL, "https://www.messenger.com"):
- protocolName = "Messenger"
- default:
- protocolName = "native app"
- }
- part.Content.Body = fmt.Sprintf("%s\n\nOpen in %s: %s", part.Content.Body, protocolName, threadURL)
- part.Content.FormattedBody = fmt.Sprintf("%s
Click here to open in %s", part.Content.FormattedBody, threadURL, protocolName)
- }
+ //_, threadURL := mc.GetThreadURL(ctx)
+ panic("GetThreadURL not implemented")
+ // if threadURL != "" {
+ // part.Extra["external_url"] = threadURL
+ // part.Content.EnsureHasHTML()
+ // var protocolName string
+ // switch {
+ // case strings.HasPrefix(threadURL, "https://www.instagram.com"):
+ // protocolName = "Instagram"
+ // case strings.HasPrefix(threadURL, "https://www.facebook.com"):
+ // protocolName = "Facebook"
+ // case strings.HasPrefix(threadURL, "https://www.messenger.com"):
+ // protocolName = "Messenger"
+ // default:
+ // protocolName = "native app"
+ // }
+ // part.Content.Body = fmt.Sprintf("%s\n\nOpen in %s: %s", part.Content.Body, protocolName, threadURL)
+ // part.Content.FormattedBody = fmt.Sprintf("%s
Click here to open in %s", part.Content.FormattedBody, threadURL, protocolName)
+ // }
}
if part.Content.Mentions == nil {
part.Content.Mentions = &event.Mentions{}
@@ -388,223 +393,223 @@ func addExternalURLCaption(content *event.MessageEventContent, externalURL strin
}
}
-func (mc *MessageConverter) fetchFullXMA(ctx context.Context, att *table.WrappedXMA, minimalConverted *bridgev2.ConvertedMessagePart) *bridgev2.ConvertedMessagePart {
- ig := mc.GetClient(ctx).Instagram
- if att.CTA == nil || ig == nil {
- minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "unsupported"
- return minimalConverted
- }
- log := zerolog.Ctx(ctx)
- switch {
- case strings.HasPrefix(att.CTA.NativeUrl, "instagram://media/?shortcode="), strings.HasPrefix(att.CTA.NativeUrl, "instagram://reels_share/?shortcode="):
- actionURL, _ := url.Parse(removeLPHP(att.CTA.ActionUrl))
- var carouselChildMediaID string
- if actionURL != nil {
- carouselChildMediaID = actionURL.Query().Get("carousel_share_child_media_id")
- }
+// func (mc *MessageConverter) fetchFullXMA(ctx context.Context, att *table.WrappedXMA, minimalConverted *bridgev2.ConvertedMessagePart) *bridgev2.ConvertedMessagePart {
+// ig := mc.GetClient(ctx).Instagram
+// if att.CTA == nil || ig == nil {
+// minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "unsupported"
+// return minimalConverted
+// }
+// log := zerolog.Ctx(ctx)
+// switch {
+// case strings.HasPrefix(att.CTA.NativeUrl, "instagram://media/?shortcode="), strings.HasPrefix(att.CTA.NativeUrl, "instagram://reels_share/?shortcode="):
+// actionURL, _ := url.Parse(removeLPHP(att.CTA.ActionUrl))
+// var carouselChildMediaID string
+// if actionURL != nil {
+// carouselChildMediaID = actionURL.Query().Get("carousel_share_child_media_id")
+// }
- mediaShortcode := strings.TrimPrefix(att.CTA.NativeUrl, "instagram://media/?shortcode=")
- mediaShortcode = strings.TrimPrefix(mediaShortcode, "instagram://reels_share/?shortcode=")
- externalURL := fmt.Sprintf("https://www.instagram.com/p/%s/", mediaShortcode)
- minimalConverted.Extra["external_url"] = externalURL
- addExternalURLCaption(minimalConverted.Content, externalURL)
- if !mc.ShouldFetchXMA(ctx) {
- log.Debug().Msg("Not fetching XMA media")
- minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "skip"
- return minimalConverted
- }
+// mediaShortcode := strings.TrimPrefix(att.CTA.NativeUrl, "instagram://media/?shortcode=")
+// mediaShortcode = strings.TrimPrefix(mediaShortcode, "instagram://reels_share/?shortcode=")
+// externalURL := fmt.Sprintf("https://www.instagram.com/p/%s/", mediaShortcode)
+// minimalConverted.Extra["external_url"] = externalURL
+// addExternalURLCaption(minimalConverted.Content, externalURL)
+// if !mc.ShouldFetchXMA(ctx) {
+// log.Debug().Msg("Not fetching XMA media")
+// minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "skip"
+// return minimalConverted
+// }
- log.Trace().Any("cta_data", att.CTA).Msg("Fetching XMA media from CTA data")
- resp, err := ig.FetchMedia(strconv.FormatInt(att.CTA.TargetId, 10), mediaShortcode)
- if err != nil {
- log.Err(err).Int64("target_id", att.CTA.TargetId).Msg("Failed to fetch XMA media")
- minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "fetch fail"
- return minimalConverted
- } else if len(resp.Items) == 0 {
- log.Warn().Int64("target_id", att.CTA.TargetId).Msg("Got empty XMA media response")
- minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "empty response"
- return minimalConverted
- } else {
- log.Trace().Int64("target_id", att.CTA.TargetId).Any("response", resp).Msg("Fetched XMA media")
- log.Debug().Msg("Fetched XMA media")
- targetItem := resp.Items[0]
- if targetItem.CarouselMedia != nil && carouselChildMediaID != "" {
- for _, subitem := range targetItem.CarouselMedia {
- if subitem.ID == carouselChildMediaID {
- targetItem = subitem
- break
- }
- }
- }
- secondConverted, err := mc.instagramFetchedMediaToMatrix(ctx, att, targetItem)
- if err != nil {
- zerolog.Ctx(ctx).Err(err).Msg("Failed to transfer fetched media")
- minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "reupload fail"
- return minimalConverted
- }
- secondConverted.Content.Info.ThumbnailInfo = minimalConverted.Content.Info
- secondConverted.Content.Info.ThumbnailURL = minimalConverted.Content.URL
- secondConverted.Content.Info.ThumbnailFile = minimalConverted.Content.File
- secondConverted.Extra["com.beeper.instagram_item_username"] = targetItem.User.Username
- if externalURL != "" {
- secondConverted.Extra["external_url"] = externalURL
- }
- secondConverted.Extra["fi.mau.meta.xma_fetch_status"] = "success"
- return secondConverted
- }
- case strings.HasPrefix(att.CTA.ActionUrl, "/stories/direct/"):
- log.Trace().Any("cta_data", att.CTA).Msg("Fetching XMA story from CTA data")
- externalURL := fmt.Sprintf("https://www.instagram.com%s", att.CTA.ActionUrl)
- match := reelActionURLRegex.FindStringSubmatch(att.CTA.ActionUrl)
- if usernameRegex.MatchString(att.HeaderTitle) && len(match) == 3 {
- // Very hacky way to hopefully fix the URL to work on mobile.
- // When fetching the XMA data, this is done again later in a safer way.
- externalURL = fmt.Sprintf("https://www.instagram.com/stories/%s/%s/", att.HeaderTitle, match[1])
- }
- minimalConverted.Extra["external_url"] = externalURL
- addExternalURLCaption(minimalConverted.Content, externalURL)
- if !mc.ShouldFetchXMA(ctx) {
- log.Debug().Msg("Not fetching XMA media")
- minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "skip"
- return minimalConverted
- }
+// log.Trace().Any("cta_data", att.CTA).Msg("Fetching XMA media from CTA data")
+// resp, err := ig.FetchMedia(strconv.FormatInt(att.CTA.TargetId, 10), mediaShortcode)
+// if err != nil {
+// log.Err(err).Int64("target_id", att.CTA.TargetId).Msg("Failed to fetch XMA media")
+// minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "fetch fail"
+// return minimalConverted
+// } else if len(resp.Items) == 0 {
+// log.Warn().Int64("target_id", att.CTA.TargetId).Msg("Got empty XMA media response")
+// minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "empty response"
+// return minimalConverted
+// } else {
+// log.Trace().Int64("target_id", att.CTA.TargetId).Any("response", resp).Msg("Fetched XMA media")
+// log.Debug().Msg("Fetched XMA media")
+// targetItem := resp.Items[0]
+// if targetItem.CarouselMedia != nil && carouselChildMediaID != "" {
+// for _, subitem := range targetItem.CarouselMedia {
+// if subitem.ID == carouselChildMediaID {
+// targetItem = subitem
+// break
+// }
+// }
+// }
+// secondConverted, err := mc.instagramFetchedMediaToMatrix(ctx, att, targetItem)
+// if err != nil {
+// zerolog.Ctx(ctx).Err(err).Msg("Failed to transfer fetched media")
+// minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "reupload fail"
+// return minimalConverted
+// }
+// secondConverted.Content.Info.ThumbnailInfo = minimalConverted.Content.Info
+// secondConverted.Content.Info.ThumbnailURL = minimalConverted.Content.URL
+// secondConverted.Content.Info.ThumbnailFile = minimalConverted.Content.File
+// secondConverted.Extra["com.beeper.instagram_item_username"] = targetItem.User.Username
+// if externalURL != "" {
+// secondConverted.Extra["external_url"] = externalURL
+// }
+// secondConverted.Extra["fi.mau.meta.xma_fetch_status"] = "success"
+// return secondConverted
+// }
+// case strings.HasPrefix(att.CTA.ActionUrl, "/stories/direct/"):
+// log.Trace().Any("cta_data", att.CTA).Msg("Fetching XMA story from CTA data")
+// externalURL := fmt.Sprintf("https://www.instagram.com%s", att.CTA.ActionUrl)
+// match := reelActionURLRegex.FindStringSubmatch(att.CTA.ActionUrl)
+// if usernameRegex.MatchString(att.HeaderTitle) && len(match) == 3 {
+// // Very hacky way to hopefully fix the URL to work on mobile.
+// // When fetching the XMA data, this is done again later in a safer way.
+// externalURL = fmt.Sprintf("https://www.instagram.com/stories/%s/%s/", att.HeaderTitle, match[1])
+// }
+// minimalConverted.Extra["external_url"] = externalURL
+// addExternalURLCaption(minimalConverted.Content, externalURL)
+// if !mc.ShouldFetchXMA(ctx) {
+// log.Debug().Msg("Not fetching XMA media")
+// minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "skip"
+// return minimalConverted
+// }
- if len(match) != 3 {
- log.Warn().Str("action_url", att.CTA.ActionUrl).Msg("Failed to parse story action URL")
- minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "parse fail"
- return minimalConverted
- } else if resp, err := ig.FetchReel([]string{match[2]}, match[1]); err != nil {
- log.Err(err).Str("action_url", att.CTA.ActionUrl).Msg("Failed to fetch XMA story")
- minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "fetch fail"
- return minimalConverted
- } else if reel, ok := resp.Reels[match[2]]; !ok {
- log.Trace().
- Str("action_url", att.CTA.ActionUrl).
- Any("response", resp).
- Msg("XMA story fetch data")
- log.Warn().
- Str("action_url", att.CTA.ActionUrl).
- Str("reel_id", match[2]).
- Str("media_id", match[1]).
- Str("response_status", resp.Status).
- Msg("Got empty XMA story response")
- minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "empty response"
- return minimalConverted
- } else {
- log.Trace().
- Str("action_url", att.CTA.ActionUrl).
- Str("reel_id", match[2]).
- Str("media_id", match[1]).
- Any("response", resp).
- Msg("Fetched XMA story")
- minimalConverted.Extra["com.beeper.instagram_item_username"] = reel.User.Username
- // Update external URL to use username so it works on mobile
- externalURL = fmt.Sprintf("https://www.instagram.com/stories/%s/%s/", reel.User.Username, match[1])
- minimalConverted.Extra["external_url"] = externalURL
- var relevantItem *responses.Items
- foundIDs := make([]string, len(reel.Items))
- for i, item := range reel.Items {
- foundIDs[i] = item.Pk
- if item.Pk == match[1] {
- relevantItem = &item.Items
- }
- }
- if relevantItem == nil {
- log.Warn().
- Str("action_url", att.CTA.ActionUrl).
- Str("reel_id", match[2]).
- Str("media_id", match[1]).
- Strs("found_ids", foundIDs).
- Msg("Failed to find exact item in fetched XMA story")
- minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "item not found in response"
- return minimalConverted
- }
- log.Debug().Msg("Fetched XMA story and found exact item")
- secondConverted, err := mc.instagramFetchedMediaToMatrix(ctx, att, relevantItem)
- if err != nil {
- zerolog.Ctx(ctx).Err(err).Msg("Failed to transfer fetched media")
- minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "reupload fail"
- return minimalConverted
- }
- secondConverted.Content.Info.ThumbnailInfo = minimalConverted.Content.Info
- secondConverted.Content.Info.ThumbnailURL = minimalConverted.Content.URL
- secondConverted.Content.Info.ThumbnailFile = minimalConverted.Content.File
- secondConverted.Extra["com.beeper.instagram_item_username"] = reel.User.Username
- if externalURL != "" {
- secondConverted.Extra["external_url"] = externalURL
- }
- secondConverted.Extra["fi.mau.meta.xma_fetch_status"] = "success"
- return secondConverted
- }
- //case strings.HasPrefix(att.CTA.ActionUrl, "/stories/archive/"):
- // TODO can these be handled?
- case strings.HasPrefix(att.CTA.ActionUrl, "https://instagram.com/stories/"):
- log.Trace().Any("cta_data", att.CTA).Msg("Fetching second type of XMA story from CTA data")
- externalURL := att.CTA.ActionUrl
- minimalConverted.Extra["external_url"] = externalURL
- addExternalURLCaption(minimalConverted.Content, externalURL)
- if !mc.ShouldFetchXMA(ctx) {
- log.Debug().Msg("Not fetching XMA media")
- minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "skip"
- return minimalConverted
- }
+// if len(match) != 3 {
+// log.Warn().Str("action_url", att.CTA.ActionUrl).Msg("Failed to parse story action URL")
+// minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "parse fail"
+// return minimalConverted
+// } else if resp, err := ig.FetchReel([]string{match[2]}, match[1]); err != nil {
+// log.Err(err).Str("action_url", att.CTA.ActionUrl).Msg("Failed to fetch XMA story")
+// minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "fetch fail"
+// return minimalConverted
+// } else if reel, ok := resp.Reels[match[2]]; !ok {
+// log.Trace().
+// Str("action_url", att.CTA.ActionUrl).
+// Any("response", resp).
+// Msg("XMA story fetch data")
+// log.Warn().
+// Str("action_url", att.CTA.ActionUrl).
+// Str("reel_id", match[2]).
+// Str("media_id", match[1]).
+// Str("response_status", resp.Status).
+// Msg("Got empty XMA story response")
+// minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "empty response"
+// return minimalConverted
+// } else {
+// log.Trace().
+// Str("action_url", att.CTA.ActionUrl).
+// Str("reel_id", match[2]).
+// Str("media_id", match[1]).
+// Any("response", resp).
+// Msg("Fetched XMA story")
+// minimalConverted.Extra["com.beeper.instagram_item_username"] = reel.User.Username
+// // Update external URL to use username so it works on mobile
+// externalURL = fmt.Sprintf("https://www.instagram.com/stories/%s/%s/", reel.User.Username, match[1])
+// minimalConverted.Extra["external_url"] = externalURL
+// var relevantItem *responses.Items
+// foundIDs := make([]string, len(reel.Items))
+// for i, item := range reel.Items {
+// foundIDs[i] = item.Pk
+// if item.Pk == match[1] {
+// relevantItem = &item.Items
+// }
+// }
+// if relevantItem == nil {
+// log.Warn().
+// Str("action_url", att.CTA.ActionUrl).
+// Str("reel_id", match[2]).
+// Str("media_id", match[1]).
+// Strs("found_ids", foundIDs).
+// Msg("Failed to find exact item in fetched XMA story")
+// minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "item not found in response"
+// return minimalConverted
+// }
+// log.Debug().Msg("Fetched XMA story and found exact item")
+// secondConverted, err := mc.instagramFetchedMediaToMatrix(ctx, att, relevantItem)
+// if err != nil {
+// zerolog.Ctx(ctx).Err(err).Msg("Failed to transfer fetched media")
+// minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "reupload fail"
+// return minimalConverted
+// }
+// secondConverted.Content.Info.ThumbnailInfo = minimalConverted.Content.Info
+// secondConverted.Content.Info.ThumbnailURL = minimalConverted.Content.URL
+// secondConverted.Content.Info.ThumbnailFile = minimalConverted.Content.File
+// secondConverted.Extra["com.beeper.instagram_item_username"] = reel.User.Username
+// if externalURL != "" {
+// secondConverted.Extra["external_url"] = externalURL
+// }
+// secondConverted.Extra["fi.mau.meta.xma_fetch_status"] = "success"
+// return secondConverted
+// }
+// //case strings.HasPrefix(att.CTA.ActionUrl, "/stories/archive/"):
+// // TODO can these be handled?
+// case strings.HasPrefix(att.CTA.ActionUrl, "https://instagram.com/stories/"):
+// log.Trace().Any("cta_data", att.CTA).Msg("Fetching second type of XMA story from CTA data")
+// externalURL := att.CTA.ActionUrl
+// minimalConverted.Extra["external_url"] = externalURL
+// addExternalURLCaption(minimalConverted.Content, externalURL)
+// if !mc.ShouldFetchXMA(ctx) {
+// log.Debug().Msg("Not fetching XMA media")
+// minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "skip"
+// return minimalConverted
+// }
- if match := reelActionURLRegex2.FindStringSubmatch(att.CTA.ActionUrl); len(match) != 3 {
- log.Warn().Str("action_url", att.CTA.ActionUrl).Msg("Failed to parse story action URL (type 2)")
- minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "parse fail"
- return minimalConverted
- } else if resp, err := ig.FetchMedia(match[2], ""); err != nil {
- log.Err(err).Str("action_url", att.CTA.ActionUrl).Msg("Failed to fetch XMA story (type 2)")
- minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "fetch fail"
- return minimalConverted
- } else if len(resp.Items) == 0 {
- log.Trace().
- Str("action_url", att.CTA.ActionUrl).
- Any("response", resp).
- Msg("XMA story fetch data")
- log.Warn().
- Str("action_url", att.CTA.ActionUrl).
- Str("reel_id", match[2]).
- Str("media_id", match[1]).
- Str("response_status", resp.Status).
- Msg("Got empty XMA story response (type 2)")
- minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "empty response"
- return minimalConverted
- } else {
- relevantItem := resp.Items[0]
- log.Trace().
- Str("action_url", att.CTA.ActionUrl).
- Str("reel_id", match[2]).
- Str("media_id", match[1]).
- Any("response", resp).
- Msg("Fetched XMA story (type 2)")
- minimalConverted.Extra["com.beeper.instagram_item_username"] = relevantItem.User.Username
- log.Debug().Int("item_count", len(resp.Items)).Msg("Fetched XMA story (type 2)")
- secondConverted, err := mc.instagramFetchedMediaToMatrix(ctx, att, relevantItem)
- if err != nil {
- zerolog.Ctx(ctx).Err(err).Msg("Failed to transfer fetched media")
- minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "reupload fail"
- return minimalConverted
- }
- secondConverted.Content.Info.ThumbnailInfo = minimalConverted.Content.Info
- secondConverted.Content.Info.ThumbnailURL = minimalConverted.Content.URL
- secondConverted.Content.Info.ThumbnailFile = minimalConverted.Content.File
- secondConverted.Extra["com.beeper.instagram_item_username"] = relevantItem.User.Username
- if externalURL != "" {
- secondConverted.Extra["external_url"] = externalURL
- }
- secondConverted.Extra["fi.mau.meta.xma_fetch_status"] = "success"
- return secondConverted
- }
- default:
- log.Debug().
- Any("cta_data", att.CTA).
- Any("xma_data", att.LSInsertXmaAttachment).
- Msg("Unrecognized CTA data")
- minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "unrecognized"
- return minimalConverted
- }
-}
+// if match := reelActionURLRegex2.FindStringSubmatch(att.CTA.ActionUrl); len(match) != 3 {
+// log.Warn().Str("action_url", att.CTA.ActionUrl).Msg("Failed to parse story action URL (type 2)")
+// minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "parse fail"
+// return minimalConverted
+// } else if resp, err := ig.FetchMedia(match[2], ""); err != nil {
+// log.Err(err).Str("action_url", att.CTA.ActionUrl).Msg("Failed to fetch XMA story (type 2)")
+// minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "fetch fail"
+// return minimalConverted
+// } else if len(resp.Items) == 0 {
+// log.Trace().
+// Str("action_url", att.CTA.ActionUrl).
+// Any("response", resp).
+// Msg("XMA story fetch data")
+// log.Warn().
+// Str("action_url", att.CTA.ActionUrl).
+// Str("reel_id", match[2]).
+// Str("media_id", match[1]).
+// Str("response_status", resp.Status).
+// Msg("Got empty XMA story response (type 2)")
+// minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "empty response"
+// return minimalConverted
+// } else {
+// relevantItem := resp.Items[0]
+// log.Trace().
+// Str("action_url", att.CTA.ActionUrl).
+// Str("reel_id", match[2]).
+// Str("media_id", match[1]).
+// Any("response", resp).
+// Msg("Fetched XMA story (type 2)")
+// minimalConverted.Extra["com.beeper.instagram_item_username"] = relevantItem.User.Username
+// log.Debug().Int("item_count", len(resp.Items)).Msg("Fetched XMA story (type 2)")
+// secondConverted, err := mc.instagramFetchedMediaToMatrix(ctx, att, relevantItem)
+// if err != nil {
+// zerolog.Ctx(ctx).Err(err).Msg("Failed to transfer fetched media")
+// minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "reupload fail"
+// return minimalConverted
+// }
+// secondConverted.Content.Info.ThumbnailInfo = minimalConverted.Content.Info
+// secondConverted.Content.Info.ThumbnailURL = minimalConverted.Content.URL
+// secondConverted.Content.Info.ThumbnailFile = minimalConverted.Content.File
+// secondConverted.Extra["com.beeper.instagram_item_username"] = relevantItem.User.Username
+// if externalURL != "" {
+// secondConverted.Extra["external_url"] = externalURL
+// }
+// secondConverted.Extra["fi.mau.meta.xma_fetch_status"] = "success"
+// return secondConverted
+// }
+// default:
+// log.Debug().
+// Any("cta_data", att.CTA).
+// Any("xma_data", att.LSInsertXmaAttachment).
+// Msg("Unrecognized CTA data")
+// minimalConverted.Extra["fi.mau.meta.xma_fetch_status"] = "unrecognized"
+// return minimalConverted
+// }
+// }
var instagramProfileURLRegex = regexp.MustCompile(`^https://www.instagram.com/([a-z0-9._]{1,30})$`)
@@ -677,7 +682,7 @@ func (mc *MessageConverter) xmaAttachmentToMatrix(ctx context.Context, att *tabl
zerolog.Ctx(ctx).Err(err).Msg("Failed to transfer XMA media")
converted = errorToNotice(err, "XMA")
} else {
- converted = mc.fetchFullXMA(ctx, att, converted)
+ //converted = mc.fetchFullXMA(ctx, att, converted)
}
_, hasExternalURL := converted.Extra["external_url"]
if !hasExternalURL && att.CTA != nil && att.CTA.ActionUrl != "" {
@@ -710,120 +715,123 @@ func (mc *MessageConverter) xmaAttachmentToMatrix(ctx context.Context, att *tabl
return parts
}
-func (mc *MessageConverter) uploadAttachment(ctx context.Context, data []byte, fileName, mimeType string) (*event.MessageEventContent, error) {
- var file *event.EncryptedFileInfo
- uploadMime := mimeType
- uploadFileName := fileName
- if mc.GetData(ctx).Encrypted {
- file = &event.EncryptedFileInfo{
- EncryptedFile: *attachment.NewEncryptedFile(),
- URL: "",
- }
- file.EncryptInPlace(data)
- uploadMime = "application/octet-stream"
- uploadFileName = ""
- }
- mxc, err := mc.UploadMatrixMedia(ctx, data, uploadFileName, uploadMime)
- if err != nil {
- return nil, err
- }
- content := &event.MessageEventContent{
- Body: fileName,
- Info: &event.FileInfo{
- MimeType: mimeType,
- Size: len(data),
- },
- }
- if file != nil {
- file.URL = mxc
- content.File = file
- } else {
- content.URL = mxc
- }
- return content, nil
-}
+// func (mc *MessageConverter) uploadAttachment(ctx context.Context, data []byte, fileName, mimeType string) (*event.MessageEventContent, error) {
+// var file *event.EncryptedFileInfo
+// uploadMime := mimeType
+// uploadFileName := fileName
+// if mc.GetData(ctx).Encrypted {
+// file = &event.EncryptedFileInfo{
+// EncryptedFile: *attachment.NewEncryptedFile(),
+// URL: "",
+// }
+// file.EncryptInPlace(data)
+// uploadMime = "application/octet-stream"
+// uploadFileName = ""
+// }
+// mxc, err := mc.UploadMatrixMedia(ctx, data, uploadFileName, uploadMime)
+// if err != nil {
+// return nil, err
+// }
+// content := &event.MessageEventContent{
+// Body: fileName,
+// Info: &event.FileInfo{
+// MimeType: mimeType,
+// Size: len(data),
+// },
+// }
+// if file != nil {
+// file.URL = mxc
+// content.File = file
+// } else {
+// content.URL = mxc
+// }
+// return content, nil
+// }
func (mc *MessageConverter) reuploadAttachment(
ctx context.Context, attachmentType table.AttachmentType,
url, fileName, mimeType string,
width, height, duration int,
) (*bridgev2.ConvertedMessagePart, error) {
- if url == "" {
- return nil, ErrURLNotFound
- }
- data, err := DownloadMedia(ctx, mimeType, url, mc.MaxFileSize)
- if err != nil {
- return nil, fmt.Errorf("failed to download attachment: %w", err)
- }
- if mimeType == "" {
- mimeType = http.DetectContentType(data)
- }
- extra := map[string]any{}
- if attachmentType == table.AttachmentTypeAudio && mc.ConvertVoiceMessages && ffmpeg.Supported() {
- data, err = ffmpeg.ConvertBytes(ctx, data, ".ogg", []string{}, []string{"-c:a", "libopus"}, mimeType)
- if err != nil {
- return nil, fmt.Errorf("failed to convert audio to ogg/opus: %w", err)
- }
- fileName += ".ogg"
- mimeType = "audio/ogg"
- extra["org.matrix.msc3245.voice"] = map[string]any{}
- extra["org.matrix.msc1767.audio"] = map[string]any{
- "duration": duration,
- }
- }
- if (attachmentType == table.AttachmentTypeImage || attachmentType == table.AttachmentTypeEphemeralImage) && (width == 0 || height == 0) {
- config, _, err := image.DecodeConfig(bytes.NewReader(data))
- if err == nil {
- width, height = config.Width, config.Height
- }
- }
- content, err := mc.uploadAttachment(ctx, data, fileName, mimeType)
- if err != nil {
- return nil, err
- }
- content.Info.Duration = duration
- content.Info.Width = width
- content.Info.Height = height
-
- if attachmentType == table.AttachmentTypeAnimatedImage && mimeType == "video/mp4" {
- extra["info"] = map[string]any{
- "fi.mau.gif": true,
- "fi.mau.loop": true,
- "fi.mau.autoplay": true,
- "fi.mau.hide_controls": true,
- "fi.mau.no_audio": true,
- }
- }
- eventType := event.EventMessage
- switch attachmentType {
- case table.AttachmentTypeSticker:
- eventType = event.EventSticker
- case table.AttachmentTypeImage, table.AttachmentTypeEphemeralImage:
- content.MsgType = event.MsgImage
- case table.AttachmentTypeVideo, table.AttachmentTypeEphemeralVideo:
- content.MsgType = event.MsgVideo
- case table.AttachmentTypeFile:
- content.MsgType = event.MsgFile
- case table.AttachmentTypeAudio:
- content.MsgType = event.MsgAudio
- default:
- switch strings.Split(mimeType, "/")[0] {
- case "image":
- content.MsgType = event.MsgImage
- case "video":
- content.MsgType = event.MsgVideo
- case "audio":
- content.MsgType = event.MsgAudio
- default:
- content.MsgType = event.MsgFile
- }
- }
- if content.Body == "" {
- content.Body = strings.TrimPrefix(string(content.MsgType), "m.") + exmime.ExtensionFromMimetype(mimeType)
- }
- return &bridgev2.ConvertedMessagePart{
- Type: eventType,
- Content: content,
- Extra: extra,
- }, nil
+ panic("not implemented")
}
+
+// if url == "" {
+// return nil, ErrURLNotFound
+// }
+// data, err := DownloadMedia(ctx, mimeType, url, mc.MaxFileSize)
+// if err != nil {
+// return nil, fmt.Errorf("failed to download attachment: %w", err)
+// }
+// if mimeType == "" {
+// mimeType = http.DetectContentType(data)
+// }
+// extra := map[string]any{}
+// if attachmentType == table.AttachmentTypeAudio && mc.ConvertVoiceMessages && ffmpeg.Supported() {
+// data, err = ffmpeg.ConvertBytes(ctx, data, ".ogg", []string{}, []string{"-c:a", "libopus"}, mimeType)
+// if err != nil {
+// return nil, fmt.Errorf("failed to convert audio to ogg/opus: %w", err)
+// }
+// fileName += ".ogg"
+// mimeType = "audio/ogg"
+// extra["org.matrix.msc3245.voice"] = map[string]any{}
+// extra["org.matrix.msc1767.audio"] = map[string]any{
+// "duration": duration,
+// }
+// }
+// if (attachmentType == table.AttachmentTypeImage || attachmentType == table.AttachmentTypeEphemeralImage) && (width == 0 || height == 0) {
+// config, _, err := image.DecodeConfig(bytes.NewReader(data))
+// if err == nil {
+// width, height = config.Width, config.Height
+// }
+// }
+// //content, err := mc.uploadAttachment(ctx, data, fileName, mimeType)
+// if err != nil {
+// return nil, err
+// }
+// //content.Info.Duration = duration
+// //content.Info.Width = width
+// //content.Info.Height = height
+
+// if attachmentType == table.AttachmentTypeAnimatedImage && mimeType == "video/mp4" {
+// extra["info"] = map[string]any{
+// "fi.mau.gif": true,
+// "fi.mau.loop": true,
+// "fi.mau.autoplay": true,
+// "fi.mau.hide_controls": true,
+// "fi.mau.no_audio": true,
+// }
+// }
+// eventType := event.EventMessage
+// switch attachmentType {
+// case table.AttachmentTypeSticker:
+// eventType = event.EventSticker
+// case table.AttachmentTypeImage, table.AttachmentTypeEphemeralImage:
+// content.MsgType = event.MsgImage
+// case table.AttachmentTypeVideo, table.AttachmentTypeEphemeralVideo:
+// content.MsgType = event.MsgVideo
+// case table.AttachmentTypeFile:
+// content.MsgType = event.MsgFile
+// case table.AttachmentTypeAudio:
+// content.MsgType = event.MsgAudio
+// default:
+// switch strings.Split(mimeType, "/")[0] {
+// case "image":
+// content.MsgType = event.MsgImage
+// case "video":
+// content.MsgType = event.MsgVideo
+// case "audio":
+// content.MsgType = event.MsgAudio
+// default:
+// content.MsgType = event.MsgFile
+// }
+// }
+// if content.Body == "" {
+// content.Body = strings.TrimPrefix(string(content.MsgType), "m.") + exmime.ExtensionFromMimetype(mimeType)
+// }
+// return &bridgev2.ConvertedMessagePart{
+// Type: eventType,
+// Content: content,
+// Extra: extra,
+// }, nil
+// }
diff --git a/pkg/connector/msgconv/mentions.go b/pkg/connector/msgconv/mentions.go
index bf1bc93..225c92e 100644
--- a/pkg/connector/msgconv/mentions.go
+++ b/pkg/connector/msgconv/mentions.go
@@ -18,7 +18,7 @@ package msgconv
import (
"context"
- "slices"
+ //"slices"
"strings"
"unicode/utf16"
@@ -68,12 +68,12 @@ func (mc *MessageConverter) metaToMatrixText(ctx context.Context, text string, r
}
var mentionLink string
switch mention.Type {
- case socket.MentionTypePerson:
- userID := mc.GetUserMXID(ctx, mention.ID)
- if !slices.Contains(content.Mentions.UserIDs, userID) {
- content.Mentions.UserIDs = append(content.Mentions.UserIDs, userID)
- }
- mentionLink = userID.URI().MatrixToURL()
+ // case socket.MentionTypePerson:
+ // userID := mc.GetUserMXID(ctx, mention.ID)
+ // if !slices.Contains(content.Mentions.UserIDs, userID) {
+ // content.Mentions.UserIDs = append(content.Mentions.UserIDs, userID)
+ // }
+ // mentionLink = userID.URI().MatrixToURL()
case socket.MentionTypeThread:
// TODO: how does one send thread mentions?
}
diff --git a/pkg/connector/msgconv/msgconv.go b/pkg/connector/msgconv/msgconv.go
index acaa29e..c645deb 100644
--- a/pkg/connector/msgconv/msgconv.go
+++ b/pkg/connector/msgconv/msgconv.go
@@ -44,7 +44,7 @@ type PortalMethods interface {
}
type MessageConverter struct {
- PortalMethods
+ //PortalMethods
ConvertVoiceMessages bool
ConvertGIFToAPNG bool
@@ -53,6 +53,6 @@ type MessageConverter struct {
BridgeMode config.BridgeMode
}
-func (mc *MessageConverter) IsPrivateChat(ctx context.Context) bool {
- return mc.GetData(ctx).IsPrivateChat()
-}
+// func (mc *MessageConverter) IsPrivateChat(ctx context.Context) bool {
+// return mc.GetData(ctx).IsPrivateChat()
+// }
diff --git a/pkg/connector/msgconv/to-whatsapp.go b/pkg/connector/msgconv/to-whatsapp.go
index 85aaae1..3859380 100644
--- a/pkg/connector/msgconv/to-whatsapp.go
+++ b/pkg/connector/msgconv/to-whatsapp.go
@@ -17,21 +17,24 @@
package msgconv
import (
- "bytes"
+ //"bytes"
"context"
"fmt"
- "image"
+
+ //"image"
"strconv"
"strings"
- "time"
- "go.mau.fi/util/ffmpeg"
+ //"time"
+
+ //"go.mau.fi/util/ffmpeg"
"go.mau.fi/whatsmeow"
"go.mau.fi/whatsmeow/proto/waCommon"
"go.mau.fi/whatsmeow/proto/waConsumerApplication"
"go.mau.fi/whatsmeow/proto/waMediaTransport"
"go.mau.fi/whatsmeow/proto/waMsgApplication"
- "go.mau.fi/whatsmeow/types"
+
+ //"go.mau.fi/whatsmeow/types"
"google.golang.org/protobuf/proto"
"maunium.net/go/mautrix/event"
)
@@ -99,15 +102,16 @@ func (mc *MessageConverter) ToWhatsApp(
return nil, nil, fmt.Errorf("%w %s", ErrUnsupportedMsgType, content.MsgType)
}
var meta waMsgApplication.MessageApplication_Metadata
- if replyTo := mc.GetMetaReply(ctx, content); replyTo != nil {
- meta.QuotedMessage = &waMsgApplication.MessageApplication_Metadata_QuotedMessage{
- StanzaID: proto.String(replyTo.ReplyMessageId),
- // TODO: this is hacky since it hardcodes the server
- // TODO 2: should this be included for DMs?
- Participant: proto.String(types.JID{User: strconv.FormatInt(replyTo.ReplySender, 10), Server: types.MessengerServer}.String()),
- Payload: nil,
- }
- }
+ //if replyTo := mc.GetMetaReply(ctx, content); replyTo != nil {
+ // if false {
+ // meta.QuotedMessage = &waMsgApplication.MessageApplication_Metadata_QuotedMessage{
+ // StanzaID: proto.String(replyTo.ReplyMessageId),
+ // // TODO: this is hacky since it hardcodes the server
+ // // TODO 2: should this be included for DMs?
+ // Participant: proto.String(types.JID{User: strconv.FormatInt(replyTo.ReplySender, 10), Server: types.MessengerServer}.String()),
+ // Payload: nil,
+ // }
+ // }
return &waConsumerApplication.ConsumerApplication{
Payload: &waConsumerApplication.ConsumerApplication_Payload{
Payload: &waConsumerApplication.ConsumerApplication_Payload_Content{
@@ -149,72 +153,73 @@ func clampTo400(w, h int) (int, int) {
}
func (mc *MessageConverter) reuploadMediaToWhatsApp(ctx context.Context, evt *event.Event, content *event.MessageEventContent) (*waMediaTransport.WAMediaTransport, string, error) {
- data, mimeType, fileName, err := mc.downloadMatrixMedia(ctx, content)
- if err != nil {
- return nil, "", err
- }
- _, isVoice := evt.Content.Raw["org.matrix.msc3245.voice"]
- if isVoice {
- data, err = ffmpeg.ConvertBytes(ctx, data, ".m4a", []string{}, []string{"-c:a", "aac"}, mimeType)
- if err != nil {
- return nil, "", fmt.Errorf("%w voice message to m4a: %w", ErrMediaConvertFailed, err)
- }
- mimeType = "audio/mp4"
- fileName += ".m4a"
- } else if mimeType == "image/gif" && content.MsgType == event.MsgImage {
- data, err = ffmpeg.ConvertBytes(ctx, data, ".mp4", []string{"-f", "gif"}, []string{
- "-pix_fmt", "yuv420p", "-c:v", "libx264", "-movflags", "+faststart",
- "-filter:v", "crop='floor(in_w/2)*2:floor(in_h/2)*2'",
- }, mimeType)
- if err != nil {
- return nil, "", fmt.Errorf("%w gif to mp4: %w", ErrMediaConvertFailed, err)
- }
- mimeType = "video/mp4"
- fileName += ".mp4"
- content.MsgType = event.MsgVideo
- customInfo, ok := evt.Content.Raw["info"].(map[string]any)
- if !ok {
- customInfo = make(map[string]any)
- evt.Content.Raw["info"] = customInfo
- }
- customInfo["fi.mau.gif"] = true
- }
- if content.MsgType == event.MsgImage && content.Info.Width == 0 {
- cfg, _, _ := image.DecodeConfig(bytes.NewReader(data))
- content.Info.Width, content.Info.Height = cfg.Width, cfg.Height
- }
- mediaType := msgToMediaType(content.MsgType)
- uploaded, err := mc.GetE2EEClient(ctx).Upload(ctx, data, mediaType)
- if err != nil {
- return nil, "", fmt.Errorf("%w: %w", ErrMediaUploadFailed, err)
- }
- w, h := clampTo400(content.Info.Width, content.Info.Height)
- if w == 0 && content.MsgType == event.MsgImage {
- w, h = 400, 400
- }
- mediaTransport := &waMediaTransport.WAMediaTransport{
- Integral: &waMediaTransport.WAMediaTransport_Integral{
- FileSHA256: uploaded.FileSHA256,
- MediaKey: uploaded.MediaKey,
- FileEncSHA256: uploaded.FileEncSHA256,
- DirectPath: &uploaded.DirectPath,
- MediaKeyTimestamp: proto.Int64(time.Now().Unix()),
- },
- Ancillary: &waMediaTransport.WAMediaTransport_Ancillary{
- FileLength: proto.Uint64(uint64(len(data))),
- Mimetype: &mimeType,
- // This field is extremely required for some reason.
- // Messenger iOS & Android will refuse to display the media if it's not present.
- // iOS also requires that width and height are non-empty.
- Thumbnail: &waMediaTransport.WAMediaTransport_Ancillary_Thumbnail{
- ThumbnailWidth: proto.Uint32(uint32(w)),
- ThumbnailHeight: proto.Uint32(uint32(h)),
- },
- ObjectID: &uploaded.ObjectID,
- },
- }
- fmt.Printf("Uploaded media transport: %+v\n", mediaTransport)
- return mediaTransport, fileName, nil
+ panic("not implemented")
+ // data, mimeType, fileName, err := mc.downloadMatrixMedia(ctx, content)
+ // if err != nil {
+ // return nil, "", err
+ // }
+ // _, isVoice := evt.Content.Raw["org.matrix.msc3245.voice"]
+ // if isVoice {
+ // data, err = ffmpeg.ConvertBytes(ctx, data, ".m4a", []string{}, []string{"-c:a", "aac"}, mimeType)
+ // if err != nil {
+ // return nil, "", fmt.Errorf("%w voice message to m4a: %w", ErrMediaConvertFailed, err)
+ // }
+ // mimeType = "audio/mp4"
+ // fileName += ".m4a"
+ // } else if mimeType == "image/gif" && content.MsgType == event.MsgImage {
+ // data, err = ffmpeg.ConvertBytes(ctx, data, ".mp4", []string{"-f", "gif"}, []string{
+ // "-pix_fmt", "yuv420p", "-c:v", "libx264", "-movflags", "+faststart",
+ // "-filter:v", "crop='floor(in_w/2)*2:floor(in_h/2)*2'",
+ // }, mimeType)
+ // if err != nil {
+ // return nil, "", fmt.Errorf("%w gif to mp4: %w", ErrMediaConvertFailed, err)
+ // }
+ // mimeType = "video/mp4"
+ // fileName += ".mp4"
+ // content.MsgType = event.MsgVideo
+ // customInfo, ok := evt.Content.Raw["info"].(map[string]any)
+ // if !ok {
+ // customInfo = make(map[string]any)
+ // evt.Content.Raw["info"] = customInfo
+ // }
+ // customInfo["fi.mau.gif"] = true
+ // }
+ // if content.MsgType == event.MsgImage && content.Info.Width == 0 {
+ // cfg, _, _ := image.DecodeConfig(bytes.NewReader(data))
+ // content.Info.Width, content.Info.Height = cfg.Width, cfg.Height
+ // }
+ // mediaType := msgToMediaType(content.MsgType)
+ // uploaded, err := mc.GetE2EEClient(ctx).Upload(ctx, data, mediaType)
+ // if err != nil {
+ // return nil, "", fmt.Errorf("%w: %w", ErrMediaUploadFailed, err)
+ // }
+ // w, h := clampTo400(content.Info.Width, content.Info.Height)
+ // if w == 0 && content.MsgType == event.MsgImage {
+ // w, h = 400, 400
+ // }
+ // mediaTransport := &waMediaTransport.WAMediaTransport{
+ // Integral: &waMediaTransport.WAMediaTransport_Integral{
+ // FileSHA256: uploaded.FileSHA256,
+ // MediaKey: uploaded.MediaKey,
+ // FileEncSHA256: uploaded.FileEncSHA256,
+ // DirectPath: &uploaded.DirectPath,
+ // MediaKeyTimestamp: proto.Int64(time.Now().Unix()),
+ // },
+ // Ancillary: &waMediaTransport.WAMediaTransport_Ancillary{
+ // FileLength: proto.Uint64(uint64(len(data))),
+ // Mimetype: &mimeType,
+ // // This field is extremely required for some reason.
+ // // Messenger iOS & Android will refuse to display the media if it's not present.
+ // // iOS also requires that width and height are non-empty.
+ // Thumbnail: &waMediaTransport.WAMediaTransport_Ancillary_Thumbnail{
+ // ThumbnailWidth: proto.Uint32(uint32(w)),
+ // ThumbnailHeight: proto.Uint32(uint32(h)),
+ // },
+ // ObjectID: &uploaded.ObjectID,
+ // },
+ // }
+ // fmt.Printf("Uploaded media transport: %+v\n", mediaTransport)
+ // return mediaTransport, fileName, nil
}
func (mc *MessageConverter) wrapWhatsAppMedia(