Add animated thumbnail support for animations and videos

GitOrigin-RevId: a9026a32be9a9ddf2597c6244e112fd853d81b1f
This commit is contained in:
levlam 2020-05-30 01:48:56 +03:00
parent e8cb1dfeb5
commit 4a1e2ee34c
15 changed files with 223 additions and 46 deletions

View File

@ -181,6 +181,9 @@ inputFileGenerated original_path:string conversion:string expected_size:int32 =
//@description Photo description @type Thumbnail type (see https://core.telegram.org/constructor/photoSize) @photo Information about the photo file @width Photo width @height Photo height //@description Photo description @type Thumbnail type (see https://core.telegram.org/constructor/photoSize) @photo Information about the photo file @width Photo width @height Photo height
photoSize type:string photo:file width:int32 height:int32 = PhotoSize; photoSize type:string photo:file width:int32 height:int32 = PhotoSize;
//@description A short animated thumbnail of a file in the MPEG4 format @width Animation width @height Animation height @animation The thumbnail
animatedThumbnail width:int32 height:int32 animation:file = AnimatedThumbnail;
//@description Thumbnail image of a very poor quality and low resolution @width Thumbnail width, usually doesn't exceed 40 @height Thumbnail height, usually doesn't exceed 40 @data The thumbnail in JPEG format //@description Thumbnail image of a very poor quality and low resolution @width Thumbnail width, usually doesn't exceed 40 @height Thumbnail height, usually doesn't exceed 40 @data The thumbnail in JPEG format
minithumbnail width:int32 height:int32 data:bytes = Minithumbnail; minithumbnail width:int32 height:int32 data:bytes = Minithumbnail;
@ -225,8 +228,9 @@ pollTypeQuiz correct_option_id:int32 explanation:formattedText = PollType;
//@description Describes an animation file. The animation must be encoded in GIF or MPEG4 format @duration Duration of the animation, in seconds; as defined by the sender @width Width of the animation @height Height of the animation //@description Describes an animation file. The animation must be encoded in GIF or MPEG4 format @duration Duration of the animation, in seconds; as defined by the sender @width Width of the animation @height Height of the animation
//@file_name Original name of the file; as defined by the sender @mime_type MIME type of the file, usually "image/gif" or "video/mp4" //@file_name Original name of the file; as defined by the sender @mime_type MIME type of the file, usually "image/gif" or "video/mp4"
//@has_stickers True, if stickers were added to the animation. The list of corresponding sticker set can be received using getAttachedStickerSets //@has_stickers True, if stickers were added to the animation. The list of corresponding sticker set can be received using getAttachedStickerSets
//@minithumbnail Animation minithumbnail; may be null @thumbnail Animation thumbnail; may be null @animation File containing the animation //@minithumbnail Animation minithumbnail; may be null @thumbnail Animation thumbnail; may be null
animation duration:int32 width:int32 height:int32 file_name:string mime_type:string has_stickers:Bool minithumbnail:minithumbnail thumbnail:photoSize animation:file = Animation; //@animated_thumbnail A short animated thumbnail of the animation in the MPEG4 format; may be null @animation File containing the animation
animation duration:int32 width:int32 height:int32 file_name:string mime_type:string has_stickers:Bool minithumbnail:minithumbnail thumbnail:photoSize animated_thumbnail:animatedThumbnail animation:file = Animation;
//@description Describes an audio file. Audio is usually in MP3 or M4A format @duration Duration of the audio, in seconds; as defined by the sender @title Title of the audio; as defined by the sender @performer Performer of the audio; as defined by the sender //@description Describes an audio file. Audio is usually in MP3 or M4A format @duration Duration of the audio, in seconds; as defined by the sender @title Title of the audio; as defined by the sender @performer Performer of the audio; as defined by the sender
//@file_name Original name of the file; as defined by the sender @mime_type The MIME type of the file; as defined by the sender @album_cover_minithumbnail The minithumbnail of the album cover; may be null @album_cover_thumbnail The thumbnail of the album cover; as defined by the sender. The full size thumbnail should be extracted from the downloaded file; may be null @audio File containing the audio //@file_name Original name of the file; as defined by the sender @mime_type The MIME type of the file; as defined by the sender @album_cover_minithumbnail The minithumbnail of the album cover; may be null @album_cover_thumbnail The thumbnail of the album cover; as defined by the sender. The full size thumbnail should be extracted from the downloaded file; may be null @audio File containing the audio
@ -247,8 +251,9 @@ sticker set_id:int64 width:int32 height:int32 emoji:string is_animated:Bool is_m
//@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 //@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 //@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 video. The list of corresponding sticker sets can be received using getAttachedStickerSets //@has_stickers True, if stickers were added to the video. The list of corresponding sticker sets can be received using getAttachedStickerSets
//@supports_streaming True, if the video should be tried to be streamed @minithumbnail Video minithumbnail; may be null @thumbnail Video thumbnail; as defined by the sender; may be null @video File containing the video //@supports_streaming True, if the video should be tried to be streamed @minithumbnail Video minithumbnail; may be null @thumbnail Video thumbnail; as defined by the sender; may be null
video duration:int32 width:int32 height:int32 file_name:string mime_type:string has_stickers:Bool supports_streaming:Bool minithumbnail:minithumbnail thumbnail:photoSize video:file = Video; //@animated_thumbnail A short animated thumbnail of the video in the MPEG4 format; may be null @video File containing the video
video duration:int32 width:int32 height:int32 file_name:string mime_type:string has_stickers:Bool supports_streaming:Bool minithumbnail:minithumbnail thumbnail:photoSize animated_thumbnail:animatedThumbnail video:file = Video;
//@description Describes a video note. The video must be equal in width and height, cropped to a circle, and stored in MPEG4 format @duration Duration of the video, in seconds; as defined by the sender @length Video width and height; as defined by the sender @minithumbnail Video minithumbnail; may be null @thumbnail Video thumbnail; as defined by the sender; may be null @video File containing the video //@description Describes a video note. The video must be equal in width and height, cropped to a circle, and stored in MPEG4 format @duration Duration of the video, in seconds; as defined by the sender @length Video width and height; as defined by the sender @minithumbnail Video minithumbnail; may be null @thumbnail Video thumbnail; as defined by the sender; may be null @video File containing the video
videoNote duration:int32 length:int32 minithumbnail:minithumbnail thumbnail:photoSize video:file = VideoNote; videoNote duration:int32 length:int32 minithumbnail:minithumbnail thumbnail:photoSize video:file = VideoNote;

Binary file not shown.

View File

@ -159,10 +159,11 @@ tl_object_ptr<td_api::animation> AnimationsManager::get_animation_object(FileId
<< static_cast<int32>(td_->file_manager_->get_file_view(file_id).get_type()); << static_cast<int32>(td_->file_manager_->get_file_view(file_id).get_type());
// TODO can we make that function const? // TODO can we make that function const?
animation->is_changed = false; animation->is_changed = false;
return make_tl_object<td_api::animation>(animation->duration, animation->dimensions.width, return make_tl_object<td_api::animation>(
animation->dimensions.height, animation->file_name, animation->mime_type, animation->duration, animation->dimensions.width, animation->dimensions.height, animation->file_name,
animation->has_stickers, get_minithumbnail_object(animation->minithumbnail), animation->mime_type, animation->has_stickers, get_minithumbnail_object(animation->minithumbnail),
get_photo_size_object(td_->file_manager_.get(), &animation->thumbnail), get_photo_size_object(td_->file_manager_.get(), &animation->thumbnail),
get_animated_thumbnail_object(td_->file_manager_.get(), &animation->animated_thumbnail),
td_->file_manager_->get_file_object(file_id)); td_->file_manager_->get_file_object(file_id));
} }
@ -210,6 +211,16 @@ FileId AnimationsManager::on_get_animation(unique_ptr<Animation> new_animation,
a->thumbnail = new_animation->thumbnail; a->thumbnail = new_animation->thumbnail;
a->is_changed = true; a->is_changed = true;
} }
if (a->animated_thumbnail != new_animation->animated_thumbnail) {
if (!a->animated_thumbnail.file_id.is_valid()) {
LOG(DEBUG) << "Animation " << file_id << " animated thumbnail has changed";
} else {
LOG(INFO) << "Animation " << file_id << " animated thumbnail has changed from " << a->animated_thumbnail
<< " to " << new_animation->animated_thumbnail;
}
a->animated_thumbnail = new_animation->animated_thumbnail;
a->is_changed = true;
}
if (a->has_stickers != new_animation->has_stickers && new_animation->has_stickers) { if (a->has_stickers != new_animation->has_stickers && new_animation->has_stickers) {
a->has_stickers = new_animation->has_stickers; a->has_stickers = new_animation->has_stickers;
a->is_changed = true; a->is_changed = true;
@ -239,10 +250,17 @@ FileId AnimationsManager::get_animation_thumbnail_file_id(FileId file_id) const
return animation->thumbnail.file_id; return animation->thumbnail.file_id;
} }
FileId AnimationsManager::get_animation_animated_thumbnail_file_id(FileId file_id) const {
auto animation = get_animation(file_id);
CHECK(animation != nullptr);
return animation->animated_thumbnail.file_id;
}
void AnimationsManager::delete_animation_thumbnail(FileId file_id) { void AnimationsManager::delete_animation_thumbnail(FileId file_id) {
auto &animation = animations_[file_id]; auto &animation = animations_[file_id];
CHECK(animation != nullptr); CHECK(animation != nullptr);
animation->thumbnail = PhotoSize(); animation->thumbnail = PhotoSize();
animation->animated_thumbnail = PhotoSize();
} }
FileId AnimationsManager::dup_animation(FileId new_id, FileId old_id) { FileId AnimationsManager::dup_animation(FileId new_id, FileId old_id) {
@ -254,6 +272,8 @@ FileId AnimationsManager::dup_animation(FileId new_id, FileId old_id) {
new_animation = make_unique<Animation>(*old_animation); new_animation = make_unique<Animation>(*old_animation);
new_animation->file_id = new_id; new_animation->file_id = new_id;
new_animation->thumbnail.file_id = td_->file_manager_->dup_file_id(new_animation->thumbnail.file_id); new_animation->thumbnail.file_id = td_->file_manager_->dup_file_id(new_animation->thumbnail.file_id);
new_animation->animated_thumbnail.file_id =
td_->file_manager_->dup_file_id(new_animation->animated_thumbnail.file_id);
return new_id; return new_id;
} }
@ -296,7 +316,8 @@ bool AnimationsManager::merge_animations(FileId new_id, FileId old_id, bool can_
return true; return true;
} }
void AnimationsManager::create_animation(FileId file_id, string minithumbnail, PhotoSize thumbnail, bool has_stickers, void AnimationsManager::create_animation(FileId file_id, string minithumbnail, PhotoSize thumbnail,
PhotoSize animated_thumbnail, bool has_stickers,
vector<FileId> &&sticker_file_ids, string file_name, string mime_type, vector<FileId> &&sticker_file_ids, string file_name, string mime_type,
int32 duration, Dimensions dimensions, bool replace) { int32 duration, Dimensions dimensions, bool replace) {
auto a = make_unique<Animation>(); auto a = make_unique<Animation>();
@ -307,6 +328,7 @@ void AnimationsManager::create_animation(FileId file_id, string minithumbnail, P
a->dimensions = dimensions; a->dimensions = dimensions;
a->minithumbnail = std::move(minithumbnail); a->minithumbnail = std::move(minithumbnail);
a->thumbnail = std::move(thumbnail); a->thumbnail = std::move(thumbnail);
a->animated_thumbnail = std::move(animated_thumbnail);
a->has_stickers = has_stickers; a->has_stickers = has_stickers;
a->sticker_file_ids = std::move(sticker_file_ids); a->sticker_file_ids = std::move(sticker_file_ids);
on_get_animation(std::move(a), replace); on_get_animation(std::move(a), replace);
@ -787,9 +809,13 @@ void AnimationsManager::send_update_saved_animations(bool from_database) {
if (are_saved_animations_loaded_) { if (are_saved_animations_loaded_) {
vector<FileId> new_saved_animation_file_ids = saved_animation_ids_; vector<FileId> new_saved_animation_file_ids = saved_animation_ids_;
for (auto &animation_id : saved_animation_ids_) { for (auto &animation_id : saved_animation_ids_) {
auto thumbnail_file_id = get_animation_thumbnail_file_id(animation_id); auto animation = get_animation(animation_id);
if (thumbnail_file_id.is_valid()) { CHECK(animation != nullptr);
new_saved_animation_file_ids.push_back(thumbnail_file_id); if (animation->thumbnail.file_id.is_valid()) {
new_saved_animation_file_ids.push_back(animation->thumbnail.file_id);
}
if (animation->animated_thumbnail.file_id.is_valid()) {
new_saved_animation_file_ids.push_back(animation->animated_thumbnail.file_id);
} }
} }
std::sort(new_saved_animation_file_ids.begin(), new_saved_animation_file_ids.end()); std::sort(new_saved_animation_file_ids.begin(), new_saved_animation_file_ids.end());

View File

@ -35,9 +35,9 @@ class AnimationsManager : public Actor {
tl_object_ptr<td_api::animation> get_animation_object(FileId file_id, const char *source); tl_object_ptr<td_api::animation> get_animation_object(FileId file_id, const char *source);
void create_animation(FileId file_id, string minithumbnail, PhotoSize thumbnail, bool has_stickers, void create_animation(FileId file_id, string minithumbnail, PhotoSize thumbnail, PhotoSize animated_thumbnail,
vector<FileId> &&sticker_file_ids, string file_name, string mime_type, int32 duration, bool has_stickers, vector<FileId> &&sticker_file_ids, string file_name, string mime_type,
Dimensions dimensions, bool replace); int32 duration, Dimensions dimensions, bool replace);
tl_object_ptr<telegram_api::InputMedia> get_input_media(FileId file_id, tl_object_ptr<telegram_api::InputMedia> get_input_media(FileId file_id,
tl_object_ptr<telegram_api::InputFile> input_file, tl_object_ptr<telegram_api::InputFile> input_file,
@ -49,6 +49,8 @@ class AnimationsManager : public Actor {
FileId get_animation_thumbnail_file_id(FileId file_id) const; FileId get_animation_thumbnail_file_id(FileId file_id) const;
FileId get_animation_animated_thumbnail_file_id(FileId file_id) const;
void delete_animation_thumbnail(FileId file_id); void delete_animation_thumbnail(FileId file_id);
FileId dup_animation(FileId new_id, FileId old_id); FileId dup_animation(FileId new_id, FileId old_id);
@ -98,6 +100,7 @@ class AnimationsManager : public Actor {
Dimensions dimensions; Dimensions dimensions;
string minithumbnail; string minithumbnail;
PhotoSize thumbnail; PhotoSize thumbnail;
PhotoSize animated_thumbnail;
bool has_stickers = false; bool has_stickers = false;
vector<FileId> sticker_file_ids; vector<FileId> sticker_file_ids;

View File

@ -22,8 +22,10 @@ void AnimationsManager::store_animation(FileId file_id, StorerT &storer) const {
auto it = animations_.find(file_id); auto it = animations_.find(file_id);
CHECK(it != animations_.end()); CHECK(it != animations_.end());
const Animation *animation = it->second.get(); const Animation *animation = it->second.get();
bool has_animated_thumbnail = animation->animated_thumbnail.file_id.is_valid();
BEGIN_STORE_FLAGS(); BEGIN_STORE_FLAGS();
STORE_FLAG(animation->has_stickers); STORE_FLAG(animation->has_stickers);
STORE_FLAG(has_animated_thumbnail);
END_STORE_FLAGS(); END_STORE_FLAGS();
store(animation->duration, storer); store(animation->duration, storer);
store(animation->dimensions, storer); store(animation->dimensions, storer);
@ -35,14 +37,19 @@ void AnimationsManager::store_animation(FileId file_id, StorerT &storer) const {
if (animation->has_stickers) { if (animation->has_stickers) {
store(animation->sticker_file_ids, storer); store(animation->sticker_file_ids, storer);
} }
if (has_animated_thumbnail) {
store(animation->animated_thumbnail, storer);
}
} }
template <class ParserT> template <class ParserT>
FileId AnimationsManager::parse_animation(ParserT &parser) { FileId AnimationsManager::parse_animation(ParserT &parser) {
auto animation = make_unique<Animation>(); auto animation = make_unique<Animation>();
bool has_animated_thumbnail = false;
if (parser.version() >= static_cast<int32>(Version::AddAnimationStickers)) { if (parser.version() >= static_cast<int32>(Version::AddAnimationStickers)) {
BEGIN_PARSE_FLAGS(); BEGIN_PARSE_FLAGS();
PARSE_FLAG(animation->has_stickers); PARSE_FLAG(animation->has_stickers);
PARSE_FLAG(has_animated_thumbnail);
END_PARSE_FLAGS(); END_PARSE_FLAGS();
} }
if (parser.version() >= static_cast<int32>(Version::AddDurationToAnimation)) { if (parser.version() >= static_cast<int32>(Version::AddDurationToAnimation)) {
@ -59,6 +66,9 @@ FileId AnimationsManager::parse_animation(ParserT &parser) {
if (animation->has_stickers) { if (animation->has_stickers) {
parse(animation->sticker_file_ids, parser); parse(animation->sticker_file_ids, parser);
} }
if (has_animated_thumbnail) {
parse(animation->animated_thumbnail, parser);
}
if (parser.get_error() != nullptr || !animation->file_id.is_valid()) { if (parser.get_error() != nullptr || !animation->file_id.is_valid()) {
return FileId(); return FileId();
} }

View File

@ -35,6 +35,7 @@ void Document::append_file_ids(const Td *td, vector<FileId> &file_ids) const {
} }
file_ids.push_back(file_id); file_ids.push_back(file_id);
FileId thumbnail_file_id = [&] { FileId thumbnail_file_id = [&] {
switch (type) { switch (type) {
case Type::Animation: case Type::Animation:
@ -54,6 +55,20 @@ void Document::append_file_ids(const Td *td, vector<FileId> &file_ids) const {
if (thumbnail_file_id.is_valid()) { if (thumbnail_file_id.is_valid()) {
file_ids.push_back(thumbnail_file_id); file_ids.push_back(thumbnail_file_id);
} }
FileId animated_thumbnail_file_id = [&] {
switch (type) {
case Type::Animation:
return td->animations_manager_->get_animation_animated_thumbnail_file_id(file_id);
case Type::Video:
return td->videos_manager_->get_video_animated_thumbnail_file_id(file_id);
default:
return FileId();
}
}();
if (animated_thumbnail_file_id.is_valid()) {
file_ids.push_back(animated_thumbnail_file_id);
}
} }
bool operator==(const Document &lhs, const Document &rhs) { bool operator==(const Document &lhs, const Document &rhs) {

View File

@ -214,6 +214,7 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
string file_reference; string file_reference;
string minithumbnail; string minithumbnail;
PhotoSize thumbnail; PhotoSize thumbnail;
PhotoSize animated_thumbnail;
FileEncryptionKey encryption_key; FileEncryptionKey encryption_key;
bool is_animated_sticker = false; bool is_animated_sticker = false;
bool is_web = false; bool is_web = false;
@ -269,6 +270,16 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
} }
} }
} }
for (auto &thumb : document->video_thumbs_) {
if (thumb->type_ == "v") {
animated_thumbnail =
get_video_photo_size(td_->file_manager_.get(), {FileType::Thumbnail, 0}, id, access_hash, file_reference,
DcId::create(dc_id), owner_dialog_id, std::move(thumb));
if (animated_thumbnail.file_id.is_valid()) {
break;
}
}
}
} else if (remote_document.secret_file != nullptr) { } else if (remote_document.secret_file != nullptr) {
CHECK(remote_document.secret_document != nullptr); CHECK(remote_document.secret_document != nullptr);
auto file = std::move(remote_document.secret_file); auto file = std::move(remote_document.secret_file);
@ -297,7 +308,11 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
id = Random::fast(0, std::numeric_limits<int32>::max()); id = Random::fast(0, std::numeric_limits<int32>::max());
dc_id = 0; dc_id = 0;
access_hash = 0; access_hash = 0;
if (remote_document.thumbnail.type == 'v') {
animated_thumbnail = std::move(remote_document.thumbnail);
} else {
thumbnail = std::move(remote_document.thumbnail); thumbnail = std::move(remote_document.thumbnail);
}
auto web_document_ptr = std::move(remote_document.web_document); auto web_document_ptr = std::move(remote_document.web_document);
switch (web_document_ptr->get_id()) { switch (web_document_ptr->get_id()) {
@ -388,9 +403,9 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
switch (document_type) { switch (document_type) {
case Document::Type::Animation: case Document::Type::Animation:
td_->animations_manager_->create_animation(file_id, std::move(minithumbnail), std::move(thumbnail), has_stickers, td_->animations_manager_->create_animation(
vector<FileId>(), std::move(file_name), std::move(mime_type), file_id, std::move(minithumbnail), std::move(thumbnail), std::move(animated_thumbnail), has_stickers,
video_duration, dimensions, !is_web); vector<FileId>(), std::move(file_name), std::move(mime_type), video_duration, dimensions, !is_web);
break; break;
case Document::Type::Audio: { case Document::Type::Audio: {
int32 duration = 0; int32 duration = 0;
@ -415,9 +430,10 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
is_animated_sticker, load_data_multipromise_ptr); is_animated_sticker, load_data_multipromise_ptr);
break; break;
case Document::Type::Video: case Document::Type::Video:
td_->videos_manager_->create_video(file_id, std::move(minithumbnail), std::move(thumbnail), has_stickers, td_->videos_manager_->create_video(file_id, std::move(minithumbnail), std::move(thumbnail),
vector<FileId>(), std::move(file_name), std::move(mime_type), video_duration, std::move(animated_thumbnail), has_stickers, vector<FileId>(),
dimensions, supports_streaming, !is_web); std::move(file_name), std::move(mime_type), video_duration, dimensions,
supports_streaming, !is_web);
break; break;
case Document::Type::VideoNote: case Document::Type::VideoNote:
td_->video_notes_manager_->create_video_note(file_id, std::move(minithumbnail), std::move(thumbnail), td_->video_notes_manager_->create_video_note(file_id, std::move(minithumbnail), std::move(thumbnail),

View File

@ -865,6 +865,11 @@ tl_object_ptr<td_api::photoSize> copy(const td_api::photoSize &obj) {
return make_tl_object<td_api::photoSize>(obj.type_, copy(obj.photo_), obj.width_, obj.height_); return make_tl_object<td_api::photoSize>(obj.type_, copy(obj.photo_), obj.width_, obj.height_);
} }
template <>
tl_object_ptr<td_api::animatedThumbnail> copy(const td_api::animatedThumbnail &obj) {
return make_tl_object<td_api::animatedThumbnail>(obj.width_, obj.height_, copy(obj.animation_));
}
static tl_object_ptr<td_api::photoSize> copy_photo_size(const tl_object_ptr<td_api::photoSize> &obj) { static tl_object_ptr<td_api::photoSize> copy_photo_size(const tl_object_ptr<td_api::photoSize> &obj) {
return copy(obj); return copy(obj);
} }
@ -895,7 +900,7 @@ template <>
tl_object_ptr<td_api::animation> copy(const td_api::animation &obj) { tl_object_ptr<td_api::animation> copy(const td_api::animation &obj) {
return make_tl_object<td_api::animation>(obj.duration_, obj.width_, obj.height_, obj.file_name_, obj.mime_type_, return make_tl_object<td_api::animation>(obj.duration_, obj.width_, obj.height_, obj.file_name_, obj.mime_type_,
obj.has_stickers_, copy(obj.minithumbnail_), copy(obj.thumbnail_), obj.has_stickers_, copy(obj.minithumbnail_), copy(obj.thumbnail_),
copy(obj.animation_)); copy(obj.animated_thumbnail_), copy(obj.animation_));
} }
template <> template <>
@ -928,7 +933,7 @@ template <>
tl_object_ptr<td_api::video> copy(const td_api::video &obj) { tl_object_ptr<td_api::video> copy(const td_api::video &obj) {
return make_tl_object<td_api::video>(obj.duration_, obj.width_, obj.height_, obj.file_name_, obj.mime_type_, return make_tl_object<td_api::video>(obj.duration_, obj.width_, obj.height_, obj.file_name_, obj.mime_type_,
obj.has_stickers_, obj.supports_streaming_, copy(obj.minithumbnail_), obj.has_stickers_, obj.supports_streaming_, copy(obj.minithumbnail_),
copy(obj.thumbnail_), copy(obj.video_)); copy(obj.thumbnail_), copy(obj.animated_thumbnail_), copy(obj.video_));
} }
template <> template <>
@ -1065,7 +1070,7 @@ tl_object_ptr<td_api::photoSize> InlineQueriesManager::register_thumbnail(
tl_object_ptr<telegram_api::WebDocument> &&web_document_ptr) const { tl_object_ptr<telegram_api::WebDocument> &&web_document_ptr) const {
PhotoSize thumbnail = get_web_document_photo_size(td_->file_manager_.get(), FileType::Thumbnail, DialogId(), PhotoSize thumbnail = get_web_document_photo_size(td_->file_manager_.get(), FileType::Thumbnail, DialogId(),
std::move(web_document_ptr)); std::move(web_document_ptr));
if (!thumbnail.file_id.is_valid()) { if (!thumbnail.file_id.is_valid() || thumbnail.type == 'v') {
return nullptr; return nullptr;
} }
@ -1390,7 +1395,7 @@ void InlineQueriesManager::on_get_inline_query_results(UserId bot_user_id, uint6
PhotoSize photo_size = get_web_document_photo_size(td_->file_manager_.get(), FileType::Temp, DialogId(), PhotoSize photo_size = get_web_document_photo_size(td_->file_manager_.get(), FileType::Temp, DialogId(),
std::move(result->content_)); std::move(result->content_));
if (!photo_size.file_id.is_valid()) { if (!photo_size.file_id.is_valid() || photo_size.type == 'v') {
LOG(ERROR) << "Receive invalid web document photo"; LOG(ERROR) << "Receive invalid web document photo";
continue; continue;
} }
@ -1398,7 +1403,7 @@ void InlineQueriesManager::on_get_inline_query_results(UserId bot_user_id, uint6
Photo new_photo; Photo new_photo;
PhotoSize thumbnail = get_web_document_photo_size(td_->file_manager_.get(), FileType::Thumbnail, DialogId(), PhotoSize thumbnail = get_web_document_photo_size(td_->file_manager_.get(), FileType::Thumbnail, DialogId(),
std::move(result->thumb_)); std::move(result->thumb_));
if (thumbnail.file_id.is_valid()) { if (thumbnail.file_id.is_valid() && thumbnail.type != 'v') {
new_photo.photos.push_back(std::move(thumbnail)); new_photo.photos.push_back(std::move(thumbnail));
} }
new_photo.photos.push_back(std::move(photo_size)); new_photo.photos.push_back(std::move(photo_size));

View File

@ -1474,10 +1474,10 @@ static Result<InputMessageContent> create_input_message_content(
auto input_animation = static_cast<td_api::inputMessageAnimation *>(input_message_content.get()); auto input_animation = static_cast<td_api::inputMessageAnimation *>(input_message_content.get());
bool has_stickers = !sticker_file_ids.empty(); bool has_stickers = !sticker_file_ids.empty();
td->animations_manager_->create_animation(file_id, string(), thumbnail, has_stickers, std::move(sticker_file_ids), td->animations_manager_->create_animation(
std::move(file_name), std::move(mime_type), input_animation->duration_, file_id, string(), thumbnail, PhotoSize(), has_stickers, std::move(sticker_file_ids), std::move(file_name),
get_dimensions(input_animation->width_, input_animation->height_), std::move(mime_type), input_animation->duration_,
false); get_dimensions(input_animation->width_, input_animation->height_), false);
content = make_unique<MessageAnimation>(file_id, std::move(caption)); content = make_unique<MessageAnimation>(file_id, std::move(caption));
break; break;
@ -1577,9 +1577,9 @@ static Result<InputMessageContent> create_input_message_content(
ttl = input_video->ttl_; ttl = input_video->ttl_;
bool has_stickers = !sticker_file_ids.empty(); bool has_stickers = !sticker_file_ids.empty();
td->videos_manager_->create_video(file_id, string(), thumbnail, has_stickers, std::move(sticker_file_ids), td->videos_manager_->create_video(
std::move(file_name), std::move(mime_type), input_video->duration_, file_id, string(), thumbnail, PhotoSize(), has_stickers, std::move(sticker_file_ids), std::move(file_name),
get_dimensions(input_video->width_, input_video->height_), std::move(mime_type), input_video->duration_, get_dimensions(input_video->width_, input_video->height_),
input_video->supports_streaming_, false); input_video->supports_streaming_, false);
content = make_unique<MessageVideo>(file_id, std::move(caption)); content = make_unique<MessageVideo>(file_id, std::move(caption));
@ -4705,6 +4705,20 @@ FileId get_message_content_thumbnail_file_id(const MessageContent *content, cons
return FileId(); return FileId();
} }
FileId get_message_content_animated_thumbnail_file_id(const MessageContent *content, const Td *td) {
switch (content->get_type()) {
case MessageContentType::Animation:
return td->animations_manager_->get_animation_animated_thumbnail_file_id(
static_cast<const MessageAnimation *>(content)->file_id);
case MessageContentType::Video:
return td->videos_manager_->get_video_animated_thumbnail_file_id(
static_cast<const MessageVideo *>(content)->file_id);
default:
break;
}
return FileId();
}
vector<FileId> get_message_content_file_ids(const MessageContent *content, const Td *td) { vector<FileId> get_message_content_file_ids(const MessageContent *content, const Td *td) {
switch (content->get_type()) { switch (content->get_type()) {
case MessageContentType::Photo: case MessageContentType::Photo:
@ -4725,6 +4739,10 @@ vector<FileId> get_message_content_file_ids(const MessageContent *content, const
if (thumbnail_file_id.is_valid()) { if (thumbnail_file_id.is_valid()) {
result.push_back(thumbnail_file_id); result.push_back(thumbnail_file_id);
} }
FileId animated_thumbnail_file_id = get_message_content_animated_thumbnail_file_id(content, td);
if (animated_thumbnail_file_id.is_valid()) {
result.push_back(animated_thumbnail_file_id);
}
return result; return result;
} }
case MessageContentType::Sticker: case MessageContentType::Sticker:

View File

@ -199,6 +199,8 @@ void update_message_content_file_id_remote(MessageContent *content, FileId file_
FileId get_message_content_thumbnail_file_id(const MessageContent *content, const Td *td); FileId get_message_content_thumbnail_file_id(const MessageContent *content, const Td *td);
FileId get_message_content_animated_thumbnail_file_id(const MessageContent *content, const Td *td);
vector<FileId> get_message_content_file_ids(const MessageContent *content, const Td *td); vector<FileId> get_message_content_file_ids(const MessageContent *content, const Td *td);
string get_message_content_search_text(const Td *td, const MessageContent *content); string get_message_content_search_text(const Td *td, const MessageContent *content);

View File

@ -105,6 +105,8 @@ static StringBuilder &operator<<(StringBuilder &string_builder, PhotoFormat form
return string_builder << "webp"; return string_builder << "webp";
case PhotoFormat::Tgs: case PhotoFormat::Tgs:
return string_builder << "tgs"; return string_builder << "tgs";
case PhotoFormat::Mpeg4:
return string_builder << "mp4";
default: default:
UNREACHABLE(); UNREACHABLE();
return string_builder; return string_builder;
@ -362,6 +364,27 @@ Variant<PhotoSize, string> get_photo_size(FileManager *file_manager, PhotoSizeSo
return std::move(res); return std::move(res);
} }
PhotoSize get_video_photo_size(FileManager *file_manager, PhotoSizeSource source, int64 id, int64 access_hash,
std::string file_reference, DcId dc_id, DialogId owner_dialog_id,
tl_object_ptr<telegram_api::videoSize> &&size) {
CHECK(size != nullptr);
PhotoSize res;
if (size->type_ != "v") {
LOG(ERROR) << "Wrong videoSize \"" << size->type_ << "\" in " << to_string(size);
}
res.type = static_cast<uint8>('v');
res.dimensions = get_dimensions(size->w_, size->h_);
res.size = size->size_;
if (source.get_type() == PhotoSizeSource::Type::Thumbnail) {
source.thumbnail().thumbnail_type = res.type;
}
res.file_id = register_photo(file_manager, source, id, access_hash, file_reference, std::move(size->location_),
owner_dialog_id, res.size, dc_id, PhotoFormat::Mpeg4);
return res;
}
PhotoSize get_web_document_photo_size(FileManager *file_manager, FileType file_type, DialogId owner_dialog_id, PhotoSize get_web_document_photo_size(FileManager *file_manager, FileType file_type, DialogId owner_dialog_id,
tl_object_ptr<telegram_api::WebDocument> web_document_ptr) { tl_object_ptr<telegram_api::WebDocument> web_document_ptr) {
if (web_document_ptr == nullptr) { if (web_document_ptr == nullptr) {
@ -371,6 +394,7 @@ PhotoSize get_web_document_photo_size(FileManager *file_manager, FileType file_t
FileId file_id; FileId file_id;
vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes; vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes;
int32 size = 0; int32 size = 0;
string mime_type;
switch (web_document_ptr->get_id()) { switch (web_document_ptr->get_id()) {
case telegram_api::webDocument::ID: { case telegram_api::webDocument::ID: {
auto web_document = move_tl_object_as<telegram_api::webDocument>(web_document_ptr); auto web_document = move_tl_object_as<telegram_api::webDocument>(web_document_ptr);
@ -385,6 +409,7 @@ PhotoSize get_web_document_photo_size(FileManager *file_manager, FileType file_t
FileLocationSource::FromServer, owner_dialog_id, 0, web_document->size_, FileLocationSource::FromServer, owner_dialog_id, 0, web_document->size_,
get_url_query_file_name(http_url.query_)); get_url_query_file_name(http_url.query_));
size = web_document->size_; size = web_document->size_;
mime_type = std::move(web_document->mime_type_);
attributes = std::move(web_document->attributes_); attributes = std::move(web_document->attributes_);
break; break;
} }
@ -403,6 +428,7 @@ PhotoSize get_web_document_photo_size(FileManager *file_manager, FileType file_t
file_id = r_file_id.move_as_ok(); file_id = r_file_id.move_as_ok();
size = web_document->size_; size = web_document->size_;
mime_type = std::move(web_document->mime_type_);
attributes = std::move(web_document->attributes_); attributes = std::move(web_document->attributes_);
break; break;
} }
@ -410,6 +436,7 @@ PhotoSize get_web_document_photo_size(FileManager *file_manager, FileType file_t
UNREACHABLE(); UNREACHABLE();
} }
CHECK(file_id.is_valid()); CHECK(file_id.is_valid());
bool is_animation = mime_type == "video/mp4";
Dimensions dimensions; Dimensions dimensions;
for (auto &attribute : attributes) { for (auto &attribute : attributes) {
@ -434,7 +461,7 @@ PhotoSize get_web_document_photo_size(FileManager *file_manager, FileType file_t
} }
PhotoSize s; PhotoSize s;
s.type = file_type == FileType::Thumbnail ? 't' : 'u'; s.type = is_animation ? 'v' : (file_type == FileType::Thumbnail ? 't' : 'u');
s.dimensions = dimensions; s.dimensions = dimensions;
s.size = size; s.size = size;
s.file_id = file_id; s.file_id = file_id;
@ -452,6 +479,16 @@ tl_object_ptr<td_api::photoSize> get_photo_size_object(FileManager *file_manager
file_manager->get_file_object(photo_size->file_id), photo_size->dimensions.width, photo_size->dimensions.height); file_manager->get_file_object(photo_size->file_id), photo_size->dimensions.width, photo_size->dimensions.height);
} }
td_api::object_ptr<td_api::animatedThumbnail> get_animated_thumbnail_object(FileManager *file_manager,
const PhotoSize *photo_size) {
if (photo_size == nullptr || !photo_size->file_id.is_valid()) {
return nullptr;
}
return td_api::make_object<td_api::animatedThumbnail>(photo_size->dimensions.width, photo_size->dimensions.height,
file_manager->get_file_object(photo_size->file_id));
}
vector<td_api::object_ptr<td_api::photoSize>> get_photo_sizes_object(FileManager *file_manager, vector<td_api::object_ptr<td_api::photoSize>> get_photo_sizes_object(FileManager *file_manager,
const vector<PhotoSize> &photo_sizes) { const vector<PhotoSize> &photo_sizes) {
auto sizes = transform(photo_sizes, [file_manager](const PhotoSize &photo_size) { auto sizes = transform(photo_sizes, [file_manager](const PhotoSize &photo_size) {
@ -572,7 +609,7 @@ Photo get_web_document_photo(FileManager *file_manager, tl_object_ptr<telegram_a
DialogId owner_dialog_id) { DialogId owner_dialog_id) {
PhotoSize s = get_web_document_photo_size(file_manager, FileType::Photo, owner_dialog_id, std::move(web_document)); PhotoSize s = get_web_document_photo_size(file_manager, FileType::Photo, owner_dialog_id, std::move(web_document));
Photo photo; Photo photo;
if (!s.file_id.is_valid()) { if (!s.file_id.is_valid() || s.type == 'v') {
photo.id = -2; photo.id = -2;
} else { } else {
photo.id = 0; photo.id = 0;

View File

@ -90,7 +90,7 @@ bool operator!=(const DialogPhoto &lhs, const DialogPhoto &rhs);
StringBuilder &operator<<(StringBuilder &string_builder, const DialogPhoto &dialog_photo); StringBuilder &operator<<(StringBuilder &string_builder, const DialogPhoto &dialog_photo);
enum class PhotoFormat : int32 { Jpeg, Png, Webp, Tgs }; enum class PhotoFormat : int32 { Jpeg, Png, Webp, Tgs, Mpeg4 };
PhotoSize get_secret_thumbnail_photo_size(FileManager *file_manager, BufferSlice bytes, DialogId owner_dialog_id, PhotoSize get_secret_thumbnail_photo_size(FileManager *file_manager, BufferSlice bytes, DialogId owner_dialog_id,
int32 width, int32 height); int32 width, int32 height);
@ -98,11 +98,16 @@ Variant<PhotoSize, string> get_photo_size(FileManager *file_manager, PhotoSizeSo
int64 access_hash, string file_reference, DcId dc_id, int64 access_hash, string file_reference, DcId dc_id,
DialogId owner_dialog_id, tl_object_ptr<telegram_api::PhotoSize> &&size_ptr, DialogId owner_dialog_id, tl_object_ptr<telegram_api::PhotoSize> &&size_ptr,
PhotoFormat format); PhotoFormat format);
PhotoSize get_video_photo_size(FileManager *file_manager, PhotoSizeSource source, int64 id, int64 access_hash,
string file_reference, DcId dc_id, DialogId owner_dialog_id,
tl_object_ptr<telegram_api::videoSize> &&size);
PhotoSize get_web_document_photo_size(FileManager *file_manager, FileType file_type, DialogId owner_dialog_id, PhotoSize get_web_document_photo_size(FileManager *file_manager, FileType file_type, DialogId owner_dialog_id,
tl_object_ptr<telegram_api::WebDocument> web_document_ptr); tl_object_ptr<telegram_api::WebDocument> web_document_ptr);
td_api::object_ptr<td_api::photoSize> get_photo_size_object(FileManager *file_manager, const PhotoSize *photo_size); td_api::object_ptr<td_api::photoSize> get_photo_size_object(FileManager *file_manager, const PhotoSize *photo_size);
vector<td_api::object_ptr<td_api::photoSize>> get_photo_sizes_object(FileManager *file_manager, vector<td_api::object_ptr<td_api::photoSize>> get_photo_sizes_object(FileManager *file_manager,
const vector<PhotoSize> &photo_sizes); const vector<PhotoSize> &photo_sizes);
td_api::object_ptr<td_api::animatedThumbnail> get_animated_thumbnail_object(FileManager *file_manager,
const PhotoSize *photo_size);
bool operator==(const PhotoSize &lhs, const PhotoSize &rhs); bool operator==(const PhotoSize &lhs, const PhotoSize &rhs);
bool operator!=(const PhotoSize &lhs, const PhotoSize &rhs); bool operator!=(const PhotoSize &lhs, const PhotoSize &rhs);

View File

@ -40,7 +40,9 @@ tl_object_ptr<td_api::video> VideosManager::get_video_object(FileId file_id) {
return make_tl_object<td_api::video>( return make_tl_object<td_api::video>(
video->duration, video->dimensions.width, video->dimensions.height, video->file_name, video->mime_type, video->duration, video->dimensions.width, video->dimensions.height, video->file_name, video->mime_type,
video->has_stickers, video->supports_streaming, get_minithumbnail_object(video->minithumbnail), video->has_stickers, video->supports_streaming, get_minithumbnail_object(video->minithumbnail),
get_photo_size_object(td_->file_manager_.get(), &video->thumbnail), td_->file_manager_->get_file_object(file_id)); get_photo_size_object(td_->file_manager_.get(), &video->thumbnail),
get_animated_thumbnail_object(td_->file_manager_.get(), &video->animated_thumbnail),
td_->file_manager_->get_file_object(file_id));
} }
FileId VideosManager::on_get_video(unique_ptr<Video> new_video, bool replace) { FileId VideosManager::on_get_video(unique_ptr<Video> new_video, bool replace) {
@ -84,6 +86,16 @@ FileId VideosManager::on_get_video(unique_ptr<Video> new_video, bool replace) {
v->thumbnail = new_video->thumbnail; v->thumbnail = new_video->thumbnail;
v->is_changed = true; v->is_changed = true;
} }
if (v->animated_thumbnail != new_video->animated_thumbnail) {
if (!v->animated_thumbnail.file_id.is_valid()) {
LOG(DEBUG) << "Video " << file_id << " animated thumbnail has changed";
} else {
LOG(INFO) << "Video " << file_id << " animated thumbnail has changed from " << v->animated_thumbnail << " to "
<< new_video->animated_thumbnail;
}
v->animated_thumbnail = new_video->animated_thumbnail;
v->is_changed = true;
}
if (v->has_stickers != new_video->has_stickers && new_video->has_stickers) { if (v->has_stickers != new_video->has_stickers && new_video->has_stickers) {
v->has_stickers = new_video->has_stickers; v->has_stickers = new_video->has_stickers;
v->is_changed = true; v->is_changed = true;
@ -112,10 +124,17 @@ FileId VideosManager::get_video_thumbnail_file_id(FileId file_id) const {
return video->thumbnail.file_id; return video->thumbnail.file_id;
} }
FileId VideosManager::get_video_animated_thumbnail_file_id(FileId file_id) const {
auto video = get_video(file_id);
CHECK(video != nullptr);
return video->animated_thumbnail.file_id;
}
void VideosManager::delete_video_thumbnail(FileId file_id) { void VideosManager::delete_video_thumbnail(FileId file_id) {
auto &video = videos_[file_id]; auto &video = videos_[file_id];
CHECK(video != nullptr); CHECK(video != nullptr);
video->thumbnail = PhotoSize(); video->thumbnail = PhotoSize();
video->animated_thumbnail = PhotoSize();
} }
FileId VideosManager::dup_video(FileId new_id, FileId old_id) { FileId VideosManager::dup_video(FileId new_id, FileId old_id) {
@ -126,6 +145,7 @@ FileId VideosManager::dup_video(FileId new_id, FileId old_id) {
new_video = make_unique<Video>(*old_video); new_video = make_unique<Video>(*old_video);
new_video->file_id = new_id; new_video->file_id = new_id;
new_video->thumbnail.file_id = td_->file_manager_->dup_file_id(new_video->thumbnail.file_id); new_video->thumbnail.file_id = td_->file_manager_->dup_file_id(new_video->thumbnail.file_id);
new_video->animated_thumbnail.file_id = td_->file_manager_->dup_file_id(new_video->animated_thumbnail.file_id);
return new_id; return new_id;
} }
@ -172,9 +192,10 @@ bool VideosManager::merge_videos(FileId new_id, FileId old_id, bool can_delete_o
return true; return true;
} }
void VideosManager::create_video(FileId file_id, string minithumbnail, PhotoSize thumbnail, bool has_stickers, void VideosManager::create_video(FileId file_id, string minithumbnail, PhotoSize thumbnail,
vector<FileId> &&sticker_file_ids, string file_name, string mime_type, int32 duration, PhotoSize animated_thumbnail, bool has_stickers, vector<FileId> &&sticker_file_ids,
Dimensions dimensions, bool supports_streaming, bool replace) { string file_name, string mime_type, int32 duration, Dimensions dimensions,
bool supports_streaming, bool replace) {
auto v = make_unique<Video>(); auto v = make_unique<Video>();
v->file_id = file_id; v->file_id = file_id;
v->file_name = std::move(file_name); v->file_name = std::move(file_name);
@ -183,6 +204,7 @@ void VideosManager::create_video(FileId file_id, string minithumbnail, PhotoSize
v->dimensions = dimensions; v->dimensions = dimensions;
v->minithumbnail = std::move(minithumbnail); v->minithumbnail = std::move(minithumbnail);
v->thumbnail = std::move(thumbnail); v->thumbnail = std::move(thumbnail);
v->animated_thumbnail = std::move(animated_thumbnail);
v->supports_streaming = supports_streaming; v->supports_streaming = supports_streaming;
v->has_stickers = has_stickers; v->has_stickers = has_stickers;
v->sticker_file_ids = std::move(sticker_file_ids); v->sticker_file_ids = std::move(sticker_file_ids);

View File

@ -30,9 +30,9 @@ class VideosManager {
tl_object_ptr<td_api::video> get_video_object(FileId file_id); tl_object_ptr<td_api::video> get_video_object(FileId file_id);
void create_video(FileId file_id, string minithumbnail, PhotoSize thumbnail, bool has_stickers, void create_video(FileId file_id, string minithumbnail, PhotoSize thumbnail, PhotoSize animated_thumbnail,
vector<FileId> &&sticker_file_ids, string file_name, string mime_type, int32 duration, bool has_stickers, vector<FileId> &&sticker_file_ids, string file_name, string mime_type,
Dimensions dimensions, bool supports_streaming, bool replace); int32 duration, Dimensions dimensions, bool supports_streaming, bool replace);
tl_object_ptr<telegram_api::InputMedia> get_input_media(FileId file_id, tl_object_ptr<telegram_api::InputMedia> get_input_media(FileId file_id,
tl_object_ptr<telegram_api::InputFile> input_file, tl_object_ptr<telegram_api::InputFile> input_file,
@ -45,6 +45,8 @@ class VideosManager {
FileId get_video_thumbnail_file_id(FileId file_id) const; FileId get_video_thumbnail_file_id(FileId file_id) const;
FileId get_video_animated_thumbnail_file_id(FileId file_id) const;
void delete_video_thumbnail(FileId file_id); void delete_video_thumbnail(FileId file_id);
FileId dup_video(FileId new_id, FileId old_id); FileId dup_video(FileId new_id, FileId old_id);
@ -68,6 +70,7 @@ class VideosManager {
Dimensions dimensions; Dimensions dimensions;
string minithumbnail; string minithumbnail;
PhotoSize thumbnail; PhotoSize thumbnail;
PhotoSize animated_thumbnail;
bool supports_streaming = false; bool supports_streaming = false;

View File

@ -22,9 +22,11 @@ void VideosManager::store_video(FileId file_id, StorerT &storer) const {
auto it = videos_.find(file_id); auto it = videos_.find(file_id);
CHECK(it != videos_.end()); CHECK(it != videos_.end());
const Video *video = it->second.get(); const Video *video = it->second.get();
bool has_animated_thumbnail = video->animated_thumbnail.file_id.is_valid();
BEGIN_STORE_FLAGS(); BEGIN_STORE_FLAGS();
STORE_FLAG(video->has_stickers); STORE_FLAG(video->has_stickers);
STORE_FLAG(video->supports_streaming); STORE_FLAG(video->supports_streaming);
STORE_FLAG(has_animated_thumbnail);
END_STORE_FLAGS(); END_STORE_FLAGS();
store(video->file_name, storer); store(video->file_name, storer);
store(video->mime_type, storer); store(video->mime_type, storer);
@ -36,14 +38,19 @@ void VideosManager::store_video(FileId file_id, StorerT &storer) const {
if (video->has_stickers) { if (video->has_stickers) {
store(video->sticker_file_ids, storer); store(video->sticker_file_ids, storer);
} }
if (has_animated_thumbnail) {
store(video->animated_thumbnail, storer);
}
} }
template <class ParserT> template <class ParserT>
FileId VideosManager::parse_video(ParserT &parser) { FileId VideosManager::parse_video(ParserT &parser) {
auto video = make_unique<Video>(); auto video = make_unique<Video>();
bool has_animated_thumbnail;
BEGIN_PARSE_FLAGS(); BEGIN_PARSE_FLAGS();
PARSE_FLAG(video->has_stickers); PARSE_FLAG(video->has_stickers);
PARSE_FLAG(video->supports_streaming); PARSE_FLAG(video->supports_streaming);
PARSE_FLAG(has_animated_thumbnail);
END_PARSE_FLAGS(); END_PARSE_FLAGS();
parse(video->file_name, parser); parse(video->file_name, parser);
parse(video->mime_type, parser); parse(video->mime_type, parser);
@ -57,6 +64,9 @@ FileId VideosManager::parse_video(ParserT &parser) {
if (video->has_stickers) { if (video->has_stickers) {
parse(video->sticker_file_ids, parser); parse(video->sticker_file_ids, parser);
} }
if (has_animated_thumbnail) {
parse(video->animated_thumbnail, parser);
}
if (parser.get_error() != nullptr || !video->file_id.is_valid()) { if (parser.get_error() != nullptr || !video->file_id.is_valid()) {
return FileId(); return FileId();
} }