This commit is contained in:
onysd 2026-08-25 00:01:59 +03:00
parent ed2e61d32a
commit fe1cf1184f

View file

@ -4,6 +4,9 @@ import (
"context" "context"
"strconv" "strconv"
"strings" "strings"
"unicode"
"go.uber.org/zap"
"telesrv/internal/domain" "telesrv/internal/domain"
"telesrv/internal/seed/catalog" "telesrv/internal/seed/catalog"
@ -45,7 +48,8 @@ func (s *Service) OnInlineQuery(ctx context.Context, botUserID, _ int64, query,
if err != nil { if err != nil {
return domain.BotInlineResults{}, false, err return domain.BotInlineResults{}, false, err
} }
if category := gifCategoryFromQuery(query); category != "" { category := gifCategoryFromQuery(query)
if category != "" {
// A category-icon tap, not a typed word (see gifCategoryFromQuery) -- // A category-icon tap, not a typed word (see gifCategoryFromQuery) --
// filter by domain.GifCatalogEntry.Category instead of ranking by // filter by domain.GifCatalogEntry.Category instead of ranking by
// title, since the query is an emoji/emoji-blob a title never // title, since the query is an emoji/emoji-blob a title never
@ -54,6 +58,11 @@ func (s *Service) OnInlineQuery(ctx context.Context, botUserID, _ int64, query,
} else { } else {
entries = rankGifCatalogEntries(entries, query) entries = rankGifCatalogEntries(entries, query)
} }
if s.log != nil {
s.log.Info("gif inline query",
zap.String("query", query), zap.String("detected_category", category),
zap.Int("result_count", len(entries)))
}
if len(entries) == 0 { if len(entries) == 0 {
return domain.BotInlineResults{Gallery: true}, true, nil return domain.BotInlineResults{Gallery: true}, true, nil
} }
@ -103,26 +112,18 @@ func (s *Service) OnInlineQuery(ctx context.Context, botUserID, _ int64, query,
// (sort_order, id) order the store already applied. // (sort_order, id) order the store already applied.
// gifCategoryFromQuery recognizes a GIF-picker category-icon tap and returns // gifCategoryFromQuery recognizes a GIF-picker category-icon tap and returns
// which domain.GifCatalogCategories entry it names, or "" for an ordinary // which domain.GifCatalogCategories entry it names, or "" for an ordinary
// typed search. // typed search. Neither client sends the category's name -- both instead
// // send the tapped group's own Emoticons back as the query, observed (see
// The two clients encode a tap completely differently, and neither sends the // the "gif inline query" log line this handler emits) to differ only in
// category's name: // whitespace between clients: Android sends them concatenated with no
// - Android (StickerCategoriesListView.EmojiCategory.remote, EmojiView.java) // separator, TDesktop space-separated. Comparing with all whitespace
// concatenates the whole tapped group's emoticons with no separator and // stripped from the query handles both without caring which client asked,
// sends that as the query -- an exact match against // and is why this checks against internal/seed/catalog data directly (the
// strings.Join(group.Emoticons, ""). // same source messages.getEmojiGroups itself serves) rather than hardcoding
// - TDesktop (GifSectionsValue, stickers_list_footer.cpp) reads a *separate* // either shape.
// fixed emoji list (app config's gif_search_emojies, defaulting to 10
// emoji including some this server never configured) and sends the
// single tapped emoji as the query -- an exact match against one
// Emoticons entry.
//
// Both are checked against the same internal/seed/catalog data (the source of
// truth messages.getEmojiGroups itself serves), so no client-side changes or
// server-side emoji-list duplication are needed.
func gifCategoryFromQuery(query string) string { func gifCategoryFromQuery(query string) string {
query = strings.TrimSpace(query) stripped := stripWhitespace(query)
if query == "" { if stripped == "" {
return "" return ""
} }
groups, _ := catalog.EmojiGroups() groups, _ := catalog.EmojiGroups()
@ -130,13 +131,13 @@ func gifCategoryFromQuery(query string) string {
if len(g.Emoticons) == 0 { if len(g.Emoticons) == 0 {
continue continue
} }
if strings.Join(g.Emoticons, "") == query { if strings.Join(g.Emoticons, "") == stripped {
return g.Title return g.Title
} }
} }
for _, g := range groups { for _, g := range groups {
for _, e := range g.Emoticons { for _, e := range g.Emoticons {
if e == query { if e == stripped {
return g.Title return g.Title
} }
} }
@ -144,6 +145,15 @@ func gifCategoryFromQuery(query string) string {
return "" return ""
} }
func stripWhitespace(s string) string {
return strings.Map(func(r rune) rune {
if unicode.IsSpace(r) {
return -1
}
return r
}, s)
}
// filterGifCatalogEntriesByCategory keeps only entries tagged with category, // filterGifCatalogEntriesByCategory keeps only entries tagged with category,
// falling back to the full (enabled) catalog if none are tagged yet -- an // falling back to the full (enabled) catalog if none are tagged yet -- an
// operator who hasn't categorized anything should still see every GIF on a // operator who hasn't categorized anything should still see every GIF on a