diff --git a/telethon/utils.py b/telethon/utils.py index 586812b9..ee123b32 100644 --- a/telethon/utils.py +++ b/telethon/utils.py @@ -2,11 +2,14 @@ Utilities for working with the Telegram API itself (such as handy methods to convert between an entity like an User, Chat, etc. into its Input version) """ +import base64 +import binascii import itertools import math import mimetypes import os import re +import struct from collections import UserList from mimetypes import guess_extension from types import GeneratorType @@ -733,6 +736,102 @@ def resolve_id(marked_id): return -marked_id, types.PeerChat +def _rle_decode(data): + """ + Decodes run-length-encoded `data`. + """ + new = b'' + last = b'' + for cur in data: + cur = bytes([cur]) + if last == b'\0': + new += last * ord(cur) + last = b'' + else: + new += last + last = cur + + return new + last + + +def resolve_bot_file_id(file_id): + """ + Given a Bot API-style `file_id`, returns the media it represents. + If the `file_id` is not valid, ``None`` is returned instead. + + Note that the `file_id` does not have information such as image + dimensions or file size, so these will be zero if present. + + For thumbnails, the photo ID and hash will always be zero. + """ + try: + data = file_id.encode('ascii') + except (UnicodeEncodeError, AttributeError): + return None + + data.replace(b'-', b'+').replace(b'_', b'/') + b'=' * (len(data) % 4) + try: + data = base64.b64decode(data) + except binascii.Error: + return None + + data = _rle_decode(data) + if data[-1] == b'\x02': + return None + + data = data[:-1] + if len(data) == 24: + file_type, dc_id, media_id, access_hash = struct.unpack('