diff --git a/pkg/connector/handlers/sticker.go b/pkg/connector/handlers/sticker.go index 80582011..89ffe4b9 100644 --- a/pkg/connector/handlers/sticker.go +++ b/pkg/connector/handlers/sticker.go @@ -1,10 +1,13 @@ package handlers import ( + "bytes" "context" "encoding/binary" "fmt" "hash/crc32" + "image" + _ "image/png" "io" "strings" @@ -14,7 +17,7 @@ import ( "github.com/beeper/line/pkg/line" ) -// ConvertSticker converts a LINE sticker message to a Matrix image or text fallback. +// ConvertSticker converts a LINE sticker message to a Matrix sticker or text fallback. func (h *Handler) ConvertSticker(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, data line.Message, relatesTo *event.RelatesTo) (*bridgev2.ConvertedMessage, error) { stkID := data.ContentMetadata["STKID"] stkTxt := data.ContentMetadata["STKTXT"] @@ -77,6 +80,15 @@ func (h *Handler) ConvertSticker(ctx context.Context, portal *bridgev2.Portal, i bodyName := "sticker." + ext + info := &event.FileInfo{ + MimeType: mimeType, + Size: len(stkData), + } + if cfg, _, err := image.DecodeConfig(bytes.NewReader(stkData)); err == nil { + info.Width = cfg.Width * 2 / 3 + info.Height = cfg.Height * 2 / 3 + } + mxc, file, err := intent.UploadMedia(ctx, portal.MXID, stkData, bodyName, mimeType) if err != nil { h.Log.Warn().Err(err).Msg("Failed to upload sticker to Matrix") @@ -84,16 +96,12 @@ func (h *Handler) ConvertSticker(ctx context.Context, portal *bridgev2.Portal, i return &bridgev2.ConvertedMessage{ Parts: []*bridgev2.ConvertedMessagePart{ { - Type: event.EventMessage, + Type: event.EventSticker, Content: &event.MessageEventContent{ - MsgType: event.MsgImage, - Body: bodyName, - URL: mxc, - File: file, - Info: &event.FileInfo{ - MimeType: mimeType, - Size: len(stkData), - }, + Body: bodyName, + URL: mxc, + File: file, + Info: info, RelatesTo: relatesTo, }, }, diff --git a/pkg/connector/send_message.go b/pkg/connector/send_message.go index 9632ad22..5fffa717 100644 --- a/pkg/connector/send_message.go +++ b/pkg/connector/send_message.go @@ -131,7 +131,9 @@ func (lc *LineClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.Mat // Matrix clients often send media as MsgFile (e.g. drag-and-drop), which would otherwise // be sent as ContentFile (14) instead of the appropriate media type on LINE. effectiveMsgType := msg.Content.MsgType - if effectiveMsgType == event.MsgFile && msg.Content.Info != nil { + if effectiveMsgType == event.CapMsgSticker { + effectiveMsgType = event.MsgImage + } else if effectiveMsgType == event.MsgFile && msg.Content.Info != nil { mime := msg.Content.Info.MimeType if strings.HasPrefix(mime, "audio/") { effectiveMsgType = event.MsgAudio diff --git a/pkg/connector/userinfo.go b/pkg/connector/userinfo.go index ecda636e..15d8fdbf 100644 --- a/pkg/connector/userinfo.go +++ b/pkg/connector/userinfo.go @@ -46,7 +46,7 @@ func (lc *LineClient) HandleMatrixReadReceipt(ctx context.Context, read *bridgev func (lc *LineClient) GetCapabilities(ctx context.Context, portal *bridgev2.Portal) *event.RoomFeatures { caps := &event.RoomFeatures{ - ID: "dev.highest.matrix.line.capabilities.2026_10_14", + ID: "dev.highest.matrix.line.capabilities.2026_10_21", MaxTextLength: 5000, Reply: event.CapLevelFullySupported, Reaction: event.CapLevelPartialSupport, @@ -81,6 +81,16 @@ func (lc *LineClient) GetCapabilities(ctx context.Context, portal *bridgev2.Port "image/jxl": event.CapLevelFullySupported, }, }, + event.CapMsgSticker: { + Caption: event.CapLevelRejected, + MaxSize: handlers.BeeperMaxFileSize, + MimeTypes: map[string]event.CapabilitySupportLevel{ + "image/png": event.CapLevelFullySupported, + "image/gif": event.CapLevelFullySupported, + "image/webp": event.CapLevelFullySupported, + "image/jpeg": event.CapLevelFullySupported, + }, + }, event.MsgFile: { Caption: event.CapLevelRejected, MaxSize: handlers.BeeperMaxFileSize,