This commit is contained in:
Hackintosh 5 2021-12-13 09:19:19 +00:00
parent 8de375323e
commit 1d4bd39307
8 changed files with 121 additions and 48 deletions

View File

@ -8,6 +8,7 @@ import asyncio
from .._crypto import AES from .._crypto import AES
from .._misc import utils, helpers, requestiter, tlobject, hints from .._misc import utils, helpers, requestiter, tlobject, hints
from ..types._custom import Message
from .. import errors, _tl from .. import errors, _tl
try: try:
@ -267,7 +268,8 @@ async def download_media(
msg_data = None msg_data = None
# TODO This won't work for messageService # TODO This won't work for messageService
if isinstance(message, _tl.Message): # TODO Handle _tl.Message
if isinstance(message, Message):
date = message.date date = message.date
media = message.media media = message.media
msg_data = (message.input_chat, message.id) if message.input_chat else None msg_data = (message.input_chat, message.id) if message.input_chat else None

View File

@ -489,7 +489,7 @@ async def send_message(
request = _tl.fn.messages.SendMessage( request = _tl.fn.messages.SendMessage(
peer=entity, peer=entity,
message=message._text, message=message._text,
entities=formatting_entities, entities=message._fmt_entities,
no_webpage=not link_preview, no_webpage=not link_preview,
reply_to_msg_id=utils.get_message_id(reply_to), reply_to_msg_id=utils.get_message_id(reply_to),
clear_draft=clear_draft, clear_draft=clear_draft,
@ -508,7 +508,7 @@ async def send_message(
date=result.date, date=result.date,
out=result.out, out=result.out,
media=result.media, media=result.media,
entities=result.entities, entities=result._fmt_entities,
reply_markup=request.reply_markup, reply_markup=request.reply_markup,
ttl_period=result.ttl_period ttl_period=result.ttl_period
), {}, entity) ), {}, entity)
@ -579,35 +579,88 @@ async def forward_messages(
async def edit_message( async def edit_message(
self: 'TelegramClient', self: 'TelegramClient',
entity: 'typing.Union[hints.EntityLike, _tl.Message]', entity: 'typing.Union[hints.EntityLike, _tl.Message]',
message: 'hints.MessageLike' = None, message_id: 'hints.MessageLike' = None,
text: str = None, text: str = None,
*, *,
parse_mode: str = (), # - Message contents
attributes: 'typing.Sequence[_tl.TypeDocumentAttribute]' = None, # Formatting
formatting_entities: typing.Optional[typing.List[_tl.TypeMessageEntity]] = None, markdown: str = None,
link_preview: bool = True, html: str = None,
file: 'hints.FileLike' = None, formatting_entities: list = None,
thumb: 'hints.FileLike' = None, link_preview: bool = (),
force_document: bool = False, # Media
buttons: 'hints.MarkupLike' = None, file: typing.Optional[hints.FileLike] = None,
file_name: str = None,
mime_type: str = None,
thumb: str = False,
force_file: bool = False,
file_size: int = None,
# Media attributes
duration: int = None,
width: int = None,
height: int = None,
title: str = None,
performer: str = None,
supports_streaming: bool = False, supports_streaming: bool = False,
schedule: 'hints.DateLike' = None video_note: bool = False,
voice_note: bool = False,
waveform: bytes = None,
# Additional parametrization
buttons: list = None,
ttl: int = None,
# - Send options
schedule: 'hints.DateLike' = None,
) -> '_tl.Message': ) -> '_tl.Message':
if formatting_entities is None: if isinstance(text, str) or text is None:
text, formatting_entities = await self._parse_message_text(text, parse_mode) message = InputMessage(
file_handle, media, image = await self._file_to_media(file, text=text,
supports_streaming=supports_streaming, markdown=markdown,
html=html,
formatting_entities=formatting_entities,
link_preview=link_preview,
file=file,
file_name=file_name,
mime_type=mime_type,
thumb=thumb, thumb=thumb,
attributes=attributes, force_file=force_file,
force_document=force_document) file_size=file_size,
duration=duration,
width=width,
height=height,
title=title,
performer=performer,
supports_streaming=supports_streaming,
video_note=video_note,
voice_note=voice_note,
waveform=waveform,
silent=False,
buttons=buttons,
ttl=ttl,
)
elif isinstance(text, _custom.Message):
# TODO accept this as the first and only parameter
message = message._as_input()
elif not isinstance(text, InputMessage):
raise TypeError(f'text must be either str, Message or InputMessage, but got: {text!r}')
if message._file:
# TODO Properly implement allow_cache to reuse the sha256 of the file
# i.e. `None` was used
# TODO album
if message._file._should_upload_thumb():
message._file._set_uploaded_thumb(await self.upload_file(message._file._thumb))
if message._file._should_upload_file():
message._file._set_uploaded_file(await self.upload_file(message._file._file))
if isinstance(message, _tl.InputBotInlineMessageID): if isinstance(message, _tl.InputBotInlineMessageID):
request = _tl.fn.messages.EditInlineBotMessage( request = _tl.fn.messages.EditInlineBotMessage(
id=message, id=message_id,
message=text, message=message._text,
no_webpage=not link_preview, no_webpage=not link_preview,
entities=formatting_entities, entities=message._fmt_entities,
media=media, media=message._file._media,
reply_markup=_custom.button.build_reply_markup(buttons) reply_markup=_custom.button.build_reply_markup(buttons)
) )
# Invoke `messages.editInlineBotMessage` from the right datacenter. # Invoke `messages.editInlineBotMessage` from the right datacenter.
@ -622,17 +675,13 @@ async def edit_message(
else: else:
return await self(request) return await self(request)
entity = await self.get_input_entity(entity) message_id = utils.get_message_id(message_id)
request = _tl.fn.messages.EditMessage( request = _tl.fn.messages.EditMessage(
peer=entity, entity, message_id, no_webpage=not link_preview, message=message._text,
id=utils.get_message_id(message), media=message._file._media if message._file else None, reply_markup=message._reply_markup, entities=message._fmt_entities, schedule_date=schedule
message=text,
no_webpage=not link_preview,
entities=formatting_entities,
media=media,
reply_markup=_custom.button.build_reply_markup(buttons),
schedule_date=schedule
) )
msg = self._get_response_message(request, await self(request), entity) msg = self._get_response_message(request, await self(request), entity)
return msg return msg

View File

@ -7,7 +7,7 @@ import typing
from ..errors._custom import MultiError from ..errors._custom import MultiError
from ..errors._rpcbase import RpcError, ServerError, FloodError, InvalidDcError, UnauthorizedError from ..errors._rpcbase import RpcError, ServerError, FloodError, InvalidDcError, UnauthorizedError
from .._misc import helpers, utils, hints from .._misc import helpers, utils, hints
from .._sessions.types import Entity from .._sessions.types import Entity, get_peer_canonical_entity_type
from .. import errors, _tl from .. import errors, _tl
_NOT_A_REQUEST = lambda: TypeError('You can only invoke requests, not types!') _NOT_A_REQUEST = lambda: TypeError('You can only invoke requests, not types!')
@ -235,8 +235,10 @@ async def get_input_entity(
# Next in priority is having a peer (or its ID) cached in-memory # Next in priority is having a peer (or its ID) cached in-memory
try: try:
# 0x2d45687 == crc32(b'Peer') # 0x2d45687 == crc32(b'Peer')
if isinstance(peer, int) or peer.SUBCLASS_OF_ID == 0x2d45687: # TODO: FIXME: This logic is incorrect - Peers are unhashable and the cache should be sorted by Entity.ty
return self._entity_cache[peer] # if isinstance(peer, int) or peer.SUBCLASS_OF_ID == 0x2d45687:
# return self._entity_cache[peer]
pass
except (AttributeError, KeyError): except (AttributeError, KeyError):
pass pass
@ -250,13 +252,14 @@ async def get_input_entity(
except TypeError: except TypeError:
pass pass
else: else:
entity = await self.session.get_entity(None, peer_id) entity_type = get_peer_canonical_entity_type(peer)
entity = await self.session.get_entity(entity_type, peer_id)
if entity: if entity:
if entity.ty in (Entity.USER, Entity.BOT): if entity_type == Entity.USER:
return _tl.InputPeerUser(entity.id, entity.access_hash) return _tl.InputPeerUser(entity.id, entity.access_hash)
elif entity.ty in (Entity.GROUP): elif entity_type == Entity.GROUP:
return _tl.InputPeerChat(peer.chat_id) return _tl.InputPeerChat(peer.chat_id)
elif entity.ty in (Entity.CHANNEL, Entity.MEGAGROUP, Entity.GIGAGROUP): elif entity_type == Entity.CHANNEL:
return _tl.InputPeerChannel(entity.id, entity.access_hash) return _tl.InputPeerChannel(entity.id, entity.access_hash)
# Only network left to try # Only network left to try

View File

@ -7,14 +7,12 @@ from ..types import _custom
Phone = str Phone = str
Username = str Username = str
PeerID = int
Entity = typing.Union[_tl.User, _tl.Chat, _tl.Channel] Entity = typing.Union[_tl.User, _tl.Chat, _tl.Channel]
FullEntity = typing.Union[_tl.UserFull, _tl.messages.ChatFull, _tl.ChatFull, _tl.ChannelFull] FullEntity = typing.Union[_tl.UserFull, _tl.messages.ChatFull, _tl.ChatFull, _tl.ChannelFull]
EntityLike = typing.Union[ EntityLike = typing.Union[
Phone, Phone,
Username, Username,
PeerID,
_tl.TypePeer, _tl.TypePeer,
_tl.TypeInputPeer, _tl.TypeInputPeer,
Entity, Entity,

View File

@ -1,4 +1,4 @@
from .types import DataCenter, ChannelState, SessionState, Entity from .types import DataCenter, ChannelState, SessionState, Entity, get_entity_type_group
from .abstract import Session from .abstract import Session
from .._misc import utils, tlobject from .._misc import utils, tlobject
from .. import _tl from .. import _tl
@ -34,11 +34,11 @@ class MemorySession(Session):
return list(self.channel_states.values()) return list(self.channel_states.values())
async def insert_entities(self, entities: List[Entity]): async def insert_entities(self, entities: List[Entity]):
self.entities.update((e.id, (e.ty, e.access_hash)) for e in entities) self.entities.update(((get_peer_canonical_entity_type(e.ty), e.id), e.access_hash) for e in entities)
async def get_entity(self, ty: Optional[int], id: int) -> Optional[Entity]: async def get_entity(self, ty: int, id: int) -> Optional[Entity]:
try: try:
ty, access_hash = self.entities[id] access_hash = self.entities[get_peer_canonical_entity_type(ty), id]
return Entity(ty, id, access_hash) return Entity(ty, id, access_hash)
except KeyError: except KeyError:
return None return None

View File

@ -1,4 +1,6 @@
from typing import Optional, Tuple from typing import Optional, Tuple, Union
from .. import _tl
from .._misc import hints, utils
class DataCenter: class DataCenter:
@ -155,3 +157,21 @@ def get_entity_type_group(ty: int, *, _mapping={
except KeyError: except KeyError:
ty = chr(ty) if isinstance(ty, int) else ty ty = chr(ty) if isinstance(ty, int) else ty
raise ValueError(f'entity type {ty!r} is not valid') raise ValueError(f'entity type {ty!r} is not valid')
def get_peer_canonical_entity_type(peer: Union[
_tl.TypePeer,
_tl.TypeInputPeer,
hints.Entity,
hints.FullEntity,
], *, _mapping={
_tl.PeerUser: Entity.USER,
_tl.PeerChat: Entity.GROUP,
_tl.PeerChannel: Entity.CHANNEL,
}) -> int:
peer = utils.get_peer(peer)
try:
return _mapping[type(peer)]
except KeyError:
# Safe to log full peer since only contains the ID
raise ValueError(f'Unexpected peer {peer!r}')

View File

@ -90,8 +90,9 @@ class InputFile:
elif isinstance(thumb, (_tl.InputFile, _tl.InputFileBig)): elif isinstance(thumb, (_tl.InputFile, _tl.InputFileBig)):
self._uploaded_thumb = (thumb, time.time()) self._uploaded_thumb = (thumb, time.time())
else: elif thumb:
raise TypeError(f'thumb must be a file to upload, but got: {thumb!r}') raise TypeError(f'thumb must be a file to upload, but got: {thumb!r}')
# else: it's falsey, ignore it
# document parameters (only if it's our file, i.e. there's no media ready yet) # document parameters (only if it's our file, i.e. there's no media ready yet)
if self._media: if self._media:

View File

@ -160,7 +160,7 @@ class Message(ChatGetter, SenderGetter):
except AttributeError: except AttributeError:
return None return None
return None if media.CONSTRUCTOR_ID == 0x3ded6320 else media return None if media is None or media.CONSTRUCTOR_ID == 0x3ded6320 else media
@media.setter @media.setter
def media(self, value): def media(self, value):