fix: sync serve client sticker categories
This commit is contained in:
parent
a989e118d7
commit
2f995f607a
2 changed files with 80 additions and 4 deletions
|
|
@ -73,11 +73,33 @@ func normalizeStickerEmoticon(e string) string {
|
|||
return strings.TrimSpace(e)
|
||||
}
|
||||
|
||||
// normalizeStickerSearchEmoticon 解析官方客户端通过 messages.getStickers
|
||||
// 传递的特殊贴纸类别标记。TDesktop、DrKLO Android 与 Telegram-iOS 都使用
|
||||
// wave+star 获取 greeting、double-star 获取 premium preview、folder+star 获取
|
||||
// premium/cloud catalog;它们不是普通复合 emoji,需先映射到 seed pack 的基础键。
|
||||
//
|
||||
// 只匹配这三个完整标记,不能把任意复合 emoji 拆分成单个 emoji,否则会改变普通
|
||||
// sticker search 的精确匹配语义。先去掉 variation selector,可同时接纳三端的
|
||||
// Unicode 表示差异。
|
||||
func normalizeStickerSearchEmoticon(e string) string {
|
||||
e = normalizeStickerEmoticon(e)
|
||||
switch e {
|
||||
case "👋⭐":
|
||||
return "👋"
|
||||
case "⭐⭐":
|
||||
return "⭐"
|
||||
case "📂⭐":
|
||||
return "📂"
|
||||
default:
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Router) onMessagesGetStickers(ctx context.Context, req *tg.MessagesGetStickersRequest) (tg.MessagesStickersClass, error) {
|
||||
if req == nil || r.deps.Files == nil || r.emojiStickers == nil {
|
||||
return &tg.MessagesStickers{Hash: 0, Stickers: []tg.DocumentClass{}}, nil
|
||||
}
|
||||
docIDs := r.emojiStickers.lookup(normalizeStickerEmoticon(req.Emoticon), func() map[string][]int64 {
|
||||
docIDs := r.emojiStickers.lookup(normalizeStickerSearchEmoticon(req.Emoticon), func() map[string][]int64 {
|
||||
return r.buildEmojiStickerIndex(ctx)
|
||||
})
|
||||
if len(docIDs) > maxStickersPerEmoji {
|
||||
|
|
|
|||
|
|
@ -15,15 +15,21 @@ func emojiStickerRouter(t *testing.T) *Router {
|
|||
t.Helper()
|
||||
files := &fakeFiles{
|
||||
docs: map[int64]domain.Document{
|
||||
201: {ID: 201, AccessHash: 1, MimeType: "application/x-tgsticker"},
|
||||
202: {ID: 202, AccessHash: 2, MimeType: "application/x-tgsticker"},
|
||||
301: {ID: 301, AccessHash: 3, MimeType: "application/x-tgsticker"},
|
||||
201: {ID: 201, AccessHash: 1, MimeType: "application/x-tgsticker", Attributes: []domain.DocumentAttribute{{Kind: domain.DocAttrSticker}}},
|
||||
202: {ID: 202, AccessHash: 2, MimeType: "application/x-tgsticker", Attributes: []domain.DocumentAttribute{{Kind: domain.DocAttrSticker}}},
|
||||
301: {ID: 301, AccessHash: 3, MimeType: "application/x-tgsticker", Attributes: []domain.DocumentAttribute{{Kind: domain.DocAttrSticker}}},
|
||||
401: {ID: 401, AccessHash: 4, MimeType: "application/x-tgsticker", Attributes: []domain.DocumentAttribute{{Kind: domain.DocAttrSticker}}},
|
||||
402: {ID: 402, AccessHash: 5, MimeType: "application/x-tgsticker", Attributes: []domain.DocumentAttribute{{Kind: domain.DocAttrSticker}}},
|
||||
403: {ID: 403, AccessHash: 6, MimeType: "application/x-tgsticker", Attributes: []domain.DocumentAttribute{{Kind: domain.DocAttrSticker}}},
|
||||
},
|
||||
sets: map[domain.StickerSetKind][]domain.StickerSet{
|
||||
domain.StickerSetKindStickers: {
|
||||
{ID: 10, Hash: 1, Packs: []domain.StickerPack{
|
||||
{Emoticon: "👍", DocumentIDs: []int64{201, 202}},
|
||||
{Emoticon: "🔥", DocumentIDs: []int64{301}},
|
||||
{Emoticon: "👋", DocumentIDs: []int64{401}},
|
||||
{Emoticon: "⭐", DocumentIDs: []int64{402}},
|
||||
{Emoticon: "📂", DocumentIDs: []int64{403}},
|
||||
}},
|
||||
{ID: 12, Hash: 2, Archived: true, Packs: []domain.StickerPack{
|
||||
{Emoticon: "👍", DocumentIDs: []int64{999}}, // 归档集应被排除
|
||||
|
|
@ -98,6 +104,54 @@ func TestMessagesGetStickersByEmoji(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestMessagesGetStickersSpecialCategories 固定 TDesktop、DrKLO Android 与
|
||||
// Telegram-iOS 共用的特殊类别标记。这些标记不是普通复合 emoji:服务端应把它们
|
||||
// 解析到对应的基础目录,同时不能拆分任意多 emoji 查询。
|
||||
func TestMessagesGetStickersSpecialCategories(t *testing.T) {
|
||||
r := emojiStickerRouter(t)
|
||||
ctx := WithUserID(context.Background(), 1000000001)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
emoticon string
|
||||
base string
|
||||
wantDocID int64
|
||||
}{
|
||||
{name: "greeting", emoticon: "👋⭐️", base: "👋", wantDocID: 401},
|
||||
{name: "greeting_without_vs16", emoticon: "👋⭐", base: "👋", wantDocID: 401},
|
||||
{name: "premium_preview", emoticon: "⭐️⭐️", base: "⭐", wantDocID: 402},
|
||||
{name: "premium_preview_mixed_vs16", emoticon: "⭐⭐️", base: "⭐", wantDocID: 402},
|
||||
{name: "all_premium", emoticon: "📂⭐️", base: "📂", wantDocID: 403},
|
||||
{name: "all_premium_without_vs16", emoticon: "📂⭐", base: "📂", wantDocID: 403},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
base := mustStickers(t, r, ctx, tt.base, 0).(*tg.MessagesStickers)
|
||||
got := mustStickers(t, r, ctx, tt.emoticon, 0)
|
||||
ids := stickerDocIDs(t, got)
|
||||
if len(ids) != 1 || ids[0] != tt.wantDocID {
|
||||
t.Fatalf("%q stickers = %v, want [%d]", tt.emoticon, ids, tt.wantDocID)
|
||||
}
|
||||
full := got.(*tg.MessagesStickers)
|
||||
if full.Hash == 0 || full.Hash != base.Hash {
|
||||
t.Fatalf("%q hash = %d, base %q hash = %d", tt.emoticon, full.Hash, tt.base, base.Hash)
|
||||
}
|
||||
if again, err := r.onMessagesGetStickers(ctx, &tg.MessagesGetStickersRequest{
|
||||
Emoticon: tt.emoticon,
|
||||
Hash: full.Hash,
|
||||
}); err != nil {
|
||||
t.Fatalf("getStickers %q hash: %v", tt.emoticon, err)
|
||||
} else if _, ok := again.(*tg.MessagesStickersNotModified); !ok {
|
||||
t.Fatalf("getStickers %q with matching hash = %T, want NotModified", tt.emoticon, again)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if ids := stickerDocIDs(t, mustStickers(t, r, ctx, "👋🔥", 0)); len(ids) != 0 {
|
||||
t.Fatalf("ordinary compound emoji stickers = %v, want empty", ids)
|
||||
}
|
||||
}
|
||||
|
||||
func mustStickers(t *testing.T, r *Router, ctx context.Context, emoticon string, hash int64) tg.MessagesStickersClass {
|
||||
t.Helper()
|
||||
res, err := r.onMessagesGetStickers(ctx, &tg.MessagesGetStickersRequest{Emoticon: emoticon, Hash: hash})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue