文件上传和下载
在使用电报 Telegram 的API时,有时需要向服务器发送较大的文件。例如,发送带有照片/视频附件的消息,或者设置当前用户的个人资料图片时。
上传文件
有多种API方法可用于保存文件。下面展示了所使用的类型和方法的架构:
inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile;inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile;inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile;inputMediaUploadedPhoto#1e287d04 flags:# spoiler:flags.2?true file:InputFile stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia; inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia;inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto;---functions---messages.sendMedia#ac55d9c1 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; messages.uploadMedia#14967978 flags:# business_connection_id:flags.0?string peer:InputPeer media:InputMedia = MessageMedia; messages.sendEncryptedFile#5559481d flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage;photos.uploadProfilePhoto#388a3b5 flags:# fallback:flags.3?true bot:flags.5?InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.4?VideoSize = photos.Photo;upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool;
在传输文件内容之前,必须为文件分配一个唯一的 64 位客户端标识符:file_id。
然后,将文件的二进制内容分割成多个部分。所有部分的大小必须相同(part_size),并且必须满足以下条件:
- part_size % 1024 = 0(可被 1KB 整除)
- 524288 % part_size = 0(512KB 必须能被part_size整除)
最后一部分不必满足这些条件,只要它的大小小于part_size即可。
以下appConfig 字段指定可上传文件部分的最大数量:
- upload_max_fileparts_default »- 非高级用户可上传的最大文件部分数。
- upload_max_fileparts_premium »- 高级用户可上传的最大文件部分数。
请注意,可上传文件部分的限制并未考虑part_size :因此,只有当part_size达到最大值 512KB 时,才能达到总文件大小的限制,而这实际上是为避免过多的协议开销而推荐的part_size 。
每个部分都应该有一个序列号file_part,其值范围从 0 到相应配置参数的值减 1。
文件分割完成后,您需要选择一种将其保存到服务器的方法。如果文件总大小超过10 MB,请使用upload.saveBigFilePart;对于较小的文件,请使用upload.saveFilePart 。
每次调用都会将一部分数据保存到服务器上的临时位置,以供后续使用。每部分数据的存储期限从几分钟到几小时不等(取决于存储区域的繁忙程度)。超过此期限后,该文件部分将无法访问。
为了提高文件保存操作的效率,我们建议使用本地调用队列(即不使用 invokeAfterMsgs 方法),这样在任何给定时刻都会保存文件的 X 个片段。每次成功保存一个片段后,都会调用方法来保存下一个片段。可以调整 X 的值以达到最佳性能。
为了进一步提高性能,可以使用多个并行调用队列(即可调数量的 Y 个队列)连接到数据中心的独立 TCP 连接,以并行上传多个数据块。
使用上述方法之一保存文件片段时,可能会返回以下数据输入错误之一:
- FILE_PARTS_INVALID - 零件数量无效。该值不在以下范围内。1..upload_max_fileparts_*
- FILE_PART_INVALID:文件部件号无效。该值不在 00到 1之间upload_max_fileparts_*-1。
- 文件部分过大:文件部分的内容大小已超过限制 (512 KB)。
- FILE_PART_EMPTY:发送的文件部分为空。
- 文件分区大小无效 - 512KB 无法被分区大小整除
- 文件部分大小已更改 - 此部分的大小与同一文件中先前某个部分的大小不同
-
FLOOD_PREMIUM_WAIT_X:表示上传速度受限,因为当前帐户没有高级订阅,客户端必须在 X 秒后自动重复请求。
收到此错误时,客户端应显示Telegram 高级订阅弹窗,提示用户购买高级订阅以提升上传速度(upload_premium_speedup_upload次)。
请注意,此弹窗仅在用户当前可见正在上传的文件时显示;如果用户不可见,则应在正在加载/已加载的文件可见后显示弹窗。此外,此弹窗最多每隔upload_premium_speedup_notify_period
次 显示一次,以避免每次上传速度变慢时都弹出此弹窗。此错误仅在用户上传数十 GB 或更多文件时才会出现。
在上传文件各部分的同时,可以计算文件内容的MD5 哈希值,以便稍后将其用作inputFile构造函数中的md5_checksum参数(由于该哈希值仅由服务器进行校验,因此对于加密的秘密聊天文件,必须从加密文件中生成)。整个文件成功保存后,可以调用 final 方法并传入生成的inputFile对象。如果使用upload.saveBigFilePart方法,则必须传入inputFileBig构造函数;否则,请使用inputFile。
- messages.sendMedia- 向聊天窗口发送媒体文件
- messages.uploadMedia- 将媒体文件上传到聊天中,但不发送该文件,仅返回一个MessageMedia构造函数,该构造函数可用于稍后将文件发送到多个聊天,而无需每次都重新上传该文件。
- photos.uploadProfilePhoto- 用于设置个人资料或聊天图片或视频
文件保存操作可能会返回以下数据输入错误之一:
- FILE_PARTS_INVALID:文件部分数无效。该值不在 1 到 . 之间upload_max_fileparts_*。
- 文件第 X 部分缺失:文件第 X 部分(X 为数字)在存储中丢失。请尝试重复调用该方法以重新保存该部分。
- MD5_CHECKSUM_INVALID:文件的 MD5 校验和与md5_checksum参数不匹配。
重新发送现有文件
inputMediaPhoto#b3ba0635 flags:# spoiler:flags.1?true id:InputPhoto ttl_seconds:flags.0?int = InputMedia; inputMediaDocument#a8763ab5 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto video_timestamp:flags.4?int ttl_seconds:flags.0?int query:flags.1?string = InputMedia;---functions---messages.sendMedia#ac55d9c1 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates;messages.sendMultiMedia#1bf89d74 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo multi_media:Vector<InputSingleMedia> schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long = Updates;
未受保护的媒体(即没有标记的消息中的媒体)可以重新发送到其他聊天,而无需重新上传:只需将`inputMediaPhoto`构造函数(用于照片)或 `inputMediaDocument`构造函数(用于其他类型的媒体)传递给`messages.sendMedia`或`messages.sendMultiMedia`,即可从现有照片或文档适当生成媒体。noforwards
可以修改inputMediaPhoto和inputMediaDocument中的所有标志,以修改媒体文件的某些属性。
当重新发送现有媒体时,messages.sendMedia可能会返回FILE_REFERENCE_EXPIRED错误(或一个FILE_REFERENCE_INVALID,应以相同方式处理),在这种情况下,必须按照此处的规定刷新file_reference输入位置的字段»。
messages.sendMultiMedia也可能以略有不同的形式返回文件引用错误,作为FILE_REFERENCE_%d_EXPIRED错误(或一个FILE_REFERENCE_%d_INVALID,应以相同的方式处理):在这种情况下,要刷新的文件引用的媒体将位于%d传递的multi_media向量的索引处。
编辑已上传的文件
inputMediaPhoto#b3ba0635 flags:# spoiler:flags.1?true id:InputPhoto ttl_seconds:flags.0?int = InputMedia; inputMediaDocument#a8763ab5 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto video_timestamp:flags.4?int ttl_seconds:flags.0?int query:flags.1?string = InputMedia;inputMediaUploadedPhoto#1e287d04 flags:# spoiler:flags.2?true file:InputFile stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia; inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia;---functions---messages.editMessage#dfd14005 flags:# no_webpage:flags.1?true invert_media:flags.16?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> schedule_date:flags.15?int quick_reply_shortcut_id:flags.17?int = Updates;
使用messages.editMessage编辑或替换使用messages.sendMedia和messages.sendMultiMedia发送的媒体文件。
如果只想编辑媒体的 `<media_photo>`spoiler、 `<media_doc>`ttl_seconds或query`<media_doc>` 属性,则无需重新上传整个媒体文件,只需将旧媒体传递给`inputMediaPhoto`、`inputMediaDocument`id的参数,并根据需要更新 `<media_photo>`、`<media_doc>` 或 `<media_doc>`属性的值即可。spoilerttl_secondsquery
如果要编辑任何其他属性(例如,documentAttributeFilename中指定的文件名、任何其他DocumentAttribute或任何与spoiler/ttl_seconds/query/video_cover/不同的标志video_timestamp),则需要完全重新上传文件,以便能够在inputMediaUploadedPhoto/inputMediaUploadedDocument中指定新属性。
上述规则的唯一例外是编辑视频故事的documentAttributeVideovideo_start_ts属性时,在这种情况下,仍然可以使用inputMediaDocument和inputFileStoryDocument而不是inputFile,而无需重新上传整个故事视频,请参阅此处 »以了解有关完整流程的更多信息。
流媒体上传
API 还支持流式上传,即在开始上传之前不知道文件长度的情况下。
例如,在转换视频时,这非常有用,可以避免将整个转换后的视频缓冲到文件系统中,每个部分在编码器生成后立即上传。
所有操作都与正常上传类似,但也有一些关键区别:
- 客户端会缓冲字节(如果流结束,则缓冲的字节数会更少),然后立即上传上一节中part_size描述的部分。
- 必须使用一个total_stream_size变量来跟踪从数据流中读取的总字节数。
- 即使流的大小小于 10MB,也必须始终使用upload.saveBigFilePart 。
-
除了最后一个部分之外,所有部分的该file_total_parts字段都必须设置为 true-1,逻辑如下:
- 如果视频流结束且缓冲部分的长度大于 0,则上传该视频流,设置file_total_parts=ceil(total_stream_size/part_size)(与普通上传相同)
- 如果流结束且缓冲部分的长度为 0,则仍然上传(上传最后一个空部分),设置file_total_parts=ceil(total_stream_size/part_size)(就像正常上传一样)
请注意,使用inputMediaUploadedPhoto上传照片时不能使用流式上传。
视频质量
messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector<Document> video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia;updateNewScheduledMessage#39a51dfb message:Message = Update; updateDeleteScheduledMessages#f2a71983 flags:# peer:Peer messages:Vector<int> sent_messages:flags.0?Vector<int> = Update;
当向大型频道发送视频时,Telegram 会自动转换视频,生成多种质量和格式的多个版本,这些版本可通过alt_documents发送的消息 MediaDocument向量提供给用户。
请注意,如果video_ignore_alt_documents 客户端配置标志 »设置且等于 true,则客户端必须忽略messageMediaDocument字段。alt_documents
由于服务器端处理需要一些时间,发送到大型频道的视频不会在调用 sendMedia/sendMultiMedia 后立即发送:而是会像定时消息一样添加到调度队列中,调度日期等于服务器端转换的近似日期:
- 调用 sendMedia 后,将立即返回updateNewScheduledMessage ,其中包含一条消息,其 ID 等于当前聊天的计划队列中的消息 ID(每个 PM、聊天、超级群组和频道都有自己的计划队列和 ID 序列),标志video_processing_pending已设置且date等于估计的转换日期(而不是计划日期)。
- 大约在 时date,会发送一个设置了标志的updateNewMessage或updateNewChannelMessagefrom_scheduled,向发送者指示已发送了带有待处理视频的指定消息。
-
大约在某个时刻date,会执行`updateDeleteScheduledMessages`操作,表明消息已从调度队列中清除。
该messages字段将包含已发送消息的调度消息 ID(最初在`updateNewScheduledMessage`中返回),以及sent_messages已发送消息的实际消息 ID。
给定消息的调度消息 ID 和实际消息 ID 将位于同一向量索引处,分别位于 `updateNewScheduledMessages`messages和 `updateNewScheduledMessages`中sent_messages。
换句话说,这些消息应该像计划消息一样处理。
视频封面
inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia; inputMediaDocumentExternal#779600f9 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int video_cover:flags.2?InputPhoto video_timestamp:flags.3?int = InputMedia; inputMediaDocument#a8763ab5 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto video_timestamp:flags.4?int ttl_seconds:flags.0?int query:flags.1?string = InputMedia;messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector<Document> video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia;
可以通过单独提供自定义视频封面,包括在重新发送现有视频时使用inputMediaDocument,通过填充video_cover字段,使用照片(如有必要,可使用messages.uploadMedia上传)。
封面随后将在messageMediaDocumentvideo_cover中 提供。
自毁消息不支持自定义视频封面,私密聊天也暂不支持自定义视频封面。
从时间戳开始播放视频
inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia; inputMediaDocumentExternal#779600f9 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int video_cover:flags.2?InputPhoto video_timestamp:flags.3?int = InputMedia; inputMediaDocument#a8763ab5 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto video_timestamp:flags.4?int ttl_seconds:flags.0?int query:flags.1?string = InputMedia;messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector<Document> video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia;---functions---messages.forwardMessages#978928ca flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true allow_paid_floodskip:flags.19?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer top_msg_id:flags.9?int reply_to:flags.22?InputReplyTo schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut video_timestamp:flags.20?int allow_paid_stars:flags.21?long suggested_post:flags.23?SuggestedPost = Updates; video_timestamp可以通过在上传视频时使用inputMediaUploadedDocument.video_timestamp、重新发送现有视频时使用inputMediaDocument.video_timestamp以及转发视频时使用messages.forwardMessages.来自定义视频开始播放的时间戳video_timestamp。 起始时间戳将在messageMediaDocument中提供。video_timestamp
专辑,分组媒体
inputMediaUploadedPhoto#1e287d04 flags:# spoiler:flags.2?true file:InputFile stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia; inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia;inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector<MessageEntity> = InputSingleMedia;---functions---messages.sendMultiMedia#1bf89d74 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo multi_media:Vector<InputSingleMedia> schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long = Updates;Telegram 允许将照片分组到相册中,并将通用文件(音频、文档)分组到媒体组中。
为此,使用了messages.sendMultiMedia ,将每个InputMedia构造函数(上传的或预先存在的,每个媒体组最多 10 个)包装到inputSingleMedia构造函数中,并可选择在每个文件中提供自定义的标题message。
对于相册,客户应仅在相册组中仅有一张照片带有标题时才显示相册标题,否则不应显示相册标题;并且仅在详细查看相册组中的特定照片时才应显示标题。
其他分组媒体可以为每个文件显示标题。
通过哈希值上传
document#8fd4c4d8 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:long thumbs:flags.0?Vector<PhotoSize> video_thumbs:flags.1?Vector<VideoSize> dc_id:int attributes:Vector<DocumentAttribute> = Document;---functions---messages.getDocumentByHash#b1f2061f sha256:bytes size:long mime_type:string = Document;对于某些类型的文档(例如 GIF),可以使用 `messages.getDocumentByHash`在 Telegram 服务器上搜索文档。该方法会计算文件的 SHA256 哈希值,并将其与文件的 MIME 类型和大小一起传递给它:如果文件类型正确且找到了文件,则会返回该文档。
上传个人资料或聊天图片
photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector<PhotoSize> video_sizes:flags.1?Vector<VideoSize> dc_id:int = Photo;photos.photo#20212ca8 photo:Photo users:Vector<User> = photos.Photo;inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto;inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile;videoSizeEmojiMarkup#f85c413c emoji_id:long background_colors:Vector<int> = VideoSize; videoSizeStickerMarkup#da082fe stickerset:InputStickerSet sticker_id:long background_colors:Vector<int> = VideoSize;inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto; inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto;emojiListNotModified#481eadfa = EmojiList; emojiList#7a1e11d1 hash:long document_id:Vector<long> = EmojiList;---functions---photos.updateProfilePhoto#9e82039 flags:# fallback:flags.0?true bot:flags.1?InputUser id:InputPhoto = photos.Photo; photos.uploadProfilePhoto#388a3b5 flags:# fallback:flags.3?true bot:flags.5?InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.4?VideoSize = photos.Photo;messages.editChatPhoto#35ddd674 chat_id:long photo:InputChatPhoto = Updates;channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates;account.getDefaultProfilePhotoEmojis#e2750328 hash:long = EmojiList; account.getDefaultGroupPhotoEmojis#915860ae hash:long = EmojiList;用户可以使用photos.uploadProfilePhoto方法上传个人资料图片:实际的个人资料图片必须像普通文件一样上传。photos.uploadProfilePhoto也可用于重新上传以前上传过的个人资料图片
。
可选bot标志可以包含我们拥有的机器人的信息,以便更改该机器人的个人资料照片,而不是当前用户的个人资料照片。
动态头像
也支持动态头像,只需填写相应的标志即可:支持最大分辨率为video100 x ...1080x1080800x800
video_start_ts
可以使用messages.editChatPhoto(基本群组)或channels.editPhoto(频道、超级群组)上传聊天、频道和超级群组的
个人资料照片和视频。 使用inputChatPhoto可以重复使用之前上传的个人资料图片。
贴纸头像
也支持贴纸和自定义表情符号贴纸video_emoji_markup的个人资料图片,只需使用videoSizeStickerMarkup或videoSizeEmojiMarkup构造函数填充标志即可。
头像应通过将贴纸放置在正方形画布的中心来渲染,使其占据画布面积的 67% 以内。画布的背景由一个background_colors包含 1、2、3 或 4 种 RGB-24 颜色的向量生成,用于生成纯色 (1)、渐变 (2) 或自由渐变 (3, 4) 背景,类似于填充壁纸的生成方式。渐变背景的旋转角度为 0。
如果使用动画或视频贴纸/自定义表情符号,则video_start_ts标志可以包含一个以秒为单位的浮点 UNIX 时间戳,指示用作静态预览的头像帧。
account.getDefaultProfilePhotoEmojis可用于获取建议的自定义表情符号列表,即使是非高级帐户也可以将其用作个人资料图片;account.getDefaultGroupPhotoEmojis是群组个人资料图片的对应函数。
自定义表情符号选择界面应提供类别列表,以便按表情符号(列表)或其他条件快速筛选结果,详情 请参见此处» 。
下载文件
有多种方法可以下载已成功上传的文件。所使用的文件类型和方法如下所示:
upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector<FileHash> = upload.File;storage.fileUnknown#aa963b05 = storage.FileType; storage.fileJpeg#7efe0e = storage.FileType; storage.fileGif#cae1aadf = storage.FileType; storage.filePng#a4f63c0 = storage.FileType; storage.fileMp3#528a0677 = storage.FileType; storage.fileMov#4b09ebbc = storage.FileType; storage.filePartial#40bc6f52 = storage.FileType; storage.fileMp4#b3cea0e4 = storage.FileType; storage.fileWebp#1081464c = storage.FileType;---functions---upload.getFile#be5335be flags:# precise:flags.0?true cdn_supported:flags.1?true location:InputFileLocation offset:long limit:int = upload.File;任何文件都可以通过调用upload.getFile函数下载。InputFileLocation 类型的输入参数的数据生成方式如下:
-
inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation; inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; inputDocumentFileLocation#bad07584 id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; inputTakeoutFileLocation#29be5899 = InputFileLocation; inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; inputPhotoLegacyFileLocation#d83466f3 id:long access_hash:long file_reference:bytes volume_id:long local_id:int secret:long = InputFileLocation; inputPeerPhotoFileLocation#37257e99 flags:# big:flags.0?true peer:InputPeer photo_id:long = InputFileLocation; inputStickerSetThumb#9d84f3db stickerset:InputStickerSet thumb_version:int = InputFileLocation; inputGroupCallStream#598a92a flags:# call:InputGroupCall time_ms:long scale:int video_channel:flags.0?int video_quality:flags.0?int = InputFileLocation;inputStickerSetEmpty#ffb62b95 = InputStickerSet; inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet; inputStickerSetDice#e67f520e emoticon:string = InputStickerSet; inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet;inputPeerSelf#7da07ec9 = InputPeer; inputPeerChat#35a95cb9 chat_id:long = InputPeer; inputPeerUser#dde8a54c user_id:long access_hash:long = InputPeer; inputPeerChannel#27bcbbfc channel_id:long access_hash:long = InputPeer;photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector<PhotoSize> video_sizes:flags.1?Vector<VideoSize> dc_id:int = Photo; document#8fd4c4d8 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:long thumbs:flags.0?Vector<PhotoSize> video_thumbs:flags.1?Vector<VideoSize> dc_id:int attributes:Vector<DocumentAttribute> = Document;photoSize#75c78e60 type:string w:int h:int size:int = PhotoSize; photoCachedSize#21e1ad6 type:string w:int h:int bytes:bytes = PhotoSize;chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; userProfilePhoto#82d1f706 flags:# has_video:flags.0?true personal:flags.2?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto;
对于照片,使用inputPhotoFileLocation :
- id取自照片构造器file_referenceaccess_hash
- thumb_sizetype从所需照片尺寸/视频尺寸的字段中提取照片
-
对于用户、频道、超级群组和群组的个人资料图片,必须使用inputPeerPhotoFileLocation :
- peer是我们要下载其照片的对等节点的标识符。
- big用于选择下载全分辨率图片还是仅下载缩略图
- photo_id从所需个人资料照片的聊天照片或用户个人资料照片中提取
-
对于文档,使用inputDocumentFileLocation :
- id,file_reference取自access_hash文档构造函数
- 如果要下载文档的缩略图或高级贴纸效果,则应从所需照片尺寸/视频尺寸字段中获取;否则,thumb_size请提供空字符串。type
-
对于贴纸集的预览,使用inputStickerSetThumb(注意:要下载贴纸和贴纸预览,请使用上面描述的文档方法):
- stickerset设置为从stickerSet生成的InputStickerSet构造函数
- thumb_version是从stickerSet中的同一字段复制的。
-
对于加密的秘密聊天和 Telegram 护照文件,必须分别使用inputEncryptedFileLocation和inputSecureFileLocation ,参数从encryptedFile和secureFile(护照文件)中提取。
-
对于直播流片段,使用inputGroupCallStream :
- call包含相关的组调用 ID+访问哈希,取自groupCall构造函数。
- time_ms指定要获取的时间戳
- scale1000通过位移操作,以毫秒为单位指定要获取的视频片段的持续时间scale:duration_ms := 1000 >> scale
- video_channel指定要获取的视频通道
- video_quality指定所选视频质量(0 = 最低,1 = 中等,2 = 最高)
-
对于旧的已弃用照片,如果客户端缓存了一些带有已弃用secret标识符的旧文件位置,则使用inputFileLocation或inputPhotoLegacyFileLocation (这主要是为了向后兼容机器人 API 文件 ID,所有用户客户端都必须使用现代的inputPhotoFileLocation文件 ID):
- file_reference除了、access_hash和之外,所有字段都取自先前缓存的 fileLocation,而id、 和 则取自photo构造函数(最后两个字段仅在可用时使用,在这种情况下,将使用inputPhotoLegacyFileLocation而不是inputFileLocation)。
每个文件的大小(以字节为单位)是已知的,因此可以使用参数offset和limit 分块下载文件,类似于上传文件的方式。
如果未指定精确标志,则
- 参数偏移量必须是 4 KB 的倍数。
- 参数限制必须能被 4 KB 整除。
- 1048576 (1 MB) 必须能被limit整除。
如果指定了精确度,则
- 参数偏移量必须是 1 KB 的倍数。
- 参数限制必须能被 1 KB 整除。
- 限制不得超过 1048576 (1 MB)。
无论如何,请求的部分应该位于文件开头 1 MB 的范围内,即
- offset/ (1024 * 1024) == (offset+limit- 1) / (1024 * 1024)。
当从同一数据中心并行下载多个文件时,客户端应限制并行下载的文件数,当下载的文件小于/大于 20MB 时,最多并行下载small_queue_max_active_operations_count/个文件(客户端配置参数 »)。large_queue_max_active_operations_count
文件下载操作可能会返回upload.fileCdnRedirect构造函数:在这种情况下,必须遵循以下说明来下载 CDN 文件。文件下载操作也可能返回以下数据输入错误之一:
- FILE_REFERENCE_EXPIRED:file_reference输入位置字段必须按照此处指定的方式刷新 »。
- FILE_REFERENCE_INVALID:file_reference输入位置的字段无效,必须按照此处所述进行刷新 »。
- FILE_ID_INVALID:文件地址无效
- OFFSET_INVALID:偏移值无效
- LIMIT_INVALID:限制值无效
- FILE_MIGRATE_X:文件位于 X 号数据中心。
- FLOOD_WAIT_X:X 秒后重复查询
-
FLOOD_PREMIUM_WAIT_X:表示由于当前帐户没有高级订阅,下载速度受到限制,客户端必须在 X 秒后自动重复请求。
收到此错误时,客户端应显示Telegram 高级订阅弹窗,提示用户购买高级订阅以提升下载速度(upload_premium_speedup_download次)。
请注意,此弹窗仅在用户当前可见正在下载的文件时显示;如果用户不可见,则应在正在加载/已加载的文件可见后显示弹窗。此外,此弹窗最多每隔upload_premium_speedup_notify_period
次 显示,以避免每次下载速度变慢时都弹出此弹窗。此错误仅在用户上传数十 GB 或更多文件时才会出现。
正在验证已下载的数据块
fileHash#f39b035c offset:long limit:int hash:bytes = FileHash;---functions---upload.getFileHashes#9156982a location:InputFileLocation offset:long = Vector<FileHash>;为了确认下载文件的完整性,建议客户端验证每个下载部分的哈希值,就像CDN 数据中心一样。upload.getFileHashes方法包含FileHash构造函数。每个构造函数都包含文件某个部分的 SHA-256 哈希值,该部分以指定字节数offset开头limit。
在将从数据中心接收的每个数据部分保存到文件之前,客户端可以确认其哈希值与从主数据中心接收的哈希值是否匹配。如果某个文件部分的哈希值缺失,客户端开发人员必须使用upload.getFileHashes方法获取缺失的哈希值。
处理音频、视频和矢量预览
模式:
photoSizeEmpty#e17e23c type:string = PhotoSize; photoSize#75c78e60 type:string w:int h:int size:int = PhotoSize; photoCachedSize#21e1ad6 type:string w:int h:int bytes:bytes = PhotoSize; photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize; photoSizeProgressive#fa3efb95 type:string w:int h:int sizes:Vector<int> = PhotoSize; photoPathSize#d8214d41 type:string bytes:bytes = PhotoSize;videoSize#de33b094 flags:# type:string w:int h:int size:int video_start_ts:flags.0?double = VideoSize;document#8fd4c4d8 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:long thumbs:flags.0?Vector<PhotoSize> video_thumbs:flags.1?Vector<VideoSize> dc_id:int attributes:Vector<DocumentAttribute> = Document; photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector<PhotoSize> video_sizes:flags.1?Vector<VideoSize> dc_id:int = Photo;photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector<PhotoSize> video_sizes:flags.1?Vector<VideoSize> dc_id:int = Photo;
Telegram 会为所有上传的媒体文件添加一组分辨率降低的缩略图。
服务器还会为视频、GIF 和动态头像生成经过裁剪和缩放的视频预览。
图片缩略图类型
每张照片预览都有一个特定的值type,表示服务器端应用的分辨率和图像变换。
| 类型 | 图像滤镜 | 尺寸 |
|---|---|---|
| s | 盒子 | 100x100 |
| m | 盒子 | 320x320 |
| x | 盒子 | 800x800 |
| y | 盒子 | 1280x1280 |
| w | 盒子 | 2560x2560 |
| a | 庄稼 | 160x160 |
| b | 庄稼 | 320x320 |
| c | 庄稼 | 640x640 |
| d | 庄稼 | 1280x1280 |
特殊类型:
| 类型 | 图像滤镜 |
|---|---|
| i | 条 |
| j | 大纲 |
去除缩略图
photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize;photoStrippedSize(类型为)是一种分辨率极低的缩略图,直接嵌入到媒体位置对象中。它应该在聊天消息预览中显示给用户,或者在通过媒体 DC下载最合适的photoSize时显示,如上所述。i
剥离后的bytes有效载荷应扩展为 JPG 有效载荷,如这里所示 »。
矢量缩略图
photoPathSize#d8214d41 type:string bytes:bytes = PhotoSize;包含动画、视频或静态贴纸的消息可以先使用压缩的 SVG 文件(小于 300 字节)显示贴纸轮廓,然后再加载实际的贴纸文件。贴纸轮廓将显示为photoPathSizej类型的缩略图。
此矢量缩略图由一个SVG 路径构成,该路径经过特殊编码以节省空间。
此路径将作为动画贴纸的轮廓,并在用户下载实际贴纸时显示。
有效载荷应使用以下算法进行膨胀:
encoded := photoPathSize.byteslookup := "AACAAAAHAAALMAAAQASTAVAAAZaacaaaahaaalmaaaqastava.az0123456789-,"path := "M"len := strlen(encoded)for (i = 0; i < len; i++) {num := ord(encoded[i])if (num >= 128 + 64) {path += lookup[num - 128 - 64]} else {if (num >= 128) {path += ','} else if (num >= 64) {path += '-'}path += itoa(num & 63)}}path += "z"path将包含实际的 SVG 路径,可以直接将其插入到svg <path> 元素d的属性中:
<?xml version="1.0" encoding="utf-8"?><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"viewBox="0 0 512 512" xml:space="preserve"><path d="{$path}"/></svg>视频类型
videoSize#de33b094 flags:# type:string w:int h:int size:int video_start_ts:flags.0?double = VideoSize;videoSize构造函数通常用于动画头像、视频预览和高级贴纸效果 »。
| 类型 | 描述 | 格式 |
|---|---|---|
| u | 动态头像 | MPEG4 |
| v | 视频预览 | MPEG4 |
| f | 高级贴纸效果 » | TGS » |
下载网页文件
内联机器人响应内联查询或其他情况发送的远程 HTTP 文件由WebDocument构造函数表示。转发此类远程 HTTP 文件时,应使用外部 InputMedia 构造函数。只有当远程 HTTP 文件包含在webDocumentNoProxy构造函数中时,客户端才能直接下载:在这种情况下,该文件被认为是安全的(来自某些受信任域的 HTTPS 文件即属于这种情况)。
但是,如果远程文件包含在Web 文档中,为了避免泄露敏感信息,必须通过 Telegram 服务器下载该文件。下载方式与下载普通文件类似,区别在于需要使用 `upload.getWebFile`方法。
upload.getWebFile方法还用于生成地图预览图片和下载音乐文件封面,如下所示。
注意:upload.getWebFile查询必须发送到webfile_dc_idMTProto 配置字段中指定的 DC 。
InputWebFileLocation构造函数生成方式如下。
inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation; inputWebFileAudioAlbumThumbLocation#f46fe924 flags:# small:flags.2?true document:flags.0?InputDocument title:flags.1?string performer:flags.1?string = InputWebFileLocation;webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector<DocumentAttribute> = WebDocument;inputGeoPoint#48222faf flags:# lat:double long:double accuracy_radius:flags.0?int = InputGeoPoint;geoPoint#b2a2f663 flags:# long:double lat:double access_hash:long accuracy_radius:flags.0?int = GeoPoint;
- inputWebFileLocation是通过获取webDocumenturl构造函数的andaccess_hash字段生成的。
-
inputWebFileGeoPointLocation用于从geoPoint下载带有地图预览的服务器生成的图像。
- geo_pointlat由geoPointlongaccuracy_radius的参数生成
- access_hash是geoPoint的访问哈希值
- w- 应用缩放前的地图宽度(像素);16-1024
- h- 应用缩放前的地图高度(像素);16-1024
- zoom地图缩放级别:13-20
- scale地图比例尺:1-3
-
`inputWebFileAudioAlbumThumbLocation`用于下载600x600缺少嵌入式专辑封面的音乐文件的专辑封面及其分辨率。请注意,document在私密聊天中,请勿提供包含音乐文件的字段,而应提供本地提取的 `<filename>`title和`<filename>` 字段。在普通聊天中,应始终提供 `<filename>` 而不是 `<filename>`和`<filename>`,因为 `<filename>` 的流量限制更宽松。performer
documenttitleperformer- small如果设置,100x100则下载缩略图。
- document包含音乐文件:绝对禁止在秘密聊天中提供。
- title包含歌曲标题:仅应在秘密聊天中提供。
- performer包含歌曲演唱者信息:仅应在秘密聊天中提供。
一般考虑因素
dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true this_port_only:flags.5?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption;建议使用一个或多个独立的会话和连接来处理大型查询(例如upload.getFile、upload.saveFilePart和upload.getWebFile
),并且在这些会话和连接中不应执行除这些查询之外的任何其他方法。 这样可以减少数据传输对获取更新和其他方法调用的干扰。
如果存在具有所需 DC ID 的媒体 DC(dcOption标志已设置media),则必须将查询发送到该 DC。
相关文章
处理文件引用
如何处理文件引用。