mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2024-11-22 17:36:34 +03:00
Clean up and complete RTD documentation
This commit is contained in:
parent
6cb5931e7a
commit
cb45e8fca9
|
@ -1,33 +1,41 @@
|
||||||
.. _accessing-the-full-api:
|
.. _accessing-the-full-api:
|
||||||
|
|
||||||
==========================
|
======================
|
||||||
Accessing the Full API
|
Accessing the Full API
|
||||||
==========================
|
======================
|
||||||
|
|
||||||
The ``TelegramClient`` doesn’t offer a method for every single request
|
|
||||||
the Telegram API supports. However, it’s very simple to ``.invoke()``
|
The ``TelegramClient`` doesn't offer a method for every single request
|
||||||
any request. Whenever you need something, don’t forget to `check the
|
the Telegram API supports. However, it's very simple to *call* or *invoke*
|
||||||
|
any request. Whenever you need something, don't forget to `check the
|
||||||
documentation`__ and look for the `method you need`__. There you can go
|
documentation`__ and look for the `method you need`__. There you can go
|
||||||
through a sorted list of everything you can do.
|
through a sorted list of everything you can do.
|
||||||
|
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Removing the hand crafted documentation for methods is still
|
||||||
|
a work in progress!
|
||||||
|
|
||||||
|
|
||||||
You should also refer to the documentation to see what the objects
|
You should also refer to the documentation to see what the objects
|
||||||
(constructors) Telegram returns look like. Every constructor inherits
|
(constructors) Telegram returns look like. Every constructor inherits
|
||||||
from a common type, and that’s the reason for this distinction.
|
from a common type, and that's the reason for this distinction.
|
||||||
|
|
||||||
Say ``client.send_message()`` didn’t exist, we could use the `search`__
|
Say ``client.send_message()`` didn't exist, we could use the `search`__
|
||||||
to look for “message”. There we would find `SendMessageRequest`__,
|
to look for "message". There we would find `SendMessageRequest`__,
|
||||||
which we can work with.
|
which we can work with.
|
||||||
|
|
||||||
Every request is a Python class, and has the parameters needed for you
|
Every request is a Python class, and has the parameters needed for you
|
||||||
to invoke it. You can also call ``help(request)`` for information on
|
to invoke it. You can also call ``help(request)`` for information on
|
||||||
what input parameters it takes. Remember to “Copy import to the
|
what input parameters it takes. Remember to "Copy import to the
|
||||||
clipboard”, or your script won’t be aware of this class! Now we have:
|
clipboard", or your script won't be aware of this class! Now we have:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
from telethon.tl.functions.messages import SendMessageRequest
|
from telethon.tl.functions.messages import SendMessageRequest
|
||||||
|
|
||||||
If you’re going to use a lot of these, you may do:
|
If you're going to use a lot of these, you may do:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -53,20 +61,20 @@ Or we call ``.get_input_entity()``:
|
||||||
|
|
||||||
peer = client.get_input_entity('someone')
|
peer = client.get_input_entity('someone')
|
||||||
|
|
||||||
When you’re going to invoke an API method, most require you to pass an
|
When you're going to invoke an API method, most require you to pass an
|
||||||
``InputUser``, ``InputChat``, or so on, this is why using
|
``InputUser``, ``InputChat``, or so on, this is why using
|
||||||
``.get_input_entity()`` is more straightforward (and sometimes
|
``.get_input_entity()`` is more straightforward (and often
|
||||||
immediate, if you know the ID of the user for instance). If you also
|
immediate, if you've seen the user before, know their ID, etc.).
|
||||||
need to have information about the whole user, use ``.get_entity()``
|
If you also need to have information about the whole user, use
|
||||||
instead:
|
``.get_entity()`` instead:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
entity = client.get_entity('someone')
|
entity = client.get_entity('someone')
|
||||||
|
|
||||||
In the later case, when you use the entity, the library will cast it to
|
In the later case, when you use the entity, the library will cast it to
|
||||||
its “input” version for you. If you already have the complete user and
|
its "input" version for you. If you already have the complete user and
|
||||||
want to cache its input version so the library doesn’t have to do this
|
want to cache its input version so the library doesn't have to do this
|
||||||
every time its used, simply call ``.get_input_peer``:
|
every time its used, simply call ``.get_input_peer``:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
@ -83,10 +91,9 @@ request we do:
|
||||||
result = client(SendMessageRequest(peer, 'Hello there!'))
|
result = client(SendMessageRequest(peer, 'Hello there!'))
|
||||||
# __call__ is an alias for client.invoke(request). Both will work
|
# __call__ is an alias for client.invoke(request). Both will work
|
||||||
|
|
||||||
Message sent! Of course, this is only an example.
|
Message sent! Of course, this is only an example. There are nearly 250
|
||||||
There are nearly 250 methods available as of layer 73,
|
methods available as of layer 73, and you can use every single of them
|
||||||
and you can use every single of them as you wish.
|
as you wish. Remember to use the right types! To sum up:
|
||||||
Remember to use the right types! To sum up:
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -97,16 +104,16 @@ Remember to use the right types! To sum up:
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Note that some requests have a "hash" parameter. This is **not** your ``api_hash``!
|
Note that some requests have a "hash" parameter. This is **not**
|
||||||
It likely isn't your self-user ``.access_hash`` either.
|
your ``api_hash``! It likely isn't your self-user ``.access_hash`` either.
|
||||||
It's a special hash used by Telegram to only send a difference of new data
|
|
||||||
that you don't already have with that request,
|
|
||||||
so you can leave it to 0, and it should work (which means no hash is known yet).
|
|
||||||
|
|
||||||
For those requests having a "limit" parameter,
|
It's a special hash used by Telegram to only send a difference of new data
|
||||||
you can often set it to zero to signify "return as many items as possible".
|
that you don't already have with that request, so you can leave it to 0,
|
||||||
This won't work for all of them though,
|
and it should work (which means no hash is known yet).
|
||||||
for instance, in "messages.search" it will actually return 0 items.
|
|
||||||
|
For those requests having a "limit" parameter, you can often set it to
|
||||||
|
zero to signify "return default amount". This won't work for all of them
|
||||||
|
though, for instance, in "messages.search" it will actually return 0 items.
|
||||||
|
|
||||||
|
|
||||||
__ https://lonamiwebs.github.io/Telethon
|
__ https://lonamiwebs.github.io/Telethon
|
46
readthedocs/extra/advanced-usage/sessions.rst
Normal file
46
readthedocs/extra/advanced-usage/sessions.rst
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
.. _sessions:
|
||||||
|
|
||||||
|
==============
|
||||||
|
Session Files
|
||||||
|
==============
|
||||||
|
|
||||||
|
The first parameter you pass the the constructor of the ``TelegramClient`` is
|
||||||
|
the ``session``, and defaults to be the session name (or full path). That is,
|
||||||
|
if you create a ``TelegramClient('anon')`` instance and connect, an
|
||||||
|
``anon.session`` file will be created on the working directory.
|
||||||
|
|
||||||
|
These database files using ``sqlite3`` contain the required information to
|
||||||
|
talk to the Telegram servers, such as to which IP the client should connect,
|
||||||
|
port, authorization key so that messages can be encrypted, and so on.
|
||||||
|
|
||||||
|
These files will by default also save all the input entities that you've seen,
|
||||||
|
so that you can get information about an user or channel by just their ID.
|
||||||
|
Telegram will **not** send their ``access_hash`` required to retrieve more
|
||||||
|
information about them, if it thinks you have already seem them. For this
|
||||||
|
reason, the library needs to store this information offline.
|
||||||
|
|
||||||
|
The library will by default too save all the entities (chats and channels
|
||||||
|
with their name and username, and users with the phone too) in the session
|
||||||
|
file, so that you can quickly access them by username or phone number.
|
||||||
|
|
||||||
|
If you're not going to work with updates, or don't need to cache the
|
||||||
|
``access_hash`` associated with the entities' ID, you can disable this
|
||||||
|
by setting ``client.session.save_entities = False``, or pass it as a
|
||||||
|
parameter to the ``TelegramClient``.
|
||||||
|
|
||||||
|
If you don't want to save the files as a database, you can also create
|
||||||
|
your custom ``Session`` subclass and override the ``.save()`` and ``.load()``
|
||||||
|
methods. For example, you could save it on a database:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
class DatabaseSession(Session):
|
||||||
|
def save():
|
||||||
|
# serialize relevant data to the database
|
||||||
|
|
||||||
|
def load():
|
||||||
|
# load relevant data to the database
|
||||||
|
|
||||||
|
|
||||||
|
You should read the ````session.py```` source file to know what "relevant
|
||||||
|
data" you need to keep track of.
|
|
@ -1,58 +0,0 @@
|
||||||
=========================
|
|
||||||
Signing In
|
|
||||||
=========================
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
Make sure you have gone through :ref:`prelude` already!
|
|
||||||
|
|
||||||
|
|
||||||
Two Factor Authorization (2FA)
|
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
If you have Two Factor Authorization (from now on, 2FA) enabled on your account, calling
|
|
||||||
:meth:`telethon.TelegramClient.sign_in` will raise a `SessionPasswordNeededError`.
|
|
||||||
When this happens, just :meth:`telethon.TelegramClient.sign_in` again with a ``password=``:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
import getpass
|
|
||||||
from telethon.errors import SessionPasswordNeededError
|
|
||||||
|
|
||||||
client.sign_in(phone)
|
|
||||||
try:
|
|
||||||
client.sign_in(code=input('Enter code: '))
|
|
||||||
except SessionPasswordNeededError:
|
|
||||||
client.sign_in(password=getpass.getpass())
|
|
||||||
|
|
||||||
Enabling 2FA
|
|
||||||
*************
|
|
||||||
|
|
||||||
If you don't have 2FA enabled, but you would like to do so through Telethon, take as example the following code snippet:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
import os
|
|
||||||
from hashlib import sha256
|
|
||||||
from telethon.tl.functions import account
|
|
||||||
from telethon.tl.types.account import PasswordInputSettings
|
|
||||||
|
|
||||||
new_salt = client(account.GetPasswordRequest()).new_salt
|
|
||||||
salt = new_salt + os.urandom(8) # new random salt
|
|
||||||
|
|
||||||
pw = 'secret'.encode('utf-8') # type your new password here
|
|
||||||
hint = 'hint'
|
|
||||||
|
|
||||||
pw_salted = salt + pw + salt
|
|
||||||
pw_hash = sha256(pw_salted).digest()
|
|
||||||
|
|
||||||
result = client(account.UpdatePasswordSettingsRequest(
|
|
||||||
current_password_hash=salt,
|
|
||||||
new_settings=PasswordInputSettings(
|
|
||||||
new_salt=salt,
|
|
||||||
new_password_hash=pw_hash,
|
|
||||||
hint=hint
|
|
||||||
)
|
|
||||||
))
|
|
||||||
|
|
||||||
Thanks to `Issue 259 <https://github.com/LonamiWebs/Telethon/issues/259>`_ for the tip!
|
|
||||||
|
|
|
@ -1,324 +0,0 @@
|
||||||
=========================
|
|
||||||
Users and Chats
|
|
||||||
=========================
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
Make sure you have gone through :ref:`prelude` already!
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
|
|
||||||
.. _retrieving-an-entity:
|
|
||||||
|
|
||||||
Retrieving an entity (user or group)
|
|
||||||
**************************************
|
|
||||||
An “entity” is used to refer to either an `User`__ or a `Chat`__
|
|
||||||
(which includes a `Channel`__). The most straightforward way to get
|
|
||||||
an entity is to use ``TelegramClient.get_entity()``. This method accepts
|
|
||||||
either a string, which can be a username, phone number or `t.me`__-like
|
|
||||||
link, or an integer that will be the ID of an **user**. You can use it
|
|
||||||
like so:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# all of these work
|
|
||||||
lonami = client.get_entity('lonami')
|
|
||||||
lonami = client.get_entity('t.me/lonami')
|
|
||||||
lonami = client.get_entity('https://telegram.dog/lonami')
|
|
||||||
|
|
||||||
# other kind of entities
|
|
||||||
channel = client.get_entity('telegram.me/joinchat/AAAAAEkk2WdoDrB4-Q8-gg')
|
|
||||||
contact = client.get_entity('+34xxxxxxxxx')
|
|
||||||
friend = client.get_entity(friend_id)
|
|
||||||
|
|
||||||
For the last one to work, the library must have “seen” the user at least
|
|
||||||
once. The library will “see” the user as long as any request contains
|
|
||||||
them, so if you’ve called ``.get_dialogs()`` for instance, and your
|
|
||||||
friend was there, the library will know about them. For more, read about
|
|
||||||
the :ref:`sessions`.
|
|
||||||
|
|
||||||
If you want to get a channel or chat by ID, you need to specify that
|
|
||||||
they are a channel or a chat. The library can’t infer what they are by
|
|
||||||
just their ID (unless the ID is marked, but this is only done
|
|
||||||
internally), so you need to wrap the ID around a `Peer`__ object:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon.tl.types import PeerUser, PeerChat, PeerChannel
|
|
||||||
my_user = client.get_entity(PeerUser(some_id))
|
|
||||||
my_chat = client.get_entity(PeerChat(some_id))
|
|
||||||
my_channel = client.get_entity(PeerChannel(some_id))
|
|
||||||
|
|
||||||
**Note** that most requests don’t ask for an ``User``, or a ``Chat``,
|
|
||||||
but rather for ``InputUser``, ``InputChat``, and so on. If this is the
|
|
||||||
case, you should prefer ``.get_input_entity()`` over ``.get_entity()``,
|
|
||||||
as it will be immediate if you provide an ID (whereas ``.get_entity()``
|
|
||||||
may need to find who the entity is first).
|
|
||||||
|
|
||||||
Via your open “chats” (dialogs)
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
Please read here: :ref:`retrieving-all-dialogs`.
|
|
||||||
|
|
||||||
Via ResolveUsernameRequest
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
This is the request used by ``.get_entity`` internally, but you can also
|
|
||||||
use it by hand:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon.tl.functions.contacts import ResolveUsernameRequest
|
|
||||||
|
|
||||||
result = client(ResolveUsernameRequest('username'))
|
|
||||||
found_chats = result.chats
|
|
||||||
found_users = result.users
|
|
||||||
# result.peer may be a PeerUser, PeerChat or PeerChannel
|
|
||||||
|
|
||||||
See `Peer`__ for more information about this result.
|
|
||||||
|
|
||||||
Via MessageFwdHeader
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
If all you have is a `MessageFwdHeader`__ after you retrieved a bunch
|
|
||||||
of messages, this gives you access to the ``from_id`` (if forwarded from
|
|
||||||
an user) and ``channel_id`` (if forwarded from a channel). Invoking
|
|
||||||
`GetMessagesRequest`__ also returns a list of ``chats`` and
|
|
||||||
``users``, and you can find the desired entity there:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# Logic to retrieve messages with `GetMessagesRequest´
|
|
||||||
messages = foo()
|
|
||||||
fwd_header = bar()
|
|
||||||
|
|
||||||
user = next(u for u in messages.users if u.id == fwd_header.from_id)
|
|
||||||
channel = next(c for c in messages.chats if c.id == fwd_header.channel_id)
|
|
||||||
|
|
||||||
Or you can just call ``.get_entity()`` with the ID, as you should have
|
|
||||||
seen that user or channel before. A call to ``GetMessagesRequest`` may
|
|
||||||
still be neeed.
|
|
||||||
|
|
||||||
Via GetContactsRequest
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
The library will call this for you if you pass a phone number to
|
|
||||||
``.get_entity``, but again, it can be done manually. If the user you
|
|
||||||
want to talk to is a contact, you can use `GetContactsRequest`__:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon.tl.functions.contacts import GetContactsRequest
|
|
||||||
from telethon.tl.types.contacts import Contacts
|
|
||||||
|
|
||||||
contacts = client(GetContactsRequest(0))
|
|
||||||
if isinstance(contacts, Contacts):
|
|
||||||
users = contacts.users
|
|
||||||
contacts = contacts.contacts
|
|
||||||
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/types/user.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/types/chat.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/constructors/channel.html
|
|
||||||
__ https://t.me
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/types/peer.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/types/peer.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/constructors/message_fwd_header.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/methods/messages/get_messages.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/methods/contacts/get_contacts.html
|
|
||||||
|
|
||||||
|
|
||||||
.. _retrieving-all-dialogs:
|
|
||||||
|
|
||||||
Retrieving all dialogs
|
|
||||||
***********************
|
|
||||||
|
|
||||||
There are several ``offset_xyz=`` parameters that have no effect at all,
|
|
||||||
but there's not much one can do since this is something the server should handle.
|
|
||||||
Currently, the only way to get all dialogs
|
|
||||||
(open chats, conversations, etc.) is by using the ``offset_date``:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon.tl.functions.messages import GetDialogsRequest
|
|
||||||
from telethon.tl.types import InputPeerEmpty
|
|
||||||
from time import sleep
|
|
||||||
|
|
||||||
dialogs = []
|
|
||||||
users = []
|
|
||||||
chats = []
|
|
||||||
|
|
||||||
last_date = None
|
|
||||||
chunk_size = 20
|
|
||||||
while True:
|
|
||||||
result = client(GetDialogsRequest(
|
|
||||||
offset_date=last_date,
|
|
||||||
offset_id=0,
|
|
||||||
offset_peer=InputPeerEmpty(),
|
|
||||||
limit=chunk_size
|
|
||||||
))
|
|
||||||
dialogs.extend(result.dialogs)
|
|
||||||
users.extend(result.users)
|
|
||||||
chats.extend(result.chats)
|
|
||||||
if not result.messages:
|
|
||||||
break
|
|
||||||
last_date = min(msg.date for msg in result.messages)
|
|
||||||
sleep(2)
|
|
||||||
|
|
||||||
|
|
||||||
Joining a chat or channel
|
|
||||||
*******************************
|
|
||||||
|
|
||||||
Note that `Chat`__\ s are normal groups, and `Channel`__\ s are a
|
|
||||||
special form of `Chat`__\ s,
|
|
||||||
which can also be super-groups if their ``megagroup`` member is
|
|
||||||
``True``.
|
|
||||||
|
|
||||||
Joining a public channel
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
Once you have the :ref:`entity <retrieving-an-entity>`
|
|
||||||
of the channel you want to join to, you can
|
|
||||||
make use of the `JoinChannelRequest`__ to join such channel:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon.tl.functions.channels import JoinChannelRequest
|
|
||||||
client(JoinChannelRequest(channel))
|
|
||||||
|
|
||||||
# In the same way, you can also leave such channel
|
|
||||||
from telethon.tl.functions.channels import LeaveChannelRequest
|
|
||||||
client(LeaveChannelRequest(input_channel))
|
|
||||||
|
|
||||||
For more on channels, check the `channels namespace`__.
|
|
||||||
|
|
||||||
Joining a private chat or channel
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
If all you have is a link like this one:
|
|
||||||
``https://t.me/joinchat/AAAAAFFszQPyPEZ7wgxLtd``, you already have
|
|
||||||
enough information to join! The part after the
|
|
||||||
``https://t.me/joinchat/``, this is, ``AAAAAFFszQPyPEZ7wgxLtd`` on this
|
|
||||||
example, is the ``hash`` of the chat or channel. Now you can use
|
|
||||||
`ImportChatInviteRequest`__ as follows:
|
|
||||||
|
|
||||||
.. -block:: python
|
|
||||||
|
|
||||||
from telethon.tl.functions.messages import ImportChatInviteRequest
|
|
||||||
updates = client(ImportChatInviteRequest('AAAAAEHbEkejzxUjAUCfYg'))
|
|
||||||
|
|
||||||
Adding someone else to such chat or channel
|
|
||||||
-------------------------------------------
|
|
||||||
|
|
||||||
If you don’t want to add yourself, maybe because you’re already in, you
|
|
||||||
can always add someone else with the `AddChatUserRequest`__, which
|
|
||||||
use is very straightforward:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon.tl.functions.messages import AddChatUserRequest
|
|
||||||
|
|
||||||
client(AddChatUserRequest(
|
|
||||||
chat_id,
|
|
||||||
user_to_add,
|
|
||||||
fwd_limit=10 # allow the user to see the 10 last messages
|
|
||||||
))
|
|
||||||
|
|
||||||
Checking a link without joining
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
If you don’t need to join but rather check whether it’s a group or a
|
|
||||||
channel, you can use the `CheckChatInviteRequest`__, which takes in
|
|
||||||
the `hash`__ of said channel or group.
|
|
||||||
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/constructors/chat.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/constructors/channel.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/types/chat.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/methods/channels/join_channel.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/methods/channels/index.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/methods/messages/import_chat_invite.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/methods/messages/add_chat_user.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/methods/messages/check_chat_invite.html
|
|
||||||
__ https://github.com/LonamiWebs/Telethon/wiki/Joining-a-chat-or-channel#joining-a-private-chat-or-channel
|
|
||||||
|
|
||||||
|
|
||||||
Retrieving all chat members (channels too)
|
|
||||||
******************************************
|
|
||||||
|
|
||||||
In order to get all the members from a mega-group or channel, you need
|
|
||||||
to use `GetParticipantsRequest`__. As we can see it needs an
|
|
||||||
`InputChannel`__, (passing the mega-group or channel you’re going to
|
|
||||||
use will work), and a mandatory `ChannelParticipantsFilter`__. The
|
|
||||||
closest thing to “no filter” is to simply use
|
|
||||||
`ChannelParticipantsSearch`__ with an empty ``'q'`` string.
|
|
||||||
|
|
||||||
If we want to get *all* the members, we need to use a moving offset and
|
|
||||||
a fixed limit:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon.tl.functions.channels import GetParticipantsRequest
|
|
||||||
from telethon.tl.types import ChannelParticipantsSearch
|
|
||||||
from time import sleep
|
|
||||||
|
|
||||||
offset = 0
|
|
||||||
limit = 100
|
|
||||||
all_participants = []
|
|
||||||
|
|
||||||
while True:
|
|
||||||
participants = client.invoke(GetParticipantsRequest(
|
|
||||||
channel, ChannelParticipantsSearch(''), offset, limit
|
|
||||||
))
|
|
||||||
if not participants.users:
|
|
||||||
break
|
|
||||||
all_participants.extend(participants.users)
|
|
||||||
offset += len(participants.users)
|
|
||||||
# sleep(1) # This line seems to be optional, no guarantees!
|
|
||||||
|
|
||||||
Note that ``GetParticipantsRequest`` returns `ChannelParticipants`__,
|
|
||||||
which may have more information you need (like the role of the
|
|
||||||
participants, total count of members, etc.)
|
|
||||||
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/methods/channels/get_participants.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/methods/channels/get_participants.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/types/channel_participants_filter.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/constructors/channel_participants_search.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/constructors/channels/channel_participants.html
|
|
||||||
|
|
||||||
|
|
||||||
Recent Actions
|
|
||||||
********************
|
|
||||||
|
|
||||||
“Recent actions” is simply the name official applications have given to
|
|
||||||
the “admin log”. Simply use `GetAdminLogRequest`__ for that, and
|
|
||||||
you’ll get AdminLogResults.events in return which in turn has the final
|
|
||||||
`.action`__.
|
|
||||||
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/methods/channels/get_admin_log.html
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/types/channel_admin_log_event_action.html
|
|
||||||
|
|
||||||
|
|
||||||
Increasing View Count in a Channel
|
|
||||||
****************************************
|
|
||||||
|
|
||||||
It has been asked `quite`__ `a few`__ `times`__ (really, `many`__), and
|
|
||||||
while I don’t understand why so many people ask this, the solution is to
|
|
||||||
use `GetMessagesViewsRequest`__, setting ``increment=True``:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
|
|
||||||
# Obtain `channel' through dialogs or through client.get_entity() or anyhow.
|
|
||||||
# Obtain `msg_ids' through `.get_message_history()` or anyhow. Must be a list.
|
|
||||||
|
|
||||||
client(GetMessagesViewsRequest(
|
|
||||||
peer=channel,
|
|
||||||
id=msg_ids,
|
|
||||||
increment=True
|
|
||||||
))
|
|
||||||
|
|
||||||
__ https://github.com/LonamiWebs/Telethon/issues/233
|
|
||||||
__ https://github.com/LonamiWebs/Telethon/issues/305
|
|
||||||
__ https://github.com/LonamiWebs/Telethon/issues/409
|
|
||||||
__ https://github.com/LonamiWebs/Telethon/issues/447
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/methods/messages/get_messages_views.html
|
|
|
@ -1,48 +0,0 @@
|
||||||
.. _prelude:
|
|
||||||
|
|
||||||
Prelude
|
|
||||||
---------
|
|
||||||
|
|
||||||
Before reading any specific example, make sure to read the following common steps:
|
|
||||||
|
|
||||||
All the examples assume that you have successfully created a client and you're authorized as follows:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon import TelegramClient
|
|
||||||
|
|
||||||
# Use your own values here
|
|
||||||
api_id = 12345
|
|
||||||
api_hash = '0123456789abcdef0123456789abcdef'
|
|
||||||
phone_number = '+34600000000'
|
|
||||||
|
|
||||||
client = TelegramClient('some_name', api_id, api_hash)
|
|
||||||
client.connect() # Must return True, otherwise, try again
|
|
||||||
|
|
||||||
if not client.is_user_authorized():
|
|
||||||
client.send_code_request(phone_number)
|
|
||||||
# .sign_in() may raise PhoneNumberUnoccupiedError
|
|
||||||
# In that case, you need to call .sign_up() to get a new account
|
|
||||||
client.sign_in(phone_number, input('Enter code: '))
|
|
||||||
|
|
||||||
# The `client´ is now ready
|
|
||||||
|
|
||||||
Although Python will probably clean up the resources used by the ``TelegramClient``,
|
|
||||||
you should always ``.disconnect()`` it once you're done:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Code using the client goes here
|
|
||||||
except:
|
|
||||||
# No matter what happens, always disconnect in the end
|
|
||||||
client.disconnect()
|
|
||||||
|
|
||||||
If the examples aren't enough, you're strongly advised to read the source code
|
|
||||||
for the InteractiveTelegramClient_ for an overview on how you could build your next script.
|
|
||||||
This example shows a basic usage more than enough in most cases. Even reading the source
|
|
||||||
for the TelegramClient_ may help a lot!
|
|
||||||
|
|
||||||
|
|
||||||
.. _InteractiveTelegramClient: https://github.com/LonamiWebs/Telethon/blob/master/telethon_examples/interactive_telegram_client.py
|
|
||||||
.. _TelegramClient: https://github.com/LonamiWebs/Telethon/blob/master/telethon/telegram_client.py
|
|
|
@ -1,24 +1,28 @@
|
||||||
.. _creating-a-client:
|
.. _creating-a-client:
|
||||||
|
|
||||||
===================
|
=================
|
||||||
Creating a Client
|
Creating a Client
|
||||||
===================
|
=================
|
||||||
|
|
||||||
|
|
||||||
Before working with Telegram's API, you need to get your own API ID and hash:
|
Before working with Telegram's API, you need to get your own API ID and hash:
|
||||||
|
|
||||||
1. Follow `this link <https://my.telegram.org/>`_ and login with your phone number.
|
1. Follow `this link <https://my.telegram.org/>`_ and login with your
|
||||||
|
phone number.
|
||||||
|
|
||||||
2. Click under API Development tools.
|
2. Click under API Development tools.
|
||||||
|
|
||||||
3. A *Create new application* window will appear. Fill in your application details.
|
3. A *Create new application* window will appear. Fill in your application
|
||||||
There is no need to enter any *URL*, and only the first two fields (*App title* and *Short name*)
|
details. There is no need to enter any *URL*, and only the first two
|
||||||
can be changed later as far as I'm aware.
|
fields (*App title* and *Short name*) can currently be changed later.
|
||||||
|
|
||||||
4. Click on *Create application* at the end. Remember that your **API hash is secret**
|
4. Click on *Create application* at the end. Remember that your
|
||||||
and Telegram won't let you revoke it. Don't post it anywhere!
|
**API hash is secret** and Telegram won't let you revoke it.
|
||||||
|
Don't post it anywhere!
|
||||||
|
|
||||||
Once that's ready, the next step is to create a ``TelegramClient``.
|
Once that's ready, the next step is to create a ``TelegramClient``.
|
||||||
This class will be your main interface with Telegram's API, and creating one is very simple:
|
This class will be your main interface with Telegram's API, and creating
|
||||||
|
one is very simple:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -31,14 +35,18 @@ This class will be your main interface with Telegram's API, and creating one is
|
||||||
|
|
||||||
client = TelegramClient('some_name', api_id, api_hash)
|
client = TelegramClient('some_name', api_id, api_hash)
|
||||||
|
|
||||||
Note that ``'some_name'`` will be used to save your session (persistent information such as access key and others)
|
|
||||||
as ``'some_name.session'`` in your disk. This is simply a JSON file which you can (but shouldn't) modify.
|
|
||||||
|
|
||||||
Before using the client, you must be connected to Telegram. Doing so is very easy:
|
Note that ``'some_name'`` will be used to save your session (persistent
|
||||||
|
information such as access key and others) as ``'some_name.session'`` in
|
||||||
|
your disk. This is by default a database file using Python's ``sqlite3``.
|
||||||
|
|
||||||
|
Before using the client, you must be connected to Telegram.
|
||||||
|
Doing so is very easy:
|
||||||
|
|
||||||
``client.connect() # Must return True, otherwise, try again``
|
``client.connect() # Must return True, otherwise, try again``
|
||||||
|
|
||||||
You may or may not be authorized yet. You must be authorized before you're able to send any request:
|
You may or may not be authorized yet. You must be authorized
|
||||||
|
before you're able to send any request:
|
||||||
|
|
||||||
``client.is_user_authorized() # Returns True if you can send requests``
|
``client.is_user_authorized() # Returns True if you can send requests``
|
||||||
|
|
||||||
|
@ -52,13 +60,25 @@ If you're not authorized, you need to ``.sign_in()``:
|
||||||
# If .sign_in raises SessionPasswordNeeded error, call .sign_in(password=...)
|
# If .sign_in raises SessionPasswordNeeded error, call .sign_in(password=...)
|
||||||
# You can import both exceptions from telethon.errors.
|
# You can import both exceptions from telethon.errors.
|
||||||
|
|
||||||
``myself`` is your Telegram user.
|
``myself`` is your Telegram user. You can view all the information about
|
||||||
You can view all the information about yourself by doing ``print(myself.stringify())``.
|
yourself by doing ``print(myself.stringify())``. You're now ready to use
|
||||||
You're now ready to use the client as you wish!
|
the client as you wish! Remember that any object returned by the API has
|
||||||
|
mentioned ``.stringify()`` method, and printing these might prove useful.
|
||||||
|
|
||||||
|
As a full example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
client = TelegramClient('anon', api_id, api_hash)
|
||||||
|
assert client.connect()
|
||||||
|
if not client.is_user_authorized():
|
||||||
|
client.send_code_request(phone_number)
|
||||||
|
me = client.sign_in(phone_number, input('Enter code: '))
|
||||||
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
If you want to use a **proxy**, you have to `install PySocks`__ (via pip or manual)
|
If you want to use a **proxy**, you have to `install PySocks`__
|
||||||
and then set the appropriated parameters:
|
(via pip or manual) and then set the appropriated parameters:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -72,5 +92,58 @@ You're now ready to use the client as you wish!
|
||||||
consisting of parameters described `here`__.
|
consisting of parameters described `here`__.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Two Factor Authorization (2FA)
|
||||||
|
******************************
|
||||||
|
|
||||||
|
If you have Two Factor Authorization (from now on, 2FA) enabled on your
|
||||||
|
account, calling :meth:`telethon.TelegramClient.sign_in` will raise a
|
||||||
|
`SessionPasswordNeededError`. When this happens, just
|
||||||
|
:meth:`telethon.TelegramClient.sign_in` again with a ``password=``:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import getpass
|
||||||
|
from telethon.errors import SessionPasswordNeededError
|
||||||
|
|
||||||
|
client.sign_in(phone)
|
||||||
|
try:
|
||||||
|
client.sign_in(code=input('Enter code: '))
|
||||||
|
except SessionPasswordNeededError:
|
||||||
|
client.sign_in(password=getpass.getpass())
|
||||||
|
|
||||||
|
|
||||||
|
If you don't have 2FA enabled, but you would like to do so through Telethon,
|
||||||
|
take as example the following code snippet:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import os
|
||||||
|
from hashlib import sha256
|
||||||
|
from telethon.tl.functions import account
|
||||||
|
from telethon.tl.types.account import PasswordInputSettings
|
||||||
|
|
||||||
|
new_salt = client(account.GetPasswordRequest()).new_salt
|
||||||
|
salt = new_salt + os.urandom(8) # new random salt
|
||||||
|
|
||||||
|
pw = 'secret'.encode('utf-8') # type your new password here
|
||||||
|
hint = 'hint'
|
||||||
|
|
||||||
|
pw_salted = salt + pw + salt
|
||||||
|
pw_hash = sha256(pw_salted).digest()
|
||||||
|
|
||||||
|
result = client(account.UpdatePasswordSettingsRequest(
|
||||||
|
current_password_hash=salt,
|
||||||
|
new_settings=PasswordInputSettings(
|
||||||
|
new_salt=salt,
|
||||||
|
new_password_hash=pw_hash,
|
||||||
|
hint=hint
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
Thanks to `Issue 259 <https://github.com/LonamiWebs/Telethon/issues/259>`_
|
||||||
|
for the tip!
|
||||||
|
|
||||||
|
|
||||||
__ https://github.com/Anorov/PySocks#installation
|
__ https://github.com/Anorov/PySocks#installation
|
||||||
__ https://github.com/Anorov/PySocks#usage-1%3E
|
__ https://github.com/Anorov/PySocks#usage-1%3E
|
87
readthedocs/extra/basic/entities.rst
Normal file
87
readthedocs/extra/basic/entities.rst
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
=========================
|
||||||
|
Users, Chats and Channels
|
||||||
|
=========================
|
||||||
|
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
************
|
||||||
|
|
||||||
|
The library widely uses the concept of "entities". An entity will refer
|
||||||
|
to any ``User``, ``Chat`` or ``Channel`` object that the API may return
|
||||||
|
in response to certain methods, such as ``GetUsersRequest``.
|
||||||
|
|
||||||
|
To save bandwidth, the API also makes use of their "input" versions.
|
||||||
|
The input version of an entity (e.g. ``InputPeerUser``, ``InputChat``,
|
||||||
|
etc.) only contains the minimum required information that's required
|
||||||
|
for Telegram to be able to identify who you're referring to: their ID
|
||||||
|
and hash. This ID/hash pair is unique per user, so if you use the pair
|
||||||
|
given by another user **or bot** it will **not** work.
|
||||||
|
|
||||||
|
To save *even more* bandwidth, the API also makes use of the ``Peer``
|
||||||
|
versions, which just have an ID. This serves to identify them, but
|
||||||
|
peers alone are not enough to use them. You need to know their hash
|
||||||
|
before you can "use them".
|
||||||
|
|
||||||
|
Luckily, the library tries to simplify this mess the best it can.
|
||||||
|
|
||||||
|
|
||||||
|
Getting entities
|
||||||
|
****************
|
||||||
|
|
||||||
|
Through the use of the :ref:`sessions`, the library will automatically
|
||||||
|
remember the ID and hash pair, along with some extra information, so
|
||||||
|
you're able to just do this:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# dialogs are the "conversations you have open"
|
||||||
|
# this method returns a list of Dialog, which
|
||||||
|
# have the .entity attribute and other information.
|
||||||
|
dialogs = client.get_dialogs(limit=200)
|
||||||
|
|
||||||
|
# all of these work and do the same
|
||||||
|
lonami = client.get_entity('lonami')
|
||||||
|
lonami = client.get_entity('t.me/lonami')
|
||||||
|
lonami = client.get_entity('https://telegram.dog/lonami')
|
||||||
|
|
||||||
|
# other kind of entities
|
||||||
|
channel = client.get_entity('telegram.me/joinchat/AAAAAEkk2WdoDrB4-Q8-gg')
|
||||||
|
contact = client.get_entity('+34xxxxxxxxx')
|
||||||
|
friend = client.get_entity(friend_id)
|
||||||
|
|
||||||
|
# using peers/input peers (note that the API may return these)
|
||||||
|
# users, chats and channels may all have the same ID, so it's
|
||||||
|
# necessary to wrap (at least) chat and channels inside Peer.
|
||||||
|
from telethon.tl.types import PeerUser, PeerChat, PeerChannel
|
||||||
|
my_user = client.get_entity(PeerUser(some_id))
|
||||||
|
my_chat = client.get_entity(PeerChat(some_id))
|
||||||
|
my_channel = client.get_entity(PeerChannel(some_id))
|
||||||
|
|
||||||
|
|
||||||
|
All methods in the :ref:`telegram-client` call ``.get_entity()`` to further
|
||||||
|
save you from the hassle of doing so manually, so doing things like
|
||||||
|
``client.send_message('lonami', 'hi!')`` is possible.
|
||||||
|
|
||||||
|
Every entity the library "sees" (in any response to any call) will by
|
||||||
|
default be cached in the ``.session`` file, to avoid performing
|
||||||
|
unnecessary API calls. If the entity cannot be found, some calls
|
||||||
|
like ``ResolveUsernameRequest`` or ``GetContactsRequest`` may be
|
||||||
|
made to obtain the required information.
|
||||||
|
|
||||||
|
|
||||||
|
Entities vs. Input Entities
|
||||||
|
***************************
|
||||||
|
|
||||||
|
As we mentioned before, API calls don't need to know the whole information
|
||||||
|
about the entities, only their ID and hash. For this reason, another method,
|
||||||
|
``.get_input_entity()`` is available. This will always use the cache while
|
||||||
|
possible, making zero API calls most of the time. When a request is made,
|
||||||
|
if you provided the full entity, e.g. an ``User``, the library will convert
|
||||||
|
it to the required ``InputPeer`` automatically for you.
|
||||||
|
|
||||||
|
**You should always favour ``.get_input_entity()``** over ``.get_entity()``
|
||||||
|
for this reason! Calling the latter will always make an API call to get
|
||||||
|
the most recent information about said entity, but invoking requests don't
|
||||||
|
need this information, just the ``InputPeer``. Only use ``.get_entity()``
|
||||||
|
if you need to get actual information, like the username, name, title, etc.
|
||||||
|
of the entity.
|
|
@ -3,13 +3,13 @@
|
||||||
You can adapt this file completely to your liking, but it should at least
|
You can adapt this file completely to your liking, but it should at least
|
||||||
contain the root `toctree` directive.
|
contain the root `toctree` directive.
|
||||||
|
|
||||||
|
===============
|
||||||
|
Getting Started
|
||||||
|
===============
|
||||||
|
|
||||||
=================
|
|
||||||
Getting Started!
|
|
||||||
=================
|
|
||||||
|
|
||||||
Simple Installation
|
Simple Installation
|
||||||
*********************
|
*******************
|
||||||
|
|
||||||
``pip install telethon``
|
``pip install telethon``
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ Simple Installation
|
||||||
|
|
||||||
|
|
||||||
Creating a client
|
Creating a client
|
||||||
**************
|
*****************
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -39,8 +39,9 @@ Creating a client
|
||||||
**More details**: :ref:`creating-a-client`
|
**More details**: :ref:`creating-a-client`
|
||||||
|
|
||||||
|
|
||||||
Simple Stuff
|
Basic Usage
|
||||||
**************
|
***********
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
print(me.stringify())
|
print(me.stringify())
|
||||||
|
@ -52,3 +53,5 @@ Simple Stuff
|
||||||
total, messages, senders = client.get_message_history('username')
|
total, messages, senders = client.get_message_history('username')
|
||||||
client.download_media(messages[0])
|
client.download_media(messages[0])
|
||||||
|
|
||||||
|
**More details**: :ref:`telegram-client`
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
.. _installation:
|
.. _installation:
|
||||||
|
|
||||||
=================
|
============
|
||||||
Installation
|
Installation
|
||||||
=================
|
============
|
||||||
|
|
||||||
|
|
||||||
Automatic Installation
|
Automatic Installation
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
**********************
|
||||||
|
|
||||||
To install Telethon, simply do:
|
To install Telethon, simply do:
|
||||||
|
|
||||||
``pip install telethon``
|
``pip install telethon``
|
||||||
|
|
||||||
If you get something like ``"SyntaxError: invalid syntax"`` or any other error while installing,
|
If you get something like ``"SyntaxError: invalid syntax"`` or any other
|
||||||
it's probably because ``pip`` defaults to Python 2, which is not supported. Use ``pip3`` instead.
|
error while installing/importing the library, it's probably because ``pip``
|
||||||
|
defaults to Python 2, which is not supported. Use ``pip3`` instead.
|
||||||
|
|
||||||
If you already have the library installed, upgrade with:
|
If you already have the library installed, upgrade with:
|
||||||
|
|
||||||
|
@ -20,7 +22,7 @@ If you already have the library installed, upgrade with:
|
||||||
|
|
||||||
You can also install the library directly from GitHub or a fork:
|
You can also install the library directly from GitHub or a fork:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: sh
|
||||||
|
|
||||||
# pip install git+https://github.com/LonamiWebs/Telethon.git
|
# pip install git+https://github.com/LonamiWebs/Telethon.git
|
||||||
or
|
or
|
||||||
|
@ -32,13 +34,15 @@ If you don't have root access, simply pass the ``--user`` flag to the pip comman
|
||||||
|
|
||||||
|
|
||||||
Manual Installation
|
Manual Installation
|
||||||
^^^^^^^^^^^^^^^^^^^^
|
*******************
|
||||||
|
|
||||||
1. Install the required ``pyaes`` (`GitHub`__ | `PyPi`__) and ``rsa`` (`GitHub`__ | `PyPi`__) modules:
|
1. Install the required ``pyaes`` (`GitHub`__ | `PyPi`__) and
|
||||||
|
``rsa`` (`GitHub`__ | `PyPi`__) modules:
|
||||||
|
|
||||||
``sudo -H pip install pyaes rsa``
|
``sudo -H pip install pyaes rsa``
|
||||||
|
|
||||||
2. Clone Telethon's GitHub repository: ``git clone https://github.com/LonamiWebs/Telethon.git``
|
2. Clone Telethon's GitHub repository:
|
||||||
|
``git clone https://github.com/LonamiWebs/Telethon.git``
|
||||||
|
|
||||||
3. Enter the cloned repository: ``cd Telethon``
|
3. Enter the cloned repository: ``cd Telethon``
|
||||||
|
|
||||||
|
@ -50,18 +54,11 @@ To generate the documentation, ``cd docs`` and then ``python3 generate.py``.
|
||||||
|
|
||||||
|
|
||||||
Optional dependencies
|
Optional dependencies
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
*********************
|
||||||
|
|
||||||
If you're using the library under ARM (or even if you aren't),
|
|
||||||
you may want to install ``sympy`` through ``pip`` for a substantial speed-up
|
|
||||||
when generating the keys required to connect to Telegram
|
|
||||||
(you can of course do this on desktop too). See `issue #199`__ for more.
|
|
||||||
|
|
||||||
If ``libssl`` is available on your system, it will also be used wherever encryption is needed.
|
|
||||||
|
|
||||||
If neither of these are available, a pure Python callback will be used instead,
|
|
||||||
so you can still run the library wherever Python is available!
|
|
||||||
|
|
||||||
|
If ``libssl`` is available on your system, it will be used wherever encryption
|
||||||
|
is needed, but otherwise it will fall back to pure Python implementation so it
|
||||||
|
will also work without it.
|
||||||
|
|
||||||
|
|
||||||
__ https://github.com/ricmoo/pyaes
|
__ https://github.com/ricmoo/pyaes
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
.. _sending-requests:
|
|
||||||
|
|
||||||
==================
|
|
||||||
Sending Requests
|
|
||||||
==================
|
|
||||||
|
|
||||||
Since we're working with Python, one must not forget that they can do ``help(client)`` or ``help(TelegramClient)``
|
|
||||||
at any time for a more detailed description and a list of all the available methods.
|
|
||||||
Calling ``help()`` from an interactive Python session will always list all the methods for any object, even yours!
|
|
||||||
|
|
||||||
Interacting with the Telegram API is done through sending **requests**,
|
|
||||||
this is, any "method" listed on the API. There are a few methods on the ``TelegramClient`` class
|
|
||||||
that abstract you from the need of manually importing the requests you need.
|
|
||||||
|
|
||||||
For instance, retrieving your own user can be done in a single line:
|
|
||||||
|
|
||||||
``myself = client.get_me()``
|
|
||||||
|
|
||||||
Internally, this method has sent a request to Telegram, who replied with the information about your own user.
|
|
||||||
|
|
||||||
If you want to retrieve any other user, chat or channel (channels are a special subset of chats),
|
|
||||||
you want to retrieve their "entity". This is how the library refers to either of these:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# The method will infer that you've passed an username
|
|
||||||
# It also accepts phone numbers, and will get the user
|
|
||||||
# from your contact list.
|
|
||||||
lonami = client.get_entity('lonami')
|
|
||||||
|
|
||||||
Note that saving and using these entities will be more important when Accessing the Full API.
|
|
||||||
For now, this is a good way to get information about an user or chat.
|
|
||||||
|
|
||||||
Other common methods for quick scripts are also available:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# Sending a message (use an entity/username/etc)
|
|
||||||
client.send_message('TheAyyBot', 'ayy')
|
|
||||||
|
|
||||||
# Sending a photo, or a file
|
|
||||||
client.send_file(myself, '/path/to/the/file.jpg', force_document=True)
|
|
||||||
|
|
||||||
# Downloading someone's profile photo. File is saved to 'where'
|
|
||||||
where = client.download_profile_photo(someone)
|
|
||||||
|
|
||||||
# Retrieving the message history
|
|
||||||
total, messages, senders = client.get_message_history(someone)
|
|
||||||
|
|
||||||
# Downloading the media from a specific message
|
|
||||||
# You can specify either a directory, a filename, or nothing at all
|
|
||||||
where = client.download_media(message, '/path/to/output')
|
|
||||||
|
|
||||||
Remember that you can call ``.stringify()`` to any object Telegram returns to pretty print it.
|
|
||||||
Calling ``str(result)`` does the same operation, but on a single line.
|
|
|
@ -1,48 +0,0 @@
|
||||||
.. _sessions:
|
|
||||||
|
|
||||||
==============
|
|
||||||
Session Files
|
|
||||||
==============
|
|
||||||
|
|
||||||
The first parameter you pass the constructor of the
|
|
||||||
``TelegramClient`` is the ``session``, and defaults to be the session
|
|
||||||
name (or full path). That is, if you create a ``TelegramClient('anon')``
|
|
||||||
instance and connect, an ``anon.session`` file will be created on the
|
|
||||||
working directory.
|
|
||||||
|
|
||||||
These JSON session files contain the required information to talk to the
|
|
||||||
Telegram servers, such as to which IP the client should connect, port,
|
|
||||||
authorization key so that messages can be encrypted, and so on.
|
|
||||||
|
|
||||||
These files will by default also save all the input entities that you’ve
|
|
||||||
seen, so that you can get information about an user or channel by just
|
|
||||||
their ID. Telegram will **not** send their ``access_hash`` required to
|
|
||||||
retrieve more information about them, if it thinks you have already seem
|
|
||||||
them. For this reason, the library needs to store this information
|
|
||||||
offline.
|
|
||||||
|
|
||||||
The library will by default too save all the entities (users with their
|
|
||||||
name, username, chats and so on) **in memory**, not to disk, so that you
|
|
||||||
can quickly access them by username or phone number. This can be
|
|
||||||
disabled too. Run ``help(client.session.entities)`` to see the available
|
|
||||||
methods (or ``help(EntityDatabase)``).
|
|
||||||
|
|
||||||
If you’re not going to work without updates, or don’t need to cache the
|
|
||||||
``access_hash`` associated with the entities’ ID, you can disable this
|
|
||||||
by setting ``client.session.save_entities = False``.
|
|
||||||
|
|
||||||
If you don’t want to save the files as JSON, you can also create your
|
|
||||||
custom ``Session`` subclass and override the ``.save()`` and ``.load()``
|
|
||||||
methods. For example, you could save it on a database:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
class DatabaseSession(Session):
|
|
||||||
def save():
|
|
||||||
# serialize relevant data to the database
|
|
||||||
|
|
||||||
def load():
|
|
||||||
# load relevant data to the database
|
|
||||||
|
|
||||||
You should read the ``session.py`` source file to know what “relevant
|
|
||||||
data” you need to keep track of.
|
|
99
readthedocs/extra/basic/telegram-client.rst
Normal file
99
readthedocs/extra/basic/telegram-client.rst
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
.. _telegram-client:
|
||||||
|
|
||||||
|
==============
|
||||||
|
TelegramClient
|
||||||
|
==============
|
||||||
|
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
************
|
||||||
|
|
||||||
|
The ``TelegramClient`` is the central class of the library, the one
|
||||||
|
you will be using most of the time. For this reason, it's important
|
||||||
|
to know what it offers.
|
||||||
|
|
||||||
|
Since we're working with Python, one must not forget that we can do
|
||||||
|
``help(client)`` or ``help(TelegramClient)`` at any time for a more
|
||||||
|
detailed description and a list of all the available methods. Calling
|
||||||
|
``help()`` from an interactive Python session will always list all the
|
||||||
|
methods for any object, even yours!
|
||||||
|
|
||||||
|
Interacting with the Telegram API is done through sending **requests**,
|
||||||
|
this is, any "method" listed on the API. There are a few methods (and
|
||||||
|
growing!) on the ``TelegramClient`` class that abstract you from the
|
||||||
|
need of manually importing the requests you need.
|
||||||
|
|
||||||
|
For instance, retrieving your own user can be done in a single line:
|
||||||
|
|
||||||
|
``myself = client.get_me()``
|
||||||
|
|
||||||
|
Internally, this method has sent a request to Telegram, who replied with
|
||||||
|
the information about your own user, and then the desired information
|
||||||
|
was extracted from their response.
|
||||||
|
|
||||||
|
If you want to retrieve any other user, chat or channel (channels are a
|
||||||
|
special subset of chats), you want to retrieve their "entity". This is
|
||||||
|
how the library refers to either of these:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# The method will infer that you've passed an username
|
||||||
|
# It also accepts phone numbers, and will get the user
|
||||||
|
# from your contact list.
|
||||||
|
lonami = client.get_entity('lonami')
|
||||||
|
|
||||||
|
The so called "entities" are another important whole concept on its own,
|
||||||
|
and you should
|
||||||
|
Note that saving and using these entities will be more important when
|
||||||
|
Accessing the Full API. For now, this is a good way to get information
|
||||||
|
about an user or chat.
|
||||||
|
|
||||||
|
Other common methods for quick scripts are also available:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# Sending a message (use an entity/username/etc)
|
||||||
|
client.send_message('TheAyyBot', 'ayy')
|
||||||
|
|
||||||
|
# Sending a photo, or a file
|
||||||
|
client.send_file(myself, '/path/to/the/file.jpg', force_document=True)
|
||||||
|
|
||||||
|
# Downloading someone's profile photo. File is saved to 'where'
|
||||||
|
where = client.download_profile_photo(someone)
|
||||||
|
|
||||||
|
# Retrieving the message history
|
||||||
|
messages = client.get_message_history(someone)
|
||||||
|
|
||||||
|
# Downloading the media from a specific message
|
||||||
|
# You can specify either a directory, a filename, or nothing at all
|
||||||
|
where = client.download_media(message, '/path/to/output')
|
||||||
|
|
||||||
|
# Call .disconnect() when you're done
|
||||||
|
client.disconnect()
|
||||||
|
|
||||||
|
Remember that you can call ``.stringify()`` to any object Telegram returns
|
||||||
|
to pretty print it. Calling ``str(result)`` does the same operation, but on
|
||||||
|
a single line.
|
||||||
|
|
||||||
|
|
||||||
|
Available methods
|
||||||
|
*****************
|
||||||
|
|
||||||
|
This page lists all the "handy" methods available for you to use in the
|
||||||
|
``TelegramClient`` class. These are simply wrappers around the "raw"
|
||||||
|
Telegram API, making it much more manageable and easier to work with.
|
||||||
|
|
||||||
|
Please refer to :ref:`accessing-the-full-api` if these aren't enough,
|
||||||
|
and don't be afraid to read the source code of the InteractiveTelegramClient_
|
||||||
|
or even the TelegramClient_ itself to learn how it works.
|
||||||
|
|
||||||
|
|
||||||
|
.. _InteractiveTelegramClient: https://github.com/LonamiWebs/Telethon/blob/master/telethon_examples/interactive_telegram_client.py
|
||||||
|
.. _TelegramClient: https://github.com/LonamiWebs/Telethon/blob/master/telethon/telegram_client.py
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.. automodule:: telethon.telegram_client
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
|
@ -14,23 +14,24 @@ The library can run in four distinguishable modes:
|
||||||
- With several worker threads that run your update handlers.
|
- With several worker threads that run your update handlers.
|
||||||
- A mix of the above.
|
- A mix of the above.
|
||||||
|
|
||||||
Since this section is about updates, we'll describe the simplest way to work with them.
|
Since this section is about updates, we'll describe the simplest way to
|
||||||
|
work with them.
|
||||||
.. warning::
|
|
||||||
Remember that you should always call ``client.disconnect()`` once you're done.
|
|
||||||
|
|
||||||
|
|
||||||
Using multiple workers
|
Using multiple workers
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
**********************
|
||||||
|
|
||||||
When you create your client, simply pass a number to the ``update_workers`` parameter:
|
When you create your client, simply pass a number to the
|
||||||
|
``update_workers`` parameter:
|
||||||
|
|
||||||
``client = TelegramClient('session', api_id, api_hash, update_workers=4)``
|
``client = TelegramClient('session', api_id, api_hash, update_workers=4)``
|
||||||
|
|
||||||
4 workers should suffice for most cases (this is also the default on `Python Telegram Bot`__).
|
4 workers should suffice for most cases (this is also the default on
|
||||||
You can set this value to more, or even less if you need.
|
`Python Telegram Bot`__). You can set this value to more, or even less
|
||||||
|
if you need.
|
||||||
|
|
||||||
The next thing you want to do is to add a method that will be called when an `Update`__ arrives:
|
The next thing you want to do is to add a method that will be called when
|
||||||
|
an `Update`__ arrives:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -41,7 +42,8 @@ The next thing you want to do is to add a method that will be called when an `Up
|
||||||
# do more work here, or simply sleep!
|
# do more work here, or simply sleep!
|
||||||
|
|
||||||
That's it! Now let's do something more interesting.
|
That's it! Now let's do something more interesting.
|
||||||
Every time an user talks to use, let's reply to them with the same text reversed:
|
Every time an user talks to use, let's reply to them with the same
|
||||||
|
text reversed:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -56,16 +58,18 @@ Every time an user talks to use, let's reply to them with the same text reversed
|
||||||
input('Press enter to stop this!')
|
input('Press enter to stop this!')
|
||||||
client.disconnect()
|
client.disconnect()
|
||||||
|
|
||||||
We only ask you one thing: don't keep this running for too long, or your contacts will go mad.
|
We only ask you one thing: don't keep this running for too long, or your
|
||||||
|
contacts will go mad.
|
||||||
|
|
||||||
|
|
||||||
Spawning no worker at all
|
Spawning no worker at all
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
*************************
|
||||||
|
|
||||||
All the workers do is loop forever and poll updates from a queue that is filled from the ``ReadThread``,
|
All the workers do is loop forever and poll updates from a queue that is
|
||||||
responsible for reading every item off the network.
|
filled from the ``ReadThread``, responsible for reading every item off
|
||||||
If you only need a worker and the ``MainThread`` would be doing no other job,
|
the network. If you only need a worker and the ``MainThread`` would be
|
||||||
this is the preferred way. You can easily do the same as the workers like so:
|
doing no other job, this is the preferred way. You can easily do the same
|
||||||
|
as the workers like so:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -81,24 +85,27 @@ this is the preferred way. You can easily do the same as the workers like so:
|
||||||
|
|
||||||
client.disconnect()
|
client.disconnect()
|
||||||
|
|
||||||
Note that ``poll`` accepts a ``timeout=`` parameter,
|
Note that ``poll`` accepts a ``timeout=`` parameter, and it will return
|
||||||
and it will return ``None`` if other thread got the update before you could or if the timeout expired,
|
``None`` if other thread got the update before you could or if the timeout
|
||||||
so it's important to check ``if not update``.
|
expired, so it's important to check ``if not update``.
|
||||||
|
|
||||||
This can coexist with the rest of ``N`` workers, or you can set it to ``0`` additional workers:
|
This can coexist with the rest of ``N`` workers, or you can set it to ``0``
|
||||||
|
additional workers:
|
||||||
|
|
||||||
``client = TelegramClient('session', api_id, api_hash, update_workers=0)``
|
``client = TelegramClient('session', api_id, api_hash, update_workers=0)``
|
||||||
|
|
||||||
You **must** set it to ``0`` (or other number), as it defaults to ``None`` and there is a different.
|
You **must** set it to ``0`` (or other number), as it defaults to ``None``
|
||||||
``None`` workers means updates won't be processed *at all*,
|
and there is a different. ``None`` workers means updates won't be processed
|
||||||
so you must set it to some value (0 or greater) if you want ``client.updates.poll()`` to work.
|
*at all*, so you must set it to some value (``0`` or greater) if you want
|
||||||
|
``client.updates.poll()`` to work.
|
||||||
|
|
||||||
|
|
||||||
Using the main thread instead the ``ReadThread``
|
Using the main thread instead the ``ReadThread``
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
************************************************
|
||||||
|
|
||||||
If you have no work to do on the ``MainThread`` and you were planning to have a ``while True: sleep(1)``,
|
If you have no work to do on the ``MainThread`` and you were planning to have
|
||||||
don't do that. Instead, don't spawn the secondary ``ReadThread`` at all like so:
|
a ``while True: sleep(1)``, don't do that. Instead, don't spawn the secondary
|
||||||
|
``ReadThread`` at all like so:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -111,8 +118,8 @@ And then ``.idle()`` from the ``MainThread``:
|
||||||
|
|
||||||
``client.idle()``
|
``client.idle()``
|
||||||
|
|
||||||
You can stop it with :kbd:`Control+C`,
|
You can stop it with :kbd:`Control+C`, and you can configure the signals
|
||||||
and you can configure the signals to be used in a similar fashion to `Python Telegram Bot`__.
|
to be used in a similar fashion to `Python Telegram Bot`__.
|
||||||
|
|
||||||
As a complete example:
|
As a complete example:
|
||||||
|
|
||||||
|
|
54
readthedocs/extra/developing/api-status.rst
Normal file
54
readthedocs/extra/developing/api-status.rst
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
==========
|
||||||
|
API Status
|
||||||
|
==========
|
||||||
|
|
||||||
|
|
||||||
|
In an attempt to help everyone who works with the Telegram API, the
|
||||||
|
library will by default report all *Remote Procedure Call* errors to
|
||||||
|
`RPC PWRTelegram <https://rpc.pwrtelegram.xyz/>`__, a public database
|
||||||
|
anyone can query, made by `Daniil <https://github.com/danog>`__. All the
|
||||||
|
information sent is a ``GET`` request with the error code, error message
|
||||||
|
and method used.
|
||||||
|
|
||||||
|
If you still would like to opt out, simply set
|
||||||
|
``client.session.report_errors = False`` to disable this feature, or
|
||||||
|
pass ``report_errors=False`` as a named parameter when creating a
|
||||||
|
``TelegramClient`` instance. However Daniil would really thank you if
|
||||||
|
you helped him (and everyone) by keeping it on!
|
||||||
|
|
||||||
|
Querying the API status
|
||||||
|
***********************
|
||||||
|
|
||||||
|
The API is accessed through ``GET`` requests, which can be made for
|
||||||
|
instance through ``curl``. A JSON response will be returned.
|
||||||
|
|
||||||
|
**All known errors and their description**:
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
curl https://rpc.pwrtelegram.xyz/?all
|
||||||
|
|
||||||
|
**Error codes for a specific request**:
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
curl https://rpc.pwrtelegram.xyz/?for=messages.sendMessage
|
||||||
|
|
||||||
|
**Number of ``RPC_CALL_FAIL``\ 's**:
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
curl https://rpc.pwrtelegram.xyz/?rip # last hour
|
||||||
|
curl https://rpc.pwrtelegram.xyz/?rip=$(time()-60) # last minute
|
||||||
|
|
||||||
|
**Description of errors**:
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
curl https://rpc.pwrtelegram.xyz/?description_for=SESSION_REVOKED
|
||||||
|
|
||||||
|
**Code of a specific error**:
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
curl https://rpc.pwrtelegram.xyz/?code_for=STICKERSET_INVALID
|
22
readthedocs/extra/developing/coding-style.rst
Normal file
22
readthedocs/extra/developing/coding-style.rst
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
============
|
||||||
|
Coding Style
|
||||||
|
============
|
||||||
|
|
||||||
|
|
||||||
|
Basically, make it **readable**, while keeping the style similar to the
|
||||||
|
code of whatever file you're working on.
|
||||||
|
|
||||||
|
Also note that not everyone has 4K screens for their primary monitors,
|
||||||
|
so please try to stick to the 80-columns limit. This makes it easy to
|
||||||
|
``git diff`` changes from a terminal before committing changes. If the
|
||||||
|
line has to be long, please don't exceed 120 characters.
|
||||||
|
|
||||||
|
For the commit messages, please make them *explanatory*. Not only
|
||||||
|
they're helpful to troubleshoot when certain issues could have been
|
||||||
|
introduced, but they're also used to construct the change log once a new
|
||||||
|
version is ready.
|
||||||
|
|
||||||
|
If you don't know enough Python, I strongly recommend reading `Dive Into
|
||||||
|
Python 3 <http://www.diveintopython3.net/>`__, available online for
|
||||||
|
free. For instance, remember to do ``if x is None`` or
|
||||||
|
``if x is not None`` instead ``if x == None``!
|
25
readthedocs/extra/developing/philosophy.rst
Normal file
25
readthedocs/extra/developing/philosophy.rst
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
==========
|
||||||
|
Philosophy
|
||||||
|
==========
|
||||||
|
|
||||||
|
|
||||||
|
The intention of the library is to have an existing MTProto library
|
||||||
|
existing with hardly any dependencies (indeed, wherever Python is
|
||||||
|
available, you can run this library).
|
||||||
|
|
||||||
|
Being written in Python means that performance will be nowhere close to
|
||||||
|
other implementations written in, for instance, Java, C++, Rust, or
|
||||||
|
pretty much any other compiled language. However, the library turns out
|
||||||
|
to actually be pretty decent for common operations such as sending
|
||||||
|
messages, receiving updates, or other scripting. Uploading files may be
|
||||||
|
notably slower, but if you would like to contribute, pull requests are
|
||||||
|
appreciated!
|
||||||
|
|
||||||
|
If ``libssl`` is available on your system, the library will make use of
|
||||||
|
it to speed up some critical parts such as encrypting and decrypting the
|
||||||
|
messages. Files will notably be sent and downloaded faster.
|
||||||
|
|
||||||
|
The main focus is to keep everything clean and simple, for everyone to
|
||||||
|
understand how working with MTProto and Telegram works. Don't be afraid
|
||||||
|
to read the source, the code won't bite you! It may prove useful when
|
||||||
|
using the library on your own use cases.
|
43
readthedocs/extra/developing/project-structure.rst
Normal file
43
readthedocs/extra/developing/project-structure.rst
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
=================
|
||||||
|
Project Structure
|
||||||
|
=================
|
||||||
|
|
||||||
|
|
||||||
|
Main interface
|
||||||
|
**************
|
||||||
|
|
||||||
|
The library itself is under the ``telethon/`` directory. The
|
||||||
|
``__init__.py`` file there exposes the main ``TelegramClient``, a class
|
||||||
|
that servers as a nice interface with the most commonly used methods on
|
||||||
|
Telegram such as sending messages, retrieving the message history,
|
||||||
|
handling updates, etc.
|
||||||
|
|
||||||
|
The ``TelegramClient`` inherits the ``TelegramBareClient``. The later is
|
||||||
|
basically a pruned version of the ``TelegramClient``, which knows basic
|
||||||
|
stuff like ``.invoke()``\ 'ing requests, downloading files, or switching
|
||||||
|
between data centers. This is primary to keep the method count per class
|
||||||
|
and file low and manageable.
|
||||||
|
|
||||||
|
Both clients make use of the ``network/mtproto_sender.py``. The
|
||||||
|
``MtProtoSender`` class handles packing requests with the ``salt``,
|
||||||
|
``id``, ``sequence``, etc., and also handles how to process responses
|
||||||
|
(i.e. pong, RPC errors). This class communicates through Telegram via
|
||||||
|
its ``.connection`` member.
|
||||||
|
|
||||||
|
The ``Connection`` class uses a ``extensions/tcp_client``, a C#-like
|
||||||
|
``TcpClient`` to ease working with sockets in Python. All the
|
||||||
|
``TcpClient`` know is how to connect through TCP and writing/reading
|
||||||
|
from the socket with optional cancel.
|
||||||
|
|
||||||
|
The ``Connection`` class bundles up all the connections modes and sends
|
||||||
|
and receives the messages accordingly (TCP full, obfuscated,
|
||||||
|
intermediate…).
|
||||||
|
|
||||||
|
Auto-generated code
|
||||||
|
*******************
|
||||||
|
|
||||||
|
The files under ``telethon_generator/`` are used to generate the code
|
||||||
|
that gets placed under ``telethon/tl/``. The ``TLGenerator`` takes in a
|
||||||
|
``.tl`` file, and spits out the generated classes which represent, as
|
||||||
|
Python classes, the request and types defined in the ``.tl`` file. It
|
||||||
|
also constructs an index so that they can be imported easily.
|
|
@ -0,0 +1,64 @@
|
||||||
|
===============================
|
||||||
|
Telegram API in Other Languages
|
||||||
|
===============================
|
||||||
|
|
||||||
|
|
||||||
|
Telethon was made for **Python**, and as far as I know, there is no
|
||||||
|
*exact* port to other languages. However, there *are* other
|
||||||
|
implementations made by awesome people (one needs to be awesome to
|
||||||
|
understand the official Telegram documentation) on several languages
|
||||||
|
(even more Python too), listed below:
|
||||||
|
|
||||||
|
C
|
||||||
|
*
|
||||||
|
|
||||||
|
Possibly the most well-known unofficial open source implementation out
|
||||||
|
there by `**@vysheng** <https://github.com/vysheng>`__,
|
||||||
|
```tgl`` <https://github.com/vysheng/tgl>`__, and its console client
|
||||||
|
```telegram-cli`` <https://github.com/vysheng/tg>`__. Latest development
|
||||||
|
has been moved to `BitBucket <https://bitbucket.org/vysheng/tdcli>`__.
|
||||||
|
|
||||||
|
JavaScript
|
||||||
|
**********
|
||||||
|
|
||||||
|
`**@zerobias** <https://github.com/zerobias>`__ is working on
|
||||||
|
```telegram-mtproto`` <https://github.com/zerobias/telegram-mtproto>`__,
|
||||||
|
a work-in-progress JavaScript library installable via
|
||||||
|
```npm`` <https://www.npmjs.com/>`__.
|
||||||
|
|
||||||
|
Kotlin
|
||||||
|
******
|
||||||
|
|
||||||
|
`Kotlogram <https://github.com/badoualy/kotlogram>`__ is a Telegram
|
||||||
|
implementation written in Kotlin (the now
|
||||||
|
`official <https://blog.jetbrains.com/kotlin/2017/05/kotlin-on-android-now-official/>`__
|
||||||
|
language for
|
||||||
|
`Android <https://developer.android.com/kotlin/index.html>`__) by
|
||||||
|
`**@badoualy** <https://github.com/badoualy>`__, currently as a beta–
|
||||||
|
yet working.
|
||||||
|
|
||||||
|
PHP
|
||||||
|
***
|
||||||
|
|
||||||
|
A PHP implementation is also available thanks to
|
||||||
|
`**@danog** <https://github.com/danog>`__ and his
|
||||||
|
`MadelineProto <https://github.com/danog/MadelineProto>`__ project, with
|
||||||
|
a very nice `online
|
||||||
|
documentation <https://daniil.it/MadelineProto/API_docs/>`__ too.
|
||||||
|
|
||||||
|
Python
|
||||||
|
******
|
||||||
|
|
||||||
|
A fairly new (as of the end of 2017) Telegram library written from the
|
||||||
|
ground up in Python by
|
||||||
|
`**@delivrance** <https://github.com/delivrance>`__ and his
|
||||||
|
`Pyrogram <https://github.com/pyrogram/pyrogram>`__ library! No hard
|
||||||
|
feelings Dan and good luck dealing with some of your users ;)
|
||||||
|
|
||||||
|
Rust
|
||||||
|
****
|
||||||
|
|
||||||
|
Yet another work-in-progress implementation, this time for Rust thanks
|
||||||
|
to `**@JuanPotato** <https://github.com/JuanPotato>`__ under the fancy
|
||||||
|
name of `Vail <https://github.com/JuanPotato/Vail>`__. This one is very
|
||||||
|
early still, but progress is being made at a steady rate.
|
32
readthedocs/extra/developing/test-servers.rst
Normal file
32
readthedocs/extra/developing/test-servers.rst
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
============
|
||||||
|
Test Servers
|
||||||
|
============
|
||||||
|
|
||||||
|
|
||||||
|
To run Telethon on a test server, use the following code:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
client = TelegramClient(None, api_id, api_hash)
|
||||||
|
client.session.server_address = '149.154.167.40'
|
||||||
|
client.connect()
|
||||||
|
|
||||||
|
You can check your ``'test ip'`` on https://my.telegram.org.
|
||||||
|
|
||||||
|
You should set ``None`` session so to ensure you're generating a new
|
||||||
|
authorization key for it (it would fail if you used a session where you
|
||||||
|
had previously connected to another data center).
|
||||||
|
|
||||||
|
Once you're connected, you'll likely need to ``.sign_up()``. Remember
|
||||||
|
`anyone can access the phone you
|
||||||
|
choose <https://core.telegram.org/api/datacenter#testing-redirects>`__,
|
||||||
|
so don't store sensitive data here:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from random import randint
|
||||||
|
|
||||||
|
dc_id = '2' # Change this to the DC id of the test server you chose
|
||||||
|
phone = '99966' + dc_id + str(randint(9999)).zfill(4)
|
||||||
|
client.send_code_request(phone)
|
||||||
|
client.sign_up(dc_id * 5, 'Some', 'Name')
|
|
@ -0,0 +1,17 @@
|
||||||
|
============================
|
||||||
|
Tips for Porting the Project
|
||||||
|
============================
|
||||||
|
|
||||||
|
|
||||||
|
If you're going to use the code on this repository to guide you, please
|
||||||
|
be kind and don't forget to mention it helped you!
|
||||||
|
|
||||||
|
You should start by reading the source code on the `first
|
||||||
|
release <https://github.com/LonamiWebs/Telethon/releases/tag/v0.1>`__ of
|
||||||
|
the project, and start creating a ``MtProtoSender``. Once this is made,
|
||||||
|
you should write by hand the code to authenticate on the Telegram's
|
||||||
|
server, which are some steps required to get the key required to talk to
|
||||||
|
them. Save it somewhere! Then, simply mimic, or reinvent other parts of
|
||||||
|
the code, and it will be ready to go within a few days.
|
||||||
|
|
||||||
|
Good luck!
|
|
@ -0,0 +1,35 @@
|
||||||
|
===============================
|
||||||
|
Understanding the Type Language
|
||||||
|
===============================
|
||||||
|
|
||||||
|
|
||||||
|
`Telegram's Type Language <https://core.telegram.org/mtproto/TL>`__
|
||||||
|
(also known as TL, found on ``.tl`` files) is a concise way to define
|
||||||
|
what other programming languages commonly call classes or structs.
|
||||||
|
|
||||||
|
Every definition is written as follows for a Telegram object is defined
|
||||||
|
as follows:
|
||||||
|
|
||||||
|
.. code:: tl
|
||||||
|
|
||||||
|
name#id argument_name:argument_type = CommonType
|
||||||
|
|
||||||
|
This means that in a single line you know what the ``TLObject`` name is.
|
||||||
|
You know it's unique ID, and you know what arguments it has. It really
|
||||||
|
isn't that hard to write a generator for generating code to any
|
||||||
|
platform!
|
||||||
|
|
||||||
|
The generated code should also be able to *encode* the ``TLObject`` (let
|
||||||
|
this be a request or a type) into bytes, so they can be sent over the
|
||||||
|
network. This isn't a big deal either, because you know how the
|
||||||
|
``TLObject``\ 's are made, and how the types should be serialized.
|
||||||
|
|
||||||
|
You can either write your own code generator, or use the one this
|
||||||
|
library provides, but please be kind and keep some special mention to
|
||||||
|
this project for helping you out.
|
||||||
|
|
||||||
|
This is only a introduction. The ``TL`` language is not *that* easy. But
|
||||||
|
it's not that hard either. You're free to sniff the
|
||||||
|
``telethon_generator/`` files and learn how to parse other more complex
|
||||||
|
lines, such as ``flags`` (to indicate things that may or may not be
|
||||||
|
written at all) and ``vector``\ 's.
|
|
@ -1,13 +1,14 @@
|
||||||
======
|
====
|
||||||
Bots
|
Bots
|
||||||
======
|
====
|
||||||
|
|
||||||
|
|
||||||
Talking to Inline Bots
|
Talking to Inline Bots
|
||||||
^^^^^^^^^^^^^^^^^^^^^^
|
**********************
|
||||||
|
|
||||||
You can query an inline bot, such as `@VoteBot`__
|
You can query an inline bot, such as `@VoteBot`__ (note, *query*,
|
||||||
(note, *query*, not *interact* with a voting message), by making use of
|
not *interact* with a voting message), by making use of the
|
||||||
the `GetInlineBotResultsRequest`__ request:
|
`GetInlineBotResultsRequest`__ request:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -32,11 +33,10 @@ And you can select any of their results by using
|
||||||
|
|
||||||
|
|
||||||
Talking to Bots with special reply markup
|
Talking to Bots with special reply markup
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
*****************************************
|
||||||
|
|
||||||
To interact with a message that has a special reply markup, such as
|
To interact with a message that has a special reply markup, such as
|
||||||
`@VoteBot`__ polls, you would use
|
`@VoteBot`__ polls, you would use `GetBotCallbackAnswerRequest`__:
|
||||||
`GetBotCallbackAnswerRequest`__:
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ To interact with a message that has a special reply markup, such as
|
||||||
data=msg.reply_markup.rows[wanted_row].buttons[wanted_button].data
|
data=msg.reply_markup.rows[wanted_row].buttons[wanted_button].data
|
||||||
))
|
))
|
||||||
|
|
||||||
It’s a bit verbose, but it has all the information you would need to
|
It's a bit verbose, but it has all the information you would need to
|
||||||
show it visually (button rows, and buttons within each row, each with
|
show it visually (button rows, and buttons within each row, each with
|
||||||
its own data).
|
its own data).
|
||||||
|
|
205
readthedocs/extra/examples/chats-and-channels.rst
Normal file
205
readthedocs/extra/examples/chats-and-channels.rst
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
===============================
|
||||||
|
Working with Chats and Channels
|
||||||
|
===============================
|
||||||
|
|
||||||
|
|
||||||
|
Joining a chat or channel
|
||||||
|
*************************
|
||||||
|
|
||||||
|
Note that `Chat`__\ s are normal groups, and `Channel`__\ s are a
|
||||||
|
special form of `Chat`__\ s,
|
||||||
|
which can also be super-groups if their ``megagroup`` member is
|
||||||
|
``True``.
|
||||||
|
|
||||||
|
|
||||||
|
Joining a public channel
|
||||||
|
************************
|
||||||
|
|
||||||
|
Once you have the :ref:`entity <entities>` of the channel you want to join
|
||||||
|
to, you can make use of the `JoinChannelRequest`__ to join such channel:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon.tl.functions.channels import JoinChannelRequest
|
||||||
|
client(JoinChannelRequest(channel))
|
||||||
|
|
||||||
|
# In the same way, you can also leave such channel
|
||||||
|
from telethon.tl.functions.channels import LeaveChannelRequest
|
||||||
|
client(LeaveChannelRequest(input_channel))
|
||||||
|
|
||||||
|
|
||||||
|
For more on channels, check the `channels namespace`__.
|
||||||
|
|
||||||
|
|
||||||
|
Joining a private chat or channel
|
||||||
|
*********************************
|
||||||
|
|
||||||
|
If all you have is a link like this one:
|
||||||
|
``https://t.me/joinchat/AAAAAFFszQPyPEZ7wgxLtd``, you already have
|
||||||
|
enough information to join! The part after the
|
||||||
|
``https://t.me/joinchat/``, this is, ``AAAAAFFszQPyPEZ7wgxLtd`` on this
|
||||||
|
example, is the ``hash`` of the chat or channel. Now you can use
|
||||||
|
`ImportChatInviteRequest`__ as follows:
|
||||||
|
|
||||||
|
.. -block:: python
|
||||||
|
|
||||||
|
from telethon.tl.functions.messages import ImportChatInviteRequest
|
||||||
|
updates = client(ImportChatInviteRequest('AAAAAEHbEkejzxUjAUCfYg'))
|
||||||
|
|
||||||
|
|
||||||
|
Adding someone else to such chat or channel
|
||||||
|
*******************************************
|
||||||
|
|
||||||
|
If you don't want to add yourself, maybe because you're already in,
|
||||||
|
you can always add someone else with the `AddChatUserRequest`__,
|
||||||
|
which use is very straightforward:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon.tl.functions.messages import AddChatUserRequest
|
||||||
|
|
||||||
|
client(AddChatUserRequest(
|
||||||
|
chat_id,
|
||||||
|
user_to_add,
|
||||||
|
fwd_limit=10 # allow the user to see the 10 last messages
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
Checking a link without joining
|
||||||
|
*******************************
|
||||||
|
|
||||||
|
If you don't need to join but rather check whether it's a group or a
|
||||||
|
channel, you can use the `CheckChatInviteRequest`__, which takes in
|
||||||
|
the `hash`__ of said channel or group.
|
||||||
|
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/constructors/chat.html
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/constructors/channel.html
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/types/chat.html
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/methods/channels/join_channel.html
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/methods/channels/index.html
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/methods/messages/import_chat_invite.html
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/methods/messages/add_chat_user.html
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/methods/messages/check_chat_invite.html
|
||||||
|
__ https://github.com/LonamiWebs/Telethon/wiki/Joining-a-chat-or-channel#joining-a-private-chat-or-channel
|
||||||
|
|
||||||
|
|
||||||
|
Retrieving all chat members (channels too)
|
||||||
|
******************************************
|
||||||
|
|
||||||
|
In order to get all the members from a mega-group or channel, you need
|
||||||
|
to use `GetParticipantsRequest`__. As we can see it needs an
|
||||||
|
`InputChannel`__, (passing the mega-group or channel you're going to
|
||||||
|
use will work), and a mandatory `ChannelParticipantsFilter`__. The
|
||||||
|
closest thing to "no filter" is to simply use
|
||||||
|
`ChannelParticipantsSearch`__ with an empty ``'q'`` string.
|
||||||
|
|
||||||
|
If we want to get *all* the members, we need to use a moving offset and
|
||||||
|
a fixed limit:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon.tl.functions.channels import GetParticipantsRequest
|
||||||
|
from telethon.tl.types import ChannelParticipantsSearch
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
offset = 0
|
||||||
|
limit = 100
|
||||||
|
all_participants = []
|
||||||
|
|
||||||
|
while True:
|
||||||
|
participants = client.invoke(GetParticipantsRequest(
|
||||||
|
channel, ChannelParticipantsSearch(''), offset, limit
|
||||||
|
))
|
||||||
|
if not participants.users:
|
||||||
|
break
|
||||||
|
all_participants.extend(participants.users)
|
||||||
|
offset += len(participants.users)
|
||||||
|
|
||||||
|
|
||||||
|
Note that ``GetParticipantsRequest`` returns `ChannelParticipants`__,
|
||||||
|
which may have more information you need (like the role of the
|
||||||
|
participants, total count of members, etc.)
|
||||||
|
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/methods/channels/get_participants.html
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/methods/channels/get_participants.html
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/types/channel_participants_filter.html
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/constructors/channel_participants_search.html
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/constructors/channels/channel_participants.html
|
||||||
|
|
||||||
|
|
||||||
|
Recent Actions
|
||||||
|
**************
|
||||||
|
|
||||||
|
"Recent actions" is simply the name official applications have given to
|
||||||
|
the "admin log". Simply use `GetAdminLogRequest`__ for that, and
|
||||||
|
you'll get AdminLogResults.events in return which in turn has the final
|
||||||
|
`.action`__.
|
||||||
|
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/methods/channels/get_admin_log.html
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/types/channel_admin_log_event_action.html
|
||||||
|
|
||||||
|
|
||||||
|
Admin Permissions
|
||||||
|
*****************
|
||||||
|
|
||||||
|
Giving or revoking admin permissions can be done with the `EditAdminRequest`__:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon.tl.functions.channels import EditAdminRequest
|
||||||
|
from telethon.tl.types import ChannelAdminRights
|
||||||
|
|
||||||
|
# You need both the channel and who to grant permissions
|
||||||
|
# They can either be channel/user or input channel/input user.
|
||||||
|
#
|
||||||
|
# ChannelAdminRights is a list of granted permissions.
|
||||||
|
# Set to True those you want to give.
|
||||||
|
rights = ChannelAdminRights(
|
||||||
|
post_messages=None,
|
||||||
|
add_admins=None,
|
||||||
|
invite_users=None,
|
||||||
|
change_info=True,
|
||||||
|
ban_users=None,
|
||||||
|
delete_messages=True,
|
||||||
|
pin_messages=True,
|
||||||
|
invite_link=None,
|
||||||
|
edit_messages=None
|
||||||
|
)
|
||||||
|
|
||||||
|
client(EditAdminRequest(channel, who, rights))
|
||||||
|
|
||||||
|
|
||||||
|
Thanks to `@Kyle2142`__ for `pointing out`__ that you **cannot** set
|
||||||
|
to ``True`` the ``post_messages`` and ``edit_messages`` fields. Those that
|
||||||
|
are ``None`` can be omitted (left here so you know `which are available`__.
|
||||||
|
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/methods/channels/edit_admin.html
|
||||||
|
__ https://github.com/Kyle2142
|
||||||
|
__ https://github.com/LonamiWebs/Telethon/issues/490
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/constructors/channel_admin_rights.html
|
||||||
|
|
||||||
|
|
||||||
|
Increasing View Count in a Channel
|
||||||
|
**********************************
|
||||||
|
|
||||||
|
It has been asked `quite`__ `a few`__ `times`__ (really, `many`__), and
|
||||||
|
while I don't understand why so many people ask this, the solution is to
|
||||||
|
use `GetMessagesViewsRequest`__, setting ``increment=True``:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
|
||||||
|
# Obtain `channel' through dialogs or through client.get_entity() or anyhow.
|
||||||
|
# Obtain `msg_ids' through `.get_message_history()` or anyhow. Must be a list.
|
||||||
|
|
||||||
|
client(GetMessagesViewsRequest(
|
||||||
|
peer=channel,
|
||||||
|
id=msg_ids,
|
||||||
|
increment=True
|
||||||
|
))
|
||||||
|
|
||||||
|
__ https://github.com/LonamiWebs/Telethon/issues/233
|
||||||
|
__ https://github.com/LonamiWebs/Telethon/issues/305
|
||||||
|
__ https://github.com/LonamiWebs/Telethon/issues/409
|
||||||
|
__ https://github.com/LonamiWebs/Telethon/issues/447
|
||||||
|
__ https://lonamiwebs.github.io/Telethon/methods/messages/get_messages_views.html
|
|
@ -1,20 +1,18 @@
|
||||||
=========================
|
=====================
|
||||||
Working with messages
|
Working with messages
|
||||||
=========================
|
=====================
|
||||||
|
|
||||||
.. note::
|
|
||||||
Make sure you have gone through :ref:`prelude` already!
|
|
||||||
|
|
||||||
|
|
||||||
Forwarding messages
|
Forwarding messages
|
||||||
*******************
|
*******************
|
||||||
|
|
||||||
Note that ForwardMessageRequest_ (note it's Message, singular) will *not* work if channels are involved.
|
Note that ForwardMessageRequest_ (note it's Message, singular) will *not*
|
||||||
This is because channel (and megagroups) IDs are not unique, so you also need to know who the sender is
|
work if channels are involved. This is because channel (and megagroups) IDs
|
||||||
(a parameter this request doesn't have).
|
are not unique, so you also need to know who the sender is (a parameter this
|
||||||
|
request doesn't have).
|
||||||
|
|
||||||
Either way, you are encouraged to use ForwardMessagesRequest_ (note it's Message*s*, plural) *always*,
|
Either way, you are encouraged to use ForwardMessagesRequest_ (note it's
|
||||||
since it is more powerful, as follows:
|
Message*s*, plural) *always*, since it is more powerful, as follows:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -31,14 +29,16 @@ since it is more powerful, as follows:
|
||||||
to_peer=to_entity # who are we forwarding them to?
|
to_peer=to_entity # who are we forwarding them to?
|
||||||
))
|
))
|
||||||
|
|
||||||
The named arguments are there for clarity, although they're not needed because they appear in order.
|
The named arguments are there for clarity, although they're not needed because
|
||||||
You can obviously just wrap a single message on the list too, if that's all you have.
|
they appear in order. You can obviously just wrap a single message on the list
|
||||||
|
too, if that's all you have.
|
||||||
|
|
||||||
|
|
||||||
Searching Messages
|
Searching Messages
|
||||||
*******************
|
*******************
|
||||||
|
|
||||||
Messages are searched through the obvious SearchRequest_, but you may run into issues_. A valid example would be:
|
Messages are searched through the obvious SearchRequest_, but you may run
|
||||||
|
into issues_. A valid example would be:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -46,27 +46,32 @@ Messages are searched through the obvious SearchRequest_, but you may run into i
|
||||||
entity, 'query', InputMessagesFilterEmpty(), None, None, 0, 0, 100
|
entity, 'query', InputMessagesFilterEmpty(), None, None, 0, 0, 100
|
||||||
))
|
))
|
||||||
|
|
||||||
It's important to note that the optional parameter ``from_id`` has been left omitted and thus defaults to ``None``.
|
It's important to note that the optional parameter ``from_id`` has been left
|
||||||
Changing it to InputUserEmpty_, as one could think to specify "no user", won't work because this parameter is a flag,
|
omitted and thus defaults to ``None``. Changing it to InputUserEmpty_, as one
|
||||||
|
could think to specify "no user", won't work because this parameter is a flag,
|
||||||
and it being unspecified has a different meaning.
|
and it being unspecified has a different meaning.
|
||||||
|
|
||||||
If one were to set ``from_id=InputUserEmpty()``, it would filter messages from "empty" senders,
|
If one were to set ``from_id=InputUserEmpty()``, it would filter messages
|
||||||
which would likely match no users.
|
from "empty" senders, which would likely match no users.
|
||||||
|
|
||||||
If you get a ``ChatAdminRequiredError`` on a channel, it's probably because you tried setting the ``from_id`` filter,
|
If you get a ``ChatAdminRequiredError`` on a channel, it's probably because
|
||||||
and as the error says, you can't do that. Leave it set to ``None`` and it should work.
|
you tried setting the ``from_id`` filter, and as the error says, you can't
|
||||||
|
do that. Leave it set to ``None`` and it should work.
|
||||||
|
|
||||||
As with every method, make sure you use the right ID/hash combination for your ``InputUser`` or ``InputChat``,
|
As with every method, make sure you use the right ID/hash combination for
|
||||||
or you'll likely run into errors like ``UserIdInvalidError``.
|
your ``InputUser`` or ``InputChat``, or you'll likely run into errors like
|
||||||
|
``UserIdInvalidError``.
|
||||||
|
|
||||||
|
|
||||||
Sending stickers
|
Sending stickers
|
||||||
*****************
|
****************
|
||||||
|
|
||||||
Stickers are nothing else than ``files``, and when you successfully retrieve the stickers for a certain sticker set,
|
Stickers are nothing else than ``files``, and when you successfully retrieve
|
||||||
all you will have are ``handles`` to these files. Remember, the files Telegram holds on their servers can be referenced
|
the stickers for a certain sticker set, all you will have are ``handles`` to
|
||||||
through this pair of ID/hash (unique per user), and you need to use this handle when sending a "document" message.
|
these files. Remember, the files Telegram holds on their servers can be
|
||||||
This working example will send yourself the very first sticker you have:
|
referenced through this pair of ID/hash (unique per user), and you need to
|
||||||
|
use this handle when sending a "document" message. This working example will
|
||||||
|
send yourself the very first sticker you have:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
=========================================
|
========================================
|
||||||
Deleted, Limited or Deactivated Accounts
|
Deleted, Limited or Deactivated Accounts
|
||||||
=========================================
|
========================================
|
||||||
|
|
||||||
If you're from Iran or Russian, we have bad news for you.
|
If you're from Iran or Russian, we have bad news for you.
|
||||||
Telegram is much more likely to ban these numbers,
|
Telegram is much more likely to ban these numbers,
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
================
|
================
|
||||||
Enable Logging
|
Enabling Logging
|
||||||
================
|
================
|
||||||
|
|
||||||
Telethon makes use of the `logging`__ module, and you can enable it as follows:
|
Telethon makes use of the `logging`__ module, and you can enable it as follows:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code:: python
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
|
||||||
You can also use it in your own project very easily:
|
The library has the `NullHandler`__ added by default so that no log calls
|
||||||
|
will be printed unless you explicitly enable it.
|
||||||
|
|
||||||
|
You can also `use the module`__ on your own project very easily:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -21,4 +24,17 @@ You can also use it in your own project very easily:
|
||||||
logger.warning('This is a warning!')
|
logger.warning('This is a warning!')
|
||||||
|
|
||||||
|
|
||||||
|
If you want to enable ``logging`` for your project *but* use a different
|
||||||
|
log level for the library:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import logging
|
||||||
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
# For instance, show only warnings and above
|
||||||
|
logging.getLogger('telethon').setLevel(level=logging.WARNING)
|
||||||
|
|
||||||
|
|
||||||
__ https://docs.python.org/3/library/logging.html
|
__ https://docs.python.org/3/library/logging.html
|
||||||
|
__ https://docs.python.org/3/howto/logging.html#configuring-logging-for-a-library
|
||||||
|
__ https://docs.python.org/3/howto/logging.html
|
||||||
|
|
|
@ -3,9 +3,9 @@ RPC Errors
|
||||||
==========
|
==========
|
||||||
|
|
||||||
RPC stands for Remote Procedure Call, and when Telethon raises an
|
RPC stands for Remote Procedure Call, and when Telethon raises an
|
||||||
``RPCError``, it’s most likely because you have invoked some of the API
|
``RPCError``, it's most likely because you have invoked some of the API
|
||||||
methods incorrectly (wrong parameters, wrong permissions, or even
|
methods incorrectly (wrong parameters, wrong permissions, or even
|
||||||
something went wrong on Telegram’s server). The most common are:
|
something went wrong on Telegram's server). The most common are:
|
||||||
|
|
||||||
- ``FloodError`` (420), the same request was repeated many times. Must
|
- ``FloodError`` (420), the same request was repeated many times. Must
|
||||||
wait ``.seconds``.
|
wait ``.seconds``.
|
||||||
|
@ -13,7 +13,7 @@ something went wrong on Telegram’s server). The most common are:
|
||||||
verification on Telegram.
|
verification on Telegram.
|
||||||
- ``CdnFileTamperedError``, if the media you were trying to download
|
- ``CdnFileTamperedError``, if the media you were trying to download
|
||||||
from a CDN has been altered.
|
from a CDN has been altered.
|
||||||
- ``ChatAdminRequiredError``, you don’t have permissions to perform
|
- ``ChatAdminRequiredError``, you don't have permissions to perform
|
||||||
said operation on a chat or channel. Try avoiding filters, i.e. when
|
said operation on a chat or channel. Try avoiding filters, i.e. when
|
||||||
searching messages.
|
searching messages.
|
||||||
|
|
||||||
|
@ -22,6 +22,6 @@ The generic classes for different error codes are: \* ``InvalidDCError``
|
||||||
``BadRequestError`` (400), the request contained errors. \*
|
``BadRequestError`` (400), the request contained errors. \*
|
||||||
``UnauthorizedError`` (401), the user is not authorized yet. \*
|
``UnauthorizedError`` (401), the user is not authorized yet. \*
|
||||||
``ForbiddenError`` (403), privacy violation error. \* ``NotFoundError``
|
``ForbiddenError`` (403), privacy violation error. \* ``NotFoundError``
|
||||||
(404), make sure you’re invoking ``Request``\ ’s!
|
(404), make sure you're invoking ``Request``\ 's!
|
||||||
|
|
||||||
If the error is not recognised, it will only be an ``RPCError``.
|
If the error is not recognised, it will only be an ``RPCError``.
|
57
readthedocs/extra/wall-of-shame.rst
Normal file
57
readthedocs/extra/wall-of-shame.rst
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
This project has an
|
||||||
|
`issues <https://github.com/LonamiWebs/Telethon/issues>`__ section for
|
||||||
|
you to file **issues** whenever you encounter any when working with the
|
||||||
|
library. Said section is **not** for issues on *your* program but rather
|
||||||
|
issues with Telethon itself.
|
||||||
|
|
||||||
|
If you have not made the effort to 1. `read through the
|
||||||
|
wiki <https://github.com/LonamiWebs/Telethon/wiki>`__ and 2. `look for
|
||||||
|
the method you need <https://lonamiwebs.github.io/Telethon/>`__, you
|
||||||
|
will end up on the `Wall of
|
||||||
|
Shame <https://github.com/LonamiWebs/Telethon/issues?q=is%3Aissue+label%3ARTFM+is%3Aclosed>`__,
|
||||||
|
i.e. all issues labeled
|
||||||
|
`"RTFM" <http://www.urbandictionary.com/define.php?term=RTFM>`__:
|
||||||
|
|
||||||
|
> > **rtfm**
|
||||||
|
> > Literally "Read The F\ **king Manual"; a term showing the
|
||||||
|
frustration of being bothered with questions so trivial that the asker
|
||||||
|
could have quickly figured out the answer on their own with minimal
|
||||||
|
effort, usually by reading readily-available documents. People who
|
||||||
|
say"RTFM!" might be considered rude, but the true rude ones are the
|
||||||
|
annoying people who take absolutely no self-responibility and expect to
|
||||||
|
have all the answers handed to them personally.
|
||||||
|
> > *"Damn, that's the twelveth time that somebody posted this question
|
||||||
|
to the messageboard today! RTFM, already!"*
|
||||||
|
> > **\ by Bill M. July 27, 2004*\*
|
||||||
|
|
||||||
|
If you have indeed read the wiki, and have tried looking for the method,
|
||||||
|
and yet you didn't find what you need, **that's fine**. Telegram's API
|
||||||
|
can have some obscure names at times, and for this reason, there is a
|
||||||
|
`"question"
|
||||||
|
label <https://github.com/LonamiWebs/Telethon/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20label%3Aquestion%20>`__
|
||||||
|
with questions that are okay to ask. Just state what you've tried so
|
||||||
|
that we know you've made an effort, or you'll go to the Wall of Shame.
|
||||||
|
|
||||||
|
Of course, if the issue you're going to open is not even a question but
|
||||||
|
a real issue with the library (thankfully, most of the issues have been
|
||||||
|
that!), you won't end up here. Don't worry.
|
||||||
|
|
||||||
|
Current winner
|
||||||
|
--------------
|
||||||
|
|
||||||
|
The current winner is `issue
|
||||||
|
213 <https://github.com/LonamiWebs/Telethon/issues/213>`__:
|
||||||
|
|
||||||
|
**Issue:**
|
||||||
|
|
||||||
|
.. figure:: https://user-images.githubusercontent.com/6297805/29822978-9a9a6ef0-8ccd-11e7-9ec5-934ea0f57681.jpg
|
||||||
|
:alt: Winner issue
|
||||||
|
|
||||||
|
Winner issue
|
||||||
|
|
||||||
|
**Answer:**
|
||||||
|
|
||||||
|
.. figure:: https://user-images.githubusercontent.com/6297805/29822983-9d523402-8ccd-11e7-9fb1-5783740ee366.jpg
|
||||||
|
:alt: Winner issue answer
|
||||||
|
|
||||||
|
Winner issue answer
|
|
@ -3,11 +3,14 @@
|
||||||
You can adapt this file completely to your liking, but it should at least
|
You can adapt this file completely to your liking, but it should at least
|
||||||
contain the root `toctree` directive.
|
contain the root `toctree` directive.
|
||||||
|
|
||||||
|
====================================
|
||||||
Welcome to Telethon's documentation!
|
Welcome to Telethon's documentation!
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
Pure Python 3 Telegram client library. Official Site `here <https://lonamiwebs.github.io/Telethon>`_.
|
|
||||||
|
|
||||||
|
Pure Python 3 Telegram client library.
|
||||||
|
Official Site `here <https://lonamiwebs.github.io/Telethon>`_.
|
||||||
|
Please follow the links below to get you started.
|
||||||
|
|
||||||
|
|
||||||
.. _installation-and-usage:
|
.. _installation-and-usage:
|
||||||
|
@ -19,10 +22,9 @@ Pure Python 3 Telegram client library. Official Site `here <https://lonamiwebs.g
|
||||||
extra/basic/getting-started
|
extra/basic/getting-started
|
||||||
extra/basic/installation
|
extra/basic/installation
|
||||||
extra/basic/creating-a-client
|
extra/basic/creating-a-client
|
||||||
extra/basic/sessions
|
extra/basic/telegram-client
|
||||||
extra/basic/sending-requests
|
extra/basic/entities
|
||||||
extra/basic/working-with-updates
|
extra/basic/working-with-updates
|
||||||
extra/basic/accessing-the-full-api
|
|
||||||
|
|
||||||
|
|
||||||
.. _Advanced-usage:
|
.. _Advanced-usage:
|
||||||
|
@ -31,11 +33,19 @@ Pure Python 3 Telegram client library. Official Site `here <https://lonamiwebs.g
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
:caption: Advanced Usage
|
:caption: Advanced Usage
|
||||||
|
|
||||||
extra/advanced
|
extra/advanced-usage/accessing-the-full-api
|
||||||
extra/advanced-usage/signing-in
|
extra/advanced-usage/sessions
|
||||||
extra/advanced-usage/working-with-messages
|
|
||||||
extra/advanced-usage/users-and-chats
|
|
||||||
extra/advanced-usage/bots
|
.. _Examples:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
:caption: Examples
|
||||||
|
|
||||||
|
extra/examples/working-with-messages
|
||||||
|
extra/examples/chats-and-channels
|
||||||
|
extra/examples/bots
|
||||||
|
|
||||||
|
|
||||||
.. _Troubleshooting:
|
.. _Troubleshooting:
|
||||||
|
@ -49,6 +59,30 @@ Pure Python 3 Telegram client library. Official Site `here <https://lonamiwebs.g
|
||||||
extra/troubleshooting/rpc-errors
|
extra/troubleshooting/rpc-errors
|
||||||
|
|
||||||
|
|
||||||
|
.. _Developing:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
:caption: Developing
|
||||||
|
|
||||||
|
extra/developing/philosophy.rst
|
||||||
|
extra/developing/api-status.rst
|
||||||
|
extra/developing/test-servers.rst
|
||||||
|
extra/developing/project-structure.rst
|
||||||
|
extra/developing/coding-style.rst
|
||||||
|
extra/developing/understanding-the-type-language.rst
|
||||||
|
extra/developing/tips-for-porting-the-project.rst
|
||||||
|
extra/developing/telegram-api-in-other-languages.rst
|
||||||
|
|
||||||
|
|
||||||
|
.. _Wall-of-shame:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
:caption: Wall of Shame
|
||||||
|
|
||||||
|
extra/wall-of-shame.rst
|
||||||
|
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:caption: Telethon modules
|
:caption: Telethon modules
|
||||||
|
@ -56,7 +90,6 @@ Pure Python 3 Telegram client library. Official Site `here <https://lonamiwebs.g
|
||||||
telethon
|
telethon
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Indices and tables
|
Indices and tables
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user