diff --git a/CMakeLists.txt b/CMakeLists.txt index fb1e762af..b7e8905cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -409,6 +409,7 @@ set(TDLIB_SOURCE td/telegram/SpecialStickerSetType.cpp td/telegram/SponsoredMessageManager.cpp td/telegram/StateManager.cpp + td/telegram/StickerFormat.cpp td/telegram/StickersManager.cpp td/telegram/StorageManager.cpp td/telegram/SuggestedAction.cpp @@ -635,6 +636,7 @@ set(TDLIB_SOURCE td/telegram/SpecialStickerSetType.h td/telegram/SponsoredMessageManager.h td/telegram/StateManager.h + td/telegram/StickerFormat.h td/telegram/StickerSetId.h td/telegram/StickersManager.h td/telegram/StorageManager.h diff --git a/td/telegram/DocumentsManager.cpp b/td/telegram/DocumentsManager.cpp index c0b970e80..7fa639225 100644 --- a/td/telegram/DocumentsManager.cpp +++ b/td/telegram/DocumentsManager.cpp @@ -19,6 +19,7 @@ #include "td/telegram/Photo.h" #include "td/telegram/PhotoSizeSource.h" #include "td/telegram/secret_api.h" +#include "td/telegram/StickerFormat.h" #include "td/telegram/StickersManager.h" #include "td/telegram/Td.h" #include "td/telegram/td_api.h" @@ -145,6 +146,7 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo FileType file_type = FileType::Document; Slice default_extension; bool supports_streaming = false; + StickerFormat sticker_format = StickerFormat::Unknown; PhotoFormat thumbnail_format = PhotoFormat::Jpeg; if (type_attributes == 1 || default_document_type != Document::Type::General) { // not a general document if (animated != nullptr || default_document_type == Document::Type::Animation) { @@ -170,6 +172,7 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo } else if (sticker != nullptr || default_document_type == Document::Type::Sticker) { document_type = Document::Type::Sticker; file_type = FileType::Sticker; + sticker_format = StickerFormat::Webp; default_extension = Slice("webp"); owner_dialog_id = DialogId(); file_name.clear(); @@ -223,7 +226,6 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo PhotoSize thumbnail; AnimationSize animated_thumbnail; FileEncryptionKey encryption_key; - bool is_animated_sticker = false; bool is_web = false; bool is_web_no_proxy = false; string url; @@ -234,7 +236,7 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo return; } - is_animated_sticker = true; + sticker_format = StickerFormat::Tgs; if (document_type == Document::Type::General) { document_type = Document::Type::Sticker; file_type = FileType::Sticker; @@ -446,7 +448,7 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo minithumbnail = string(); } td_->stickers_manager_->create_sticker(file_id, std::move(minithumbnail), std::move(thumbnail), dimensions, - std::move(sticker), is_animated_sticker, load_data_multipromise_ptr); + std::move(sticker), sticker_format, load_data_multipromise_ptr); break; case Document::Type::Video: td_->videos_manager_->create_video(file_id, std::move(minithumbnail), std::move(thumbnail), diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index 1274d9657..c745dd7a5 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -53,6 +53,7 @@ #include "td/telegram/secret_api.hpp" #include "td/telegram/SecureValue.h" #include "td/telegram/SecureValue.hpp" +#include "td/telegram/StickerFormat.h" #include "td/telegram/StickersManager.h" #include "td/telegram/StickersManager.hpp" #include "td/telegram/Td.h" @@ -1762,8 +1763,8 @@ static Result create_input_message_content( td->stickers_manager_->create_sticker( file_id, string(), thumbnail, - get_dimensions(input_sticker->width_, input_sticker->height_, "inputMessageSticker"), nullptr, false, - nullptr); + get_dimensions(input_sticker->width_, input_sticker->height_, "inputMessageSticker"), nullptr, + StickerFormat::Unknown, nullptr); content = make_unique(file_id); break; diff --git a/td/telegram/StickerFormat.cpp b/td/telegram/StickerFormat.cpp new file mode 100644 index 000000000..314e8c361 --- /dev/null +++ b/td/telegram/StickerFormat.cpp @@ -0,0 +1,103 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/telegram/StickerFormat.h" + +namespace td { + +StickerFormat get_sticker_format(Slice mime_type) { + if (mime_type == "application/x-tgsticker") { + return StickerFormat::Tgs; + } + if (mime_type == "image/webp") { + return StickerFormat::Webp; + } + return StickerFormat::Unknown; +} + +string get_sticker_format_mime_type(StickerFormat sticker_format) { + switch (sticker_format) { + case StickerFormat::Unknown: + case StickerFormat::Webp: + return "image/webp"; + case StickerFormat::Tgs: + return "application/x-tgsticker"; + default: + UNREACHABLE(); + return string(); + } +} + +Slice get_sticker_format_extension(StickerFormat sticker_format) { + switch (sticker_format) { + case StickerFormat::Unknown: + return Slice(); + case StickerFormat::Webp: + return Slice(".webp"); + case StickerFormat::Tgs: + return Slice(".tgs"); + default: + UNREACHABLE(); + return Slice(); + } +} + +bool is_sticker_format_animated(StickerFormat sticker_format) { + switch (sticker_format) { + case StickerFormat::Unknown: + return false; + case StickerFormat::Webp: + return false; + case StickerFormat::Tgs: + return true; + default: + UNREACHABLE(); + return false; + } +} + +bool is_sticker_format_vector(StickerFormat sticker_format) { + switch (sticker_format) { + case StickerFormat::Unknown: + return false; + case StickerFormat::Webp: + return false; + case StickerFormat::Tgs: + return true; + default: + UNREACHABLE(); + return false; + } +} + +size_t get_max_sticker_file_size(StickerFormat sticker_format, bool for_thumbnail) { + switch (sticker_format) { + case StickerFormat::Unknown: + case StickerFormat::Webp: + return for_thumbnail ? (1 << 17) : (1 << 19); + case StickerFormat::Tgs: + return for_thumbnail ? (1 << 15) : (1 << 16); + default: + UNREACHABLE(); + return 0; + } +} + +StringBuilder &operator<<(StringBuilder &string_builder, StickerFormat sticker_format) { + switch (sticker_format) { + case StickerFormat::Unknown: + return string_builder << "unknown"; + case StickerFormat::Webp: + return string_builder << "WEBP"; + case StickerFormat::Tgs: + return string_builder << "TGS"; + default: + UNREACHABLE(); + return string_builder; + } +} + +} // namespace td diff --git a/td/telegram/StickerFormat.h b/td/telegram/StickerFormat.h new file mode 100644 index 000000000..dfa9a55f7 --- /dev/null +++ b/td/telegram/StickerFormat.h @@ -0,0 +1,32 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/utils/common.h" +#include "td/utils/Slice.h" +#include "td/utils/StringBuilder.h" + +namespace td { + +// update store_sticker/store_sticker_set when this type changes +enum class StickerFormat : int32 { Unknown, Webp, Tgs }; + +StickerFormat get_sticker_format(Slice mime_type); + +string get_sticker_format_mime_type(StickerFormat sticker_format); + +Slice get_sticker_format_extension(StickerFormat sticker_format); + +bool is_sticker_format_animated(StickerFormat sticker_format); + +bool is_sticker_format_vector(StickerFormat sticker_format); + +size_t get_max_sticker_file_size(StickerFormat sticker_format, bool for_thumbnail); + +StringBuilder &operator<<(StringBuilder &string_builder, StickerFormat sticker_format); + +} // namespace td diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index 985a2d5e8..545e42872 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -974,15 +974,15 @@ class CreateNewStickerSetQuery final : public Td::ResultHandler { } void send(tl_object_ptr &&input_user, const string &title, const string &short_name, - bool is_masks, bool is_animated, vector> &&input_stickers, - const string &software) { + bool is_masks, StickerFormat sticker_format, + vector> &&input_stickers, const string &software) { CHECK(input_user != nullptr); int32 flags = 0; if (is_masks) { flags |= telegram_api::stickers_createStickerSet::MASKS_MASK; } - if (is_animated) { + if (sticker_format == StickerFormat::Tgs) { flags |= telegram_api::stickers_createStickerSet::ANIMATED_MASK; } if (!software.empty()) { @@ -1808,13 +1808,13 @@ tl_object_ptr StickersManager::get_sticker_object(FileId file_i int32 width = sticker->dimensions.width; int32 height = sticker->dimensions.height; double zoom = 1.0; - if (sticker->is_animated && (for_animated_emoji || for_clicked_animated_emoji)) { + if (is_sticker_format_vector(sticker->format) && (for_animated_emoji || for_clicked_animated_emoji)) { zoom = for_clicked_animated_emoji ? 3 * animated_emoji_zoom_ : animated_emoji_zoom_; width = static_cast(width * zoom + 0.5); height = static_cast(height * zoom + 0.5); } return make_tl_object( - sticker->set_id.get(), width, height, sticker->alt, sticker->is_animated, sticker->is_mask, + sticker->set_id.get(), width, height, sticker->alt, sticker->format == StickerFormat::Tgs, sticker->is_mask, std::move(mask_position), get_sticker_minithumbnail(sticker->minithumbnail, sticker->set_id, document_id, zoom), std::move(thumbnail_object), td_->file_manager_->get_file_object(file_id)); } @@ -1898,6 +1898,20 @@ int32 StickersManager::get_dice_success_animation_frame_number(const string &emo return result.first == value ? result.second : std::numeric_limits::max(); } +PhotoFormat StickersManager::get_sticker_set_thumbnail_format(StickerFormat sticker_format) { + switch (sticker_format) { + case StickerFormat::Unknown: + return PhotoFormat::Webp; + case StickerFormat::Webp: + return PhotoFormat::Webp; + case StickerFormat::Tgs: + return PhotoFormat::Tgs; + default: + UNREACHABLE(); + return PhotoFormat::Webp; + } +} + tl_object_ptr StickersManager::get_sticker_set_object(StickerSetId sticker_set_id) const { const StickerSet *sticker_set = get_sticker_set(sticker_set_id); CHECK(sticker_set != nullptr); @@ -1916,13 +1930,14 @@ tl_object_ptr StickersManager::get_sticker_set_object(Sticke } emojis.push_back(make_tl_object(std::move(sticker_emojis))); } - auto thumbnail = get_thumbnail_object(td_->file_manager_.get(), sticker_set->thumbnail, - sticker_set->is_animated ? PhotoFormat::Tgs : PhotoFormat::Webp); + auto thumbnail_format = get_sticker_set_thumbnail_format(sticker_set->sticker_format); + auto thumbnail = get_thumbnail_object(td_->file_manager_.get(), sticker_set->thumbnail, thumbnail_format); return make_tl_object( sticker_set->id.get(), sticker_set->title, sticker_set->short_name, std::move(thumbnail), get_sticker_minithumbnail(sticker_set->minithumbnail, sticker_set->id, -2, 1.0), 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)); + sticker_set->sticker_format == StickerFormat::Tgs, 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, @@ -1962,13 +1977,13 @@ tl_object_ptr StickersManager::get_sticker_set_info_obje } } - auto thumbnail = get_thumbnail_object(td_->file_manager_.get(), sticker_set->thumbnail, - sticker_set->is_animated ? PhotoFormat::Tgs : PhotoFormat::Webp); + auto thumbnail_format = get_sticker_set_thumbnail_format(sticker_set->sticker_format); + auto thumbnail = get_thumbnail_object(td_->file_manager_.get(), sticker_set->thumbnail, thumbnail_format); return make_tl_object( sticker_set->id.get(), sticker_set->title, sticker_set->short_name, std::move(thumbnail), get_sticker_minithumbnail(sticker_set->minithumbnail, sticker_set->id, -3, 1.0), 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, + sticker_set->sticker_format == StickerFormat::Tgs, 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)); } @@ -2109,8 +2124,8 @@ FileId StickersManager::on_get_sticker(unique_ptr new_sticker, bool rep << s->m_thumbnail << " to " << new_sticker->m_thumbnail; s->m_thumbnail = std::move(new_sticker->m_thumbnail); } - if (s->is_animated != new_sticker->is_animated && new_sticker->is_animated) { - s->is_animated = new_sticker->is_animated; + if (s->format != new_sticker->format && new_sticker->format != StickerFormat::Unknown) { + s->format = new_sticker->format; } if (s->is_mask != new_sticker->is_mask && new_sticker->is_mask) { s->is_mask = new_sticker->is_mask; @@ -2181,13 +2196,13 @@ std::pair StickersManager::on_get_sticker_document( return {}; } - bool is_animated = document->mime_type_ == "application/x-tgsticker"; + auto format = get_sticker_format(document->mime_type_); int64 document_id = document->id_; FileId sticker_id = td_->file_manager_->register_remote(FullRemoteFileLocation(FileType::Sticker, document_id, document->access_hash_, dc_id, document->file_reference_.as_slice().str()), FileLocationSource::FromServer, DialogId(), document->size_, 0, - PSTRING() << document_id << (is_animated ? ".tgs" : ".webp")); + PSTRING() << document_id << get_sticker_format_extension(format)); PhotoSize thumbnail; string minithumbnail; @@ -2208,8 +2223,8 @@ std::pair StickersManager::on_get_sticker_document( } } - create_sticker(sticker_id, std::move(minithumbnail), std::move(thumbnail), dimensions, std::move(sticker), - is_animated, nullptr); + create_sticker(sticker_id, std::move(minithumbnail), std::move(thumbnail), dimensions, std::move(sticker), format, + nullptr); return {document_id, sticker_id}; } @@ -2383,9 +2398,10 @@ void StickersManager::merge_stickers(FileId new_id, FileId old_id, bool can_dele Sticker *new_ = new_it->second.get(); CHECK(new_ != nullptr); - if (old_->set_id == new_->set_id && (old_->alt != new_->alt || old_->set_id != new_->set_id || - (!old_->is_animated && !new_->is_animated && old_->dimensions.width != 0 && - old_->dimensions.height != 0 && old_->dimensions != new_->dimensions))) { + if (old_->set_id == new_->set_id && + (old_->alt != new_->alt || old_->set_id != new_->set_id || + (!is_sticker_format_vector(old_->format) && !is_sticker_format_vector(new_->format) && + old_->dimensions.width != 0 && old_->dimensions.height != 0 && old_->dimensions != new_->dimensions))) { LOG(ERROR) << "Sticker has changed: alt = (" << old_->alt << ", " << new_->alt << "), set_id = (" << old_->set_id << ", " << new_->set_id << "), dimensions = (" << old_->dimensions << ", " << new_->dimensions << ")"; } @@ -2523,9 +2539,9 @@ void StickersManager::add_sticker_thumbnail(Sticker *s, PhotoSize thumbnail) { } void StickersManager::create_sticker(FileId file_id, string minithumbnail, PhotoSize thumbnail, Dimensions dimensions, - tl_object_ptr sticker, bool is_animated, - MultiPromiseActor *load_data_multipromise_ptr) { - if (is_animated && dimensions.width == 0) { + tl_object_ptr sticker, + StickerFormat format, MultiPromiseActor *load_data_multipromise_ptr) { + if (is_sticker_format_vector(format) && dimensions.width == 0) { dimensions.width = 512; dimensions.height = 512; } @@ -2553,7 +2569,7 @@ void StickersManager::create_sticker(FileId file_id, string minithumbnail, Photo } } } - s->is_animated = is_animated; + s->format = format; on_get_sticker(std::move(s), sticker != nullptr); } @@ -2640,7 +2656,7 @@ SecretInputMedia StickersManager::get_secret_input_media(FileId sticker_file_id, return SecretInputMedia{std::move(input_file), make_tl_object( std::move(thumbnail), sticker->s_thumbnail.dimensions.width, - sticker->s_thumbnail.dimensions.height, get_sticker_mime_type(sticker), + sticker->s_thumbnail.dimensions.height, get_sticker_format_mime_type(sticker->format), narrow_cast(file_view.size()), BufferSlice(encryption_key.key_slice()), BufferSlice(encryption_key.iv_slice()), std::move(attributes), "")}; } else { @@ -2651,11 +2667,12 @@ SecretInputMedia StickersManager::get_secret_input_media(FileId sticker_file_id, LOG(ERROR) << "Have a web sticker in " << 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("t"), - remote_location.get_dc_id().get_raw_id(), std::move(attributes))}; + return SecretInputMedia{ + nullptr, make_tl_object( + remote_location.get_id(), remote_location.get_access_hash(), 0 /*date*/, + get_sticker_format_mime_type(sticker->format), narrow_cast(file_view.size()), + make_tl_object("t"), remote_location.get_dc_id().get_raw_id(), + std::move(attributes))}; } } @@ -2694,8 +2711,8 @@ tl_object_ptr StickersManager::get_input_media( if (input_thumbnail != nullptr) { flags |= telegram_api::inputMediaUploadedDocument::THUMB_MASK; } - auto mime_type = get_sticker_mime_type(s); - if (!s->is_animated && !s->set_id.is_valid()) { + auto mime_type = get_sticker_format_mime_type(s->format); + if (s->format == StickerFormat::Unknown && !s->set_id.is_valid()) { auto suggested_path = file_view.suggested_path(); const PathView path_view(suggested_path); if (path_view.extension() == "tgs") { @@ -2721,7 +2738,7 @@ StickerSetId StickersManager::on_get_sticker_set(tl_object_ptrflags_ & telegram_api::stickerSet::INSTALLED_DATE_MASK) != 0; bool is_archived = set->archived_; bool is_official = set->official_; - bool is_animated = set->animated_; + StickerFormat sticker_format = set->animated_ ? StickerFormat::Tgs : StickerFormat::Webp; bool is_masks = set->masks_; PhotoSize thumbnail; @@ -2731,7 +2748,7 @@ StickerSetId StickersManager::on_get_sticker_set(tl_object_ptrfile_manager_.get(), PhotoSizeSource::sticker_set_thumbnail(set_id.get(), s->access_hash, set->thumb_version_), 0, 0, "", DcId::create(set->thumb_dc_id_), DialogId(), std::move(thumb), - is_animated ? PhotoFormat::Tgs : PhotoFormat::Webp); + get_sticker_set_thumbnail_format(sticker_format)); if (photo_size.get_offset() == 0) { if (!thumbnail.file_id.is_valid()) { thumbnail = std::move(photo_size.get<0>()); @@ -2754,7 +2771,7 @@ StickerSetId 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->sticker_format = sticker_format; s->is_masks = is_masks; s->is_changed = true; } else { @@ -2819,10 +2836,10 @@ StickerSetId StickersManager::on_get_sticker_set(tl_object_ptris_official = is_official; s->is_changed = true; } - if (s->is_animated != is_animated) { - LOG(ERROR) << "Animated type of " << set_id << "/" << s->short_name << " has changed from " << s->is_animated - << " to " << is_animated << " from " << source; - s->is_animated = is_animated; + if (s->sticker_format != sticker_format) { + LOG(ERROR) << "Format of stickers in " << set_id << "/" << s->short_name << " has changed from " + << s->sticker_format << " to " << sticker_format << " from " << source; + s->sticker_format = sticker_format; s->is_changed = true; } LOG_IF(ERROR, s->is_masks != is_masks) << "Masks type of " << set_id << "/" << s->short_name << " has changed from " @@ -3225,7 +3242,7 @@ vector StickersManager::get_stickers(string emoji, int32 limit, bool for const Sticker *lhs_s = get_sticker(lhs); const Sticker *rhs_s = get_sticker(rhs); CHECK(lhs_s != nullptr && rhs_s != nullptr); - return lhs_s->is_animated && !rhs_s->is_animated; + return is_sticker_format_animated(lhs_s->format) && !is_sticker_format_animated(rhs_s->format); }; // std::stable_sort(prepend_sticker_ids.begin(), prepend_sticker_ids.begin() + recent_sticker_ids_[0].size(), // prefer_animated); @@ -3292,8 +3309,9 @@ vector StickersManager::get_stickers(string emoji, int32 limit, bool for } } std::stable_sort( - examined_sticker_sets.begin(), examined_sticker_sets.end(), - [](const StickerSet *lhs, const StickerSet *rhs) { return lhs->is_animated && !rhs->is_animated; }); + examined_sticker_sets.begin(), examined_sticker_sets.end(), [](const StickerSet *lhs, const StickerSet *rhs) { + return is_sticker_format_animated(lhs->sticker_format) && !is_sticker_format_animated(rhs->sticker_format); + }); for (auto sticker_set : examined_sticker_sets) { auto it = sticker_set->emoji_stickers_map_.find(emoji); if (it != sticker_set->emoji_stickers_map_.end()) { @@ -5387,7 +5405,8 @@ string &StickersManager::get_input_sticker_emojis(td_api::InputSticker *sticker) return static_cast(sticker)->emojis_; } -Result> StickersManager::prepare_input_sticker(td_api::InputSticker *sticker) { +Result> StickersManager::prepare_input_sticker( + td_api::InputSticker *sticker) { if (sticker == nullptr) { return Status::Error(400, "Input sticker must be non-empty"); } @@ -5398,30 +5417,32 @@ Result> StickersManager::prepare_input_stic switch (sticker->get_id()) { case td_api::inputStickerStatic::ID: - return prepare_input_file(static_cast(sticker)->sticker_, false, false); + return prepare_input_file(static_cast(sticker)->sticker_, StickerFormat::Webp, + false); case td_api::inputStickerAnimated::ID: - return prepare_input_file(static_cast(sticker)->sticker_, true, false); + return prepare_input_file(static_cast(sticker)->sticker_, StickerFormat::Tgs, + false); default: UNREACHABLE(); return {}; } } -Result> StickersManager::prepare_input_file( - const tl_object_ptr &input_file, bool is_animated, bool for_thumbnail) { - auto r_file_id = td_->file_manager_->get_input_file_id(is_animated ? FileType::Sticker : FileType::Document, - input_file, DialogId(), for_thumbnail, false); +Result> StickersManager::prepare_input_file( + const tl_object_ptr &input_file, StickerFormat format, bool for_thumbnail) { + auto file_type = format == StickerFormat::Tgs ? FileType::Sticker : FileType::Document; + auto r_file_id = td_->file_manager_->get_input_file_id(file_type, input_file, DialogId(), for_thumbnail, false); if (r_file_id.is_error()) { return Status::Error(400, r_file_id.error().message()); } auto file_id = r_file_id.move_as_ok(); if (file_id.empty()) { - return std::make_tuple(FileId(), false, false, false); + return std::make_tuple(FileId(), false, false, StickerFormat::Unknown); } - if (is_animated) { + if (file_type == FileType::Sticker) { int32 width = for_thumbnail ? 100 : 512; - create_sticker(file_id, string(), PhotoSize(), get_dimensions(width, width, "prepare_input_file"), nullptr, true, + create_sticker(file_id, string(), PhotoSize(), get_dimensions(width, width, "prepare_input_file"), nullptr, format, nullptr); } else { td_->documents_manager_->create_document(file_id, string(), PhotoSize(), "sticker.png", "image/png", false); @@ -5443,20 +5464,14 @@ Result> StickersManager::prepare_input_file if (file_view.has_url()) { is_url = true; } else { - auto max_file_size = [&] { - if (for_thumbnail) { - return is_animated ? MAX_ANIMATED_THUMBNAIL_FILE_SIZE : MAX_THUMBNAIL_FILE_SIZE; - } else { - return is_animated ? MAX_ANIMATED_STICKER_FILE_SIZE : MAX_STICKER_FILE_SIZE; - } - }(); - if (file_view.has_local_location() && file_view.expected_size() > max_file_size) { + if (file_view.has_local_location() && + file_view.expected_size() > get_max_sticker_file_size(format, for_thumbnail)) { return Status::Error(400, "File is too big"); } is_local = true; } } - return std::make_tuple(file_id, is_url, is_local, is_animated); + return std::make_tuple(file_id, is_url, is_local, format); } FileId StickersManager::upload_sticker_file(UserId user_id, tl_object_ptr &&sticker, @@ -5607,7 +5622,8 @@ void StickersManager::create_new_sticker_set(UserId user_id, string &title, stri file_ids.reserve(stickers.size()); vector local_file_ids; vector url_file_ids; - size_t animated_sticker_count = 0; + std::unordered_set sticker_formats; + StickerFormat sticker_format = StickerFormat::Unknown; for (auto &sticker : stickers) { auto r_file_id = prepare_input_sticker(sticker.get()); if (r_file_id.is_error()) { @@ -5616,13 +5632,11 @@ void StickersManager::create_new_sticker_set(UserId user_id, string &title, stri auto file_id = std::get<0>(r_file_id.ok()); auto is_url = std::get<1>(r_file_id.ok()); auto is_local = std::get<2>(r_file_id.ok()); - auto is_animated = std::get<3>(r_file_id.ok()); - if (is_animated) { - animated_sticker_count++; - if (is_url) { - return promise.set_error(Status::Error(400, "Animated stickers can't be uploaded by URL")); - } + sticker_format = std::get<3>(r_file_id.ok()); + if (is_sticker_format_animated(sticker_format) && is_url) { + return promise.set_error(Status::Error(400, "Animated stickers can't be uploaded by URL")); } + sticker_formats.insert(static_cast(sticker_format)); file_ids.push_back(file_id); if (is_url) { @@ -5631,17 +5645,16 @@ void StickersManager::create_new_sticker_set(UserId user_id, string &title, stri local_file_ids.push_back(file_id); } } - if (animated_sticker_count != stickers.size() && animated_sticker_count != 0) { - return promise.set_error(Status::Error(400, "All stickers must be either animated or static")); + if (sticker_formats.size() != 1) { + return promise.set_error(Status::Error(400, "All stickers must be of the same format")); } - bool is_animated = animated_sticker_count == stickers.size(); auto pending_new_sticker_set = make_unique(); pending_new_sticker_set->user_id = user_id; pending_new_sticker_set->title = std::move(title); pending_new_sticker_set->short_name = short_name; pending_new_sticker_set->is_masks = is_masks; - pending_new_sticker_set->is_animated = is_animated; + pending_new_sticker_set->sticker_format = sticker_format; pending_new_sticker_set->file_ids = std::move(file_ids); pending_new_sticker_set->stickers = std::move(stickers); pending_new_sticker_set->software = std::move(software); @@ -5732,11 +5745,12 @@ void StickersManager::do_upload_sticker_file(UserId user_id, FileId file_id, } FileView file_view = td_->file_manager_->get_file_view(file_id); - bool is_animated = file_view.get_type() == FileType::Sticker; + FileType file_type = file_view.get_type(); bool had_input_file = input_file != nullptr; - auto input_media = is_animated ? get_input_media(file_id, std::move(input_file), nullptr, string()) - : td_->documents_manager_->get_input_media(file_id, std::move(input_file), nullptr); + auto input_media = file_type == FileType::Sticker + ? get_input_media(file_id, std::move(input_file), nullptr, string()) + : td_->documents_manager_->get_input_media(file_id, std::move(input_file), nullptr); CHECK(input_media != nullptr); if (had_input_file && !FileManager::extract_was_uploaded(input_media)) { // if we had InputFile, but has failed to use it, then we need to immediately cancel file upload @@ -5765,8 +5779,8 @@ void StickersManager::on_uploaded_sticker_file(FileId file_id, tl_object_ptrfile_manager_->get_file_view(file_id); - bool is_animated = file_view.get_type() == FileType::Sticker; - auto expected_document_type = is_animated ? Document::Type::Sticker : Document::Type::General; + FileType file_type = file_view.get_type(); + auto expected_document_type = file_type == FileType::Sticker ? Document::Type::Sticker : Document::Type::General; auto parsed_document = td_->documents_manager_->on_get_document( move_tl_object_as(document_ptr), DialogId(), nullptr); @@ -5775,7 +5789,7 @@ void StickersManager::on_uploaded_sticker_file(FileId file_id, tl_object_ptr res TRY_RESULT_PROMISE(promise, input_user, td_->contacts_manager_->get_input_user(pending_new_sticker_set->user_id)); bool is_masks = pending_new_sticker_set->is_masks; - bool is_animated = pending_new_sticker_set->is_animated; + StickerFormat sticker_format = pending_new_sticker_set->sticker_format; auto sticker_count = pending_new_sticker_set->stickers.size(); vector> input_stickers; @@ -5820,7 +5834,7 @@ void StickersManager::on_new_stickers_uploaded(int64 random_id, Result res td_->create_handler(std::move(pending_new_sticker_set->promise)) ->send(std::move(input_user), pending_new_sticker_set->title, pending_new_sticker_set->short_name, is_masks, - is_animated, std::move(input_stickers), pending_new_sticker_set->software); + sticker_format, std::move(input_stickers), pending_new_sticker_set->software); } void StickersManager::add_sticker_to_set(UserId user_id, string &short_name, @@ -5923,7 +5937,7 @@ void StickersManager::do_set_sticker_set_thumbnail(UserId user_id, string short_ return promise.set_error(Status::Error(400, "Sticker set not found")); } - auto r_file_id = prepare_input_file(thumbnail, sticker_set->is_animated, true); + auto r_file_id = prepare_input_file(thumbnail, sticker_set->sticker_format, true); if (r_file_id.is_error()) { return promise.set_error(r_file_id.move_as_error()); } @@ -6928,10 +6942,6 @@ 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 d42115ffd..ec90c476d 100644 --- a/td/telegram/StickersManager.h +++ b/td/telegram/StickersManager.h @@ -13,6 +13,7 @@ #include "td/telegram/Photo.h" #include "td/telegram/SecretInputMedia.h" #include "td/telegram/SpecialStickerSetType.h" +#include "td/telegram/StickerFormat.h" #include "td/telegram/StickerSetId.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" @@ -91,7 +92,7 @@ class StickersManager final : public Actor { vector get_active_reactions(const vector &available_reactions); void create_sticker(FileId file_id, string minithumbnail, PhotoSize thumbnail, Dimensions dimensions, - tl_object_ptr sticker, bool is_animated, + tl_object_ptr sticker, StickerFormat sticker_format, MultiPromiseActor *load_data_multipromise_ptr); bool has_input_media(FileId sticker_file_id, bool is_secret) const; @@ -328,13 +329,9 @@ class StickersManager final : public Actor { static constexpr int32 MAX_FEATURED_STICKER_SET_VIEW_DELAY = 5; static constexpr int32 OLD_FEATURED_STICKER_SET_SLICE_SIZE = 20; - static constexpr int32 MAX_FOUND_STICKERS = 100; // server side limit - static constexpr int64 MAX_STICKER_FILE_SIZE = 1 << 19; // server side limit - static constexpr int64 MAX_THUMBNAIL_FILE_SIZE = 1 << 17; // server side limit - static constexpr int64 MAX_ANIMATED_STICKER_FILE_SIZE = 1 << 16; // server side limit - static constexpr int64 MAX_ANIMATED_THUMBNAIL_FILE_SIZE = 1 << 15; // server side limit - static constexpr size_t MAX_STICKER_SET_TITLE_LENGTH = 64; // server side limit - static constexpr size_t MAX_STICKER_SET_SHORT_NAME_LENGTH = 64; // server side limit + static constexpr int32 MAX_FOUND_STICKERS = 100; // server side limit + static constexpr size_t MAX_STICKER_SET_TITLE_LENGTH = 64; // server side limit + static constexpr size_t MAX_STICKER_SET_SHORT_NAME_LENGTH = 64; // server side limit static constexpr int32 EMOJI_KEYWORDS_UPDATE_DELAY = 3600; static constexpr double MIN_ANIMATED_EMOJI_CLICK_DELAY = 0.2; @@ -348,7 +345,7 @@ class StickersManager final : public Actor { PhotoSize s_thumbnail; PhotoSize m_thumbnail; FileId file_id; - bool is_animated = false; + StickerFormat format = StickerFormat::Unknown; bool is_mask = false; int32 point = -1; double x_shift = 0; @@ -366,6 +363,7 @@ class StickersManager final : public Actor { int64 access_hash = 0; string title; string short_name; + StickerFormat sticker_format = StickerFormat::Unknown; int32 sticker_count = 0; int32 hash = 0; int32 expires_at = 0; @@ -380,7 +378,6 @@ class StickersManager final : 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; @@ -398,8 +395,8 @@ class StickersManager final : public Actor { UserId user_id; string title; string short_name; + StickerFormat sticker_format = StickerFormat::Unknown; bool is_masks = false; - bool is_animated = false; vector file_ids; vector> stickers; string software; @@ -465,6 +462,8 @@ class StickersManager final : public Actor { StickerSet *add_sticker_set(StickerSetId sticker_set_id, int64 access_hash); + static PhotoFormat get_sticker_set_thumbnail_format(StickerFormat sticker_format); + std::pair on_get_sticker_document(tl_object_ptr &&document_ptr); static tl_object_ptr get_input_sticker_set(const StickerSet *set); @@ -588,10 +587,10 @@ class StickersManager final : public Actor { static string &get_input_sticker_emojis(td_api::InputSticker *sticker); - Result> prepare_input_file(const tl_object_ptr &input_file, - bool is_animated, bool for_thumbnail); + Result> prepare_input_file( + const tl_object_ptr &input_file, StickerFormat format, bool for_thumbnail); - Result> prepare_input_sticker(td_api::InputSticker *sticker); + Result> prepare_input_sticker(td_api::InputSticker *sticker); tl_object_ptr get_input_sticker(td_api::InputSticker *sticker, FileId file_id) const; @@ -674,8 +673,6 @@ class StickersManager final : public Actor { static void add_sticker_thumbnail(Sticker *s, PhotoSize thumbnail); - 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 612adbb15..42201a59a 100644 --- a/td/telegram/StickersManager.hpp +++ b/td/telegram/StickersManager.hpp @@ -11,6 +11,7 @@ #include "td/telegram/files/FileId.hpp" #include "td/telegram/misc.h" #include "td/telegram/Photo.hpp" +#include "td/telegram/StickerFormat.h" #include "td/utils/emoji.h" #include "td/utils/logging.h" @@ -28,11 +29,12 @@ void StickersManager::store_sticker(FileId file_id, bool in_sticker_set, StorerT const Sticker *sticker = it->second.get(); bool has_sticker_set_access_hash = sticker->set_id.is_valid() && !in_sticker_set; bool has_minithumbnail = !sticker->minithumbnail.empty(); + bool is_tgs = sticker->format == StickerFormat::Tgs; BEGIN_STORE_FLAGS(); STORE_FLAG(sticker->is_mask); STORE_FLAG(has_sticker_set_access_hash); STORE_FLAG(in_sticker_set); - STORE_FLAG(sticker->is_animated); + STORE_FLAG(is_tgs); STORE_FLAG(has_minithumbnail); END_STORE_FLAGS(); if (!in_sticker_set) { @@ -69,13 +71,19 @@ FileId StickersManager::parse_sticker(bool in_sticker_set, ParserT &parser) { bool has_sticker_set_access_hash; bool in_sticker_set_stored; bool has_minithumbnail; + bool is_tgs; BEGIN_PARSE_FLAGS(); PARSE_FLAG(sticker->is_mask); PARSE_FLAG(has_sticker_set_access_hash); PARSE_FLAG(in_sticker_set_stored); - PARSE_FLAG(sticker->is_animated); + PARSE_FLAG(is_tgs); PARSE_FLAG(has_minithumbnail); END_PARSE_FLAGS(); + if (is_tgs) { + sticker->format = StickerFormat::Tgs; + } else { + sticker->format = StickerFormat::Webp; + } if (in_sticker_set_stored != in_sticker_set) { Slice data = parser.template fetch_string_raw(parser.get_left_len()); for (auto c : data) { @@ -133,6 +141,7 @@ void StickersManager::store_sticker_set(const StickerSet *sticker_set, bool with bool has_expires_at = !sticker_set->is_installed && sticker_set->expires_at != 0; bool has_thumbnail = sticker_set->thumbnail.file_id.is_valid(); bool has_minithumbnail = !sticker_set->minithumbnail.empty(); + bool is_tgs = sticker_set->sticker_format == StickerFormat::Tgs; BEGIN_STORE_FLAGS(); STORE_FLAG(sticker_set->is_inited); STORE_FLAG(was_loaded); @@ -145,7 +154,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); + STORE_FLAG(is_tgs); STORE_FLAG(sticker_set->are_legacy_sticker_thumbnails_reloaded); STORE_FLAG(has_minithumbnail); END_STORE_FLAGS(); @@ -195,7 +204,7 @@ void StickersManager::parse_sticker_set(StickerSet *sticker_set, ParserT &parser bool is_masks; bool has_expires_at; bool has_thumbnail; - bool is_animated; + bool is_tgs; bool has_minithumbnail; BEGIN_PARSE_FLAGS(); PARSE_FLAG(sticker_set->is_inited); @@ -209,7 +218,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); + PARSE_FLAG(is_tgs); PARSE_FLAG(sticker_set->are_legacy_sticker_thumbnails_reloaded); PARSE_FLAG(has_minithumbnail); END_PARSE_FLAGS(); @@ -223,6 +232,13 @@ void StickersManager::parse_sticker_set(StickerSet *sticker_set, ParserT &parser << sticker_set->access_hash; } + StickerFormat sticker_format = StickerFormat::Unknown; + if (is_tgs) { + sticker_format = StickerFormat::Tgs; + } else { + sticker_format = StickerFormat::Webp; + } + if (sticker_set->is_inited) { string title; string short_name; @@ -255,7 +271,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; + sticker_set->sticker_format = sticker_format; 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); @@ -270,9 +286,9 @@ 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) << "Is animated of " << sticker_set->id << " has changed from \"" << is_animated << "\" to \"" - << sticker_set->is_animated << "\""; + if (sticker_set->sticker_format != sticker_format) { + LOG(ERROR) << "Sticker format of " << sticker_set->id << " has changed from \"" << sticker_format << "\" to \"" + << sticker_set->sticker_format << "\""; } if (sticker_set->is_masks != is_masks) { LOG(ERROR) << "Is masks of " << sticker_set->id << " has changed from \"" << is_masks << "\" to \""