文件上传和下载

在使用电报 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即可。

以下appConfig 字段指定可上传文件部分的最大数量:

请注意,可上传文件部分的限制并未考虑part_size :因此,只有当part_size达到最大值 512KB 时,才能达到总文件大小的限制,而这实际上是为避免过多的协议开销而推荐的part_size 。

每个部分都应该有一个序列号file_part,其值范围从 0 到相应配置参数的值减 1。

文件分割完成后,您需要选择一种将其保存到服务器的方法。如果文件总大小超过10 MB,请使用upload.saveBigFilePart;对于较小的文件,请使用upload.saveFilePart 。

每次调用都会将一部分数据保存到服务器上的临时位置,以供后续使用。每部分数据的存储期限从几分钟到几小时不等(取决于存储区域的繁忙程度)。超过此期限后,该文件部分将无法访问。

为了提高文件保存操作的效率,我们建议使用本地调用队列(即不使用 invokeAfterMsgs 方法),这样在任何给定时刻都会保存文件的 X 个片段。每次成功保存一个片段后,都会调用方法来保存下一个片段。可以调整 X 的值以达到最佳性能。

为了进一步提高性能,可以使用多个并行调用队列(即可调数量的 Y 个队列)连接到数据中心的独立 TCP 连接,以并行上传多个数据块。

使用上述方法之一保存文件片段时,可能会返回以下数据输入错误之一:

在上传文件各部分的同时,可以计算文件内容的MD5 哈希值,以便稍后将其用作inputFile构造函数中的md5_checksum参数(由于该哈希值仅由服务器进行校验,因此对于加密的秘密聊天文件,必须从加密文件中生成)。整个文件成功保存后,可以调用 final 方法并传入生成的inputFile对象。如果使用upload.saveBigFilePart方法,则必须传入inputFileBig构造函数;否则,请使用inputFile。

文件保存操作可能会返回以下数据输入错误之一:

重新发送现有文件

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 还支持流式上传,即在开始上传之前不知道文件长度的情况下。

例如,在转换视频时,这非常有用,可以避免将整个转换后的视频缓冲到文件系统中,每个部分在编码器生成后立即上传。

所有操作都与正常上传类似,但也有一些关键区别:

请注意,使用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 后立即发送:而是会像定时消息一样添加到调度队列中,调度日期等于服务器端转换的近似日期:

换句话说,这些消息应该像计划消息一样处理。

视频封面

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 类型的输入参数的数据生成方式如下:


每个文件的大小(以字节为单位)是已知的,因此可以使用参数offset和limit 分块下载文件,类似于上传文件的方式。

如果未指定精确标志,则

如果指定了精确度,则

无论如何,请求的部分应该位于文件开头 1 MB 的范围内,即

当从同一数据中心并行下载多个文件时,客户端应限制并行下载的文件数,当下载的文件小于/大于 20MB 时,最多并行下载small_queue_max_active_operations_count/个文件(客户端配置参数 »)。large_queue_max_active_operations_count

文件下载操作可能会返回upload.fileCdnRedirect构造函数:在这种情况下,必须遵循以下说明来下载 CDN 文件。文件下载操作也可能返回以下数据输入错误之一:

正在验证已下载的数据块

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;


一般考虑因素


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。


相关文章

处理文件引用

如何处理文件引用。