From 81baced12b8d6ee0e69215f3b0357bbd35f84fc1 Mon Sep 17 00:00:00 2001 From: Lonami Exo Date: Fri, 10 Nov 2017 13:27:51 +0100 Subject: [PATCH] Support t.me/ links when resolving usernames/joinchat links Closes #419 --- telethon/telegram_client.py | 23 +++++++++++++++++------ telethon/tl/entity_database.py | 21 ++++++++++++++++++++- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/telethon/telegram_client.py b/telethon/telegram_client.py index a90214b0..b1eec2b2 100644 --- a/telethon/telegram_client.py +++ b/telethon/telegram_client.py @@ -30,8 +30,9 @@ from .tl.functions.contacts import ( ) from .tl.functions.messages import ( GetDialogsRequest, GetHistoryRequest, ReadHistoryRequest, SendMediaRequest, - SendMessageRequest, GetChatsRequest, - GetAllDraftsRequest) + SendMessageRequest, GetChatsRequest, GetAllDraftsRequest, + CheckChatInviteRequest +) from .tl.functions import channels from .tl.functions import messages @@ -49,13 +50,13 @@ from .tl.types import ( Message, MessageMediaContact, MessageMediaDocument, MessageMediaPhoto, InputUserSelf, UserProfilePhoto, ChatPhoto, UpdateMessageID, UpdateNewChannelMessage, UpdateNewMessage, UpdateShortSentMessage, - PeerUser, InputPeerUser, InputPeerChat, InputPeerChannel, MessageEmpty + PeerUser, InputPeerUser, InputPeerChat, InputPeerChannel, MessageEmpty, + ChatInvite, ChatInviteAlready ) from .tl.types.messages import DialogsSlice from .extensions import markdown - class TelegramClient(TelegramBareClient): """Full featured TelegramClient meant to extend the basic functionality - @@ -1053,8 +1054,18 @@ class TelegramClient(TelegramBareClient): entity = phone self(GetContactsRequest(0)) else: - entity = string.strip('@').lower() - self(ResolveUsernameRequest(entity)) + entity, is_join_chat = EntityDatabase.parse_username(string) + if is_join_chat: + invite = self(CheckChatInviteRequest(entity)) + if isinstance(invite, ChatInvite): + # If it's an invite to a chat, the user must join before + # for the link to be resolved and work, otherwise raise. + if invite.channel: + return invite.channel + elif isinstance(invite, ChatInviteAlready): + return invite.chat + else: + self(ResolveUsernameRequest(entity)) # MtProtoSender will call .process_entities on the requests made try: return self.session.entities[entity] diff --git a/telethon/tl/entity_database.py b/telethon/tl/entity_database.py index 2b7e0501..9002ebd8 100644 --- a/telethon/tl/entity_database.py +++ b/telethon/tl/entity_database.py @@ -9,6 +9,11 @@ from ..tl.types import ( from .. import utils # Keep this line the last to maybe fix #357 +USERNAME_RE = re.compile( + r'@|(?:https?://)?(?:telegram\.(?:me|dog)|t\.me)/(joinchat/)?' +) + + class EntityDatabase: def __init__(self, input_list=None, enabled=True, enabled_full=True): """Creates a new entity database with an initial load of "Input" @@ -153,7 +158,8 @@ class EntityDatabase: if phone: return self._phone_id[phone] else: - return self._username_id[key.lstrip('@').lower()] + username, _ = EntityDatabase.parse_username(key) + return self._username_id[username.lower()] except KeyError as e: raise ValueError() from e @@ -206,6 +212,19 @@ class EntityDatabase: if phone.isdigit(): return phone + @staticmethod + def parse_username(username): + """Parses the given username or channel access hash, given + a string, username or URL. Returns a tuple consisting of + both the stripped username and whether it is a joinchat/ hash. + """ + username = username.strip() + m = USERNAME_RE.match(username) + if m: + return username[m.end():], bool(m.group(1)) + else: + return username, False + def get_input_entity(self, peer): try: i = utils.get_peer_id(peer, add_mark=True)