Add separate class for StoryContent.

This commit is contained in:
levlam 2023-05-18 17:20:22 +03:00
parent 0fb5916ea2
commit 17fc0c3a88
7 changed files with 279 additions and 15 deletions

View File

@ -468,6 +468,8 @@ set(TDLIB_SOURCE
td/telegram/StickersManager.cpp
td/telegram/StickerType.cpp
td/telegram/StorageManager.cpp
td/telegram/StoryContent.cpp
td/telegram/StoryContentType.cpp
td/telegram/StoryManager.cpp
td/telegram/SuggestedAction.cpp
td/telegram/Support.cpp
@ -758,6 +760,8 @@ set(TDLIB_SOURCE
td/telegram/StickersManager.h
td/telegram/StickerType.h
td/telegram/StorageManager.h
td/telegram/StoryContent.h
td/telegram/StoryContentType.h
td/telegram/StoryId.h
td/telegram/StoryManager.h
td/telegram/SuggestedAction.h

View File

@ -0,0 +1,167 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// 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/StoryContent.h"
#include "td/telegram/DocumentsManager.h"
#include "td/telegram/files/FileId.h"
#include "td/telegram/Photo.h"
#include "td/telegram/Td.h"
#include "td/telegram/VideosManager.h"
#include "td/utils/common.h"
namespace td {
class StoryContentPhoto final : public StoryContent {
public:
Photo photo_;
StoryContentPhoto() = default;
explicit StoryContentPhoto(Photo &&photo) : photo_(std::move(photo)) {
}
StoryContentType get_type() const final {
return StoryContentType::Photo;
}
};
class StoryContentVideo final : public StoryContent {
public:
FileId file_id_;
FileId alt_file_id_;
StoryContentVideo() = default;
StoryContentVideo(FileId file_id, FileId alt_file_id) : file_id_(file_id), alt_file_id_(alt_file_id) {
}
StoryContentType get_type() const final {
return StoryContentType::Video;
}
};
class StoryContentUnsupported final : public StoryContent {
public:
static constexpr int32 CURRENT_VERSION = 1;
int32 version_ = CURRENT_VERSION;
StoryContentUnsupported() = default;
explicit StoryContentUnsupported(int32 version) : version_(version) {
}
StoryContentType get_type() const final {
return StoryContentType::Unsupported;
}
};
unique_ptr<StoryContent> get_story_content(Td *td, tl_object_ptr<telegram_api::MessageMedia> &&media_ptr,
DialogId owner_dialog_id) {
CHECK(media_ptr != nullptr);
int32 constructor_id = media_ptr->get_id();
switch (constructor_id) {
case telegram_api::messageMediaPhoto::ID: {
auto media = move_tl_object_as<telegram_api::messageMediaPhoto>(media_ptr);
if (media->photo_ == nullptr || (media->flags_ & telegram_api::messageMediaPhoto::TTL_SECONDS_MASK) != 0 ||
media->spoiler_) {
break;
}
auto photo = get_photo(td, std::move(media->photo_), owner_dialog_id);
if (photo.is_empty()) {
break;
}
return make_unique<StoryContentPhoto>(std::move(photo));
}
case telegram_api::messageMediaDocument::ID: {
auto media = move_tl_object_as<telegram_api::messageMediaDocument>(media_ptr);
if (media->document_ == nullptr || (media->flags_ & telegram_api::messageMediaDocument::TTL_SECONDS_MASK) != 0 ||
media->spoiler_) {
break;
}
auto document_ptr = std::move(media->document_);
int32 document_id = document_ptr->get_id();
if (document_id == telegram_api::documentEmpty::ID) {
break;
}
CHECK(document_id == telegram_api::document::ID);
auto parsed_document = td->documents_manager_->on_get_document(
move_tl_object_as<telegram_api::document>(document_ptr), owner_dialog_id, nullptr);
if (parsed_document.empty() || parsed_document.type != Document::Type::Video) {
break;
}
CHECK(parsed_document.file_id.is_valid());
FileId alt_file_id;
if (media->alt_document_ != nullptr) {
auto alt_document_ptr = std::move(media->alt_document_);
int32 alt_document_id = alt_document_ptr->get_id();
if (alt_document_id == telegram_api::documentEmpty::ID) {
LOG(ERROR) << "Receive alternative " << to_string(alt_document_ptr);
} else {
CHECK(alt_document_id == telegram_api::document::ID);
auto parsed_alt_document = td->documents_manager_->on_get_document(
move_tl_object_as<telegram_api::document>(alt_document_ptr), owner_dialog_id, nullptr);
if (parsed_alt_document.empty() || parsed_alt_document.type != Document::Type::Video) {
LOG(ERROR) << "Receive alternative " << to_string(alt_document_ptr);
} else {
alt_file_id = parsed_alt_document.file_id;
}
}
}
return make_unique<StoryContentVideo>(parsed_document.file_id, alt_file_id);
}
case telegram_api::messageMediaUnsupported::ID:
return make_unique<StoryContentUnsupported>();
default:
break;
}
LOG(ERROR) << "Receive a story with content " << to_string(media_ptr);
return nullptr;
}
void merge_story_contents(Td *td, const StoryContent *old_content, StoryContent *new_content, DialogId dialog_id,
bool need_merge_files, bool &is_content_changed, bool &need_update) {
StoryContentType content_type = new_content->get_type();
CHECK(old_content->get_type() == content_type);
switch (content_type) {
case StoryContentType::Photo: {
const auto *old_ = static_cast<const StoryContentPhoto *>(old_content);
auto *new_ = static_cast<StoryContentPhoto *>(new_content);
merge_photos(td, &old_->photo_, &new_->photo_, dialog_id, need_merge_files, is_content_changed, need_update);
break;
}
case StoryContentType::Video: {
const auto *old_ = static_cast<const StoryContentVideo *>(old_content);
const auto *new_ = static_cast<const StoryContentVideo *>(new_content);
if (old_->file_id_ != new_->file_id_) {
if (need_merge_files) {
td->videos_manager_->merge_videos(new_->file_id_, old_->file_id_);
}
need_update = true;
}
if (old_->alt_file_id_ != new_->alt_file_id_) {
need_update = true;
}
break;
}
case StoryContentType::Unsupported: {
const auto *old_ = static_cast<const StoryContentUnsupported *>(old_content);
const auto *new_ = static_cast<const StoryContentUnsupported *>(new_content);
if (old_->version_ != new_->version_) {
is_content_changed = true;
}
break;
}
default:
UNREACHABLE();
break;
}
}
} // namespace td

View File

@ -0,0 +1,35 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// 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/telegram/DialogId.h"
#include "td/telegram/StoryContentType.h"
#include "td/telegram/telegram_api.h"
namespace td {
class Td;
class StoryContent {
public:
StoryContent() = default;
StoryContent(const StoryContent &) = default;
StoryContent &operator=(const StoryContent &) = default;
StoryContent(StoryContent &&) = default;
StoryContent &operator=(StoryContent &&) = default;
virtual StoryContentType get_type() const = 0;
virtual ~StoryContent() = default;
};
unique_ptr<StoryContent> get_story_content(Td *td, telegram_api::object_ptr<telegram_api::MessageMedia> &&media_ptr,
DialogId owner_dialog_id);
void merge_story_contents(Td *td, const StoryContent *old_content, StoryContent *new_content, DialogId dialog_id,
bool need_merge_files, bool &is_content_changed, bool &need_update);
} // namespace td

View File

@ -0,0 +1,25 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// 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/StoryContentType.h"
namespace td {
StringBuilder &operator<<(StringBuilder &string_builder, StoryContentType content_type) {
switch (content_type) {
case StoryContentType::Photo:
return string_builder << "Photo";
case StoryContentType::Video:
return string_builder << "Video";
case StoryContentType::Unsupported:
return string_builder << "Unsupported";
default:
UNREACHABLE();
return string_builder;
}
}
} // namespace td

View File

@ -0,0 +1,26 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
//
// 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/HashTableUtils.h"
#include "td/utils/StringBuilder.h"
namespace td {
// increase StoryContentUnsupported::CURRENT_VERSION each time a new Story content type is added
enum class StoryContentType : int32 { Photo, Video, Unsupported };
StringBuilder &operator<<(StringBuilder &string_builder, StoryContentType content_type);
struct StoryContentTypeHash {
uint32 operator()(StoryContentType content_type) const {
return Hash<int32>()(static_cast<int32>(content_type));
}
};
} // namespace td

View File

@ -8,9 +8,9 @@
#include "td/telegram/AuthManager.h"
#include "td/telegram/ContactsManager.h"
#include "td/telegram/MessageContent.h"
#include "td/telegram/MessageContentType.h"
#include "td/telegram/MessageEntity.h"
#include "td/telegram/StoryContent.h"
#include "td/telegram/StoryContentType.h"
#include "td/telegram/Td.h"
namespace td {
@ -18,6 +18,8 @@ namespace td {
StoryManager::StoryManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) {
}
StoryManager::~StoryManager() = default;
void StoryManager::tear_down() {
parent_.reset();
}
@ -53,18 +55,14 @@ StoryId StoryManager::on_get_story(DialogId owner_dialog_id,
CHECK(story != nullptr);
bool is_bot = td_->auth_manager_->is_bot();
auto message_text =
auto caption =
get_message_text(td_->contacts_manager_.get(), std::move(story_item->caption_), std::move(story_item->entities_),
true, is_bot, story_item->date_, false, "on_get_story");
int32 ttl = 0;
auto content = get_message_content(td_, std::move(message_text), std::move(story_item->media_), owner_dialog_id,
false, UserId(), &ttl, nullptr, "on_get_story");
auto content_type = content->get_type();
if (content_type != MessageContentType::Photo && content_type != MessageContentType::Video &&
content_type != MessageContentType::Unsupported) {
LOG(ERROR) << "Receive " << story_id << " of type " << content_type;
auto content = get_story_content(td_, std::move(story_item->media_), owner_dialog_id);
if (content == nullptr) {
return StoryId();
}
auto content_type = content->get_type();
auto privacy_rules = UserPrivacySettingRules::get_user_privacy_setting_rules(td_, std::move(story_item->privacy_));
@ -85,7 +83,8 @@ StoryId StoryManager::on_get_story(DialogId owner_dialog_id,
if (story->is_pinned_ != story_item->pinned_ || story->is_public_ != story_item->public_ ||
story->is_for_close_friends_ != story_item->close_friends_ || story->date_ != story_item->date_ ||
story->expire_date_ != story_item->expire_date_ || !(story->privacy_rules_ == privacy_rules) ||
story->recent_viewer_user_ids_ != recent_viewer_user_ids || story->view_count_ != view_count) {
story->recent_viewer_user_ids_ != recent_viewer_user_ids || story->view_count_ != view_count ||
story->caption_ != caption) {
story->is_pinned_ = story_item->pinned_;
story->is_public_ = story_item->public_;
story->is_for_close_friends_ = story_item->close_friends_;
@ -94,14 +93,15 @@ StoryId StoryManager::on_get_story(DialogId owner_dialog_id,
story->privacy_rules_ = std::move(privacy_rules);
story->recent_viewer_user_ids_ = std::move(recent_viewer_user_ids);
story->view_count_ = view_count;
story->caption_ = std::move(caption);
is_changed = true;
}
if (story->content_ == nullptr || story->content_->get_type() != content_type) {
story->content_ = std::move(content);
is_changed = true;
} else {
merge_message_contents(td_, story->content_.get(), content.get(), false, owner_dialog_id, false,
need_save_to_database, is_changed);
merge_story_contents(td_, story->content_.get(), content.get(), owner_dialog_id, false, need_save_to_database,
is_changed);
}
if (is_changed || need_save_to_database) {

View File

@ -7,6 +7,7 @@
#pragma once
#include "td/telegram/DialogId.h"
#include "td/telegram/MessageEntity.h"
#include "td/telegram/StoryId.h"
#include "td/telegram/UserId.h"
#include "td/telegram/UserPrivacySettingRule.h"
@ -18,12 +19,17 @@
namespace td {
class MessageContent;
class StoryContent;
class Td;
class StoryManager final : public Actor {
public:
StoryManager(Td *td, ActorShared<> parent);
StoryManager(const StoryManager &) = delete;
StoryManager &operator=(const StoryManager &) = delete;
StoryManager(StoryManager &&) = delete;
StoryManager &operator=(StoryManager &&) = delete;
~StoryManager() final;
StoryId on_get_story(DialogId owner_dialog_id, telegram_api::object_ptr<telegram_api::storyItem> &&story_item);
@ -37,7 +43,8 @@ class StoryManager final : public Actor {
vector<UserId> recent_viewer_user_ids_;
int32 view_count_ = 0;
UserPrivacySettingRules privacy_rules_;
unique_ptr<MessageContent> content_;
unique_ptr<StoryContent> content_;
FormattedText caption_;
};
void tear_down() final;