From 8730fd6f34a6dc4e9cf20590c9b748af0399b495 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 24 Jan 2023 18:11:02 +0300 Subject: [PATCH] Add td_api::getEmojiCategories. --- CMakeLists.txt | 3 + td/generate/scheme/td_api.tl | 13 ++++ td/telegram/EmojiGroup.cpp | 49 +++++++++++++++ td/telegram/EmojiGroup.h | 69 +++++++++++++++++++++ td/telegram/EmojiGroup.hpp | 43 ++++++++++++++ td/telegram/StickersManager.cpp | 102 +++++++++++++++++++++++++++++++- td/telegram/StickersManager.h | 11 ++++ td/telegram/Td.cpp | 6 ++ td/telegram/Td.h | 2 + td/telegram/cli.cpp | 2 + 10 files changed, 297 insertions(+), 3 deletions(-) create mode 100644 td/telegram/EmojiGroup.cpp create mode 100644 td/telegram/EmojiGroup.h create mode 100644 td/telegram/EmojiGroup.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 408c81263..848f7b7b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -331,6 +331,7 @@ set(TDLIB_SOURCE td/telegram/DownloadManagerCallback.cpp td/telegram/DraftMessage.cpp td/telegram/EmailVerification.cpp + td/telegram/EmojiGroup.cpp td/telegram/EmojiStatus.cpp td/telegram/FileReferenceManager.cpp td/telegram/files/FileBitmask.cpp @@ -562,6 +563,7 @@ set(TDLIB_SOURCE td/telegram/DownloadManagerCallback.h td/telegram/DraftMessage.h td/telegram/EmailVerification.h + td/telegram/EmojiGroup.h td/telegram/EmojiStatus.h td/telegram/EncryptedFile.h td/telegram/FileReferenceManager.h @@ -761,6 +763,7 @@ set(TDLIB_SOURCE td/telegram/Document.hpp td/telegram/DocumentsManager.hpp td/telegram/DraftMessage.hpp + td/telegram/EmojiGroup.hpp td/telegram/FileReferenceManager.hpp td/telegram/files/FileData.hpp td/telegram/files/FileId.hpp diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 930ddeada..36806fdb1 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2940,6 +2940,16 @@ stickerSets total_count:int32 sets:vector = StickerSets; trendingStickerSets total_count:int32 sets:vector is_premium:Bool = TrendingStickerSets; +//@description Contains a list of similar emoji to search for in getStickers and searchStickers +//@name Name of the category +//@icon_custom_emoji_id Unique identifier of the custom emoji, which represents icon of the category +//@emojis List of emojis in the category +emojiCategory name:string icon_custom_emoji_id:int64 emojis:vector = EmojiCategory; + +//@description Represents a list of emoji categories @categories List of categories +emojiCategories categories:vector = EmojiCategories; + + //@class CallDiscardReason @description Describes the reason why a call was discarded //@description The call wasn't discarded, or the reason is unknown @@ -7296,6 +7306,9 @@ getStickerEmojis sticker:InputFile = Emojis; //@input_language_codes List of possible IETF language tags of the user's input language; may be empty if unknown searchEmojis text:string exact_match:Bool input_language_codes:vector = Emojis; +//@description Returns available emojis categories +getEmojiCategories = EmojiCategories; + //@description Returns an animated emoji corresponding to a given emoji. Returns a 404 error if the emoji has no animated emoji @emoji The emoji getAnimatedEmoji emoji:string = AnimatedEmoji; diff --git a/td/telegram/EmojiGroup.cpp b/td/telegram/EmojiGroup.cpp new file mode 100644 index 000000000..20894a65d --- /dev/null +++ b/td/telegram/EmojiGroup.cpp @@ -0,0 +1,49 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/telegram/EmojiGroup.h" + +#include "td/utils/algorithm.h" +#include "td/utils/Time.h" + +namespace td { + +EmojiGroup::EmojiGroup(telegram_api::object_ptr &&emoji_group) + : title_(std::move(emoji_group->title_)) + , icon_custom_emoji_id_(emoji_group->icon_emoji_id_) + , emojis_(std::move(emoji_group->emoticons_)) { +} + +td_api::object_ptr EmojiGroup::get_emoji_category_object() const { + return td_api::make_object(title_, icon_custom_emoji_id_.get(), vector(emojis_)); +} + +EmojiGroupList::EmojiGroupList(string &&used_language_codes, int32 hash, + vector> &&emoji_groups) + : used_language_codes_(std::move(used_language_codes)) + , hash_(hash) + , emoji_groups_(transform(std::move(emoji_groups), + [](telegram_api::object_ptr &&emoji_group) { + return EmojiGroup(std::move(emoji_group)); + })) + , next_reload_time_(Time::now() + 3600) { +} + +td_api::object_ptr EmojiGroupList::get_emoji_categories_object() const { + return td_api::make_object( + transform(emoji_groups_, [](const EmojiGroup &emoji_group) { return emoji_group.get_emoji_category_object(); })); +} + +bool EmojiGroupList::is_expired() const { + return next_reload_time_ < Time::now(); +} + +void EmojiGroupList::update_next_reload_time() { + next_reload_time_ = Time::now() + 3600; +} + + +} // namespace td diff --git a/td/telegram/EmojiGroup.h b/td/telegram/EmojiGroup.h new file mode 100644 index 000000000..c93f47a40 --- /dev/null +++ b/td/telegram/EmojiGroup.h @@ -0,0 +1,69 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/telegram/CustomEmojiId.h" +#include "td/telegram/td_api.h" +#include "td/telegram/telegram_api.h" + +#include "td/utils/common.h" + +namespace td { + +class EmojiGroup { + string title_; + CustomEmojiId icon_custom_emoji_id_; + vector emojis_; + + public: + EmojiGroup() = default; + + explicit EmojiGroup(telegram_api::object_ptr &&emoji_group); + + td_api::object_ptr get_emoji_category_object() const; + + template + void store(StorerT &storer) const; + + template + void parse(ParserT &parser); +}; + +class EmojiGroupList { + string used_language_codes_; + int32 hash_ = 0; + vector emoji_groups_; + double next_reload_time_ = 0.0; + + public: + EmojiGroupList() = default; + + EmojiGroupList(string &&used_language_codes, int32 hash, + vector> &&emoji_groups); + + td_api::object_ptr get_emoji_categories_object() const; + + const string &get_used_language_codes() const { + return used_language_codes_; + } + + int32 get_hash() const { + return hash_; + } + + bool is_expired() const; + + void update_next_reload_time(); + + template + void store(StorerT &storer) const; + + template + void parse(ParserT &parser); +}; + +} // namespace td diff --git a/td/telegram/EmojiGroup.hpp b/td/telegram/EmojiGroup.hpp new file mode 100644 index 000000000..a5fef879c --- /dev/null +++ b/td/telegram/EmojiGroup.hpp @@ -0,0 +1,43 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/telegram/EmojiGroup.h" + +#include "td/utils/tl_helpers.h" + +namespace td { + +template +void EmojiGroup::store(StorerT &storer) const { + td::store(title_, storer); + td::store(icon_custom_emoji_id_, storer); + td::store(emojis_, storer); +} + +template +void EmojiGroup::parse(ParserT &parser) { + td::parse(title_, parser); + td::parse(icon_custom_emoji_id_, parser); + td::parse(emojis_, parser); +} + +template +void EmojiGroupList::store(StorerT &storer) const { + td::store(used_language_codes_, storer); + td::store(hash_, storer); + td::store(emoji_groups_, storer); +} + +template +void EmojiGroupList::parse(ParserT &parser) { + td::parse(used_language_codes_, parser); + td::parse(hash_, parser); + td::parse(emoji_groups_, parser); +} + +} // namespace td diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index 95d7c29ae..b116f7ecd 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -1345,6 +1345,32 @@ class GetCustomEmojiDocumentsQuery final : public Td::ResultHandler { } }; +class GetEmojiGroupsQuery final : public Td::ResultHandler { + Promise> promise_; + + public: + explicit GetEmojiGroupsQuery(Promise> &&promise) + : promise_(std::move(promise)) { + } + + void send(int32 hash) { + send_query(G()->net_query_creator().create(telegram_api::messages_getEmojiGroups(hash))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + promise_.set_value(result_ptr.move_as_ok()); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + class GetDefaultDialogPhotoEmojisQuery final : public Td::ResultHandler { Promise> promise_; @@ -6600,6 +6626,7 @@ void StickersManager::on_get_default_dialog_photo_custom_emoji_ids_success(bool are_default_dialog_photo_custom_emoji_ids_loaded_[for_user] = true; auto promises = std::move(default_dialog_photo_custom_emoji_ids_load_queries_[for_user]); + reset_to_empty(default_dialog_photo_custom_emoji_ids_load_queries_[for_user]); for (auto &promise : promises) { get_custom_emoji_stickers(default_dialog_photo_custom_emoji_ids_[for_user], true, std::move(promise)); } @@ -9553,8 +9580,7 @@ void StickersManager::on_get_language_codes(const string &key, Result StickersManager::get_emoji_language_codes(const vector &input_language_codes, Slice text, - Promise &promise) { +vector StickersManager::get_used_language_codes(const vector &input_language_codes, Slice text) const { vector language_codes = td_->language_pack_manager_.get_actor_unsafe()->get_used_language_codes(); auto system_language_code = G()->mtproto_header().get_system_language_code(); if (system_language_code.size() >= 2 && system_language_code.find('$') == string::npos && @@ -9582,12 +9608,18 @@ vector StickersManager::get_emoji_language_codes(const vector &i } } } + td::unique(language_codes); if (language_codes.empty()) { LOG(INFO) << "List of language codes is empty"; language_codes.push_back("en"); } - td::unique(language_codes); + return language_codes; +} + +vector StickersManager::get_emoji_language_codes(const vector &input_language_codes, Slice text, + Promise &promise) { + auto language_codes = get_used_language_codes(input_language_codes, text); LOG(DEBUG) << "Have language codes " << language_codes; auto key = get_emoji_language_codes_database_key(language_codes); @@ -9923,6 +9955,70 @@ td_api::object_ptr StickersManager::get_emoji_suggestions_url_r return result; } +void StickersManager::get_emoji_categories(Promise> &&promise) { + auto used_language_codes = implode(get_used_language_codes({}, Slice()), '$'); + LOG(INFO) << "Have language codes " << used_language_codes; + if (emoji_group_list_.get_used_language_codes() == used_language_codes) { + promise.set_value(emoji_group_list_.get_emoji_categories_object()); + if (!emoji_group_list_.is_expired()) { + return; + } + promise = Promise>(); + } + + emoji_group_load_queries_.push_back(std::move(promise)); + if (emoji_group_load_queries_.size() != 1) { + // query has already been sent, just wait for the result + return; + } + + auto query_promise = + PromiseCreator::lambda([actor_id = actor_id(this), used_language_codes = std::move(used_language_codes)]( + Result> r_emoji_groups) { + send_closure(actor_id, &StickersManager::on_get_emoji_categories, std::move(used_language_codes), + std::move(r_emoji_groups)); + }); + td_->create_handler(std::move(query_promise))->send(emoji_group_list_.get_hash()); +} + +void StickersManager::on_get_emoji_categories( + string used_language_codes, Result> r_emoji_groups) { + if (G()->close_flag()) { + r_emoji_groups = Global::request_aborted_error(); + } + if (r_emoji_groups.is_error()) { + if (!G()->is_expected_error(r_emoji_groups.error())) { + LOG(ERROR) << "Receive " << r_emoji_groups.error() << " from GetEmojiGroupsQuery"; + } + return fail_promises(emoji_group_load_queries_, r_emoji_groups.move_as_error()); + } + + auto new_used_language_codes = implode(get_used_language_codes({}, Slice()), '$'); + if (new_used_language_codes != used_language_codes) { + used_language_codes.clear(); + } + + auto emoji_groups = r_emoji_groups.move_as_ok(); + switch (emoji_groups->get_id()) { + case telegram_api::messages_emojiGroupsNotModified::ID: + emoji_group_list_.update_next_reload_time(); + break; + case telegram_api::messages_emojiGroups::ID: { + auto groups = telegram_api::move_object_as(emoji_groups); + emoji_group_list_ = EmojiGroupList(std::move(used_language_codes), groups->hash_, std::move(groups->groups_)); + break; + } + default: + UNREACHABLE(); + } + + auto promises = std::move(emoji_group_load_queries_); + reset_to_empty(emoji_group_load_queries_); + for (auto &promise : promises) { + promise.set_value(emoji_group_list_.get_emoji_categories_object()); + } +} + void StickersManager::get_current_state(vector> &updates) const { if (td_->auth_manager_->is_bot()) { return; diff --git a/td/telegram/StickersManager.h b/td/telegram/StickersManager.h index 17ec9cfb8..17bc633a1 100644 --- a/td/telegram/StickersManager.h +++ b/td/telegram/StickersManager.h @@ -9,6 +9,7 @@ #include "td/telegram/CustomEmojiId.h" #include "td/telegram/DialogId.h" #include "td/telegram/Dimensions.h" +#include "td/telegram/EmojiGroup.h" #include "td/telegram/files/FileId.h" #include "td/telegram/files/FileSourceId.h" #include "td/telegram/FullMessageId.h" @@ -364,6 +365,8 @@ class StickersManager final : public Actor { int64 get_emoji_suggestions_url(const string &language_code, Promise &&promise); + void get_emoji_categories(Promise> &&promise); + td_api::object_ptr get_emoji_suggestions_url_result(int64 random_id); void reload_sticker_set(StickerSetId sticker_set_id, int64 access_hash, Promise &&promise); @@ -971,6 +974,8 @@ class StickersManager final : public Actor { double get_emoji_language_code_last_difference_time(const string &language_code); + vector get_used_language_codes(const vector &input_language_codes, Slice text) const; + vector get_emoji_language_codes(const vector &input_language_codes, Slice text, Promise &promise); @@ -996,6 +1001,9 @@ class StickersManager final : public Actor { void on_get_emoji_suggestions_url(int64 random_id, Promise &&promise, Result> &&r_emoji_url); + void on_get_emoji_categories(string used_language_codes, + Result> r_emoji_groups); + Td *td_; ActorShared<> parent_; @@ -1173,6 +1181,9 @@ class StickersManager final : public Actor { string emoji_sounds_str_; FlatHashMap emoji_sounds_; + EmojiGroupList emoji_group_list_; + vector>> emoji_group_load_queries_; + vector default_dialog_photo_custom_emoji_ids_[2]; int64 default_dialog_photo_custom_emoji_ids_hash_[2] = {0, 0}; vector>> default_dialog_photo_custom_emoji_ids_load_queries_[2]; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 3e2bbb6ab..33db70e0d 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -7348,6 +7348,12 @@ void Td::on_request(uint64 id, td_api::searchEmojis &request) { std::move(request.input_language_codes_)); } +void Td::on_request(uint64 id, const td_api::getEmojiCategories &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + stickers_manager_->get_emoji_categories(std::move(promise)); +} + void Td::on_request(uint64 id, td_api::getAnimatedEmoji &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.emoji_); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 6a34d7f7a..6c42a7a26 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -1213,6 +1213,8 @@ class Td final : public Actor { void on_request(uint64 id, td_api::searchEmojis &request); + void on_request(uint64 id, const td_api::getEmojiCategories &request); + void on_request(uint64 id, td_api::getAnimatedEmoji &request); void on_request(uint64 id, td_api::getEmojiSuggestionsUrl &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 5d0d19c13..68cea0c95 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2921,6 +2921,8 @@ class CliClient final : public Actor { send_request(td_api::make_object(args, true, vector())); } else if (op == "seru") { send_request(td_api::make_object(args, false, vector{"ru_RU"})); + } else if (op == "gec") { + send_request(td_api::make_object()); } else if (op == "gae") { send_request(td_api::make_object(args)); } else if (op == "gesu") {