Add td_api::messagePaidMedia.

This commit is contained in:
levlam 2024-06-21 12:25:23 +03:00
parent 5cb008b58d
commit d0bc0ccfd8
7 changed files with 182 additions and 11 deletions

View File

@ -1516,8 +1516,8 @@ inputTextQuote text:formattedText position:int32 = InputTextQuote;
//@origin_send_date Point in time (Unix timestamp) when the message was sent if the message was from another chat or topic; 0 for messages from the same chat
//@content Media content of the message if the message was from another chat or topic; may be null for messages from the same chat and messages without media.
//-Can be only one of the following types: messageAnimation, messageAudio, messageContact, messageDice, messageDocument, messageGame, messageInvoice, messageLocation,
//-messagePhoto, messagePoll, messagePremiumGiveaway, messagePremiumGiveawayWinners, messageSticker, messageStory, messageText (for link preview), messageVenue,
//-messageVideo, messageVideoNote, or messageVoiceNote
//-messagePaidMedia, messagePhoto, messagePoll, messagePremiumGiveaway, messagePremiumGiveawayWinners, messageSticker, messageStory, messageText (for link preview),
//-messageVenue, messageVideo, messageVideoNote, or messageVoiceNote
messageReplyToMessage chat_id:int53 message_id:int53 quote:textQuote origin:MessageOrigin origin_send_date:int32 content:MessageContent = MessageReplyTo;
//@description Describes a story replied by a given message @story_sender_chat_id The identifier of the sender of the story @story_id The identifier of the story
@ -3117,6 +3117,12 @@ messageAudio audio:audio caption:formattedText = MessageContent;
//@description A document message (general file) @document The document description @caption Document caption
messageDocument document:document caption:formattedText = MessageContent;
//@description A message with paid media
//@star_count Number of stars needed to buy access to the media in the message
//@media Information about the media
//@caption Media caption
messagePaidMedia star_count:int53 media:vector<MessageExtendedMedia> caption:formattedText = MessageContent;
//@description A photo message
//@photo The photo
//@caption Photo caption
@ -3507,7 +3513,7 @@ messageSelfDestructTypeImmediately = MessageSelfDestructType;
//@only_preview Pass true to get a fake message instead of actually sending them
messageSendOptions disable_notification:Bool from_background:Bool protect_content:Bool update_order_of_installed_sticker_sets:Bool scheduling_state:MessageSchedulingState effect_id:int64 sending_id:int32 only_preview:Bool = MessageSendOptions;
//@description Options to be used when a message content is copied without reference to the original sender. Service messages, messages with messageInvoice, messagePremiumGiveaway, or messagePremiumGiveawayWinners content can't be copied
//@description Options to be used when a message content is copied without reference to the original sender. Service messages, messages with messageInvoice, messagePaidMedia, messagePremiumGiveaway, or messagePremiumGiveawayWinners content can't be copied
//@send_copy True, if content of the message needs to be copied without reference to the original sender. Always true if the message is forwarded to a secret chat or is local
//@replace_caption True, if media caption of the message copy needs to be replaced. Ignored if send_copy is false
//@new_caption New message caption; pass null to copy message without caption. Ignored if replace_caption is false

View File

@ -1047,8 +1047,8 @@ void BusinessConnectionManager::complete_upload_media(unique_ptr<PendingMessage>
bool need_update = false;
unique_ptr<MessageContent> &old_content = message->content_;
MessageContentType old_content_type = old_content->get_type();
MessageContentType new_content_type = new_content->get_type();
auto old_content_type = old_content->get_type();
auto new_content_type = new_content->get_type();
auto old_file_id = get_message_file_id(message);
if (old_content_type != new_content_type) {

View File

@ -373,6 +373,7 @@ bool DialogAction::is_canceled_by_message_of_type(MessageContentType message_con
return type_ == Type::ChoosingSticker;
case MessageContentType::Game:
case MessageContentType::Invoice:
case MessageContentType::PaidMedia:
case MessageContentType::Text:
case MessageContentType::Unsupported:
case MessageContentType::ChatCreate:
@ -434,6 +435,7 @@ DialogAction DialogAction::get_uploading_action(MessageContentType message_conte
case MessageContentType::Animation:
case MessageContentType::Audio:
case MessageContentType::Document:
case MessageContentType::PaidMedia:
return DialogAction(Type::UploadingDocument, progress);
case MessageContentType::Photo:
return DialogAction(Type::UploadingPhoto, progress);

View File

@ -51,6 +51,7 @@
#include "td/telegram/Location.h"
#include "td/telegram/MessageEntity.h"
#include "td/telegram/MessageEntity.hpp"
#include "td/telegram/MessageExtendedMedia.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/MessageSearchFilter.h"
#include "td/telegram/MessageSender.h"
@ -72,6 +73,7 @@
#include "td/telegram/ServerMessageId.h"
#include "td/telegram/SharedDialog.h"
#include "td/telegram/SharedDialog.hpp"
#include "td/telegram/StarManager.h"
#include "td/telegram/StickerFormat.h"
#include "td/telegram/StickersManager.h"
#include "td/telegram/StickersManager.hpp"
@ -502,7 +504,7 @@ class MessageChatSetTtl final : public MessageContent {
class MessageUnsupported final : public MessageContent {
public:
static constexpr int32 CURRENT_VERSION = 31;
static constexpr int32 CURRENT_VERSION = 32;
int32 version = CURRENT_VERSION;
MessageUnsupported() = default;
@ -1120,6 +1122,22 @@ class MessageDialogShared final : public MessageContent {
}
};
class MessagePaidMedia final : public MessageContent {
public:
vector<MessageExtendedMedia> media;
FormattedText caption;
int64 star_count = 0;
MessagePaidMedia() = default;
MessagePaidMedia(vector<MessageExtendedMedia> &&media, FormattedText &&caption, int64 star_count)
: media(std::move(media)), caption(std::move(caption)), star_count(star_count) {
}
MessageContentType get_type() const final {
return MessageContentType::PaidMedia;
}
};
template <class StorerT>
static void store(const MessageContent *content, StorerT &storer) {
CHECK(content != nullptr);
@ -1684,6 +1702,19 @@ static void store(const MessageContent *content, StorerT &storer) {
store(m->button_id, storer);
break;
}
case MessageContentType::PaidMedia: {
const auto *m = static_cast<const MessagePaidMedia *>(content);
bool has_caption = !m->caption.text.empty();
BEGIN_STORE_FLAGS();
STORE_FLAG(has_caption);
END_STORE_FLAGS();
store(m->media, storer);
if (has_caption) {
store(m->caption, storer);
}
store(m->star_count, storer);
break;
}
default:
UNREACHABLE();
}
@ -2433,6 +2464,26 @@ static void parse(unique_ptr<MessageContent> &content, ParserT &parser) {
content = std::move(m);
break;
}
case MessageContentType::PaidMedia: {
auto m = make_unique<MessagePaidMedia>();
bool has_caption;
BEGIN_PARSE_FLAGS();
PARSE_FLAG(has_caption);
END_PARSE_FLAGS();
parse(m->media, parser);
if (has_caption) {
parse(m->caption, parser);
}
parse(m->star_count, parser);
for (auto &media : m->media) {
if (media.is_empty()) {
is_bad = true;
}
}
content = std::move(m);
break;
}
default:
is_bad = true;
@ -3158,6 +3209,7 @@ bool can_have_input_media(const Td *td, const MessageContent *content, bool is_s
case MessageContentType::Video:
case MessageContentType::VideoNote:
case MessageContentType::VoiceNote:
case MessageContentType::PaidMedia:
return true;
default:
UNREACHABLE();
@ -3284,6 +3336,7 @@ SecretInputMedia get_secret_input_media(const MessageContent *content, Td *td,
case MessageContentType::ExpiredVoiceNote:
case MessageContentType::BoostApply:
case MessageContentType::DialogShared:
case MessageContentType::PaidMedia:
break;
default:
UNREACHABLE();
@ -3342,6 +3395,11 @@ static tl_object_ptr<telegram_api::InputMedia> get_input_media_impl(
const auto *m = static_cast<const MessageLocation *>(content);
return m->location.get_input_media_geo_point();
}
case MessageContentType::PaidMedia: {
// const auto *m = static_cast<const MessagePaidMedia *>(content);
// TODO get_input_media
return nullptr;
}
case MessageContentType::Photo: {
const auto *m = static_cast<const MessagePhoto *>(content);
return photo_get_input_media(td->file_manager_.get(), m->photo, std::move(input_file), ttl.get_input_ttl(),
@ -3559,6 +3617,9 @@ void delete_message_content_thumbnail(MessageContent *content, Td *td) {
auto *m = static_cast<MessageInvoice *>(content);
return m->input_invoice.delete_thumbnail(td);
}
case MessageContentType::PaidMedia:
// TODO delete_message_content_thumbnail
break;
case MessageContentType::Photo: {
auto *m = static_cast<MessagePhoto *>(content);
return photo_delete_thumbnail(m->photo);
@ -3739,6 +3800,14 @@ Status can_send_message_content(DialogId dialog_id, const MessageContent *conten
return Status::Error(400, "Not enough rights to send locations to the chat");
}
break;
case MessageContentType::PaidMedia:
if (!permissions.can_send_photos() || !permissions.can_send_videos()) {
return Status::Error(400, "Not enough rights to send paid media to the chat");
}
if (dialog_type == DialogType::SecretChat) {
return Status::Error(400, "Paid media can't be sent to secret chats");
}
break;
case MessageContentType::Photo:
if (!permissions.can_send_photos()) {
return Status::Error(400, "Not enough rights to send photos to the chat");
@ -4005,6 +4074,7 @@ static int32 get_message_content_media_index_mask(const MessageContent *content,
case MessageContentType::ExpiredVoiceNote:
case MessageContentType::BoostApply:
case MessageContentType::DialogShared:
case MessageContentType::PaidMedia:
return 0;
default:
UNREACHABLE();
@ -4290,6 +4360,8 @@ vector<UserId> get_message_content_min_user_ids(const Td *td, const MessageConte
break;
case MessageContentType::DialogShared:
break;
case MessageContentType::PaidMedia:
break;
default:
UNREACHABLE();
break;
@ -4598,6 +4670,14 @@ void merge_message_contents(Td *td, const MessageContent *old_content, MessageCo
}
break;
}
case MessageContentType::PaidMedia: {
//const auto *old_ = static_cast<const MessagePaidMedia *>(old_content);
//const auto *new_ = static_cast<const MessagePaidMedia *>(new_content);
if (need_merge_files) {
// TODO merge extended media
}
break;
}
case MessageContentType::Photo: {
const auto *old_ = static_cast<const MessagePhoto *>(old_content);
auto *new_ = static_cast<MessagePhoto *>(new_content);
@ -4795,6 +4875,7 @@ bool merge_message_content_file_id(Td *td, MessageContent *message_content, File
case MessageContentType::Invoice:
case MessageContentType::LiveLocation:
case MessageContentType::Location:
case MessageContentType::PaidMedia:
case MessageContentType::Story:
case MessageContentType::Text:
case MessageContentType::Venue:
@ -5391,6 +5472,14 @@ void compare_message_contents(Td *td, const MessageContent *old_content, const M
}
break;
}
case MessageContentType::PaidMedia: {
const auto *lhs = static_cast<const MessagePaidMedia *>(old_content);
const auto *rhs = static_cast<const MessagePaidMedia *>(new_content);
if (lhs->caption != rhs->caption || lhs->star_count != rhs->star_count) {
need_update = true;
}
break;
}
default:
UNREACHABLE();
break;
@ -6313,8 +6402,14 @@ unique_ptr<MessageContent> get_message_content(Td *td, FormattedText message,
std::move(media->prize_description_), media->until_date_, media->only_new_subscribers_, media->refunded_,
media->winners_count_, media->unclaimed_count_, std::move(winner_user_ids));
}
case telegram_api::messageMediaPaidMedia::ID:
return make_unique<MessageUnsupported>();
case telegram_api::messageMediaPaidMedia::ID: {
auto media = telegram_api::move_object_as<telegram_api::messageMediaPaidMedia>(media_ptr);
auto extended_media = transform(std::move(media->extended_media_), [&](auto &&extended_media) {
return MessageExtendedMedia(td, std::move(extended_media), FormattedText(), owner_dialog_id);
});
return td::make_unique<MessagePaidMedia>(std::move(extended_media), std::move(message),
StarManager::get_star_count(media->stars_amount_));
}
case telegram_api::messageMediaUnsupported::ID:
return make_unique<MessageUnsupported>();
default:
@ -6425,6 +6520,17 @@ unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const
}
case MessageContentType::Location:
return make_unique<MessageLocation>(*static_cast<const MessageLocation *>(content));
case MessageContentType::PaidMedia: {
if (type == MessageContentDupType::Copy || type == MessageContentDupType::ServerCopy) {
return nullptr;
}
auto result = make_unique<MessagePaidMedia>(*static_cast<const MessagePaidMedia *>(content));
if (type != MessageContentDupType::Forward) {
// TODO support PaidMedia sending
return nullptr;
}
return result;
}
case MessageContentType::Photo: {
auto result = make_unique<MessagePhoto>(*static_cast<const MessagePhoto *>(content));
if (replace_caption) {
@ -6437,7 +6543,7 @@ unique_ptr<MessageContent> dup_message_content(Td *td, DialogId dialog_id, const
// having remote location is not enough to have InputMedia, because the file may not have valid file_reference
// also file_id needs to be duped, because upload can be called to repair the file_reference and every upload
// request must have unique file_id
if (!td->auth_manager_->is_bot()) {
if (!td->auth_manager_->is_bot() && type != MessageContentDupType::Forward) {
result->photo.photos.back().file_id = fix_file_id(result->photo.photos.back().file_id);
}
return std::move(result);
@ -7499,6 +7605,13 @@ tl_object_ptr<td_api::MessageContent> get_message_content_object(const MessageCo
return td_api::make_object<td_api::messageChatShared>(m->shared_dialogs[0].get_shared_chat_object(td),
m->button_id);
}
case MessageContentType::PaidMedia: {
const auto *m = static_cast<const MessagePaidMedia *>(content);
return td_api::make_object<td_api::messagePaidMedia>(
m->star_count,
transform(m->media, [&](const auto &media) { return media.get_message_extended_media_object(td); }),
get_formatted_text_object(m->caption, skip_bot_commands, max_media_timestamp));
}
default:
UNREACHABLE();
return nullptr;
@ -7532,6 +7645,8 @@ const FormattedText *get_message_content_caption(const MessageContent *content)
return &static_cast<const MessageDocument *>(content)->caption;
case MessageContentType::Invoice:
return static_cast<const MessageInvoice *>(content)->input_invoice.get_caption();
case MessageContentType::PaidMedia:
return &static_cast<const MessagePaidMedia *>(content)->caption;
case MessageContentType::Photo:
return &static_cast<const MessagePhoto *>(content)->caption;
case MessageContentType::Video:
@ -7585,6 +7700,13 @@ int32 get_message_content_duration(const MessageContent *content, const Td *td)
}
case MessageContentType::Invoice:
return static_cast<const MessageInvoice *>(content)->input_invoice.get_duration(td);
case MessageContentType::PaidMedia: {
int32 result = -1;
for (auto &media : static_cast<const MessagePaidMedia *>(content)->media) {
result = max(result, media.get_duration(td));
}
return result;
}
case MessageContentType::Video: {
auto video_file_id = static_cast<const MessageVideo *>(content)->file_id;
return td->videos_manager_->get_video_duration(video_file_id);
@ -7611,6 +7733,13 @@ int32 get_message_content_media_duration(const MessageContent *content, const Td
}
case MessageContentType::Invoice:
return static_cast<const MessageInvoice *>(content)->input_invoice.get_duration(td);
case MessageContentType::PaidMedia: {
int32 result = -1;
for (const auto &media : static_cast<const MessagePaidMedia *>(content)->media) {
result = max(result, media.get_duration(td));
}
return result;
}
case MessageContentType::Story: {
auto story_full_id = static_cast<const MessageStory *>(content)->story_full_id;
return td->story_manager_->get_story_duration(story_full_id);
@ -7814,6 +7943,13 @@ vector<FileId> get_message_content_file_ids(const MessageContent *content, const
case MessageContentType::Story:
// story file references are repaired independently
return {};
case MessageContentType::PaidMedia: {
vector<FileId> result;
for (const auto &media : static_cast<const MessagePaidMedia *>(content)->media) {
media.append_file_ids(td, result);
}
return result;
}
default:
return {};
}
@ -7858,6 +7994,10 @@ string get_message_content_search_text(const Td *td, const MessageContent *conte
const auto *invoice = static_cast<const MessageInvoice *>(content);
return invoice->input_invoice.get_caption()->text;
}
case MessageContentType::PaidMedia: {
const auto *paid_media = static_cast<const MessagePaidMedia *>(content);
return paid_media->caption.text;
}
case MessageContentType::Photo: {
const auto *photo = static_cast<const MessagePhoto *>(content);
return photo->caption.text;
@ -8004,6 +8144,15 @@ bool need_reget_message_content(const MessageContent *content) {
const auto *m = static_cast<const MessageInvoice *>(content);
return m->input_invoice.need_reget();
}
case MessageContentType::PaidMedia: {
const auto *m = static_cast<const MessagePaidMedia *>(content);
for (const auto &media : m->media) {
if (media.need_reget()) {
return true;
}
}
return false;
}
default:
return false;
}
@ -8285,6 +8434,8 @@ void add_message_content_dependencies(Dependencies &dependencies, const MessageC
break;
case MessageContentType::DialogShared:
break;
case MessageContentType::PaidMedia:
break;
default:
UNREACHABLE();
break;

View File

@ -146,6 +146,8 @@ StringBuilder &operator<<(StringBuilder &string_builder, MessageContentType cont
return string_builder << "BoostApply";
case MessageContentType::DialogShared:
return string_builder << "ChatShared";
case MessageContentType::PaidMedia:
return string_builder << "PaidMedia";
default:
return string_builder << "Invalid type " << static_cast<int32>(content_type);
}
@ -232,6 +234,7 @@ bool is_allowed_media_group_content(MessageContentType content_type) {
case MessageContentType::ExpiredVoiceNote:
case MessageContentType::BoostApply:
case MessageContentType::DialogShared:
case MessageContentType::PaidMedia:
return false;
default:
UNREACHABLE();
@ -313,6 +316,7 @@ bool can_be_secret_message_content(MessageContentType content_type) {
case MessageContentType::ExpiredVoiceNote:
case MessageContentType::BoostApply:
case MessageContentType::DialogShared:
case MessageContentType::PaidMedia:
return false;
default:
UNREACHABLE();
@ -390,6 +394,7 @@ bool can_be_local_message_content(MessageContentType content_type) {
case MessageContentType::ExpiredVoiceNote:
case MessageContentType::BoostApply:
case MessageContentType::DialogShared:
case MessageContentType::PaidMedia:
return false;
default:
UNREACHABLE();
@ -414,6 +419,7 @@ bool is_service_message_content(MessageContentType content_type) {
case MessageContentType::Invoice:
case MessageContentType::LiveLocation:
case MessageContentType::Location:
case MessageContentType::PaidMedia:
case MessageContentType::Photo:
case MessageContentType::Poll:
case MessageContentType::Sticker:
@ -480,6 +486,7 @@ bool is_editable_message_content(MessageContentType content_type) {
case MessageContentType::Audio:
case MessageContentType::Document:
case MessageContentType::Game:
case MessageContentType::PaidMedia:
case MessageContentType::Photo:
case MessageContentType::Text:
case MessageContentType::Video:
@ -563,6 +570,7 @@ bool is_supported_reply_message_content(MessageContentType content_type) {
case MessageContentType::GiveawayWinners:
case MessageContentType::Invoice:
case MessageContentType::Location:
case MessageContentType::PaidMedia:
case MessageContentType::Photo:
case MessageContentType::Poll:
case MessageContentType::Sticker:
@ -619,6 +627,7 @@ bool can_have_message_content_caption(MessageContentType content_type) {
case MessageContentType::Animation:
case MessageContentType::Audio:
case MessageContentType::Document:
case MessageContentType::PaidMedia:
case MessageContentType::Photo:
case MessageContentType::Video:
case MessageContentType::VoiceNote:
@ -697,6 +706,7 @@ uint64 get_message_content_chain_id(MessageContentType content_type) {
case MessageContentType::Audio:
case MessageContentType::Document:
case MessageContentType::Invoice:
case MessageContentType::PaidMedia:
case MessageContentType::Photo:
case MessageContentType::Sticker:
case MessageContentType::Video:

View File

@ -80,7 +80,8 @@ enum class MessageContentType : int32 {
ExpiredVideoNote,
ExpiredVoiceNote,
BoostApply,
DialogShared
DialogShared,
PaidMedia
};
// increase MessageUnsupported::CURRENT_VERSION each time a new message content type is added

View File

@ -1092,7 +1092,8 @@ unique_ptr<QuickReplyManager::QuickReplyMessage> QuickReplyManager::create_messa
auto content_type = content->get_type();
if (is_service_message_content(content_type) || content_type == MessageContentType::LiveLocation ||
is_expired_message_content(content_type) || content_type == MessageContentType::Poll) {
is_expired_message_content(content_type) || content_type == MessageContentType::Poll ||
content_type == MessageContentType::PaidMedia) {
LOG(ERROR) << "Receive " << content_type << " from " << source;
break;
}