diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 87bc6b797..fd67640cf 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -1707,6 +1707,9 @@ messageVenue venue:venue = MessageContent; //@description A message with a user contact @contact The contact description messageContact contact:contact = MessageContent; +//@description A message with an animated emoji @sticker The animated sticker with the emoji animation @emoji The corresponding emoji +messageAnimatedEmoji sticker:sticker emoji:string = MessageContent; + //@description A dice message. The dice value is randomly generated by the server //@initial_state The animated stickers with the initial dice animation; may be null if unknown. updateMessageContent will be sent when the sticker became known //@final_state The animated stickers with the final dice animation; may be null if unknown. updateMessageContent will be sent when the sticker became known diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index dd480bb87..c9a180569 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -1360,6 +1360,7 @@ void StickersManager::load_special_sticker_set_by_type(const SpecialStickerSetTy } void StickersManager::load_special_sticker_set(SpecialStickerSet &sticker_set) { + CHECK(!td_->auth_manager_->is_bot()); if (sticker_set.is_being_loaded_) { return; } @@ -1407,23 +1408,17 @@ void StickersManager::on_load_special_sticker_set(const SpecialStickerSetType &t CHECK(sticker_set->was_loaded); if (type.type_ == SpecialStickerSetType::animated_emoji()) { - for (auto sticker_it : sticker_set->sticker_emojis_map_) { - for (auto &emoji : sticker_it.second) { - auto it = emoji_messages_.find(emoji); - if (it == emoji_messages_.end()) { - continue; - } - - vector full_message_ids; - for (auto full_message_id : it->second) { + vector full_message_ids; + for (const auto &it : emoji_messages_) { + if (get_animated_emoji_sticker(sticker_set, it.first).first.is_valid()) { + for (auto full_message_id : it.second) { full_message_ids.push_back(full_message_id); } - CHECK(!full_message_ids.empty()); - for (auto full_message_id : full_message_ids) { - td_->messages_manager_->on_external_update_message_content(full_message_id); - } } } + for (auto full_message_id : full_message_ids) { + td_->messages_manager_->on_external_update_message_content(full_message_id); + } return; } @@ -1916,8 +1911,64 @@ tl_object_ptr StickersManager::get_sticker_set_info_obje std::move(stickers)); } +std::pair StickersManager::get_animated_emoji_sticker(const StickerSet *sticker_set, const string &emoji) { + auto emoji_without_modifiers = remove_emoji_modifiers(emoji).str(); + auto it = sticker_set->emoji_stickers_map_.find(emoji_without_modifiers); + if (it == sticker_set->emoji_stickers_map_.end()) { + return {}; + } + + // trying to find full emoji match + for (const auto &sticker_id : it->second) { + auto emoji_it = sticker_set->sticker_emojis_map_.find(sticker_id); + CHECK(emoji_it != sticker_set->sticker_emojis_map_.end()); + if (td::contains(emoji_it->second, emoji)) { + return {sticker_id, 0}; + } + } + + // trying to find match without Fitzpatrick modifiers + int modifier_id = get_fitzpatrick_modifier(emoji); + if (modifier_id > 0) { + for (const auto &sticker_id : it->second) { + auto emoji_it = sticker_set->sticker_emojis_map_.find(sticker_id); + CHECK(emoji_it != sticker_set->sticker_emojis_map_.end()); + if (td::contains(emoji_it->second, Slice(emoji).remove_suffix(4))) { + return {sticker_id, modifier_id}; + } + } + } + + // there is no match + return {}; +} + +std::pair StickersManager::get_animated_emoji_sticker(const string &emoji) { + if (td_->auth_manager_->is_bot()) { + return {}; + } + auto &special_sticker_set = add_special_sticker_set(SpecialStickerSetType::animated_emoji()); + if (!special_sticker_set.id_.is_valid()) { + load_special_sticker_set(special_sticker_set); + return {}; + } + + auto sticker_set = get_sticker_set(special_sticker_set.id_); + CHECK(sticker_set != nullptr); + if (!sticker_set->was_loaded) { + load_special_sticker_set(special_sticker_set); + return {}; + } + + return get_animated_emoji_sticker(sticker_set, emoji); +} + td_api::object_ptr StickersManager::get_message_content_animated_emoji_object( const string &emoji) { + auto animated_sticker = get_animated_emoji_sticker(emoji); + if (animated_sticker.first.is_valid()) { + return td_api::make_object(get_sticker_object(animated_sticker.first), emoji); + } return td_api::make_object( td_api::make_object(emoji, std::vector>()), nullptr); @@ -4139,7 +4190,7 @@ int StickersManager::get_emoji_number(Slice emoji) { return emoji[0] - '0'; } -vector StickersManager::get_animated_emoji_stickers(const StickerSet *sticker_set, Slice emoji) const { +vector StickersManager::get_animated_emoji_click_stickers(const StickerSet *sticker_set, Slice emoji) const { vector result; for (auto sticker_id : sticker_set->sticker_ids) { auto s = get_sticker(sticker_id); @@ -4151,7 +4202,7 @@ vector StickersManager::get_animated_emoji_stickers(const StickerSet *st if (result.empty()) { const static vector heart_emojis{"๐Ÿ’›", "๐Ÿ’™", "๐Ÿ’š", "๐Ÿ’œ", "๐Ÿงก", "๐Ÿ–ค", "๐ŸคŽ", "๐Ÿค"}; if (td::contains(heart_emojis, emoji)) { - return get_animated_emoji_stickers(sticker_set, Slice("โค")); + return get_animated_emoji_click_stickers(sticker_set, Slice("โค")); } } return result; @@ -4172,7 +4223,7 @@ void StickersManager::choose_animated_emoji_click_sticker(const StickerSet *stic return promise.set_value(nullptr); } - auto all_sticker_ids = get_animated_emoji_stickers(sticker_set, message_text); + auto all_sticker_ids = get_animated_emoji_click_stickers(sticker_set, message_text); vector> found_stickers; for (auto sticker_id : all_sticker_ids) { auto it = sticker_set->sticker_emojis_map_.find(sticker_id); @@ -4322,6 +4373,10 @@ bool StickersManager::is_sent_animated_emoji_click(DialogId dialog_id, Slice emo } Status StickersManager::on_animated_emoji_message_clicked(Slice emoji, FullMessageId full_message_id, string data) { + if (td_->auth_manager_->is_bot()) { + return Status::OK(); + } + TRY_RESULT(value, json_decode(data)); if (value.type() != JsonValue::Type::Object) { return Status::Error("Expected an object"); @@ -4402,7 +4457,7 @@ void StickersManager::schedule_update_animated_emoji_clicked(const StickerSet *s return; } - auto all_sticker_ids = get_animated_emoji_stickers(sticker_set, emoji); + auto all_sticker_ids = get_animated_emoji_click_stickers(sticker_set, emoji); std::unordered_map sticker_ids; for (auto sticker_id : all_sticker_ids) { auto it = sticker_set->sticker_emojis_map_.find(sticker_id); diff --git a/td/telegram/StickersManager.h b/td/telegram/StickersManager.h index 8a1427488..ab830f38c 100644 --- a/td/telegram/StickersManager.h +++ b/td/telegram/StickersManager.h @@ -603,7 +603,11 @@ class StickersManager final : public Actor { static int get_emoji_number(Slice emoji); - vector get_animated_emoji_stickers(const StickerSet *sticker_set, Slice emoji) const; + static std::pair get_animated_emoji_sticker(const StickerSet *sticker_set, const string &emoji); + + std::pair get_animated_emoji_sticker(const string &emoji); + + vector get_animated_emoji_click_stickers(const StickerSet *sticker_set, Slice emoji) const; void choose_animated_emoji_click_sticker(const StickerSet *sticker_set, Slice message_text, FullMessageId full_message_id, double start_time, diff --git a/tdutils/td/utils/emoji.cpp b/tdutils/td/utils/emoji.cpp index 918aff2ff..37ce7743e 100644 --- a/tdutils/td/utils/emoji.cpp +++ b/tdutils/td/utils/emoji.cpp @@ -839,6 +839,18 @@ bool is_emoji(Slice str) { return emojis.count(str) != 0; } +int get_fitzpatrick_modifier(Slice emoji) { + if (emoji.size() < 4 || emoji[emoji.size() - 4] != '\xF0' || emoji[emoji.size() - 3] != '\x9F' || + emoji[emoji.size() - 2] != '\x8F') { + return 0; + } + auto c = static_cast(emoji.back()); + if (c < 0xBB || c > 0xBF) { + return 0; + } + return (c - 0xBB) + 2; +} + Slice remove_emoji_modifiers(Slice emoji) { static const Slice modifiers[] = {u8"\uFE0E" /* variation selector-15 */, u8"\uFE0F" /* variation selector-16 */, diff --git a/tdutils/td/utils/emoji.h b/tdutils/td/utils/emoji.h index 4a0020187..89018cb1a 100644 --- a/tdutils/td/utils/emoji.h +++ b/tdutils/td/utils/emoji.h @@ -14,6 +14,9 @@ namespace td { // checks whether the string is an emoji; variation selectors are ignored bool is_emoji(Slice str); +// checks whether emoji ends on a Fitzpatrick modifier and returns it's number or 0 +int get_fitzpatrick_modifier(Slice emoji); + // removes all emoji modifiers from the end of the string Slice remove_emoji_modifiers(Slice emoji);