Support animated stickers.

GitOrigin-RevId: f4a02797a47ffb39eaeee5bcc75ad4b5231dfdfd
This commit is contained in:
levlam 2019-07-15 03:43:05 +03:00
parent d1f53092d1
commit 5a7f326140
12 changed files with 105 additions and 36 deletions

View File

@ -217,8 +217,8 @@ document file_name:string mime_type:string minithumbnail:minithumbnail thumbnail
photo has_stickers:Bool minithumbnail:minithumbnail sizes:vector<photoSize> = 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<string> = 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<sticker> emojis:vector<emojis> = 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<sticker> emojis:vector<emojis> = 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<sticker> = 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<sticker> = 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<stickerSetInfo> = StickerSets;

Binary file not shown.

View File

@ -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<StickerPack> documents:Vector<Document> = messages.StickerSet;

Binary file not shown.

View File

@ -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,

View File

@ -914,8 +914,9 @@ tl_object_ptr<td_api::photo> copy(const td_api::photo &obj) {
template <>
tl_object_ptr<td_api::sticker> copy(const td_api::sticker &obj) {
return make_tl_object<td_api::sticker>(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<td_api::sticker>(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 <>

View File

@ -1579,8 +1579,9 @@ static Result<InputMessageContent> create_input_message_content(
}
case td_api::inputMessageSticker::ID: {
auto input_sticker = static_cast<td_api::inputMessageSticker *>(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<MessageSticker>(file_id);
break;

View File

@ -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;

View File

@ -1084,7 +1084,7 @@ tl_object_ptr<td_api::sticker> 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<td_api::sticker>(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<td_api::stickerSet> StickersManager::get_sticker_set_object(int64
emojis.push_back(make_tl_object<td_api::emojis>(vector<string>(it->second)));
}
}
return make_tl_object<td_api::stickerSet>(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<td_api::stickerSet>(
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<td_api::stickerSets> StickersManager::get_sticker_sets_object(int32 total_count,
@ -1162,7 +1162,7 @@ tl_object_ptr<td_api::stickerSetInfo> 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<int32>(sticker_set->sticker_ids.size()) : sticker_set->sticker_count,
std::move(stickers));
}
@ -1213,6 +1213,10 @@ FileId StickersManager::on_get_sticker(unique_ptr<Sticker> 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<int64, FileId> 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<telegram_api::documentAttributeSticker> sticker,
tl_object_ptr<telegram_api::documentAttributeSticker> sticker, bool is_animated,
MultiPromiseActor *load_data_multipromise_ptr) {
if (is_animated) {
dimensions.width = 512;
dimensions.height = 512;
}
auto s = make_unique<Sticker>();
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<secret_api::decryptedMessageMediaDocument>(
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<int32>(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<secret_api::decryptedMessageMediaExternalDocument>(
remote_location.get_id(), remote_location.get_access_hash(), 0 /*date*/, "image/webp",
narrow_cast<int32>(file_view.size()), make_tl_object<secret_api::photoSizeEmpty>(),
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<secret_api::decryptedMessageMediaExternalDocument>(
remote_location.get_id(), remote_location.get_access_hash(), 0 /*date*/,
get_sticker_mime_type(sticker), narrow_cast<int32>(file_view.size()),
make_tl_object<secret_api::photoSizeEmpty>(),
remote_location.get_dc_id().get_raw_id(), std::move(attributes))};
}
}
@ -1717,7 +1732,7 @@ tl_object_ptr<telegram_api::InputMedia> StickersManager::get_input_media(
flags |= telegram_api::inputMediaUploadedDocument::THUMB_MASK;
}
return make_tl_object<telegram_api::inputMediaUploadedDocument>(
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<tl_object_ptr<telegram_api::InputDocument>>(), 0);
} else {
CHECK(!file_view.has_remote_location());
@ -1733,6 +1748,7 @@ int64 StickersManager::on_get_sticker_set(tl_object_ptr<telegram_api::stickerSet
bool is_installed = (set->flags_ & 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_ptr<telegram_api::stickerSet
s->sticker_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_ptr<telegram_api::stickerSet
s->is_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<string> StickersManager::get_sticker_emojis(const tl_object_ptr<td_api::I
return it->second;
}
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;
}

View File

@ -52,7 +52,7 @@ class StickersManager : public Actor {
tl_object_ptr<telegram_api::InputStickerSet> 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<telegram_api::documentAttributeSticker> sticker,
tl_object_ptr<telegram_api::documentAttributeSticker> 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);

View File

@ -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<Slice>(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;

View File

@ -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: