From 02b8f1d0077872a67b7f462b6861800c0318fc29 Mon Sep 17 00:00:00 2001 From: Daniil Date: Sat, 29 Aug 2020 12:41:50 +0300 Subject: [PATCH 1/5] Document STICKER_DOCUMENT_INVALID error (#1537) --- telethon_generator/data/errors.csv | 1 + telethon_generator/data/methods.csv | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/telethon_generator/data/errors.csv b/telethon_generator/data/errors.csv index e2b73b5d..d129bd91 100644 --- a/telethon_generator/data/errors.csv +++ b/telethon_generator/data/errors.csv @@ -271,6 +271,7 @@ START_PARAM_INVALID,400,Start parameter invalid STATS_MIGRATE_X,303,The channel statistics must be fetched from DC {dc} STICKERSET_INVALID,400,The provided sticker set is invalid STICKERS_EMPTY,400,No sticker provided +STICKER_DOCUMENT_INVALID,400,"The sticker file was invalid (make sure to use the correct format, animated stickers may not be allowed in this request)" STICKER_EMOJI_INVALID,400,Sticker emoji invalid STICKER_FILE_INVALID,400,Sticker file invalid STICKER_ID_INVALID,400,The provided sticker ID is invalid diff --git a/telethon_generator/data/methods.csv b/telethon_generator/data/methods.csv index 83317861..d9a1ce0d 100644 --- a/telethon_generator/data/methods.csv +++ b/telethon_generator/data/methods.csv @@ -282,7 +282,7 @@ messages.setBotPrecheckoutResults,both,ERROR_TEXT_EMPTY messages.setBotShippingResults,both,QUERY_ID_INVALID messages.setEncryptedTyping,user,CHAT_ID_INVALID messages.setGameScore,bot,PEER_ID_INVALID USER_BOT_REQUIRED -messages.setInlineBotResults,bot,ARTICLE_TITLE_EMPTY BUTTON_DATA_INVALID BUTTON_TYPE_INVALID BUTTON_URL_INVALID MESSAGE_EMPTY PHOTO_CONTENT_URL_EMPTY PHOTO_THUMB_URL_EMPTY QUERY_ID_INVALID REPLY_MARKUP_INVALID RESULT_TYPE_INVALID SEND_MESSAGE_MEDIA_INVALID SEND_MESSAGE_TYPE_INVALID START_PARAM_INVALID USER_BOT_INVALID WEBDOCUMENT_URL_INVALID +messages.setInlineBotResults,bot,ARTICLE_TITLE_EMPTY BUTTON_DATA_INVALID BUTTON_TYPE_INVALID BUTTON_URL_INVALID MESSAGE_EMPTY PHOTO_CONTENT_URL_EMPTY PHOTO_THUMB_URL_EMPTY QUERY_ID_INVALID REPLY_MARKUP_INVALID RESULT_TYPE_INVALID SEND_MESSAGE_MEDIA_INVALID SEND_MESSAGE_TYPE_INVALID START_PARAM_INVALID STICKER_DOCUMENT_INVALID USER_BOT_INVALID WEBDOCUMENT_URL_INVALID messages.setInlineGameScore,bot,MESSAGE_ID_INVALID USER_BOT_REQUIRED messages.setTyping,both,CHANNEL_INVALID CHANNEL_PRIVATE CHAT_ID_INVALID CHAT_WRITE_FORBIDDEN PEER_ID_INVALID USER_BANNED_IN_CHANNEL USER_IS_BLOCKED USER_IS_BOT messages.startBot,user,BOT_INVALID PEER_ID_INVALID START_PARAM_EMPTY START_PARAM_INVALID From 1ed0f75c4948aacbcd3235912da2a01e1ec4e276 Mon Sep 17 00:00:00 2001 From: Allerter <45076212+Allerter@users.noreply.github.com> Date: Tue, 8 Sep 2020 02:50:37 +0430 Subject: [PATCH 2/5] Support extracting metadata from bytes and stream objects (#1547) This should enable more accurate uploads of in-memory files. --- telethon/utils.py | 82 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 15 deletions(-) diff --git a/telethon/utils.py b/telethon/utils.py index f74ef880..86a8661e 100644 --- a/telethon/utils.py +++ b/telethon/utils.py @@ -601,16 +601,52 @@ def get_message_id(message): def _get_metadata(file): - # `hachoir` only deals with paths to in-disk files, while - # `_get_extension` supports a few other things. The parser - # may also fail in any case and we don't want to crash if + if not hachoir: + return + + stream = None + close_stream = True + seekable = True + + # The parser may fail and we don't want to crash if # the extraction process fails. - if hachoir and isinstance(file, str) and os.path.isfile(file): - try: - with hachoir.parser.createParser(file) as parser: - return hachoir.metadata.extractMetadata(parser) - except Exception as e: - _log.warning('Failed to analyze %s: %s %s', file, e.__class__, e) + try: + # Note: aiofiles are intentionally left out for simplicity + if isinstance(file, str): + stream = open(file, 'rb') + elif isinstance(file, bytes): + stream = io.BytesIO(file) + else: + stream = file + close_stream = False + if getattr(file, 'seekable', None): + seekable = file.seekable() + else: + seekable = False + + if not seekable: + return None + + pos = stream.tell() + filename = getattr(file, 'name', '') + + parser = hachoir.parser.guess.guessParser(hachoir.stream.InputIOStream( + stream, + source='file:' + filename, + tags=[], + filename=filename + )) + + return hachoir.metadata.extractMetadata(parser) + + except Exception as e: + _log.warning('Failed to analyze %s: %s %s', file, e.__class__, e) + + finally: + if stream and close_stream: + stream.close() + elif stream and seekable: + stream.seek(pos) def get_attributes(file, *, attributes=None, mime_type=None, @@ -803,15 +839,31 @@ def is_gif(file): def is_audio(file): - """Returns `True` if the file extension looks like an audio file.""" - file = 'a' + _get_extension(file) - return (mimetypes.guess_type(file)[0] or '').startswith('audio/') + """Returns `True` if the file has an audio mime type.""" + ext = _get_extension(file) + if not ext: + metadata = _get_metadata(file) + if metadata and metadata.has('mime_type'): + return metadata.get('mime_type').startswith('audio/') + else: + return False + else: + file = 'a' + ext + return (mimetypes.guess_type(file)[0] or '').startswith('audio/') def is_video(file): - """Returns `True` if the file extension looks like a video file.""" - file = 'a' + _get_extension(file) - return (mimetypes.guess_type(file)[0] or '').startswith('video/') + """Returns `True` if the file has a video mime type.""" + ext = _get_extension(file) + if not ext: + metadata = _get_metadata(file) + if metadata and metadata.has('mime_type'): + return metadata.get('mime_type').startswith('video/') + else: + return False + else: + file = 'a' + ext + return (mimetypes.guess_type(file)[0] or '').startswith('video/') def is_list_like(obj): From 8cbaacabdb8cf10d9a8d1eabd1e88972c049c804 Mon Sep 17 00:00:00 2001 From: daaawx Date: Thu, 10 Sep 2020 14:51:31 +0200 Subject: [PATCH 3/5] Add missing word in docs (#1538) --- readthedocs/concepts/strings.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readthedocs/concepts/strings.rst b/readthedocs/concepts/strings.rst index dee48c80..a696b684 100644 --- a/readthedocs/concepts/strings.rst +++ b/readthedocs/concepts/strings.rst @@ -3,7 +3,7 @@ String-based Debugging ====================== Debugging is *really* important. Telegram's API is really big and there -is a lot of things that you should know. Such as, what attributes or fields +are a lot of things that you should know. Such as, what attributes or fields does a result have? Well, the easiest thing to do is printing it: .. code-block:: python @@ -32,7 +32,7 @@ Can we get better than the shown string, though? Yes! print(entity.stringify()) -Will show a much better: +Will show a much better representation: .. code-block:: python From 1afb5b95e3b3820baaa4ebefaaa721b962ca25d8 Mon Sep 17 00:00:00 2001 From: Tanya Degurechaff <34323200+TanyaEleventhGoddess@users.noreply.github.com> Date: Thu, 10 Sep 2020 12:52:25 +0000 Subject: [PATCH 4/5] Update init params to match those of tdesktop (#1549) --- telethon/client/telegrambaseclient.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/telethon/client/telegrambaseclient.py b/telethon/client/telegrambaseclient.py index 62faecae..ce80211b 100644 --- a/telethon/client/telegrambaseclient.py +++ b/telethon/client/telegrambaseclient.py @@ -1,4 +1,5 @@ import abc +import re import asyncio import collections import logging @@ -161,11 +162,11 @@ class TelegramBaseClient(abc.ABC): device_model (`str`, optional): "Device model" to be sent when creating the initial connection. - Defaults to ``platform.node()``. + Defaults to 'PC (n)bit' derived from ``platform.uname().machine``, or its direct value if unknown. system_version (`str`, optional): "System version" to be sent when creating the initial connection. - Defaults to ``platform.system()``. + Defaults to ``platform.uname().release`` stripped of everything ahead of -. app_version (`str`, optional): "App version" to be sent when creating the initial connection. @@ -320,11 +321,19 @@ class TelegramBaseClient(abc.ABC): # Used on connection. Capture the variables in a lambda since # exporting clients need to create this InvokeWithLayerRequest. system = platform.uname() + + if system.machine in ('x86_64', 'AMD64'): + default_device_model = 'PC 64bit' + elif system.machine in ('i386','i686','x86'): + default_device_model = 'PC 32bit' + else: + default_device_model = system.machine + default_system_version = re.sub(r'-.+','',system.release) self._init_with = lambda x: functions.InvokeWithLayerRequest( LAYER, functions.InitConnectionRequest( api_id=self.api_id, - device_model=device_model or system.system or 'Unknown', - system_version=system_version or system.release or '1.0', + device_model=device_model or default_device_model or 'Unknown', + system_version=system_version or default_system_version or '1.0', app_version=app_version or self.__version__, lang_code=lang_code, system_lang_code=system_lang_code, From 2a114917f10fa5f3356e4e797fdc6b354ea36c9c Mon Sep 17 00:00:00 2001 From: apepenkov <39992738+apepenkov@users.noreply.github.com> Date: Thu, 10 Sep 2020 17:25:44 +0300 Subject: [PATCH 5/5] Fix AlbumHack in combination with events.Raw (#1555) --- telethon/client/updates.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/telethon/client/updates.py b/telethon/client/updates.py index e609f9ab..de051454 100644 --- a/telethon/client/updates.py +++ b/telethon/client/updates.py @@ -467,6 +467,8 @@ class UpdateMethods: # the name of speed; we don't want to make it worse for all updates # just because albums may need it. for builder, callback in self._event_builders: + if isinstance(builder, events.Raw): + continue if not isinstance(event, builder.Event): continue