已保存的消息

“已保存消息”聊天功能允许用户收藏消息和媒体:它是一个个人云存储空间,用于存储您可能想要发送或转发的任何消息或媒体。

在内部,“已保存消息”聊天实际上就是我们自己的私聊(即与inputPeerSelf的聊天):与任何其他用户的聊天唯一的区别在于,“已保存消息”聊天提供了额外的功能,可以更好地组织发送到其中的消息和媒体。

已保存的消息对话框

模式:

message#9815cec8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true paid_suggested_post_stars:flags2.8?true paid_suggested_post_ton:flags2.9?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector<RestrictionReason> ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long suggested_post:flags2.7?SuggestedPost = Message; messageFwdHeader#4e4df4bb flags:# imported:flags.7?true saved_out:flags.11?true from_id:flags.0?Peer from_name:flags.5?string date:int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int saved_from_id:flags.8?Peer saved_from_name:flags.9?string saved_date:flags.10?int psa_type:flags.6?string = MessageFwdHeader;savedDialog#bd87cb6c flags:# pinned:flags.2?true peer:Peer top_message:int = SavedDialog;updateSavedDialogPinned#aeaf9e74 flags:# pinned:flags.0?true peer:DialogPeer = Update; updatePinnedSavedDialogs#686c85a6 flags:# order:flags.0?Vector<DialogPeer> = Update;messages.savedDialogs#f83ae221 dialogs:Vector<SavedDialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.SavedDialogs; messages.savedDialogsSlice#44ba9dd9 count:int dialogs:Vector<SavedDialog> messages:Vector<Message> chats:Vector<Chat> users:Vector<User> = messages.SavedDialogs; messages.savedDialogsNotModified#c01f6fe8 count:int = messages.SavedDialogs;savedDialog#bd87cb6c flags:# pinned:flags.2?true peer:Peer top_message:int = SavedDialog;---functions---messages.getSavedDialogs#1e91fc99 flags:# exclude_pinned:flags.0?true parent_peer:flags.1?InputPeer offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.SavedDialogs; messages.getSavedDialogsByID#6f6f9c96 flags:# parent_peer:flags.1?InputPeer ids:Vector<InputPeer> = messages.SavedDialogs; messages.getSavedHistory#998ab009 flags:# parent_peer:flags.0?InputPeer peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; messages.deleteSavedHistory#4dc5085f flags:# parent_peer:flags.0?InputPeer peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; messages.getPinnedSavedDialogs#d63d94e0 = messages.SavedDialogs; messages.toggleSavedDialogPin#ac81bbde flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; messages.reorderPinnedSavedDialogs#8b716587 flags:# force:flags.0?true order:Vector<InputDialogPeer> = Bool;messages.search#29ee847a flags:# peer:InputPeer q:string from_id:flags.0?InputPeer saved_peer_id:flags.2?InputPeer saved_reaction:flags.3?Vector<Reaction> top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; messages.getSearchCounters#1bbcf300 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer top_msg_id:flags.0?int filters:Vector<MessagesFilter> = Vector<messages.SearchCounter>; messages.getSearchResultsCalendar#6aa3f6bd flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int offset_date:int = messages.SearchResultsCalendar; messages.getSearchResultsPositions#9c7f2f10 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int limit:int = messages.SearchResultsPositions;

从各种用户(包括我们自己)发送和转发到“已保存消息”的消息,都会根据其原始对话自动分类到已保存的对话列表中,这与通常用于与聊天进行交互的普通对话列表非常相似。

要将新对话添加到普通对话列表中,用户必须向对话发送消息(或加入频道/聊天等)。
要将新对话添加到已保存的对话列表中,只需将任何普通对话中的消息转发给inputPeerSelf(当前用户):转发的消息(包括已发送的消息)将被添加到与原始对话具有相同 ID 的已保存对话中。

这包括发送的消息,例如假设以下情况:

保存与启用了前向隐私的用户进行的私人聊天消息,会将这些消息添加到具有特殊匿名用户的已保存对话条目中id=2666000。

客户可以使用以下伪代码手动填充存储在本地saved_peer_id数据库中的旧layer < 170消息。

// user_id is the ID of the current user.if (message.peer_id == user_id) {if (message.fwd_from.saved_from_peer) {message.saved_peer_id = message.fwd_from.saved_from_peer} elseif (message.fwd_from.from_id) {message.saved_peer_id = user_id;} elseif (message.fwd_from.from_name) {message.saved_peer_id = 2666000;} else {message.saved_peer_id = user_id;}}

直接向自己发送(而不是从其他对话转发)新消息,会将这些消息添加到与自己已保存的对话条目中。

注意:saved_peer_id消息字段也用于实现一个独特的功能,即直接频道消息 »:在这种情况下,它将peer_id等于 Monoforum 直接频道消息的 ID。

然后可以使用一系列方法来获取此对话框列表,固定/取消固定其中的对话框,查看和删除已保存对话框中的消息:messages.getSavedDialogs、messages.getSavedDialogsByID、messages.getSavedHistory、messages.deleteSavedHistory、messages.getPinnedSavedDialogs、messages.toggleSavedDialogPin、messages.reorderPinnedSavedDialogs的工作方式与它们的对应方法messages.getDialogs、messages.getHistory、messages.deleteHistory、messages.getPinnedDialogs、messages.toggleDialogPin、messages.reorderPinnedDialogs完全相同,唯一的区别是它们影响的是已保存的对话框列表,而不是主对话框列表。

上面列出的一些方法有一个可选parent_peer参数,该参数只有在处理monoforums时才应该填充,而处理已保存的消息时则不应该填充。

要搜索已保存对话框中的消息,请使用通常的messages.search、messages.getSearchCounters、messages.getSearchResultsCalendar、messages.getSearchResultsPositions方法,并传入peer=inputPeerSelf和saved_peer_id=id 参数来指定已保存对话框的 ID。

该 API 还提供了一个messages.readSavedHistory方法,但与名称所暗示的不同,它只能用于monoforum主题。

标签

为了更好地进行整理,高级用户可以为已保存的消息添加多个标签,以便在搜索中快速筛选。

messageReactions#a339f0b flags:# min:flags.0?true can_see_list:flags.2?true reactions_as_tags:flags.3?true results:Vector<ReactionCount> recent_reactions:flags.1?Vector<MessagePeerReaction> top_reactors:flags.4?Vector<MessageReactor> = MessageReactions;savedReactionTag#cb6ff828 flags:# reaction:Reaction title:flags.0?string count:int = SavedReactionTag;messages.savedReactionTagsNotModified#889b59ef = messages.SavedReactionTags; messages.savedReactionTags#3259950a tags:Vector<SavedReactionTag> hash:long = messages.SavedReactionTags;updateSavedReactionTags#39c67432 = Update;---functions---messages.sendReaction#d30d78d4 flags:# big:flags.1?true add_to_recent:flags.2?true peer:InputPeer msg_id:int reaction:flags.0?Vector<Reaction> = Updates;messages.search#29ee847a flags:# peer:InputPeer q:string from_id:flags.0?InputPeer saved_peer_id:flags.2?InputPeer saved_reaction:flags.3?Vector<Reaction> top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages;messages.getDefaultTagReactions#bdf93428 hash:long = messages.Reactions;messages.updateSavedReactionTag#60297dec flags:# reaction:Reaction title:flags.0?string = Bool; messages.getSavedReactionTags#3637e05b flags:# peer:flags.0?InputPeer hash:long = messages.SavedReactionTags;

标签基于反应 »:向已保存的消息添加标签就像对其做出反应一样简单 »使用messages.sendReaction。

只有在满足以下条件的情况下,回复才会被视为已保存消息的标签:

您可以使用messages.searchsaved_reaction参数搜索带有一个或多个反应标记的已保存消息。

messages.getDefaultTagReactions可用于获取默认推荐的标签反应列表。

用户还可以使用messages.updateSavedReactionTag为标签反应分配一个名称(最多 12 个 UTF-8 字符) ;要删除名称,请调用相同的方法而不设置标志title。

`messages.getSavedReactionTags`可用于获取并本地缓存用户分配的所有反应标签名称列表;peer可以指定一个参数,仅获取特定已保存消息对话框中消息所使用的反应标签。
更新反应标签名称会向除当前会话之外的所有已登录会话发出`updateSavedReactionTags`更新;此更新应触发对`messages.getSavedReactionTags`的调用, 而无需设置peer刷新本地缓存列表的标志。

更新了反应标签的客户端不会收到updateSavedReactionTags 的请求:在这种情况下,客户端可以选择每次更新反应标签时手动调用messages.getSavedReactionTags,或者,为了避免额外的调用,它可以选择手动更新缓存列表,在这种情况下,hash应该使用以下算法重新生成缓存列表:

string remove_emoji_selectors(string emoji) {string str;for (i = 0; i < len(emoji); i++) {if (i + 3 <= len(emoji) && emoji[i] == '\xEF' && emoji[i + 1] == '\xB8' && emoji[i + 2] == '\x8F') {// skip \uFE0Fi += 2;} else {str += emoji[i];}}return str;}uint64 get_md5_string_hash(string str) {// Binary md5 hash, not hexstring hash = md5(str);uint64 result = 0;for (int i = 0; i <= 7; i++) {result += ((uint64)hash[i]) << (56 - 8 * i);}return result;}vector<uint64> numbers = [];// tags is an array of savedReactionTag constructorsforeach (tags as tag) {if tag.reaction instanceof reactionEmoji {numbers.append(get_md5_string_hash(remove_emoji_selectors(tag.reaction.emoticon)))} else if reaction instanceof reactionCustomEmoji {numbers.append(tag.reaction.document_id)}if (len(tag.title) > 0) {numbers.append(get_md5_string_hash(tag.title));}numbers.append(tag.count);}

然后必须将生成的 64 位整数列表传递给通常的哈希算法。

如果非空,则messages.getSavedReactionTags返回的已保存反应标签列表应显示在 UI 中搜索输入栏的正下方,按降序排列;如果在特定已保存的消息对话框count中搜索,则仅返回特定已保存消息对话框中使用的标签。peer

另一方面,标签反应选择界面应首先按降序显示messages.getSavedReactionTags返回的反应(全局标签列表,即不考虑当前已保存的消息对话框),然后显示messages.getDefaultTagReactions返回的、尚未被messages.getSavedReactionTags返回的反应,最后显示任何已安装的自定义表情包。peercount