Create a new Message.file property (#1168)

This commit is contained in:
Lonami Exo 2019-05-08 18:41:40 +02:00
parent cfd6d3ce04
commit 10251f9782
5 changed files with 193 additions and 0 deletions

View File

@ -216,6 +216,7 @@ Properties
forward
buttons
button_count
file
photo
document
web_preview
@ -255,6 +256,31 @@ Methods
get_buttons
File
====
The `File <telethon.tl.custom.file.File>` type is a wrapper object
returned by `Message.file <telethon.tl.custom.message.Message.file>`,
and you can use it to easily access a document's attributes, such as
its name, bot-API style file ID, etc.
.. currentmodule:: telethon.tl.custom.file.File
.. autosummary::
:nosignatures:
id
name
width
height
size
duration
title
performer
emoji
sticker_set
Conversation
============

View File

@ -18,6 +18,14 @@ telethon\.tl\.custom\.dialog module
:undoc-members:
:show-inheritance:
telethon\.tl\.custom\.file module
---------------------------------
.. automodule:: telethon.tl.custom.file
:members:
:undoc-members:
:show-inheritance:
telethon\.tl\.custom\.message module
------------------------------------

128
telethon/tl/custom/file.py Normal file
View File

@ -0,0 +1,128 @@
import mimetypes
from ... import utils
from ...tl import types
class File:
"""
Convenience class over media like photos or documents, which
supports accessing the attributes in a more convenient way.
If any of the attributes are not present in the current media,
the properties will be ``None``.
The original media is available through the ``media`` attribute.
"""
def __init__(self, media):
self.media = media
@property
def id(self):
"""
The bot-API style ``file_id`` representing this file.
"""
return utils.pack_bot_file_id(self.media)
@property
def name(self):
"""
The file name of this document.
"""
return self._from_attr(types.DocumentAttributeFilename, 'file_name')
@property
def ext(self):
"""
The extension from the mime type of this file.
"""
return mimetypes.guess_extension(self.mime_type)
@property
def mime_type(self):
"""
The mime-type of this file.
"""
if isinstance(self.media, types.Photo):
return 'image/jpeg'
elif isinstance(self.media, types.Document):
return self.media.mime_type
@property
def width(self):
"""
The width in pixels of this media if it's a photo or a video.
"""
return self._from_attr((
types.DocumentAttributeImageSize, types.DocumentAttributeVideo), 'w')
@property
def height(self):
"""
The height in pixels of this media if it's a photo or a video.
"""
return self._from_attr((
types.DocumentAttributeImageSize, types.DocumentAttributeVideo), 'h')
@property
def duration(self):
"""
The duration in seconds of the audio or video.
"""
return self._from_attr((
types.DocumentAttributeAudio, types.DocumentAttributeVideo), 'duration')
@property
def title(self):
"""
The title of the song.
"""
return self._from_attr(types.DocumentAttributeAudio, 'title')
@property
def performer(self):
"""
The performer of the song.
"""
return self._from_attr(types.DocumentAttributeAudio, 'performer')
@property
def emoji(self):
"""
A string with all emoji that represent the current sticker.
"""
return self._from_attr(types.DocumentAttributeSticker, 'alt')
@property
def sticker_set(self):
"""
The :tl:`InputStickerSet` to which the sticker file belongs.
"""
return self._from_attr(types.DocumentAttributeSticker, 'stickerset')
@property
def size(self):
"""
The size in bytes of this file.
"""
if isinstance(self.media, types.Photo):
return self._size_for(self.media.sizes[-1])
elif isinstance(self.media, types.Document):
return self.media.size
@staticmethod
def _size_for(kind):
if isinstance(kind, types.PhotoSize):
return kind.size
elif isinstance(kind, types.PhotoStrippedSize):
return utils._stripped_real_length(kind.bytes)
elif isinstance(kind, types.PhotoCachedSize):
return len(kind.bytes)
# elif isinstance(kind, types.PhotoSizeEmpty):
return 0
def _from_attr(self, cls, field):
if isinstance(self.media, types.Document):
for attr in self.media.attributes:
if isinstance(attr, cls):
return getattr(attr, field, None)

View File

@ -3,9 +3,11 @@ from .chatgetter import ChatGetter
from .sendergetter import SenderGetter
from .messagebutton import MessageButton
from .forward import Forward
from .file import File
from .. import TLObject, types, functions
from ... import utils, errors
# TODO Figure out a way to have the code generator error on missing fields
# Maybe parsing the init function alone if that's possible.
class Message(ChatGetter, SenderGetter, TLObject, abc.ABC):
@ -174,8 +176,10 @@ class Message(ChatGetter, SenderGetter, TLObject, abc.ABC):
self.action = action
# Convenient storage for custom functions
# TODO This is becoming a bit of bloat
self._client = None
self._text = None
self._file = None
self._reply_message = None
self._buttons = None
self._buttons_flat = None
@ -370,6 +374,25 @@ class Message(ChatGetter, SenderGetter, TLObject, abc.ABC):
return self._buttons_count
@property
def file(self):
"""
Returns a `File <telethon.tl.custom.file.File>` wrapping the
`photo` or `document` in this message. If the media type is different
(polls, games, none, etc.), this property will be ``None``.
This instance lets you easily access other properties, such as
`file.id <telethon.tl.custom.file.File.id>`,
`file.name <telethon.tl.custom.file.File.name>`,
etc., without having to manually inspect the ``document.attributes``.
"""
if not self._file:
media = self.photo or self.document
if media:
self._file = File(media)
return self._file
@property
def photo(self):
"""

View File

@ -1162,6 +1162,7 @@ def stripped_photo_to_jpg(stripped):
Ported from https://github.com/telegramdesktop/tdesktop/blob/bec39d89e19670eb436dc794a8f20b657cb87c71/Telegram/SourceFiles/ui/image/image.cpp#L225
"""
# NOTE: Changes here should update _stripped_real_length
if len(stripped) < 3 or stripped[0] != 1:
return stripped
@ -1170,3 +1171,10 @@ def stripped_photo_to_jpg(stripped):
header[164] = stripped[1]
header[166] = stripped[2]
return bytes(header) + stripped[3:] + footer
def _stripped_real_length(stripped):
if len(stripped) < 3 or stripped[0] != 1:
return len(stripped)
return len(stripped) + 622