mirror of
https://github.com/mautrix/telegram.git
synced 2026-05-16 23:15:45 +03:00
imagepack: add support for direct media
This commit is contained in:
@@ -133,7 +133,23 @@ func (tc *TelegramConnector) Download(ctx context.Context, mediaID networkid.Med
|
||||
transferer := media.NewTransferer(client.client.API())
|
||||
var readyTransferer *media.ReadyTransferer
|
||||
|
||||
if info.MessageID > 0 {
|
||||
if info.PeerType == ids.FakePeerTypeSticker {
|
||||
pack, err := client.GetCachedStickerPack(ctx, "", &tg.InputStickerSetID{
|
||||
ID: info.PeerID,
|
||||
AccessHash: info.MessageID, // sticker pack direct media abuses the user ID field for access hashes
|
||||
}, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get sticker pack: %w", err)
|
||||
}
|
||||
doc, ok := pack.docs[info.ID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("sticker %d not found in pack %s", info.ID, pack.meta.ShortName)
|
||||
}
|
||||
readyTransferer = transferer.
|
||||
WithStickerConfig(tc.Config.AnimatedSticker).
|
||||
WithForceWebmStickerConvert(pack.meta.Emojis).
|
||||
WithDocument(doc, info.Thumbnail)
|
||||
} else if info.MessageID > 0 {
|
||||
rawMsgMedia, err := client.refetchMedia(ctx, info.PeerType, info.PeerID, int(info.MessageID))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to refetch media message: %w", err)
|
||||
|
||||
@@ -135,7 +135,8 @@ const (
|
||||
PeerTypeChat PeerType = "chat"
|
||||
PeerTypeChannel PeerType = "channel"
|
||||
|
||||
FakePeerTypeEmoji PeerType = "emoji"
|
||||
FakePeerTypeEmoji PeerType = "emoji"
|
||||
FakePeerTypeSticker PeerType = "sticker"
|
||||
)
|
||||
|
||||
func PeerTypeFromByte(pt byte) (PeerType, error) {
|
||||
@@ -148,6 +149,8 @@ func PeerTypeFromByte(pt byte) (PeerType, error) {
|
||||
return PeerTypeChannel, nil
|
||||
case 0x04:
|
||||
return FakePeerTypeEmoji, nil
|
||||
case 0x05:
|
||||
return FakePeerTypeSticker, nil
|
||||
default:
|
||||
return "", fmt.Errorf("unknown peer type %d", pt)
|
||||
}
|
||||
@@ -163,6 +166,8 @@ func (pt PeerType) AsByte() byte {
|
||||
return 0x03
|
||||
case FakePeerTypeEmoji:
|
||||
return 0x04
|
||||
case FakePeerTypeSticker:
|
||||
return 0x05
|
||||
default:
|
||||
panic(fmt.Errorf("unknown peer type %s", pt))
|
||||
}
|
||||
|
||||
@@ -551,12 +551,17 @@ func (tc *TelegramClient) DownloadImagePack(ctx context.Context, url string) (*b
|
||||
}
|
||||
}
|
||||
for i, rawDoc := range set.Documents {
|
||||
// TODO use direct media
|
||||
mxc, _, info, err := media.NewTransferer(tc.client.API()).
|
||||
var mxc id.ContentURIString
|
||||
var info *event.FileInfo
|
||||
xfer := media.NewTransferer(tc.client.API()).
|
||||
WithStickerConfig(tc.main.Config.AnimatedSticker).
|
||||
WithForceWebmStickerConvert(set.Set.Emojis).
|
||||
WithDocument(rawDoc, false).
|
||||
Transfer(ctx, tc.main.Store, tc.main.Bridge.Bot)
|
||||
WithDocument(rawDoc, false)
|
||||
if tc.main.useDirectMedia {
|
||||
mxc, info, err = xfer.StickerDirectDownloadURL(ctx, tc.main.Bridge, set.Set, tc.telegramUserID)
|
||||
} else {
|
||||
mxc, _, info, err = xfer.Transfer(ctx, tc.main.Store, tc.main.Bridge.Bot)
|
||||
}
|
||||
if err != nil {
|
||||
zerolog.Ctx(ctx).Err(err).Msg("Failed to transfer image in pack")
|
||||
return nil, fmt.Errorf("failed to transfer document %d: %w", rawDoc.GetID(), err)
|
||||
|
||||
@@ -39,6 +39,69 @@ type AnimatedStickerConfig struct {
|
||||
} `yaml:"args"`
|
||||
}
|
||||
|
||||
func (c *AnimatedStickerConfig) Supported(inputMime string) bool {
|
||||
if inputMime == "application/x-tgsticker" {
|
||||
switch c.Target {
|
||||
case "disable":
|
||||
return true
|
||||
case "gif", "png":
|
||||
return lottie.Supported()
|
||||
case "webm", "webp":
|
||||
return lottie.Supported() && ffmpeg.Supported()
|
||||
}
|
||||
} else if inputMime == "video/webm" {
|
||||
if !c.ConvertFromWebm {
|
||||
return true
|
||||
}
|
||||
switch c.Target {
|
||||
case "disable", "webm":
|
||||
return true
|
||||
case "webp", "png", "gif":
|
||||
return ffmpeg.Supported()
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *AnimatedStickerConfig) TargetMime(inputMime string) string {
|
||||
if c == nil || !c.Supported(inputMime) {
|
||||
return ""
|
||||
}
|
||||
switch inputMime {
|
||||
case "application/x-tgsticker":
|
||||
switch c.Target {
|
||||
case "png":
|
||||
return "image/png"
|
||||
case "gif":
|
||||
return "image/gif"
|
||||
case "webm":
|
||||
return "video/webm"
|
||||
case "webp":
|
||||
return "image/webp"
|
||||
case "disable":
|
||||
return "video/lottie+json"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
case "video/webm":
|
||||
if !c.ConvertFromWebm {
|
||||
return ""
|
||||
}
|
||||
switch c.Target {
|
||||
case "png":
|
||||
return "image/png"
|
||||
case "gif":
|
||||
return "image/gif"
|
||||
case "webp":
|
||||
return "image/webp"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
type ConvertedSticker struct {
|
||||
Success bool
|
||||
NewPath string
|
||||
@@ -51,7 +114,7 @@ type ConvertedSticker struct {
|
||||
}
|
||||
|
||||
func (c *AnimatedStickerConfig) convertWebm(ctx context.Context, src *os.File) *ConvertedSticker {
|
||||
if !c.ConvertFromWebm || c.Target == "webm" {
|
||||
if !c.ConvertFromWebm || c.Target == "webm" || c.Target == "disable" {
|
||||
return nil
|
||||
}
|
||||
log := zerolog.Ctx(ctx).With().Str("animated_sticker_target", c.Target).Logger()
|
||||
|
||||
@@ -331,8 +331,7 @@ func (t *ReadyTransferer) Transfer(ctx context.Context, db *store.Container, int
|
||||
return "", nil, nil, fmt.Errorf("downloading file failed: %w", err)
|
||||
}
|
||||
|
||||
needStickerConvert := t.inner.animatedStickerConfig != nil && (t.inner.fileInfo.MimeType == "application/x-tgsticker" ||
|
||||
(t.inner.fileInfo.MimeType == "video/webm" && t.inner.animatedStickerConfig.ConvertFromWebm && t.inner.animatedStickerConfig.Target != "webm"))
|
||||
needStickerConvert := t.expectedStickerConvertMime() != ""
|
||||
needsDimensions := strings.HasPrefix(t.inner.fileInfo.MimeType, "image/") &&
|
||||
t.inner.fileInfo.Width == 0 && t.inner.fileInfo.Height == 0
|
||||
|
||||
@@ -457,6 +456,10 @@ func (t *ReadyTransferer) Stream(ctx context.Context) (r io.Reader, mimeType str
|
||||
return r, t.inner.fileInfo.MimeType, t.inner.fileInfo.Size, nil
|
||||
}
|
||||
|
||||
func (t *ReadyTransferer) expectedStickerConvertMime() string {
|
||||
return t.inner.animatedStickerConfig.TargetMime(t.inner.fileInfo.MimeType)
|
||||
}
|
||||
|
||||
func (t *ReadyTransferer) ToDirectMediaResponse(ctx context.Context) (mediaproxy.GetMediaResponse, error) {
|
||||
if t == nil {
|
||||
return nil, fmt.Errorf("invalid direct media request")
|
||||
@@ -472,7 +475,7 @@ func (t *ReadyTransferer) ToDirectMediaResponse(ctx context.Context) (mediaproxy
|
||||
Int("size", size).
|
||||
Msg("Started downloading media successfully")
|
||||
|
||||
if t.inner.animatedStickerConfig != nil {
|
||||
if t.expectedStickerConvertMime() != "" {
|
||||
return &mediaproxy.GetMediaResponseFile{
|
||||
Callback: func(w *os.File) (*mediaproxy.FileMeta, error) {
|
||||
_, err = io.Copy(w, r)
|
||||
@@ -515,6 +518,27 @@ func (t *ReadyTransferer) DownloadBytes(ctx context.Context) ([]byte, error) {
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
|
||||
func (t *ReadyTransferer) StickerDirectDownloadURL(ctx context.Context, br *bridgev2.Bridge, set tg.StickerSet, loggedInUserID int64) (id.ContentURIString, *event.FileInfo, error) {
|
||||
mediaID, err := ids.DirectMediaInfo{
|
||||
PeerType: ids.FakePeerTypeSticker,
|
||||
PeerID: set.ID,
|
||||
UserID: loggedInUserID,
|
||||
MessageID: set.AccessHash, // sticker pack direct media abuses the user ID field for access hashes
|
||||
ID: t.loc.(*tg.InputDocumentFileLocation).ID,
|
||||
}.AsMediaID()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
mxc, err := br.Matrix.GenerateContentURI(ctx, mediaID)
|
||||
if t.inner.fileInfo.MimeType == "" {
|
||||
t.inner.fileInfo.MimeType = "application/octet-stream"
|
||||
}
|
||||
if convertMime := t.expectedStickerConvertMime(); convertMime != "" {
|
||||
t.inner.fileInfo.MimeType = convertMime
|
||||
}
|
||||
return mxc, &t.inner.fileInfo, err
|
||||
}
|
||||
|
||||
// DirectDownloadURL returns the direct download URL for the media.
|
||||
func (t *ReadyTransferer) DirectDownloadURL(ctx context.Context, loggedInUserID int64, portal *bridgev2.Portal, msgID int, thumbnail bool, telegramMediaID int64) (id.ContentURIString, *event.FileInfo, error) {
|
||||
peerType, chatID, _, err := ids.ParsePortalID(portal.ID)
|
||||
@@ -536,8 +560,8 @@ func (t *ReadyTransferer) DirectDownloadURL(ctx context.Context, loggedInUserID
|
||||
if t.inner.fileInfo.MimeType == "" {
|
||||
t.inner.fileInfo.MimeType = "application/octet-stream"
|
||||
}
|
||||
if t.inner.fileInfo.MimeType == "application/x-tgsticker" {
|
||||
t.inner.fileInfo.MimeType = "video/lottie+json"
|
||||
if convertMime := t.expectedStickerConvertMime(); convertMime != "" {
|
||||
t.inner.fileInfo.MimeType = convertMime
|
||||
}
|
||||
return mxc, &t.inner.fileInfo, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user