From 8f3cc2e28e903ba9229f5ea80774e380d26bf5fe Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 19 Jan 2026 19:53:31 +0200 Subject: [PATCH] media: fix lottie stickers not being decompressed --- pkg/connector/directdownload.go | 4 ++-- pkg/connector/media/sticker.go | 40 ++++++++++++++++++++++++++++++--- pkg/connector/media/transfer.go | 4 ++-- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/pkg/connector/directdownload.go b/pkg/connector/directdownload.go index 61783314..ea101ce3 100644 --- a/pkg/connector/directdownload.go +++ b/pkg/connector/directdownload.go @@ -161,7 +161,7 @@ func (tc *TelegramConnector) Download(ctx context.Context, mediaID networkid.Med log.Debug(). Int64("document_id", msgMedia.Document.GetID()). Bool("is_sticker", isSticker). - Msg("downloading photo") + Msg("downloading document") readyTransferer = transferer.WithDocument(msgMedia.Document, info.Thumbnail) case *tg.MessageMediaWebPage: webpage, ok := msgMedia.Webpage.(*tg.WebPage) @@ -172,7 +172,7 @@ func (tc *TelegramConnector) Download(ctx context.Context, mediaID networkid.Med if pc, ok := webpage.GetPhoto(); ok && pc.TypeID() == tg.PhotoTypeID { log.Debug(). Int64("photo_id", pc.GetID()). - Msg("downloading photo") + Msg("downloading webpage photo") readyTransferer = transferer.WithPhoto(pc) } else { return nil, fmt.Errorf("not a photo: %T", pc.TypeName()) diff --git a/pkg/connector/media/sticker.go b/pkg/connector/media/sticker.go index d678abc5..160df901 100644 --- a/pkg/connector/media/sticker.go +++ b/pkg/connector/media/sticker.go @@ -18,9 +18,12 @@ package media import ( "context" + "fmt" + "io" "os" "strconv" + "github.com/klauspost/compress/gzip" "github.com/rs/zerolog" "go.mau.fi/util/ffmpeg" "go.mau.fi/util/lottie" @@ -107,13 +110,44 @@ func (c *AnimatedStickerConfig) convertWebm(ctx context.Context, src *os.File) * } } -func (c *AnimatedStickerConfig) convert(ctx context.Context, src *os.File) *ConvertedSticker { - if c.Target == "disable" { - return nil +func extractGZip(src *os.File) (*ConvertedSticker, error) { + reader, err := gzip.NewReader(src) + if err != nil { + return nil, fmt.Errorf("failed to create gzip reader: %w", err) } + defer func() { + _ = reader.Close() + }() + replFile, err := os.OpenFile(src.Name()+".json", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) + if err != nil { + return nil, fmt.Errorf("failed to create temp file: %w", err) + } + defer func() { + _ = replFile.Close() + }() + n, err := io.Copy(replFile, reader) + if err != nil { + return nil, fmt.Errorf("failed to extract lottie gzip: %w", err) + } + return &ConvertedSticker{ + Success: true, + NewPath: replFile.Name(), + MIMEType: "video/lottie+json", + Size: int(n), + }, nil +} +func (c *AnimatedStickerConfig) convert(ctx context.Context, src *os.File) *ConvertedSticker { log := zerolog.Ctx(ctx).With().Str("animated_sticker_target", c.Target).Logger() + if c.Target == "disable" { + converted, err := extractGZip(src) + if err != nil { + log.Err(err).Msg("Failed to extract lottie sticker") + } + return converted + } + if !lottie.Supported() { log.Warn().Msg("Not converting lottie sticker as lottieconverter is not installed") return nil diff --git a/pkg/connector/media/transfer.go b/pkg/connector/media/transfer.go index 2ebc6cfa..9699c153 100644 --- a/pkg/connector/media/transfer.go +++ b/pkg/connector/media/transfer.go @@ -293,7 +293,7 @@ func (t *ReadyTransferer) Transfer(ctx context.Context, store *store.Container, if t.inner.fileInfo.MimeType == "video/webm" { converted = t.inner.animatedStickerConfig.convertWebm(ctx, osFile) } else { - t.inner.fileInfo.MimeType = "video/lottie+json" + t.inner.fileInfo.MimeType = "application/x-tgsticker" // This is expected to get overridden by convert converted = t.inner.animatedStickerConfig.convert(ctx, osFile) } if converted != nil { @@ -407,7 +407,7 @@ func (t *ReadyTransferer) ToDirectMediaResponse(ctx context.Context) (mediaproxy if t.inner.fileInfo.MimeType == "video/webm" { converted = t.inner.animatedStickerConfig.convertWebm(ctx, w) } else { - t.inner.fileInfo.MimeType = "video/lottie+json" + t.inner.fileInfo.MimeType = "application/x-tgsticker" // This is expected to get overridden by convert converted = t.inner.animatedStickerConfig.convert(ctx, w) } if converted == nil {