diff --git a/pkg/connector/handle_message.go b/pkg/connector/handle_message.go index 10e1c03..812354b 100644 --- a/pkg/connector/handle_message.go +++ b/pkg/connector/handle_message.go @@ -476,7 +476,7 @@ func (lc *LineClient) convertLineMessage(ctx context.Context, portal *bridgev2.P } // Default to text - converted, err = h.ConvertText(unwrappedText, replyRelatesTo) + converted, err = h.ConvertText(ctx, portal, intent, unwrappedText, replyRelatesTo) } if err != nil { return nil, err diff --git a/pkg/connector/handlers/emoji.go b/pkg/connector/handlers/emoji.go index 01f2c89..064a7e2 100644 --- a/pkg/connector/handlers/emoji.go +++ b/pkg/connector/handlers/emoji.go @@ -185,7 +185,7 @@ func (h *Handler) ConvertInlineEmoji(ctx context.Context, portal *bridgev2.Porta if msg := h.tryDownloadSticon(ctx, portal, intent, stkPkgID, stkID, relatesTo); msg != nil { return msg, nil } - return h.ConvertText(cleanInlineSticonPlaceholders(stkTxt), relatesTo) + return h.ConvertText(ctx, portal, intent, cleanInlineSticonPlaceholders(stkTxt), relatesTo) } // Try parsing the text body for inline sticon references ($STK:productId:emojiId$). @@ -233,7 +233,7 @@ func (h *Handler) ConvertInlineEmoji(ctx context.Context, portal *bridgev2.Porta Int("raw_body_length", len(bodyText)). Int("metadata_count", len(data.ContentMetadata)). Msg("Falling back to text for inline emoji") - return h.ConvertText(cleanInlineSticonPlaceholders(stkTxt), relatesTo) + return h.ConvertText(ctx, portal, intent, cleanInlineSticonPlaceholders(stkTxt), relatesTo) } type sticonReplacement struct { diff --git a/pkg/connector/handlers/text.go b/pkg/connector/handlers/text.go index a31fc66..31afb1b 100644 --- a/pkg/connector/handlers/text.go +++ b/pkg/connector/handlers/text.go @@ -1,16 +1,20 @@ package handlers import ( + "context" + "fmt" + "net/http" "regexp" "strings" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/event" - "maunium.net/go/mautrix/id" + + "github.com/beeper/line/pkg/line" ) // ConvertText converts a LINE text message to a Matrix text message, including link previews. -func (h *Handler) ConvertText(unwrappedText string, relatesTo *event.RelatesTo) (*bridgev2.ConvertedMessage, error) { +func (h *Handler) ConvertText(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, unwrappedText string, relatesTo *event.RelatesTo) (*bridgev2.ConvertedMessage, error) { client := h.NewClient() content := &event.MessageEventContent{ @@ -36,7 +40,9 @@ func (h *Handler) ConvertText(unwrappedText string, relatesTo *event.RelatesTo) }, } if info.Image != "" && info.Obs.CDN != "" { - preview.ImageURL = id.ContentURIString(info.Obs.CDN + info.Image) + if err := h.uploadPreviewImage(ctx, client, portal, intent, info.Obs.CDN+info.Image, preview); err != nil { + h.Log.Warn().Err(err).Str("url", requestURL).Msg("Failed to bridge link preview image") + } } content.BeeperLinkPreviews = []*event.BeeperLinkPreview{preview} } @@ -51,3 +57,21 @@ func (h *Handler) ConvertText(unwrappedText string, relatesTo *event.RelatesTo) }, }, nil } + +func (h *Handler) uploadPreviewImage(ctx context.Context, client *line.Client, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, imageURL string, preview *event.BeeperLinkPreview) error { + data, err := client.DownloadOBSPublicResource(ctx, imageURL) + if err != nil { + return err + } + mimeType := http.DetectContentType(data) + if !strings.HasPrefix(mimeType, "image/") { + return fmt.Errorf("unexpected content type %q", mimeType) + } + preview.ImageURL, preview.ImageEncryption, err = intent.UploadMedia(ctx, portal.MXID, data, "", mimeType) + if err != nil { + return err + } + preview.ImageSize = event.IntOrString(len(data)) + preview.ImageType = mimeType + return nil +}