diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 31d5c7f03..a23c126c1 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2500,9 +2500,12 @@ clearImportedContacts = Ok; getUserProfilePhotos user_id:int32 offset:int32 limit:int32 = UserProfilePhotos; -//@description Returns stickers from the installed sticker sets that correspond to a given emoji. If the emoji is not empty, favorite and recently used stickers may also be returned @emoji String representation of emoji. If empty, returns all known stickers @limit Maximum number of stickers to be returned +//@description Returns stickers from the installed sticker sets that correspond to a given emoji. If the emoji is not empty, favorite, recently used and trending stickers may also be returned @emoji String representation of emoji. If empty, returns all known installed stickers @limit Maximum number of stickers to be returned getStickers emoji:string limit:int32 = Stickers; +//@description Searches for stickers from public sticker sets that correspond to a given emoji. May exclude some stickers returned by getStickers from the results @emoji String representation of emoji; must be non-empty @limit Maximum number of stickers to be returned +searchStickers emoji:string limit:int32 = Stickers; + //@description Returns a list of installed sticker sets @is_masks Pass true to return mask sticker sets; pass false to return ordinary sticker sets getInstalledStickerSets is_masks:Bool = StickerSets; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index ee531d292..849794bf3 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index 32b2165eb..816460e40 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -73,6 +73,34 @@ class GetAllStickersQuery : public Td::ResultHandler { } }; +class SearchStickersQuery : public Td::ResultHandler { + string emoji_; + + public: + void send(string emoji) { + emoji_ = std::move(emoji); + int32 flags = telegram_api::messages_getStickers::EXCLUDE_FEATURED_MASK; + send_query(G()->net_query_creator().create( + create_storer(telegram_api::messages_getStickers(flags, false /*ignored*/, emoji_, "")))); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for search stickers: " << to_string(ptr); + td->stickers_manager_->on_find_stickers_success(emoji_, std::move(ptr)); + } + + void on_error(uint64 id, Status status) override { + LOG(ERROR) << "Receive error for search stickers: " << status; + td->stickers_manager_->on_find_stickers_fail(emoji_, std::move(status)); + } +}; + class GetArchivedStickerSetsQuery : public Td::ResultHandler { Promise promise_; bool is_masks_; @@ -1885,6 +1913,93 @@ vector StickersManager::get_stickers(string emoji, int32 limit, bool for return result; } +vector StickersManager::search_stickers(string emoji, int32 limit, Promise &&promise) { + if (td_->auth_manager_->is_bot()) { + promise.set_error(Status::Error(7, "Method is not available for bots")); + return {}; + } + if (limit <= 0) { + promise.set_error(Status::Error(3, "Parameter limit must be positive")); + return {}; + } + if (limit > MAX_FOUND_STICKERS) { + limit = MAX_FOUND_STICKERS; + } + if (emoji.empty()) { + promise.set_error(Status::Error(3, "Emoji must be non-empty")); + return {}; + } + + emoji = remove_emoji_modifiers(emoji); + if (emoji.empty()) { + promise.set_value(Unit()); + return {}; + } + + auto it = found_stickers_.find(emoji); + if (it != found_stickers_.end()) { + promise.set_value(Unit()); + auto result_size = min(static_cast(limit), it->second.size()); + return vector(it->second.begin(), it->second.begin() + result_size); + } + + auto &promises = search_stickers_queries_[emoji]; + promises.push_back(std::move(promise)); + if (promises.size() == 1u) { + td_->create_handler()->send(std::move(emoji)); + } + + return {}; +} + +void StickersManager::on_find_stickers_success(const string &emoji, + tl_object_ptr &&stickers) { + CHECK(stickers != nullptr); + switch (stickers->get_id()) { + case telegram_api::messages_stickersNotModified::ID: + return on_find_stickers_fail(emoji, Status::Error(500, "Receive messages.stickerNotModified")); + case telegram_api::messages_stickers::ID: { + auto found_stickers = move_tl_object_as(stickers); + vector &sticker_ids = found_stickers_[emoji]; + CHECK(sticker_ids.empty()); + + for (auto &sticker : found_stickers->stickers_) { + FileId sticker_id = on_get_sticker_document(std::move(sticker), false).second; + if (sticker_id.is_valid()) { + sticker_ids.push_back(sticker_id); + } + } + break; + } + default: + UNREACHABLE(); + } + + auto it = search_stickers_queries_.find(emoji); + CHECK(it != search_stickers_queries_.end()); + CHECK(!it->second.empty()); + auto promises = std::move(it->second); + search_stickers_queries_.erase(it); + + for (auto &promise : promises) { + promise.set_value(Unit()); + } +} + +void StickersManager::on_find_stickers_fail(const string &emoji, Status &&error) { + CHECK(found_stickers_.count(emoji) == 0); + + auto it = search_stickers_queries_.find(emoji); + CHECK(it != search_stickers_queries_.end()); + CHECK(!it->second.empty()); + auto promises = std::move(it->second); + search_stickers_queries_.erase(it); + + for (auto &promise : promises) { + promise.set_error(error.clone()); + } +} + vector StickersManager::get_installed_sticker_sets(bool is_masks, Promise &&promise) { if (!are_installed_sticker_sets_loaded_[is_masks]) { load_installed_sticker_sets(is_masks, std::move(promise)); diff --git a/td/telegram/StickersManager.h b/td/telegram/StickersManager.h index 55be468f3..367c8c596 100644 --- a/td/telegram/StickersManager.h +++ b/td/telegram/StickersManager.h @@ -67,6 +67,8 @@ class StickersManager : public Actor { vector get_stickers(string emoji, int32 limit, bool force, Promise &&promise); + vector search_stickers(string emoji, int32 limit, Promise &&promise); + vector get_installed_sticker_sets(bool is_masks, Promise &&promise); int64 add_sticker_set(tl_object_ptr &&set_ptr); @@ -200,6 +202,10 @@ class StickersManager : public Actor { void on_uploaded_sticker_file(FileId file_id, tl_object_ptr media, Promise &&promise); + void on_find_stickers_success(const string &emoji, tl_object_ptr &&sticker_sets); + + void on_find_stickers_fail(const string &emoji, Status &&error); + void on_find_sticker_sets_success(const string &query, tl_object_ptr &&sticker_sets); @@ -208,6 +214,7 @@ class StickersManager : public Actor { private: static constexpr int32 MAX_FEATURED_STICKER_SET_VIEW_DELAY = 5; + static constexpr int32 MAX_FOUND_STICKERS = 100; // server side limit static constexpr int64 MAX_STICKER_FILE_SIZE = 1 << 19; // server side limit static constexpr size_t MAX_STICKER_SET_TITLE_LENGTH = 64; // server side limit static constexpr size_t MAX_STICKER_SET_SHORT_NAME_LENGTH = 64; // server side limit @@ -468,6 +475,9 @@ class StickersManager : public Actor { Hints installed_sticker_sets_hints_[2]; // search installed sticker sets by their title and name + std::unordered_map> found_stickers_; + std::unordered_map>> search_stickers_queries_; + std::unordered_map> found_sticker_sets_; std::unordered_map>> search_sticker_sets_queries_; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 4bb15914b..01cb01ecb 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -2770,6 +2770,26 @@ class GetStickersRequest : public RequestActor<> { } }; +class SearchStickersRequest : public RequestActor<> { + string emoji_; + int32 limit_; + + vector sticker_ids_; + + void do_run(Promise &&promise) override { + sticker_ids_ = td->stickers_manager_->search_stickers(emoji_, limit_, std::move(promise)); + } + + void do_send_result() override { + send_result(td->stickers_manager_->get_stickers_object(sticker_ids_)); + } + + public: + SearchStickersRequest(ActorShared td, uint64 request_id, string &&emoji, int32 limit) + : RequestActor(std::move(td), request_id), emoji_(std::move(emoji)), limit_(limit) { + } +}; + class GetInstalledStickerSetsRequest : public RequestActor<> { bool is_masks_; @@ -6277,6 +6297,13 @@ void Td::on_request(uint64 id, td_api::getStickers &request) { CREATE_REQUEST(GetStickersRequest, std::move(request.emoji_), request.limit_); } +void Td::on_request(uint64 id, td_api::searchStickers &request) { + CHECK_AUTH(); + CHECK_IS_USER(); + CLEAN_INPUT_STRING(request.emoji_); + CREATE_REQUEST(SearchStickersRequest, std::move(request.emoji_), request.limit_); +} + void Td::on_request(uint64 id, const td_api::getInstalledStickerSets &request) { CHECK_AUTH(); CHECK_IS_USER(); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index 23b55f1e3..eb49e9370 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -645,6 +645,8 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, td_api::getStickers &request); + void on_request(uint64 id, td_api::searchStickers &request); + void on_request(uint64 id, const td_api::getInstalledStickerSets &request); void on_request(uint64 id, const td_api::getArchivedStickerSets &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index ee77cf189..df0df9005 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -1531,6 +1531,11 @@ class CliClient final : public Actor { string emoji; std::tie(limit, emoji) = split(args); send_request(make_tl_object(emoji, to_integer(limit))); + } else if (op == "sst") { + string limit; + string emoji; + std::tie(limit, emoji) = split(args); + send_request(make_tl_object(emoji, to_integer(limit))); } else if (op == "gss") { send_request(make_tl_object(to_integer(args))); } else if (op == "giss") {