diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 101b1c59..efea7d4a 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -217,8 +217,8 @@ document file_name:string mime_type:string minithumbnail:minithumbnail thumbnail photo has_stickers:Bool minithumbnail:minithumbnail sizes:vector = Photo; //@description Describes a sticker @set_id The identifier of the sticker set to which the sticker belongs; 0 if none @width Sticker width; as defined by the sender @height Sticker height; as defined by the sender -//@emoji Emoji corresponding to the sticker @is_mask True, if the sticker is a mask @mask_position Position where the mask should be placed; may be null @thumbnail Sticker thumbnail in WEBP or JPEG format; may be null @sticker File containing the sticker -sticker set_id:int64 width:int32 height:int32 emoji:string is_mask:Bool mask_position:maskPosition thumbnail:photoSize sticker:file = Sticker; +//@emoji Emoji corresponding to the sticker @is_animated True, if the sticker is an animated sticker in TGS format @is_mask True, if the sticker is a mask @mask_position Position where the mask should be placed; may be null @thumbnail Sticker thumbnail in WEBP or JPEG format; may be null @sticker File containing the sticker +sticker set_id:int64 width:int32 height:int32 emoji:string is_animated:Bool is_mask:Bool mask_position:maskPosition thumbnail:photoSize sticker:file = Sticker; //@description Describes a video file @duration Duration of the video, in seconds; as defined by the sender @width Video width; as defined by the sender @height Video height; as defined by the sender //@file_name Original name of the file; as defined by the sender @mime_type MIME type of the file; as defined by the sender @has_stickers True, if stickers were added to the photo @@ -1559,16 +1559,16 @@ emojis emojis:vector = Emojis; //@description Represents a sticker set //@id Identifier of the sticker set @title Title of the sticker set @name Name of the sticker set @thumbnail Sticker set thumbnail in WEBP format with width and height 100; may be null. The file can be downloaded only before the thumbnail is changed //@is_installed True, if the sticker set has been installed by the current user @is_archived True, if the sticker set has been archived. A sticker set can't be installed and archived simultaneously -//@is_official True, if the sticker set is official @is_masks True, if the stickers in the set are masks @is_viewed True for already viewed trending sticker sets +//@is_official True, if the sticker set is official @is_animated True, is the stickers in the set are animated @is_masks True, if the stickers in the set are masks @is_viewed True for already viewed trending sticker sets //@stickers List of stickers in this set @emojis A list of emoji corresponding to the stickers in the same order. The list is only for informational purposes, because a sticker is always sent with a fixed emoji from the corresponding Sticker object -stickerSet id:int64 title:string name:string thumbnail:photoSize is_installed:Bool is_archived:Bool is_official:Bool is_masks:Bool is_viewed:Bool stickers:vector emojis:vector = StickerSet; +stickerSet id:int64 title:string name:string thumbnail:photoSize is_installed:Bool is_archived:Bool is_official:Bool is_animated:Bool is_masks:Bool is_viewed:Bool stickers:vector emojis:vector = StickerSet; //@description Represents short information about a sticker set //@id Identifier of the sticker set @title Title of the sticker set @name Name of the sticker set @thumbnail Sticker set thumbnail in WEBP format with width and height 100; may be null //@is_installed True, if the sticker set has been installed by current user @is_archived True, if the sticker set has been archived. A sticker set can't be installed and archived simultaneously -//@is_official True, if the sticker set is official @is_masks True, if the stickers in the set are masks @is_viewed True for already viewed trending sticker sets +//@is_official True, if the sticker set is official @is_animated True, is the stickers in the set are animated @is_masks True, if the stickers in the set are masks @is_viewed True for already viewed trending sticker sets //@size Total number of stickers in the set @covers Contains up to the first 5 stickers from the set, depending on the context. If the client needs more stickers the full set should be requested -stickerSetInfo id:int64 title:string name:string thumbnail:photoSize is_installed:Bool is_archived:Bool is_official:Bool is_masks:Bool is_viewed:Bool size:int32 covers:vector = StickerSetInfo; +stickerSetInfo id:int64 title:string name:string thumbnail:photoSize is_installed:Bool is_archived:Bool is_official:Bool is_animated:Bool is_masks:Bool is_viewed:Bool size:int32 covers:vector = StickerSetInfo; //@description Represents a list of sticker sets @total_count Approximate total number of sticker sets found @sets List of sticker sets stickerSets total_count:int32 sets:vector = StickerSets; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index 915d6b7a..12725b14 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/generate/scheme/telegram_api.tl b/td/generate/scheme/telegram_api.tl index 993230dd..4010a17d 100644 --- a/td/generate/scheme/telegram_api.tl +++ b/td/generate/scheme/telegram_api.tl @@ -500,7 +500,7 @@ inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; -stickerSet#eeb46f27 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize thumb_dc_id:flags.4?int count:int hash:int = StickerSet; +stickerSet#eeb46f27 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize thumb_dc_id:flags.4?int count:int hash:int = StickerSet; messages.stickerSet#b60a24a6 set:StickerSet packs:Vector documents:Vector = messages.StickerSet; diff --git a/td/generate/scheme/telegram_api.tlo b/td/generate/scheme/telegram_api.tlo index b6b94881..03921345 100644 Binary files a/td/generate/scheme/telegram_api.tlo and b/td/generate/scheme/telegram_api.tlo differ diff --git a/td/telegram/DocumentsManager.cpp b/td/telegram/DocumentsManager.cpp index 08afb6f1..d120f01d 100644 --- a/td/telegram/DocumentsManager.cpp +++ b/td/telegram/DocumentsManager.cpp @@ -212,10 +212,27 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo string minithumbnail; PhotoSize thumbnail; FileEncryptionKey encryption_key; + bool is_animated_sticker = false; bool is_web = false; bool is_web_no_proxy = false; string url; FileLocationSource source = FileLocationSource::FromServer; + + auto fix_animated_sticker_type = [&] { + if (mime_type != "application/x-tgsticker") { + return; + } + + is_animated_sticker = true; + if (document_type == Document::Type::General) { + document_type = Document::Type::Sticker; + file_type = FileType::Sticker; + default_extension = Slice("tgs"); + owner_dialog_id = DialogId(); + file_name.clear(); + } + }; + if (remote_document.document != nullptr) { auto document = std::move(remote_document.document); @@ -226,6 +243,8 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo mime_type = std::move(document->mime_type_); file_reference = document->file_reference_.as_slice().str(); + fix_animated_sticker_type(); + if (owner_dialog_id.get_type() == DialogType::SecretChat) { // secret_api::decryptedMessageMediaExternalDocument if (document_type != Document::Type::Sticker) { @@ -263,6 +282,8 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo return {}; } + fix_animated_sticker_type(); + if (document_type != Document::Type::VoiceNote) { thumbnail = get_secret_thumbnail_photo_size(td_->file_manager_.get(), std::move(document->thumb_), owner_dialog_id, document->thumb_w_, document->thumb_h_); @@ -310,6 +331,8 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo default: UNREACHABLE(); } + + fix_animated_sticker_type(); } LOG(DEBUG) << "Receive document with id = " << id << " of type " << document_type; @@ -383,7 +406,7 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo break; case Document::Type::Sticker: td_->stickers_manager_->create_sticker(file_id, std::move(thumbnail), dimensions, true, std::move(sticker), - load_data_multipromise_ptr); + is_animated_sticker, load_data_multipromise_ptr); break; case Document::Type::Video: td_->videos_manager_->create_video(file_id, std::move(minithumbnail), std::move(thumbnail), has_stickers, diff --git a/td/telegram/InlineQueriesManager.cpp b/td/telegram/InlineQueriesManager.cpp index c83c9f43..2bf9c570 100644 --- a/td/telegram/InlineQueriesManager.cpp +++ b/td/telegram/InlineQueriesManager.cpp @@ -914,8 +914,9 @@ tl_object_ptr copy(const td_api::photo &obj) { template <> tl_object_ptr copy(const td_api::sticker &obj) { - return make_tl_object(obj.set_id_, obj.width_, obj.height_, obj.emoji_, obj.is_mask_, - copy(obj.mask_position_), copy(obj.thumbnail_), copy(obj.sticker_)); + return make_tl_object(obj.set_id_, obj.width_, obj.height_, obj.emoji_, obj.is_animated_, + obj.is_mask_, copy(obj.mask_position_), copy(obj.thumbnail_), + copy(obj.sticker_)); } template <> diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index 8ad418ce..97fa375b 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -1579,8 +1579,9 @@ static Result create_input_message_content( } case td_api::inputMessageSticker::ID: { auto input_sticker = static_cast(input_message_content.get()); - td->stickers_manager_->create_sticker( - file_id, thumbnail, get_dimensions(input_sticker->width_, input_sticker->height_), true, nullptr, nullptr); + td->stickers_manager_->create_sticker(file_id, thumbnail, + get_dimensions(input_sticker->width_, input_sticker->height_), true, + nullptr, mime_type == "application/x-tgsticker", nullptr); content = make_unique(file_id); break; diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 551e68a1..69c9d04e 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -23966,13 +23966,13 @@ bool MessagesManager::update_message_content(DialogId dialog_id, Message *old_me auto new_file_type = new_file_view.get_type(); auto is_document_file_type = [](FileType file_type) { switch (file_type) { - case FileType::Video: - case FileType::VoiceNote: + case FileType::Animation: + case FileType::Audio: case FileType::Document: case FileType::Sticker: - case FileType::Audio: - case FileType::Animation: + case FileType::Video: case FileType::VideoNote: + case FileType::VoiceNote: return true; default: return false; diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index db31539e..22b2ef11 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -1084,7 +1084,7 @@ tl_object_ptr StickersManager::get_sticker_object(FileId file_i const PhotoSize &thumbnail = sticker->sticker_thumbnail.file_id.is_valid() ? sticker->sticker_thumbnail : sticker->message_thumbnail; return make_tl_object(sticker->set_id, sticker->dimensions.width, sticker->dimensions.height, - sticker->alt, sticker->is_mask, std::move(mask_position), + sticker->alt, sticker->is_animated, sticker->is_mask, std::move(mask_position), get_photo_size_object(td_->file_manager_.get(), &thumbnail), td_->file_manager_->get_file_object(file_id)); } @@ -1115,11 +1115,11 @@ tl_object_ptr StickersManager::get_sticker_set_object(int64 emojis.push_back(make_tl_object(vector(it->second))); } } - return make_tl_object(sticker_set->id, sticker_set->title, sticker_set->short_name, - get_photo_size_object(td_->file_manager_.get(), &sticker_set->thumbnail), - sticker_set->is_installed && !sticker_set->is_archived, - sticker_set->is_archived, sticker_set->is_official, sticker_set->is_masks, - sticker_set->is_viewed, std::move(stickers), std::move(emojis)); + return make_tl_object( + sticker_set->id, sticker_set->title, sticker_set->short_name, + get_photo_size_object(td_->file_manager_.get(), &sticker_set->thumbnail), + sticker_set->is_installed && !sticker_set->is_archived, sticker_set->is_archived, sticker_set->is_official, + sticker_set->is_animated, sticker_set->is_masks, sticker_set->is_viewed, std::move(stickers), std::move(emojis)); } tl_object_ptr StickersManager::get_sticker_sets_object(int32 total_count, @@ -1162,7 +1162,7 @@ tl_object_ptr StickersManager::get_sticker_set_info_obje sticker_set->id, sticker_set->title, sticker_set->short_name, get_photo_size_object(td_->file_manager_.get(), &sticker_set->thumbnail), sticker_set->is_installed && !sticker_set->is_archived, sticker_set->is_archived, sticker_set->is_official, - sticker_set->is_masks, sticker_set->is_viewed, + sticker_set->is_animated, sticker_set->is_masks, sticker_set->is_viewed, sticker_set->was_loaded ? narrow_cast(sticker_set->sticker_ids.size()) : sticker_set->sticker_count, std::move(stickers)); } @@ -1213,6 +1213,10 @@ FileId StickersManager::on_get_sticker(unique_ptr new_sticker, bool rep s->sticker_thumbnail = new_sticker->sticker_thumbnail; s->is_changed = true; } + if (s->is_animated != new_sticker->is_animated && new_sticker->is_animated) { + s->is_animated = new_sticker->is_animated; + s->is_changed = true; + } if (s->is_mask != new_sticker->is_mask && new_sticker->is_mask) { s->is_mask = new_sticker->is_mask; s->is_changed = true; @@ -1293,7 +1297,8 @@ std::pair StickersManager::on_get_sticker_document(tl_object_ptr< } } - create_sticker(sticker_id, std::move(thumbnail), dimensions, from_message, std::move(sticker), nullptr); + create_sticker(sticker_id, std::move(thumbnail), dimensions, from_message, std::move(sticker), + document->mime_type_ == "application/x-tgsticker", nullptr); return {document_id, sticker_id}; } @@ -1566,8 +1571,13 @@ void StickersManager::on_resolve_sticker_set_short_name(FileId sticker_file_id, } void StickersManager::create_sticker(FileId file_id, PhotoSize thumbnail, Dimensions dimensions, bool from_message, - tl_object_ptr sticker, + tl_object_ptr sticker, bool is_animated, MultiPromiseActor *load_data_multipromise_ptr) { + if (is_animated) { + dimensions.width = 512; + dimensions.height = 512; + } + auto s = make_unique(); s->file_id = file_id; s->dimensions = dimensions; @@ -1592,6 +1602,7 @@ void StickersManager::create_sticker(FileId file_id, PhotoSize thumbnail, Dimens } } } + s->is_animated = is_animated; on_get_sticker(std::move(s), sticker != nullptr); } @@ -1671,18 +1682,22 @@ SecretInputMedia StickersManager::get_secret_input_media(FileId sticker_file_id, return SecretInputMedia{std::move(input_file), make_tl_object( std::move(thumbnail), sticker->message_thumbnail.dimensions.width, - sticker->message_thumbnail.dimensions.height, "image/webp", + sticker->message_thumbnail.dimensions.height, get_sticker_mime_type(sticker), narrow_cast(file_view.size()), BufferSlice(encryption_key.key_slice()), BufferSlice(encryption_key.iv_slice()), std::move(attributes), "")}; } else { CHECK(!file_view.is_encrypted()); auto &remote_location = file_view.remote_location(); - CHECK(!remote_location.is_web()); // web stickers shouldn't have set_id - return SecretInputMedia{nullptr, - make_tl_object( - remote_location.get_id(), remote_location.get_access_hash(), 0 /*date*/, "image/webp", - narrow_cast(file_view.size()), make_tl_object(), - remote_location.get_dc_id().get_raw_id(), std::move(attributes))}; + if (remote_location.is_web()) { + // web stickers shouldn't have set_id + LOG(ERROR) << "Have a web sticker in set " << sticker->set_id; + return {}; + } + return SecretInputMedia{nullptr, make_tl_object( + remote_location.get_id(), remote_location.get_access_hash(), 0 /*date*/, + get_sticker_mime_type(sticker), narrow_cast(file_view.size()), + make_tl_object(), + remote_location.get_dc_id().get_raw_id(), std::move(attributes))}; } } @@ -1717,7 +1732,7 @@ tl_object_ptr StickersManager::get_input_media( flags |= telegram_api::inputMediaUploadedDocument::THUMB_MASK; } return make_tl_object( - flags, false /*ignored*/, std::move(input_file), std::move(input_thumbnail), "image/webp", + flags, false /*ignored*/, std::move(input_file), std::move(input_thumbnail), get_sticker_mime_type(s), std::move(attributes), vector>(), 0); } else { CHECK(!file_view.has_remote_location()); @@ -1733,6 +1748,7 @@ int64 StickersManager::on_get_sticker_set(tl_object_ptrflags_ & telegram_api::stickerSet::INSTALLED_DATE_MASK) != 0; bool is_archived = (set->flags_ & telegram_api::stickerSet::ARCHIVED_MASK) != 0; bool is_official = (set->flags_ & telegram_api::stickerSet::OFFICIAL_MASK) != 0; + bool is_animated = (set->flags_ & telegram_api::stickerSet::ANIMATED_MASK) != 0; bool is_masks = (set->flags_ & telegram_api::stickerSet::MASKS_MASK) != 0; PhotoSize thumbnail; @@ -1754,6 +1770,7 @@ int64 StickersManager::on_get_sticker_set(tl_object_ptrsticker_count = set->count_; s->hash = set->hash_; s->is_official = is_official; + s->is_animated = is_animated; s->is_masks = is_masks; s->is_changed = true; } else { @@ -1805,7 +1822,8 @@ int64 StickersManager::on_get_sticker_set(tl_object_ptris_official = is_official; s->is_changed = true; } - LOG_IF(ERROR, s->is_masks != is_masks) << "Type of the sticker set " << set_id << " has changed"; + LOG_IF(ERROR, s->is_animated != is_animated) << "Animated type of the sticker set " << set_id << " has changed"; + LOG_IF(ERROR, s->is_masks != is_masks) << "Masks type of the sticker set " << set_id << " has changed"; } short_name_to_sticker_set_id_.emplace(clean_username(s->short_name), set_id); @@ -4721,6 +4739,10 @@ vector StickersManager::get_sticker_emojis(const tl_object_ptrsecond; } +string StickersManager::get_sticker_mime_type(const Sticker *s) { + return s->is_animated ? "application/x-tgsticker" : "image/webp"; +} + string StickersManager::get_emoji_language_code_version_database_key(const string &language_code) { return PSTRING() << "emojiv$" << language_code; } diff --git a/td/telegram/StickersManager.h b/td/telegram/StickersManager.h index cff22a1d..846f7c3a 100644 --- a/td/telegram/StickersManager.h +++ b/td/telegram/StickersManager.h @@ -52,7 +52,7 @@ class StickersManager : public Actor { tl_object_ptr get_input_sticker_set(int64 sticker_set_id) const; void create_sticker(FileId file_id, PhotoSize thumbnail, Dimensions dimensions, bool from_message, - tl_object_ptr sticker, + tl_object_ptr sticker, bool is_animated, MultiPromiseActor *load_data_multipromise_ptr); bool has_input_media(FileId sticker_file_id, bool is_secret) const; @@ -261,6 +261,7 @@ class StickersManager : public Actor { PhotoSize message_thumbnail; PhotoSize sticker_thumbnail; FileId file_id; + bool is_animated = false; bool is_mask = false; int32 point = -1; double x_shift = 0; @@ -293,6 +294,7 @@ class StickersManager : public Actor { bool is_installed = false; bool is_archived = false; bool is_official = false; + bool is_animated = false; bool is_masks = false; bool is_viewed = true; bool is_thumbnail_reloaded = false; @@ -475,6 +477,8 @@ class StickersManager : public Actor { void tear_down() override; + static string get_sticker_mime_type(const Sticker *s); + static string get_emoji_language_code_version_database_key(const string &language_code); static string get_emoji_language_code_last_difference_time_database_key(const string &language_code); diff --git a/td/telegram/StickersManager.hpp b/td/telegram/StickersManager.hpp index 66ad9185..8e5d16cd 100644 --- a/td/telegram/StickersManager.hpp +++ b/td/telegram/StickersManager.hpp @@ -30,6 +30,7 @@ void StickersManager::store_sticker(FileId file_id, bool in_sticker_set, StorerT STORE_FLAG(sticker->is_mask); STORE_FLAG(has_sticker_set_access_hash); STORE_FLAG(in_sticker_set); + STORE_FLAG(sticker->is_animated); END_STORE_FLAGS(); if (!in_sticker_set) { store(sticker->set_id, storer); @@ -65,6 +66,7 @@ FileId StickersManager::parse_sticker(bool in_sticker_set, ParserT &parser) { PARSE_FLAG(sticker->is_mask); PARSE_FLAG(has_sticker_set_access_hash); PARSE_FLAG(in_sticker_set_stored); + PARSE_FLAG(sticker->is_animated); END_PARSE_FLAGS(); if (in_sticker_set_stored != in_sticker_set) { Slice data = parser.template fetch_string_raw(parser.get_left_len()); @@ -123,6 +125,7 @@ void StickersManager::store_sticker_set(const StickerSet *sticker_set, bool with STORE_FLAG(has_expires_at); STORE_FLAG(has_thumbnail); STORE_FLAG(sticker_set->is_thumbnail_reloaded); + STORE_FLAG(sticker_set->is_animated); END_STORE_FLAGS(); store(sticker_set->id, storer); store(sticker_set->access_hash, storer); @@ -165,6 +168,7 @@ void StickersManager::parse_sticker_set(StickerSet *sticker_set, ParserT &parser bool is_archived; bool is_official; bool is_masks; + bool is_animated; bool has_expires_at; bool has_thumbnail; BEGIN_PARSE_FLAGS(); @@ -179,6 +183,7 @@ void StickersManager::parse_sticker_set(StickerSet *sticker_set, ParserT &parser PARSE_FLAG(has_expires_at); PARSE_FLAG(has_thumbnail); PARSE_FLAG(sticker_set->is_thumbnail_reloaded); + PARSE_FLAG(is_animated); END_PARSE_FLAGS(); int64 sticker_set_id; int64 access_hash; @@ -214,6 +219,7 @@ void StickersManager::parse_sticker_set(StickerSet *sticker_set, ParserT &parser sticker_set->expires_at = expires_at; sticker_set->is_official = is_official; sticker_set->is_masks = is_masks; + sticker_set->is_animated = is_animated; short_name_to_sticker_set_id_.emplace(clean_username(sticker_set->short_name), sticker_set_id); on_update_sticker_set(sticker_set, is_installed, is_archived, false, true); @@ -228,6 +234,14 @@ void StickersManager::parse_sticker_set(StickerSet *sticker_set, ParserT &parser if (sticker_set->sticker_count != sticker_count || sticker_set->hash != hash) { sticker_set->is_loaded = false; } + if (sticker_set->is_animated != is_animated) { + LOG(ERROR) << "Sticker set " << sticker_set_id << " is_animated has changed from \"" << is_animated + << "\" to \"" << sticker_set->is_animated << "\""; + } + if (sticker_set->is_masks != is_masks) { + LOG(ERROR) << "Sticker set " << sticker_set_id << " is_masks has changed from \"" << is_masks << "\" to \"" + << sticker_set->is_masks << "\""; + } } uint32 stored_sticker_count; diff --git a/td/telegram/files/FileManager.cpp b/td/telegram/files/FileManager.cpp index 98a458ef..fbeb4117 100644 --- a/td/telegram/files/FileManager.cpp +++ b/td/telegram/files/FileManager.cpp @@ -782,8 +782,12 @@ string FileManager::get_file_name(FileType file_type, Slice path) { return fix_file_extension(file_name, "wallpaper", "jpg"); } break; - case FileType::Document: case FileType::Sticker: + if (extension != "webp" && extension != "tgs") { + return fix_file_extension(file_name, "sticker", "webp"); + } + break; + case FileType::Document: case FileType::Animation: case FileType::Encrypted: case FileType::Temp: