mirror of
				https://github.com/LonamiWebs/Telethon.git
				synced 2025-10-30 23:47:33 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			297 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			297 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
| .. _entities:
 | |
| 
 | |
| ===============
 | |
| Users and Chats
 | |
| ===============
 | |
| 
 | |
| The library widely uses the concept of "users" to refer to both real accounts
 | |
| and bot accounts, as well as the concept of "chats" to refer to groups and
 | |
| broadcast channels.
 | |
| 
 | |
| The most general term you can use to think about these is "an entity", but
 | |
| recent versions of the library often prefer to opt for names which better
 | |
| reflect the intention, such as "dialog" when a previously-existing
 | |
| conversation is expected, or "profile" when referring to the information about
 | |
| the user or chat.
 | |
| 
 | |
| .. note::
 | |
| 
 | |
|     When something "dialog-like" is required, it means that you need to
 | |
|     provide something that can be used to refer to an open conversation.
 | |
|     These things include, but are not limited to, packed chats, usernames,
 | |
|     integer IDs (identifiers), :tl:`Peer` objects, or even entire :tl:`User`,
 | |
|     :tl:`Chat` and :tl:`Channel` objects and even phone numbers **from people
 | |
|     you have in your contact list**.
 | |
| 
 | |
|     To "encounter" an ID, you would have to "find it" like you would in the
 | |
|     normal app. If the peer is in your dialogs, you would need to
 | |
|     `client.get_dialogs() <telethon.client.dialogs.DialogMethods.get_dialogs>`.
 | |
|     If the peer is someone in a group, you would similarly
 | |
|     `client.get_participants(group) <telethon.client.chats.ChatMethods.get_participants>`.
 | |
| 
 | |
|     Once you have encountered an ID, the library will (by default) have saved
 | |
|     its packed version for you, which is needed to invoke most methods.
 | |
|     This is why sometimes you might encounter this error when working with
 | |
|     the library. You should ``except ValueError`` and run code that you know
 | |
|     should work to find the user or chat. You **cannot** use an ID of someone
 | |
|     you haven't interacted with. Because this is more unreliable, packed chats
 | |
|     are recommended instead.
 | |
| 
 | |
| 
 | |
| .. contents::
 | |
| 
 | |
| 
 | |
| What is a User?
 | |
| ===============
 | |
| 
 | |
| A `User <telethon.types._custom.user.User>` can be either a real user account
 | |
| (some person who has signed up for an account) or a bot account which is
 | |
| programmed to perform certain actions (created by a developer via
 | |
| `@BotFather <https://t.me/BotFather>`_).
 | |
| 
 | |
| A lot of methods and requests require user or chats to work. For example,
 | |
| you can send a message to a *user*, ban a *user* from a group, and so on.
 | |
| These methods accept more than just `User <telethon.types._custom.user.User>`
 | |
| as the input parameter. You can also use packed users, usernames, string phone
 | |
| numbers, or integer IDs, although some have higher cost than others.
 | |
| 
 | |
| When using the username, the library must fetch it first, which can be
 | |
| expensive. When using the phone number, the library must fetch it first, which
 | |
| can be expensive. If you plan to use these, it's recommended you manually use
 | |
| `client.get_profile() <telethon.client.users.UserMethods.get_profile>` to cache
 | |
| the username or phone number, and then use the value returned instead.
 | |
| 
 | |
| .. note::
 | |
| 
 | |
|     Remember that the phone number must be in your contact list before you
 | |
|     can use it.
 | |
| 
 | |
| The recommended type to use as input parameters to the methods is either a
 | |
| `User <telethon.types._custom.user.User>` instance or its packed type.
 | |
| 
 | |
| In the raw API, users are instances of :tl:`User` (or :tl:`UserEmpty`), which
 | |
| are returned in response to some requests, such as :tl:`GetUsersRequest`.
 | |
| There are also variants for use as "input parameters", such as :tl:`InputUser`
 | |
| and :tl:`InputPeerUser`. You generally **do not need** to worry about these
 | |
| types unless you're using raw API.
 | |
| 
 | |
| 
 | |
| What is a Chat?
 | |
| ===============
 | |
| 
 | |
| A `Chat <telethon.types._custom.chat.Chat>` can be a small group chat (the
 | |
| default group type created by users where many users can join and talk), a
 | |
| megagroup (also known as "supergroup"), a broadcast channel or a broadcast
 | |
| group.
 | |
| 
 | |
| The term "chat" is really overloaded in Telegram. The library tries to be
 | |
| explicit and always use "small group chat", "megagroup" and "broadcast" to
 | |
| differentiate. However, Telegram's API uses "chat" to refer to both "chat"
 | |
| (small group chat), and "channel" (megagroup, broadcast or "gigagroup" which
 | |
| is a broadcast group of type channel).
 | |
| 
 | |
| A lot of methods and requests require a chat to work. For example,
 | |
| you can get the participants from a *chat*, kick users from a *chat*, and so on.
 | |
| These methods accept more than just `Chat <telethon.types._custom.chat.Chat>`
 | |
| as the input parameter. You can also use packed chats, the public link, or
 | |
| integer IDs, although some have higher cost than others.
 | |
| 
 | |
| When using the public link, the library must fetch it first, which can be
 | |
| expensive. If you plan to use these, it's recommended you manually use
 | |
| `client.get_profile() <telethon.client.users.UserMethods.get_profile>` to cache
 | |
| the link, and then use the value returned instead.
 | |
| 
 | |
| .. note::
 | |
| 
 | |
|     The link of a public chat has the form "t.me/username", where the username
 | |
|     can belong to either an actual user or a public chat.
 | |
| 
 | |
| The recommended type to use as input parameters to the methods is either a
 | |
| `Chat <telethon.types._custom.chat.Chat>` instance or its packed type.
 | |
| 
 | |
| In the raw API, chats are instances of :tl:`Chat` and :tl:`Channel` (or
 | |
| :tl:`ChatEmpty`, :tl:`ChatForbidden` and :tl:`ChannelForbidden`), which
 | |
| are returned in response to some requests, such as :tl:`messages.GetChats`
 | |
| and :tl:`channels.GetChannels`. There are also variants for use as "input
 | |
| parameters", such as :tl:`InputChannel` and :tl:`InputPeerChannel`. You
 | |
| generally **do not need** to worry about these types unless you're using raw API.
 | |
| 
 | |
| 
 | |
| When to use each term?
 | |
| ======================
 | |
| 
 | |
| The term "dialog" is used when the library expects a reference to an open
 | |
| conversation (from the list the user sees when they open the application).
 | |
| 
 | |
| The term "profile" is used instead of "dialog" when the conversation is not
 | |
| expected to exist. Because "dialog" is more specific than "profile", "dialog"
 | |
| is used where possible instead.
 | |
| 
 | |
| In general, you should not use named arguments for neither "dialogs" or
 | |
| "profiles", since they're the first argument. The parameter name only exists
 | |
| for documentation purposes.
 | |
| 
 | |
| The term "chat" is used where a group or broadcast channel is expected. This
 | |
| includes small groups, megagroups, broadcast channels and broadcast groups.
 | |
| Telegram's API has, in the past, made a difference between which methods can
 | |
| be used for "small group chats" and everything else. For example, small group
 | |
| chats cannot have a public link (they automatically convert to megagroups).
 | |
| Group permissions also used to be different, but because Telegram may unify
 | |
| these eventually, the library attempts to hide this distinction. In general,
 | |
| this is not something you should worry about.
 | |
| 
 | |
| 
 | |
| Fetching profile information
 | |
| ============================
 | |
| 
 | |
| Through the use of the :ref:`sessions`, the library will automatically
 | |
| remember the packed users and chats, along with some extra information,
 | |
| so you're able to just do this:
 | |
| 
 | |
| .. code-block:: python
 | |
| 
 | |
|     # (These examples assume you are inside an "async def")
 | |
|     #
 | |
|     # Dialogs are the "conversations you have open".
 | |
|     # This method returns a list of Dialog, which
 | |
|     # has the .user and .chat attributes (among others).
 | |
|     #
 | |
|     # This part is IMPORTANT, because it fills the cache.
 | |
|     dialogs = await client.get_dialogs()
 | |
| 
 | |
|     # All of these work and do the same, but are more expensive to use.
 | |
|     channel = await client.get_profile('username')
 | |
|     channel = await client.get_profile('t.me/username')
 | |
|     channel = await client.get_profile('https://telegram.dog/username')
 | |
|     contact = await client.get_profile('+34xxxxxxxxx')
 | |
| 
 | |
|     # This will work, but only if the ID is in cache.
 | |
|     friend = await client.get_profile(friend_id)
 | |
| 
 | |
|     # This is the most reliable way to fetch a profile.
 | |
|     user = await client.get_profile('U.123.456789')
 | |
|     group = await client.get_profile('G.456.0')
 | |
|     broadcast = await client.get_profile('C.789.123456')
 | |
| 
 | |
| 
 | |
| All methods in the :ref:`telethon-client` accept any of the above
 | |
| prior to sending the request to save you from the hassle of doing so manually.
 | |
| That way, convenience calls such as `client.send_message('username', 'hi!')
 | |
| <telethon.client.messages.MessageMethods.send_message>` become possible.
 | |
| However, it can be expensive to fetch the username every time, so this is
 | |
| better left for things which are not executed often.
 | |
| 
 | |
| Although it's explicitly noted in the documentation that messages
 | |
| *subclass* `ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`
 | |
| and `SenderGetter <telethon.tl.custom.sendergetter.SenderGetter>`,
 | |
| this section will explain what this means.
 | |
| 
 | |
| When the documentation says "Bases: `telethon.tl.custom.chatgetter.ChatGetter`"
 | |
| it means that the class you're looking at, *also* can act as the class it
 | |
| bases. In this case, `ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`
 | |
| knows how to get the *chat* where a thing belongs to.
 | |
| 
 | |
| So, a `Message <telethon.tl.custom.message.Message>` is a
 | |
| `ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`.
 | |
| That means you can do this:
 | |
| 
 | |
| .. code-block:: python
 | |
| 
 | |
|     message.chat_id
 | |
|     message.chat
 | |
|     await event.get_chat()
 | |
|     # ...etc
 | |
| 
 | |
| `SenderGetter <telethon.tl.custom.sendergetter.SenderGetter>` is similar:
 | |
| 
 | |
| .. code-block:: python
 | |
| 
 | |
|     message.user_id
 | |
|     message.user
 | |
|     await event.get_input_user()
 | |
|     # ...etc
 | |
| 
 | |
| Quite a few things implement them, so it makes sense to reuse the code.
 | |
| For example, all events (except raw updates) implement `ChatGetter
 | |
| <telethon.tl.custom.chatgetter.ChatGetter>` since all events occur
 | |
| in some chat.
 | |
| 
 | |
| 
 | |
| Packed User and packed Chat
 | |
| ===========================
 | |
| 
 | |
| A packed `User <telethon.types._custom.user.User>` or a packed
 | |
| `Chat <telethon.types._custom.chat.Chat>` can be thought of as
 | |
| "a small string reference to the actual user or chat".
 | |
| 
 | |
| It can easily be saved or embedded in the code for later use,
 | |
| without having to worry if the user is in the session file cache.
 | |
| 
 | |
| This "packed representation" is a compact way to store the type of the User
 | |
| or Chat (is it a user account, a bot, a broadcast channel…), the identifier,
 | |
| and the access hash. This "access hash" is something Telegram uses to ensure
 | |
| that you can actually use this "User" or "Chat" in requests (so you can't just
 | |
| create some random user identifier and expect it to work).
 | |
| 
 | |
| In the raw API, this is pretty much "input peers", but the library uses the
 | |
| term "packed user or chat" to refer to its custom type and string
 | |
| representation.
 | |
| 
 | |
| The User and Chat IDs are the same for all user and bot accounts. However, the
 | |
| access hash is **different for each account**, so trying to reuse the access
 | |
| hash from one account in another will **not** work. This also means the packed
 | |
| representation will only work for the account that created it.
 | |
| 
 | |
| The library needs to have this access hash in some way for it to work.
 | |
| If it only has an ID and this ID is not in cache, it will not work.
 | |
| If using the packed representation, the hash is embedded, and will always work.
 | |
| 
 | |
| Every method, including raw API, will automatically convert your types to the
 | |
| expected input type the API uses, meaning the following will work:
 | |
| 
 | |
| 
 | |
| .. code-block:: python
 | |
| 
 | |
|     await client(_tl.fn.messages.SendMessage('username', 'hello'))
 | |
| 
 | |
| (This is only a raw API example, there are better ways to send messages.)
 | |
| 
 | |
| 
 | |
| Summary
 | |
| =======
 | |
| 
 | |
| TL;DR; If you're here because of *"Could not find the input peer for"*,
 | |
| you must ask yourself, "how did I find this user or chat through official
 | |
| applications"? Now do the same with the library. Use what applies:
 | |
| 
 | |
| .. code-block:: python
 | |
| 
 | |
|     # (These examples assume you are inside an "async def")
 | |
|     async with client:
 | |
|         # Does it have a username? Use it!
 | |
|         user = await client.get_profile(username)
 | |
| 
 | |
|         # Do you have a conversation open with them? Get dialogs.
 | |
|         await client.get_dialogs()
 | |
| 
 | |
|         # Are they participants of some group? Get them.
 | |
|         await client.get_participants('username')
 | |
| 
 | |
|         # Is the user the original sender of a forwarded message? Fetch the message.
 | |
|         await client.get_messages('username', 100)
 | |
| 
 | |
|         # NOW you can use the ID anywhere!
 | |
|         await client.send_message(123456, 'Hi!')
 | |
| 
 | |
|         user = await client.get_profile(123456)
 | |
|         print(user)
 | |
| 
 | |
| Once the library has "seen" the user or chat, you can use their **integer** ID.
 | |
| You can't use users or chats from IDs the library hasn't seen. You must make
 | |
| the library see them *at least once* and disconnect properly. You know where
 | |
| the user or chat are, and you must tell the library. It won't guess for you.
 | |
| 
 | |
| This is why it's recommended to use the packed versions instead. They will
 | |
| always work (unless Telegram, for some very unlikely reason, changes the way
 | |
| using users and chats works, of course).
 |