2017-06-09 17:13:39 +03:00
|
|
|
"""
|
|
|
|
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)
|
|
|
|
"""
|
2016-11-13 16:51:50 +03:00
|
|
|
from mimetypes import add_type, guess_extension
|
2016-10-09 13:57:38 +03:00
|
|
|
|
2017-08-30 12:12:25 +03:00
|
|
|
from .tl import TLObject
|
2017-06-09 17:13:39 +03:00
|
|
|
from .tl.types import (
|
2017-06-15 18:03:59 +03:00
|
|
|
Channel, ChannelForbidden, Chat, ChatEmpty, ChatForbidden, ChatFull,
|
2017-07-10 17:09:20 +03:00
|
|
|
ChatPhoto, InputPeerChannel, InputPeerChat, InputPeerUser, InputPeerEmpty,
|
2017-07-07 10:48:06 +03:00
|
|
|
MessageMediaDocument, MessageMediaPhoto, PeerChannel, InputChannel,
|
2017-07-10 17:09:20 +03:00
|
|
|
UserEmpty, InputUser, InputUserEmpty, InputUserSelf, InputPeerSelf,
|
2017-08-24 18:44:38 +03:00
|
|
|
PeerChat, PeerUser, User, UserFull, UserProfilePhoto, Document
|
|
|
|
)
|
2016-10-09 13:57:38 +03:00
|
|
|
|
|
|
|
|
|
|
|
def get_display_name(entity):
|
|
|
|
"""Gets the input peer for the given "entity" (user, chat or channel)
|
|
|
|
Returns None if it was not found"""
|
|
|
|
if isinstance(entity, User):
|
2017-06-16 10:11:49 +03:00
|
|
|
if entity.last_name and entity.first_name:
|
2016-10-09 13:57:38 +03:00
|
|
|
return '{} {}'.format(entity.first_name, entity.last_name)
|
2017-06-16 10:11:49 +03:00
|
|
|
elif entity.first_name:
|
|
|
|
return entity.first_name
|
|
|
|
elif entity.last_name:
|
|
|
|
return entity.last_name
|
|
|
|
else:
|
|
|
|
return '(No name)'
|
2016-10-09 13:57:38 +03:00
|
|
|
|
|
|
|
if isinstance(entity, Chat) or isinstance(entity, Channel):
|
|
|
|
return entity.title
|
|
|
|
|
2017-05-23 10:45:48 +03:00
|
|
|
return '(unknown)'
|
|
|
|
|
2016-11-13 16:51:50 +03:00
|
|
|
# For some reason, .webp (stickers' format) is not registered
|
|
|
|
add_type('image/webp', '.webp')
|
|
|
|
|
2016-10-09 13:57:38 +03:00
|
|
|
|
|
|
|
def get_extension(media):
|
|
|
|
"""Gets the corresponding extension for any Telegram media"""
|
|
|
|
|
|
|
|
# Photos are always compressed as .jpg by Telegram
|
2016-11-30 00:29:42 +03:00
|
|
|
if (isinstance(media, UserProfilePhoto) or isinstance(media, ChatPhoto) or
|
2016-10-09 13:57:38 +03:00
|
|
|
isinstance(media, MessageMediaPhoto)):
|
|
|
|
return '.jpg'
|
|
|
|
|
2017-08-24 18:44:38 +03:00
|
|
|
# Documents will come with a mime type
|
2016-10-09 13:57:38 +03:00
|
|
|
if isinstance(media, MessageMediaDocument):
|
2017-08-24 18:44:38 +03:00
|
|
|
if isinstance(media.document, Document):
|
|
|
|
if media.document.mime_type == 'application/octet-stream':
|
|
|
|
# Octet stream are just bytes, which have no default extension
|
|
|
|
return ''
|
|
|
|
else:
|
|
|
|
extension = guess_extension(media.document.mime_type)
|
|
|
|
return extension if extension else ''
|
|
|
|
|
|
|
|
return ''
|
2016-10-09 13:57:38 +03:00
|
|
|
|
|
|
|
|
2017-08-30 12:12:25 +03:00
|
|
|
def _raise_cast_fail(entity, target):
|
|
|
|
raise ValueError('Cannot cast {} to any kind of {}.'
|
|
|
|
.format(type(entity).__name__, target))
|
|
|
|
|
|
|
|
|
2016-10-09 13:57:38 +03:00
|
|
|
def get_input_peer(entity):
|
|
|
|
"""Gets the input peer for the given "entity" (user, chat or channel).
|
2017-06-03 14:36:41 +03:00
|
|
|
A ValueError is raised if the given entity isn't a supported type."""
|
2017-08-30 12:12:25 +03:00
|
|
|
if entity is None:
|
|
|
|
return None
|
|
|
|
|
|
|
|
if not isinstance(entity, TLObject):
|
|
|
|
_raise_cast_fail(entity, 'InputPeer')
|
|
|
|
|
2017-07-07 10:48:06 +03:00
|
|
|
if type(entity).subclass_of_id == 0xc91c90b6: # crc32(b'InputPeer')
|
2017-01-17 22:22:47 +03:00
|
|
|
return entity
|
|
|
|
|
2016-10-09 13:57:38 +03:00
|
|
|
if isinstance(entity, User):
|
2017-07-10 17:09:20 +03:00
|
|
|
if entity.is_self:
|
|
|
|
return InputPeerSelf()
|
|
|
|
else:
|
|
|
|
return InputPeerUser(entity.id, entity.access_hash)
|
2017-06-15 18:03:59 +03:00
|
|
|
|
|
|
|
if any(isinstance(entity, c) for c in (
|
|
|
|
Chat, ChatEmpty, ChatForbidden)):
|
2016-10-09 13:57:38 +03:00
|
|
|
return InputPeerChat(entity.id)
|
2017-06-15 18:03:59 +03:00
|
|
|
|
|
|
|
if any(isinstance(entity, c) for c in (
|
|
|
|
Channel, ChannelForbidden)):
|
2016-10-09 13:57:38 +03:00
|
|
|
return InputPeerChannel(entity.id, entity.access_hash)
|
|
|
|
|
2017-06-15 18:03:59 +03:00
|
|
|
# Less common cases
|
2017-07-10 17:09:20 +03:00
|
|
|
if isinstance(entity, UserEmpty):
|
|
|
|
return InputPeerEmpty()
|
|
|
|
|
|
|
|
if isinstance(entity, InputUser):
|
|
|
|
return InputPeerUser(entity.user_id, entity.access_hash)
|
|
|
|
|
2017-06-15 18:03:59 +03:00
|
|
|
if isinstance(entity, UserFull):
|
2017-07-10 17:09:20 +03:00
|
|
|
return get_input_peer(entity.user)
|
2017-06-15 18:03:59 +03:00
|
|
|
|
|
|
|
if isinstance(entity, ChatFull):
|
|
|
|
return InputPeerChat(entity.id)
|
|
|
|
|
2017-07-04 22:18:35 +03:00
|
|
|
if isinstance(entity, PeerChat):
|
|
|
|
return InputPeerChat(entity.chat_id)
|
|
|
|
|
2017-08-30 12:12:25 +03:00
|
|
|
_raise_cast_fail(entity, 'InputPeer')
|
2017-05-23 10:45:48 +03:00
|
|
|
|
2016-10-09 13:57:38 +03:00
|
|
|
|
2017-07-07 10:48:06 +03:00
|
|
|
def get_input_channel(entity):
|
2017-07-10 17:04:10 +03:00
|
|
|
"""Similar to get_input_peer, but for InputChannel's alone"""
|
2017-08-30 12:12:25 +03:00
|
|
|
if entity is None:
|
|
|
|
return None
|
|
|
|
|
|
|
|
if not isinstance(entity, TLObject):
|
|
|
|
_raise_cast_fail(entity, 'InputChannel')
|
|
|
|
|
2017-07-07 10:48:06 +03:00
|
|
|
if type(entity).subclass_of_id == 0x40f202fd: # crc32(b'InputChannel')
|
|
|
|
return entity
|
|
|
|
|
|
|
|
if isinstance(entity, Channel) or isinstance(entity, ChannelForbidden):
|
|
|
|
return InputChannel(entity.id, entity.access_hash)
|
|
|
|
|
2017-08-05 10:37:34 +03:00
|
|
|
if isinstance(entity, InputPeerChannel):
|
|
|
|
return InputChannel(entity.channel_id, entity.access_hash)
|
|
|
|
|
2017-08-30 12:12:25 +03:00
|
|
|
_raise_cast_fail(entity, 'InputChannel')
|
2017-07-07 10:48:06 +03:00
|
|
|
|
|
|
|
|
2017-07-10 17:04:10 +03:00
|
|
|
def get_input_user(entity):
|
|
|
|
"""Similar to get_input_peer, but for InputUser's alone"""
|
2017-08-30 12:12:25 +03:00
|
|
|
if entity is None:
|
|
|
|
return None
|
|
|
|
|
|
|
|
if not isinstance(entity, TLObject):
|
|
|
|
_raise_cast_fail(entity, 'InputUser')
|
|
|
|
|
2017-07-10 17:04:10 +03:00
|
|
|
if type(entity).subclass_of_id == 0xe669bf46: # crc32(b'InputUser')
|
|
|
|
return entity
|
|
|
|
|
|
|
|
if isinstance(entity, User):
|
|
|
|
if entity.is_self:
|
|
|
|
return InputUserSelf()
|
|
|
|
else:
|
|
|
|
return InputUser(entity.id, entity.access_hash)
|
|
|
|
|
|
|
|
if isinstance(entity, UserEmpty):
|
|
|
|
return InputUserEmpty()
|
|
|
|
|
|
|
|
if isinstance(entity, UserFull):
|
|
|
|
return get_input_user(entity.user)
|
|
|
|
|
2017-07-10 17:09:20 +03:00
|
|
|
if isinstance(entity, InputPeerUser):
|
|
|
|
return InputUser(entity.user_id, entity.access_hash)
|
|
|
|
|
2017-08-30 12:12:25 +03:00
|
|
|
_raise_cast_fail(entity, 'InputUser')
|
2017-07-10 17:04:10 +03:00
|
|
|
|
|
|
|
|
2016-10-09 13:57:38 +03:00
|
|
|
def find_user_or_chat(peer, users, chats):
|
|
|
|
"""Finds the corresponding user or chat given a peer.
|
|
|
|
Returns None if it was not found"""
|
|
|
|
try:
|
|
|
|
if isinstance(peer, PeerUser):
|
2017-06-14 15:06:35 +03:00
|
|
|
return next(u for u in users if u.id == peer.user_id)
|
2016-10-09 13:57:38 +03:00
|
|
|
|
|
|
|
elif isinstance(peer, PeerChat):
|
2017-06-14 15:06:35 +03:00
|
|
|
return next(c for c in chats if c.id == peer.chat_id)
|
2016-10-09 13:57:38 +03:00
|
|
|
|
|
|
|
elif isinstance(peer, PeerChannel):
|
2017-06-14 15:06:35 +03:00
|
|
|
return next(c for c in chats if c.id == peer.channel_id)
|
2016-10-09 13:57:38 +03:00
|
|
|
|
2017-06-14 15:06:35 +03:00
|
|
|
except StopIteration: return
|
|
|
|
|
|
|
|
if isinstance(peer, int):
|
|
|
|
try: return next(u for u in users if u.id == peer)
|
|
|
|
except StopIteration: pass
|
|
|
|
|
|
|
|
try: return next(c for c in chats if c.id == peer)
|
|
|
|
except StopIteration: pass
|
2016-10-09 13:57:38 +03:00
|
|
|
|
|
|
|
|
2017-05-21 14:59:16 +03:00
|
|
|
def get_appropriated_part_size(file_size):
|
|
|
|
"""Gets the appropriated part size when uploading or downloading files,
|
2016-10-09 13:57:38 +03:00
|
|
|
given an initial file size"""
|
|
|
|
if file_size <= 1048576: # 1MB
|
|
|
|
return 32
|
|
|
|
if file_size <= 10485760: # 10MB
|
|
|
|
return 64
|
|
|
|
if file_size <= 393216000: # 375MB
|
|
|
|
return 128
|
|
|
|
if file_size <= 786432000: # 750MB
|
|
|
|
return 256
|
|
|
|
if file_size <= 1572864000: # 1500MB
|
|
|
|
return 512
|
|
|
|
|
|
|
|
raise ValueError('File size too large')
|