mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-02-09 08:00:53 +03:00
Change the way thumb size selection works
This commit is contained in:
parent
03de901b7f
commit
e2132d5f7c
|
@ -706,3 +706,9 @@ formatting_entities stays because otherwise it's the only feasible way to manual
|
|||
todo update send_message and send_file docs (well review all functions)
|
||||
|
||||
album overhaul. use a list of Message instead.
|
||||
|
||||
size selector for download_profile_photo and download_media is now different
|
||||
|
||||
still thumb because otherwise documents are weird.
|
||||
|
||||
keep support for explicit size instance?
|
||||
|
|
|
@ -7,7 +7,7 @@ import inspect
|
|||
import asyncio
|
||||
|
||||
from .._crypto import AES
|
||||
from .._misc import utils, helpers, requestiter, tlobject, hints
|
||||
from .._misc import utils, helpers, requestiter, tlobject, hints, enums
|
||||
from .. import errors, _tl
|
||||
|
||||
try:
|
||||
|
@ -180,7 +180,7 @@ async def download_profile_photo(
|
|||
entity: 'hints.EntityLike',
|
||||
file: 'hints.FileLike' = None,
|
||||
*,
|
||||
download_big: bool = True) -> typing.Optional[str]:
|
||||
thumb) -> typing.Optional[str]:
|
||||
# hex(crc32(x.encode('ascii'))) for x in
|
||||
# ('User', 'Chat', 'UserFull', 'ChatFull')
|
||||
ENTITIES = (0x2da17977, 0xc5af5d94, 0x1f4661b9, 0xd49a2697)
|
||||
|
@ -189,8 +189,6 @@ async def download_profile_photo(
|
|||
if not isinstance(entity, tlobject.TLObject) or entity.SUBCLASS_OF_ID in INPUTS:
|
||||
entity = await self.get_entity(entity)
|
||||
|
||||
thumb = -1 if download_big else 0
|
||||
|
||||
possible_names = []
|
||||
if entity.SUBCLASS_OF_ID not in ENTITIES:
|
||||
photo = entity
|
||||
|
@ -212,11 +210,13 @@ async def download_profile_photo(
|
|||
photo = entity.photo
|
||||
|
||||
if isinstance(photo, (_tl.UserProfilePhoto, _tl.ChatPhoto)):
|
||||
thumb = enums.Size.ORIGINAL if thumb == () else enums.parse_photo_size(thumb)
|
||||
|
||||
dc_id = photo.dc_id
|
||||
loc = _tl.InputPeerPhotoFileLocation(
|
||||
peer=await self.get_input_entity(entity),
|
||||
photo_id=photo.photo_id,
|
||||
big=download_big
|
||||
big=thumb >= enums.Size.LARGE
|
||||
)
|
||||
else:
|
||||
# It doesn't make any sense to check if `photo` can be used
|
||||
|
@ -259,7 +259,7 @@ async def download_media(
|
|||
message: 'hints.MessageLike',
|
||||
file: 'hints.FileLike' = None,
|
||||
*,
|
||||
thumb: 'typing.Union[int, _tl.TypePhotoSize]' = None,
|
||||
size = (),
|
||||
progress_callback: 'hints.ProgressCallback' = None) -> typing.Optional[typing.Union[str, bytes]]:
|
||||
# Downloading large documents may be slow enough to require a new file reference
|
||||
# to be obtained mid-download. Store (input chat, message id) so that the message
|
||||
|
@ -292,11 +292,11 @@ async def download_media(
|
|||
return await _download_document(
|
||||
self, media, file, date, thumb, progress_callback, msg_data
|
||||
)
|
||||
elif isinstance(media, _tl.MessageMediaContact) and thumb is None:
|
||||
elif isinstance(media, _tl.MessageMediaContact):
|
||||
return _download_contact(
|
||||
self, media, file
|
||||
)
|
||||
elif isinstance(media, (_tl.WebDocument, _tl.WebDocumentNoProxy)) and thumb is None:
|
||||
elif isinstance(media, (_tl.WebDocument, _tl.WebDocumentNoProxy)):
|
||||
return await _download_web_document(
|
||||
self, media, file, progress_callback
|
||||
)
|
||||
|
@ -491,44 +491,15 @@ def _iter_download(
|
|||
|
||||
|
||||
def _get_thumb(thumbs, thumb):
|
||||
# Seems Telegram has changed the order and put `PhotoStrippedSize`
|
||||
# last while this is the smallest (layer 116). Ensure we have the
|
||||
# sizes sorted correctly with a custom function.
|
||||
def sort_thumbs(thumb):
|
||||
if isinstance(thumb, _tl.PhotoStrippedSize):
|
||||
return 1, len(thumb.bytes)
|
||||
if isinstance(thumb, _tl.PhotoCachedSize):
|
||||
return 1, len(thumb.bytes)
|
||||
if isinstance(thumb, _tl.PhotoSize):
|
||||
return 1, thumb.size
|
||||
if isinstance(thumb, _tl.PhotoSizeProgressive):
|
||||
return 1, max(thumb.sizes)
|
||||
if isinstance(thumb, _tl.VideoSize):
|
||||
return 2, thumb.size
|
||||
|
||||
# Empty size or invalid should go last
|
||||
return 0, 0
|
||||
|
||||
thumbs = list(sorted(thumbs, key=sort_thumbs))
|
||||
|
||||
for i in reversed(range(len(thumbs))):
|
||||
# :tl:`PhotoPathSize` is used for animated stickers preview, and the thumb is actually
|
||||
# a SVG path of the outline. Users expect thumbnails to be JPEG files, so pretend this
|
||||
# thumb size doesn't actually exist (#1655).
|
||||
if isinstance(thumbs[i], _tl.PhotoPathSize):
|
||||
thumbs.pop(i)
|
||||
|
||||
if thumb is None:
|
||||
return thumbs[-1]
|
||||
elif isinstance(thumb, int):
|
||||
return thumbs[thumb]
|
||||
elif isinstance(thumb, str):
|
||||
return next((t for t in thumbs if t.type == thumb), None)
|
||||
elif isinstance(thumb, (_tl.PhotoSize, _tl.PhotoCachedSize,
|
||||
_tl.PhotoStrippedSize, _tl.VideoSize)):
|
||||
if isinstance(thumb, tlobject.TLObject):
|
||||
return thumb
|
||||
else:
|
||||
return None
|
||||
|
||||
thumb = enums.parse_photo_size(thumb)
|
||||
return min(
|
||||
thumbs,
|
||||
default=None,
|
||||
key=lambda t: abs(thumb - enums.parse_photo_size(t.type))
|
||||
)
|
||||
|
||||
def _download_cached_photo_size(self: 'TelegramClient', size, file):
|
||||
# No need to download anything, simply write the bytes
|
||||
|
@ -623,7 +594,7 @@ async def _download_document(
|
|||
if not isinstance(document, _tl.Document):
|
||||
return
|
||||
|
||||
if thumb is None:
|
||||
if thumb == ():
|
||||
kind, possible_names = _get_kind_and_names(document.attributes)
|
||||
file = _get_proper_filename(
|
||||
file, kind, utils.get_extension(document),
|
||||
|
|
|
@ -1610,7 +1610,7 @@ class TelegramClient:
|
|||
entity: 'hints.EntityLike',
|
||||
file: 'hints.FileLike' = None,
|
||||
*,
|
||||
download_big: bool = True) -> typing.Optional[str]:
|
||||
thumb: typing.Union[str, enums.Size] = ()) -> typing.Optional[str]:
|
||||
"""
|
||||
Downloads the profile photo from the given user, chat or channel.
|
||||
|
||||
|
@ -1634,8 +1634,15 @@ class TelegramClient:
|
|||
If file is the type `bytes`, it will be downloaded in-memory
|
||||
as a bytestring (e.g. ``file=bytes``).
|
||||
|
||||
download_big (`bool`, optional):
|
||||
Whether to use the big version of the available photos.
|
||||
thumb (optional):
|
||||
The thumbnail size to download. A different size may be chosen
|
||||
if the specified size doesn't exist. The category of the size
|
||||
you choose will be respected when possible (e.g. if you
|
||||
specify a cropped size, a cropped variant of similar size will
|
||||
be preferred over a boxed variant of similar size). Cropped
|
||||
images are considered to be smaller than boxed images.
|
||||
|
||||
By default, the largest size (original) is downloaded.
|
||||
|
||||
Returns
|
||||
`None` if no photo was provided, or if it was Empty. On success
|
||||
|
@ -1655,7 +1662,7 @@ class TelegramClient:
|
|||
message: 'hints.MessageLike',
|
||||
file: 'hints.FileLike' = None,
|
||||
*,
|
||||
thumb: 'typing.Union[int, _tl.TypePhotoSize]' = None,
|
||||
thumb: typing.Union[str, enums.Size] = (),
|
||||
progress_callback: 'hints.ProgressCallback' = None) -> typing.Optional[typing.Union[str, bytes]]:
|
||||
"""
|
||||
Downloads the given media from a message object.
|
||||
|
@ -1680,29 +1687,15 @@ class TelegramClient:
|
|||
A callback function accepting two parameters:
|
||||
``(received bytes, total)``.
|
||||
|
||||
thumb (`int` | :tl:`PhotoSize`, optional):
|
||||
Which thumbnail size from the document or photo to download,
|
||||
instead of downloading the document or photo itself.
|
||||
thumb (optional):
|
||||
The thumbnail size to download. A different size may be chosen
|
||||
if the specified size doesn't exist. The category of the size
|
||||
you choose will be respected when possible (e.g. if you
|
||||
specify a cropped size, a cropped variant of similar size will
|
||||
be preferred over a boxed variant of similar size). Cropped
|
||||
images are considered to be smaller than boxed images.
|
||||
|
||||
If it's specified but the file does not have a thumbnail,
|
||||
this method will return `None`.
|
||||
|
||||
The parameter should be an integer index between ``0`` and
|
||||
``len(sizes)``. ``0`` will download the smallest thumbnail,
|
||||
and ``len(sizes) - 1`` will download the largest thumbnail.
|
||||
You can also use negative indices, which work the same as
|
||||
they do in Python's `list`.
|
||||
|
||||
You can also pass the :tl:`PhotoSize` instance to use.
|
||||
Alternatively, the thumb size type `str` may be used.
|
||||
|
||||
In short, use ``thumb=0`` if you want the smallest thumbnail
|
||||
and ``thumb=-1`` if you want the largest thumbnail.
|
||||
|
||||
.. note::
|
||||
The largest thumbnail may be a video instead of a photo,
|
||||
as they are available since layer 116 and are bigger than
|
||||
any of the photos.
|
||||
By default, the original media is downloaded.
|
||||
|
||||
Returns
|
||||
`None` if no media was provided, or if it was Empty. On success
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
from enum import Enum
|
||||
|
||||
|
||||
def _impl_op(which):
|
||||
def op(self, other):
|
||||
if not isinstance(other, type(self)):
|
||||
return NotImplemented
|
||||
|
||||
return getattr(self._val(), which)(other._val())
|
||||
|
||||
return op
|
||||
|
||||
|
||||
class ConnectionMode(Enum):
|
||||
FULL = 'full'
|
||||
INTERMEDIATE = 'intermediate'
|
||||
|
@ -38,6 +48,91 @@ class Action(Enum):
|
|||
CANCEL = 'cancel'
|
||||
|
||||
|
||||
class Size(Enum):
|
||||
"""
|
||||
See https://core.telegram.org/api/files#image-thumbnail-types.
|
||||
|
||||
* ``'s'``. The image fits within a box of 100x100.
|
||||
* ``'m'``. The image fits within a box of 320x320.
|
||||
* ``'x'``. The image fits within a box of 800x800.
|
||||
* ``'y'``. The image fits within a box of 1280x1280.
|
||||
* ``'w'``. The image fits within a box of 2560x2560.
|
||||
* ``'a'``. The image was cropped to be at most 160x160.
|
||||
* ``'b'``. The image was cropped to be at most 320x320.
|
||||
* ``'c'``. The image was cropped to be at most 640x640.
|
||||
* ``'d'``. The image was cropped to be at most 1280x1280.
|
||||
* ``'i'``. The image comes inline (no need to download anything).
|
||||
* ``'j'``. Only the image outline is present (for stickers).
|
||||
* ``'u'``. The image is actually a short MPEG4 animated video.
|
||||
* ``'v'``. The image is actually a short MPEG4 video preview.
|
||||
|
||||
The sorting order is first dimensions, then ``cropped < boxed < video < other``.
|
||||
"""
|
||||
SMALL = 's'
|
||||
MEDIUM = 'm'
|
||||
LARGE = 'x'
|
||||
EXTRA_LARGE = 'y'
|
||||
ORIGINAL = 'w'
|
||||
CROPPED_SMALL = 'a'
|
||||
CROPPED_MEDIUM = 'b'
|
||||
CROPPED_LARGE = 'c'
|
||||
CROPPED_EXTRA_LARGE = 'd'
|
||||
INLINE = 'i'
|
||||
OUTLINE = 'j'
|
||||
ANIMATED = 'u'
|
||||
VIDEO = 'v'
|
||||
|
||||
def __hash__(self):
|
||||
return object.__hash__(self)
|
||||
|
||||
__sub__ = _impl_op('__sub__')
|
||||
__lt__ = _impl_op('__lt__')
|
||||
__le__ = _impl_op('__le__')
|
||||
__eq__ = _impl_op('__eq__')
|
||||
__ne__ = _impl_op('__ne__')
|
||||
__gt__ = _impl_op('__gt__')
|
||||
__ge__ = _impl_op('__ge__')
|
||||
|
||||
def _val(self):
|
||||
return self._category() * 100 + self._size()
|
||||
|
||||
def _category(self):
|
||||
return {
|
||||
Size.SMALL: 2,
|
||||
Size.MEDIUM: 2,
|
||||
Size.LARGE: 2,
|
||||
Size.EXTRA_LARGE: 2,
|
||||
Size.ORIGINAL: 2,
|
||||
Size.CROPPED_SMALL: 1,
|
||||
Size.CROPPED_MEDIUM: 1,
|
||||
Size.CROPPED_LARGE: 1,
|
||||
Size.CROPPED_EXTRA_LARGE: 1,
|
||||
Size.INLINE: 4,
|
||||
Size.OUTLINE: 5,
|
||||
Size.ANIMATED: 3,
|
||||
Size.VIDEO: 3,
|
||||
}[self]
|
||||
|
||||
def _size(self):
|
||||
return {
|
||||
Size.SMALL: 1,
|
||||
Size.MEDIUM: 3,
|
||||
Size.LARGE: 5,
|
||||
Size.EXTRA_LARGE: 6,
|
||||
Size.ORIGINAL: 7,
|
||||
Size.CROPPED_SMALL: 2,
|
||||
Size.CROPPED_MEDIUM: 3,
|
||||
Size.CROPPED_LARGE: 4,
|
||||
Size.CROPPED_EXTRA_LARGE: 6,
|
||||
# 0, since they're not the original photo at all
|
||||
Size.INLINE: 0,
|
||||
Size.OUTLINE: 0,
|
||||
# same size as original or extra large (videos are large)
|
||||
Size.ANIMATED: 7,
|
||||
Size.VIDEO: 6,
|
||||
}[self]
|
||||
|
||||
|
||||
def _mk_parser(cls):
|
||||
def parser(value):
|
||||
if isinstance(value, cls):
|
||||
|
@ -57,3 +152,4 @@ def _mk_parser(cls):
|
|||
parse_conn_mode = _mk_parser(ConnectionMode)
|
||||
parse_participant = _mk_parser(Participant)
|
||||
parse_typing_action = _mk_parser(Action)
|
||||
parse_photo_size = _mk_parser(Size)
|
||||
|
|
|
@ -2,4 +2,5 @@ from ._misc.enums import (
|
|||
ConnectionMode,
|
||||
Participant,
|
||||
Action,
|
||||
Size,
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue
Block a user