fix: sync sticker material reuse handling
This commit is contained in:
parent
bb07eb16d1
commit
20b388eeaa
5 changed files with 370 additions and 44 deletions
|
|
@ -102,10 +102,6 @@ func (s *Service) CreateStickerSet(ctx context.Context, req domain.CreateSticker
|
|||
return domain.StickerSet{}, nil, err
|
||||
}
|
||||
docByID := documentsByID(loaded)
|
||||
documentIDs := make([]int64, 0, len(req.Items))
|
||||
packs := make([]domain.StickerPack, 0, len(req.Items))
|
||||
packIndex := map[string]int{}
|
||||
keywords := []domain.StickerKeyword{}
|
||||
items := make([]domain.StickerSetItemInput, 0, len(req.Items))
|
||||
seenDocs := map[int64]struct{}{}
|
||||
for _, item := range req.Items {
|
||||
|
|
@ -122,40 +118,55 @@ func (s *Service) CreateStickerSet(ctx context.Context, req domain.CreateSticker
|
|||
return domain.StickerSet{}, nil, err
|
||||
}
|
||||
item.Emoji = emoji
|
||||
documentIDs = append(documentIDs, item.DocumentID)
|
||||
if idx, ok := packIndex[emoji]; ok {
|
||||
packs[idx].DocumentIDs = append(packs[idx].DocumentIDs, item.DocumentID)
|
||||
} else {
|
||||
packIndex[emoji] = len(packs)
|
||||
packs = append(packs, domain.StickerPack{Emoticon: emoji, DocumentIDs: []int64{item.DocumentID}})
|
||||
}
|
||||
if kw := parseStickerKeywords(item.DocumentID, item.Keywords); len(kw.Keywords) > 0 {
|
||||
keywords = append(keywords, kw)
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
if thumbID != 0 {
|
||||
thumb, ok := docByID[thumbID]
|
||||
if !ok || thumb.AccessHash != thumbAccess {
|
||||
return domain.StickerSet{}, nil, domain.ErrStickerSetFileInvalid
|
||||
}
|
||||
}
|
||||
|
||||
set := domain.StickerSet{
|
||||
ID: randomID(),
|
||||
AccessHash: randomID(),
|
||||
ShortName: shortName,
|
||||
Title: title,
|
||||
Count: len(documentIDs),
|
||||
Kind: kind,
|
||||
Emojis: kind == domain.StickerSetKindEmoji,
|
||||
Masks: kind == domain.StickerSetKindMasks,
|
||||
TextColor: kind == domain.StickerSetKindEmoji && req.TextColor,
|
||||
Creator: true,
|
||||
CreatorUserID: req.CreatorUserID,
|
||||
DocumentIDs: documentIDs,
|
||||
Packs: packs,
|
||||
Keywords: keywords,
|
||||
Software: strings.TrimSpace(req.Software),
|
||||
}
|
||||
|
||||
updatedDocs := make([]domain.Document, 0, len(items))
|
||||
finalBySourceID := make(map[int64]domain.Document, len(items))
|
||||
for _, item := range items {
|
||||
doc := docByID[item.DocumentID]
|
||||
doc, err = s.materialDocumentForStickerSet(ctx, doc, set.ID)
|
||||
if err != nil {
|
||||
return domain.StickerSet{}, nil, err
|
||||
}
|
||||
doc, err = s.prepareStickerSetDocument(ctx, doc, set, item.Emoji)
|
||||
if err != nil {
|
||||
return domain.StickerSet{}, nil, err
|
||||
}
|
||||
set.DocumentIDs = append(set.DocumentIDs, doc.ID)
|
||||
set.Packs = addDocumentToStickerPacks(set.Packs, item.Emoji, doc.ID)
|
||||
set.Keywords = upsertStickerKeywords(set.Keywords, parseStickerKeywords(doc.ID, item.Keywords))
|
||||
finalBySourceID[item.DocumentID] = doc
|
||||
updatedDocs = append(updatedDocs, doc)
|
||||
}
|
||||
set.Count = len(set.DocumentIDs)
|
||||
if thumbID != 0 {
|
||||
thumb, ok := docByID[thumbID]
|
||||
if !ok || thumb.AccessHash != thumbAccess {
|
||||
return domain.StickerSet{}, nil, domain.ErrStickerSetFileInvalid
|
||||
thumb, ok := finalBySourceID[thumbID]
|
||||
if !ok {
|
||||
thumb, ok = docByID[thumbID]
|
||||
if !ok || thumb.AccessHash != thumbAccess {
|
||||
return domain.StickerSet{}, nil, domain.ErrStickerSetFileInvalid
|
||||
}
|
||||
}
|
||||
set.ThumbDocumentID = thumb.ID
|
||||
set.Thumbs = copyPhotoSizes(thumb.Thumbs)
|
||||
|
|
@ -165,17 +176,6 @@ func (s *Service) CreateStickerSet(ctx context.Context, req domain.CreateSticker
|
|||
}
|
||||
}
|
||||
set.Hash = stickerSetHash(set)
|
||||
|
||||
updatedDocs := make([]domain.Document, 0, len(items))
|
||||
for _, item := range items {
|
||||
doc := docByID[item.DocumentID]
|
||||
doc, err = s.prepareStickerSetDocument(ctx, doc, set, item.Emoji)
|
||||
if err != nil {
|
||||
return domain.StickerSet{}, nil, err
|
||||
}
|
||||
docByID[item.DocumentID] = doc
|
||||
updatedDocs = append(updatedDocs, doc)
|
||||
}
|
||||
if err := s.media.CreateStickerSet(ctx, set, updatedDocs); err != nil {
|
||||
if errors.Is(err, domain.ErrStickerSetShortNameOccupied) {
|
||||
return domain.StickerSet{}, nil, domain.ErrStickerSetShortNameOccupied
|
||||
|
|
@ -286,10 +286,7 @@ func (s *Service) prepareStickerSetDocument(ctx context.Context, doc domain.Docu
|
|||
}
|
||||
|
||||
func (s *Service) ensureStickerMaterialShape(ctx context.Context, doc domain.Document) (domain.Document, error) {
|
||||
if doc.IsStickerLike() {
|
||||
return doc, nil
|
||||
}
|
||||
mimeType := doc.StickerSetMaterialMime()
|
||||
mimeType := canonicalStickerMaterialMime(doc.StickerSetMaterialMime())
|
||||
hasImageSize := false
|
||||
hasVideo := false
|
||||
for _, attr := range doc.Attributes {
|
||||
|
|
@ -301,7 +298,7 @@ func (s *Service) ensureStickerMaterialShape(ctx context.Context, doc domain.Doc
|
|||
}
|
||||
}
|
||||
switch mimeType {
|
||||
case "application/json":
|
||||
case stickerMaterialMimeJSON:
|
||||
data, ok := s.readStickerMaterialBlob(ctx, doc)
|
||||
if !ok {
|
||||
return domain.Document{}, domain.ErrStickerSetFileInvalid
|
||||
|
|
@ -314,10 +311,10 @@ func (s *Service) ensureStickerMaterialShape(ctx context.Context, doc domain.Doc
|
|||
if err != nil || int64(len(tgsData)) > domain.MaxStickerMaterialDocumentSize {
|
||||
return domain.Document{}, domain.ErrStickerSetFileInvalid
|
||||
}
|
||||
if err := s.rewriteStickerMaterialBlob(ctx, doc.ID, tgsData, "application/x-tgsticker"); err != nil {
|
||||
if err := s.rewriteStickerMaterialBlob(ctx, doc.ID, tgsData, stickerMaterialMimeTGS); err != nil {
|
||||
return domain.Document{}, err
|
||||
}
|
||||
doc.MimeType = "application/x-tgsticker"
|
||||
doc.MimeType = stickerMaterialMimeTGS
|
||||
doc.Size = int64(len(tgsData))
|
||||
doc.Attributes = replaceStickerMaterialFilename(doc.Attributes, "sticker.tgs")
|
||||
if !hasImageSize {
|
||||
|
|
@ -327,10 +324,15 @@ func (s *Service) ensureStickerMaterialShape(ctx context.Context, doc domain.Doc
|
|||
H: 512,
|
||||
})
|
||||
}
|
||||
case "application/x-tgsticker":
|
||||
case stickerMaterialMimeTGS:
|
||||
if data, ok := s.readStickerMaterialBlob(ctx, doc); ok && !validTGSStickerData(data) {
|
||||
return domain.Document{}, domain.ErrStickerSetFileInvalid
|
||||
}
|
||||
var err error
|
||||
doc, err = s.ensureStickerMaterialMIME(ctx, doc, stickerMaterialMimeTGS)
|
||||
if err != nil {
|
||||
return domain.Document{}, err
|
||||
}
|
||||
if !hasImageSize {
|
||||
doc.Attributes = append(doc.Attributes, domain.DocumentAttribute{
|
||||
Kind: domain.DocAttrImageSize,
|
||||
|
|
@ -338,7 +340,12 @@ func (s *Service) ensureStickerMaterialShape(ctx context.Context, doc domain.Doc
|
|||
H: 512,
|
||||
})
|
||||
}
|
||||
case "image/webp":
|
||||
case stickerMaterialMimeWebP:
|
||||
var err error
|
||||
doc, err = s.ensureStickerMaterialMIME(ctx, doc, stickerMaterialMimeWebP)
|
||||
if err != nil {
|
||||
return domain.Document{}, err
|
||||
}
|
||||
if !hasImageSize {
|
||||
data, ok := s.readStickerMaterialBlob(ctx, doc)
|
||||
if !ok {
|
||||
|
|
@ -354,11 +361,19 @@ func (s *Service) ensureStickerMaterialShape(ctx context.Context, doc domain.Doc
|
|||
H: h,
|
||||
})
|
||||
}
|
||||
case "video/webm", "video/mp4":
|
||||
case stickerMaterialMimeWebM, stickerMaterialMimeMP4:
|
||||
if !hasVideo {
|
||||
return domain.Document{}, domain.ErrStickerSetFileInvalid
|
||||
}
|
||||
var err error
|
||||
doc, err = s.ensureStickerMaterialMIME(ctx, doc, mimeType)
|
||||
if err != nil {
|
||||
return domain.Document{}, err
|
||||
}
|
||||
default:
|
||||
if doc.IsStickerLike() {
|
||||
return doc, nil
|
||||
}
|
||||
return domain.Document{}, domain.ErrStickerSetFileInvalid
|
||||
}
|
||||
return doc, nil
|
||||
|
|
|
|||
|
|
@ -106,6 +106,106 @@ func TestCreateStickerSetAcceptsUploadedStickerMaterial(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestCreateStickerSetNormalizesUploadedTGSMime(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
media := newFakeMediaStore()
|
||||
media.docs[206] = domain.Document{
|
||||
ID: 206,
|
||||
AccessHash: 2006,
|
||||
DCID: 2,
|
||||
Size: 1024,
|
||||
Attributes: []domain.DocumentAttribute{{Kind: domain.DocAttrFilename, FileName: "local.tgs"}},
|
||||
}
|
||||
media.blobs["doc:206"] = domain.FileBlob{
|
||||
LocationKey: "doc:206",
|
||||
Size: 1024,
|
||||
}
|
||||
svc := NewService(media, nil, 2)
|
||||
|
||||
_, docs, err := svc.CreateStickerSet(ctx, domain.CreateStickerSetRequest{
|
||||
CreatorUserID: 1000000001,
|
||||
Title: "Uploads",
|
||||
ShortName: "tgs_uploads",
|
||||
Items: []domain.StickerSetItemInput{{
|
||||
DocumentID: 206,
|
||||
DocumentAccessHash: 2006,
|
||||
Emoji: "👋",
|
||||
}},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create with uploaded tgs material: %v", err)
|
||||
}
|
||||
if len(docs) != 1 || docs[0].MimeType != stickerMaterialMimeTGS {
|
||||
t.Fatalf("created docs = %+v, want normalized tgs mime", docs)
|
||||
}
|
||||
stored := media.docs[206]
|
||||
if stored.MimeType != stickerMaterialMimeTGS {
|
||||
t.Fatalf("stored document mime = %q, want %q", stored.MimeType, stickerMaterialMimeTGS)
|
||||
}
|
||||
blob := media.blobs["doc:206"]
|
||||
if blob.MimeType != stickerMaterialMimeTGS {
|
||||
t.Fatalf("stored blob mime = %q, want %q", blob.MimeType, stickerMaterialMimeTGS)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateStickerSetClonesDocumentWhenReusedAcrossSets(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
media := &fakeMediaStore{
|
||||
docs: map[int64]domain.Document{
|
||||
301: {ID: 301, AccessHash: 3001, DCID: 2, Attributes: []domain.DocumentAttribute{{Kind: domain.DocAttrSticker}}},
|
||||
},
|
||||
sets: map[int64]domain.StickerSet{},
|
||||
}
|
||||
svc := NewService(media, nil, 2)
|
||||
|
||||
emojiSet, emojiDocs, err := svc.CreateStickerSet(ctx, domain.CreateStickerSetRequest{
|
||||
CreatorUserID: 1000000001,
|
||||
Title: "Emoji Pack",
|
||||
ShortName: "emoji_pack",
|
||||
Kind: domain.StickerSetKindEmoji,
|
||||
Items: []domain.StickerSetItemInput{{
|
||||
DocumentID: 301,
|
||||
DocumentAccessHash: 3001,
|
||||
Emoji: "🙂",
|
||||
}},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create emoji set: %v", err)
|
||||
}
|
||||
stickerSet, stickerDocs, err := svc.CreateStickerSet(ctx, domain.CreateStickerSetRequest{
|
||||
CreatorUserID: 1000000001,
|
||||
Title: "Sticker Pack",
|
||||
ShortName: "sticker_pack",
|
||||
Items: []domain.StickerSetItemInput{{
|
||||
DocumentID: 301,
|
||||
DocumentAccessHash: 3001,
|
||||
Emoji: "😄",
|
||||
}},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create sticker set from existing emoji doc: %v", err)
|
||||
}
|
||||
if len(emojiDocs) != 1 || len(stickerDocs) != 1 {
|
||||
t.Fatalf("created docs: emoji=%+v sticker=%+v, want one doc each", emojiDocs, stickerDocs)
|
||||
}
|
||||
if stickerDocs[0].ID == 301 || stickerSet.DocumentIDs[0] == 301 {
|
||||
t.Fatalf("sticker set reused source doc id, set=%+v docs=%+v", stickerSet, stickerDocs)
|
||||
}
|
||||
source := media.docs[301]
|
||||
if !source.IsCustomEmoji() {
|
||||
t.Fatalf("source doc attrs = %+v, want custom emoji preserved", source.Attributes)
|
||||
}
|
||||
if id, _, ok := source.StickerSetRef(); !ok || id != emojiSet.ID {
|
||||
t.Fatalf("source doc set ref = %d/%v, want emoji set %d", id, ok, emojiSet.ID)
|
||||
}
|
||||
if !stickerDocs[0].IsSticker() || stickerDocs[0].IsCustomEmoji() {
|
||||
t.Fatalf("cloned doc attrs = %+v, want regular sticker", stickerDocs[0].Attributes)
|
||||
}
|
||||
if id, _, ok := stickerDocs[0].StickerSetRef(); !ok || id != stickerSet.ID {
|
||||
t.Fatalf("cloned doc set ref = %d/%v, want sticker set %d", id, ok, stickerSet.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateStickerSetAcceptsWebPMaterialWithClientImageSize(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
media := &fakeMediaStore{
|
||||
|
|
|
|||
|
|
@ -19,8 +19,9 @@ func (s *Service) AddStickerToSet(ctx context.Context, actorUserID int64, ref do
|
|||
if err != nil {
|
||||
return domain.StickerSet{}, nil, err
|
||||
}
|
||||
if ownedSetID, _, ok := doc.StickerSetRef(); ok && ownedSetID != set.ID {
|
||||
return domain.StickerSet{}, nil, domain.ErrStickerSetFileInvalid
|
||||
doc, err = s.materialDocumentForStickerSet(ctx, doc, set.ID)
|
||||
if err != nil {
|
||||
return domain.StickerSet{}, nil, err
|
||||
}
|
||||
if containsInt64(set.DocumentIDs, doc.ID) {
|
||||
return set, docs, nil
|
||||
|
|
|
|||
|
|
@ -178,3 +178,71 @@ func TestAddStickerToSetAcceptsUploadedMaterial(t *testing.T) {
|
|||
t.Fatalf("added doc = %+v, want sticker-tagged video material", added)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddStickerToSetClonesDocumentWhenReusedAcrossSets(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
media := &fakeMediaStore{
|
||||
docs: map[int64]domain.Document{
|
||||
401: {ID: 401, AccessHash: 4001, Attributes: []domain.DocumentAttribute{{Kind: domain.DocAttrSticker}}},
|
||||
402: {ID: 402, AccessHash: 4002, Attributes: []domain.DocumentAttribute{{Kind: domain.DocAttrSticker}}},
|
||||
},
|
||||
sets: map[int64]domain.StickerSet{},
|
||||
}
|
||||
svc := NewService(media, nil, 2)
|
||||
|
||||
emojiSet, _, err := svc.CreateStickerSet(ctx, domain.CreateStickerSetRequest{
|
||||
CreatorUserID: 1000000001,
|
||||
Title: "Emoji Pack",
|
||||
ShortName: "emoji_pack",
|
||||
Kind: domain.StickerSetKindEmoji,
|
||||
Items: []domain.StickerSetItemInput{{
|
||||
DocumentID: 401,
|
||||
DocumentAccessHash: 4001,
|
||||
Emoji: "🙂",
|
||||
}},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create emoji set: %v", err)
|
||||
}
|
||||
stickerSet, _, err := svc.CreateStickerSet(ctx, domain.CreateStickerSetRequest{
|
||||
CreatorUserID: 1000000001,
|
||||
Title: "Sticker Pack",
|
||||
ShortName: "sticker_pack",
|
||||
Items: []domain.StickerSetItemInput{{
|
||||
DocumentID: 402,
|
||||
DocumentAccessHash: 4002,
|
||||
Emoji: "😄",
|
||||
}},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create sticker set: %v", err)
|
||||
}
|
||||
stickerSet, docs, err := svc.AddStickerToSet(ctx, 1000000001, domain.StickerSetRef{Kind: domain.StickerSetRefByID, ID: stickerSet.ID, AccessHash: stickerSet.AccessHash}, domain.StickerSetItemInput{
|
||||
DocumentID: 401,
|
||||
DocumentAccessHash: 4001,
|
||||
Emoji: "👋",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("add existing emoji doc to sticker set: %v", err)
|
||||
}
|
||||
if stickerSet.Count != 2 || len(docs) != 2 {
|
||||
t.Fatalf("after add set=%+v docs=%d, want two docs", stickerSet, len(docs))
|
||||
}
|
||||
added := docs[1]
|
||||
if added.ID == 401 || stickerSet.DocumentIDs[1] == 401 {
|
||||
t.Fatalf("added doc reused source id, set=%+v docs=%+v", stickerSet, docs)
|
||||
}
|
||||
source := media.docs[401]
|
||||
if !source.IsCustomEmoji() {
|
||||
t.Fatalf("source doc attrs = %+v, want custom emoji preserved", source.Attributes)
|
||||
}
|
||||
if id, _, ok := source.StickerSetRef(); !ok || id != emojiSet.ID {
|
||||
t.Fatalf("source doc set ref = %d/%v, want emoji set %d", id, ok, emojiSet.ID)
|
||||
}
|
||||
if !added.IsSticker() || added.IsCustomEmoji() {
|
||||
t.Fatalf("added clone attrs = %+v, want regular sticker", added.Attributes)
|
||||
}
|
||||
if id, _, ok := added.StickerSetRef(); !ok || id != stickerSet.ID {
|
||||
t.Fatalf("added clone set ref = %d/%v, want sticker set %d", id, ok, stickerSet.ID)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
142
internal/app/files/sticker_material.go
Normal file
142
internal/app/files/sticker_material.go
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
package files
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
||||
const (
|
||||
stickerMaterialMimeTGS = "application/x-tgsticker"
|
||||
stickerMaterialMimeWebP = "image/webp"
|
||||
stickerMaterialMimeWebM = "video/webm"
|
||||
stickerMaterialMimeMP4 = "video/mp4"
|
||||
stickerMaterialMimeJSON = "application/json"
|
||||
stickerMaterialMimeOctet = "application/octet-stream"
|
||||
)
|
||||
|
||||
func normalizeStickerMaterialDocumentMIME(doc domain.Document) (domain.Document, bool) {
|
||||
mimeType := canonicalStickerMaterialMime(doc.StickerSetMaterialMime())
|
||||
if mimeType == "" || mimeType == stickerMaterialMimeJSON {
|
||||
return doc, false
|
||||
}
|
||||
if !shouldReplaceStickerMaterialMime(doc.MimeType, mimeType) {
|
||||
return doc, false
|
||||
}
|
||||
doc.MimeType = mimeType
|
||||
return doc, true
|
||||
}
|
||||
|
||||
func (s *Service) materialDocumentForStickerSet(ctx context.Context, doc domain.Document, targetSetID int64) (domain.Document, error) {
|
||||
if ownedSetID, _, ok := doc.StickerSetRef(); ok && ownedSetID != 0 && ownedSetID != targetSetID {
|
||||
return s.cloneStickerSetDocument(ctx, doc)
|
||||
}
|
||||
return doc, nil
|
||||
}
|
||||
|
||||
func (s *Service) cloneStickerSetDocument(ctx context.Context, source domain.Document) (domain.Document, error) {
|
||||
copied := copyDocuments([]domain.Document{source})
|
||||
if len(copied) == 0 {
|
||||
return domain.Document{}, domain.ErrStickerSetFileInvalid
|
||||
}
|
||||
clone := copied[0]
|
||||
oldID := clone.ID
|
||||
clone.ID = randomID()
|
||||
clone.AccessHash = randomID()
|
||||
clone.FileReference = randomFileReference()
|
||||
|
||||
if source.Size > 0 {
|
||||
blob, found, err := s.media.GetFileBlob(ctx, fmt.Sprintf("doc:%d", oldID))
|
||||
if err != nil {
|
||||
return domain.Document{}, err
|
||||
}
|
||||
if !found {
|
||||
return domain.Document{}, domain.ErrStickerSetFileInvalid
|
||||
}
|
||||
blob.LocationKey = fmt.Sprintf("doc:%d", clone.ID)
|
||||
if normalized, changed := normalizeStickerMaterialDocumentMIME(clone); changed {
|
||||
clone = normalized
|
||||
}
|
||||
if mimeType := canonicalStickerMaterialMime(clone.StickerSetMaterialMime()); mimeType != "" && shouldReplaceStickerMaterialMime(blob.MimeType, mimeType) {
|
||||
blob.MimeType = mimeType
|
||||
}
|
||||
if err := s.media.PutFileBlob(ctx, blob); err != nil {
|
||||
return domain.Document{}, err
|
||||
}
|
||||
s.blobCache.put(blob.LocationKey, blob)
|
||||
}
|
||||
|
||||
for _, thumb := range source.Thumbs {
|
||||
if !thumb.Downloadable() || thumb.Type == "" {
|
||||
continue
|
||||
}
|
||||
oldKey := fmt.Sprintf("doc:%d:%s", oldID, thumb.Type)
|
||||
blob, found, err := s.media.GetFileBlob(ctx, oldKey)
|
||||
if err != nil {
|
||||
return domain.Document{}, err
|
||||
}
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
blob.LocationKey = fmt.Sprintf("doc:%d:%s", clone.ID, thumb.Type)
|
||||
if err := s.media.PutFileBlob(ctx, blob); err != nil {
|
||||
return domain.Document{}, err
|
||||
}
|
||||
s.blobCache.put(blob.LocationKey, blob)
|
||||
}
|
||||
|
||||
return clone, nil
|
||||
}
|
||||
|
||||
func (s *Service) ensureStickerMaterialMIME(ctx context.Context, doc domain.Document, mimeType string) (domain.Document, error) {
|
||||
mimeType = canonicalStickerMaterialMime(mimeType)
|
||||
if mimeType == "" || mimeType == stickerMaterialMimeJSON {
|
||||
return doc, nil
|
||||
}
|
||||
if shouldReplaceStickerMaterialMime(doc.MimeType, mimeType) {
|
||||
doc.MimeType = mimeType
|
||||
}
|
||||
if s == nil || s.media == nil || doc.ID == 0 {
|
||||
return doc, nil
|
||||
}
|
||||
blob, found, err := s.media.GetFileBlob(ctx, fmt.Sprintf("doc:%d", doc.ID))
|
||||
if err != nil {
|
||||
return domain.Document{}, err
|
||||
}
|
||||
if found && shouldReplaceStickerMaterialMime(blob.MimeType, mimeType) {
|
||||
blob.MimeType = mimeType
|
||||
if err := s.media.PutFileBlob(ctx, blob); err != nil {
|
||||
return domain.Document{}, err
|
||||
}
|
||||
s.blobCache.put(blob.LocationKey, blob)
|
||||
}
|
||||
return doc, nil
|
||||
}
|
||||
|
||||
func canonicalStickerMaterialMime(mimeType string) string {
|
||||
switch strings.ToLower(strings.TrimSpace(mimeType)) {
|
||||
case stickerMaterialMimeTGS:
|
||||
return stickerMaterialMimeTGS
|
||||
case stickerMaterialMimeWebP:
|
||||
return stickerMaterialMimeWebP
|
||||
case stickerMaterialMimeWebM:
|
||||
return stickerMaterialMimeWebM
|
||||
case stickerMaterialMimeMP4:
|
||||
return stickerMaterialMimeMP4
|
||||
case stickerMaterialMimeJSON, "text/json", "application/lottie+json":
|
||||
return stickerMaterialMimeJSON
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func shouldReplaceStickerMaterialMime(current, inferred string) bool {
|
||||
inferred = canonicalStickerMaterialMime(inferred)
|
||||
if inferred == "" {
|
||||
return false
|
||||
}
|
||||
current = strings.ToLower(strings.TrimSpace(current))
|
||||
return current == "" || current == stickerMaterialMimeOctet
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue